diff --git a/SLS_C/tests/lexer_tests.c b/SLS_C/tests/lexer_tests.c index ab3ad85..380da75 100644 --- a/SLS_C/tests/lexer_tests.c +++ b/SLS_C/tests/lexer_tests.c @@ -19,7 +19,7 @@ typedef struct { LexerInfo lexer_info; } LexerTest; -const char *TOKEN_TYPES[] = { +const char *TOKEN_TYPES_NAMES[] = { "End of File", "Identifier", "Integer", @@ -32,6 +32,17 @@ const char *TOKEN_TYPES[] = { "Type Tuple", }; +const char *INTEGER_TYPES_NAMES[] = { + "i64", + "i32", + "i16", + "i8", + "u64", + "u32", + "u16", + "u8", +}; + // Test start and end helpers static LexerTest start_up_test(const char *test_name, const char *test_code) { @@ -47,30 +58,30 @@ static void clean_up_test(LexerResult result) { clean_token_result(result.result); } -static TestResult logic_fail_test(LexerTest test, LexerResult result, const char *message) { +static TestResult logic_fail_test(LexerTest *test, LexerResult result, const char *message) { clean_up_test(result); - test.result.status = TEST_LOGIC_FAIL; - test.result.message = message; - return test.result; + test->result.status = TEST_LOGIC_FAIL; + test->result.message = message; + return test->result; } -static TestResult error_fail_test(LexerTest test, LexerResult result, SlsError error) { +static TestResult error_fail_test(LexerTest *test, LexerResult result, SlsError error) { clean_up_test(result); - test.result.status = TEST_ERROR_FAIL; - test.result.error = error; - return test.result; + test->result.status = TEST_ERROR_FAIL; + test->result.error = error; + return test->result; } -static TestResult skip_test(LexerTest test, LexerResult result) { +static TestResult skip_test(LexerTest *test, LexerResult result) { clean_up_test(result); - test.result.status = TEST_NOT_IMPLEMENTED; - return test.result; + test->result.status = TEST_NOT_IMPLEMENTED; + return test->result; } -static TestResult pass_test(LexerTest test, LexerResult result) { +static TestResult pass_test(LexerTest *test, LexerResult result) { clean_up_test(result); - test.result.status = TEST_PASS; - return test.result; + test->result.status = TEST_PASS; + return test->result; } // Test messages @@ -83,9 +94,16 @@ static char *unexpected_end_of_token_stream(size_t i) { } static char *token_should_be(size_t i, TokenType should, TokenType found) { - size_t length = floor(log10(i + 1)) + strnlen(TOKEN_TYPES[should], 13) + strnlen(TOKEN_TYPES[found], 13) + 35; + size_t length = floor(log10(i + 1)) + strnlen(TOKEN_TYPES_NAMES[should], 13) + strnlen(TOKEN_TYPES_NAMES[found], 13) + 35; char *string = malloc(sizeof(char) * length); - snprintf(string, length, "Token #%d should be a %s, but found a %s", i, TOKEN_TYPES[should], TOKEN_TYPES[found]); + snprintf(string, length, "Token #%d should be a %s, but found a %s", i, TOKEN_TYPES_NAMES[should], TOKEN_TYPES_NAMES[found]); + return string; +} + +static char *integer_type_should_be(size_t i, TokenType should, TokenType found) { + size_t length = floor(log10(i + 1)) + strnlen(INTEGER_TYPES_NAMES[should], 5) + strnlen(INTEGER_TYPES_NAMES[found], 5) + 48; + char *string = malloc(sizeof(char) * length); + snprintf(string, length, "Token #%d integer type should be a %s, but found a %s", i, TOKEN_TYPES_NAMES[should], TOKEN_TYPES_NAMES[found]); return string; } @@ -96,24 +114,94 @@ static char *integer_value_should_be(size_t i, uint64_t should, uint64_t found) return string; } +static char *identifier_should_be_literal(size_t i) { + size_t length = floor(log10(i + 1)) + 51; + char *string = malloc(sizeof(char) * length); + snprintf(string, length, "Token #%d identifier should be an identifier literal", i); + return string; +} + +static char *identifier_should_not_be_literal(size_t i) { + size_t length = floor(log10(i + 1)) + 55; + char *string = malloc(sizeof(char) * length); + snprintf(string, length, "Token #%d identifier should not be an identifier literal", i); + return string; +} + +static char *token_length_should_be(size_t i, TokenType type, uint64_t should, uint64_t found) { + size_t length = floor(log10(i + 1)) + strnlen(TOKEN_TYPES_NAMES[type], 13) + floor(log10(should + 1)) + floor(log10(found + 1)) + 47; + char *string = malloc(sizeof(char) * length); + snprintf(string, length, "Token #%d of type %s length should be %d, but found %d", i, TOKEN_TYPES_NAMES[type], should, found); + return string; +} + +static char *token_name_should_be(size_t i, TokenType type, size_t length, const char *should, const char *found) { + size_t length = floor(log10(i + 1)) + strnlen(TOKEN_TYPES_NAMES[type], 13) + strnlen(should, length) + strnlen(found, length) + 45; + char *string = malloc(sizeof(char) * length); + snprintf(string, length, "Token #%d of type %s name should be %s, but found %s", i, TOKEN_TYPES_NAMES[type], should, found); + return string; +} + // Test parts -static Boolean test_integer_value(LexerTest test, LexerResult result, size_t i, IntegerBuiltInType type, uint64_t value) { +static Boolean test_integer_value(LexerTest *test, LexerResult result, size_t i, IntegerBuiltInType type, uint64_t value) { LexerTokenResult *head = get_token(result.result, i); if (head == 0) { - logic_fail_test(test, result, unexpected_end_of_token_stream(i)); + logic_fail_test(test, result, unexpected_end_of_token_stream(i+1)); return TRUE; } if (head->type == SLS_ERROR) { error_fail_test(test, result, result.error); return TRUE; } if (head->result.type != TOKEN_INTEGER) { - logic_fail_test(test, result, token_should_be(i, TOKEN_INTEGER, head->result.type)); + logic_fail_test(test, result, token_should_be(i + 1, TOKEN_INTEGER, head->result.type)); return TRUE; } if (head->result.integer_literal.type != type) { - logic_fail_test(test, result, "First integer type should be "); + logic_fail_test(test, result, integer_type_should_be(i + 1, type, head->result.integer_literal.type)); return TRUE; } if (head->result.integer_literal.value != value) { - logic_fail_test(test, result, integer_value_should_be(i, value, head->result.integer_literal.value)); + logic_fail_test(test, result, integer_value_should_be(i + 1, value, head->result.integer_literal.value)); + return TRUE; + } + return FALSE; +} + +static Boolean test_identifier_value(LexerTest *test, LexerResult result, size_t i, Boolean is_literal, const char *name) { + LexerTokenResult *head = get_token(result.result, i); + if (head == 0) { + logic_fail_test(test, result, unexpected_end_of_token_stream(i+1)); + return TRUE; + } if (head->type == SLS_ERROR) { + error_fail_test(test, result, result.error); + return TRUE; + } if (head->result.type != TOKEN_IDENTIFIER) { + logic_fail_test(test, result, token_should_be(i + 1, TOKEN_IDENTIFIER, head->result.type)); + return TRUE; + } if (head->result.identifier.is_literal != is_literal) { + logic_fail_test(test, result, is_literal ? identifier_should_be_literal(i + 1) : identifier_should_not_be_literal(i+1)); + return TRUE; + } if (head->result.identifier.length == strnlen(name)) { + logic_fail_test(test, result, token_length_should_be(i + 1, TOKEN_IDENTIFIER, strnlen(name), head->result.identifier.length)); + return TRUE; + } if (strcmp(head->result.identifier.name, "+") != 0) { + logic_fail_test(test, result, token_length_should_be(i + 1, TOKEN_IDENTIFIER, strnlen(name), head->result.identifier.length)); + return TRUE; + } + return FALSE; +} + +static Boolean test_eof_value(LexerTest *test, LexerResult result, size_t i) { + LexerTokenResult *head = get_token(result.result, i); + if (head == 0) { + logic_fail_test(test, result, unexpected_end_of_token_stream(i+1)); + return TRUE; + } if (head->type == SLS_ERROR) { + error_fail_test(test, result, result.error); + return TRUE; + } if (head->result.type != TOKEN_EOF) { + logic_fail_test(test, result, token_should_be(i + 1, TOKEN_EOF, head->result.type)); + return TRUE; + } if (head->next != 0) { + logic_fail_test(test, result, "Expected end of token stream (more tokens found)"); return TRUE; } return FALSE; @@ -127,58 +215,19 @@ static TestResult test_add_statement() { LexerResult result = lexical_analysis(&test.lexer_info); if (result.type == SLS_ERROR) - return error_fail_test(test, result, result.error); + return error_fail_test(&test, result, result.error); LexerTokenResult *head = result.result; + size_t i = 0; - if (head == 0) - return logic_fail_test(test, result, "Unexpected end of token stream (0 tokens found)"); - if (head->type == SLS_ERROR) - return error_fail_test(test, result, result.error); - if (head->result.type != TOKEN_INTEGER) - return logic_fail_test(test, result, "First token should be an integer"); - if (head->result.integer_literal.type != INTEGER_I64) - return logic_fail_test(test, result, "First integer type should be i64"); - if (head->result.integer_literal.value != 3) - return logic_fail_test(test, result, "First integer value should be 3"); - - head = head->next; - if (head == 0) - return logic_fail_test(test, result, "Unexpected end of token stream (1 token found)"); - if (head->type == SLS_ERROR) - return error_fail_test(test, result, result.error); - if (head->result.type != TOKEN_INTEGER) - return logic_fail_test(test, result, "Second token should be an integer"); - if (head->result.integer_literal.type != INTEGER_I64) - return logic_fail_test(test, result, "Second integer type should be `i64`"); - if (head->result.integer_literal.value != 4) - return logic_fail_test(test, result, "Second integer value should be `4`"); - - head = head->next; - if (head == 0) - return logic_fail_test(test, result, "Unexpected end of token stream (2 tokens found)"); - if (head->type == SLS_ERROR) - return error_fail_test(test, result, result.error); - if (head->result.type != TOKEN_IDENTIFIER) - return logic_fail_test(test, result, "Third token should be an identifier"); - if (head->result.identifier.is_literal == TRUE) - return logic_fail_test(test, result, "Identifier should not be a literal identifier"); - if (head->result.identifier.length == 1) - return logic_fail_test(test, result, "Identifier length should be `1`"); - if (strcmp(head->result.identifier.name, "+") != 0) - return logic_fail_test(test, result, "Identifier name should be `+`"); - - head = head->next; - if (head == 0) - return logic_fail_test(test, result, "Unexpected end of token stream (3 tokens found)"); - if (head->type == SLS_ERROR) - return error_fail_test(test, result, result.error); - if (head->result.type != TOKEN_EOF) - return logic_fail_test(test, result, "Fourth token should be EOF"); - if (head->next == 0) - return logic_fail_test(test, result, "Expected end of token stream (more tokens found)"); - - return pass_test(test, result); + if (test_integer_value(&test, result, i, INTEGER_I64, 3)) return test.result; + i++; + if (test_integer_value(&test, result, i, INTEGER_I64, 4)) return test.result; + i++; + if (test_identifier_value(&test, result, i, FALSE, "+")) return test.result; + i++; + if (test_eof_value(&test, result, i)) return test.result; + return pass_test(&test, result); } TestsReport run_lexer_tests() {