Compare commits
39 Commits
master
...
a7eeedf7fb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7eeedf7fb | ||
|
|
5bb83cfab7 | ||
|
|
5a78b01a57 | ||
|
|
2c1aebc8a5 | ||
|
|
9452a14567 | ||
|
|
01fb0bf131 | ||
|
|
a662454ea7 | ||
|
|
c503acb050 | ||
|
|
fde3dbbf9a | ||
|
|
9e357cbc3b | ||
|
|
0b3d659f14 | ||
|
|
0e6a43ec5f | ||
|
|
2ddddf5774 | ||
|
|
8d3f4f896f | ||
|
|
0318dcbb65 | ||
|
|
f7cfe16c67 | ||
|
|
3612313e76 | ||
|
|
762dabd3e5 | ||
|
|
61efa91403 | ||
|
|
3add9beb59 | ||
|
|
df1076f7d7 | ||
|
|
a809d9de25 | ||
|
|
3b14144ccc | ||
|
|
bd838c02ab | ||
|
|
54e9edcba6 | ||
|
|
b32f420cb9 | ||
|
|
34d3417e74 | ||
|
|
66770f22d9 | ||
|
|
3d0e373862 | ||
|
|
0e8cdd7507 | ||
|
|
4d693c8a92 | ||
|
|
1c88253b3c | ||
|
|
de6fcd17ee | ||
|
|
91264d96e4 | ||
|
|
d88d7f7f23 | ||
|
|
16be3392b0 | ||
|
|
2705ef9bb7 | ||
|
|
45ef1fa01a | ||
|
|
9095b118fd |
4
Makefile
4
Makefile
@@ -12,8 +12,10 @@ RFLAGS=-O3
|
||||
MODE=release
|
||||
ifeq ($(MODE), release)
|
||||
CFLAGS=$(GFLAGS) $(RFLAGS)
|
||||
else
|
||||
else ifeq ($(MODE), debug)
|
||||
CFLAGS=$(GFLAGS) $(DFLAGS)
|
||||
else ifeq ($(MODE), full)
|
||||
CFLAGS=$(GFLAGS) $(DFLAGS) -DTEST_VERBOSE=1
|
||||
endif
|
||||
|
||||
# Units to compile
|
||||
|
||||
57
alisp.org
57
alisp.org
@@ -45,11 +45,61 @@ i.e. no parsing.
|
||||
*** DONE Design what a "parser function" would look like
|
||||
The general function is something like ~stream -> T | Err~. What
|
||||
other state do we need to encode?
|
||||
*** WIP Write a parser for integers
|
||||
*** TODO Write a parser for integers
|
||||
*** TODO Write a parser for symbols
|
||||
*** TODO Write a parser for lists
|
||||
*** TODO Write a parser for vectors
|
||||
*** TODO Write the general parser
|
||||
** WIP Unit tests :tests:
|
||||
*** TODO Test streams
|
||||
**** DONE Test file init
|
||||
[[file:test/test_stream.c::void stream_test_file(void)]]
|
||||
***** DONE Test successful init from real files
|
||||
Ensure stream_size is 0 i.e. we don't read anything on creation.
|
||||
Also ensure stream_eoc is false.
|
||||
***** DONE Test failed init from fake files
|
||||
**** DONE Test peeking and next
|
||||
[[file:test/test_stream.c::void stream_test_peek_next(void)]]
|
||||
- Peeking with bad streams ('\0' return)
|
||||
- Peeking with good streams (no effect on position)
|
||||
- Next with bad streams ('\0' return, no effect on position)
|
||||
- Next with good streams (effects position)
|
||||
- Peeking after next (should just work)
|
||||
**** DONE Test seeking
|
||||
[[file:test/test_stream.c::void stream_test_seek(void)]]
|
||||
- Seeking forward/backward on a bad stream (should stop at 0)
|
||||
- Seeking forward/backward too far (should clamp)
|
||||
- Seeking forward/backward zero sum via relative index (stream_seek)
|
||||
**** TODO Test substring
|
||||
[[file:test/test_stream.c::void stream_test_substr(void)]]
|
||||
- Substr on bad stream (NULL sv)
|
||||
- Substr on bad position/size (NULL sv)
|
||||
- Substr relative/absolute (good SV)
|
||||
**** TODO Test till
|
||||
[[file:test/test_stream.c::void stream_test_till(void)]]
|
||||
- till on a bad stream (NULL SV)
|
||||
- till on an ended stream (NULL SV)
|
||||
- till on a stream with no items in search string (eoc)
|
||||
- till on a stream with all items in search string (no effect)
|
||||
- till on a stream with prefix being all search string (no effect)
|
||||
- till on a stream with suffix being all search string (stops at
|
||||
suffix)
|
||||
**** TODO Test while
|
||||
[[file:test/test_stream.c::void stream_test_while(void)]]
|
||||
- while on a bad stream (NULL SV)
|
||||
- while on an ended stream (NULL SV)
|
||||
- while on a stream with no items in search string (no effect)
|
||||
- while on a stream with all items in search string (eoc)
|
||||
- while on a stream with prefix being all search string (effect)
|
||||
- while on a stream with suffix being all search string (no effect)
|
||||
**** TODO Test line_col
|
||||
[[file:test/test_stream.c::void stream_test_line_col(void)]]
|
||||
- line_col on bad stream (no effect on args)
|
||||
- line_col on eoc stream (should go right to the end)
|
||||
- line_col on random points in a stream
|
||||
*** DONE Test system registration of allocated units
|
||||
In particular, does clean up work as we expect? Do we have situations
|
||||
where we may double free or not clean up something we should've?
|
||||
** Backlog
|
||||
*** TODO Design Big Integers
|
||||
We currently have 62 bit integers implemented via immediate values
|
||||
@@ -139,9 +189,6 @@ Latter approach time complexity:
|
||||
|
||||
Former approach is better time complexity wise, but latter is way
|
||||
better in terms of simplicity of code. Must deliberate.
|
||||
*** TODO Test system registration of allocated units :test:
|
||||
In particular, does clean up work as we expect? Do we have situations
|
||||
where we may double free or not clean up something we should've?
|
||||
*** TODO Design Strings
|
||||
We have ~sv_t~ so our basic C API is done. We just need pluggable
|
||||
functions to construct and deconstruct strings as lisps.
|
||||
@@ -160,4 +207,4 @@ Test if ~make_vec~ works with ~as_vec~, ~cons~ with ~as_cons~ AND
|
||||
We may need to think of effective ways to deal with NILs in ~car~ and
|
||||
~cdr~. Maybe make functions as well as the macros so I can choose
|
||||
between them?
|
||||
**** DONE Write more tests
|
||||
*** DONE Write more tests
|
||||
|
||||
@@ -49,6 +49,8 @@ vec_t *as_vec(lisp_t *);
|
||||
lisp_t *car(lisp_t *);
|
||||
lisp_t *cdr(lisp_t *);
|
||||
|
||||
void lisp_free(lisp_t *);
|
||||
|
||||
#endif
|
||||
|
||||
/* Copyright (C) 2026 Aryadev Chavali
|
||||
|
||||
@@ -40,7 +40,7 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
stream_type_t type;
|
||||
char *name;
|
||||
const char *name;
|
||||
u64 position;
|
||||
union
|
||||
{
|
||||
@@ -51,9 +51,9 @@ typedef struct
|
||||
|
||||
#define STREAM_DEFAULT_CHUNK 64
|
||||
|
||||
stream_err_t stream_init_string(stream_t *, char *, sv_t);
|
||||
stream_err_t stream_init_pipe(stream_t *, char *, FILE *);
|
||||
stream_err_t stream_init_file(stream_t *, char *, FILE *);
|
||||
stream_err_t stream_init_string(stream_t *, const char *, sv_t);
|
||||
stream_err_t stream_init_pipe(stream_t *, const char *, FILE *);
|
||||
stream_err_t stream_init_file(stream_t *, const char *, FILE *);
|
||||
void stream_stop(stream_t *);
|
||||
|
||||
// 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
|
||||
char stream_peek(stream_t *);
|
||||
// Move forward or backward in the stream, return success of operation
|
||||
bool stream_seek(stream_t *, i64);
|
||||
bool stream_seek_forward(stream_t *, u64);
|
||||
bool stream_seek_backward(stream_t *, u64);
|
||||
u64 stream_seek(stream_t *, i64);
|
||||
u64 stream_seek_forward(stream_t *, u64);
|
||||
u64 stream_seek_backward(stream_t *, u64);
|
||||
|
||||
// Return a relative substring of a given size
|
||||
sv_t stream_substr(stream_t *, u64);
|
||||
|
||||
@@ -22,7 +22,7 @@ typedef struct
|
||||
|
||||
void sym_table_init(sym_table_t *);
|
||||
char *sym_table_find(sym_table_t *, sv_t);
|
||||
void sym_table_cleanup(sym_table_t *);
|
||||
void sym_table_free(sym_table_t *);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
47
src/lisp.c
47
src/lisp.c
@@ -26,7 +26,7 @@ void sys_free(sys_t *sys)
|
||||
{
|
||||
static_assert(NUM_TAGS == 5);
|
||||
|
||||
sym_table_cleanup(&sys->symtable);
|
||||
sym_table_free(&sys->symtable);
|
||||
if (sys->memory.size == 0)
|
||||
return;
|
||||
|
||||
@@ -34,26 +34,7 @@ void sys_free(sys_t *sys)
|
||||
for (size_t i = 0; i < VEC_SIZE(&sys->memory, lisp_t **); ++i)
|
||||
{
|
||||
lisp_t *allocated = VEC_GET(&sys->memory, i, lisp_t *);
|
||||
switch (get_tag(allocated))
|
||||
{
|
||||
case TAG_CONS:
|
||||
// Delete the cons
|
||||
free(as_cons(allocated));
|
||||
break;
|
||||
case TAG_VEC:
|
||||
{
|
||||
vec_t *vec = as_vec(allocated);
|
||||
vec_free(vec);
|
||||
free(vec);
|
||||
break;
|
||||
}
|
||||
case TAG_NIL:
|
||||
case TAG_INT:
|
||||
case TAG_SYM:
|
||||
case NUM_TAGS:
|
||||
// shouldn't be dealt with (either constant or dealt with elsewhere)
|
||||
break;
|
||||
}
|
||||
lisp_free(allocated);
|
||||
}
|
||||
|
||||
// Free the container
|
||||
@@ -110,6 +91,30 @@ lisp_t *cdr(lisp_t *lsp)
|
||||
return CDR(lsp);
|
||||
}
|
||||
|
||||
void lisp_free(lisp_t *item)
|
||||
{
|
||||
switch (get_tag(item))
|
||||
{
|
||||
case TAG_CONS:
|
||||
// Delete the cons
|
||||
free(as_cons(item));
|
||||
break;
|
||||
case TAG_VEC:
|
||||
{
|
||||
vec_t *vec = as_vec(item);
|
||||
vec_free(vec);
|
||||
free(vec);
|
||||
break;
|
||||
}
|
||||
case TAG_NIL:
|
||||
case TAG_INT:
|
||||
case TAG_SYM:
|
||||
case NUM_TAGS:
|
||||
// shouldn't be dealt with (either constant or dealt with elsewhere)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copyright (C) 2025, 2026 Aryadev Chavali
|
||||
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
|
||||
15
src/main.c
15
src/main.c
@@ -23,7 +23,10 @@ void usage(FILE *fp)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret = 0;
|
||||
int ret = 0;
|
||||
FILE *pipe = NULL;
|
||||
stream_t stream = {0};
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
usage(stderr);
|
||||
@@ -35,8 +38,6 @@ int main(int argc, char *argv[])
|
||||
TODO("alisp doesn't support multiple files currently.");
|
||||
}
|
||||
|
||||
FILE *fp = NULL;
|
||||
stream_t stream = {0};
|
||||
if (strncmp(argv[1], "--", 2) == 0)
|
||||
{
|
||||
stream_err_t err = stream_init_pipe(&stream, "stdin", stdin);
|
||||
@@ -55,8 +56,8 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
else
|
||||
{
|
||||
fp = fopen(argv[1], "rb");
|
||||
stream_err_t err = stream_init_file(&stream, argv[1], fp);
|
||||
pipe = fopen(argv[1], "rb");
|
||||
stream_err_t err = stream_init_file(&stream, argv[1], pipe);
|
||||
if (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);
|
||||
end:
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
if (pipe)
|
||||
fclose(pipe);
|
||||
stream_stop(&stream);
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
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->pipe.file = pipe;
|
||||
|
||||
vec_init(&stream->pipe.cache, STREAM_DEFAULT_CHUNK);
|
||||
|
||||
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)
|
||||
return stream_seek_backward(stream, offset * -1);
|
||||
@@ -247,20 +246,20 @@ bool stream_seek(stream_t *stream, i64 offset)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool stream_seek_forward(stream_t *stream, u64 offset)
|
||||
u64 stream_seek_forward(stream_t *stream, u64 offset)
|
||||
{
|
||||
if (stream_eoc(stream))
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
switch (stream->type)
|
||||
{
|
||||
case STREAM_TYPE_STRING:
|
||||
{
|
||||
if (stream->position + offset >= stream->string.size)
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
stream->position += offset;
|
||||
return true;
|
||||
return offset;
|
||||
}
|
||||
case STREAM_TYPE_PIPE:
|
||||
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)
|
||||
{
|
||||
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
|
||||
@@ -283,9 +282,11 @@ bool stream_seek_forward(stream_t *stream, u64 offset)
|
||||
|
||||
// Same principle as the stream_eoc(stream) check.
|
||||
if (stream->position + offset > stream->pipe.cache.size)
|
||||
return false;
|
||||
{
|
||||
offset = stream->pipe.cache.size - stream->position;
|
||||
}
|
||||
stream->position += offset;
|
||||
return true;
|
||||
return offset;
|
||||
}
|
||||
default:
|
||||
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);
|
||||
if (stream->position < offset)
|
||||
return false;
|
||||
{
|
||||
offset = stream->position;
|
||||
}
|
||||
|
||||
stream->position -= offset;
|
||||
return true;
|
||||
return offset;
|
||||
}
|
||||
|
||||
sv_t stream_substr(stream_t *stream, u64 size)
|
||||
|
||||
4
src/sv.c
4
src/sv.c
@@ -12,6 +12,10 @@
|
||||
|
||||
sv_t sv_copy(sv_t old)
|
||||
{
|
||||
if (old.size == 0)
|
||||
return SV(old.data, 0);
|
||||
else if (old.data == NULL)
|
||||
return SV(NULL, old.size);
|
||||
char *newstr = calloc(1, (old.size + 1) * sizeof(*newstr));
|
||||
memcpy(newstr, old.data, old.size);
|
||||
newstr[old.size] = '\0';
|
||||
|
||||
@@ -54,7 +54,7 @@ char *sym_table_find(sym_table_t *table, sv_t sv)
|
||||
return ENTRY_GET(table, index).data;
|
||||
}
|
||||
|
||||
void sym_table_cleanup(sym_table_t *table)
|
||||
void sym_table_free(sym_table_t *table)
|
||||
{
|
||||
// Iterate through the strings and free each of them.
|
||||
sv_t current = {0};
|
||||
|
||||
11
test/main.c
11
test/main.c
@@ -6,28 +6,33 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "./data.h"
|
||||
#include "./test.h"
|
||||
|
||||
#include "./test_lisp_api.c"
|
||||
#include "./test_stream.c"
|
||||
#include "./test_sv.c"
|
||||
#include "./test_symtable.c"
|
||||
#include "./test_vec.c"
|
||||
|
||||
test_suite_t SUITES[] = {
|
||||
LISP_API_SUITE,
|
||||
VEC_SUITE,
|
||||
SV_SUITE, VEC_SUITE, SYMTABLE_SUITE, STREAM_SUITE, LISP_API_SUITE,
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Seed the pseudorandom gen for subsequent tests.
|
||||
srand(time(NULL));
|
||||
for (u64 i = 0; i < ARRSIZE(SUITES); ++i)
|
||||
{
|
||||
test_suite_t suite = SUITES[i];
|
||||
printf("Suite [%s]\n", suite.name);
|
||||
for (u64 j = 0; j < suite.size; ++j)
|
||||
{
|
||||
printf("[%s]: Running...\n", suite.tests[j].name);
|
||||
suite.tests[j].fn();
|
||||
}
|
||||
}
|
||||
|
||||
72
test/test.h
72
test/test.h
@@ -10,27 +10,50 @@
|
||||
|
||||
#include <alisp/alisp.h>
|
||||
|
||||
#define TEST_PASSED() printf("[%s]: Passed\n", __func__)
|
||||
#define TEST(COND, ...) \
|
||||
do \
|
||||
{ \
|
||||
bool cond = (COND); \
|
||||
if (!cond) \
|
||||
{ \
|
||||
printf("\tFAIL: "); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
printf("\tPASS: "); \
|
||||
} \
|
||||
printf("%s => ", #COND); \
|
||||
printf(__VA_ARGS__); \
|
||||
printf("\n"); \
|
||||
if (!cond) \
|
||||
{ \
|
||||
assert(0); \
|
||||
} \
|
||||
#ifndef TEST_VERBOSE
|
||||
#define TEST_VERBOSE 0
|
||||
#endif
|
||||
|
||||
#define TEST_END() printf("\t[%s]: Passed\n", __func__)
|
||||
#define TEST_INFO(...) \
|
||||
do \
|
||||
{ \
|
||||
printf("\tINFO: "); \
|
||||
printf(__VA_ARGS__); \
|
||||
} while (0);
|
||||
|
||||
#if TEST_VERBOSE
|
||||
#define TEST_START() printf("\t[%s]: Running...\n", __func__)
|
||||
#define TEST(COND, ...) \
|
||||
do \
|
||||
{ \
|
||||
bool cond = (COND); \
|
||||
if (!cond) \
|
||||
{ \
|
||||
printf("\t\tFAIL: "); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
printf("\t\tPASS: "); \
|
||||
} \
|
||||
printf(__VA_ARGS__); \
|
||||
printf("\n\t\t [%s]\n", #COND); \
|
||||
if (!cond) \
|
||||
{ \
|
||||
assert(0); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define TEST_START()
|
||||
#define TEST(COND, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (!(COND)) \
|
||||
{ \
|
||||
assert(0); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
typedef struct TestFn
|
||||
{
|
||||
@@ -47,8 +70,13 @@ typedef struct
|
||||
const u64 size;
|
||||
} test_suite_t;
|
||||
|
||||
#define MAKE_TEST_SUITE(NAME) \
|
||||
{.name = #NAME, .tests = NAME, .size = ARRSIZE(NAME)}
|
||||
#define MAKE_TEST_SUITE(NAME, DESC, ...) \
|
||||
const test_fn NAME##_TESTS[] = {__VA_ARGS__}; \
|
||||
const test_suite_t NAME = { \
|
||||
.name = DESC, \
|
||||
.tests = NAME##_TESTS, \
|
||||
.size = ARRSIZE(NAME##_TESTS), \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -10,8 +10,11 @@
|
||||
|
||||
#include <alisp/lisp.h>
|
||||
|
||||
void int_test(void)
|
||||
void smi_test(void)
|
||||
{
|
||||
TEST_START();
|
||||
// Standard old testing, checking both sides of the number line and our set
|
||||
// bounds.
|
||||
i64 ints[] = {
|
||||
1, -1, (1 << 10) - 1, (-1) * ((1 << 10) - 1), INT_MIN, INT_MAX,
|
||||
};
|
||||
@@ -25,31 +28,41 @@ void int_test(void)
|
||||
TEST(in == out, "%ld == %ld", in, out);
|
||||
}
|
||||
|
||||
TEST_PASSED();
|
||||
TEST_END();
|
||||
}
|
||||
|
||||
void symtable_test(void)
|
||||
void smi_oob_test(void)
|
||||
{
|
||||
sym_table_t table = {0};
|
||||
sym_table_init(&table);
|
||||
for (u64 i = 0; i < ARRSIZE(words); ++i)
|
||||
sym_table_find(&table, SV((char *)words[i], strlen(words[i])));
|
||||
TEST_START();
|
||||
// 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.
|
||||
i64 ints[] = {
|
||||
INT_MIN - 1,
|
||||
INT_MAX + 1,
|
||||
INT64_MIN,
|
||||
INT64_MAX,
|
||||
};
|
||||
|
||||
TEST(table.count == ARRSIZE(unique_words), "%lu == %lu", table.count,
|
||||
ARRSIZE(unique_words));
|
||||
for (u64 i = 0; i < ARRSIZE(ints); ++i)
|
||||
{
|
||||
i64 in = ints[i];
|
||||
lisp_t *lisp = make_int(in);
|
||||
i64 out = as_int(lisp);
|
||||
|
||||
TEST(table.count < ARRSIZE(unique_words), "%lu < %lu", table.count,
|
||||
ARRSIZE(unique_words));
|
||||
TEST(in != out, "%ld != %ld", in, out);
|
||||
}
|
||||
|
||||
TEST_PASSED();
|
||||
|
||||
sym_table_cleanup(&table);
|
||||
TEST_END();
|
||||
}
|
||||
|
||||
void sym_test(void)
|
||||
void sym_fresh_test(void)
|
||||
{
|
||||
TEST_START();
|
||||
sys_t system = {0};
|
||||
sys_init(&system);
|
||||
|
||||
// We expect every interned symbol to get a fresh allocation, but still be a
|
||||
// valid representation of the original symbol.
|
||||
for (u64 i = 0; i < ARRSIZE(words); ++i)
|
||||
{
|
||||
const char *in = words[i];
|
||||
@@ -57,14 +70,48 @@ void sym_test(void)
|
||||
char *out = as_sym(lisp);
|
||||
TEST(in != out, "%p != %p", in, out);
|
||||
TEST(strlen(in) == strlen(out), "%zu == %zu", strlen(in), strlen(out));
|
||||
TEST(strncmp(in, out, strlen(in)) == 0, "%d", strncmp(in, out, strlen(in)));
|
||||
TEST(strncmp(in, out, strlen(in)) == 0, "`%s` == `%s`", in, out);
|
||||
}
|
||||
TEST_PASSED();
|
||||
|
||||
sys_free(&system);
|
||||
TEST_END();
|
||||
}
|
||||
|
||||
void sym_unique_test(void)
|
||||
{
|
||||
TEST_START();
|
||||
sys_t system = {0};
|
||||
sys_init(&system);
|
||||
|
||||
sv_t symbols[] = {
|
||||
SV("hello", 5),
|
||||
SV("goodbye", 7),
|
||||
SV("display", 7),
|
||||
SV("@xs'a_sh;d::a-h]", 16),
|
||||
};
|
||||
|
||||
lisp_t *ptrs[ARRSIZE(symbols)];
|
||||
for (u64 i = 0; i < ARRSIZE(symbols); ++i)
|
||||
{
|
||||
ptrs[i] = intern(&system, symbols[i]);
|
||||
TEST(ptrs[i] != 0, "%p (derived from `" PR_SV "`) is not NIL",
|
||||
(void *)ptrs[i], SV_FMT(symbols[i]));
|
||||
}
|
||||
|
||||
for (u64 i = 0; i < ARRSIZE(symbols); ++i)
|
||||
{
|
||||
lisp_t *newptr = intern(&system, symbols[i]);
|
||||
TEST(newptr == ptrs[i], "interning again (%p) gives us the same (%p)",
|
||||
(void *)newptr, (void *)ptrs[i]);
|
||||
}
|
||||
|
||||
sys_free(&system);
|
||||
TEST_END();
|
||||
}
|
||||
|
||||
void cons_test(void)
|
||||
{
|
||||
TEST_START();
|
||||
sys_t system = {0};
|
||||
sys_init(&system);
|
||||
|
||||
@@ -77,7 +124,13 @@ void cons_test(void)
|
||||
lisp = cons(&system, lword, lisp);
|
||||
}
|
||||
|
||||
// Make sure we've essentially reversed the `words` array
|
||||
/*
|
||||
As we've cons'd each word, we'd expect the order to be reversed. This test
|
||||
will allow us to verify:
|
||||
1) words have actually been added to the linked list.
|
||||
2) words are in the order we expect.
|
||||
in one go.
|
||||
*/
|
||||
u64 i = ARRSIZE(words);
|
||||
for (lisp_t *iter = lisp; iter; iter = cdr(iter), --i)
|
||||
{
|
||||
@@ -89,22 +142,61 @@ void cons_test(void)
|
||||
TEST(strncmp(expected, got, size) == 0, "%s == %s", expected, got);
|
||||
}
|
||||
|
||||
TEST_PASSED();
|
||||
|
||||
sys_free(&system);
|
||||
TEST_END();
|
||||
}
|
||||
|
||||
const test_fn TESTS_LISP_API[] = {
|
||||
MAKE_TEST_FN(int_test),
|
||||
MAKE_TEST_FN(sym_test),
|
||||
MAKE_TEST_FN(cons_test),
|
||||
};
|
||||
void sys_test(void)
|
||||
{
|
||||
TEST_START();
|
||||
sys_t sys = {0};
|
||||
sys_init(&sys);
|
||||
u64 old_memory_size = sys.memory.size;
|
||||
|
||||
const test_suite_t LISP_API_SUITE = {
|
||||
.name = "Lisp API Tests",
|
||||
.tests = TESTS_LISP_API,
|
||||
.size = ARRSIZE(TESTS_LISP_API),
|
||||
};
|
||||
// Creating integers doesn't affect memory size
|
||||
(void)make_int(2000);
|
||||
TEST(sys.memory.size == old_memory_size,
|
||||
"Making integers doesn't affect system memory size");
|
||||
|
||||
// Creating symbols won't affect memory size, but does affect the symbol table
|
||||
(void)intern(&sys, SV("hello world!", 12));
|
||||
TEST(sys.memory.size == old_memory_size,
|
||||
"Interning doesn't affect system memory size");
|
||||
TEST(sys.symtable.count > 0, "Interning affects symbol table");
|
||||
|
||||
// Creating conses do affect memory size
|
||||
(void)cons(&sys, make_int(1), make_int(2));
|
||||
TEST(sys.memory.size > 0, "Creating conses affects memory size");
|
||||
old_memory_size = sys.memory.size;
|
||||
|
||||
(void)cons(&sys, intern(&sys, SV("test", 4)), NIL);
|
||||
TEST(sys.memory.size > old_memory_size,
|
||||
"Creating conses back to back affects memory size");
|
||||
old_memory_size = sys.memory.size;
|
||||
|
||||
// Creating vectors does affect memory size
|
||||
(void)make_vec(&sys, 8);
|
||||
TEST(sys.memory.size > old_memory_size,
|
||||
"Creating vectors (size 8) affects memory size");
|
||||
old_memory_size = sys.memory.size;
|
||||
|
||||
(void)make_vec(&sys, 1000);
|
||||
TEST(sys.memory.size > old_memory_size,
|
||||
"Creating vectors (size 1000) affects memory size");
|
||||
old_memory_size = sys.memory.size;
|
||||
|
||||
sys_free(&sys);
|
||||
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_END();
|
||||
}
|
||||
|
||||
MAKE_TEST_SUITE(LISP_API_SUITE, "LISP API Tests",
|
||||
|
||||
MAKE_TEST_FN(smi_test), MAKE_TEST_FN(smi_oob_test),
|
||||
MAKE_TEST_FN(sym_fresh_test), MAKE_TEST_FN(sym_unique_test),
|
||||
MAKE_TEST_FN(cons_test), MAKE_TEST_FN(sys_test), );
|
||||
|
||||
/* Copyright (C) 2026 Aryadev Chavali
|
||||
|
||||
|
||||
321
test/test_stream.c
Normal file
321
test/test_stream.c
Normal file
@@ -0,0 +1,321 @@
|
||||
/* test_stream.c: Stream tests
|
||||
* Created: 2026-02-05
|
||||
* Author: Aryadev Chavali
|
||||
* License: See end of file
|
||||
* Commentary:
|
||||
*/
|
||||
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "./data.h"
|
||||
#include "./test.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)
|
||||
{
|
||||
TEST_START();
|
||||
sv_t test_strings[] = {
|
||||
SV("hello, world!", 13),
|
||||
SV("another string", 14),
|
||||
SV((char *)text, ARRSIZE(text) / 2),
|
||||
};
|
||||
|
||||
for (u64 i = 0; i < ARRSIZE(test_strings); ++i)
|
||||
{
|
||||
sv_t copy = sv_copy(test_strings[i]);
|
||||
|
||||
stream_t stream = {0};
|
||||
stream_err_t err = stream_init_string(&stream, NULL, test_strings[i]);
|
||||
TEST(err == STREAM_ERR_OK, "Stream initialising did not fail: %s",
|
||||
stream_err_to_cstr(err));
|
||||
TEST(stream_size(&stream) == test_strings[i].size,
|
||||
"Stream size is always string size (%lu == %lu)", stream_size(&stream),
|
||||
test_strings[i].size);
|
||||
TEST(!stream_eoc(&stream), "Not end of content already");
|
||||
|
||||
stream_stop(&stream);
|
||||
TEST(strncmp(copy.data, test_strings[i].data, copy.size) == 0,
|
||||
"Freeing a stream does not free the underlying memory it was derived "
|
||||
"from");
|
||||
|
||||
free(copy.data);
|
||||
}
|
||||
|
||||
stream_t stream = {0};
|
||||
stream_err_t err = stream_init_string(&stream, NULL, SV(NULL, 0));
|
||||
TEST(err == STREAM_ERR_OK, "NULL stream initialising did not fail: %s",
|
||||
stream_err_to_cstr(err));
|
||||
TEST(stream_size(&stream) == 0, "NULL stream size is 0");
|
||||
TEST(stream_eoc(&stream), "NULL stream is always at end of content");
|
||||
stream_stop(&stream);
|
||||
|
||||
TEST_END();
|
||||
}
|
||||
|
||||
void stream_test_file(void)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
TEST_START();
|
||||
TODO("Not implemented");
|
||||
}
|
||||
|
||||
void stream_test_till(void)
|
||||
{
|
||||
TEST_START();
|
||||
TODO("Not implemented");
|
||||
}
|
||||
|
||||
void stream_test_while(void)
|
||||
{
|
||||
TEST_START();
|
||||
TODO("Not implemented");
|
||||
}
|
||||
|
||||
void stream_test_line_col(void)
|
||||
{
|
||||
TEST_START();
|
||||
TODO("Not implemented");
|
||||
}
|
||||
|
||||
MAKE_TEST_SUITE(STREAM_SUITE, "Stream Tests",
|
||||
|
||||
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
|
||||
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License Version 2 for
|
||||
* details.
|
||||
|
||||
* You may distribute and modify this code under the terms of the GNU General
|
||||
* Public License Version 2, which you should have received a copy of along with
|
||||
* this program. If not, please go to <https://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
45
test/test_sv.c
Normal file
45
test/test_sv.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/* test_sv.c: String View tests
|
||||
* Created: 2026-02-05
|
||||
* Author: Aryadev Chavali
|
||||
* License: See end of file
|
||||
* Commentary:
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "./data.h"
|
||||
#include "./test.h"
|
||||
|
||||
void sv_copy_test(void)
|
||||
{
|
||||
TEST_START();
|
||||
static_assert(ARRSIZE(unique_words) > 3, "Expected at least 3 unique words");
|
||||
for (u64 i = 0; i < 3; ++i)
|
||||
{
|
||||
sv_t word = SV((char *)unique_words[i], strlen(unique_words[i]));
|
||||
sv_t copy = sv_copy(word);
|
||||
TEST(word.data != copy.data, "%p != %p", word.data, copy.data);
|
||||
TEST(word.size == copy.size, "%lu == %lu", word.size, copy.size);
|
||||
TEST(strncmp(word.data, copy.data, copy.size) == 0, "`%s` == `%s`",
|
||||
word.data, copy.data);
|
||||
|
||||
// Obviously we can't just have this lying around.
|
||||
free(copy.data);
|
||||
}
|
||||
}
|
||||
|
||||
MAKE_TEST_SUITE(SV_SUITE, "String View Tests", MAKE_TEST_FN(sv_copy_test), );
|
||||
|
||||
/* Copyright (C) 2026 Aryadev Chavali
|
||||
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License Version 2 for
|
||||
* details.
|
||||
|
||||
* You may distribute and modify this code under the terms of the GNU General
|
||||
* Public License Version 2, which you should have received a copy of along with
|
||||
* this program. If not, please go to <https://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
41
test/test_symtable.c
Normal file
41
test/test_symtable.c
Normal file
@@ -0,0 +1,41 @@
|
||||
/* test_symtable.c: Symbol table tests
|
||||
* Created: 2026-02-05
|
||||
* Author: Aryadev Chavali
|
||||
* License: See end of file
|
||||
* Commentary:
|
||||
*/
|
||||
|
||||
#include "./data.h"
|
||||
#include "./test.h"
|
||||
|
||||
void symtable_test(void)
|
||||
{
|
||||
TEST_START();
|
||||
sym_table_t table = {0};
|
||||
sym_table_init(&table);
|
||||
for (u64 i = 0; i < ARRSIZE(words); ++i)
|
||||
sym_table_find(&table, SV((char *)words[i], strlen(words[i])));
|
||||
|
||||
TEST(table.count == ARRSIZE(unique_words), "%lu == %lu", table.count,
|
||||
ARRSIZE(unique_words));
|
||||
|
||||
sym_table_free(&table);
|
||||
TEST_END();
|
||||
}
|
||||
|
||||
MAKE_TEST_SUITE(SYMTABLE_SUITE, "Symbol Table Tests",
|
||||
|
||||
MAKE_TEST_FN(symtable_test), );
|
||||
|
||||
/* Copyright (C) 2026 Aryadev Chavali
|
||||
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License Version 2 for
|
||||
* details.
|
||||
|
||||
* You may distribute and modify this code under the terms of the GNU General
|
||||
* Public License Version 2, which you should have received a copy of along with
|
||||
* this program. If not, please go to <https://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
@@ -8,8 +8,9 @@
|
||||
#include "./data.h"
|
||||
#include "./test.h"
|
||||
|
||||
void vec_test1(void)
|
||||
void vec_test_concat(void)
|
||||
{
|
||||
TEST_START();
|
||||
sys_t system = {0};
|
||||
sys_init(&system);
|
||||
|
||||
@@ -28,15 +29,17 @@ void vec_test1(void)
|
||||
|
||||
TEST(vec->size == ARRSIZE(words_text), "%lu == %lu", vec->size,
|
||||
ARRSIZE(words_text));
|
||||
TEST(strncmp((char *)vec_data(vec), words_text, vec->size) == 0, "%d",
|
||||
strncmp((char *)vec_data(vec), words_text, vec->size));
|
||||
TEST(strncmp((char *)vec_data(vec), words_text, vec->size) == 0,
|
||||
"%p@%lu == %p@%lu", (char *)vec_data(vec), vec->size, words_text,
|
||||
strlen(words_text));
|
||||
|
||||
TEST_PASSED();
|
||||
sys_free(&system);
|
||||
TEST_END();
|
||||
}
|
||||
|
||||
void vec_test2(void)
|
||||
void vec_test_substr(void)
|
||||
{
|
||||
TEST_START();
|
||||
sys_t system = {0};
|
||||
sys_init(&system);
|
||||
// Generating substrings
|
||||
@@ -60,24 +63,17 @@ void vec_test2(void)
|
||||
vec_append(as_vec(lvec), text + test.start, test.size);
|
||||
TEST(as_vec(lvec)->size > size, "%lu > %lu", as_vec(lvec)->size, size);
|
||||
TEST(strncmp((char *)vec_data(as_vec(lvec)), substr.data, substr.size) == 0,
|
||||
"%d",
|
||||
strncmp((char *)vec_data(as_vec(lvec)), substr.data, substr.size));
|
||||
"%p@%lu == %p@%lu", (char *)vec_data(as_vec(lvec)), as_vec(lvec)->size,
|
||||
substr.data, substr.size);
|
||||
}
|
||||
|
||||
TEST_PASSED();
|
||||
sys_free(&system);
|
||||
TEST_END();
|
||||
}
|
||||
|
||||
const test_fn TESTS_VEC[] = {
|
||||
MAKE_TEST_FN(vec_test1),
|
||||
MAKE_TEST_FN(vec_test2),
|
||||
};
|
||||
MAKE_TEST_SUITE(VEC_SUITE, "Vector Tests",
|
||||
|
||||
const test_suite_t VEC_SUITE = {
|
||||
.name = "Vector Tests",
|
||||
.tests = TESTS_VEC,
|
||||
.size = ARRSIZE(TESTS_VEC),
|
||||
};
|
||||
MAKE_TEST_FN(vec_test_concat), MAKE_TEST_FN(vec_test_substr), );
|
||||
|
||||
/* Copyright (C) 2026 Aryadev Chavali
|
||||
|
||||
|
||||
Reference in New Issue
Block a user