From 8d1eaf5d785ae7e5b37162bbfadcb8b9519c123a Mon Sep 17 00:00:00 2001 From: Laria Carolin Chabowski Date: Sun, 19 Dec 2021 00:27:34 +0100 Subject: [PATCH] Add tests for some parsing errors --- src/apfl.h | 2 + src/error.c | 43 +++++++++++++++++++ src/parser_test.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+) diff --git a/src/apfl.h b/src/apfl.h index 4a3b446..74ef2fd 100644 --- a/src/apfl.h +++ b/src/apfl.h @@ -131,6 +131,8 @@ enum apfl_error_type { APFL_ERR_EMPTY_ASSIGNMENT, }; +const char *apfl_error_type_name(enum apfl_error_type); + struct apfl_error { enum apfl_error_type type; diff --git a/src/error.c b/src/error.c index 5323a14..c288f7d 100644 --- a/src/error.c +++ b/src/error.c @@ -6,6 +6,49 @@ #define POSARGS error.position.line, error.position.col #define POS2ARGS error.position2.line, error.position2.col +const char * +apfl_error_type_name(enum apfl_error_type type) +{ + switch (type) { + case APFL_ERR_MALLOC_FAILED: + return "APFL_ERR_MALLOC_FAILED"; + case APFL_ERR_INPUT_ERROR: + return "APFL_ERR_INPUT_ERROR"; + case APFL_ERR_UNEXPECTED_EOF: + return "APFL_ERR_UNEXPECTED_EOF"; + case APFL_ERR_EXPECTED_EQ_AFTER_COLON: + return "APFL_ERR_EXPECTED_EQ_AFTER_COLON"; + case APFL_ERR_UNEXPECTED_BYTE_IN_NUMBER: + return "APFL_ERR_UNEXPECTED_BYTE_IN_NUMBER"; + case APFL_ERR_EXPECTED_DIGIT: + return "APFL_ERR_EXPECTED_DIGIT"; + case APFL_ERR_EXPECTED_HEX_IN_HEX_ESCAPE: + return "APFL_ERR_EXPECTED_HEX_IN_HEX_ESCAPE"; + case APFL_ERR_INVALID_ESCAPE_SEQUENCE: + return "APFL_ERR_INVALID_ESCAPE_SEQUENCE"; + case APFL_ERR_NO_LINEBREAK_AFTER_CONTINUE_LINE: + return "APFL_ERR_NO_LINEBREAK_AFTER_CONTINUE_LINE"; + case APFL_ERR_UNEXPECTED_TOKEN: + return "APFL_ERR_UNEXPECTED_TOKEN"; + case APFL_ERR_MISMATCHING_CLOSING_BRACKET: + return "APFL_ERR_MISMATCHING_CLOSING_BRACKET"; + case APFL_ERR_UNEXPECTED_EOF_AFTER_TOKEN: + return "APFL_ERR_UNEXPECTED_EOF_AFTER_TOKEN"; + case APFL_ERR_STATEMENTS_BEFORE_PARAMETERS: + return "APFL_ERR_STATEMENTS_BEFORE_PARAMETERS"; + case APFL_ERR_EMPTY_ASSIGNMENT_BEFORE_PARAMETERS: + return "APFL_ERR_EMPTY_ASSIGNMENT_BEFORE_PARAMETERS"; + case APFL_ERR_UNEXPECTED_EXPRESSION: + return "APFL_ERR_UNEXPECTED_EXPRESSION"; + case APFL_ERR_INVALID_ASSIGNMENT_LHS: + return "APFL_ERR_INVALID_ASSIGNMENT_LHS"; + case APFL_ERR_EMPTY_ASSIGNMENT: + return "APFL_ERR_EMPTY_ASSIGNMENT"; + } + + return ""; +} + void apfl_error_print(struct apfl_error error, FILE *file) { diff --git a/src/parser_test.c b/src/parser_test.c index 403e0a4..f42f3de 100644 --- a/src/parser_test.c +++ b/src/parser_test.c @@ -87,6 +87,27 @@ expect_expr(struct parser_test *pt, struct apfl_expr expected) } } +static void +expect_error_of_type(struct parser_test *pt, enum apfl_error_type want) +{ + struct apfl_error have; + switch (apfl_parser_next(pt->parser)) { + case APFL_PARSE_OK: + test_failf(pt->t, "Expected error but got an OK"); + break; + case APFL_PARSE_EOF: + test_fatalf(pt->t, "Expected error but got an EOF"); + break; + case APFL_PARSE_ERROR: + have = apfl_parser_get_error(pt->parser); + if (have.type != want) { + test_failf(pt->t, "Expected error of type %s, got this error instead:", apfl_error_type_name(want)); + apfl_error_print(have, stderr); + } + break; + } +} + static struct apfl_string new_string(struct parser_test *pt, const char *in) { @@ -1120,6 +1141,77 @@ TEST(complex_function, t) { destroy_parser_test(pt); } +TEST(err_empty_assignment, t) { + struct parser_test *pt = new_parser_test(t, "= foo bar"); + expect_error_of_type(pt, APFL_ERR_EMPTY_ASSIGNMENT); + destroy_parser_test(pt); +} + +TEST(err_mismatching_parens, t) { + struct parser_test *pt = new_parser_test(t, "{[(}"); + expect_error_of_type(pt, APFL_ERR_UNEXPECTED_TOKEN); + destroy_parser_test(pt); +} + +TEST(err_unclosed_func, t) { + struct parser_test *pt = new_parser_test(t, "{ foo -> bar; baz a; b ->"); + expect_error_of_type(pt, APFL_ERR_UNEXPECTED_EOF); + destroy_parser_test(pt); +} + +TEST(err_unclosed_paren, t) { + struct parser_test *pt = new_parser_test(t, "(a b.c@d"); + expect_error_of_type(pt, APFL_ERR_UNEXPECTED_EOF_AFTER_TOKEN); + destroy_parser_test(pt); +} + +TEST(err_assignment_missing_rhs, t) { + struct parser_test *pt = new_parser_test(t, "foo = bar = ;"); + expect_error_of_type(pt, APFL_ERR_EMPTY_ASSIGNMENT); + // TODO: Actually kinda weird that we return the same error as in err_empty_assignment. + destroy_parser_test(pt); +} + +TEST(err_assignment_invalid_lhs, t) { + struct parser_test *pt = new_parser_test(t, "{foo} = bar"); + expect_error_of_type(pt, APFL_ERR_INVALID_ASSIGNMENT_LHS); + destroy_parser_test(pt); + + pt = new_parser_test(t, "(a b) = bar"); + expect_error_of_type(pt, APFL_ERR_INVALID_ASSIGNMENT_LHS); + destroy_parser_test(pt); +} + +TEST(err_fragments_after_mapsto_in_empty_dict, t) { + struct parser_test *pt = new_parser_test(t, "[-> foo]"); + expect_error_of_type(pt, APFL_ERR_UNEXPECTED_TOKEN); + destroy_parser_test(pt); +} + +TEST(err_fragments_after_mapsto_in_dict, t) { + struct parser_test *pt = new_parser_test(t, "[a -> b, (c d) -> e foo->]"); + expect_error_of_type(pt, APFL_ERR_UNEXPECTED_TOKEN); + destroy_parser_test(pt); +} + +TEST(err_mapsto_in_list, t) { + struct parser_test *pt = new_parser_test(t, "[a b c -> d]"); + expect_error_of_type(pt, APFL_ERR_UNEXPECTED_TOKEN); + destroy_parser_test(pt); +} + +TEST(err_expr_in_param, t) { + struct parser_test *pt = new_parser_test(t, "{ foo (bar baz) -> }"); + expect_error_of_type(pt, APFL_ERR_UNEXPECTED_EXPRESSION); + destroy_parser_test(pt); +} + +TEST(err_statements_before_params, t) { + struct parser_test *pt = new_parser_test(t, "{ a = b = foo bar; 1 \n baz -> }"); + expect_error_of_type(pt, APFL_ERR_STATEMENTS_BEFORE_PARAMETERS); + destroy_parser_test(pt); +} + TESTS_BEGIN ADDTEST(empty), ADDTEST(hello_world), @@ -1139,4 +1231,15 @@ TESTS_BEGIN ADDTEST(assignment), ADDTEST(simple_function), ADDTEST(complex_function), + ADDTEST(err_empty_assignment), + ADDTEST(err_mismatching_parens), + ADDTEST(err_unclosed_func), + ADDTEST(err_unclosed_paren), + ADDTEST(err_assignment_missing_rhs), + ADDTEST(err_assignment_invalid_lhs), + ADDTEST(err_fragments_after_mapsto_in_empty_dict), + ADDTEST(err_fragments_after_mapsto_in_dict), + ADDTEST(err_mapsto_in_list), + ADDTEST(err_expr_in_param), + ADDTEST(err_statements_before_params), TESTS_END