unittests #9
							
								
								
									
										4
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								Makefile
									
									
									
									
									
								
							| @@ -27,6 +27,9 @@ validate: asan msan debug | |||||||
| analyze: | analyze: | ||||||
| 	make -rRf make/analyze.mk clean all | 	make -rRf make/analyze.mk clean all | ||||||
|  |  | ||||||
|  | test: | ||||||
|  | 	make -rRf make/test.mk test | ||||||
|  |  | ||||||
| clean: | clean: | ||||||
| 	make -rRf make/release.mk clean | 	make -rRf make/release.mk clean | ||||||
| 	make -rRf make/debug.mk clean | 	make -rRf make/debug.mk clean | ||||||
| @@ -34,6 +37,7 @@ clean: | |||||||
| 	make -rRf make/msan.mk clean | 	make -rRf make/msan.mk clean | ||||||
| 	make -rRf make/asan.mk clean | 	make -rRf make/asan.mk clean | ||||||
| 	make -rRf make/analyze.mk clean | 	make -rRf make/analyze.mk clean | ||||||
|  | 	make -rRf make/test.mk clean | ||||||
| 	rm -rf build/ | 	rm -rf build/ | ||||||
|  |  | ||||||
| distclean: clean | distclean: clean | ||||||
|   | |||||||
							
								
								
									
										9
									
								
								make/test.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								make/test.mk
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | .PHONY: test | ||||||
|  |  | ||||||
|  | BUILD_DIR=build/test/ | ||||||
|  | TARGET=oas-tests | ||||||
|  | SOURCES = $(filter-out src/main.c, $(shell find src/ tests/ -type f -name '*.c')) | ||||||
|  | -include make/base.mk | ||||||
|  |  | ||||||
|  | test: $(BUILD_DIR)$(TARGET) | ||||||
|  | 	$(BUILD_DIR)$(TARGET) | ||||||
							
								
								
									
										6
									
								
								tests/.clang-format
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								tests/.clang-format
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | BasedOnStyle:    LLVM | ||||||
|  | IndentWidth:     4 | ||||||
|  | Cpp11BracedListStyle: true | ||||||
|  | AlignArrayOfStructures: Left | ||||||
|  | AllowShortFunctionsOnASingleLine: Empty | ||||||
|  | ColumnLimit: 120 | ||||||
							
								
								
									
										22
									
								
								tests/ast.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								tests/ast.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | #include "../src/ast.h" | ||||||
