From bc2247481b719fac3fbbb60cf40696d4dc7e5377 Mon Sep 17 00:00:00 2001 From: Kyler Date: Wed, 5 Nov 2025 15:20:11 -0700 Subject: [PATCH] Extracted lexer test helpers --- SLS_C/include/tests/lexer_test_helpers.h | 132 +++++ SLS_C/tests/lexer_test_helpers.c | 578 ++++++++++++++++++++ SLS_C/tests/lexer_tests.c | 648 +---------------------- 3 files changed, 711 insertions(+), 647 deletions(-) create mode 100644 SLS_C/include/tests/lexer_test_helpers.h create mode 100644 SLS_C/tests/lexer_test_helpers.c diff --git a/SLS_C/include/tests/lexer_test_helpers.h b/SLS_C/include/tests/lexer_test_helpers.h new file mode 100644 index 0000000..0dcccfb --- /dev/null +++ b/SLS_C/include/tests/lexer_test_helpers.h @@ -0,0 +1,132 @@ +// Kyler Olsen +// YREA SLS +// Tests Header +// October 2025 + +#ifndef SLS_LEXER_TEST_HELPERS_H +#define SLS_LEXER_TEST_HELPERS_H + +#include + +#include +#include +#include +#include +#include + +#include "sls/sls_errors.h" +#include "sls/lexer.h" +#include "sls/string.h" +#include "tests/lexer_test_helpers.h" +#include "tests/tests.h" + +typedef struct { + TestResult result; + LexerInfo lexer_info; +} LexerTest; + +typedef struct { + Boolean is_literal; + size_t length; + const char *name; +} TestIdentifierValue; + +typedef struct { + IntegerBuiltInType type; + uint64_t value; +} TestIntegerValue; + +typedef struct { + size_t length; + const char *string; +} TestStringValue; + +typedef struct { + size_t dimensions; + size_t *shape; + TestIdentifierValue *values; +} TestArrayIdentifierValue; + +typedef struct { + size_t dimensions; + size_t *shape; + TestIntegerValue *values; +} TestArrayIntegerValue; + +typedef struct { + size_t dimensions; + size_t *shape; + float *values; +} TestArrayFloatValue; + +typedef struct { + size_t dimensions; + size_t *shape; + double *values; +} TestArrayDoubleValue; + +typedef struct { + size_t dimensions; + size_t *shape; + TestStringValue *values; +} TestArrayStringValue; + +typedef struct { + size_t dimensions; + size_t *shape; + Boolean *values; +} TestArrayBooleanValue; + +typedef struct { + size_t dimensions; + size_t *shape; + size_t struct_name_length; + const char *struct_name; + Boolean (*struct_handler)(LexerTest *, LexerResult, size_t, size_t, void *, void *); + void **values; +} TestArrayStructInlineValue; + +typedef struct { + Boolean (*token_handler)(LexerTest *, LexerResult, size_t, void *); + void *value; +} TestTokenStringToken; + +typedef struct { + size_t tokens; + TestTokenStringToken *values; +} TestTokenStringValue; + +typedef struct { + size_t input_length; + TestIdentifierValue *input_values; + size_t output_length; + TestIdentifierValue *output_values; +} TestTypeTupleValue; + +LexerTest start_up_test(const char *test_name, const char *test_code); +void clean_up_test(LexerResult result); +TestResult error_test(LexerTest *test, LexerResult result, SlsError error); +TestResult logic_fail_test(LexerTest *test, LexerResult result, char *message); +TestResult error_fail_test(LexerTest *test, LexerResult result, SlsError error); +TestResult skip_test(LexerTest *test, LexerResult result); +TestResult skip_test_no_result(LexerTest *test); +TestResult pass_test(LexerTest *test, LexerResult result); + +Boolean test_eof_value(LexerTest *test, LexerResult result, size_t i, void *_); +Boolean test_identifier_value(LexerTest *test, LexerResult result, size_t i, TestIdentifierValue *value); +Boolean test_integer_value(LexerTest *test, LexerResult result, size_t i, TestIntegerValue *value); +Boolean test_float_value(LexerTest *test, LexerResult result, size_t i, float *value); +Boolean test_double_value(LexerTest *test, LexerResult result, size_t i, double *value); +Boolean test_string_value(LexerTest *test, LexerResult result, size_t i, TestStringValue *value); +Boolean test_boolean_value(LexerTest *test, LexerResult result, size_t i, Boolean *value); +Boolean test_array_identifier_value(LexerTest *test, LexerResult result, size_t i, TestArrayIdentifierValue *values); +Boolean test_array_integer_value(LexerTest *test, LexerResult result, size_t i, TestArrayIntegerValue *values); +Boolean test_array_float_value(LexerTest *test, LexerResult result, size_t i, TestArrayFloatValue *values); +Boolean test_array_double_value(LexerTest *test, LexerResult result, size_t i, TestArrayDoubleValue *values); +Boolean test_array_string_value(LexerTest *test, LexerResult result, size_t i, TestArrayStringValue *values); +Boolean test_array_boolean_value(LexerTest *test, LexerResult result, size_t i, TestArrayBooleanValue *values); +Boolean test_array_struct_inline_value(LexerTest *test, LexerResult result, size_t i, TestArrayStructInlineValue *values); +Boolean test_token_string_value(LexerTest *test, LexerResult result, size_t i, TestTokenStringValue *values); +Boolean test_type_tuple_value(LexerTest *test, LexerResult result, size_t i, TestTypeTupleValue *values); + +#endif // SLS_LEXER_TEST_HELPERS_H diff --git a/SLS_C/tests/lexer_test_helpers.c b/SLS_C/tests/lexer_test_helpers.c new file mode 100644 index 0000000..1939412 --- /dev/null +++ b/SLS_C/tests/lexer_test_helpers.c @@ -0,0 +1,578 @@ +// Kyler Olsen +// YREA SLS +// Lexer Tests +// October 2025 + +#include +#include +#include +#include +#include + +#include "sls/sls_errors.h" +#include "sls/lexer.h" +#include "sls/string.h" +#include "tests/lexer_test_helpers.h" +#include "tests/tests.h" + +static const double FLOAT_TEST_PRECISION = 0.01; + +// Test start and end helpers + +LexerTest start_up_test(const char *test_name, const char *test_code) { + LexerTest test = (LexerTest) { + .result = (TestResult) { + .name = test_name, .status = TEST_NOT_IMPLEMENTED } }; + init_lexer(&test.lexer_info, TEST_FILE_NAME, test_code); + return test; +} + +void clean_up_test(LexerResult result) { + if (result.type == SLS_RESULT) + clean_token_result(result.result); +} + +TestResult error_test(LexerTest *test, LexerResult result, SlsError error) { + clean_up_test(result); + test->result.status = TEST_ERROR; + test->result.error = error; + return test->result; +} + +TestResult logic_fail_test(LexerTest *test, LexerResult result, char *message) { + if (message == 0) return error_test(test, result, (SlsError) { + .message = "Out of Memory Error!", .code = 1, }); + clean_up_test(result); + test->result.status = TEST_LOGIC_FAIL; + test->result.message = message; + return test->result; +} + +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; +} + +TestResult skip_test(LexerTest *test, LexerResult result) { + clean_up_test(result); + test->result.status = TEST_NOT_IMPLEMENTED; + return test->result; +} + +TestResult skip_test_no_result(LexerTest *test) { + test->result.status = TEST_NOT_IMPLEMENTED; + return test->result; +} + +TestResult pass_test(LexerTest *test, LexerResult result) { + clean_up_test(result); + test->result.status = TEST_PASS; + return test->result; +} + +// Test messages + +static char *unexpected_end_of_token_stream(size_t i) { + size_t length = ceil(log10(i)) + 47; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + snprintf(string, length, "Unexpected end of token stream (%zu tokens found)", i - 1); + return string; +} + +static char *expected_end_of_token_stream(size_t i) { + size_t length = ceil(log10(i)) + 47; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + snprintf(string, length, "Expected end of token stream (more than %zu tokens found)", i - 1); + return string; +} + +static char *token_should_be(size_t i, TokenType should, TokenType found) { + size_t length = ceil(log10(i + 1)) + strnlen(TOKEN_TYPES_NAMES[should], TYPE_NAMES_SAFE_LENGTH) + strnlen(TOKEN_TYPES_NAMES[found], TYPE_NAMES_SAFE_LENGTH) + 35; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + snprintf(string, length, "Token #%zu 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, IntegerBuiltInType should, IntegerBuiltInType found) { + size_t length = ceil(log10(i + 1)) + strnlen(INTEGER_TYPES_NAMES[should], 5) + strnlen(INTEGER_TYPES_NAMES[found], 5) + 48; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + snprintf(string, length, "Token #%zu integer type should be a %s, but found a %s", i, TOKEN_TYPES_NAMES[should], TOKEN_TYPES_NAMES[found]); + return string; +} + +static char *integer_value_should_be(size_t i, uint64_t should, uint64_t found) { + size_t length = ceil(log10(i + 1)) + ceil(log10(should + 1)) + ceil(log10(found + 1)) + 45; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + snprintf(string, length, "Token #%zu integer value should be %lu, but found %lu", i, should, found); + return string; +} + +static char *float_value_should_be(size_t i, double should, double found) { + size_t length = ceil(log10(i + 1)) + ceil(log10(should + 1) + 3) + ceil(log10(found + 1) + 3) + 43; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + snprintf(string, length, "Token #%zu float value should be %.2f, but found %.2f", i, should, found); + return string; +} + +static char *identifier_should_be_literal(size_t i) { + size_t length = ceil(log10(i + 1)) + 51; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + snprintf(string, length, "Token #%zu identifier should be an identifier literal", i); + return string; +} + +static char *identifier_should_not_be_literal(size_t i) { + size_t length = ceil(log10(i + 1)) + 55; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + snprintf(string, length, "Token #%zu 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 = ceil(log10(i + 1)) + strnlen(TOKEN_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + ceil(log10(should + 1)) + ceil(log10(found + 1)) + 47; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + snprintf(string, length, "Token #%zu of type %s length should be %lu, but found %lu", i, TOKEN_TYPES_NAMES[type], should, found); + return string; +} + +static char *token_value_string_should_be(size_t i, TokenType type, size_t value_length, const char *should, const char *found) { + size_t length = ceil(log10(i + 1)) + strnlen(TOKEN_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + strnlen(should, value_length) + strnlen(found, value_length) + 53; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + snprintf(string, length, "Token #%zu of type %s string value should be %s, but found %s", i, TOKEN_TYPES_NAMES[type], should, found); + return string; +} + +static char *boolean_should_be(size_t i, Boolean value) { + size_t length = ceil(log10(i + 1)) + 45; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + if (value) snprintf(string, length, "Token #%zu boolean should be true, but is false", i); + else snprintf(string, length, "Token #%zu boolean should be false, but is true", i); + return string; +} + +static char *array_type_should_be(size_t i, ArrayType should, ArrayType found) { + size_t length = ceil(log10(i + 1)) + strnlen(ARRAY_TYPES_NAMES[should], TYPE_NAMES_SAFE_LENGTH) + strnlen(ARRAY_TYPES_NAMES[found], TYPE_NAMES_SAFE_LENGTH) + 35; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + snprintf(string, length, "Token #%zu should be a %s, but found a %s", i, ARRAY_TYPES_NAMES[should], ARRAY_TYPES_NAMES[found]); + return string; +} + +static char *array_dimensions_should_be(size_t i, size_t should, size_t found) { + size_t length = ceil(log10(i + 1)) + ceil(log10(should + 1)) + ceil(log10(found + 1)) + 48; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + snprintf(string, length, "Token #%zu array dimensions should be %zu, but found %zu", i, should, found); + return string; +} + +static char *array_element_shape_should_be(size_t i, size_t j, ArrayType type, uint64_t should, uint64_t found) { + size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(ARRAY_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + ceil(log10(should + 1) + 3) + ceil(log10(found + 1) + 3) + 63; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + snprintf(string, length, "Token #%zu dimension %zu of array type %s should be shape %lu, but found %lu", i, j, TOKEN_TYPES_NAMES[type], should, found); + return string; +} + +static char *array_element_integer_should_be(size_t i, size_t j, ArrayType type, uint64_t should, uint64_t found) { + size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(ARRAY_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + ceil(log10(should + 1) + 3) + ceil(log10(found + 1) + 3) + 55; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + snprintf(string, length, "Token #%zu element %zu of array type %s should be %lu, but found %lu", i, j, TOKEN_TYPES_NAMES[type], should, found); + return string; +} + +static char *array_element_float_should_be(size_t i, size_t j, ArrayType type, double should, double found) { + size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(ARRAY_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + ceil(log10(should + 1)) + ceil(log10(found + 1)) + 55; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + snprintf(string, length, "Token #%zu element %zu of array type %s should be %.2f, but found %.2f", i, j, TOKEN_TYPES_NAMES[type], should, found); + return string; +} + +static char *array_element_string_should_be(size_t i, size_t j, ArrayType type, size_t value_length, const char *should, const char *found) { + size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(ARRAY_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + strnlen(should, value_length) + strnlen(found, value_length) + 55; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + snprintf(string, length, "Token #%zu element %zu of array type %s should be %s, but found %s", i, j, TOKEN_TYPES_NAMES[type], should, found); + return string; +} + +static char *array_element_boolean_should_be(size_t i, size_t j, ArrayType type, Boolean value) { + size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(ARRAY_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + 64; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + if (value) snprintf(string, length, "Token #%zu element %zu of array type %s should be true, but found false", i, j, TOKEN_TYPES_NAMES[type]); + else snprintf(string, length, "Token #%zu element %zu of array type %s should be false, but found true", i, j, TOKEN_TYPES_NAMES[type]); + return string; +} + +static char *type_tuple_element_integer_should_be(size_t i, size_t j, uint64_t should, uint64_t found) { + size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + ceil(log10(should + 1) + 3) + ceil(log10(found + 1) + 3) + 54; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + snprintf(string, length, "Token #%zu element %zu of type tuple should be %lu, but found %lu", i, j, should, found); + return string; +} + +static char *type_tuple_element_string_should_be(size_t i, size_t j, size_t value_length, const char *should, const char *found) { + size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(should, value_length) + strnlen(found, value_length) + 54; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + snprintf(string, length, "Token #%zu element %zu of type tuple should be %s, but found %s", i, j, should, found); + return string; +} + +static char *type_tuple_element_boolean_should_be(size_t i, size_t j, Boolean value) { + size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + 63; + char *string = (char *)malloc(sizeof(char) * length); + if (string == 0) return string; + if (value) snprintf(string, length, "Token #%zu element %zu of type tuple should be true, but found false", i, j); + else snprintf(string, length, "Token #%zu element %zu of type tuple should be false, but found true", i, j); + return string; +} + +// Test parts + +static Boolean test_token_type(LexerTest *test, LexerResult result, size_t i, TokenType token_type) { + 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, head->error); + return TRUE; + } if (head->result.type != token_type) { + logic_fail_test(test, result, token_should_be(i + 1, token_type, head->result.type)); + return TRUE; + } + return FALSE; +} + +static Boolean test_array_type(LexerTest *test, LexerResult result, size_t i, ArrayType array_type, size_t *shape, size_t dimensions) { + LexerTokenResult *head = get_token(result.result, i); + if (test_token_type(test, result, i, TOKEN_ARRAY)) { + return TRUE; + } if (head->result.array_literal.type != array_type) { + logic_fail_test(test, result, array_type_should_be(i + 1, array_type, head->result.array_literal.type)); + return TRUE; + } if (head->result.array_literal.dimensions != dimensions) { + logic_fail_test(test, result, array_dimensions_should_be(i + 1, dimensions, head->result.array_literal.dimensions)); + return TRUE; + } + for (size_t j = 0; j < dimensions; j++) { + if (head->result.array_literal.shape[j] != shape[j]) { + logic_fail_test(test, result, array_element_shape_should_be(i + 1, j, array_type, shape[j], head->result.array_literal.shape[j])); + return TRUE; + } + } + return FALSE; +} + +Boolean test_eof_value(LexerTest *test, LexerResult result, size_t i, void *_) { + (void)_; // We don't use this anywhere in this function + static const TokenType token_type = TOKEN_EOF; + LexerTokenResult *head = get_token(result.result, i); + if (test_token_type(test, result, i, token_type)) { + return TRUE; + } if (head->next != 0) { + logic_fail_test(test, result, expected_end_of_token_stream(i + 1)); + return TRUE; + } + return FALSE; +} + +Boolean test_identifier_value(LexerTest *test, LexerResult result, size_t i, TestIdentifierValue *value) { + static const TokenType token_type = TOKEN_IDENTIFIER; + LexerTokenResult *head = get_token(result.result, i); + if (test_token_type(test, result, i, token_type)) { + return TRUE; + } if (head->result.identifier.is_literal != value->is_literal) { + logic_fail_test(test, result, value->is_literal ? identifier_should_be_literal(i + 1) : identifier_should_not_be_literal(i + 1)); + return TRUE; + } if (head->result.identifier.length == strnlen(value->name, value->length)) { + logic_fail_test(test, result, token_length_should_be(i + 1, token_type, strnlen(value->name, value->length), head->result.identifier.length)); + return TRUE; + } if (strncmp(head->result.identifier.name, value->name, value->length) != 0) { + logic_fail_test(test, result, token_value_string_should_be(i + 1, token_type, strnlen(value->name, value->length), head->result.identifier.name, value->name)); + return TRUE; + } + return FALSE; +} + +Boolean test_integer_value(LexerTest *test, LexerResult result, size_t i, TestIntegerValue *value) { + static const TokenType token_type = TOKEN_INTEGER; + LexerTokenResult *head = get_token(result.result, i); + if (test_token_type(test, result, i, token_type)) { + return TRUE; + } if (head->result.integer_literal.type != value->type) { + logic_fail_test(test, result, integer_type_should_be(i + 1, value->type, head->result.integer_literal.type)); + return TRUE; + } if (head->result.integer_literal.value != value->value) { + logic_fail_test(test, result, integer_value_should_be(i + 1, value->value, head->result.integer_literal.value)); + return TRUE; + } + return FALSE; +} + +Boolean test_float_value(LexerTest *test, LexerResult result, size_t i, float *value) { + static const TokenType token_type = TOKEN_FLOAT; + LexerTokenResult *head = get_token(result.result, i); + if (test_token_type(test, result, i, token_type)) { + return TRUE; + } if (fabsf(head->result.float_literal - *value) >= FLOAT_TEST_PRECISION) { + logic_fail_test(test, result, float_value_should_be(i + 1, *value, head->result.float_literal)); + return TRUE; + } + return FALSE; +} + +Boolean test_double_value(LexerTest *test, LexerResult result, size_t i, double *value) { + static const TokenType token_type = TOKEN_DOUBLE; + LexerTokenResult *head = get_token(result.result, i); + if (test_token_type(test, result, i, token_type)) { + return TRUE; + } if (fabs(head->result.float_literal - *value) >= FLOAT_TEST_PRECISION) { + logic_fail_test(test, result, float_value_should_be(i + 1, *value, head->result.float_literal)); + return TRUE; + } + return FALSE; +} + +Boolean test_string_value(LexerTest *test, LexerResult result, size_t i, TestStringValue *value) { + static const TokenType token_type = TOKEN_STRING; + LexerTokenResult *head = get_token(result.result, i); + if (test_token_type(test, result, i, token_type)) { + return TRUE; + } if (head->result.string_literal.length == strnlen(value->string, value->length)) { + logic_fail_test(test, result, token_length_should_be(i + 1, token_type, strnlen(value->string, value->length), head->result.string_literal.length)); + return TRUE; + } if (strncmp(head->result.string_literal.value, value->string, value->length) != 0) { + logic_fail_test(test, result, token_value_string_should_be(i + 1, token_type, fmax(strnlen(value->string, value->length), strnlen(head->result.string_literal.value, value->length)), value->string, head->result.string_literal.value)); + return TRUE; + } + return FALSE; +} + +Boolean test_boolean_value(LexerTest *test, LexerResult result, size_t i, Boolean *value) { + static const TokenType token_type = TOKEN_BOOLEAN; + LexerTokenResult *head = get_token(result.result, i); + if (test_token_type(test, result, i, token_type)) { + return TRUE; + } if (head->result.boolean_literal != *value) { + logic_fail_test(test, result, boolean_should_be(i + 1, *value)); + return TRUE; + } + return FALSE; +} + +Boolean test_array_identifier_value(LexerTest *test, LexerResult result, size_t i, TestArrayIdentifierValue *values) { + static const ArrayType array_type = ARRAY_IDENTIFIER; + LexerTokenResult *head = get_token(result.result, i); + if (test_array_type(test, result, i, array_type, values->shape, values->dimensions)) { + return TRUE; + } + size_t length = 1; + for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j]; + for (size_t j = 0; j < length; j++) { + if (head->result.array_literal.identifiers[j].length == values->values[j].length) { + logic_fail_test(test, result, array_element_integer_should_be(i + 1, j, array_type, values->values[j].length, head->result.array_literal.identifiers[j].length)); + return TRUE; + } if (strncmp(head->result.array_literal.identifiers[j].name, values->values[j].name, values->values[j].length)) { + logic_fail_test(test, result, array_element_string_should_be(i + 1, j, array_type, values->values[j].length, values->values[j].name, head->result.array_literal.identifiers[j].name)); + return TRUE; + } if (head->result.array_literal.identifiers[j].is_literal) { + logic_fail_test(test, result, array_element_boolean_should_be(i + 1, j, array_type, TRUE)); + return TRUE; + } + } + return FALSE; +} + +Boolean test_array_integer_value(LexerTest *test, LexerResult result, size_t i, TestArrayIntegerValue *values) { + const ArrayType array_type = values->values[0].type + 1; + LexerTokenResult *head = get_token(result.result, i); + if (test_array_type(test, result, i, array_type, values->shape, values->dimensions)) { + return TRUE; + } + size_t length = 1; + for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j]; + for (size_t j = 0; j < length; j++) { + if (head->result.array_literal.integer_literals[j] == values->values[j].value) { + logic_fail_test(test, result, array_element_integer_should_be(i + 1, j, array_type, values->values[j].value, head->result.array_literal.integer_literals[j])); + return TRUE; + } + } + return FALSE; +} + +Boolean test_array_float_value(LexerTest *test, LexerResult result, size_t i, TestArrayFloatValue *values) { + static const ArrayType array_type = ARRAY_FLOAT; + LexerTokenResult *head = get_token(result.result, i); + if (test_array_type(test, result, i, array_type, values->shape, values->dimensions)) { + return TRUE; + } + size_t length = 1; + for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j]; + for (size_t j = 0; j < length; j++) { + if (fabsf(head->result.array_literal.float_literals[j] - values->values[j]) >= FLOAT_TEST_PRECISION) { + logic_fail_test(test, result, array_element_float_should_be(i + 1, j, array_type, values->values[j], head->result.array_literal.float_literals[j])); + return TRUE; + } + } + return FALSE; +} + +Boolean test_array_double_value(LexerTest *test, LexerResult result, size_t i, TestArrayDoubleValue *values) { + static const ArrayType array_type = ARRAY_DOUBLE; + LexerTokenResult *head = get_token(result.result, i); + if (test_array_type(test, result, i, array_type, values->shape, values->dimensions)) { + return TRUE; + } + size_t length = 1; + for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j]; + for (size_t j = 0; j < length; j++) { + if (fabs(head->result.array_literal.float_literals[j] - values->values[j]) >= FLOAT_TEST_PRECISION) { + logic_fail_test(test, result, array_element_float_should_be(i + 1, j, array_type, values->values[j], head->result.array_literal.float_literals[j])); + return TRUE; + } + } + return FALSE; +} + +Boolean test_array_string_value(LexerTest *test, LexerResult result, size_t i, TestArrayStringValue *values) { + static const ArrayType array_type = ARRAY_STRING; + LexerTokenResult *head = get_token(result.result, i); + if (test_array_type(test, result, i, array_type, values->shape, values->dimensions)) { + return TRUE; + } + size_t length = 1; + for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j]; + for (size_t j = 0; j < length; j++) { + if (head->result.array_literal.string_literals[j].length == values->values[j].length) { + logic_fail_test(test, result, array_element_integer_should_be(i + 1, j, array_type, values->values[j].length, head->result.array_literal.string_literals[j].length)); + return TRUE; + } if (strncmp(head->result.array_literal.string_literals[j].value, values->values[j].string, values->values[j].length)) { + logic_fail_test(test, result, array_element_string_should_be(i + 1, j, array_type, values->values[j].length, values->values[j].string, head->result.array_literal.string_literals[j].value)); + return TRUE; + } + } + return FALSE; +} + +Boolean test_array_boolean_value(LexerTest *test, LexerResult result, size_t i, TestArrayBooleanValue *values) { + static const ArrayType array_type = ARRAY_BOOLEAN; + LexerTokenResult *head = get_token(result.result, i); + if (test_array_type(test, result, i, array_type, values->shape, values->dimensions)) { + return TRUE; + } + size_t length = 1; + for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j]; + for (size_t j = 0; j < length; j++) { + if (head->result.array_literal.boolean_literals[j] == values->values[j]) { + logic_fail_test(test, result, array_element_boolean_should_be(i + 1, j, array_type, values->values[j])); + return TRUE; + } + } + return FALSE; +} + +Boolean test_array_struct_inline_value(LexerTest *test, LexerResult result, size_t i, TestArrayStructInlineValue *values) { + static const ArrayType array_type = ARRAY_STRUCT_INLINE; + LexerTokenResult *head = get_token(result.result, i); + if (test_array_type(test, result, i, array_type, values->shape, values->dimensions)) { + return TRUE; + } if (strncmp(head->result.array_literal.struct_inline.name, values->struct_name, values->struct_name_length)) { + logic_fail_test(test, result, token_value_string_should_be(i + 1, TOKEN_IDENTIFIER, values->struct_name_length, values->struct_name, head->result.array_literal.struct_inline.name)); + return TRUE; + } + size_t length = 1; + for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j]; + for (size_t j = 0; j < length; j++) { + if (values->struct_handler(test, result, i, j, head->result.array_literal.struct_inline.values[j], values->values[j])) { + return TRUE; + } + } + return FALSE; +} + +static LexerResult token_string_to_lexer_result(TokenString token_string, FileInfo file_info) { + LexerTokenResult *new, *head; + head = 0; + for (size_t i = 0; i> token_string.length; i++) { + new = (LexerTokenResult *)malloc(sizeof(LexerTokenResult)); + *new = (LexerTokenResult) { .type = SLS_RESULT, .result = token_string.tokens[i], .file_info = file_info, .next = head }; + head = new; + } + return (LexerResult) { .type = SLS_RESULT, .result = head }; +} + +Boolean test_token_string_value(LexerTest *test, LexerResult result, size_t i, TestTokenStringValue *values) { + static const TokenType token_type = TOKEN_TOKEN_STRING; + LexerTokenResult *head = get_token(result.result, i); + if (test_token_type(test, result, i, token_type)) { + return TRUE; + } if (head->result.token_string.length != values->tokens) { + logic_fail_test(test, result, integer_value_should_be(i + 1, values->tokens, head->result.token_string.length)); + return TRUE; + } + for (size_t j = 0; j < values->tokens; j++) { + LexerResult token_string_result = token_string_to_lexer_result(head->result.token_string, head->file_info); + if (values->values[j].token_handler(test, token_string_result, j, values->values[j].value)) { + clean_token_result(token_string_result.result); + return TRUE; + } + clean_token_result(token_string_result.result); + } + return FALSE; +} + +Boolean test_type_tuple_value(LexerTest *test, LexerResult result, size_t i, TestTypeTupleValue *values) { + static const TokenType token_type = TOKEN_TYPE_TUPLE; + LexerTokenResult *head = get_token(result.result, i); + if (test_token_type(test, result, i, token_type)) { + return TRUE; + } if (head->result.type_tuple.input_length != values->input_length) { + logic_fail_test(test, result, token_length_should_be(i + 1, token_type, values->input_length, head->result.type_tuple.input_length)); + return TRUE; + } if (head->result.type_tuple.output_length != values->output_length) { + logic_fail_test(test, result, token_length_should_be(i + 1, token_type, values->output_length, head->result.type_tuple.output_length)); + return TRUE; + } for (size_t j = 0; j < values->input_length; j++) { + if (head->result.type_tuple.input_identifiers[j].length == values->input_values[j].length) { + logic_fail_test(test, result, type_tuple_element_integer_should_be(i + 1, j, values->input_values[j].length, head->result.type_tuple.input_identifiers[j].length)); + return TRUE; + } if (strncmp(head->result.type_tuple.input_identifiers[j].name, values->input_values[j].name, values->input_values[j].length)) { + logic_fail_test(test, result, type_tuple_element_string_should_be(i + 1, j, values->input_values[j].length, values->input_values[j].name, head->result.type_tuple.input_identifiers[j].name)); + return TRUE; + } if (head->result.type_tuple.input_identifiers[j].is_literal) { + logic_fail_test(test, result, type_tuple_element_boolean_should_be(i + 1, j, TRUE)); + return TRUE; + } + } for (size_t j = 0; j < values->output_length; j++) { + if (head->result.type_tuple.output_identifiers[j].length == values->output_values[j].length) { + logic_fail_test(test, result, type_tuple_element_integer_should_be(i + 1, j, values->output_values[j].length, head->result.type_tuple.output_identifiers[j].length)); + return TRUE; + } if (strncmp(head->result.type_tuple.output_identifiers[j].name, values->output_values[j].name, values->input_values[j].length)) { + logic_fail_test(test, result, type_tuple_element_string_should_be(i + 1, j, values->output_values[j].length, values->output_values[j].name, head->result.type_tuple.output_identifiers[j].name)); + return TRUE; + } if (head->result.type_tuple.output_identifiers[j].is_literal) { + logic_fail_test(test, result, type_tuple_element_boolean_should_be(i + 1, j, TRUE)); + return TRUE; + } + } + return FALSE; +} diff --git a/SLS_C/tests/lexer_tests.c b/SLS_C/tests/lexer_tests.c index bf2eb9c..76c95bc 100644 --- a/SLS_C/tests/lexer_tests.c +++ b/SLS_C/tests/lexer_tests.c @@ -12,657 +12,11 @@ #include "sls/sls_errors.h" #include "sls/lexer.h" #include "sls/string.h" +#include "tests/lexer_test_helpers.h" #include "tests/tests.h" static const size_t NUM_OF_TESTS = 14; -static const double FLOAT_TEST_PRECISION = 0.01; - -typedef struct { - TestResult result; - LexerInfo lexer_info; -} LexerTest; - -// Test start and end helpers - -static LexerTest start_up_test(const char *test_name, const char *test_code) { - LexerTest test = (LexerTest) { - .result = (TestResult) { - .name = test_name, .status = TEST_NOT_IMPLEMENTED } }; - init_lexer(&test.lexer_info, TEST_FILE_NAME, test_code); - return test; -} - -static void clean_up_test(LexerResult result) { - if (result.type == SLS_RESULT) - clean_token_result(result.result); -} - -static TestResult error_test(LexerTest *test, LexerResult result, SlsError error) { - clean_up_test(result); - test->result.status = TEST_ERROR; - test->result.error = error; - return test->result; -} - -static TestResult logic_fail_test(LexerTest *test, LexerResult result, char *message) { - if (message == 0) return error_test(test, result, (SlsError) { - .message = "Out of Memory Error!", .code = 1, }); - clean_up_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) { - clean_up_test(result); - test->result.status = TEST_ERROR_FAIL; - test->result.error = error; - return test->result; -} - -static TestResult skip_test(LexerTest *test, LexerResult result) { - clean_up_test(result); - test->result.status = TEST_NOT_IMPLEMENTED; - return test->result; -} - -static TestResult skip_test_no_result(LexerTest *test) { - test->result.status = TEST_NOT_IMPLEMENTED; - return test->result; -} - -static TestResult pass_test(LexerTest *test, LexerResult result) { - clean_up_test(result); - test->result.status = TEST_PASS; - return test->result; -} - -// Test messages - -static char *unexpected_end_of_token_stream(size_t i) { - size_t length = ceil(log10(i)) + 47; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - snprintf(string, length, "Unexpected end of token stream (%zu tokens found)", i - 1); - return string; -} - -static char *expected_end_of_token_stream(size_t i) { - size_t length = ceil(log10(i)) + 47; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - snprintf(string, length, "Expected end of token stream (more than %zu tokens found)", i - 1); - return string; -} - -static char *token_should_be(size_t i, TokenType should, TokenType found) { - size_t length = ceil(log10(i + 1)) + strnlen(TOKEN_TYPES_NAMES[should], TYPE_NAMES_SAFE_LENGTH) + strnlen(TOKEN_TYPES_NAMES[found], TYPE_NAMES_SAFE_LENGTH) + 35; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - snprintf(string, length, "Token #%zu 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, IntegerBuiltInType should, IntegerBuiltInType found) { - size_t length = ceil(log10(i + 1)) + strnlen(INTEGER_TYPES_NAMES[should], 5) + strnlen(INTEGER_TYPES_NAMES[found], 5) + 48; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - snprintf(string, length, "Token #%zu integer type should be a %s, but found a %s", i, TOKEN_TYPES_NAMES[should], TOKEN_TYPES_NAMES[found]); - return string; -} - -static char *integer_value_should_be(size_t i, uint64_t should, uint64_t found) { - size_t length = ceil(log10(i + 1)) + ceil(log10(should + 1)) + ceil(log10(found + 1)) + 45; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - snprintf(string, length, "Token #%zu integer value should be %lu, but found %lu", i, should, found); - return string; -} - -static char *float_value_should_be(size_t i, double should, double found) { - size_t length = ceil(log10(i + 1)) + ceil(log10(should + 1) + 3) + ceil(log10(found + 1) + 3) + 43; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - snprintf(string, length, "Token #%zu float value should be %.2f, but found %.2f", i, should, found); - return string; -} - -static char *identifier_should_be_literal(size_t i) { - size_t length = ceil(log10(i + 1)) + 51; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - snprintf(string, length, "Token #%zu identifier should be an identifier literal", i); - return string; -} - -static char *identifier_should_not_be_literal(size_t i) { - size_t length = ceil(log10(i + 1)) + 55; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - snprintf(string, length, "Token #%zu 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 = ceil(log10(i + 1)) + strnlen(TOKEN_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + ceil(log10(should + 1)) + ceil(log10(found + 1)) + 47; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - snprintf(string, length, "Token #%zu of type %s length should be %lu, but found %lu", i, TOKEN_TYPES_NAMES[type], should, found); - return string; -} - -static char *token_value_string_should_be(size_t i, TokenType type, size_t value_length, const char *should, const char *found) { - size_t length = ceil(log10(i + 1)) + strnlen(TOKEN_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + strnlen(should, value_length) + strnlen(found, value_length) + 53; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - snprintf(string, length, "Token #%zu of type %s string value should be %s, but found %s", i, TOKEN_TYPES_NAMES[type], should, found); - return string; -} - -static char *boolean_should_be(size_t i, Boolean value) { - size_t length = ceil(log10(i + 1)) + 45; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - if (value) snprintf(string, length, "Token #%zu boolean should be true, but is false", i); - else snprintf(string, length, "Token #%zu boolean should be false, but is true", i); - return string; -} - -static char *array_type_should_be(size_t i, ArrayType should, ArrayType found) { - size_t length = ceil(log10(i + 1)) + strnlen(ARRAY_TYPES_NAMES[should], TYPE_NAMES_SAFE_LENGTH) + strnlen(ARRAY_TYPES_NAMES[found], TYPE_NAMES_SAFE_LENGTH) + 35; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - snprintf(string, length, "Token #%zu should be a %s, but found a %s", i, ARRAY_TYPES_NAMES[should], ARRAY_TYPES_NAMES[found]); - return string; -} - -static char *array_dimensions_should_be(size_t i, size_t should, size_t found) { - size_t length = ceil(log10(i + 1)) + ceil(log10(should + 1)) + ceil(log10(found + 1)) + 48; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - snprintf(string, length, "Token #%zu array dimensions should be %zu, but found %zu", i, should, found); - return string; -} - -static char *array_element_shape_should_be(size_t i, size_t j, ArrayType type, uint64_t should, uint64_t found) { - size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(ARRAY_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + ceil(log10(should + 1) + 3) + ceil(log10(found + 1) + 3) + 63; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - snprintf(string, length, "Token #%zu dimension %zu of array type %s should be shape %lu, but found %lu", i, j, TOKEN_TYPES_NAMES[type], should, found); - return string; -} - -static char *array_element_integer_should_be(size_t i, size_t j, ArrayType type, uint64_t should, uint64_t found) { - size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(ARRAY_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + ceil(log10(should + 1) + 3) + ceil(log10(found + 1) + 3) + 55; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - snprintf(string, length, "Token #%zu element %zu of array type %s should be %lu, but found %lu", i, j, TOKEN_TYPES_NAMES[type], should, found); - return string; -} - -static char *array_element_float_should_be(size_t i, size_t j, ArrayType type, double should, double found) { - size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(ARRAY_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + ceil(log10(should + 1)) + ceil(log10(found + 1)) + 55; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - snprintf(string, length, "Token #%zu element %zu of array type %s should be %.2f, but found %.2f", i, j, TOKEN_TYPES_NAMES[type], should, found); - return string; -} - -static char *array_element_string_should_be(size_t i, size_t j, ArrayType type, size_t value_length, const char *should, const char *found) { - size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(ARRAY_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + strnlen(should, value_length) + strnlen(found, value_length) + 55; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - snprintf(string, length, "Token #%zu element %zu of array type %s should be %s, but found %s", i, j, TOKEN_TYPES_NAMES[type], should, found); - return string; -} - -static char *array_element_boolean_should_be(size_t i, size_t j, ArrayType type, Boolean value) { - size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(ARRAY_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + 64; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - if (value) snprintf(string, length, "Token #%zu element %zu of array type %s should be true, but found false", i, j, TOKEN_TYPES_NAMES[type]); - else snprintf(string, length, "Token #%zu element %zu of array type %s should be false, but found true", i, j, TOKEN_TYPES_NAMES[type]); - return string; -} - -static char *type_tuple_element_integer_should_be(size_t i, size_t j, uint64_t should, uint64_t found) { - size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + ceil(log10(should + 1) + 3) + ceil(log10(found + 1) + 3) + 54; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - snprintf(string, length, "Token #%zu element %zu of type tuple should be %lu, but found %lu", i, j, should, found); - return string; -} - -static char *type_tuple_element_string_should_be(size_t i, size_t j, size_t value_length, const char *should, const char *found) { - size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(should, value_length) + strnlen(found, value_length) + 54; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - snprintf(string, length, "Token #%zu element %zu of type tuple should be %s, but found %s", i, j, should, found); - return string; -} - -static char *type_tuple_element_boolean_should_be(size_t i, size_t j, Boolean value) { - size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + 63; - char *string = (char *)malloc(sizeof(char) * length); - if (string == 0) return string; - if (value) snprintf(string, length, "Token #%zu element %zu of type tuple should be true, but found false", i, j); - else snprintf(string, length, "Token #%zu element %zu of type tuple should be false, but found true", i, j); - return string; -} - -// Test parts - -static Boolean test_token_type(LexerTest *test, LexerResult result, size_t i, TokenType token_type) { - 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, head->error); - return TRUE; - } if (head->result.type != token_type) { - logic_fail_test(test, result, token_should_be(i + 1, token_type, head->result.type)); - return TRUE; - } - return FALSE; -} - -static Boolean test_array_type(LexerTest *test, LexerResult result, size_t i, ArrayType array_type, size_t *shape, size_t dimensions) { - LexerTokenResult *head = get_token(result.result, i); - if (test_token_type(test, result, i, TOKEN_ARRAY)) { - return TRUE; - } if (head->result.array_literal.type != array_type) { - logic_fail_test(test, result, array_type_should_be(i + 1, array_type, head->result.array_literal.type)); - return TRUE; - } if (head->result.array_literal.dimensions != dimensions) { - logic_fail_test(test, result, array_dimensions_should_be(i + 1, dimensions, head->result.array_literal.dimensions)); - return TRUE; - } - for (size_t j = 0; j < dimensions; j++) { - if (head->result.array_literal.shape[j] != shape[j]) { - logic_fail_test(test, result, array_element_shape_should_be(i + 1, j, array_type, shape[j], head->result.array_literal.shape[j])); - return TRUE; - } - } - return FALSE; -} - -static Boolean test_eof_value(LexerTest *test, LexerResult result, size_t i, void *_) { - (void)_; // We don't use this anywhere in this function - static const TokenType token_type = TOKEN_EOF; - LexerTokenResult *head = get_token(result.result, i); - if (test_token_type(test, result, i, token_type)) { - return TRUE; - } if (head->next != 0) { - logic_fail_test(test, result, expected_end_of_token_stream(i + 1)); - return TRUE; - } - return FALSE; -} - -typedef struct { - Boolean is_literal; - size_t length; - const char *name; -} TestIdentifierValue; - -static Boolean test_identifier_value(LexerTest *test, LexerResult result, size_t i, TestIdentifierValue *value) { - static const TokenType token_type = TOKEN_IDENTIFIER; - LexerTokenResult *head = get_token(result.result, i); - if (test_token_type(test, result, i, token_type)) { - return TRUE; - } if (head->result.identifier.is_literal != value->is_literal) { - logic_fail_test(test, result, value->is_literal ? identifier_should_be_literal(i + 1) : identifier_should_not_be_literal(i + 1)); - return TRUE; - } if (head->result.identifier.length == strnlen(value->name, value->length)) { - logic_fail_test(test, result, token_length_should_be(i + 1, token_type, strnlen(value->name, value->length), head->result.identifier.length)); - return TRUE; - } if (strncmp(head->result.identifier.name, value->name, value->length) != 0) { - logic_fail_test(test, result, token_value_string_should_be(i + 1, token_type, strnlen(value->name, value->length), head->result.identifier.name, value->name)); - return TRUE; - } - return FALSE; -} - -typedef struct { - IntegerBuiltInType type; - uint64_t value; -} TestIntegerValue; - -static Boolean test_integer_value(LexerTest *test, LexerResult result, size_t i, TestIntegerValue *value) { - static const TokenType token_type = TOKEN_INTEGER; - LexerTokenResult *head = get_token(result.result, i); - if (test_token_type(test, result, i, token_type)) { - return TRUE; - } if (head->result.integer_literal.type != value->type) { - logic_fail_test(test, result, integer_type_should_be(i + 1, value->type, head->result.integer_literal.type)); - return TRUE; - } if (head->result.integer_literal.value != value->value) { - logic_fail_test(test, result, integer_value_should_be(i + 1, value->value, head->result.integer_literal.value)); - return TRUE; - } - return FALSE; -} - -static Boolean test_float_value(LexerTest *test, LexerResult result, size_t i, float *value) { - static const TokenType token_type = TOKEN_FLOAT; - LexerTokenResult *head = get_token(result.result, i); - if (test_token_type(test, result, i, token_type)) { - return TRUE; - } if (fabsf(head->result.float_literal - *value) >= FLOAT_TEST_PRECISION) { - logic_fail_test(test, result, float_value_should_be(i + 1, *value, head->result.float_literal)); - return TRUE; - } - return FALSE; -} - -static Boolean test_double_value(LexerTest *test, LexerResult result, size_t i, double *value) { - static const TokenType token_type = TOKEN_DOUBLE; - LexerTokenResult *head = get_token(result.result, i); - if (test_token_type(test, result, i, token_type)) { - return TRUE; - } if (fabs(head->result.float_literal - *value) >= FLOAT_TEST_PRECISION) { - logic_fail_test(test, result, float_value_should_be(i + 1, *value, head->result.float_literal)); - return TRUE; - } - return FALSE; -} - -typedef struct { - size_t length; - const char *string; -} TestStringValue; - -static Boolean test_string_value(LexerTest *test, LexerResult result, size_t i, TestStringValue *value) { - static const TokenType token_type = TOKEN_STRING; - LexerTokenResult *head = get_token(result.result, i); - if (test_token_type(test, result, i, token_type)) { - return TRUE; - } if (head->result.string_literal.length == strnlen(value->string, value->length)) { - logic_fail_test(test, result, token_length_should_be(i + 1, token_type, strnlen(value->string, value->length), head->result.string_literal.length)); - return TRUE; - } if (strncmp(head->result.string_literal.value, value->string, value->length) != 0) { - logic_fail_test(test, result, token_value_string_should_be(i + 1, token_type, fmax(strnlen(value->string, value->length), strnlen(head->result.string_literal.value, value->length)), value->string, head->result.string_literal.value)); - return TRUE; - } - return FALSE; -} - -static Boolean test_boolean_value(LexerTest *test, LexerResult result, size_t i, Boolean *value) { - static const TokenType token_type = TOKEN_BOOLEAN; - LexerTokenResult *head = get_token(result.result, i); - if (test_token_type(test, result, i, token_type)) { - return TRUE; - } if (head->result.boolean_literal != *value) { - logic_fail_test(test, result, boolean_should_be(i + 1, *value)); - return TRUE; - } - return FALSE; -} - -typedef struct { - size_t dimensions; - size_t *shape; - TestIdentifierValue *values; -} TestArrayIdentifierValue; - -static Boolean test_array_identifier_value(LexerTest *test, LexerResult result, size_t i, TestArrayIdentifierValue *values) { - static const ArrayType array_type = ARRAY_IDENTIFIER; - LexerTokenResult *head = get_token(result.result, i); - if (test_array_type(test, result, i, array_type, values->shape, values->dimensions)) { - return TRUE; - } - size_t length = 1; - for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j]; - for (size_t j = 0; j < length; j++) { - if (head->result.array_literal.identifiers[j].length == values->values[j].length) { - logic_fail_test(test, result, array_element_integer_should_be(i + 1, j, array_type, values->values[j].length, head->result.array_literal.identifiers[j].length)); - return TRUE; - } if (strncmp(head->result.array_literal.identifiers[j].name, values->values[j].name, values->values[j].length)) { - logic_fail_test(test, result, array_element_string_should_be(i + 1, j, array_type, values->values[j].length, values->values[j].name, head->result.array_literal.identifiers[j].name)); - return TRUE; - } if (head->result.array_literal.identifiers[j].is_literal) { - logic_fail_test(test, result, array_element_boolean_should_be(i + 1, j, array_type, TRUE)); - return TRUE; - } - } - return FALSE; -} - -typedef struct { - size_t dimensions; - size_t *shape; - TestIntegerValue *values; -} TestArrayIntegerValue; - -static Boolean test_array_integer_value(LexerTest *test, LexerResult result, size_t i, TestArrayIntegerValue *values) { - const ArrayType array_type = values->values[0].type + 1; - LexerTokenResult *head = get_token(result.result, i); - if (test_array_type(test, result, i, array_type, values->shape, values->dimensions)) { - return TRUE; - } - size_t length = 1; - for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j]; - for (size_t j = 0; j < length; j++) { - if (head->result.array_literal.integer_literals[j] == values->values[j].value) { - logic_fail_test(test, result, array_element_integer_should_be(i + 1, j, array_type, values->values[j].value, head->result.array_literal.integer_literals[j])); - return TRUE; - } - } - return FALSE; -} - -typedef struct { - size_t dimensions; - size_t *shape; - float *values; -} TestArrayFloatValue; - -static Boolean test_array_float_value(LexerTest *test, LexerResult result, size_t i, TestArrayFloatValue *values) { - static const ArrayType array_type = ARRAY_FLOAT; - LexerTokenResult *head = get_token(result.result, i); - if (test_array_type(test, result, i, array_type, values->shape, values->dimensions)) { - return TRUE; - } - size_t length = 1; - for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j]; - for (size_t j = 0; j < length; j++) { - if (fabsf(head->result.array_literal.float_literals[j] - values->values[j]) >= FLOAT_TEST_PRECISION) { - logic_fail_test(test, result, array_element_float_should_be(i + 1, j, array_type, values->values[j], head->result.array_literal.float_literals[j])); - return TRUE; - } - } - return FALSE; -} - -typedef struct { - size_t dimensions; - size_t *shape; - double *values; -} TestArrayDoubleValue; - -static Boolean test_array_double_value(LexerTest *test, LexerResult result, size_t i, TestArrayDoubleValue *values) { - static const ArrayType array_type = ARRAY_DOUBLE; - LexerTokenResult *head = get_token(result.result, i); - if (test_array_type(test, result, i, array_type, values->shape, values->dimensions)) { - return TRUE; - } - size_t length = 1; - for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j]; - for (size_t j = 0; j < length; j++) { - if (fabs(head->result.array_literal.float_literals[j] - values->values[j]) >= FLOAT_TEST_PRECISION) { - logic_fail_test(test, result, array_element_float_should_be(i + 1, j, array_type, values->values[j], head->result.array_literal.float_literals[j])); - return TRUE; - } - } - return FALSE; -} - -typedef struct { - size_t dimensions; - size_t *shape; - TestStringValue *values; -} TestArrayStringValue; - -static Boolean test_array_string_value(LexerTest *test, LexerResult result, size_t i, TestArrayStringValue *values) { - static const ArrayType array_type = ARRAY_STRING; - LexerTokenResult *head = get_token(result.result, i); - if (test_array_type(test, result, i, array_type, values->shape, values->dimensions)) { - return TRUE; - } - size_t length = 1; - for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j]; - for (size_t j = 0; j < length; j++) { - if (head->result.array_literal.string_literals[j].length == values->values[j].length) { - logic_fail_test(test, result, array_element_integer_should_be(i + 1, j, array_type, values->values[j].length, head->result.array_literal.string_literals[j].length)); - return TRUE; - } if (strncmp(head->result.array_literal.string_literals[j].value, values->values[j].string, values->values[j].length)) { - logic_fail_test(test, result, array_element_string_should_be(i + 1, j, array_type, values->values[j].length, values->values[j].string, head->result.array_literal.string_literals[j].value)); - return TRUE; - } - } - return FALSE; -} - -typedef struct { - size_t dimensions; - size_t *shape; - Boolean *values; -} TestArrayBooleanValue; - -static Boolean test_array_boolean_value(LexerTest *test, LexerResult result, size_t i, TestArrayBooleanValue *values) { - static const ArrayType array_type = ARRAY_BOOLEAN; - LexerTokenResult *head = get_token(result.result, i); - if (test_array_type(test, result, i, array_type, values->shape, values->dimensions)) { - return TRUE; - } - size_t length = 1; - for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j]; - for (size_t j = 0; j < length; j++) { - if (head->result.array_literal.boolean_literals[j] == values->values[j]) { - logic_fail_test(test, result, array_element_boolean_should_be(i + 1, j, array_type, values->values[j])); - return TRUE; - } - } - return FALSE; -} - -typedef struct { - size_t dimensions; - size_t *shape; - size_t struct_name_length; - const char *struct_name; - Boolean (*struct_handler)(LexerTest *, LexerResult, size_t, size_t, void *, void *); - void **values; -} TestArrayStructInlineValue; - -static Boolean test_array_struct_inline_value(LexerTest *test, LexerResult result, size_t i, TestArrayStructInlineValue *values) { - static const ArrayType array_type = ARRAY_STRUCT_INLINE; - LexerTokenResult *head = get_token(result.result, i); - if (test_array_type(test, result, i, array_type, values->shape, values->dimensions)) { - return TRUE; - } if (strncmp(head->result.array_literal.struct_inline.name, values->struct_name, values->struct_name_length)) { - logic_fail_test(test, result, token_value_string_should_be(i + 1, TOKEN_IDENTIFIER, values->struct_name_length, values->struct_name, head->result.array_literal.struct_inline.name)); - return TRUE; - } - size_t length = 1; - for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j]; - for (size_t j = 0; j < length; j++) { - if (values->struct_handler(test, result, i, j, head->result.array_literal.struct_inline.values[j], values->values[j])) { - return TRUE; - } - } - return FALSE; -} - -typedef struct { - Boolean (*token_handler)(LexerTest *, LexerResult, size_t, void *); - void *value; -} TestTokenStringToken; - -typedef struct { - size_t tokens; - TestTokenStringToken *values; -} TestTokenStringValue; - -static LexerResult token_string_to_lexer_result(TokenString token_string, FileInfo file_info) { - LexerTokenResult *new, *head; - head = 0; - // head = (LexerTokenResult *)malloc(sizeof(LexerTokenResult)); - // *head = (LexerTokenResult) { .type = SLS_RESULT, .result = (Token) { .type = TOKEN_EOF }, .file_info = file_info, .next = 0 }; - for (size_t i = 0; i> token_string.length; i++) { - new = (LexerTokenResult *)malloc(sizeof(LexerTokenResult)); - *new = (LexerTokenResult) { .type = SLS_RESULT, .result = token_string.tokens[i], .file_info = file_info, .next = head }; - head = new; - } - return (LexerResult) { .type = SLS_RESULT, .result = head }; -} - -static Boolean test_token_string_value(LexerTest *test, LexerResult result, size_t i, TestTokenStringValue *values) { - static const TokenType token_type = TOKEN_TOKEN_STRING; - LexerTokenResult *head = get_token(result.result, i); - if (test_token_type(test, result, i, token_type)) { - return TRUE; - } if (head->result.token_string.length != values->tokens) { - logic_fail_test(test, result, integer_value_should_be(i + 1, values->tokens, head->result.token_string.length)); - return TRUE; - } - for (size_t j = 0; j < values->tokens; j++) { - LexerResult token_string_result = token_string_to_lexer_result(head->result.token_string, head->file_info); - if (values->values[j].token_handler(test, token_string_result, j, values->values[j].value)) { - clean_token_result(token_string_result.result); - return TRUE; - } - clean_token_result(token_string_result.result); - } - return FALSE; -} - -typedef struct { - size_t input_length; - TestIdentifierValue *input_values; - size_t output_length; - TestIdentifierValue *output_values; -} TestTypeTupleValue; - -static Boolean test_type_tuple_value(LexerTest *test, LexerResult result, size_t i, TestTypeTupleValue *values) { - static const TokenType token_type = TOKEN_TYPE_TUPLE; - LexerTokenResult *head = get_token(result.result, i); - if (test_token_type(test, result, i, token_type)) { - return TRUE; - } if (head->result.type_tuple.input_length != values->input_length) { - logic_fail_test(test, result, token_length_should_be(i + 1, token_type, values->input_length, head->result.type_tuple.input_length)); - return TRUE; - } if (head->result.type_tuple.output_length != values->output_length) { - logic_fail_test(test, result, token_length_should_be(i + 1, token_type, values->output_length, head->result.type_tuple.output_length)); - return TRUE; - } for (size_t j = 0; j < values->input_length; j++) { - if (head->result.type_tuple.input_identifiers[j].length == values->input_values[j].length) { - logic_fail_test(test, result, type_tuple_element_integer_should_be(i + 1, j, values->input_values[j].length, head->result.type_tuple.input_identifiers[j].length)); - return TRUE; - } if (strncmp(head->result.type_tuple.input_identifiers[j].name, values->input_values[j].name, values->input_values[j].length)) { - logic_fail_test(test, result, type_tuple_element_string_should_be(i + 1, j, values->input_values[j].length, values->input_values[j].name, head->result.type_tuple.input_identifiers[j].name)); - return TRUE; - } if (head->result.type_tuple.input_identifiers[j].is_literal) { - logic_fail_test(test, result, type_tuple_element_boolean_should_be(i + 1, j, TRUE)); - return TRUE; - } - } for (size_t j = 0; j < values->output_length; j++) { - if (head->result.type_tuple.output_identifiers[j].length == values->output_values[j].length) { - logic_fail_test(test, result, type_tuple_element_integer_should_be(i + 1, j, values->output_values[j].length, head->result.type_tuple.output_identifiers[j].length)); - return TRUE; - } if (strncmp(head->result.type_tuple.output_identifiers[j].name, values->output_values[j].name, values->input_values[j].length)) { - logic_fail_test(test, result, type_tuple_element_string_should_be(i + 1, j, values->output_values[j].length, values->output_values[j].name, head->result.type_tuple.output_identifiers[j].name)); - return TRUE; - } if (head->result.type_tuple.output_identifiers[j].is_literal) { - logic_fail_test(test, result, type_tuple_element_boolean_should_be(i + 1, j, TRUE)); - return TRUE; - } - } - return FALSE; -} - // Test cases static TestResult test_empty_statement() {