Add first parser test cases
This commit is contained in:
parent
10a99d0b1e
commit
3469623fee
2 changed files with 155 additions and 0 deletions
|
|
@ -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
|
||||
|
|
|
|||
150
src/parser_test.c
Normal file
150
src/parser_test.c
Normal file
|
|
@ -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
|
||||
Loading…
Reference in a new issue