|  | #include "munit.h" | ||||||
|  |  | ||||||
|  | MunitResult test_ast_node_alloc(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     ast_node_t *node = nullptr; | ||||||
|  |     error_t *err = ast_node_alloc(&node); | ||||||
|  |  | ||||||
|  |     munit_assert_ptr_not_null(node); | ||||||
|  |     munit_assert_ptr_null(err); | ||||||
|  |  | ||||||
|  |     ast_node_free(node); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitTest ast_tests[] = { | ||||||
|  |     {"/node_alloc", test_ast_node_alloc, nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {nullptr,       nullptr,             nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr} | ||||||
|  | }; | ||||||
							
								
								
									
										896
									
								
								tests/lexer.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										896
									
								
								tests/lexer.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,896 @@ | |||||||
|  | #include "../src/lexer.h" | ||||||
|  | #include "../src/error.h" | ||||||
|  | #include "munit.h" | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | void lexer_setup_memory_test(lexer_t *lex, const char *input) { | ||||||
|  |     munit_assert_null(lex->fp); | ||||||
|  |     FILE *stream = fmemopen((void *)input, strlen(input), "rb"); | ||||||
|  |     munit_assert_not_null(stream); | ||||||
|  |     lex->fp = stream; | ||||||
|  |     lex->line_number = 0; | ||||||
|  |     lex->character_number = 0; | ||||||
|  |     lex->buffer_count = 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void lexer_expect_one_token(lexer_t *lex, lexer_token_id_t id, const char *value, size_t line, size_t column) { | ||||||
|  |     lexer_token_t token = {}; | ||||||
|  |  | ||||||
|  |     error_t *err = lexer_next(lex, &token); | ||||||
|  |     munit_assert_null(err); | ||||||
|  |  | ||||||
|  |     munit_assert_int(token.id, ==, id); | ||||||
|  |     munit_assert_string_equal(token.value, value); | ||||||
|  |     munit_assert_int(token.line_number, ==, line); | ||||||
|  |     munit_assert_int(token.character_number, ==, column); | ||||||
|  |     lexer_token_cleanup(&token); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void lexer_expect_eof(lexer_t *lex) { | ||||||
|  |     lexer_token_t token = {}; | ||||||
|  |     error_t *err = lexer_next(lex, &token); | ||||||
|  |     munit_assert_ptr_equal(err, err_eof); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void lexer_test_one_token(lexer_token_id_t id, const char *value) { | ||||||
|  |     lexer_t lex = {}; | ||||||
|  |     lexer_setup_memory_test(&lex, value); | ||||||
|  |     lexer_expect_one_token(&lex, id, value, 0, 0); | ||||||
|  |     lexer_expect_eof(&lex); | ||||||
|  |     lexer_close(&lex); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_identifier(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |     lexer_test_one_token(TOKEN_IDENTIFIER, "identifier"); | ||||||
|  |     lexer_test_one_token(TOKEN_IDENTIFIER, "_identifier"); | ||||||
|  |     lexer_test_one_token(TOKEN_IDENTIFIER, "_identifier123_55"); | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | typedef struct token_data { | ||||||
|  |     lexer_token_id_t id; | ||||||
|  |     char *value; | ||||||
|  |     size_t line; | ||||||
|  |     size_t column; | ||||||
|  | } token_data_t; | ||||||
|  |  | ||||||
|  | typedef struct boundary { | ||||||
|  |     const char *input; | ||||||
|  |     token_data_t first; | ||||||
|  |     token_data_t second; | ||||||
|  | } boundary_t; | ||||||
|  |  | ||||||
|  | void test_lexer_boundary(boundary_t boundaries[]) { | ||||||
|  |     for (size_t i = 0; boundaries[i].input; ++i) { | ||||||
|  |         auto boundary = boundaries[i]; | ||||||
|  |         auto first = boundary.first; | ||||||
|  |         auto second = boundary.second; | ||||||
|  |  | ||||||
|  |         lexer_t lex = {}; | ||||||
|  |         lexer_setup_memory_test(&lex, boundary.input); | ||||||
|  |         lexer_expect_one_token(&lex, first.id, first.value, first.line, first.column); | ||||||
|  |         lexer_expect_one_token(&lex, second.id, second.value, second.line, second.column); | ||||||
|  |         lexer_expect_eof(&lex); | ||||||
|  |         lexer_close(&lex); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_identifier_boundary(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     boundary_t boundaries[] = { | ||||||
|  |         {"id:",        {TOKEN_IDENTIFIER, "id", 0, 0}, {TOKEN_COLON, ":", 0, 2}         }, | ||||||
|  |         {"id[",        {TOKEN_IDENTIFIER, "id", 0, 0}, {TOKEN_LBRACKET, "[", 0, 2}      }, | ||||||
|  |         {"id]",        {TOKEN_IDENTIFIER, "id", 0, 0}, {TOKEN_RBRACKET, "]", 0, 2}      }, | ||||||
|  |         {"id+",        {TOKEN_IDENTIFIER, "id", 0, 0}, {TOKEN_PLUS, "+", 0, 2}          }, | ||||||
|  |         {"id-",        {TOKEN_IDENTIFIER, "id", 0, 0}, {TOKEN_MINUS, "-", 0, 2}         }, | ||||||
|  |         {"id*",        {TOKEN_IDENTIFIER, "id", 0, 0}, {TOKEN_ASTERISK, "*", 0, 2}      }, | ||||||
|  |         {"id.",        {TOKEN_IDENTIFIER, "id", 0, 0}, {TOKEN_DOT, ".", 0, 2}           }, | ||||||
|  |         {"id;comment", {TOKEN_IDENTIFIER, "id", 0, 0}, {TOKEN_COMMENT, ";comment", 0, 2}}, | ||||||
|  |         {"id\n",       {TOKEN_IDENTIFIER, "id", 0, 0}, {TOKEN_NEWLINE, "\n", 0, 2}      }, | ||||||
|  |         {"id\r\n",     {TOKEN_IDENTIFIER, "id", 0, 0}, {TOKEN_NEWLINE, "\r\n", 0, 2}    }, | ||||||
|  |         {"id ",        {TOKEN_IDENTIFIER, "id", 0, 0}, {TOKEN_WHITESPACE, " ", 0, 2}    }, | ||||||
|  |         {"id\t",       {TOKEN_IDENTIFIER, "id", 0, 0}, {TOKEN_WHITESPACE, "\t", 0, 2}   }, | ||||||
|  |         {nullptr,      {},                             {}                               }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     test_lexer_boundary(boundaries); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_decimal(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |     lexer_test_one_token(TOKEN_DECIMAL, "123"); | ||||||
|  |     lexer_test_one_token(TOKEN_DECIMAL, "0"); | ||||||
|  |     lexer_test_one_token(TOKEN_DECIMAL, "42"); | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_decimal_with_suffix(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |     lexer_test_one_token(TOKEN_DECIMAL, "123:8"); | ||||||
|  |     lexer_test_one_token(TOKEN_DECIMAL, "0:16"); | ||||||
|  |     lexer_test_one_token(TOKEN_DECIMAL, "42:32"); | ||||||
|  |     lexer_test_one_token(TOKEN_DECIMAL, "69:64"); | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_hexadecimal(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |     lexer_test_one_token(TOKEN_HEXADECIMAL, "0x123"); | ||||||
|  |     lexer_test_one_token(TOKEN_HEXADECIMAL, "0xDEAD"); | ||||||
|  |     lexer_test_one_token(TOKEN_HEXADECIMAL, "0x0"); | ||||||
|  |     lexer_test_one_token(TOKEN_HEXADECIMAL, "0xabcdef"); | ||||||
|  |     lexer_test_one_token(TOKEN_HEXADECIMAL, "0xABCDEF"); | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_hexadecimal_with_suffix(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |     lexer_test_one_token(TOKEN_HEXADECIMAL, "0x123:8"); | ||||||
|  |     lexer_test_one_token(TOKEN_HEXADECIMAL, "0xDEAD:16"); | ||||||
|  |     lexer_test_one_token(TOKEN_HEXADECIMAL, "0xABC:32"); | ||||||
|  |     lexer_test_one_token(TOKEN_HEXADECIMAL, "0xffff:64"); | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_octal(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |     lexer_test_one_token(TOKEN_OCTAL, "0o777"); | ||||||
|  |     lexer_test_one_token(TOKEN_OCTAL, "0o0"); | ||||||
|  |     lexer_test_one_token(TOKEN_OCTAL, "0o123"); | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_octal_with_suffix(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |     lexer_test_one_token(TOKEN_OCTAL, "0o777:8"); | ||||||
|  |     lexer_test_one_token(TOKEN_OCTAL, "0o123:16"); | ||||||
|  |     lexer_test_one_token(TOKEN_OCTAL, "0o777:32"); | ||||||
|  |     lexer_test_one_token(TOKEN_OCTAL, "0o123:64"); | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_binary(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |     lexer_test_one_token(TOKEN_BINARY, "0b101"); | ||||||
|  |     lexer_test_one_token(TOKEN_BINARY, "0b0"); | ||||||
|  |     lexer_test_one_token(TOKEN_BINARY, "0b1"); | ||||||
|  |     lexer_test_one_token(TOKEN_BINARY, "0b01010101"); | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_binary_with_suffix(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |     lexer_test_one_token(TOKEN_BINARY, "0b101:8"); | ||||||
|  |     lexer_test_one_token(TOKEN_BINARY, "0b0:16"); | ||||||
|  |     lexer_test_one_token(TOKEN_BINARY, "0b1:32"); | ||||||
|  |     lexer_test_one_token(TOKEN_BINARY, "0b01010101:64"); | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_colon(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |     lexer_test_one_token(TOKEN_COLON, ":"); | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_comma(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |     lexer_test_one_token(TOKEN_COMMA, ","); | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_lbracket(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |     lexer_test_one_token(TOKEN_LBRACKET, "["); | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_rbracket(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |     lexer_test_one_token(TOKEN_RBRACKET, "]"); | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_plus(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |     lexer_test_one_token(TOKEN_PLUS, "+"); | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_minus(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |     lexer_test_one_token(TOKEN_MINUS, "-"); | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_asterisk(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |     lexer_test_one_token(TOKEN_ASTERISK, "*"); | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_dot(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |     lexer_test_one_token(TOKEN_DOT, "."); | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_comment(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |     lexer_test_one_token(TOKEN_COMMENT, ";This is a comment"); | ||||||
|  |     lexer_test_one_token(TOKEN_COMMENT, "; Another comment"); | ||||||
|  |     lexer_test_one_token(TOKEN_COMMENT, ";"); | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_whitespace(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |     lexer_test_one_token(TOKEN_WHITESPACE, " "); | ||||||
|  |     lexer_test_one_token(TOKEN_WHITESPACE, "  "); | ||||||
|  |     lexer_test_one_token(TOKEN_WHITESPACE, "\t"); | ||||||
|  |     lexer_test_one_token(TOKEN_WHITESPACE, " \t "); | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_newlines(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     // Test simple newline | ||||||
|  |     lexer_t lex = {}; | ||||||
|  |     lexer_setup_memory_test(&lex, "\n"); | ||||||
|  |     lexer_expect_one_token(&lex, TOKEN_NEWLINE, "\n", 0, 0); | ||||||
|  |     lexer_expect_eof(&lex); | ||||||
|  |     lexer_close(&lex); | ||||||
|  |  | ||||||
|  |     // Test Windows-style newline | ||||||
|  |     lexer_t lex2 = {}; | ||||||
|  |     lexer_setup_memory_test(&lex2, "\r\n"); | ||||||
|  |     lexer_expect_one_token(&lex2, TOKEN_NEWLINE, "\r\n", 0, 0); | ||||||
|  |     lexer_expect_eof(&lex2); | ||||||
|  |     lexer_close(&lex2); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_line_numbers(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     lexer_t lex = {}; | ||||||
|  |     lexer_setup_memory_test(&lex, "a\nb\nc"); | ||||||
|  |  | ||||||
|  |     lexer_expect_one_token(&lex, TOKEN_IDENTIFIER, "a", 0, 0); | ||||||
|  |     lexer_expect_one_token(&lex, TOKEN_NEWLINE, "\n", 0, 1); | ||||||
|  |     lexer_expect_one_token(&lex, TOKEN_IDENTIFIER, "b", 1, 0); | ||||||
|  |     lexer_expect_one_token(&lex, TOKEN_NEWLINE, "\n", 1, 1); | ||||||
|  |     lexer_expect_one_token(&lex, TOKEN_IDENTIFIER, "c", 2, 0); | ||||||
|  |     lexer_expect_eof(&lex); | ||||||
|  |     lexer_close(&lex); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_decimal_boundary(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     boundary_t boundaries[] = { | ||||||
|  |         {"123,",    {TOKEN_DECIMAL, "123", 0, 0}, {TOKEN_COMMA, ",", 0, 3}      }, | ||||||
|  |         {"123:",    {TOKEN_DECIMAL, "123", 0, 0}, {TOKEN_COLON, ":", 0, 3}      }, | ||||||
|  |         {"123[",    {TOKEN_DECIMAL, "123", 0, 0}, {TOKEN_LBRACKET, "[", 0, 3}   }, | ||||||
|  |         {"123]",    {TOKEN_DECIMAL, "123", 0, 0}, {TOKEN_RBRACKET, "]", 0, 3}   }, | ||||||
|  |         {"123+",    {TOKEN_DECIMAL, "123", 0, 0}, {TOKEN_PLUS, "+", 0, 3}       }, | ||||||
|  |         {"123-",    {TOKEN_DECIMAL, "123", 0, 0}, {TOKEN_MINUS, "-", 0, 3}      }, | ||||||
|  |         {"123*",    {TOKEN_DECIMAL, "123", 0, 0}, {TOKEN_ASTERISK, "*", 0, 3}   }, | ||||||
|  |         {"123.",    {TOKEN_DECIMAL, "123", 0, 0}, {TOKEN_DOT, ".", 0, 3}        }, | ||||||
|  |         {"123;",    {TOKEN_DECIMAL, "123", 0, 0}, {TOKEN_COMMENT, ";", 0, 3}    }, | ||||||
|  |         {"123\n",   {TOKEN_DECIMAL, "123", 0, 0}, {TOKEN_NEWLINE, "\n", 0, 3}   }, | ||||||
|  |         {"123\r\n", {TOKEN_DECIMAL, "123", 0, 0}, {TOKEN_NEWLINE, "\r\n", 0, 3} }, | ||||||
|  |         {"123 ",    {TOKEN_DECIMAL, "123", 0, 0}, {TOKEN_WHITESPACE, " ", 0, 3} }, | ||||||
|  |         {"123\t",   {TOKEN_DECIMAL, "123", 0, 0}, {TOKEN_WHITESPACE, "\t", 0, 3}}, | ||||||
|  |         {nullptr,   {},                           {}                            }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     test_lexer_boundary(boundaries); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_hexadecimal_boundary(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     boundary_t boundaries[] = { | ||||||
|  |         {"0x123,",    {TOKEN_HEXADECIMAL, "0x123", 0, 0}, {TOKEN_COMMA, ",", 0, 5}      }, | ||||||
|  |         {"0x123:",    {TOKEN_HEXADECIMAL, "0x123", 0, 0}, {TOKEN_COLON, ":", 0, 5}      }, | ||||||
|  |         {"0x123[",    {TOKEN_HEXADECIMAL, "0x123", 0, 0}, {TOKEN_LBRACKET, "[", 0, 5}   }, | ||||||
|  |         {"0x123]",    {TOKEN_HEXADECIMAL, "0x123", 0, 0}, {TOKEN_RBRACKET, "]", 0, 5}   }, | ||||||
|  |         {"0x123+",    {TOKEN_HEXADECIMAL, "0x123", 0, 0}, {TOKEN_PLUS, "+", 0, 5}       }, | ||||||
|  |         {"0x123-",    {TOKEN_HEXADECIMAL, "0x123", 0, 0}, {TOKEN_MINUS, "-", 0, 5}      }, | ||||||
|  |         {"0x123*",    {TOKEN_HEXADECIMAL, "0x123", 0, 0}, {TOKEN_ASTERISK, "*", 0, 5}   }, | ||||||
|  |         {"0x123.",    {TOKEN_HEXADECIMAL, "0x123", 0, 0}, {TOKEN_DOT, ".", 0, 5}        }, | ||||||
|  |         {"0x123;",    {TOKEN_HEXADECIMAL, "0x123", 0, 0}, {TOKEN_COMMENT, ";", 0, 5}    }, | ||||||
|  |         {"0x123\n",   {TOKEN_HEXADECIMAL, "0x123", 0, 0}, {TOKEN_NEWLINE, "\n", 0, 5}   }, | ||||||
|  |         {"0x123\r\n", {TOKEN_HEXADECIMAL, "0x123", 0, 0}, {TOKEN_NEWLINE, "\r\n", 0, 5} }, | ||||||
|  |         {"0x123 ",    {TOKEN_HEXADECIMAL, "0x123", 0, 0}, {TOKEN_WHITESPACE, " ", 0, 5} }, | ||||||
|  |         {"0x123\t",   {TOKEN_HEXADECIMAL, "0x123", 0, 0}, {TOKEN_WHITESPACE, "\t", 0, 5}}, | ||||||
|  |         {nullptr,     {},                                 {}                            }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     test_lexer_boundary(boundaries); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_octal_boundary(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     boundary_t boundaries[] = { | ||||||
|  |         {"0o123,",    {TOKEN_OCTAL, "0o123", 0, 0}, {TOKEN_COMMA, ",", 0, 5}      }, | ||||||
|  |         {"0o123:",    {TOKEN_OCTAL, "0o123", 0, 0}, {TOKEN_COLON, ":", 0, 5}      }, | ||||||
|  |         {"0o123[",    {TOKEN_OCTAL, "0o123", 0, 0}, {TOKEN_LBRACKET, "[", 0, 5}   }, | ||||||
|  |         {"0o123]",    {TOKEN_OCTAL, "0o123", 0, 0}, {TOKEN_RBRACKET, "]", 0, 5}   }, | ||||||
|  |         {"0o123+",    {TOKEN_OCTAL, "0o123", 0, 0}, {TOKEN_PLUS, "+", 0, 5}       }, | ||||||
|  |         {"0o123-",    {TOKEN_OCTAL, "0o123", 0, 0}, {TOKEN_MINUS, "-", 0, 5}      }, | ||||||
|  |         {"0o123*",    {TOKEN_OCTAL, "0o123", 0, 0}, {TOKEN_ASTERISK, "*", 0, 5}   }, | ||||||
|  |         {"0o123.",    {TOKEN_OCTAL, "0o123", 0, 0}, {TOKEN_DOT, ".", 0, 5}        }, | ||||||
|  |         {"0o123;",    {TOKEN_OCTAL, "0o123", 0, 0}, {TOKEN_COMMENT, ";", 0, 5}    }, | ||||||
|  |         {"0o123\n",   {TOKEN_OCTAL, "0o123", 0, 0}, {TOKEN_NEWLINE, "\n", 0, 5}   }, | ||||||
|  |         {"0o123\r\n", {TOKEN_OCTAL, "0o123", 0, 0}, {TOKEN_NEWLINE, "\r\n", 0, 5} }, | ||||||
|  |         {"0o123 ",    {TOKEN_OCTAL, "0o123", 0, 0}, {TOKEN_WHITESPACE, " ", 0, 5} }, | ||||||
|  |         {"0o123\t",   {TOKEN_OCTAL, "0o123", 0, 0}, {TOKEN_WHITESPACE, "\t", 0, 5}}, | ||||||
|  |         {nullptr,     {},                           {}                            }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     test_lexer_boundary(boundaries); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_binary_boundary(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     boundary_t boundaries[] = { | ||||||
|  |         {"0b101,",    {TOKEN_BINARY, "0b101", 0, 0}, {TOKEN_COMMA, ",", 0, 5}      }, | ||||||
|  |         {"0b101:",    {TOKEN_BINARY, "0b101", 0, 0}, {TOKEN_COLON, ":", 0, 5}      }, | ||||||
|  |         {"0b101[",    {TOKEN_BINARY, "0b101", 0, 0}, {TOKEN_LBRACKET, "[", 0, 5}   }, | ||||||
|  |         {"0b101]",    {TOKEN_BINARY, "0b101", 0, 0}, {TOKEN_RBRACKET, "]", 0, 5}   }, | ||||||
|  |         {"0b101+",    {TOKEN_BINARY, "0b101", 0, 0}, {TOKEN_PLUS, "+", 0, 5}       }, | ||||||
|  |         {"0b101-",    {TOKEN_BINARY, "0b101", 0, 0}, {TOKEN_MINUS, "-", 0, 5}      }, | ||||||
|  |         {"0b101*",    {TOKEN_BINARY, "0b101", 0, 0}, {TOKEN_ASTERISK, "*", 0, 5}   }, | ||||||
|  |         {"0b101.",    {TOKEN_BINARY, "0b101", 0, 0}, {TOKEN_DOT, ".", 0, 5}        }, | ||||||
|  |         {"0b101;",    {TOKEN_BINARY, "0b101", 0, 0}, {TOKEN_COMMENT, ";", 0, 5}    }, | ||||||
|  |         {"0b101\n",   {TOKEN_BINARY, "0b101", 0, 0}, {TOKEN_NEWLINE, "\n", 0, 5}   }, | ||||||
|  |         {"0b101\r\n", {TOKEN_BINARY, "0b101", 0, 0}, {TOKEN_NEWLINE, "\r\n", 0, 5} }, | ||||||
|  |         {"0b101 ",    {TOKEN_BINARY, "0b101", 0, 0}, {TOKEN_WHITESPACE, " ", 0, 5} }, | ||||||
|  |         {"0b101\t",   {TOKEN_BINARY, "0b101", 0, 0}, {TOKEN_WHITESPACE, "\t", 0, 5}}, | ||||||
|  |         {nullptr,     {},                            {}                            }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     test_lexer_boundary(boundaries); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_colon_boundary(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     boundary_t boundaries[] = { | ||||||
|  |         {":,",    {TOKEN_COLON, ":", 0, 0}, {TOKEN_COMMA, ",", 0, 1}      }, | ||||||
|  |         {"::",    {TOKEN_COLON, ":", 0, 0}, {TOKEN_COLON, ":", 0, 1}      }, | ||||||
|  |         {":[",    {TOKEN_COLON, ":", 0, 0}, {TOKEN_LBRACKET, "[", 0, 1}   }, | ||||||
|  |         {":]",    {TOKEN_COLON, ":", 0, 0}, {TOKEN_RBRACKET, "]", 0, 1}   }, | ||||||
|  |         {":+",    {TOKEN_COLON, ":", 0, 0}, {TOKEN_PLUS, "+", 0, 1}       }, | ||||||
|  |         {":-",    {TOKEN_COLON, ":", 0, 0}, {TOKEN_MINUS, "-", 0, 1}      }, | ||||||
|  |         {":*",    {TOKEN_COLON, ":", 0, 0}, {TOKEN_ASTERISK, "*", 0, 1}   }, | ||||||
|  |         {":.",    {TOKEN_COLON, ":", 0, 0}, {TOKEN_DOT, ".", 0, 1}        }, | ||||||
|  |         {":;",    {TOKEN_COLON, ":", 0, 0}, {TOKEN_COMMENT, ";", 0, 1}    }, | ||||||
|  |         {":\n",   {TOKEN_COLON, ":", 0, 0}, {TOKEN_NEWLINE, "\n", 0, 1}   }, | ||||||
|  |         {":\r\n", {TOKEN_COLON, ":", 0, 0}, {TOKEN_NEWLINE, "\r\n", 0, 1} }, | ||||||
|  |         {": ",    {TOKEN_COLON, ":", 0, 0}, {TOKEN_WHITESPACE, " ", 0, 1} }, | ||||||
|  |         {":\t",   {TOKEN_COLON, ":", 0, 0}, {TOKEN_WHITESPACE, "\t", 0, 1}}, | ||||||
|  |         {nullptr, {},                       {}                            }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     test_lexer_boundary(boundaries); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_comma_boundary(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     boundary_t boundaries[] = { | ||||||
|  |         {",,",    {TOKEN_COMMA, ",", 0, 0}, {TOKEN_COMMA, ",", 0, 1}      }, | ||||||
|  |         {",:",    {TOKEN_COMMA, ",", 0, 0}, {TOKEN_COLON, ":", 0, 1}      }, | ||||||
|  |         {",[",    {TOKEN_COMMA, ",", 0, 0}, {TOKEN_LBRACKET, "[", 0, 1}   }, | ||||||
|  |         {",]",    {TOKEN_COMMA, ",", 0, 0}, {TOKEN_RBRACKET, "]", 0, 1}   }, | ||||||
|  |         {",+",    {TOKEN_COMMA, ",", 0, 0}, {TOKEN_PLUS, "+", 0, 1}       }, | ||||||
|  |         {",-",    {TOKEN_COMMA, ",", 0, 0}, {TOKEN_MINUS, "-", 0, 1}      }, | ||||||
|  |         {",*",    {TOKEN_COMMA, ",", 0, 0}, {TOKEN_ASTERISK, "*", 0, 1}   }, | ||||||
|  |         {",.",    {TOKEN_COMMA, ",", 0, 0}, {TOKEN_DOT, ".", 0, 1}        }, | ||||||
|  |         {",;",    {TOKEN_COMMA, ",", 0, 0}, {TOKEN_COMMENT, ";", 0, 1}    }, | ||||||
|  |         {",\n",   {TOKEN_COMMA, ",", 0, 0}, {TOKEN_NEWLINE, "\n", 0, 1}   }, | ||||||
|  |         {",\r\n", {TOKEN_COMMA, ",", 0, 0}, {TOKEN_NEWLINE, "\r\n", 0, 1} }, | ||||||
|  |         {", ",    {TOKEN_COMMA, ",", 0, 0}, {TOKEN_WHITESPACE, " ", 0, 1} }, | ||||||
|  |         {",\t",   {TOKEN_COMMA, ",", 0, 0}, {TOKEN_WHITESPACE, "\t", 0, 1}}, | ||||||
|  |         {nullptr, {},                       {}                            }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     test_lexer_boundary(boundaries); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_lbracket_boundary(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     boundary_t boundaries[] = { | ||||||
|  |         {"[,",    {TOKEN_LBRACKET, "[", 0, 0}, {TOKEN_COMMA, ",", 0, 1}      }, | ||||||
|  |         {"[:",    {TOKEN_LBRACKET, "[", 0, 0}, {TOKEN_COLON, ":", 0, 1}      }, | ||||||
|  |         {"[[",    {TOKEN_LBRACKET, "[", 0, 0}, {TOKEN_LBRACKET, "[", 0, 1}   }, | ||||||
|  |         {"[]",    {TOKEN_LBRACKET, "[", 0, 0}, {TOKEN_RBRACKET, "]", 0, 1}   }, | ||||||
|  |         {"[+",    {TOKEN_LBRACKET, "[", 0, 0}, {TOKEN_PLUS, "+", 0, 1}       }, | ||||||
|  |         {"[-",    {TOKEN_LBRACKET, "[", 0, 0}, {TOKEN_MINUS, "-", 0, 1}      }, | ||||||
|  |         {"[*",    {TOKEN_LBRACKET, "[", 0, 0}, {TOKEN_ASTERISK, "*", 0, 1}   }, | ||||||
|  |         {"[.",    {TOKEN_LBRACKET, "[", 0, 0}, {TOKEN_DOT, ".", 0, 1}        }, | ||||||
|  |         {"[;",    {TOKEN_LBRACKET, "[", 0, 0}, {TOKEN_COMMENT, ";", 0, 1}    }, | ||||||
|  |         {"[\n",   {TOKEN_LBRACKET, "[", 0, 0}, {TOKEN_NEWLINE, "\n", 0, 1}   }, | ||||||
|  |         {"[\r\n", {TOKEN_LBRACKET, "[", 0, 0}, {TOKEN_NEWLINE, "\r\n", 0, 1} }, | ||||||
|  |         {"[ ",    {TOKEN_LBRACKET, "[", 0, 0}, {TOKEN_WHITESPACE, " ", 0, 1} }, | ||||||
|  |         {"[\t",   {TOKEN_LBRACKET, "[", 0, 0}, {TOKEN_WHITESPACE, "\t", 0, 1}}, | ||||||
|  |         {nullptr, {},                          {}                            }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     test_lexer_boundary(boundaries); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_rbracket_boundary(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     boundary_t boundaries[] = { | ||||||
|  |         {"],",    {TOKEN_RBRACKET, "]", 0, 0}, {TOKEN_COMMA, ",", 0, 1}      }, | ||||||
|  |         {"]:",    {TOKEN_RBRACKET, "]", 0, 0}, {TOKEN_COLON, ":", 0, 1}      }, | ||||||
|  |         {"][",    {TOKEN_RBRACKET, "]", 0, 0}, {TOKEN_LBRACKET, "[", 0, 1}   }, | ||||||
|  |         {"]]",    {TOKEN_RBRACKET, "]", 0, 0}, {TOKEN_RBRACKET, "]", 0, 1}   }, | ||||||
|  |         {"]+",    {TOKEN_RBRACKET, "]", 0, 0}, {TOKEN_PLUS, "+", 0, 1}       }, | ||||||
|  |         {"]-",    {TOKEN_RBRACKET, "]", 0, 0}, {TOKEN_MINUS, "-", 0, 1}      }, | ||||||
|  |         {"]*",    {TOKEN_RBRACKET, "]", 0, 0}, {TOKEN_ASTERISK, "*", 0, 1}   }, | ||||||
|  |         {"].",    {TOKEN_RBRACKET, "]", 0, 0}, {TOKEN_DOT, ".", 0, 1}        }, | ||||||
|  |         {"];",    {TOKEN_RBRACKET, "]", 0, 0}, {TOKEN_COMMENT, ";", 0, 1}    }, | ||||||
|  |         {"]\n",   {TOKEN_RBRACKET, "]", 0, 0}, {TOKEN_NEWLINE, "\n", 0, 1}   }, | ||||||
|  |         {"]\r\n", {TOKEN_RBRACKET, "]", 0, 0}, {TOKEN_NEWLINE, "\r\n", 0, 1} }, | ||||||
|  |         {"] ",    {TOKEN_RBRACKET, "]", 0, 0}, {TOKEN_WHITESPACE, " ", 0, 1} }, | ||||||
|  |         {"]\t",   {TOKEN_RBRACKET, "]", 0, 0}, {TOKEN_WHITESPACE, "\t", 0, 1}}, | ||||||
|  |         {nullptr, {},                          {}                            }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     test_lexer_boundary(boundaries); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_plus_boundary(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     boundary_t boundaries[] = { | ||||||
|  |         {"+,",    {TOKEN_PLUS, "+", 0, 0}, {TOKEN_COMMA, ",", 0, 1}      }, | ||||||
|  |         {"+:",    {TOKEN_PLUS, "+", 0, 0}, {TOKEN_COLON, ":", 0, 1}      }, | ||||||
|  |         {"+[",    {TOKEN_PLUS, "+", 0, 0}, {TOKEN_LBRACKET, "[", 0, 1}   }, | ||||||
|  |         {"+]",    {TOKEN_PLUS, "+", 0, 0}, {TOKEN_RBRACKET, "]", 0, 1}   }, | ||||||
|  |         {"++",    {TOKEN_PLUS, "+", 0, 0}, {TOKEN_PLUS, "+", 0, 1}       }, | ||||||
|  |         {"+-",    {TOKEN_PLUS, "+", 0, 0}, {TOKEN_MINUS, "-", 0, 1}      }, | ||||||
|  |         {"+*",    {TOKEN_PLUS, "+", 0, 0}, {TOKEN_ASTERISK, "*", 0, 1}   }, | ||||||
|  |         {"+.",    {TOKEN_PLUS, "+", 0, 0}, {TOKEN_DOT, ".", 0, 1}        }, | ||||||
|  |         {"+;",    {TOKEN_PLUS, "+", 0, 0}, {TOKEN_COMMENT, ";", 0, 1}    }, | ||||||
|  |         {"+\n",   {TOKEN_PLUS, "+", 0, 0}, {TOKEN_NEWLINE, "\n", 0, 1}   }, | ||||||
|  |         {"+\r\n", {TOKEN_PLUS, "+", 0, 0}, {TOKEN_NEWLINE, "\r\n", 0, 1} }, | ||||||
|  |         {"+ ",    {TOKEN_PLUS, "+", 0, 0}, {TOKEN_WHITESPACE, " ", 0, 1} }, | ||||||
|  |         {"+\t",   {TOKEN_PLUS, "+", 0, 0}, {TOKEN_WHITESPACE, "\t", 0, 1}}, | ||||||
|  |         {nullptr, {},                      {}                            }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     test_lexer_boundary(boundaries); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_minus_boundary(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     boundary_t boundaries[] = { | ||||||
|  |         {"-,",    {TOKEN_MINUS, "-", 0, 0}, {TOKEN_COMMA, ",", 0, 1}      }, | ||||||
|  |         {"-:",    {TOKEN_MINUS, "-", 0, 0}, {TOKEN_COLON, ":", 0, 1}      }, | ||||||
|  |         {"-[",    {TOKEN_MINUS, "-", 0, 0}, {TOKEN_LBRACKET, "[", 0, 1}   }, | ||||||
|  |         {"-]",    {TOKEN_MINUS, "-", 0, 0}, {TOKEN_RBRACKET, "]", 0, 1}   }, | ||||||
|  |         {"-+",    {TOKEN_MINUS, "-", 0, 0}, {TOKEN_PLUS, "+", 0, 1}       }, | ||||||
|  |         {"--",    {TOKEN_MINUS, "-", 0, 0}, {TOKEN_MINUS, "-", 0, 1}      }, | ||||||
|  |         {"-*",    {TOKEN_MINUS, "-", 0, 0}, {TOKEN_ASTERISK, "*", 0, 1}   }, | ||||||
|  |         {"-.",    {TOKEN_MINUS, "-", 0, 0}, {TOKEN_DOT, ".", 0, 1}        }, | ||||||
|  |         {"-;",    {TOKEN_MINUS, "-", 0, 0}, {TOKEN_COMMENT, ";", 0, 1}    }, | ||||||
|  |         {"-\n",   {TOKEN_MINUS, "-", 0, 0}, {TOKEN_NEWLINE, "\n", 0, 1}   }, | ||||||
|  |         {"-\r\n", {TOKEN_MINUS, "-", 0, 0}, {TOKEN_NEWLINE, "\r\n", 0, 1} }, | ||||||
|  |         {"- ",    {TOKEN_MINUS, "-", 0, 0}, {TOKEN_WHITESPACE, " ", 0, 1} }, | ||||||
|  |         {"-\t",   {TOKEN_MINUS, "-", 0, 0}, {TOKEN_WHITESPACE, "\t", 0, 1}}, | ||||||
|  |         {nullptr, {},                       {}                            }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     test_lexer_boundary(boundaries); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_asterisk_boundary(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     boundary_t boundaries[] = { | ||||||
|  |         {"*,",    {TOKEN_ASTERISK, "*", 0, 0}, {TOKEN_COMMA, ",", 0, 1}      }, | ||||||
|  |         {"*:",    {TOKEN_ASTERISK, "*", 0, 0}, {TOKEN_COLON, ":", 0, 1}      }, | ||||||
|  |         {"*[",    {TOKEN_ASTERISK, "*", 0, 0}, {TOKEN_LBRACKET, "[", 0, 1}   }, | ||||||
|  |         {"*]",    {TOKEN_ASTERISK, "*", 0, 0}, {TOKEN_RBRACKET, "]", 0, 1}   }, | ||||||
|  |         {"*+",    {TOKEN_ASTERISK, "*", 0, 0}, {TOKEN_PLUS, "+", 0, 1}       }, | ||||||
|  |         {"*-",    {TOKEN_ASTERISK, "*", 0, 0}, {TOKEN_MINUS, "-", 0, 1}      }, | ||||||
|  |         {"**",    {TOKEN_ASTERISK, "*", 0, 0}, {TOKEN_ASTERISK, "*", 0, 1}   }, | ||||||
|  |         {"*.",    {TOKEN_ASTERISK, "*", 0, 0}, {TOKEN_DOT, ".", 0, 1}        }, | ||||||
|  |         {"*;",    {TOKEN_ASTERISK, "*", 0, 0}, {TOKEN_COMMENT, ";", 0, 1}    }, | ||||||
|  |         {"*\n",   {TOKEN_ASTERISK, "*", 0, 0}, {TOKEN_NEWLINE, "\n", 0, 1}   }, | ||||||
|  |         {"*\r\n", {TOKEN_ASTERISK, "*", 0, 0}, {TOKEN_NEWLINE, "\r\n", 0, 1} }, | ||||||
|  |         {"* ",    {TOKEN_ASTERISK, "*", 0, 0}, {TOKEN_WHITESPACE, " ", 0, 1} }, | ||||||
|  |         {"*\t",   {TOKEN_ASTERISK, "*", 0, 0}, {TOKEN_WHITESPACE, "\t", 0, 1}}, | ||||||
|  |         {nullptr, {},                          {}                            }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     test_lexer_boundary(boundaries); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_dot_boundary(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     boundary_t boundaries[] = { | ||||||
|  |         {".,",    {TOKEN_DOT, ".", 0, 0}, {TOKEN_COMMA, ",", 0, 1}      }, | ||||||
|  |         {".:",    {TOKEN_DOT, ".", 0, 0}, {TOKEN_COLON, ":", 0, 1}      }, | ||||||
|  |         {".[",    {TOKEN_DOT, ".", 0, 0}, {TOKEN_LBRACKET, "[", 0, 1}   }, | ||||||
|  |         {".]",    {TOKEN_DOT, ".", 0, 0}, {TOKEN_RBRACKET, "]", 0, 1}   }, | ||||||
|  |         {".+",    {TOKEN_DOT, ".", 0, 0}, {TOKEN_PLUS, "+", 0, 1}       }, | ||||||
|  |         {".-",    {TOKEN_DOT, ".", 0, 0}, {TOKEN_MINUS, "-", 0, 1}      }, | ||||||
|  |         {".*",    {TOKEN_DOT, ".", 0, 0}, {TOKEN_ASTERISK, "*", 0, 1}   }, | ||||||
|  |         {"..",    {TOKEN_DOT, ".", 0, 0}, {TOKEN_DOT, ".", 0, 1}        }, | ||||||
|  |         {".;",    {TOKEN_DOT, ".", 0, 0}, {TOKEN_COMMENT, ";", 0, 1}    }, | ||||||
|  |         {".\n",   {TOKEN_DOT, ".", 0, 0}, {TOKEN_NEWLINE, "\n", 0, 1}   }, | ||||||
|  |         {".\r\n", {TOKEN_DOT, ".", 0, 0}, {TOKEN_NEWLINE, "\r\n", 0, 1} }, | ||||||
|  |         {". ",    {TOKEN_DOT, ".", 0, 0}, {TOKEN_WHITESPACE, " ", 0, 1} }, | ||||||
|  |         {".\t",   {TOKEN_DOT, ".", 0, 0}, {TOKEN_WHITESPACE, "\t", 0, 1}}, | ||||||
|  |         {nullptr, {},                     {}                            }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     test_lexer_boundary(boundaries); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_comment_boundary(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     boundary_t boundaries[] = { | ||||||
|  |         {";comment\n",   {TOKEN_COMMENT, ";comment", 0, 0}, {TOKEN_NEWLINE, "\n", 0, 8}  }, | ||||||
|  |         {";comment\r\n", {TOKEN_COMMENT, ";comment", 0, 0}, {TOKEN_NEWLINE, "\r\n", 0, 8}}, | ||||||
|  |         {nullptr,        {},                                {}                           }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     test_lexer_boundary(boundaries); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_whitespace_boundary(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     boundary_t boundaries[] = { | ||||||
|  |         {" ,",    {TOKEN_WHITESPACE, " ", 0, 0}, {TOKEN_COMMA, ",", 0, 1}     }, | ||||||
|  |         {" :",    {TOKEN_WHITESPACE, " ", 0, 0}, {TOKEN_COLON, ":", 0, 1}     }, | ||||||
|  |         {" [",    {TOKEN_WHITESPACE, " ", 0, 0}, {TOKEN_LBRACKET, "[", 0, 1}  }, | ||||||
|  |         {" ]",    {TOKEN_WHITESPACE, " ", 0, 0}, {TOKEN_RBRACKET, "]", 0, 1}  }, | ||||||
|  |         {" +",    {TOKEN_WHITESPACE, " ", 0, 0}, {TOKEN_PLUS, "+", 0, 1}      }, | ||||||
|  |         {" -",    {TOKEN_WHITESPACE, " ", 0, 0}, {TOKEN_MINUS, "-", 0, 1}     }, | ||||||
|  |         {" *",    {TOKEN_WHITESPACE, " ", 0, 0}, {TOKEN_ASTERISK, "*", 0, 1}  }, | ||||||
|  |         {" .",    {TOKEN_WHITESPACE, " ", 0, 0}, {TOKEN_DOT, ".", 0, 1}       }, | ||||||
|  |         {" ;",    {TOKEN_WHITESPACE, " ", 0, 0}, {TOKEN_COMMENT, ";", 0, 1}   }, | ||||||
|  |         {" \n",   {TOKEN_WHITESPACE, " ", 0, 0}, {TOKEN_NEWLINE, "\n", 0, 1}  }, | ||||||
|  |         {" \r\n", {TOKEN_WHITESPACE, " ", 0, 0}, {TOKEN_NEWLINE, "\r\n", 0, 1}}, | ||||||
|  |         {nullptr, {},                            {}                           }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     test_lexer_boundary(boundaries); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_newline_boundary(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     boundary_t boundaries[] = { | ||||||
|  |         {"\n,",    {TOKEN_NEWLINE, "\n", 0, 0}, {TOKEN_COMMA, ",", 1, 0}      }, | ||||||
|  |         {"\n:",    {TOKEN_NEWLINE, "\n", 0, 0}, {TOKEN_COLON, ":", 1, 0}      }, | ||||||
|  |         {"\n[",    {TOKEN_NEWLINE, "\n", 0, 0}, {TOKEN_LBRACKET, "[", 1, 0}   }, | ||||||
|  |         {"\n]",    {TOKEN_NEWLINE, "\n", 0, 0}, {TOKEN_RBRACKET, "]", 1, 0}   }, | ||||||
|  |         {"\n+",    {TOKEN_NEWLINE, "\n", 0, 0}, {TOKEN_PLUS, "+", 1, 0}       }, | ||||||
|  |         {"\n-",    {TOKEN_NEWLINE, "\n", 0, 0}, {TOKEN_MINUS, "-", 1, 0}      }, | ||||||
|  |         {"\n*",    {TOKEN_NEWLINE, "\n", 0, 0}, {TOKEN_ASTERISK, "*", 1, 0}   }, | ||||||
|  |         {"\n.",    {TOKEN_NEWLINE, "\n", 0, 0}, {TOKEN_DOT, ".", 1, 0}        }, | ||||||
|  |         {"\n;",    {TOKEN_NEWLINE, "\n", 0, 0}, {TOKEN_COMMENT, ";", 1, 0}    }, | ||||||
|  |         {"\n\n",   {TOKEN_NEWLINE, "\n", 0, 0}, {TOKEN_NEWLINE, "\n", 1, 0}   }, | ||||||
|  |         {"\n\r\n", {TOKEN_NEWLINE, "\n", 0, 0}, {TOKEN_NEWLINE, "\r\n", 1, 0} }, | ||||||
|  |         {"\n ",    {TOKEN_NEWLINE, "\n", 0, 0}, {TOKEN_WHITESPACE, " ", 1, 0} }, | ||||||
|  |         {"\n\t",   {TOKEN_NEWLINE, "\n", 0, 0}, {TOKEN_WHITESPACE, "\t", 1, 0}}, | ||||||
|  |         {nullptr,  {},                          {}                            }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     test_lexer_boundary(boundaries); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_crlf_boundary(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     boundary_t boundaries[] = { | ||||||
|  |         {"\r\n,",    {TOKEN_NEWLINE, "\r\n", 0, 0}, {TOKEN_COMMA, ",", 1, 0}      }, | ||||||
|  |         {"\r\n:",    {TOKEN_NEWLINE, "\r\n", 0, 0}, {TOKEN_COLON, ":", 1, 0}      }, | ||||||
|  |         {"\r\n[",    {TOKEN_NEWLINE, "\r\n", 0, 0}, {TOKEN_LBRACKET, "[", 1, 0}   }, | ||||||
|  |         {"\r\n]",    {TOKEN_NEWLINE, "\r\n", 0, 0}, {TOKEN_RBRACKET, "]", 1, 0}   }, | ||||||
|  |         {"\r\n+",    {TOKEN_NEWLINE, "\r\n", 0, 0}, {TOKEN_PLUS, "+", 1, 0}       }, | ||||||
|  |         {"\r\n-",    {TOKEN_NEWLINE, "\r\n", 0, 0}, {TOKEN_MINUS, "-", 1, 0}      }, | ||||||
|  |         {"\r\n*",    {TOKEN_NEWLINE, "\r\n", 0, 0}, {TOKEN_ASTERISK, "*", 1, 0}   }, | ||||||
|  |         {"\r\n.",    {TOKEN_NEWLINE, "\r\n", 0, 0}, {TOKEN_DOT, ".", 1, 0}        }, | ||||||
|  |         {"\r\n;",    {TOKEN_NEWLINE, "\r\n", 0, 0}, {TOKEN_COMMENT, ";", 1, 0}    }, | ||||||
|  |         {"\r\n\n",   {TOKEN_NEWLINE, "\r\n", 0, 0}, {TOKEN_NEWLINE, "\n", 1, 0}   }, | ||||||
|  |         {"\r\n\r\n", {TOKEN_NEWLINE, "\r\n", 0, 0}, {TOKEN_NEWLINE, "\r\n", 1, 0} }, | ||||||
|  |         {"\r\n ",    {TOKEN_NEWLINE, "\r\n", 0, 0}, {TOKEN_WHITESPACE, " ", 1, 0} }, | ||||||
|  |         {"\r\n\t",   {TOKEN_NEWLINE, "\r\n", 0, 0}, {TOKEN_WHITESPACE, "\t", 1, 0}}, | ||||||
|  |         {nullptr,    {},                            {}                            }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     test_lexer_boundary(boundaries); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_number_boundary(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     boundary_t boundaries[] = { | ||||||
|  |         {"0x123:8,",     {TOKEN_HEXADECIMAL, "0x123:8", 0, 0},  {TOKEN_COMMA, ",", 0, 7}      }, | ||||||
|  |         {"0x123:16:",    {TOKEN_HEXADECIMAL, "0x123:16", 0, 0}, {TOKEN_COLON, ":", 0, 8}      }, | ||||||
|  |         {"0o777:32[",    {TOKEN_OCTAL, "0o777:32", 0, 0},       {TOKEN_LBRACKET, "[", 0, 8}   }, | ||||||
|  |         {"0b101:64]",    {TOKEN_BINARY, "0b101:64", 0, 0},      {TOKEN_RBRACKET, "]", 0, 8}   }, | ||||||
|  |         {"0x123:8+",     {TOKEN_HEXADECIMAL, "0x123:8", 0, 0},  {TOKEN_PLUS, "+", 0, 7}       }, | ||||||
|  |         {"0x123:16-",    {TOKEN_HEXADECIMAL, "0x123:16", 0, 0}, {TOKEN_MINUS, "-", 0, 8}      }, | ||||||
|  |         {"0o777:32*",    {TOKEN_OCTAL, "0o777:32", 0, 0},       {TOKEN_ASTERISK, "*", 0, 8}   }, | ||||||
|  |         {"0b101:64.",    {TOKEN_BINARY, "0b101:64", 0, 0},      {TOKEN_DOT, ".", 0, 8}        }, | ||||||
|  |         {"0x123:8;",     {TOKEN_HEXADECIMAL, "0x123:8", 0, 0},  {TOKEN_COMMENT, ";", 0, 7}    }, | ||||||
|  |         {"0x123:16\n",   {TOKEN_HEXADECIMAL, "0x123:16", 0, 0}, {TOKEN_NEWLINE, "\n", 0, 8}   }, | ||||||
|  |         {"0o777:32\r\n", {TOKEN_OCTAL, "0o777:32", 0, 0},       {TOKEN_NEWLINE, "\r\n", 0, 8} }, | ||||||
|  |         {"0b101:64 ",    {TOKEN_BINARY, "0b101:64", 0, 0},      {TOKEN_WHITESPACE, " ", 0, 8} }, | ||||||
|  |         {"0x123:8\t",    {TOKEN_HEXADECIMAL, "0x123:8", 0, 0},  {TOKEN_WHITESPACE, "\t", 0, 7}}, | ||||||
|  |         {nullptr,        {},                                    {}                            }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     test_lexer_boundary(boundaries); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_maximum_length_numbers(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     char *numbers[] = { | ||||||
|  |         "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" | ||||||
|  |         "9999999999999999999988", | ||||||
|  |         "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" | ||||||
|  |         "9999999999999999998:64", | ||||||
|  |         "0x99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" | ||||||
|  |         "9999999999999999999988", | ||||||
|  |         "0x99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" | ||||||
|  |         "9999999999999999998:64", | ||||||
|  |         nullptr, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     for (size_t i = 0; numbers[i]; ++i) { | ||||||
|  |         auto number = numbers[i]; | ||||||
|  |         munit_assert_size(128, ==, strlen(number)); | ||||||
|  |         lexer_t lex = {}; | ||||||
|  |         lexer_token_t token = {}; | ||||||
|  |         lexer_setup_memory_test(&lex, number); | ||||||
|  |         lexer_next(&lex, &token); | ||||||
|  |         munit_assert_true(token.id == TOKEN_DECIMAL || token.id == TOKEN_HEXADECIMAL); | ||||||
|  |         munit_assert_size(128, ==, strlen(token.value)); | ||||||
|  |         lexer_token_cleanup(&token); | ||||||
|  |         lexer_close(&lex); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_too_long_numbers(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     char *numbers[] = { | ||||||
|  |         "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" | ||||||
|  |         "99999999999999999999988", | ||||||
|  |         "0x99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" | ||||||
|  |         "99999999999999999999988", | ||||||
|  |         "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" | ||||||
|  |         "99999999999999999998:64", | ||||||
|  |         "0x99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" | ||||||
|  |         "99999999999999999998:64", | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     // Without suffix we expect 128 characters and then failure | ||||||
|  |     for (size_t i = 0; i < 2; ++i) { | ||||||
|  |         auto number = numbers[i]; | ||||||
|  |         munit_assert_size(129, ==, strlen(number)); | ||||||
|  |         lexer_t lex = {}; | ||||||
|  |         lexer_token_t token = {}; | ||||||
|  |         lexer_setup_memory_test(&lex, number); | ||||||
|  |         lexer_next(&lex, &token); | ||||||
|  |         munit_assert_int(TOKEN_ERROR, ==, token.id); | ||||||
|  |         munit_assert_size(128, ==, strlen(token.value)); | ||||||
|  |         lexer_token_cleanup(&token); | ||||||
|  |         lexer_close(&lex); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // With suffix we fail at the suffix boundary | ||||||
|  |     for (size_t i = 2; i < 4; ++i) { | ||||||
|  |         auto number = numbers[i]; | ||||||
|  |         munit_assert_size(129, ==, strlen(number)); | ||||||
|  |         lexer_t lex = {}; | ||||||
|  |         lexer_token_t token = {}; | ||||||
|  |         lexer_setup_memory_test(&lex, number); | ||||||
|  |         lexer_next(&lex, &token); | ||||||
|  |         munit_assert_int(TOKEN_ERROR, ==, token.id); | ||||||
|  |         munit_assert_size(128, >=, strlen(token.value)); | ||||||
|  |         lexer_token_cleanup(&token); | ||||||
|  |  | ||||||
|  |         lexer_expect_one_token(&lex, TOKEN_COLON, ":", 0, 126); | ||||||
|  |         lexer_expect_one_token(&lex, TOKEN_DECIMAL, "64", 0, 127); | ||||||
|  |         lexer_close(&lex); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_max_whitespace_length(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     char whitespace[1025]; | ||||||
|  |     memset(whitespace, ' ', 1024); | ||||||
|  |     whitespace[1024] = '\0'; | ||||||
|  |  | ||||||
|  |     munit_assert_size(1024, ==, strlen(whitespace)); | ||||||
|  |     lexer_t lex = {}; | ||||||
|  |     lexer_token_t token = {}; | ||||||
|  |     lexer_setup_memory_test(&lex, whitespace); | ||||||
|  |     lexer_next(&lex, &token); | ||||||
|  |     munit_assert_int(TOKEN_WHITESPACE, ==, token.id); | ||||||
|  |     munit_assert_size(1024, ==, strlen(token.value)); | ||||||
|  |     lexer_token_cleanup(&token); | ||||||
|  |     lexer_close(&lex); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitResult test_lexer_too_long_whitespace(const MunitParameter params[], void *data) { | ||||||
|  |     (void)params; | ||||||
|  |     (void)data; | ||||||
|  |  | ||||||
|  |     char whitespace[1026]; | ||||||
|  |     memset(whitespace, ' ', 1025); | ||||||
|  |     whitespace[1025] = '\0'; | ||||||
|  |  | ||||||
|  |     munit_assert_size(1025, ==, strlen(whitespace)); | ||||||
|  |     lexer_t lex = {}; | ||||||
|  |     lexer_token_t token = {}; | ||||||
|  |     lexer_setup_memory_test(&lex, whitespace); | ||||||
|  |     lexer_next(&lex, &token); | ||||||
|  |     munit_assert_int(TOKEN_ERROR, ==, token.id); | ||||||
|  |     munit_assert_size(1024, ==, strlen(token.value)); | ||||||
|  |     lexer_token_cleanup(&token); | ||||||
|  |  | ||||||
|  |     lexer_expect_one_token(&lex, TOKEN_WHITESPACE, " ", 0, 1024); | ||||||
|  |     lexer_close(&lex); | ||||||
|  |  | ||||||
|  |     return MUNIT_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MunitTest lexer_tests[] = { | ||||||
|  |     {"/identifier",              test_lexer_identifier,              nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/identifier_boundary",     test_lexer_identifier_boundary,     nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/decimal",                 test_lexer_decimal,                 nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/decimal_boundary",        test_lexer_decimal_boundary,        nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/hexadecimal",             test_lexer_hexadecimal,             nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/hexadecimal_with_suffix", test_lexer_hexadecimal_with_suffix, nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/hexadecimal_boundary",    test_lexer_hexadecimal_boundary,    nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/octal",                   test_lexer_octal,                   nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/octal_with_suffix",       test_lexer_octal_with_suffix,       nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/octal_boundary",          test_lexer_octal_boundary,          nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/binary",                  test_lexer_binary,                  nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/binary_with_suffix",      test_lexer_binary_with_suffix,      nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/binary_boundary",         test_lexer_binary_boundary,         nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/number_boundary",         test_lexer_number_boundary,         nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/colon",                   test_lexer_colon,                   nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/colon_boundary",          test_lexer_colon_boundary,          nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/comma",                   test_lexer_comma,                   nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/comma_boundary",          test_lexer_comma_boundary,          nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/lbracket",                test_lexer_lbracket,                nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/lbracket_boundary",       test_lexer_lbracket_boundary,       nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/rbracket",                test_lexer_rbracket,                nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/rbracket_boundary",       test_lexer_rbracket_boundary,       nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/plus",                    test_lexer_plus,                    nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/plus_boundary",           test_lexer_plus_boundary,           nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/minus",                   test_lexer_minus,                   nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/minus_boundary",          test_lexer_minus_boundary,          nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/asterisk",                test_lexer_asterisk,                nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/asterisk_boundary",       test_lexer_asterisk_boundary,       nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/dot",                     test_lexer_dot,                     nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/dot_boundary",            test_lexer_dot_boundary,            nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/comment",                 test_lexer_comment,                 nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/comment_boundary",        test_lexer_comment_boundary,        nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/whitespace",              test_lexer_whitespace,              nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/whitespace_boundary",     test_lexer_whitespace_boundary,     nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/newlines",                test_lexer_newlines,                nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/newline_boundary",        test_lexer_newline_boundary,        nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/crlf_boundary",           test_lexer_crlf_boundary,           nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/line_numbers",            test_lexer_line_numbers,            nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/maximum_length_numbers",  test_lexer_maximum_length_numbers,  nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/too_long_numbers",        test_lexer_too_long_numbers,        nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/max_whitespace_length",   test_lexer_max_whitespace_length,   nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {"/too_long_whitespace",     test_lexer_too_long_whitespace,     nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}, | ||||||
|  |     {nullptr,                    nullptr,                            nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr} | ||||||
|  | }; | ||||||
							
								
								
									
										16
									
								
								tests/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								tests/main.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | #include "munit.h" | ||||||
|  |  | ||||||
|  | extern MunitTest ast_tests[]; | ||||||
|  | extern MunitTest lexer_tests[]; | ||||||
|  |  | ||||||
|  | int main(int argc, char *argv[MUNIT_ARRAY_PARAM(argc + 1)]) { | ||||||
|  |     MunitSuite suites[] = { | ||||||
|  |         {"/ast",   ast_tests,   nullptr, 1, MUNIT_SUITE_OPTION_NONE}, | ||||||
|  |         {"/lexer", lexer_tests, nullptr, 1, MUNIT_SUITE_OPTION_NONE}, | ||||||
|  |         {nullptr,  nullptr,     nullptr, 0, MUNIT_SUITE_OPTION_NONE}, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     MunitSuite master_suite = {"/oas", nullptr, suites, 1, MUNIT_SUITE_OPTION_NONE}; | ||||||
|  |  | ||||||
|  |     return munit_suite_main(&master_suite, nullptr, argc, argv); | ||||||
|  | } | ||||||
							
								
								
									
										2055
									
								
								tests/munit.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2055
									
								
								tests/munit.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										535
									
								
								tests/munit.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										535
									
								
								tests/munit.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,535 @@ | |||||||
|  | /* µnit Testing Framework | ||||||
|  |  * Copyright (c) 2013-2017 Evan Nemerson <evan@nemerson.com> | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person | ||||||
|  |  * obtaining a copy of this software and associated documentation | ||||||
|  |  * files (the "Software"), to deal in the Software without | ||||||
|  |  * restriction, including without limitation the rights to use, copy, | ||||||
|  |  * modify, merge, publish, distribute, sublicense, and/or sell copies | ||||||
|  |  * of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be | ||||||
|  |  * included in all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||||
|  |  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||||
|  |  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||||||
|  |  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||||||
|  |  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||||
|  |  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||||||
|  |  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  |  * SOFTWARE. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #if !defined(MUNIT_H) | ||||||
|  | #define MUNIT_H | ||||||
|  |  | ||||||
|  | #include <stdarg.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  |  | ||||||
|  | #define MUNIT_VERSION(major, minor, revision) \ | ||||||
|  |   (((major) << 16) | ((minor) << 8) | (revision)) | ||||||
|  |  | ||||||
|  | #define MUNIT_CURRENT_VERSION MUNIT_VERSION(0, 4, 1) | ||||||
|  |  | ||||||
|  | #if defined(_MSC_VER) && (_MSC_VER < 1600) | ||||||
|  | #  define munit_int8_t   __int8 | ||||||
|  | #  define munit_uint8_t  unsigned __int8 | ||||||
|  | #  define munit_int16_t  __int16 | ||||||
|  | #  define munit_uint16_t unsigned __int16 | ||||||
|  | #  define munit_int32_t  __int32 | ||||||
|  | #  define munit_uint32_t unsigned __int32 | ||||||
|  | #  define munit_int64_t  __int64 | ||||||
|  | #  define munit_uint64_t unsigned __int64 | ||||||
|  | #else | ||||||
|  | #  include <stdint.h> | ||||||
|  | #  define munit_int8_t   int8_t | ||||||
|  | #  define munit_uint8_t  uint8_t | ||||||
|  | #  define munit_int16_t  int16_t | ||||||
|  | #  define munit_uint16_t uint16_t | ||||||
|  | #  define munit_int32_t  int32_t | ||||||
|  | #  define munit_uint32_t uint32_t | ||||||
|  | #  define munit_int64_t  int64_t | ||||||
|  | #  define munit_uint64_t uint64_t | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined(_MSC_VER) && (_MSC_VER < 1800) | ||||||
|  | #  if !defined(PRIi8) | ||||||
|  | #    define PRIi8 "i" | ||||||
|  | #  endif | ||||||
|  | #  if !defined(PRIi16) | ||||||
|  | #    define PRIi16 "i" | ||||||
|  | #  endif | ||||||
|  | #  if !defined(PRIi32) | ||||||
|  | #    define PRIi32 "i" | ||||||
|  | #  endif | ||||||
|  | #  if !defined(PRIi64) | ||||||
|  | #    define PRIi64 "I64i" | ||||||
|  | #  endif | ||||||
|  | #  if !defined(PRId8) | ||||||
|  | #    define PRId8 "d" | ||||||
|  | #  endif | ||||||
|  | #  if !defined(PRId16) | ||||||
|  | #    define PRId16 "d" | ||||||
|  | #  endif | ||||||
|  | #  if !defined(PRId32) | ||||||
|  | #    define PRId32 "d" | ||||||
|  | #  endif | ||||||
|  | #  if !defined(PRId64) | ||||||
|  | #    define PRId64 "I64d" | ||||||
|  | #  endif | ||||||
|  | #  if !defined(PRIx8) | ||||||
|  | #    define PRIx8 "x" | ||||||
|  | #  endif | ||||||
|  | #  if !defined(PRIx16) | ||||||
|  | #    define PRIx16 "x" | ||||||
|  | #  endif | ||||||
|  | #  if !defined(PRIx32) | ||||||
|  | #    define PRIx32 "x" | ||||||
|  | #  endif | ||||||
|  | #  if !defined(PRIx64) | ||||||
|  | #    define PRIx64 "I64x" | ||||||
|  | #  endif | ||||||
|  | #  if !defined(PRIu8) | ||||||
|  | #    define PRIu8 "u" | ||||||
|  | #  endif | ||||||
|  | #  if !defined(PRIu16) | ||||||
|  | #    define PRIu16 "u" | ||||||
|  | #  endif | ||||||
|  | #  if !defined(PRIu32) | ||||||
|  | #    define PRIu32 "u" | ||||||
|  | #  endif | ||||||
|  | #  if !defined(PRIu64) | ||||||
|  | #    define PRIu64 "I64u" | ||||||
|  | #  endif | ||||||
|  | #else | ||||||
|  | #  include <inttypes.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if !defined(munit_bool) | ||||||
|  | #  if defined(bool) | ||||||
|  | #    define munit_bool bool | ||||||
|  | #  elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) | ||||||
|  | #    define munit_bool _Bool | ||||||
|  | #  else | ||||||
|  | #    define munit_bool int | ||||||
|  | #  endif | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined(__cplusplus) | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined(__GNUC__) | ||||||
|  | #  define MUNIT_LIKELY(expr) (__builtin_expect ((expr), 1)) | ||||||
|  | #  define MUNIT_UNLIKELY(expr) (__builtin_expect ((expr), 0)) | ||||||
|  | #  define MUNIT_UNUSED __attribute__((__unused__)) | ||||||
|  | #else | ||||||
|  | #  define MUNIT_LIKELY(expr) (expr) | ||||||
|  | #  define MUNIT_UNLIKELY(expr) (expr) | ||||||
|  | #  define MUNIT_UNUSED | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__PGI) | ||||||
|  | #  define MUNIT_ARRAY_PARAM(name) name | ||||||
|  | #else | ||||||
|  | #  define MUNIT_ARRAY_PARAM(name) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if !defined(_WIN32) | ||||||
|  | #  define MUNIT_SIZE_MODIFIER "z" | ||||||
|  | #  define MUNIT_CHAR_MODIFIER "hh" | ||||||
|  | #  define MUNIT_SHORT_MODIFIER "h" | ||||||
|  | #else | ||||||
|  | #  if defined(_M_X64) || defined(__amd64__) | ||||||
|  | #    define MUNIT_SIZE_MODIFIER "I64" | ||||||
|  | #  else | ||||||
|  | #    define MUNIT_SIZE_MODIFIER "" | ||||||
|  | #  endif | ||||||
|  | #  define MUNIT_CHAR_MODIFIER "" | ||||||
|  | #  define MUNIT_SHORT_MODIFIER "" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L | ||||||
|  | #  define MUNIT_NO_RETURN _Noreturn | ||||||
|  | #elif defined(__GNUC__) | ||||||
|  | #  define MUNIT_NO_RETURN __attribute__((__noreturn__)) | ||||||
|  | #elif defined(_MSC_VER) | ||||||
|  | #  define MUNIT_NO_RETURN __declspec(noreturn) | ||||||
|  | #else | ||||||
|  | #  define MUNIT_NO_RETURN | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined(_MSC_VER) &&  (_MSC_VER >= 1500) | ||||||
|  | #  define MUNIT_PUSH_DISABLE_MSVC_C4127_ __pragma(warning(push)) __pragma(warning(disable:4127)) | ||||||
|  | #  define MUNIT_POP_DISABLE_MSVC_C4127_ __pragma(warning(pop)) | ||||||
|  | #else | ||||||
|  | #  define MUNIT_PUSH_DISABLE_MSVC_C4127_ | ||||||
|  | #  define MUNIT_POP_DISABLE_MSVC_C4127_ | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |   MUNIT_LOG_DEBUG, | ||||||
|  |   MUNIT_LOG_INFO, | ||||||
|  |   MUNIT_LOG_WARNING, | ||||||
|  |   MUNIT_LOG_ERROR | ||||||
|  | } MunitLogLevel; | ||||||
|  |  | ||||||
|  | #if defined(__GNUC__) && !defined(__MINGW32__) | ||||||
|  | #  define MUNIT_PRINTF(string_index, first_to_check) __attribute__((format (printf, string_index, first_to_check))) | ||||||
|  | #else | ||||||
|  | #  define MUNIT_PRINTF(string_index, first_to_check) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | MUNIT_PRINTF(4, 5) | ||||||
|  | void munit_logf_ex(MunitLogLevel level, const char* filename, int line, const char* format, ...); | ||||||
|  |  | ||||||
|  | #define munit_logf(level, format, ...) \ | ||||||
|  |   munit_logf_ex(level, __FILE__, __LINE__, format, __VA_ARGS__) | ||||||
|  |  | ||||||
|  | #define munit_log(level, msg) \ | ||||||
|  |   munit_logf(level, "%s", msg) | ||||||
|  |  | ||||||
|  | MUNIT_NO_RETURN | ||||||
|  | MUNIT_PRINTF(3, 4) | ||||||
|  | void munit_errorf_ex(const char* filename, int line, const char* format, ...); | ||||||
|  |  | ||||||
|  | #define munit_errorf(format, ...) \ | ||||||
|  |   munit_errorf_ex(__FILE__, __LINE__, format, __VA_ARGS__) | ||||||
|  |  | ||||||
|  | #define munit_error(msg) \ | ||||||
|  |   munit_errorf("%s", msg) | ||||||
|  |  | ||||||
|  | #define munit_assert(expr) \ | ||||||
|  |   do { \ | ||||||
|  |     if (!MUNIT_LIKELY(expr)) { \ | ||||||
|  |       munit_error("assertion failed: " #expr); \ | ||||||
|  |     } \ | ||||||
|  |     MUNIT_PUSH_DISABLE_MSVC_C4127_ \ | ||||||
|  |   } while (0) \ | ||||||
|  |   MUNIT_POP_DISABLE_MSVC_C4127_ | ||||||
|  |  | ||||||
|  | #define munit_assert_true(expr) \ | ||||||
|  |   do { \ | ||||||
|  |     if (!MUNIT_LIKELY(expr)) { \ | ||||||
|  |       munit_error("assertion failed: " #expr " is not true"); \ | ||||||
|  |     } \ | ||||||
|  |     MUNIT_PUSH_DISABLE_MSVC_C4127_ \ | ||||||
|  |   } while (0) \ | ||||||
|  |   MUNIT_POP_DISABLE_MSVC_C4127_ | ||||||
|  |  | ||||||
|  | #define munit_assert_false(expr) \ | ||||||
|  |   do { \ | ||||||
|  |     if (!MUNIT_LIKELY(!(expr))) { \ | ||||||
|  |       munit_error("assertion failed: " #expr " is not false"); \ | ||||||
|  |     } \ | ||||||
|  |     MUNIT_PUSH_DISABLE_MSVC_C4127_ \ | ||||||
|  |   } while (0) \ | ||||||
|  |   MUNIT_POP_DISABLE_MSVC_C4127_ | ||||||
|  |  | ||||||
|  | #define munit_assert_type_full(prefix, suffix, T, fmt, a, op, b)   \ | ||||||
|  |   do { \ | ||||||
|  |     T munit_tmp_a_ = (a); \ | ||||||
|  |     T munit_tmp_b_ = (b); \ | ||||||
|  |     if (!(munit_tmp_a_ op munit_tmp_b_)) {                               \ | ||||||
|  |       munit_errorf("assertion failed: %s %s %s (" prefix "%" fmt suffix " %s " prefix "%" fmt suffix ")", \ | ||||||
|  |                    #a, #op, #b, munit_tmp_a_, #op, munit_tmp_b_); \ | ||||||
|  |     } \ | ||||||
|  |     MUNIT_PUSH_DISABLE_MSVC_C4127_ \ | ||||||
|  |   } while (0) \ | ||||||
|  |   MUNIT_POP_DISABLE_MSVC_C4127_ | ||||||
|  |  | ||||||
|  | #define munit_assert_type(T, fmt, a, op, b) \ | ||||||
|  |   munit_assert_type_full("", "", T, fmt, a, op, b) | ||||||
|  |  | ||||||
|  | #define munit_assert_char(a, op, b) \ | ||||||
|  |   munit_assert_type_full("'\\x", "'", char, "02" MUNIT_CHAR_MODIFIER "x", a, op, b) | ||||||
|  | #define munit_assert_uchar(a, op, b) \ | ||||||
|  |   munit_assert_type_full("'\\x", "'", unsigned char, "02" MUNIT_CHAR_MODIFIER "x", a, op, b) | ||||||
|  | #define munit_assert_short(a, op, b) \ | ||||||
|  |   munit_assert_type(short, MUNIT_SHORT_MODIFIER "d", a, op, b) | ||||||
|  | #define munit_assert_ushort(a, op, b) \ | ||||||
|  |   munit_assert_type(unsigned short, MUNIT_SHORT_MODIFIER "u", a, op, b) | ||||||
|  | #define munit_assert_int(a, op, b) \ | ||||||
|  |   munit_assert_type(int, "d", a, op, b) | ||||||
|  | #define munit_assert_uint(a, op, b) \ | ||||||
|  |   munit_assert_type(unsigned int, "u", a, op, b) | ||||||
|  | #define munit_assert_long(a, op, b) \ | ||||||
|  |   munit_assert_type(long int, "ld", a, op, b) | ||||||
|  | #define munit_assert_ulong(a, op, b) \ | ||||||
|  |   munit_assert_type(unsigned long int, "lu", a, op, b) | ||||||
|  | #define munit_assert_llong(a, op, b) \ | ||||||
|  |   munit_assert_type(long long int, "lld", a, op, b) | ||||||
|  | #define munit_assert_ullong(a, op, b) \ | ||||||
|  |   munit_assert_type(unsigned long long int, "llu", a, op, b) | ||||||
|  |  | ||||||
|  | #define munit_assert_size(a, op, b) \ | ||||||
|  |   munit_assert_type(size_t, MUNIT_SIZE_MODIFIER "u", a, op, b) | ||||||
|  |  | ||||||
|  | #define munit_assert_float(a, op, b) \ | ||||||
|  |   munit_assert_type(float, "f", a, op, b) | ||||||
|  | #define munit_assert_double(a, op, b) \ | ||||||
|  |   munit_assert_type(double, "g", a, op, b) | ||||||
|  | #define munit_assert_ptr(a, op, b) \ | ||||||
|  |   munit_assert_type(const void*, "p", a, op, b) | ||||||
|  |  | ||||||
|  | #define munit_assert_int8(a, op, b)             \ | ||||||
|  |   munit_assert_type(munit_int8_t, PRIi8, a, op, b) | ||||||
|  | #define munit_assert_uint8(a, op, b) \ | ||||||
|  |   munit_assert_type(munit_uint8_t, PRIu8, a, op, b) | ||||||
|  | #define munit_assert_int16(a, op, b) \ | ||||||
|  |   munit_assert_type(munit_int16_t, PRIi16, a, op, b) | ||||||
|  | #define munit_assert_uint16(a, op, b) \ | ||||||
|  |   munit_assert_type(munit_uint16_t, PRIu16, a, op, b) | ||||||
|  | #define munit_assert_int32(a, op, b) \ | ||||||
|  |   munit_assert_type(munit_int32_t, PRIi32, a, op, b) | ||||||
|  | #define munit_assert_uint32(a, op, b) \ | ||||||
|  |   munit_assert_type(munit_uint32_t, PRIu32, a, op, b) | ||||||
|  | #define munit_assert_int64(a, op, b) \ | ||||||
|  |   munit_assert_type(munit_int64_t, PRIi64, a, op, b) | ||||||
|  | #define munit_assert_uint64(a, op, b) \ | ||||||
|  |   munit_assert_type(munit_uint64_t, PRIu64, a, op, b) | ||||||
|  |  | ||||||
|  | #define munit_assert_double_equal(a, b, precision) \ | ||||||
|  |   do { \ | ||||||
|  |     const double munit_tmp_a_ = (a); \ | ||||||
|  |     const double munit_tmp_b_ = (b); \ | ||||||
|  |     const double munit_tmp_diff_ = ((munit_tmp_a_ - munit_tmp_b_) < 0) ? \ | ||||||
|  |       -(munit_tmp_a_ - munit_tmp_b_) : \ | ||||||
|  |       (munit_tmp_a_ - munit_tmp_b_); \ | ||||||
|  |     if (MUNIT_UNLIKELY(munit_tmp_diff_ > 1e-##precision)) { \ | ||||||
|  |       munit_errorf("assertion failed: %s == %s (%0." #precision "g == %0." #precision "g)", \ | ||||||
|  | 		   #a, #b, munit_tmp_a_, munit_tmp_b_); \ | ||||||
|  |     } \ | ||||||
|  |     MUNIT_PUSH_DISABLE_MSVC_C4127_ \ | ||||||
|  |   } while (0) \ | ||||||
|  |   MUNIT_POP_DISABLE_MSVC_C4127_ | ||||||
|  |  | ||||||
|  | #include <string.h> | ||||||
|  | #define munit_assert_string_equal(a, b) \ | ||||||
|  |   do { \ | ||||||
|  |     const char* munit_tmp_a_ = a; \ | ||||||
|  |     const char* munit_tmp_b_ = b; \ | ||||||
|  |     if (MUNIT_UNLIKELY(strcmp(munit_tmp_a_, munit_tmp_b_) != 0)) { \ | ||||||
|  |       munit_errorf("assertion failed: string %s == %s (\"%s\" == \"%s\")", \ | ||||||
|  |                    #a, #b, munit_tmp_a_, munit_tmp_b_); \ | ||||||
|  |     } \ | ||||||
|  |     MUNIT_PUSH_DISABLE_MSVC_C4127_ \ | ||||||
|  |   } while (0) \ | ||||||
|  |   MUNIT_POP_DISABLE_MSVC_C4127_ | ||||||
|  |  | ||||||
|  | #define munit_assert_string_not_equal(a, b) \ | ||||||
|  |   do { \ | ||||||
|  |     const char* munit_tmp_a_ = a; \ | ||||||
|  |     const char* munit_tmp_b_ = b; \ | ||||||
|  |     if (MUNIT_UNLIKELY(strcmp(munit_tmp_a_, munit_tmp_b_) == 0)) { \ | ||||||
|  |       munit_errorf("assertion failed: string %s != %s (\"%s\" == \"%s\")", \ | ||||||
|  |                    #a, #b, munit_tmp_a_, munit_tmp_b_); \ | ||||||
|  |     } \ | ||||||
|  |     MUNIT_PUSH_DISABLE_MSVC_C4127_ \ | ||||||
|  |   } while (0) \ | ||||||
|  |   MUNIT_POP_DISABLE_MSVC_C4127_ | ||||||
|  |  | ||||||
|  | #define munit_assert_memory_equal(size, a, b) \ | ||||||
|  |   do { \ | ||||||
|  |     const unsigned char* munit_tmp_a_ = (const unsigned char*) (a); \ | ||||||
|  |     const unsigned char* munit_tmp_b_ = (const unsigned char*) (b); \ | ||||||
|  |     const size_t munit_tmp_size_ = (size); \ | ||||||
|  |     if (MUNIT_UNLIKELY(memcmp(munit_tmp_a_, munit_tmp_b_, munit_tmp_size_)) != 0) { \ | ||||||
|  |       size_t munit_tmp_pos_; \ | ||||||
|  |       for (munit_tmp_pos_ = 0 ; munit_tmp_pos_ < munit_tmp_size_ ; munit_tmp_pos_++) { \ | ||||||
|  |         if (munit_tmp_a_[munit_tmp_pos_] != munit_tmp_b_[munit_tmp_pos_]) { \ | ||||||
|  |           munit_errorf("assertion failed: memory %s == %s, at offset %" MUNIT_SIZE_MODIFIER "u", \ | ||||||
|  |                        #a, #b, munit_tmp_pos_); \ | ||||||
|  |           break; \ | ||||||
|  |         } \ | ||||||
|  |       } \ | ||||||
|  |     } \ | ||||||
|  |     MUNIT_PUSH_DISABLE_MSVC_C4127_ \ | ||||||
|  |   } while (0) \ | ||||||
|  |   MUNIT_POP_DISABLE_MSVC_C4127_ | ||||||
|  |  | ||||||
|  | #define munit_assert_memory_not_equal(size, a, b) \ | ||||||
|  |   do { \ | ||||||
|  |     const unsigned char* munit_tmp_a_ = (const unsigned char*) (a); \ | ||||||
|  |     const unsigned char* munit_tmp_b_ = (const unsigned char*) (b); \ | ||||||
|  |     const size_t munit_tmp_size_ = (size); \ | ||||||
|  |     if (MUNIT_UNLIKELY(memcmp(munit_tmp_a_, munit_tmp_b_, munit_tmp_size_)) == 0) { \ | ||||||
|  |       munit_errorf("assertion failed: memory %s != %s (%zu bytes)", \ | ||||||
|  |                    #a, #b, munit_tmp_size_); \ | ||||||
|  |     } \ | ||||||
|  |     MUNIT_PUSH_DISABLE_MSVC_C4127_ \ | ||||||
|  |   } while (0) \ | ||||||
|  |   MUNIT_POP_DISABLE_MSVC_C4127_ | ||||||
|  |  | ||||||
|  | #define munit_assert_ptr_equal(a, b) \ | ||||||
|  |   munit_assert_ptr(a, ==, b) | ||||||
|  | #define munit_assert_ptr_not_equal(a, b) \ | ||||||
|  |   munit_assert_ptr(a, !=, b) | ||||||
|  | #define munit_assert_null(ptr) \ | ||||||
|  |   munit_assert_ptr(ptr, ==, NULL) | ||||||
|  | #define munit_assert_not_null(ptr) \ | ||||||
|  |   munit_assert_ptr(ptr, !=, NULL) | ||||||
|  | #define munit_assert_ptr_null(ptr) \ | ||||||
|  |   munit_assert_ptr(ptr, ==, NULL) | ||||||
|  | #define munit_assert_ptr_not_null(ptr) \ | ||||||
|  |   munit_assert_ptr(ptr, !=, NULL) | ||||||
|  |  | ||||||
|  | /*** Memory allocation ***/ | ||||||
|  |  | ||||||
|  | void* munit_malloc_ex(const char* filename, int line, size_t size); | ||||||
|  |  | ||||||
|  | #define munit_malloc(size) \ | ||||||
|  |   munit_malloc_ex(__FILE__, __LINE__, (size)) | ||||||
|  |  | ||||||
|  | #define munit_new(type) \ | ||||||
|  |   ((type*) munit_malloc(sizeof(type))) | ||||||
|  |  | ||||||
|  | #define munit_calloc(nmemb, size) \ | ||||||
|  |   munit_malloc((nmemb) * (size)) | ||||||
|  |  | ||||||
|  | #define munit_newa(type, nmemb) \ | ||||||
|  |   ((type*) munit_calloc((nmemb), sizeof(type))) | ||||||
|  |  | ||||||
|  | /*** Random number generation ***/ | ||||||
|  |  | ||||||
|  | void munit_rand_seed(munit_uint32_t seed); | ||||||
|  | munit_uint32_t munit_rand_uint32(void); | ||||||
|  | int munit_rand_int_range(int min, int max); | ||||||
|  | double munit_rand_double(void); | ||||||
|  | void munit_rand_memory(size_t size, munit_uint8_t buffer[MUNIT_ARRAY_PARAM(size)]); | ||||||
|  |  | ||||||
|  | /*** Tests and Suites ***/ | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |   /* Test successful */ | ||||||
|  |   MUNIT_OK, | ||||||
|  |   /* Test failed */ | ||||||
|  |   MUNIT_FAIL, | ||||||
|  |   /* Test was skipped */ | ||||||
|  |   MUNIT_SKIP, | ||||||
|  |   /* Test failed due to circumstances not intended to be tested | ||||||
|  |    * (things like network errors, invalid parameter value, failure to | ||||||
|  |    * allocate memory in the test harness, etc.). */ | ||||||
|  |   MUNIT_ERROR | ||||||
|  | } MunitResult; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |   char*  name; | ||||||
|  |   char** values; | ||||||
|  | } MunitParameterEnum; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |   char* name; | ||||||
|  |   char* value; | ||||||
|  | } MunitParameter; | ||||||
|  |  | ||||||
|  | const char* munit_parameters_get(const MunitParameter params[], const char* key); | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |   MUNIT_TEST_OPTION_NONE             = 0, | ||||||
|  |   MUNIT_TEST_OPTION_SINGLE_ITERATION = 1 << 0, | ||||||
|  |   MUNIT_TEST_OPTION_TODO             = 1 << 1 | ||||||
|  | } MunitTestOptions; | ||||||
|  |  | ||||||
|  | typedef MunitResult (* MunitTestFunc)(const MunitParameter params[], void* user_data_or_fixture); | ||||||
|  | typedef void*       (* MunitTestSetup)(const MunitParameter params[], void* user_data); | ||||||
|  | typedef void        (* MunitTestTearDown)(void* fixture); | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |   char*               name; | ||||||
|  |   MunitTestFunc       test; | ||||||
|  |   MunitTestSetup      setup; | ||||||
|  |   MunitTestTearDown   tear_down; | ||||||
|  |   MunitTestOptions    options; | ||||||
|  |   MunitParameterEnum* parameters; | ||||||
|  | } MunitTest; | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |   MUNIT_SUITE_OPTION_NONE = 0 | ||||||
|  | } MunitSuiteOptions; | ||||||
|  |  | ||||||
|  | typedef struct MunitSuite_ MunitSuite; | ||||||
|  |  | ||||||
|  | struct MunitSuite_ { | ||||||
|  |   char*             prefix; | ||||||
|  |   MunitTest*        tests; | ||||||
|  |   MunitSuite*       suites; | ||||||
|  |   unsigned int      iterations; | ||||||
|  |   MunitSuiteOptions options; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | int munit_suite_main(const MunitSuite* suite, void* user_data, int argc, char* const argv[MUNIT_ARRAY_PARAM(argc + 1)]); | ||||||
|  |  | ||||||
|  | /* Note: I'm not very happy with this API; it's likely to change if I | ||||||
|  |  * figure out something better.  Suggestions welcome. */ | ||||||
|  |  | ||||||
|  | typedef struct MunitArgument_ MunitArgument; | ||||||
|  |  | ||||||
|  | struct MunitArgument_ { | ||||||
|  |   char* name; | ||||||
|  |   munit_bool (* parse_argument)(const MunitSuite* suite, void* user_data, int* arg, int argc, char* const argv[MUNIT_ARRAY_PARAM(argc + 1)]); | ||||||
|  |   void (* write_help)(const MunitArgument* argument, void* user_data); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | int munit_suite_main_custom(const MunitSuite* suite, | ||||||
|  |                             void* user_data, | ||||||
|  |                             int argc, char* const argv[MUNIT_ARRAY_PARAM(argc + 1)], | ||||||
|  |                             const MunitArgument arguments[]); | ||||||
|  |  | ||||||
|  | #if defined(MUNIT_ENABLE_ASSERT_ALIASES) | ||||||
|  |  | ||||||
|  | #define assert_true(expr) munit_assert_true(expr) | ||||||
|  | #define assert_false(expr) munit_assert_false(expr) | ||||||
|  | #define assert_char(a, op, b) munit_assert_char(a, op, b) | ||||||
|  | #define assert_uchar(a, op, b) munit_assert_uchar(a, op, b) | ||||||
|  | #define assert_short(a, op, b) munit_assert_short(a, op, b) | ||||||
|  | #define assert_ushort(a, op, b) munit_assert_ushort(a, op, b) | ||||||
|  | #define assert_int(a, op, b) munit_assert_int(a, op, b) | ||||||
|  | #define assert_uint(a, op, b) munit_assert_uint(a, op, b) | ||||||
|  | #define assert_long(a, op, b) munit_assert_long(a, op, b) | ||||||
|  | #define assert_ulong(a, op, b) munit_assert_ulong(a, op, b) | ||||||
|  | #define assert_llong(a, op, b) munit_assert_llong(a, op, b) | ||||||
|  | #define assert_ullong(a, op, b) munit_assert_ullong(a, op, b) | ||||||
|  | #define assert_size(a, op, b) munit_assert_size(a, op, b) | ||||||
|  | #define assert_float(a, op, b) munit_assert_float(a, op, b) | ||||||
|  | #define assert_double(a, op, b) munit_assert_double(a, op, b) | ||||||
|  | #define assert_ptr(a, op, b) munit_assert_ptr(a, op, b) | ||||||
|  |  | ||||||
|  | #define assert_int8(a, op, b) munit_assert_int8(a, op, b) | ||||||
|  | #define assert_uint8(a, op, b) munit_assert_uint8(a, op, b) | ||||||
|  | #define assert_int16(a, op, b) munit_assert_int16(a, op, b) | ||||||
|  | #define assert_uint16(a, op, b) munit_assert_uint16(a, op, b) | ||||||
|  | #define assert_int32(a, op, b) munit_assert_int32(a, op, b) | ||||||
|  | #define assert_uint32(a, op, b) munit_assert_uint32(a, op, b) | ||||||
|  | #define assert_int64(a, op, b) munit_assert_int64(a, op, b) | ||||||
|  | #define assert_uint64(a, op, b) munit_assert_uint64(a, op, b) | ||||||
|  |  | ||||||
|  | #define assert_double_equal(a, b, precision) munit_assert_double_equal(a, b, precision) | ||||||
|  | #define assert_string_equal(a, b) munit_assert_string_equal(a, b) | ||||||
|  | #define assert_string_not_equal(a, b) munit_assert_string_not_equal(a, b) | ||||||
|  | #define assert_memory_equal(size, a, b) munit_assert_memory_equal(size, a, b) | ||||||
|  | #define assert_memory_not_equal(size, a, b) munit_assert_memory_not_equal(size, a, b) | ||||||
|  | #define assert_ptr_equal(a, b) munit_assert_ptr_equal(a, b) | ||||||
|  | #define assert_ptr_not_equal(a, b) munit_assert_ptr_not_equal(a, b) | ||||||
|  | #define assert_ptr_null(ptr) munit_assert_null_equal(ptr) | ||||||
|  | #define assert_ptr_not_null(ptr) munit_assert_not_null(ptr) | ||||||
|  |  | ||||||
|  | #define assert_null(ptr) munit_assert_null(ptr) | ||||||
|  | #define assert_not_null(ptr) munit_assert_not_null(ptr) | ||||||
|  |  | ||||||
|  | #endif /* defined(MUNIT_ENABLE_ASSERT_ALIASES) */ | ||||||
|  |  | ||||||
|  | #if defined(__cplusplus) | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif /* !defined(MUNIT_H) */ | ||||||
|  |  | ||||||
|  | #if defined(MUNIT_ENABLE_ASSERT_ALIASES) | ||||||
|  | #  if defined(assert) | ||||||
|  | #    undef assert | ||||||
|  | #  endif | ||||||
|  | #  define assert(expr) munit_assert(expr) | ||||||
|  | #endif | ||||||
		Reference in New Issue
	
	Block a user