#include #include #include #include "uclisp.h" #include "internal.h" #include "utility.h" #include "testing_helpers.h" #include "state.h" #include "builtins.h" #include "special.h" static struct ucl_object *input; static struct ucl_object *response; static struct ucl_state *state; void setUp(void) { input = NULL; response = NULL; state = ucl_state_create(); ucl_state_put(state, "let", ucl_special_create(ucl_special_let)); ucl_state_put(state, "defun", ucl_special_create(ucl_special_defun)); ucl_state_put(state, "+", ucl_builtin_create(ucl_builtin_add)); ucl_state_put(state, "error", ucl_builtin_create(ucl_builtin_error)); ucl_state_put(state, "list", ucl_builtin_create(ucl_builtin_list)); ucl_state_put(state, "setq", ucl_special_create(ucl_special_setq)); ucl_state_put(state, "car", ucl_builtin_create(ucl_builtin_car)); ucl_state_put(state, "cdr", ucl_builtin_create(ucl_builtin_cdr)); ucl_state_put(state, "nth", ucl_builtin_create(ucl_builtin_nth)); ucl_state_put(state, "mapcar", ucl_builtin_create(ucl_builtin_mapcar)); ucl_state_put(state, "lambda", ucl_special_create(ucl_special_lambda)); ucl_state_put(state, "quote", ucl_special_create(ucl_special_quote)); } void tearDown(void) { // TODO: Implement GC so we can clean these both up //ucl_object_delete(input); input = NULL; ucl_object_delete(response); response = NULL; state = NULL; } static struct ucl_object *eval (const char *code) { struct ucl_object *sexp = ucl_parse(code); return ucl_evaluate(state, ucl_car(sexp)); } void test_simple_add(void) { ucl_state_put(state, "+", ucl_builtin_create(ucl_builtin_add)); response = eval("(+ 2 3)"); TEST_ASSERT_OBJ_INT(response); TEST_ASSERT_EQUAL(response->integer, 5); } void test_simple_let(void) { response = eval("(let ((x 2)) (+ x 3))"); TEST_ASSERT_OBJ_INT(response); TEST_ASSERT_EQUAL(response->integer, 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(response); TEST_ASSERT_EQUAL(response->integer, 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(response); TEST_ASSERT_EQUAL(response->integer, 7); } void test_let_return_sym(void) { response = eval("(let ((x 2)) x)"); TEST_ASSERT_OBJ_INT(response); TEST_ASSERT_EQUAL(response->integer, 2); } void test_eval_int(void) { response = eval("2"); TEST_ASSERT_OBJ_INT(response); TEST_ASSERT_EQUAL(response->integer, 2); } void test_eval_string(void) { response = eval("\"foo\""); TEST_ASSERT_OBJ_STRING(response); TEST_ASSERT_EQUAL_STRING(response->string, "foo"); } void test_eval_sym_defined(void) { ucl_state_put(state, "foo", ucl_int_create(2)); response = eval("foo"); TEST_ASSERT_OBJ_INT(response); TEST_ASSERT_EQUAL(response->integer, 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(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(response); TEST_ASSERT_EQUAL_STRING(response->symbol, "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 2)"); TEST_ASSERT_OBJ_INT(response); TEST_ASSERT_EQUAL(response->symbol, 2); response = eval("bar"); TEST_ASSERT_OBJ_INT(response); TEST_ASSERT_EQUAL(response->symbol, 2); } void test_setq_from_function(void) { response = eval("(defun foo (a) (setq bar a))"); TEST_ASSERT_OBJ_SYMBOL(response); TEST_ASSERT_EQUAL_STRING(response->symbol, "foo"); response = eval("(foo 2)"); TEST_ASSERT_OBJ_INT(response); TEST_ASSERT_EQUAL(response->symbol, 2); response = eval("bar"); TEST_ASSERT_OBJ_INT(response); TEST_ASSERT_EQUAL(response->symbol, 2); } void test_lambda(void) { response = eval("((lambda (x) (+ x 2)) 2)"); TEST_ASSERT_OBJ_INT(response); TEST_ASSERT_EQUAL(response->integer, 4); } void test_mapcar_lambda(void) { response = eval("(car (mapcar (quote (lambda (x) (+ x 2))) (list 5)))"); TEST_ASSERT_OBJ_INT(response); TEST_ASSERT_EQUAL(response->integer, 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(response); TEST_ASSERT_EQUAL(response->integer, 7); } void test_car(void) { response = eval("(car (list 2 3 4))"); TEST_ASSERT_OBJ_INT(response); TEST_ASSERT_EQUAL(response->integer, 2); } void test_cdr(void) { response = eval("(car (cdr (list 2 3 4)))"); TEST_ASSERT_OBJ_INT(response); TEST_ASSERT_EQUAL(response->integer, 3); } void test_nth_0(void) { response = eval("(nth 0 (list 2 3 4))"); TEST_ASSERT_OBJ_INT(response); TEST_ASSERT_EQUAL(response->integer, 2); } void test_nth_1(void) { response = eval("(nth 1 (list 2 3 4))"); TEST_ASSERT_OBJ_INT(response); TEST_ASSERT_EQUAL(response->integer, 3); } void test_nth_oob(void) { response = eval("(nth 3 (list 2 3 4))"); TEST_ASSERT_OBJ_ERROR(response); } 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); return UNITY_END(); }