/* test_lisp_api.c: Testing of constructors/destructors of Lisp expressions * Created: 2026-02-04 * Author: Aryadev Chavali * License: See end of file * Commentary: */ #include "./data.h" #include "./test.h" #include 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, }; for (u64 i = 0; i < ARRSIZE(ints); ++i) { i64 in = ints[i]; lisp_t *lisp = make_int(in); i64 out = as_smi(lisp); TEST(in == out, "%ld == %ld", in, out); } TEST_END(); } void smi_oob_test(void) { 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, }; for (u64 i = 0; i < ARRSIZE(ints); ++i) { i64 in = ints[i]; lisp_t *lisp = make_int(in); i64 out = as_smi(lisp); TEST(in != out, "%ld != %ld", in, out); } TEST_END(); } 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]; lisp_t *lisp = intern(&system, SV((char *)in, strlen(in))); 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, "`%s` == `%s`", in, out); } sys_free(&system); TEST_END(); } void sym_unique_test(void) { TEST_START(); sys_t system = {0}; sys_init(&system); sv_t symbols[] = { SV_AUTO("hello"), SV_AUTO("goodbye"), SV_AUTO("display"), SV_AUTO("@xs'a_sh;d::a-h]"), }; 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); // Let's make a list of words using `cons` lisp_t *lisp = NIL; for (u64 i = 0; i < ARRSIZE(words); ++i) { const char *word = words[i]; lisp_t *lword = intern(&system, SV((char *)word, strlen(word))); lisp = cons(&system, lword, lisp); } /* 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) { const char *expected = words[i - 1]; lisp_t *item = car(iter); char *got = as_sym(item); size_t size = MIN(strlen(expected), strlen(got)); TEST(strncmp(expected, got, size) == 0, "%s == %s", expected, got); } sys_free(&system); TEST_END(); } void sys_test(void) { TEST_START(); sys_t sys = {0}; sys_init(&sys); u64 old_memory_size = sys_cost(&sys); // Creating integers doesn't affect memory size (void)make_int(2000); TEST(sys_cost(&sys) == old_memory_size, "Making integers doesn't affect system memory size"); // Creating symbols does affect memory size and memory table (void)intern(&sys, SV_AUTO("hello world!")); TEST(sys_cost(&sys) > old_memory_size, "Interning doesn't affect system memory size"); TEST(sys.symtable.count > 0, "Interning affects symbol table"); old_memory_size = sys_cost(&sys); // Creating conses do affect memory size (void)cons(&sys, make_int(1), make_int(2)); TEST(sys_cost(&sys) > 0, "Creating conses affects memory size"); old_memory_size = sys_cost(&sys); (void)cons(&sys, intern(&sys, SV_AUTO("test")), NIL); TEST(sys_cost(&sys) > old_memory_size, "Creating conses back to back affects memory size"); old_memory_size = sys_cost(&sys); // Creating vectors does affect memory size (void)make_vec(&sys, 8); TEST(sys_cost(&sys) > old_memory_size, "Creating vectors (size 8) affects memory size"); old_memory_size = sys_cost(&sys); (void)make_vec(&sys, 1000); TEST(sys_cost(&sys) > old_memory_size, "Creating vectors (size 1000) affects memory size"); old_memory_size = sys_cost(&sys); sys_free(&sys); 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 * 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 . */