#include #include #include #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_OBJ_LIST(response); TEST_ASSERT_EQUAL(ucl_list_length(state, response)->integer, 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_low(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 4)"); TEST_ASSERT_OBJ_INT_V(response, 3); } void test_memory_perf_medium(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 10)"); TEST_ASSERT_OBJ_INT_V(response, 55); } void test_memory_perf_high(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 8)"); TEST_ASSERT_OBJ_INT_V(response, 21); } 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_low); RUN_TEST(test_memory_perf_medium); RUN_TEST(test_memory_perf_high); return UNITY_END(); }