279 lines
13 KiB
Python
279 lines
13 KiB
Python
from typing import List, Dict, Any, Optional
|
|
from .utils import Token, Operation, StackItem, RuntimeError, TestCase, to_dict
|
|
|
|
class IntegerTestGenerator:
|
|
"""Generate test cases for integer literals."""
|
|
|
|
# Type ranges
|
|
TYPE_RANGES = {
|
|
'i8': (-128, 127),
|
|
'i16': (-32768, 32767),
|
|
'i32': (-2147483648, 2147483647),
|
|
'i64': (-9223372036854775808, 9223372036854775807),
|
|
'u8': (0, 255),
|
|
'u16': (0, 65535),
|
|
'u32': (0, 4294967295),
|
|
'u64': (0, 18446744073709551615),
|
|
}
|
|
|
|
def __init__(self):
|
|
self.tests = []
|
|
|
|
def add_test(self, name: str, code: str, tokens: List[Token],
|
|
operations: Optional[List[Operation]] = None,
|
|
stack_final: Optional[List[StackItem]] = None,
|
|
runtime_error: Optional[RuntimeError] = None):
|
|
"""Add a test case."""
|
|
test = TestCase(
|
|
name=name,
|
|
code=code,
|
|
tokens=[to_dict(t) for t in tokens],
|
|
operations=[to_dict(o) for o in operations] if operations else None,
|
|
stack_final=[to_dict(s) for s in stack_final] if stack_final else None,
|
|
runtime_error=to_dict(runtime_error) if runtime_error else None
|
|
)
|
|
self.tests.append(to_dict(test))
|
|
|
|
def make_push_op(self, type_name: str, value: Any) -> Operation:
|
|
"""Create a push operation."""
|
|
return Operation(function="push", type=type_name, value=value)
|
|
|
|
def make_stack_item(self, type_name: str, value: Any) -> StackItem:
|
|
"""Create a stack item."""
|
|
return StackItem(type=type_name, value=value)
|
|
|
|
def make_error_token(self, message: str) -> Token:
|
|
"""Create an error token."""
|
|
return Token(type="error", value=message)
|
|
|
|
def make_success_test(self, name: str, code: str, type_name: str, value: Any):
|
|
"""Create a successful test case."""
|
|
token = Token(type=type_name, value=value)
|
|
op = self.make_push_op(type_name, value)
|
|
stack = self.make_stack_item(type_name, value)
|
|
self.add_test(name, code, [token], [op], [stack])
|
|
|
|
def make_error_test(self, name: str, code: str, error_msg: str):
|
|
"""Create an error test case."""
|
|
token = self.make_error_token(error_msg)
|
|
self.add_test(name, code, [token])
|
|
|
|
def generate_basic_tests(self):
|
|
"""Generate basic test cases."""
|
|
# Empty statement
|
|
self.add_test("Empty_Statement", "", [], [], [])
|
|
|
|
# Simple default integers
|
|
self.make_success_test("Integer Default Decimal 0", "0", "i64", 0)
|
|
self.make_success_test("Integer Default Decimal -1", "-1", "i64", -1)
|
|
self.make_success_test("Integer Default Decimal 42", "42", "i64", 42)
|
|
self.make_success_test("Integer Default Decimal Leading Zeros", "00042", "i64", 42)
|
|
|
|
def generate_default_base_tests(self):
|
|
"""Generate tests for default type with different bases."""
|
|
# Hexadecimal
|
|
self.make_success_test("Integer Default Hex 0xFF", "0xFF", "i64", 255)
|
|
self.make_success_test("Integer Default Hex 0xdeadbeef", "0xdeadbeef", "i64", 3735928559)
|
|
self.make_success_test("Integer Default Hex Max", "0x7FFFFFFFFFFFFFFF", "i64", 9223372036854775807)
|
|
|
|
# Binary
|
|
self.make_success_test("Integer Default Binary 0b1010", "0b1010", "i64", 10)
|
|
self.make_success_test("Integer Default Binary All Ones", "0b1111111111111111", "i64", 65535)
|
|
|
|
# Octal
|
|
self.make_success_test("Integer Default Octal 0o755", "0o755", "i64", 493)
|
|
self.make_success_test("Integer Default Octal Max Three Digits", "0o777", "i64", 511)
|
|
|
|
def generate_default_edge_cases(self):
|
|
"""Generate edge case tests for default type."""
|
|
# Min/max values
|
|
self.make_success_test("Integer Default Decimal Max i64",
|
|
"9223372036854775807", "i64", 9223372036854775807)
|
|
self.make_success_test("Integer Default Decimal Min i64",
|
|
"-9223372036854775808", "i64", -9223372036854775808)
|
|
|
|
# Underscores
|
|
self.make_success_test("Integer Default Decimal with Underscore",
|
|
"1_000_000", "i64", 1000000)
|
|
self.make_success_test("Integer Default Underscore End", "42_", "i64", 42)
|
|
self.make_success_test("Integer Default Underscore Double", "4__2", "i64", 42)
|
|
|
|
# Whitespace
|
|
self.make_success_test("Integer Default Whitespace", " 42 ", "i64", 42)
|
|
|
|
# Zeros in different bases
|
|
self.make_success_test("Integer Default Hex Zero", "0x0", "i64", 0)
|
|
self.make_success_test("Integer Default Binary Zero", "0b0", "i64", 0)
|
|
self.make_success_test("Integer Default Octal Zero", "0o0", "i64", 0)
|
|
|
|
def generate_default_error_tests(self):
|
|
"""Generate error tests for default type."""
|
|
self.make_error_test("Integer Default Decimal with Commas Invalid",
|
|
"1,000,000",
|
|
"Invalid decimal literal: unexpected ',' in decimal integer.")
|
|
self.make_error_test("Integer Default Invalid Characters",
|
|
"12a3",
|
|
"Invalid decimal literal: unexpected 'a' in decimal integer.")
|
|
self.make_error_test("Integer Default Invalid Prefix",
|
|
"0b2",
|
|
"Invalid binary literal: unexpected '2' in binary integer.")
|
|
|
|
def generate_typed_tests(self, type_name: str):
|
|
"""Generate tests for a specific type across all bases."""
|
|
min_val, max_val = self.TYPE_RANGES[type_name]
|
|
is_unsigned = type_name.startswith('u')
|
|
|
|
# Basic decimal
|
|
test_val = 42 if max_val >= 42 else max_val
|
|
self.make_success_test(f"Integer {type_name} Decimal Positive",
|
|
f"{test_val}:{type_name}", type_name, test_val)
|
|
|
|
# Zero
|
|
self.make_success_test(f"Integer {type_name} Zero",
|
|
f"0:{type_name}", type_name, 0)
|
|
|
|
# Negative (only for signed types)
|
|
if not is_unsigned:
|
|
neg_val = -100 if min_val <= -100 else min_val
|
|
self.make_success_test(f"Integer {type_name} Decimal Negative",
|
|
f"{neg_val}:{type_name}", type_name, neg_val)
|
|
|
|
# Hexadecimal
|
|
hex_val = min(255, max_val)
|
|
self.make_success_test(f"Integer {type_name} Hex",
|
|
f"0x{hex_val:X}:{type_name}", type_name, hex_val)
|
|
|
|
# Binary
|
|
bin_val = min(15, max_val)
|
|
self.make_success_test(f"Integer {type_name} Binary",
|
|
f"0b{bin_val:b}:{type_name}", type_name, bin_val)
|
|
|
|
# Octal
|
|
oct_val = min(63, max_val)
|
|
self.make_success_test(f"Integer {type_name} Octal",
|
|
f"0o{oct_val:o}:{type_name}", type_name, oct_val)
|
|
|
|
# Max value
|
|
self.make_success_test(f"Integer {type_name} Max Value",
|
|
f"{max_val}:{type_name}", type_name, max_val)
|
|
|
|
# Min value
|
|
self.make_success_test(f"Integer {type_name} Min Value",
|
|
f"{min_val}:{type_name}", type_name, min_val)
|
|
|
|
# Overflow
|
|
overflow_val = max_val + 1
|
|
self.make_error_test(f"Integer {type_name} Overflow",
|
|
f"{overflow_val}:{type_name}",
|
|
f"Integer overflow: value exceeds range for {type_name}.")
|
|
|
|
# Underflow
|
|
underflow_val = min_val - 1
|
|
self.make_error_test(f"Integer {type_name} Underflow",
|
|
f"{underflow_val}:{type_name}",
|
|
f"Integer overflow: value exceeds range for {type_name}.")
|
|
|
|
def generate_special_typed_tests(self, type_name: str):
|
|
"""Generate special tests for specific types."""
|
|
min_val, max_val = self.TYPE_RANGES[type_name]
|
|
is_unsigned = type_name.startswith('u')
|
|
|
|
# Underscores with type annotation
|
|
if max_val >= 1000000:
|
|
self.make_success_test(f"Integer {type_name} With Underscores",
|
|
f"1_000_000:{type_name}", type_name, 1000000)
|
|
|
|
# Special values for specific types
|
|
if type_name == 'i8':
|
|
self.make_success_test("Integer i8 Hex Max", "0x7F:i8", "i8", 127)
|
|
self.make_success_test("Integer i8 Binary Max", "0b01111111:i8", "i8", 127)
|
|
self.make_success_test("Integer i8 Octal Max", "0o177:i8", "i8", 127)
|
|
self.make_success_test("Integer i8 Negative Hex", "-0x80:i8", "i8", -128)
|
|
|
|
elif type_name == 'u8':
|
|
self.make_success_test("Integer u8 Hex Max", "0xFF:u8", "u8", 255)
|
|
self.make_success_test("Integer u8 Binary Max", "0b11111111:u8", "u8", 255)
|
|
self.make_success_test("Integer u8 Octal Max", "0o377:u8", "u8", 255)
|
|
|
|
elif type_name == 'i16':
|
|
self.make_success_test("Integer i16 Hex Sample", "0x1234:i16", "i16", 4660)
|
|
self.make_success_test("Integer i16 Binary Sample",
|
|
"0b1111111100000000:i16", "i16", 65280)
|
|
self.make_success_test("Integer i16 Octal Sample", "0o1234:i16", "i16", 668)
|
|
|
|
elif type_name == 'u16':
|
|
self.make_success_test("Integer u16 Hex Max", "0xFFFF:u16", "u16", 65535)
|
|
self.make_success_test("Integer u16 Binary Max",
|
|
"0b1111111111111111:u16", "u16", 65535)
|
|
self.make_success_test("Integer u16 Octal Max", "0o177777:u16", "u16", 65535)
|
|
self.make_success_test("Integer u16 Decimal Mid", "50000:u16", "u16", 50000)
|
|
|
|
elif type_name == 'i32':
|
|
self.make_success_test("Integer i32 Hex Sample", "0xABCD:i32", "i32", 43981)
|
|
self.make_success_test("Integer i32 Binary Sample",
|
|
"0b11110000:i32", "i32", 240)
|
|
|
|
elif type_name == 'u32':
|
|
self.make_success_test("Integer u32 Hex Max", "0xFFFFFFFF:u32", "u32", 4294967295)
|
|
self.make_success_test("Integer u32 Binary Sample",
|
|
"0b11111111000000001111111100000000:u32",
|
|
"u32", 4278255360)
|
|
self.make_success_test("Integer u32 Octal Max",
|
|
"0o37777777777:u32", "u32", 4294967295)
|
|
self.make_success_test("Integer u32 Decimal Mid", "1000000:u32", "u32", 1000000)
|
|
|
|
elif type_name == 'i64':
|
|
self.make_success_test("Integer i64 Decimal Positive 42", "42:i64", "i64", 42)
|
|
self.make_success_test("Integer i64 Hex 0xFF", "0xFF:i64", "i64", 255)
|
|
self.make_success_test("Integer i64 Binary 0b1010", "0b1010:i64", "i64", 10)
|
|
self.make_success_test("Integer i64 Octal 0o755", "0o755:i64", "i64", 493)
|
|
|
|
elif type_name == 'u64':
|
|
self.make_success_test("Integer u64 Hex Max",
|
|
"0xFFFFFFFFFFFFFFFF:u64",
|
|
"u64", 18446744073709551615)
|
|
self.make_success_test("Integer u64 Binary Sample",
|
|
"0b1010101010101010:u64", "u64", 43690)
|
|
self.make_success_test("Integer u64 Octal Sample", "0o7777:u64", "u64", 4095)
|
|
self.make_success_test("Integer u64 Decimal", "42:u64", "u64", 42)
|
|
|
|
def generate_underscore_tests(self):
|
|
"""Generate tests for underscores in different bases."""
|
|
self.make_success_test("Integer Hex With Underscores",
|
|
"0xDEAD_BEEF:i64", "i64", 3735928559)
|
|
self.make_success_test("Integer Binary With Underscores",
|
|
"0b1111_0000_1010_0101:i32", "i32", 61605)
|
|
self.make_success_test("Integer Octal With Underscores",
|
|
"0o7_7_7:i16", "i16", 511)
|
|
|
|
def generate_all_tests(self) -> List[Dict[str, Any]]:
|
|
"""Generate all test cases."""
|
|
# Basic tests
|
|
self.generate_basic_tests()
|
|
|
|
# Default type (i64) comprehensive tests
|
|
self.generate_default_base_tests()
|
|
self.generate_default_edge_cases()
|
|
self.generate_default_error_tests()
|
|
|
|
# Tests for each specific type
|
|
for type_name in ['i8', 'i16', 'i32', 'i64', 'u8', 'u16', 'u32', 'u64']:
|
|
self.generate_typed_tests(type_name)
|
|
self.generate_special_typed_tests(type_name)
|
|
|
|
# Additional edge cases
|
|
self.generate_underscore_tests()
|
|
|
|
return self.tests
|
|
|
|
|
|
def generate_integer_literal_tests() -> List[Dict[str, Any]]:
|
|
"""
|
|
Main function to generate all integer literal test cases.
|
|
|
|
Returns:
|
|
List of test case dictionaries ready for serialization
|
|
"""
|
|
generator = IntegerTestGenerator()
|
|
return generator.generate_all_tests()
|