#define epsilon 2.2204460492503131E-16 #define testresult int #define pass 1 #define fail 0 #define print_assert_equal_fail(variable, value, type, format) \ printf("\n\tAssertion failed for '" #variable "'" \ "\n\t in %s:%d" \ "\n\texpected: " format \ "\n\tgot: " format "\n", \ __FILE__, __LINE__, (type)value, (type)variable) #define print_assert_not_equal_fail(variable, value, type, format) \ printf("\n\tAssertion failed for '" #variable "'" \ "\n\t in %s:%d" \ "\n\texpected not: " format \ "\n\tgot anyways: " format "\n", \ __FILE__, __LINE__, (type)value, (type)variable) /* print_assert_not_equal_fail(error, 0, int, "%d"); \ */ #define assert_no_error(error) \ if (error) { \ printf("\n\tExpected no error to occur," \ " but an error occured anyways:\n"); \ log_error(); \ return fail; \ } \ #define assert_equal_int(variable, value) \ if (variable != value) { \ print_assert_equal_fail(variable, value, int, "%d"); \ return fail; \ } #define assert_not_equal_int(variable, value) \ if (variable == value) { \ print_assert_not_equal_fail(variable, value, int, "%d"); \ return fail; \ } #define assert_equal_double(variable, value) \ if (fabs((double)variable - (double)value) > epsilon) { \ print_assert_equal_fail(variable, value, double, "%f"); \ return fail; \ } #define assert_not_equal_double(variable, value) \ if (fabs((double)variable - (double)value) <= epsilon) { \ print_assert_not_equal_fail(variable, value, double, "%f"); \ return fail; \ } #define assert_null(variable) \ assert_equal_int(variable, NULL) #define assert_not_null(variable) \ assert_not_equal_int(variable, NULL) #define invoke_test(name) \ printf("" #name ":"); \ for(int i = 0; i < 45 - strlen(#name); ++i) \ printf(" "); \ if (name() == pass) \ printf("%spassed%s\n", console_green, console_normal); \ else { \ printf("%sfailed%s\n", console_red, console_normal); \ if(error) { \ free(error); \ error = NULL; \ } \ } \ testresult test_built_in_add() { Ast_Node* plus = create_ast_node_symbol("+"); Ast_Node* ten = create_ast_node_number(10); Ast_Node* four = create_ast_node_number(4); Ast_Node* nil = create_ast_node_nil(); Ast_Node* form = create_ast_node_pair( plus, create_ast_node_pair( ten, create_ast_node_pair( four, nil))); Ast_Node* result = eval_expr(form, new(Environment)); assert_no_error(error); assert_not_null(result); assert_equal_int(result->type, Ast_Node_Type_Number); assert_equal_double(result->value.number->value, 14); return pass; } testresult test_built_in_substract() { Ast_Node* minus = create_ast_node_symbol("-"); Ast_Node* ten = create_ast_node_number(10); Ast_Node* four = create_ast_node_number(4); Ast_Node* nil = create_ast_node_nil(); Ast_Node* form = create_ast_node_pair( minus, create_ast_node_pair( ten, create_ast_node_pair( four, nil))); Ast_Node* result = eval_expr(form, new(Environment)); assert_no_error(error); assert_not_null(result); assert_equal_int(result->type, Ast_Node_Type_Number); assert_equal_double(result->value.number->value, 6); return pass; } testresult test_built_in_multiply() { Ast_Node* times = create_ast_node_symbol("*"); Ast_Node* ten = create_ast_node_number(10); Ast_Node* four = create_ast_node_number(4); Ast_Node* nil = create_ast_node_nil(); Ast_Node* form = create_ast_node_pair( times, create_ast_node_pair( ten, create_ast_node_pair( four, nil))); Ast_Node* result = eval_expr(form, new(Environment)); assert_no_error(error); assert_not_null(result); assert_equal_int(result->type, Ast_Node_Type_Number); assert_equal_double(result->value.number->value, 40); return pass; } testresult test_built_in_divide() { Ast_Node* over = create_ast_node_symbol("/"); Ast_Node* ten = create_ast_node_number(20); Ast_Node* four = create_ast_node_number(4); Ast_Node* nil = create_ast_node_nil(); Ast_Node* form = create_ast_node_pair( over, create_ast_node_pair( ten, create_ast_node_pair( four, nil))); Ast_Node* result = eval_expr(form, new(Environment)); assert_null(error); assert_not_null(result); assert_equal_int(result->type, Ast_Node_Type_Number); assert_equal_double(result->value.number->value, 5); return pass; } testresult test_built_in_if() { Ast_Node* _if = create_ast_node_symbol("if"); Ast_Node* cond = create_ast_node_number(1); Ast_Node* four = create_ast_node_number(4); Ast_Node* five = create_ast_node_number(5); Ast_Node* nil = create_ast_node_nil(); Ast_Node* form = create_ast_node_pair( _if, create_ast_node_pair( cond, create_ast_node_pair( four, create_ast_node_pair( five, nil)))); Ast_Node* result; // test *then* case result = eval_expr(form, new(Environment)); assert_no_error(error); assert_not_null(result); assert_equal_int(result->type, Ast_Node_Type_Number); assert_equal_double(result->value.number->value, 4); // test *else* case cond->value.number->value = 0; result = eval_expr(form, new(Environment)); assert_null(error); assert_not_null(result); assert_equal_int(result->type, Ast_Node_Type_Number); assert_equal_double(result->value.number->value, 5); return pass; } testresult test_built_in_and() { Ast_Node* _and = create_ast_node_symbol("and"); Ast_Node* cond1 = create_ast_node_number(1); Ast_Node* cond2 = create_ast_node_string("asd"); Ast_Node* cond3 = create_ast_node_number(4); Ast_Node* nil = create_ast_node_nil(); Ast_Node* form = create_ast_node_pair( _and, create_ast_node_pair( cond1, create_ast_node_pair( cond2, create_ast_node_pair( cond3, nil)))); Ast_Node* result; // a true case result = eval_expr(form, new(Environment)); assert_no_error(error); assert_not_null(result); assert_equal_int(result->type, Ast_Node_Type_Number); assert_equal_double(result->value.number->value, 1); // a false case cond1->value.number->value = 0; result = eval_expr(form, new(Environment)); assert_no_error(error); assert_not_null(result); assert_equal_int(result->type, Ast_Node_Type_Number); assert_equal_double(result->value.number->value, 0); return pass; } void run_all_tests() { log_level = Log_Level_None; invoke_test(test_built_in_add); invoke_test(test_built_in_substract); invoke_test(test_built_in_multiply); invoke_test(test_built_in_divide); invoke_test(test_built_in_if); invoke_test(test_built_in_and); }