Setting up float and character tests

This commit is contained in:
Kyler Olsen 2025-11-14 17:22:06 -07:00
parent db14867474
commit 60925dab53
5 changed files with 107 additions and 77 deletions

View File

@ -10,6 +10,7 @@
- `u` uint64_t - `u` uint64_t
- `z` size_t - `z` size_t
- `f` double - `f` double
- `n` unicode uint8_t\[4\] (Not Implemented)
- `s` string.h SlsStr - `s` string.h SlsStr
- `t` lexer.h TokenType - `t` lexer.h TokenType
- `a` lexer.h ArrayType - `a` lexer.h ArrayType

View File

@ -127,6 +127,11 @@ static SlsStr integer_value_should_be(size_t i, uint64_t should, uint64_t found)
return sls_format(SLS_STR("Token #%z integer value should be %i, but found %i"), i, should, found); return sls_format(SLS_STR("Token #%z integer value should be %i, but found %i"), i, should, found);
} }
static SlsStr character_value_should_be(size_t i, uint8_t should, uint8_t found) {
return sls_format(SLS_STR("Token #%z integer value should be %i, but found %i"), i, should, found);
// return sls_format(SLS_STR("Token #%z character value should be '', but found ''"), i, should[0], found[0]);
}
static SlsStr float_value_should_be(size_t i, double should, double found) { static SlsStr float_value_should_be(size_t i, double should, double found) {
return sls_format(SLS_STR("Token #%z float value should be %f, but found %f"), i, should, found); return sls_format(SLS_STR("Token #%z float value should be %f, but found %f"), i, should, found);
} }
@ -285,6 +290,18 @@ Boolean test_integer_value(LexerTest *test, LexerResult result, size_t i, TestIn
return FALSE; return FALSE;
} }
Boolean test_character_value(LexerTest *test, LexerResult result, size_t i, uint8_t *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.value != *value) {
logic_fail_test(test, result, character_value_should_be(i + 1, *value, head->result.float_literal));
return TRUE;
}
return FALSE;
}
Boolean test_float_value(LexerTest *test, LexerResult result, size_t i, float *value) { Boolean test_float_value(LexerTest *test, LexerResult result, size_t i, float *value) {
static const TokenType token_type = TOKEN_FLOAT; static const TokenType token_type = TOKEN_FLOAT;
LexerTokenResult *head = get_token(result.result, i); LexerTokenResult *head = get_token(result.result, i);

View File

@ -5,15 +5,17 @@ from .base_tests import BaseTestGenerator
class CharTestGenerator(BaseTestGenerator): class CharTestGenerator(BaseTestGenerator):
"""Generate test cases for character literals.""" """Generate test cases for character literals."""
ENABLE_UNICODE = False
# Common escape sequences # Common escape sequences
ESCAPE_SEQUENCES = { ESCAPE_SEQUENCES = {
'\\n': '\n', # Newline ("Newline", '\\n', '\n',), # Newline
'\\r': '\r', # Carriage return ("Carriage return", '\\r', '\r',), # Carriage return
'\\t': '\t', # Tab ("Tab", '\\t', '\t',), # Tab
'\\\\': '\\', # Backslash ("Backslash", '\\\\', '\\',), # Backslash
'\\"': '"', # Double quote ("Double quote", '\\\\"', '"',), # Double quote
"\\'": "'", # Single quote ("Single quote", "\\'", "'",), # Single quote
'\\0': '\0', # Null character ("Null character", '\\0', '\0',), # Null character
} }
# Hexadecimal escape examples # Hexadecimal escape examples
@ -77,8 +79,8 @@ class CharTestGenerator(BaseTestGenerator):
def generate_escape_sequence_tests(self): def generate_escape_sequence_tests(self):
"""Generate tests for escape sequences.""" """Generate tests for escape sequences."""
# Standard escape sequences # Standard escape sequences
for escape_str, char_val in self.ESCAPE_SEQUENCES.items(): for escape_name, escape_str, char_val in self.ESCAPE_SEQUENCES:
name = f"Char Escape {escape_str}" name = f"Char Escape {escape_name}"
code = f"'{escape_str}'" code = f"'{escape_str}'"
self.make_success_test(name, code, "char", char_val) self.make_success_test(name, code, "char", char_val)
@ -88,7 +90,7 @@ class CharTestGenerator(BaseTestGenerator):
("Carriage Return", "'\\r'", '\r'), ("Carriage Return", "'\\r'", '\r'),
("Tab", "'\\t'", '\t'), ("Tab", "'\\t'", '\t'),
("Backslash", "'\\\\'", '\\'), ("Backslash", "'\\\\'", '\\'),
("Double Quote", "'\\\"'", '"'), ("Double Quote", "'\\\\\"'", '"'),
("Single Quote", "'\\''", "'"), ("Single Quote", "'\\''", "'"),
("Null", "'\\0'", '\0'), ("Null", "'\\0'", '\0'),
] ]
@ -163,8 +165,8 @@ class CharTestGenerator(BaseTestGenerator):
self.make_success_test("Char With Leading Whitespace", " 'A'", "char", 'A') self.make_success_test("Char With Leading Whitespace", " 'A'", "char", 'A')
self.make_success_test("Char With Trailing Whitespace", "'A' ", "char", 'A') self.make_success_test("Char With Trailing Whitespace", "'A' ", "char", 'A')
self.make_success_test("Char With Both Whitespace", " 'A' ", "char", 'A') self.make_success_test("Char With Both Whitespace", " 'A' ", "char", 'A')
self.make_success_test("Char Tab Before", "\t'B'", "char", 'B') self.make_success_test("Char Tab Before", "\\t'B'", "char", 'B')
self.make_success_test("Char Newline Before", "\n'C'", "char", 'C') self.make_success_test("Char Newline Before", "\\n'C'", "char", 'C')
def generate_error_tests(self): def generate_error_tests(self):
"""Generate error test cases.""" """Generate error test cases."""
@ -185,7 +187,7 @@ class CharTestGenerator(BaseTestGenerator):
# Unescaped newline # Unescaped newline
self.make_error_test("Char Unescaped Newline", self.make_error_test("Char Unescaped Newline",
"'\n'", "'\\n'",
"Invalid character literal: unescaped newline in character literal.") "Invalid character literal: unescaped newline in character literal.")
# Invalid escape sequence # Invalid escape sequence
@ -204,42 +206,43 @@ class CharTestGenerator(BaseTestGenerator):
# Invalid hex digits # Invalid hex digits
self.make_error_test("Char Hex Invalid Digit", self.make_error_test("Char Hex Invalid Digit",
"'\\xGG'", "'\\\\xGG'",
"Invalid character literal: invalid hexadecimal digit 'G'.") "Invalid character literal: invalid hexadecimal digit 'G'.")
# Invalid Unicode escape (no braces) if self.ENABLE_UNICODE:
self.make_error_test("Char Unicode No Braces", # Invalid Unicode escape (no braces)
"'\\u1F600'", self.make_error_test("Char Unicode No Braces",
"Invalid character literal: Unicode escape must use braces \\u{...}.") "'\\u1F600'",
"Invalid character literal: Unicode escape must use braces \\u{...}.")
# Invalid Unicode escape (empty)
self.make_error_test("Char Unicode Empty", # Invalid Unicode escape (empty)
"'\\u{}'", self.make_error_test("Char Unicode Empty",
"Invalid character literal: empty Unicode escape sequence.") "'\\u{}'",
"Invalid character literal: empty Unicode escape sequence.")
# Invalid Unicode escape (too many digits)
self.make_error_test("Char Unicode Too Many Digits", # Invalid Unicode escape (too many digits)
"'\\u{1234567}'", self.make_error_test("Char Unicode Too Many Digits",
"Invalid character literal: Unicode escape sequence too long (max 6 hex digits).") "'\\u{1234567}'",
"Invalid character literal: Unicode escape sequence too long (max 6 hex digits).")
# Invalid Unicode escape (invalid code point)
self.make_error_test("Char Unicode Invalid Code Point", # Invalid Unicode escape (invalid code point)
"'\\u{D800}'", self.make_error_test("Char Unicode Invalid Code Point",
"Invalid character literal: invalid Unicode code point (surrogate range).") "'\\u{D800}'",
"Invalid character literal: invalid Unicode code point (surrogate range).")
self.make_error_test("Char Unicode Out Of Range",
"'\\u{110000}'", self.make_error_test("Char Unicode Out Of Range",
"Invalid character literal: Unicode code point out of range (max 0x10FFFF).") "'\\u{110000}'",
"Invalid character literal: Unicode code point out of range (max 0x10FFFF).")
# Invalid Unicode escape (non-hex digits)
self.make_error_test("Char Unicode Invalid Hex", # Invalid Unicode escape (non-hex digits)
"'\\u{GGGG}'", self.make_error_test("Char Unicode Invalid Hex",
"Invalid character literal: invalid hexadecimal digit 'G' in Unicode escape.") "'\\u{GGGG}'",
"Invalid character literal: invalid hexadecimal digit 'G' in Unicode escape.")
# Unclosed Unicode escape
self.make_error_test("Char Unicode Unclosed", # Unclosed Unicode escape
"'\\u{1F600'", self.make_error_test("Char Unicode Unclosed",
"Invalid character literal: unclosed Unicode escape sequence.") "'\\u{1F600'",
"Invalid character literal: unclosed Unicode escape sequence.")
# Double quotes instead of single # Double quotes instead of single
self.make_error_test("Char Double Quotes", self.make_error_test("Char Double Quotes",
@ -263,29 +266,30 @@ class CharTestGenerator(BaseTestGenerator):
self.make_success_test("Char Extended ASCII Lower", "'\\x80'", "char", '\x80') self.make_success_test("Char Extended ASCII Lower", "'\\x80'", "char", '\x80')
self.make_success_test("Char Extended ASCII Upper", "'\\xFF'", "char", '\xFF') self.make_success_test("Char Extended ASCII Upper", "'\\xFF'", "char", '\xFF')
# Zero-width characters if self.ENABLE_UNICODE:
self.make_success_test("Char Zero Width Space", "'\\u{200B}'", "char", '\u200B') # Zero-width characters
self.make_success_test("Char Zero Width Joiner", "'\\u{200D}'", "char", '\u200D') self.make_success_test("Char Zero Width Space", "'\\u{200B}'", "char", '\u200B')
self.make_success_test("Char Zero Width Joiner", "'\\u{200D}'", "char", '\u200D')
# Right-to-left marks
self.make_success_test("Char RTL Mark", "'\\u{200F}'", "char", '\u200F') # Right-to-left marks
self.make_success_test("Char RTL Mark", "'\\u{200F}'", "char", '\u200F')
# Combining characters
self.make_success_test("Char Combining Acute", "'\\u{0301}'", "char", '\u0301') # Combining characters
self.make_success_test("Char Combining Acute", "'\\u{0301}'", "char", '\u0301')
# Low Unicode values
self.make_success_test("Char Unicode Zero", "'\\u{0}'", "char", '\0') # Low Unicode values
self.make_success_test("Char Unicode One", "'\\u{1}'", "char", '\x01') self.make_success_test("Char Unicode Zero", "'\\u{0}'", "char", '\0')
self.make_success_test("Char Unicode One", "'\\u{1}'", "char", '\x01')
# High Unicode values (but valid)
self.make_success_test("Char Unicode High Valid", "'\\u{10FFFF}'", "char", '\U0010FFFF') # High Unicode values (but valid)
self.make_success_test("Char Unicode High Valid", "'\\u{10FFFF}'", "char", '\U0010FFFF')
# Backslash before valid character # Backslash before valid character
self.make_success_test("Char Backslash Literal", "'\\\\'", "char", '\\') self.make_success_test("Char Backslash Literal", "'\\\\'", "char", '\\')
# Quote escaping # Quote escaping
self.make_success_test("Char Single Quote Escaped", "'\\''", "char", "'") self.make_success_test("Char Single Quote Escaped", "'\\''", "char", "'")
self.make_success_test("Char Double Quote Escaped", "'\\\"'", "char", '"') # self.make_success_test("Char Double Quote Escaped", "'\\\"'", "char", '"')
def generate_case_sensitivity_tests(self): def generate_case_sensitivity_tests(self):
"""Generate tests for case sensitivity in escape sequences.""" """Generate tests for case sensitivity in escape sequences."""
@ -297,13 +301,14 @@ class CharTestGenerator(BaseTestGenerator):
self.make_success_test("Char Hex Digits Lowercase", "'\\xff'", "char", '\xff') self.make_success_test("Char Hex Digits Lowercase", "'\\xff'", "char", '\xff')
self.make_success_test("Char Hex Digits Mixed", "'\\xAb'", "char", '\xAB') self.make_success_test("Char Hex Digits Mixed", "'\\xAb'", "char", '\xAB')
# Unicode escapes - lowercase u if self.ENABLE_UNICODE:
self.make_success_test("Char Unicode Lowercase u", "'\\u{41}'", "char", 'A') # Unicode escapes - lowercase u
self.make_success_test("Char Unicode Lowercase u", "'\\u{41}'", "char", 'A')
# Unicode hex digits - both cases
self.make_success_test("Char Unicode Hex Uppercase", "'\\u{1F600}'", "char", '😀') # Unicode hex digits - both cases
self.make_success_test("Char Unicode Hex Lowercase", "'\\u{1f600}'", "char", '😀') self.make_success_test("Char Unicode Hex Uppercase", "'\\u{1F600}'", "char", '😀')
self.make_success_test("Char Unicode Hex Mixed", "'\\u{1F60a}'", "char", '😊') self.make_success_test("Char Unicode Hex Lowercase", "'\\u{1f600}'", "char", '😀')
self.make_success_test("Char Unicode Hex Mixed", "'\\u{1F60a}'", "char", '😊')
def generate_all_tests(self) -> List[Dict[str, Any]]: def generate_all_tests(self) -> List[Dict[str, Any]]:
"""Generate all character literal test cases.""" """Generate all character literal test cases."""
@ -316,11 +321,12 @@ class CharTestGenerator(BaseTestGenerator):
# Hexadecimal escapes # Hexadecimal escapes
self.generate_hexadecimal_escape_tests() self.generate_hexadecimal_escape_tests()
# Unicode escapes if self.ENABLE_UNICODE:
self.generate_unicode_escape_tests() # Unicode escapes
self.generate_unicode_escape_tests()
# Direct Unicode characters
self.generate_unicode_direct_tests() # Direct Unicode characters
self.generate_unicode_direct_tests()
# Whitespace handling # Whitespace handling
self.generate_whitespace_tests() self.generate_whitespace_tests()

View File

@ -287,7 +287,7 @@ class FloatTestGenerator(BaseTestGenerator):
self.generate_underscore_tests() self.generate_underscore_tests()
# Special values (inf, nan) # Special values (inf, nan)
self.generate_special_value_tests() # self.generate_special_value_tests()
# Edge cases for each type # Edge cases for each type
for type_name in ['f32', 'f64']: for type_name in ['f32', 'f64']:

View File

@ -68,6 +68,12 @@ def _token_to_c_call(token: dict, idx_var="i") -> str:
return f'test_integer_value(&test, result, {idx_var}++, &(TestIntegerValue){{INTEGER_U16, {value}}})' return f'test_integer_value(&test, result, {idx_var}++, &(TestIntegerValue){{INTEGER_U16, {value}}})'
elif ttype == "u8": elif ttype == "u8":
return f'test_integer_value(&test, result, {idx_var}++, &(TestIntegerValue){{INTEGER_U8, {value}}})' return f'test_integer_value(&test, result, {idx_var}++, &(TestIntegerValue){{INTEGER_U8, {value}}})'
elif ttype == "f64":
return f'test_double_value(&test, result, {idx_var}++, &(double){{{value}}})'
elif ttype == "f32":
return f'test_float_value(&test, result, {idx_var}++, &(float){{{value}}})'
elif ttype == "char":
return f'test_character_value(&test, result, {idx_var}++, &(uint8_t){{{ord(value)}}})' # type: ignore
elif ttype == "identifier": elif ttype == "identifier":
return f'test_identifier_value(&test, result, {idx_var}++, &(TestIdentifierValue){{FALSE, {len(value)}, "{value}"}})' # type: ignore return f'test_identifier_value(&test, result, {idx_var}++, &(TestIdentifierValue){{FALSE, {len(value)}, "{value}"}})' # type: ignore
elif ttype == "identifier_literal": elif ttype == "identifier_literal":