270 lines
6.0 KiB
C
270 lines
6.0 KiB
C
#include <stdlib.h>
|
|
#include <unity.h>
|
|
#include <string.h>
|
|
|
|
#include "testing_helpers.h"
|
|
|
|
#include "uclisp.h"
|
|
#include "common.h"
|
|
#include "scope.h"
|
|
#include "builtins.h"
|
|
#include "special.h"
|
|
|
|
static struct ucl *state;
|
|
static struct ucl_object *input;
|
|
static struct ucl_object *response;
|
|
|
|
void setUp(void) {
|
|
input = NULL;
|
|
response = NULL;
|
|
state = ucl_create();
|
|
}
|
|
|
|
void tearDown(void) {
|
|
// TODO: Actually release resources
|
|
state = NULL;
|
|
input = NULL;
|
|
response = NULL;
|
|
}
|
|
|
|
static struct ucl_object *eval (const char *code) {
|
|
struct ucl_object *sexp = ucl_parse(state, code);
|
|
return ucl_evaluate(state, ucl_car(state, sexp));
|
|
}
|
|
|
|
void test_simple_add(void) {
|
|
response = eval("(+ 2 3)");
|
|
TEST_ASSERT_OBJ_INT_V(response, 5);
|
|
}
|
|
|
|
void test_simple_let(void) {
|
|
response = eval("(let ((x 2)) (+ x 3))");
|
|
TEST_ASSERT_OBJ_INT_V(response, 5);
|
|
}
|
|
|
|
void test_let_assignment_error(void) {
|
|
response = eval("(let ((x (error \"foo\"))) (+ x 3))");
|
|
TEST_ASSERT_OBJ_ERROR(response);
|
|
}
|
|
|
|
void test_nested_let(void) {
|
|
response = eval("(let ((x 2)) (let ((y 5)) (+ x y)))");
|
|
TEST_ASSERT_OBJ_INT_V(response, 7);
|
|
}
|
|
|
|
void test_nested_let_scope(void) {
|
|
response = eval("(let ((x 2)) (let ((y 5)) (+ x y)) y)");
|
|
TEST_ASSERT_OBJ_ERROR(response);
|
|
}
|
|
|
|
void test_multi_let(void) {
|
|
response = eval("(let ((x 2)(y 5)) (+ x y))");
|
|
TEST_ASSERT_OBJ_INT_V(response, 7);
|
|
}
|
|
|
|
void test_let_return_sym(void) {
|
|
response = eval("(let ((x 2)) x)");
|
|
TEST_ASSERT_OBJ_INT_V(response, 2);
|
|
}
|
|
|
|
void test_eval_int(void) {
|
|
response = eval("2");
|
|
TEST_ASSERT_OBJ_INT_V(response, 2);
|
|
}
|
|
|
|
void test_eval_string(void) {
|
|
response = eval("\"foo\"");
|
|
TEST_ASSERT_OBJ_STRING_V(response, "foo");
|
|
}
|
|
|
|
void test_eval_sym_defined(void) {
|
|
ucl_scope_put(state, state->global_scope, "foo", ucl_int_create(state, 2));
|
|
response = eval("foo");
|
|
TEST_ASSERT_OBJ_INT_V(response, 2);
|
|
}
|
|
|
|
void test_eval_sym_undefined(void) {
|
|
response = eval("foo");
|
|
TEST_ASSERT_OBJ_ERROR(response);
|
|
}
|
|
|
|
void test_eval_nested_error(void) {
|
|
response = eval("(+ (error \"foo\") 3)");
|
|
TEST_ASSERT_OBJ_ERROR(response);
|
|
}
|
|
|
|
void test_eval_list(void) {
|
|
response = eval("(list 1 2 3)");
|
|
TEST_ASSERT_LIST_LEN(response, 3);
|
|
|
|
int i = 1;
|
|
FOREACH_LIST(response, iter, item) {
|
|
TEST_ASSERT_EQUAL(item->integer, i);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
void test_eval_defun(void) {
|
|
response = eval("(defun foo (a b) (+ a b))");
|
|
|
|
TEST_ASSERT_OBJ_SYMBOL_V(response, "foo");
|
|
}
|
|
|
|
void test_call_function(void) {
|
|
response = eval("(defun foo (a b) (+ a b))");
|
|
|
|
TEST_ASSERT_OBJ_SYMBOL(response);
|
|
TEST_ASSERT_EQUAL_STRING(response->symbol, "foo");
|
|
|
|
response = eval("(foo 2 3)");
|
|
|
|
TEST_ASSERT_OBJ_INT(response);
|
|
TEST_ASSERT_EQUAL(response->integer, 5);
|
|
}
|
|
|
|
void test_setq(void) {
|
|
response = eval("(setq bar 123)");
|
|
|
|
TEST_ASSERT_OBJ_INT_V(response, 123);
|
|
|
|
response = eval("bar");
|
|
|
|
TEST_ASSERT_OBJ_INT_V(response, 123);
|
|
}
|
|
|
|
void test_setq_from_function(void) {
|
|
response = eval("(setq bar 1)");
|
|
|
|
TEST_ASSERT_OBJ_INT_V(response, 1);
|
|
|
|
response = eval("(defun foo (a) (setq bar a))");
|
|
|
|
TEST_ASSERT_OBJ_SYMBOL_V(response, "foo");
|
|
|
|
response = eval("(foo 2)");
|
|
|
|
TEST_ASSERT_OBJ_INT_V(response, 2);
|
|
|
|
response = eval("bar");
|
|
|
|
TEST_ASSERT_OBJ_INT_V(response, 1);
|
|
}
|
|
|
|
void test_lambda(void) {
|
|
response = eval("((lambda (x) (+ x 2)) 2)");
|
|
|
|
TEST_ASSERT_OBJ_INT_V(response, 4);
|
|
}
|
|
|
|
void test_mapcar_lambda(void) {
|
|
response = eval("(car (mapcar (quote (lambda (x) (+ x 2))) (list 5)))");
|
|
|
|
TEST_ASSERT_OBJ_INT_V(response, 7);
|
|
}
|
|
|
|
void test_mapcar_function(void) {
|
|
response = eval("(defun foo (a) (+ a 2))");
|
|
|
|
TEST_ASSERT_OBJ_SYMBOL(response);
|
|
TEST_ASSERT_EQUAL_STRING(response->symbol, "foo");
|
|
|
|
response = eval("(car (mapcar (quote foo) (list 5)))");
|
|
|
|
TEST_ASSERT_OBJ_INT_V(response, 7);
|
|
}
|
|
|
|
void test_car(void) {
|
|
response = eval("(car (list 2 3 4))");
|
|
|
|
TEST_ASSERT_OBJ_INT_V(response, 2);
|
|
}
|
|
|
|
void test_cdr(void) {
|
|
response = eval("(car (cdr (list 2 3 4)))");
|
|
|
|
TEST_ASSERT_OBJ_INT_V(response, 3);
|
|
}
|
|
|
|
void test_nth_0(void) {
|
|
response = eval("(nth 0 (list 2 3 4))");
|
|
|
|
TEST_ASSERT_OBJ_INT_V(response, 2);
|
|
}
|
|
|
|
void test_nth_1(void) {
|
|
response = eval("(nth 1 (list 2 3 4))");
|
|
|
|
TEST_ASSERT_OBJ_INT_V(response, 3);
|
|
}
|
|
|
|
void test_nth_oob(void) {
|
|
response = eval("(nth 3 (list 2 3 4))");
|
|
|
|
TEST_ASSERT_OBJ_ERROR(response);
|
|
}
|
|
|
|
void test_eval_defun_gc(void) {
|
|
response = eval("(defun foo (a b) (+ a b))");
|
|
|
|
TEST_ASSERT_OBJ_SYMBOL_V(response, "foo");
|
|
|
|
ucl_gc(state);
|
|
response = eval("(foo 10 15)");
|
|
|
|
TEST_ASSERT_OBJ_INT_V(response, 25);
|
|
}
|
|
|
|
void test_complex(void) {
|
|
response = eval("(defun sum (elems) (reduce (quote +) elems 0))");
|
|
|
|
TEST_ASSERT_OBJ_SYMBOL_V(response, "sum");
|
|
|
|
response = eval("(sum (filter (quote (lambda (x) (% x 2))) (list 1 2 3 4 5)))");
|
|
|
|
TEST_ASSERT_OBJ_INT_V(response, 9);
|
|
}
|
|
|
|
void test_memory_perf(void) {
|
|
response = eval("(defun fib (n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))");
|
|
|
|
TEST_ASSERT_OBJ_SYMBOL_V(response, "fib");
|
|
|
|
response = eval("(fib 11)");
|
|
|
|
TEST_ASSERT_OBJ_INT_V(response, 89);
|
|
}
|
|
|
|
int main(void) {
|
|
UNITY_BEGIN();
|
|
|
|
RUN_TEST(test_simple_add);
|
|
RUN_TEST(test_simple_let);
|
|
RUN_TEST(test_let_assignment_error);
|
|
RUN_TEST(test_nested_let);
|
|
RUN_TEST(test_nested_let_scope);
|
|
RUN_TEST(test_multi_let);
|
|
RUN_TEST(test_let_return_sym);
|
|
RUN_TEST(test_eval_int);
|
|
RUN_TEST(test_eval_string);
|
|
RUN_TEST(test_eval_sym_defined);
|
|
RUN_TEST(test_eval_sym_undefined);
|
|
RUN_TEST(test_eval_nested_error);
|
|
RUN_TEST(test_eval_list);
|
|
RUN_TEST(test_eval_defun);
|
|
RUN_TEST(test_call_function);
|
|
RUN_TEST(test_setq);
|
|
RUN_TEST(test_setq_from_function);
|
|
RUN_TEST(test_lambda);
|
|
RUN_TEST(test_mapcar_lambda);
|
|
RUN_TEST(test_car);
|
|
RUN_TEST(test_cdr);
|
|
RUN_TEST(test_nth_0);
|
|
RUN_TEST(test_nth_1);
|
|
RUN_TEST(test_nth_oob);
|
|
RUN_TEST(test_eval_defun_gc);
|
|
RUN_TEST(test_complex);
|
|
RUN_TEST(test_memory_perf);
|
|
|
|
return UNITY_END();
|
|
}
|