""" Test case generator for integer literals in the Stack Language. Generates comprehensive test cases for all integer types and bases. """ from typing import List, Dict, Any, Optional from dataclasses import dataclass, asdict @dataclass class Token: type: str value: Any @dataclass class Operation: function: str type: str value: Any @dataclass class StackItem: type: str value: Any @dataclass class RuntimeError: message: str @dataclass class TestCase: name: str code: str tokens: List[Dict[str, Any]] operations: Optional[List[Dict[str, Any]]] = None stack_final: Optional[List[Dict[str, Any]]] = None runtime_error: Optional[Dict[str, str]] = None def to_dict(obj): """Convert dataclass to dict, removing None values.""" if obj is None: return None d = asdict(obj) if hasattr(obj, '__dataclass_fields__') else obj return {k: v for k, v in d.items() if v is not None} 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() if __name__ == "__main__": # import json import yaml # Generate tests tests = generate_integer_literal_tests() # Print summary print(f"Generated {len(tests)} test cases") # # Save as JSON # with open("integer_literal_tests.json", "w") as f: # json.dump(tests, f, indent=2) # print("Saved to integer_literal_tests.json") # # Save as YAML # with open("integer_literal_tests.yaml", "w") as f: # yaml.dump(tests, f, default_flow_style=False, sort_keys=False) # print("Saved to integer_literal_tests.yaml") # Save as YAML with open("cases.yaml", "w") as f: yaml.dump(tests, f, default_flow_style=False, sort_keys=False) # Print first few tests as example print("\nFirst 3 test cases:") print(yaml.dump(tests[:3], default_flow_style=False, sort_keys=False))