diff --git a/Makefile b/Makefile index f2d0f83..c37e5c6 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC = gcc CPPFLAGS = -Isrc/ -D_POSIX_C_SOURCE=200809L -D_USE_CLIMBING=$(USE_CLIMBING) CFLAGS = -Wall -Wextra -pedantic -Werror -std=c99 -VPATH = src/ +VPATH = src/ tests/ USE_CLIMBING = 1 SRC = \ @@ -19,6 +19,20 @@ all: $(BIN) # Write this one rule instead of using the implicit rules to buid at the root $(BIN): $(OBJ) src/evalexpr.o +check: testsuite + ./testsuite --verbose + +TEST_SRC = \ + tests/climbing.c \ + tests/recursive.c \ + tests/testsuite.c \ + +TEST_OBJ = $(TEST_SRC:.c=.o) + +testsuite: LDFLAGS+=-lcriterion -fsanitize=address +testsuite: CFLAGS+=-fsanitize=address +testsuite: $(OBJ) $(TEST_OBJ) + .PHONY: clean clean: $(RM) $(OBJ) # remove object files diff --git a/tests/climbing.c b/tests/climbing.c new file mode 100644 index 0000000..b80bd93 --- /dev/null +++ b/tests/climbing.c @@ -0,0 +1,181 @@ +#include + +#include "ast/ast.h" +#include "eval/eval.h" +#include "parse/parse.h" + +static void do_success(const char *input, int expected) +{ + struct ast_node *ast = climbing_parse(input); + + cr_assert_not_null(ast); + cr_expect_eq(eval_ast(ast), expected); + + destroy_ast(ast); +} + +static void do_failure(const char *input) +{ + struct ast_node *ast = climbing_parse(input); + + cr_expect_null(ast); + + destroy_ast(ast); // Do not leak if it exists +} + +TestSuite(climbing); + +Test(climbing, empty) +{ + do_failure(""); +} + +Test(climbing, trailing_operator) +{ + do_failure("1 +"); +} + +Test(climbing, trailing_expression) +{ + do_failure("1 1"); +} + +Test(climbing, double_operator) +{ + do_failure("1 * * 1"); +} + +Test(climbing, one) +{ + do_success("1", 1); +} + +Test(climbing, the_answer) +{ + do_success("42", 42); +} + +Test(climbing, int_max) +{ + do_success("2147483647", 2147483647); +} + +Test(climbing, whitespace) +{ + do_success(" 1 ", 1); +} + +Test(climbing, more_whitespace) +{ + do_success(" 1 + 2 ", 3); +} + +Test(climbing, one_plus_one) +{ + do_success("1+1", 2); +} + +Test(climbing, one_minus_one) +{ + do_success("1-1", 0); +} + +Test(climbing, additions) +{ + do_success("1+1+1+1+1", 5); +} + +Test(climbing, substractions) +{ + do_success("1-1-1-1-1", -3); +} + +Test(climbing, multiplication) +{ + do_success("2 * 3", 6); +} + +Test(climbing, multiplications) +{ + do_success("1 * 2 * 3 * 4", 24); +} + +Test(climbing, division) +{ + do_success("12 / 3", 4); +} + +Test(climbing, divisions) +{ + do_success("24 / 4 / 3 / 2", 1); +} + +Test(climbing, simple_priority) +{ + do_success("1 + 2 * 3", 7); +} + +Test(climbing, more_priority) +{ + do_success("1 + 6 / 3 + 4 * 6 + 14 / 7", 29); +} + +Test(climbing, fail_parenthesis) +{ + do_failure("(1 + 2))"); +} + +Test(climbing, simple_parenthesis) +{ + do_success("(1 + 2) * 3", 9); +} + +Test(climbing, more_parentheses) +{ + do_success("(1 + 2) * (3 - 4)", -3); +} + +Test(climbing, unary_minus) +{ + do_success("-1", -1); +} + +Test(climbing, unary_plus) +{ + do_success("+1", 1); +} + +Test(climbing, unary_torture) +{ + do_success("--+++--+-+-+-1", -1); +} + +Test(climbing, factorial) +{ + do_success("3!", 6); +} + +Test(climbing, fail_factorial) +{ + do_failure("3!!"); +} + +Test(climbing, power) +{ + do_success("4^3", 64); +} + +Test(climbing, powers) +{ + do_success("4^3^2", 262144); +} + +Test(climbing, fact_and_power) +{ + do_success("2^3!", 64); +} + +Test(climbing, altogether) +{ + do_success(" - 3 ^ 2 + - 4 * 8 / 2 + + 3! -- 2 + ((-1) + 1) * 2 ", -17); +} diff --git a/tests/recursive.c b/tests/recursive.c new file mode 100644 index 0000000..dcc0a9d --- /dev/null +++ b/tests/recursive.c @@ -0,0 +1,181 @@ +#include + +#include "ast/ast.h" +#include "eval/eval.h" +#include "parse/parse.h" + +static void do_success(const char *input, int expected) +{ + struct ast_node *ast = recursive_parse(input); + + cr_assert_not_null(ast); + cr_expect_eq(eval_ast(ast), expected); + + destroy_ast(ast); +} + +static void do_failure(const char *input) +{ + struct ast_node *ast = recursive_parse(input); + + cr_expect_null(ast); + + destroy_ast(ast); // Do not leak if it exists +} + +TestSuite(recursive); + +Test(recursive, empty) +{ + do_failure(""); +} + +Test(recursive, trailing_operator) +{ + do_failure("1 +"); +} + +Test(recursive, trailing_expression) +{ + do_failure("1 1"); +} + +Test(recursive, double_operator) +{ + do_failure("1 * * 1"); +} + +Test(recursive, one) +{ + do_success("1", 1); +} + +Test(recursive, the_answer) +{ + do_success("42", 42); +} + +Test(recursive, int_max) +{ + do_success("2147483647", 2147483647); +} + +Test(recursive, whitespace) +{ + do_success(" 1 ", 1); +} + +Test(recursive, more_whitespace) +{ + do_success(" 1 + 2 ", 3); +} + +Test(recursive, one_plus_one) +{ + do_success("1+1", 2); +} + +Test(recursive, one_minus_one) +{ + do_success("1-1", 0); +} + +Test(recursive, additions) +{ + do_success("1+1+1+1+1", 5); +} + +Test(recursive, substractions) +{ + do_success("1-1-1-1-1", -3); +} + +Test(recursive, multiplication) +{ + do_success("2 * 3", 6); +} + +Test(recursive, multiplications) +{ + do_success("1 * 2 * 3 * 4", 24); +} + +Test(recursive, division) +{ + do_success("12 / 3", 4); +} + +Test(recursive, divisions) +{ + do_success("24 / 4 / 3 / 2", 1); +} + +Test(recursive, simple_priority) +{ + do_success("1 + 2 * 3", 7); +} + +Test(recursive, more_priority) +{ + do_success("1 + 6 / 3 + 4 * 6 + 14 / 7", 29); +} + +Test(recursive, fail_parenthesis) +{ + do_failure("(1 + 2))"); +} + +Test(recursive, simple_parenthesis) +{ + do_success("(1 + 2) * 3", 9); +} + +Test(recursive, more_parentheses) +{ + do_success("(1 + 2) * (3 - 4)", -3); +} + +Test(recursive, unary_minus) +{ + do_success("-1", -1); +} + +Test(recursive, unary_plus) +{ + do_success("+1", 1); +} + +Test(recursive, unary_torture) +{ + do_success("--+++--+-+-+-1", -1); +} + +Test(recursive, factorial) +{ + do_success("3!", 6); +} + +Test(recursive, fail_factorial) +{ + do_failure("3!!"); +} + +Test(recursive, power) +{ + do_success("4^3", 64); +} + +Test(recursive, powers) +{ + do_success("4^3^2", 262144); +} + +Test(recursive, fact_and_power) +{ + do_success("2^3!", 64); +} + +Test(recursive, altogether) +{ + do_success(" - 3 ^ 2 + - 4 * 8 / 2 + + 3! -- 2 + ((-1) + 1) * 2 ", -17); +} diff --git a/tests/testsuite.c b/tests/testsuite.c new file mode 100644 index 0000000..4a2e43b --- /dev/null +++ b/tests/testsuite.c @@ -0,0 +1,13 @@ +#include + +int main(int argc, char *argv[]) +{ + struct criterion_test_set *tests = criterion_initialize(); + + int result = 0; + if (criterion_handle_args(argc, argv, true)) + result = !criterion_run_all_tests(tests); + + criterion_finalize(tests); + return result; +}