Extracted lexer test helpers
This commit is contained in:
parent
b121c1dc9b
commit
bc2247481b
|
|
@ -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 <stddef.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#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
|
||||
|
|
@ -0,0 +1,578 @@
|
|||
// Kyler Olsen
|
||||
// YREA SLS
|
||||
// Lexer Tests
|
||||
// October 2025
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
@ -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() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue