Compare commits
17 Commits
762dabd3e5
...
a7eeedf7fb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7eeedf7fb | ||
|
|
5bb83cfab7 | ||
|
|
5a78b01a57 | ||
|
|
2c1aebc8a5 | ||
|
|
9452a14567 | ||
|
|
01fb0bf131 | ||
|
|
a662454ea7 | ||
|
|
c503acb050 | ||
|
|
fde3dbbf9a | ||
|
|
9e357cbc3b | ||
|
|
0b3d659f14 | ||
|
|
0e6a43ec5f | ||
|
|
2ddddf5774 | ||
|
|
8d3f4f896f | ||
|
|
0318dcbb65 | ||
|
|
f7cfe16c67 | ||
|
|
3612313e76 |
10
alisp.org
10
alisp.org
@@ -52,20 +52,20 @@ other state do we need to encode?
|
|||||||
*** TODO Write the general parser
|
*** TODO Write the general parser
|
||||||
** WIP Unit tests :tests:
|
** WIP Unit tests :tests:
|
||||||
*** TODO Test streams
|
*** TODO Test streams
|
||||||
**** TODO Test file init
|
**** DONE Test file init
|
||||||
[[file:test/test_stream.c::void stream_test_file(void)]]
|
[[file:test/test_stream.c::void stream_test_file(void)]]
|
||||||
***** TODO Test successful init from real files
|
***** DONE Test successful init from real files
|
||||||
Ensure stream_size is 0 i.e. we don't read anything on creation.
|
Ensure stream_size is 0 i.e. we don't read anything on creation.
|
||||||
Also ensure stream_eoc is false.
|
Also ensure stream_eoc is false.
|
||||||
***** TODO Test failed init from fake files
|
***** DONE Test failed init from fake files
|
||||||
**** TODO Test peeking and next
|
**** DONE Test peeking and next
|
||||||
[[file:test/test_stream.c::void stream_test_peek_next(void)]]
|
[[file:test/test_stream.c::void stream_test_peek_next(void)]]
|
||||||
- Peeking with bad streams ('\0' return)
|
- Peeking with bad streams ('\0' return)
|
||||||
- Peeking with good streams (no effect on position)
|
- Peeking with good streams (no effect on position)
|
||||||
- Next with bad streams ('\0' return, no effect on position)
|
- Next with bad streams ('\0' return, no effect on position)
|
||||||
- Next with good streams (effects position)
|
- Next with good streams (effects position)
|
||||||
- Peeking after next (should just work)
|
- Peeking after next (should just work)
|
||||||
**** TODO Test seeking
|
**** DONE Test seeking
|
||||||
[[file:test/test_stream.c::void stream_test_seek(void)]]
|
[[file:test/test_stream.c::void stream_test_seek(void)]]
|
||||||
- Seeking forward/backward on a bad stream (should stop at 0)
|
- Seeking forward/backward on a bad stream (should stop at 0)
|
||||||
- Seeking forward/backward too far (should clamp)
|
- Seeking forward/backward too far (should clamp)
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ typedef struct
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
stream_type_t type;
|
stream_type_t type;
|
||||||
char *name;
|
const char *name;
|
||||||
u64 position;
|
u64 position;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
@@ -51,9 +51,9 @@ typedef struct
|
|||||||
|
|
||||||
#define STREAM_DEFAULT_CHUNK 64
|
#define STREAM_DEFAULT_CHUNK 64
|
||||||
|
|
||||||
stream_err_t stream_init_string(stream_t *, char *, sv_t);
|
stream_err_t stream_init_string(stream_t *, const char *, sv_t);
|
||||||
stream_err_t stream_init_pipe(stream_t *, char *, FILE *);
|
stream_err_t stream_init_pipe(stream_t *, const char *, FILE *);
|
||||||
stream_err_t stream_init_file(stream_t *, char *, FILE *);
|
stream_err_t stream_init_file(stream_t *, const char *, FILE *);
|
||||||
void stream_stop(stream_t *);
|
void stream_stop(stream_t *);
|
||||||
|
|
||||||
// End of Content (i.e. we've consumed all cached content/file)
|
// End of Content (i.e. we've consumed all cached content/file)
|
||||||
@@ -66,9 +66,9 @@ char stream_next(stream_t *);
|
|||||||
// Peek current character, do not push position
|
// Peek current character, do not push position
|
||||||
char stream_peek(stream_t *);
|
char stream_peek(stream_t *);
|
||||||
// Move forward or backward in the stream, return success of operation
|
// Move forward or backward in the stream, return success of operation
|
||||||
bool stream_seek(stream_t *, i64);
|
u64 stream_seek(stream_t *, i64);
|
||||||
bool stream_seek_forward(stream_t *, u64);
|
u64 stream_seek_forward(stream_t *, u64);
|
||||||
bool stream_seek_backward(stream_t *, u64);
|
u64 stream_seek_backward(stream_t *, u64);
|
||||||
|
|
||||||
// Return a relative substring of a given size
|
// Return a relative substring of a given size
|
||||||
sv_t stream_substr(stream_t *, u64);
|
sv_t stream_substr(stream_t *, u64);
|
||||||
|
|||||||
13
src/main.c
13
src/main.c
@@ -24,6 +24,9 @@ void usage(FILE *fp)
|
|||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
FILE *pipe = NULL;
|
||||||
|
stream_t stream = {0};
|
||||||
|
|
||||||
if (argc == 1)
|
if (argc == 1)
|
||||||
{
|
{
|
||||||
usage(stderr);
|
usage(stderr);
|
||||||
@@ -35,8 +38,6 @@ int main(int argc, char *argv[])
|
|||||||
TODO("alisp doesn't support multiple files currently.");
|
TODO("alisp doesn't support multiple files currently.");
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *fp = NULL;
|
|
||||||
stream_t stream = {0};
|
|
||||||
if (strncmp(argv[1], "--", 2) == 0)
|
if (strncmp(argv[1], "--", 2) == 0)
|
||||||
{
|
{
|
||||||
stream_err_t err = stream_init_pipe(&stream, "stdin", stdin);
|
stream_err_t err = stream_init_pipe(&stream, "stdin", stdin);
|
||||||
@@ -55,8 +56,8 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fp = fopen(argv[1], "rb");
|
pipe = fopen(argv[1], "rb");
|
||||||
stream_err_t err = stream_init_file(&stream, argv[1], fp);
|
stream_err_t err = stream_init_file(&stream, argv[1], pipe);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "ERROR: %s from `%s`\n", stream_err_to_cstr(err),
|
fprintf(stderr, "ERROR: %s from `%s`\n", stream_err_to_cstr(err),
|
||||||
@@ -68,8 +69,8 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
LOG("[INFO]: Initialised stream for `%s`\n", stream.name);
|
LOG("[INFO]: Initialised stream for `%s`\n", stream.name);
|
||||||
end:
|
end:
|
||||||
if (fp)
|
if (pipe)
|
||||||
fclose(fp);
|
fclose(pipe);
|
||||||
stream_stop(&stream);
|
stream_stop(&stream);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
36
src/stream.c
36
src/stream.c
@@ -35,7 +35,8 @@ const char *stream_err_to_cstr(stream_err_t err)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stream_err_t stream_init_string(stream_t *stream, char *name, sv_t contents)
|
stream_err_t stream_init_string(stream_t *stream, const char *name,
|
||||||
|
sv_t contents)
|
||||||
{
|
{
|
||||||
if (!stream)
|
if (!stream)
|
||||||
return STREAM_ERR_INVALID_PTR;
|
return STREAM_ERR_INVALID_PTR;
|
||||||
@@ -49,7 +50,7 @@ stream_err_t stream_init_string(stream_t *stream, char *name, sv_t contents)
|
|||||||
return STREAM_ERR_OK;
|
return STREAM_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream_err_t stream_init_pipe(stream_t *stream, char *name, FILE *pipe)
|
stream_err_t stream_init_pipe(stream_t *stream, const char *name, FILE *pipe)
|
||||||
{
|
{
|
||||||
if (!stream)
|
if (!stream)
|
||||||
return STREAM_ERR_INVALID_PTR;
|
return STREAM_ERR_INVALID_PTR;
|
||||||
@@ -68,7 +69,7 @@ stream_err_t stream_init_pipe(stream_t *stream, char *name, FILE *pipe)
|
|||||||
return STREAM_ERR_OK;
|
return STREAM_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream_err_t stream_init_file(stream_t *stream, char *name, FILE *pipe)
|
stream_err_t stream_init_file(stream_t *stream, const char *name, FILE *pipe)
|
||||||
{
|
{
|
||||||
if (!stream)
|
if (!stream)
|
||||||
return STREAM_ERR_INVALID_PTR;
|
return STREAM_ERR_INVALID_PTR;
|
||||||
@@ -82,8 +83,6 @@ stream_err_t stream_init_file(stream_t *stream, char *name, FILE *pipe)
|
|||||||
stream->name = name;
|
stream->name = name;
|
||||||
stream->pipe.file = pipe;
|
stream->pipe.file = pipe;
|
||||||
|
|
||||||
vec_init(&stream->pipe.cache, STREAM_DEFAULT_CHUNK);
|
|
||||||
|
|
||||||
return STREAM_ERR_OK;
|
return STREAM_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +235,7 @@ char stream_peek(stream_t *stream)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool stream_seek(stream_t *stream, i64 offset)
|
u64 stream_seek(stream_t *stream, i64 offset)
|
||||||
{
|
{
|
||||||
if (offset < 0)
|
if (offset < 0)
|
||||||
return stream_seek_backward(stream, offset * -1);
|
return stream_seek_backward(stream, offset * -1);
|
||||||
@@ -247,20 +246,20 @@ bool stream_seek(stream_t *stream, i64 offset)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool stream_seek_forward(stream_t *stream, u64 offset)
|
u64 stream_seek_forward(stream_t *stream, u64 offset)
|
||||||
{
|
{
|
||||||
if (stream_eoc(stream))
|
if (stream_eoc(stream))
|
||||||
return false;
|
return 0;
|
||||||
|
|
||||||
switch (stream->type)
|
switch (stream->type)
|
||||||
{
|
{
|
||||||
case STREAM_TYPE_STRING:
|
case STREAM_TYPE_STRING:
|
||||||
{
|
{
|
||||||
if (stream->position + offset >= stream->string.size)
|
if (stream->position + offset >= stream->string.size)
|
||||||
return false;
|
return 0;
|
||||||
|
|
||||||
stream->position += offset;
|
stream->position += offset;
|
||||||
return true;
|
return offset;
|
||||||
}
|
}
|
||||||
case STREAM_TYPE_PIPE:
|
case STREAM_TYPE_PIPE:
|
||||||
case STREAM_TYPE_FILE:
|
case STREAM_TYPE_FILE:
|
||||||
@@ -271,7 +270,7 @@ bool stream_seek_forward(stream_t *stream, u64 offset)
|
|||||||
if (stream->position + offset < stream->pipe.cache.size)
|
if (stream->position + offset < stream->pipe.cache.size)
|
||||||
{
|
{
|
||||||
stream->position += offset;
|
stream->position += offset;
|
||||||
return true;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to read chunks in till we've reached it or we're at the end of the
|
// Try to read chunks in till we've reached it or we're at the end of the
|
||||||
@@ -283,9 +282,11 @@ bool stream_seek_forward(stream_t *stream, u64 offset)
|
|||||||
|
|
||||||
// Same principle as the stream_eoc(stream) check.
|
// Same principle as the stream_eoc(stream) check.
|
||||||
if (stream->position + offset > stream->pipe.cache.size)
|
if (stream->position + offset > stream->pipe.cache.size)
|
||||||
return false;
|
{
|
||||||
|
offset = stream->pipe.cache.size - stream->position;
|
||||||
|
}
|
||||||
stream->position += offset;
|
stream->position += offset;
|
||||||
return true;
|
return offset;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
FAIL("Unreachable");
|
FAIL("Unreachable");
|
||||||
@@ -293,13 +294,16 @@ bool stream_seek_forward(stream_t *stream, u64 offset)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool stream_seek_backward(stream_t *stream, u64 offset)
|
u64 stream_seek_backward(stream_t *stream, u64 offset)
|
||||||
{
|
{
|
||||||
assert(stream);
|
assert(stream);
|
||||||
if (stream->position < offset)
|
if (stream->position < offset)
|
||||||
return false;
|
{
|
||||||
|
offset = stream->position;
|
||||||
|
}
|
||||||
|
|
||||||
stream->position -= offset;
|
stream->position -= offset;
|
||||||
return true;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
sv_t stream_substr(stream_t *stream, u64 size)
|
sv_t stream_substr(stream_t *stream, u64 size)
|
||||||
|
|||||||
@@ -6,7 +6,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "./data.h"
|
#include "./data.h"
|
||||||
#include "./test.h"
|
#include "./test.h"
|
||||||
@@ -18,18 +20,19 @@
|
|||||||
#include "./test_vec.c"
|
#include "./test_vec.c"
|
||||||
|
|
||||||
test_suite_t SUITES[] = {
|
test_suite_t SUITES[] = {
|
||||||
VEC_SUITE, SV_SUITE, SYMTABLE_SUITE, STREAM_SUITE, LISP_API_SUITE,
|
SV_SUITE, VEC_SUITE, SYMTABLE_SUITE, STREAM_SUITE, LISP_API_SUITE,
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
// Seed the pseudorandom gen for subsequent tests.
|
||||||
|
srand(time(NULL));
|
||||||
for (u64 i = 0; i < ARRSIZE(SUITES); ++i)
|
for (u64 i = 0; i < ARRSIZE(SUITES); ++i)
|
||||||
{
|
{
|
||||||
test_suite_t suite = SUITES[i];
|
test_suite_t suite = SUITES[i];
|
||||||
printf("Suite [%s]\n", suite.name);
|
printf("Suite [%s]\n", suite.name);
|
||||||
for (u64 j = 0; j < suite.size; ++j)
|
for (u64 j = 0; j < suite.size; ++j)
|
||||||
{
|
{
|
||||||
printf("\t[%s]: Running...\n", suite.tests[j].name);
|
|
||||||
suite.tests[j].fn();
|
suite.tests[j].fn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
11
test/test.h
11
test/test.h
@@ -14,8 +14,16 @@
|
|||||||
#define TEST_VERBOSE 0
|
#define TEST_VERBOSE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TEST_PASSED() printf("\t[%s]: Passed\n", __func__)
|
#define TEST_END() printf("\t[%s]: Passed\n", __func__)
|
||||||
|
#define TEST_INFO(...) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
printf("\tINFO: "); \
|
||||||
|
printf(__VA_ARGS__); \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
#if TEST_VERBOSE
|
#if TEST_VERBOSE
|
||||||
|
#define TEST_START() printf("\t[%s]: Running...\n", __func__)
|
||||||
#define TEST(COND, ...) \
|
#define TEST(COND, ...) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
@@ -36,6 +44,7 @@
|
|||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
#else
|
#else
|
||||||
|
#define TEST_START()
|
||||||
#define TEST(COND, ...) \
|
#define TEST(COND, ...) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
void smi_test(void)
|
void smi_test(void)
|
||||||
{
|
{
|
||||||
|
TEST_START();
|
||||||
// Standard old testing, checking both sides of the number line and our set
|
// Standard old testing, checking both sides of the number line and our set
|
||||||
// bounds.
|
// bounds.
|
||||||
i64 ints[] = {
|
i64 ints[] = {
|
||||||
@@ -27,11 +28,12 @@ void smi_test(void)
|
|||||||
TEST(in == out, "%ld == %ld", in, out);
|
TEST(in == out, "%ld == %ld", in, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_PASSED();
|
TEST_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
void smi_oob_test(void)
|
void smi_oob_test(void)
|
||||||
{
|
{
|
||||||
|
TEST_START();
|
||||||
// These are integers that are completely out of the bounds of our standard
|
// These are integers that are completely out of the bounds of our standard
|
||||||
// tagging system due to their size. We need to use big integers for this.
|
// tagging system due to their size. We need to use big integers for this.
|
||||||
i64 ints[] = {
|
i64 ints[] = {
|
||||||
@@ -50,11 +52,12 @@ void smi_oob_test(void)
|
|||||||
TEST(in != out, "%ld != %ld", in, out);
|
TEST(in != out, "%ld != %ld", in, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_PASSED();
|
TEST_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sym_fresh_test(void)
|
void sym_fresh_test(void)
|
||||||
{
|
{
|
||||||
|
TEST_START();
|
||||||
sys_t system = {0};
|
sys_t system = {0};
|
||||||
sys_init(&system);
|
sys_init(&system);
|
||||||
|
|
||||||
@@ -71,11 +74,12 @@ void sym_fresh_test(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
sys_free(&system);
|
sys_free(&system);
|
||||||
TEST_PASSED();
|
TEST_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sym_unique_test(void)
|
void sym_unique_test(void)
|
||||||
{
|
{
|
||||||
|
TEST_START();
|
||||||
sys_t system = {0};
|
sys_t system = {0};
|
||||||
sys_init(&system);
|
sys_init(&system);
|
||||||
|
|
||||||
@@ -102,11 +106,12 @@ void sym_unique_test(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
sys_free(&system);
|
sys_free(&system);
|
||||||
TEST_PASSED();
|
TEST_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cons_test(void)
|
void cons_test(void)
|
||||||
{
|
{
|
||||||
|
TEST_START();
|
||||||
sys_t system = {0};
|
sys_t system = {0};
|
||||||
sys_init(&system);
|
sys_init(&system);
|
||||||
|
|
||||||
@@ -138,11 +143,12 @@ void cons_test(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
sys_free(&system);
|
sys_free(&system);
|
||||||
TEST_PASSED();
|
TEST_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sys_test(void)
|
void sys_test(void)
|
||||||
{
|
{
|
||||||
|
TEST_START();
|
||||||
sys_t sys = {0};
|
sys_t sys = {0};
|
||||||
sys_init(&sys);
|
sys_init(&sys);
|
||||||
u64 old_memory_size = sys.memory.size;
|
u64 old_memory_size = sys.memory.size;
|
||||||
@@ -158,14 +164,14 @@ void sys_test(void)
|
|||||||
"Interning doesn't affect system memory size");
|
"Interning doesn't affect system memory size");
|
||||||
TEST(sys.symtable.count > 0, "Interning affects symbol table");
|
TEST(sys.symtable.count > 0, "Interning affects symbol table");
|
||||||
|
|
||||||
// Creating cons' do affect memory size
|
// Creating conses do affect memory size
|
||||||
(void)cons(&sys, make_int(1), make_int(2));
|
(void)cons(&sys, make_int(1), make_int(2));
|
||||||
TEST(sys.memory.size > 0, "Creating cons' affects memory size");
|
TEST(sys.memory.size > 0, "Creating conses affects memory size");
|
||||||
old_memory_size = sys.memory.size;
|
old_memory_size = sys.memory.size;
|
||||||
|
|
||||||
(void)cons(&sys, intern(&sys, SV("test", 4)), NIL);
|
(void)cons(&sys, intern(&sys, SV("test", 4)), NIL);
|
||||||
TEST(sys.memory.size > old_memory_size,
|
TEST(sys.memory.size > old_memory_size,
|
||||||
"Creating cons' back to back affects memory size");
|
"Creating conses back to back affects memory size");
|
||||||
old_memory_size = sys.memory.size;
|
old_memory_size = sys.memory.size;
|
||||||
|
|
||||||
// Creating vectors does affect memory size
|
// Creating vectors does affect memory size
|
||||||
@@ -183,7 +189,7 @@ void sys_test(void)
|
|||||||
TEST(sys.memory.size == 0, "sys_free cleans up memory (shallow check)");
|
TEST(sys.memory.size == 0, "sys_free cleans up memory (shallow check)");
|
||||||
TEST(sys.symtable.count == 0, "sys_free cleans up symtable (shallow check)");
|
TEST(sys.symtable.count == 0, "sys_free cleans up symtable (shallow check)");
|
||||||
|
|
||||||
TEST_PASSED();
|
TEST_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
MAKE_TEST_SUITE(LISP_API_SUITE, "LISP API Tests",
|
MAKE_TEST_SUITE(LISP_API_SUITE, "LISP API Tests",
|
||||||
|
|||||||
@@ -6,14 +6,63 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "./data.h"
|
#include "./data.h"
|
||||||
#include "./test.h"
|
#include "./test.h"
|
||||||
|
|
||||||
#include <alisp/stream.h>
|
#include <alisp/stream.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
char valid_filename[50];
|
||||||
|
FILE *valid_fp = NULL;
|
||||||
|
FILE *invalid_fp = NULL;
|
||||||
|
|
||||||
|
void stream_test_prologue(void)
|
||||||
|
{
|
||||||
|
const char filename_prefix[] = "build/stream_test_";
|
||||||
|
valid_filename[ARRSIZE(valid_filename) - 1] = '\0';
|
||||||
|
memcpy(valid_filename, filename_prefix, ARRSIZE(filename_prefix) - 1);
|
||||||
|
for (u64 i = ARRSIZE(filename_prefix) - 1; i < ARRSIZE(valid_filename) - 1;
|
||||||
|
++i)
|
||||||
|
{
|
||||||
|
u8 num = (rand() % 36);
|
||||||
|
if (num < 26)
|
||||||
|
{
|
||||||
|
valid_filename[i] = num + 'a';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
valid_filename[i] = num + '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_INFO("Creating file named `%.*s`\n", (int)ARRSIZE(valid_filename),
|
||||||
|
valid_filename);
|
||||||
|
valid_fp = fopen(valid_filename, "wb");
|
||||||
|
// This should do a few things for us
|
||||||
|
// 1) Create a file, or clear the contents of it if it exists already.
|
||||||
|
// 2) Write some content to it.
|
||||||
|
assert(valid_fp);
|
||||||
|
fwrite(words_text, ARRSIZE(words_text) - 1, 1, valid_fp);
|
||||||
|
fclose(valid_fp);
|
||||||
|
valid_fp = fopen(valid_filename, "rb");
|
||||||
|
assert(valid_fp);
|
||||||
|
|
||||||
|
invalid_fp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stream_test_epilogue(void)
|
||||||
|
{
|
||||||
|
TEST_INFO("Freeing resources and deleting file `%s`\n", valid_filename);
|
||||||
|
assert(valid_fp);
|
||||||
|
fclose(valid_fp);
|
||||||
|
remove(valid_filename);
|
||||||
|
}
|
||||||
|
|
||||||
void stream_test_string(void)
|
void stream_test_string(void)
|
||||||
{
|
{
|
||||||
|
TEST_START();
|
||||||
sv_t test_strings[] = {
|
sv_t test_strings[] = {
|
||||||
SV("hello, world!", 13),
|
SV("hello, world!", 13),
|
||||||
SV("another string", 14),
|
SV("another string", 14),
|
||||||
@@ -49,47 +98,214 @@ void stream_test_string(void)
|
|||||||
TEST(stream_eoc(&stream), "NULL stream is always at end of content");
|
TEST(stream_eoc(&stream), "NULL stream is always at end of content");
|
||||||
stream_stop(&stream);
|
stream_stop(&stream);
|
||||||
|
|
||||||
TEST_PASSED();
|
TEST_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
void stream_test_file(void)
|
void stream_test_file(void)
|
||||||
{
|
{
|
||||||
TODO("Not implemented");
|
TEST_START();
|
||||||
|
|
||||||
|
// Test that initialising works correctly
|
||||||
|
{
|
||||||
|
stream_t stream = {0};
|
||||||
|
{
|
||||||
|
stream_err_t err = stream_init_file(&stream, valid_filename, valid_fp);
|
||||||
|
TEST(err == STREAM_ERR_OK, "Expected initialisating to be okay: %s",
|
||||||
|
stream_err_to_cstr(err));
|
||||||
|
}
|
||||||
|
TEST(stream_size(&stream) == 0, "Stream doesn't read on init: size = %lu",
|
||||||
|
stream_size(&stream));
|
||||||
|
TEST(!stream_eoc(&stream), "Stream should not be at the EoC from init.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to initialise the stream again but against a nonexistent file - we're
|
||||||
|
// expecting an error.
|
||||||
|
{
|
||||||
|
stream_t stream = {0};
|
||||||
|
{
|
||||||
|
stream_err_t err = stream_init_file(&stream, NULL, invalid_fp);
|
||||||
|
TEST(err != STREAM_ERR_OK, "Expected initialisating to not be okay: %s",
|
||||||
|
stream_err_to_cstr(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
void stream_test_peek_next(void)
|
void stream_test_peek_next(void)
|
||||||
{
|
{
|
||||||
TODO("Not implemented");
|
TEST_START();
|
||||||
|
|
||||||
|
// Valid streams
|
||||||
|
{
|
||||||
|
stream_t stream = {0};
|
||||||
|
stream_init_file(&stream, valid_filename, valid_fp);
|
||||||
|
|
||||||
|
u64 old_position = stream.position;
|
||||||
|
char c1 = stream_peek(&stream);
|
||||||
|
TEST(c1 != '\0', "Peek should provide a normal character (%c)", c1);
|
||||||
|
TEST(stream.position == old_position,
|
||||||
|
"Peek should not shift the position (%lu -> %lu)", old_position,
|
||||||
|
stream.position);
|
||||||
|
|
||||||
|
char c2 = stream_next(&stream);
|
||||||
|
TEST(c2 != '\0', "Next should provide a normal character (%c)", c2);
|
||||||
|
TEST(stream.position > old_position,
|
||||||
|
"Next should shift the position (%lu -> %lu)", old_position,
|
||||||
|
stream.position);
|
||||||
|
TEST(c2 != c1,
|
||||||
|
"Next should yield a different character (%c) to the previous peek "
|
||||||
|
"(%c)",
|
||||||
|
c2, c1);
|
||||||
|
|
||||||
|
char c3 = stream_peek(&stream);
|
||||||
|
TEST(c3 == c2,
|
||||||
|
"Peeking should yield the same character (%c) as the previous next "
|
||||||
|
"(%c)",
|
||||||
|
c3, c2);
|
||||||
|
|
||||||
|
stream_stop(&stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid streams
|
||||||
|
{
|
||||||
|
stream_t stream = {0};
|
||||||
|
stream_init_file(&stream, NULL, invalid_fp);
|
||||||
|
char c = stream_peek(&stream);
|
||||||
|
TEST(c == '\0', "Invalid streams should have an invalid peek (%c)", c);
|
||||||
|
|
||||||
|
u64 old_position = stream.position;
|
||||||
|
c = stream_next(&stream);
|
||||||
|
TEST(c == '\0', "Invalid streams should have an invalid next (%c)", c);
|
||||||
|
TEST(old_position == stream.position,
|
||||||
|
"Next on an invalid stream should not affect position (%lu -> %lu)",
|
||||||
|
old_position, stream.position);
|
||||||
|
|
||||||
|
stream_stop(&stream);
|
||||||
|
}
|
||||||
|
TEST_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
void stream_test_seek(void)
|
void stream_test_seek(void)
|
||||||
{
|
{
|
||||||
TODO("Not implemented");
|
TEST_START();
|
||||||
|
// Seeking on invalid streams
|
||||||
|
{
|
||||||
|
stream_t stream = {0};
|
||||||
|
stream_init_file(&stream, NULL, invalid_fp);
|
||||||
|
|
||||||
|
u64 old_position = stream.position;
|
||||||
|
TEST(!stream_seek_forward(&stream, 1),
|
||||||
|
"Shouldn't be possible to seek forward on an invalid stream.");
|
||||||
|
TEST(old_position == stream.position,
|
||||||
|
"Position shouldn't be affected when seeking forward on an invalid "
|
||||||
|
"stream"
|
||||||
|
"(%lu -> %lu)",
|
||||||
|
old_position, stream.position);
|
||||||
|
|
||||||
|
TEST(!stream_seek_backward(&stream, 1),
|
||||||
|
"Shouldn't be possible to seek backward on an invalid stream.");
|
||||||
|
TEST(old_position == stream.position,
|
||||||
|
"Position shouldn't be affected when seeking backward on an invalid "
|
||||||
|
"stream (%lu -> %lu)",
|
||||||
|
old_position, stream.position);
|
||||||
|
|
||||||
|
stream_stop(&stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid streams
|
||||||
|
{
|
||||||
|
stream_t stream = {0};
|
||||||
|
stream_init_file(&stream, valid_filename, valid_fp);
|
||||||
|
|
||||||
|
u64 old_position = stream.position;
|
||||||
|
TEST(stream_seek_forward(&stream, 1),
|
||||||
|
"Okay to seek forward on a valid stream.");
|
||||||
|
TEST(old_position < stream.position,
|
||||||
|
"Position should be greater than before when seeking forward on a "
|
||||||
|
"valid stream (%lu -> %lu)",
|
||||||
|
old_position, stream.position);
|
||||||
|
|
||||||
|
TEST(stream_seek_backward(&stream, 1),
|
||||||
|
"Okay to seek backward on a valid stream.");
|
||||||
|
TEST(old_position == stream.position,
|
||||||
|
"stream_seek_forward and stream_seek_backward are inverse operations");
|
||||||
|
|
||||||
|
u64 forward_offset = stream_seek_forward(&stream, ARRSIZE(words_text) * 2);
|
||||||
|
TEST(forward_offset < ARRSIZE(words_text) * 2,
|
||||||
|
"Forward seeking by offsets greater than file size clamps (%lu "
|
||||||
|
"clamps to %lu)",
|
||||||
|
ARRSIZE(words_text) * 2, forward_offset);
|
||||||
|
|
||||||
|
u64 file_size = stream_size(&stream);
|
||||||
|
u64 backward_offset = stream_seek_backward(&stream, file_size + 1);
|
||||||
|
TEST(backward_offset == file_size,
|
||||||
|
"Backward seeking by offsets greater than file size clamps (%lu "
|
||||||
|
"clamps to %lu)",
|
||||||
|
file_size + 1, backward_offset);
|
||||||
|
|
||||||
|
TEST(stream.position == 0,
|
||||||
|
"Clamped forward and clamped backward seeking "
|
||||||
|
"leads to start of stream (position=%lu)",
|
||||||
|
stream.position);
|
||||||
|
|
||||||
|
i64 r_forward_offset = (rand() % (file_size - 1)) + 1;
|
||||||
|
i64 r_backward_offset = (rand() % (file_size - 1)) + 1;
|
||||||
|
while (r_backward_offset >= r_forward_offset)
|
||||||
|
r_backward_offset = (rand() % (file_size - 1)) + 1;
|
||||||
|
|
||||||
|
TEST(stream_seek(&stream, r_forward_offset) == (u64)r_forward_offset,
|
||||||
|
"Seeking by a random positive offset (%lu) is valid",
|
||||||
|
r_forward_offset);
|
||||||
|
|
||||||
|
TEST(stream_seek(&stream, -r_backward_offset) == (u64)r_backward_offset,
|
||||||
|
"Seeking backward by a random negative offset (%lu) is valid",
|
||||||
|
r_backward_offset);
|
||||||
|
|
||||||
|
TEST(
|
||||||
|
(i64)stream.position == r_forward_offset - r_backward_offset,
|
||||||
|
"Stream position (%lu) is exactly shifted by seeking offsets described "
|
||||||
|
"above.",
|
||||||
|
stream.position);
|
||||||
|
|
||||||
|
stream_stop(&stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
void stream_test_substr(void)
|
void stream_test_substr(void)
|
||||||
{
|
{
|
||||||
|
TEST_START();
|
||||||
TODO("Not implemented");
|
TODO("Not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
void stream_test_till(void)
|
void stream_test_till(void)
|
||||||
{
|
{
|
||||||
|
TEST_START();
|
||||||
TODO("Not implemented");
|
TODO("Not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
void stream_test_while(void)
|
void stream_test_while(void)
|
||||||
{
|
{
|
||||||
|
TEST_START();
|
||||||
TODO("Not implemented");
|
TODO("Not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
void stream_test_line_col(void)
|
void stream_test_line_col(void)
|
||||||
{
|
{
|
||||||
|
TEST_START();
|
||||||
TODO("Not implemented");
|
TODO("Not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
MAKE_TEST_SUITE(STREAM_SUITE, "Stream Tests",
|
MAKE_TEST_SUITE(STREAM_SUITE, "Stream Tests",
|
||||||
|
|
||||||
MAKE_TEST_FN(stream_test_string), );
|
MAKE_TEST_FN(stream_test_prologue),
|
||||||
|
MAKE_TEST_FN(stream_test_string),
|
||||||
|
MAKE_TEST_FN(stream_test_file),
|
||||||
|
MAKE_TEST_FN(stream_test_peek_next),
|
||||||
|
MAKE_TEST_FN(stream_test_seek),
|
||||||
|
MAKE_TEST_FN(stream_test_epilogue), );
|
||||||
|
|
||||||
/* Copyright (C) 2026 Aryadev Chavali
|
/* Copyright (C) 2026 Aryadev Chavali
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
void sv_copy_test(void)
|
void sv_copy_test(void)
|
||||||
{
|
{
|
||||||
|
TEST_START();
|
||||||
static_assert(ARRSIZE(unique_words) > 3, "Expected at least 3 unique words");
|
static_assert(ARRSIZE(unique_words) > 3, "Expected at least 3 unique words");
|
||||||
for (u64 i = 0; i < 3; ++i)
|
for (u64 i = 0; i < 3; ++i)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
void symtable_test(void)
|
void symtable_test(void)
|
||||||
{
|
{
|
||||||
|
TEST_START();
|
||||||
sym_table_t table = {0};
|
sym_table_t table = {0};
|
||||||
sym_table_init(&table);
|
sym_table_init(&table);
|
||||||
for (u64 i = 0; i < ARRSIZE(words); ++i)
|
for (u64 i = 0; i < ARRSIZE(words); ++i)
|
||||||
@@ -19,7 +20,7 @@ void symtable_test(void)
|
|||||||
ARRSIZE(unique_words));
|
ARRSIZE(unique_words));
|
||||||
|
|
||||||
sym_table_free(&table);
|
sym_table_free(&table);
|
||||||
TEST_PASSED();
|
TEST_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
MAKE_TEST_SUITE(SYMTABLE_SUITE, "Symbol Table Tests",
|
MAKE_TEST_SUITE(SYMTABLE_SUITE, "Symbol Table Tests",
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
void vec_test_concat(void)
|
void vec_test_concat(void)
|
||||||
{
|
{
|
||||||
|
TEST_START();
|
||||||
sys_t system = {0};
|
sys_t system = {0};
|
||||||
sys_init(&system);
|
sys_init(&system);
|
||||||
|
|
||||||
@@ -33,11 +34,12 @@ void vec_test_concat(void)
|
|||||||
strlen(words_text));
|
strlen(words_text));
|
||||||
|
|
||||||
sys_free(&system);
|
sys_free(&system);
|
||||||
TEST_PASSED();
|
TEST_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
void vec_test_substr(void)
|
void vec_test_substr(void)
|
||||||
{
|
{
|
||||||
|
TEST_START();
|
||||||
sys_t system = {0};
|
sys_t system = {0};
|
||||||
sys_init(&system);
|
sys_init(&system);
|
||||||
// Generating substrings
|
// Generating substrings
|
||||||
@@ -66,7 +68,7 @@ void vec_test_substr(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
sys_free(&system);
|
sys_free(&system);
|
||||||
TEST_PASSED();
|
TEST_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
MAKE_TEST_SUITE(VEC_SUITE, "Vector Tests",
|
MAKE_TEST_SUITE(VEC_SUITE, "Vector Tests",
|
||||||
|
|||||||
Reference in New Issue
Block a user