From 3469623feef1c16e3f697560040c4b1719102548 Mon Sep 17 00:00:00 2001 From: Laria Carolin Chabowski Date: Thu, 16 Dec 2021 23:42:37 +0100 Subject: [PATCH] Add first parser test cases --- src/Makefile.am | 5 ++ src/parser_test.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 src/parser_test.c diff --git a/src/Makefile.am b/src/Makefile.am index 2eb2648..d97387a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -35,3 +35,8 @@ TESTS += tokenizer.test check_PROGRAMS += tokenizer.test tokenizer_test_SOURCES = tokenizer_test.c test.h tokenizer_test_LDADD = libapfl.a + +TESTS += parser.test +check_PROGRAMS += parser.test +parser_test_SOURCES = parser_test.c test.h +parser_test_LDADD = libapfl.a diff --git a/src/parser_test.c b/src/parser_test.c new file mode 100644 index 0000000..b0a1b89 --- /dev/null +++ b/src/parser_test.c @@ -0,0 +1,150 @@ +#include "apfl.h" + +#include "test.h" + +struct parser_test { + testctx t; + void *source_reader_ctx; + apfl_tokenizer_ptr tokenizer; + apfl_parser_ptr parser; +}; + +static struct parser_test * +new_parser_test(testctx t, const char *source) +{ + struct parser_test *pt = must_alloc(t, sizeof(struct parser_test)); + pt->t = t; + if ((pt->source_reader_ctx = apfl_string_source_reader_new(apfl_string_view_from(source))) == NULL) { + test_fatalf(t, "Failed initializing source reader"); + } + + if ((pt->tokenizer = apfl_tokenizer_new(apfl_string_source_reader, pt->source_reader_ctx)) == NULL) { + test_fatalf(t, "Failed initializing the tokenizer"); + } + + if ((pt->parser = apfl_parser_new(apfl_tokenizer_as_token_source(pt->tokenizer))) == NULL) { + test_fatalf(t, "Failed initializing the parser"); + } + + return pt; +} + +static void +destroy_parser_test(struct parser_test *pt) +{ + apfl_parser_destroy(pt->parser); + apfl_tokenizer_destroy(pt->tokenizer); + apfl_string_source_reader_destroy(pt->source_reader_ctx); + free(pt); +} + +static void +expect_eof(struct parser_test *pt) +{ + switch (apfl_parser_next(pt->parser)) { + case APFL_PARSE_OK: + test_fatalf(pt->t, "Expected EOF but got an expression"); + break; + case APFL_PARSE_EOF: + break; + case APFL_PARSE_ERROR: + test_failf(pt->t, "Got an error instead of an EOF"); + apfl_error_print(apfl_parser_get_error(pt->parser), stderr); + test_fatal(pt->t); + break; + } +} + +static void +expect_expr(struct parser_test *pt, struct apfl_expr expected) +{ + struct apfl_expr expr; + + switch (apfl_parser_next(pt->parser)) { + case APFL_PARSE_OK: + expr = apfl_parser_get_expr(pt->parser); + if (!apfl_expr_eq(expr, expected)) { + test_failf(pt->t, "Expected expression differs from actual expression"); + test_failf(pt->t, "Expected:"); + apfl_expr_print(expected, stderr); + test_failf(pt->t, "Have:"); + apfl_expr_print(expr, stderr); + } + apfl_expr_deinit(&expr); + apfl_expr_deinit(&expected); + break; + case APFL_PARSE_EOF: + test_fatalf(pt->t, "Extected an expression but got EOF"); + break; + case APFL_PARSE_ERROR: + test_failf(pt->t, "Got an error instead of an EOF"); + apfl_error_print(apfl_parser_get_error(pt->parser), stderr); + test_fatal(pt->t); + break; + } +} + +static struct apfl_string +new_string(struct parser_test *pt, const char *in) +{ + struct apfl_string out = { .bytes = NULL, .len = 0 }; + if (!apfl_string_copy(&out, apfl_string_view_from(in))) { + test_fatalf(pt->t, "Failed copying string in new_string"); + } + return out; +} + +static void * +new_helper(struct parser_test *pt, size_t size, void *data) +{ + void *out = must_alloc(pt->t, size); + memcpy(out, data, size); + return out; +} + +// Fugly macros to make it a bit easier to create a heap allocated struct value +#define BEGIN_NEW(pt, T) ((T *)new_helper(pt, sizeof(T), &((T) +#define END_NEW ))) + +TEST(empty, t) { + struct parser_test *pt = new_parser_test(t, ""); + expect_eof(pt); + destroy_parser_test(pt); +} + +TEST(hello_world, t) { + struct parser_test *pt = new_parser_test(t, "print \"Hello World!\""); + expect_expr(pt, (struct apfl_expr) { + .type = APFL_EXPR_CALL, + .position.line = 1, + .position.col = 1, + .call = (struct apfl_expr_call) { + .callee = BEGIN_NEW(pt, struct apfl_expr) { + .type = APFL_EXPR_VAR, + .position.line = 1, + .position.col = 1, + .var = new_string(pt, "print"), + } END_NEW, + .arguments = (struct apfl_expr_list) { + .len = 1, + .items = BEGIN_NEW(pt, struct apfl_expr_list_item) { + .expand = false, + .expr = BEGIN_NEW(pt, struct apfl_expr) { + .type = APFL_EXPR_CONSTANT, + .position.line = 1, + .position.col = 7, + .constant.type = APFL_EXPR_CONST_STRING, + .constant.string = new_string(pt, "Hello World!"), + } END_NEW, + } END_NEW, + }, + }, + }); + expect_eof(pt); + destroy_parser_test(pt); +} + +TESTS_BEGIN + ADDTEST(empty), + ADDTEST(hello_world), +TESTS_END