Files
alisp/test/test_lisp_api.c
Aryadev Chavali b93042fd27 lisp: INT -> SMI
when we implement big integer support, we should use INT there
instead.  SMI signals intent much better.
2026-03-05 19:41:16 +00:00

211 lines
5.6 KiB
C

/* 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 <alisp/lisp.h>
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 <https://www.gnu.org/licenses/>.
*/