from typing import List, Dict, Any from .base_tests import BaseTestGenerator class FloatTestGenerator(BaseTestGenerator): """Generate test cases for floating point literals.""" # Special float values SPECIAL_VALUES = { 'f32': { 'min': -3.4028235e38, 'max': 3.4028235e38, 'min_positive': 1.1754944e-38, 'epsilon': 1.1920929e-7, }, 'f64': { 'min': -1.7976931348623157e308, 'max': 1.7976931348623157e308, 'min_positive': 2.2250738585072014e-308, 'epsilon': 2.220446049250313e-16, } } def generate_basic_tests(self): """Generate basic test cases.""" # Simple default floats (f64) self.make_success_test("Float Default Simple", "3.14", "f64", 3.14) self.make_success_test("Float Default Zero", "0.0", "f64", 0.0) self.make_success_test("Float Default Negative", "-2.5", "f64", -2.5) self.make_success_test("Float Default One", "1.0", "f64", 1.0) # Simple with type annotation self.make_success_test("Float f32 Simple", "3.14:f32", "f32", 3.14) self.make_success_test("Float f64 Simple", "2.718:f64", "f64", 2.718) def generate_format_tests(self): """Generate tests for different float formats.""" # Leading zeros self.make_success_test("Float Default Leading Zeros", "00042.5", "f64", 42.5) self.make_success_test("Float Default Leading Zero Decimal", "0.5", "f64", 0.5) # Trailing zeros self.make_success_test("Float Default Trailing Zeros", "3.1400", "f64", 3.14) # No leading digit self.make_success_test("Float Default No Leading Digit", ".5", "f64", 0.5) self.make_success_test("Float Default No Leading Digit Negative", "-.25", "f64", -0.25) # No trailing digits self.make_success_test("Float Default No Trailing Digits", "42.", "f64", 42.0) self.make_success_test("Float Default No Trailing Digits Negative", "-7.", "f64", -7.0) if self.ENABLE_EXPONENTIAL_LITERALS: # Scientific notation self.make_success_test("Float Default Scientific Positive Exp", "1.5e10", "f64", 1.5e10) self.make_success_test("Float Default Scientific Negative Exp", "2.5e-5", "f64", 2.5e-5) self.make_success_test("Float Default Scientific Capital E", "3.14E8", "f64", 3.14e8) self.make_success_test("Float Default Scientific Plus Sign", "1.0e+3", "f64", 1000.0) # Very small numbers self.make_success_test("Float Default Very Small", "0.000001", "f64", 0.000001) if self.ENABLE_EXPONENTIAL_LITERALS: self.make_success_test("Float Default Scientific Very Small", "1.0e-20", "f64", 1.0e-20) # Very large numbers self.make_success_test("Float Default Very Large", "1000000.0", "f64", 1000000.0) if self.ENABLE_EXPONENTIAL_LITERALS: self.make_success_test("Float Default Scientific Very Large", "1.0e20", "f64", 1.0e20) def generate_underscore_tests(self): """Generate tests for underscores in floats.""" # Underscores in integer part self.make_success_test("Float Default Underscore Integer Part", "1_000_000.5", "f64", 1000000.5) # Underscores in decimal part self.make_success_test("Float Default Underscore Decimal Part", "3.141_592_653", "f64", 3.141592653) # Underscores in both parts self.make_success_test("Float Default Underscore Both Parts", "1_234.567_89", "f64", 1234.56789) if self.ENABLE_EXPONENTIAL_LITERALS: # Underscores in scientific notation self.make_success_test("Float Default Underscore Scientific Mantissa", "1_000.5e10", "f64", 1000.5e10) self.make_success_test("Float Default Underscore Scientific Exponent", "1.5e1_0", "f64", 1.5e10) # Trailing underscore self.make_success_test("Float Default Underscore Trailing", "42.5_", "f64", 42.5) # Double underscore self.make_success_test("Float Default Underscore Double", "4__2.5", "f64", 42.5) # With type annotation self.make_success_test("Float f32 With Underscores", "1_234.567_89:f32", "f32", 1234.56789) def generate_special_value_tests(self): """Generate tests for special float values.""" # Infinity self.make_success_test("Float Default Positive Infinity", "inf", "f64", float('inf')) self.make_success_test("Float Default Negative Infinity", "-inf", "f64", float('-inf')) self.make_success_test("Float f32 Positive Infinity", "inf:f32", "f32", float('inf')) self.make_success_test("Float f32 Negative Infinity", "-inf:f32", "f32", float('-inf')) # NaN self.make_success_test("Float Default NaN", "nan", "f64", float('nan')) self.make_success_test("Float f32 NaN", "nan:f32", "f32", float('nan')) # Note: NaN comparison is special - NaN != NaN, so these tests may need # special handling in the test runner def generate_edge_case_tests(self, type_name: str): """Generate edge case tests for a specific float type.""" values = self.SPECIAL_VALUES[type_name] if self.ENABLE_EXPONENTIAL_LITERALS: # Maximum value self.make_success_test(f"Float {type_name} Max Value", f"{values['max']}:{type_name}", type_name, values['max']) # Minimum value (most negative) self.make_success_test(f"Float {type_name} Min Value", f"{values['min']}:{type_name}", type_name, values['min']) # Smallest positive normalized value self.make_success_test(f"Float {type_name} Min Positive", f"{values['min_positive']}:{type_name}", type_name, values['min_positive']) # Machine epsilon self.make_success_test(f"Float {type_name} Epsilon", f"{values['epsilon']}:{type_name}", type_name, values['epsilon']) # Near zero self.make_success_test(f"Float {type_name} Near Zero Positive", f"1e-30:{type_name}", type_name, 1e-30) self.make_success_test(f"Float {type_name} Near Zero Negative", f"-1e-30:{type_name}", type_name, -1e-30) # Subnormal numbers if type_name == 'f64': self.make_success_test("Float f64 Subnormal", "1e-320:f64", "f64", 1e-320) elif type_name == 'f32': self.make_success_test("Float f32 Subnormal", "1e-40:f32", "f32", 1e-40) def generate_overflow_tests(self): """Generate overflow tests.""" if self.ENABLE_EXPONENTIAL_LITERALS: # f32 overflow self.make_error_test("Float f32 Overflow Positive", "1e40:f32", "Float overflow: value exceeds range for f32.") self.make_error_test("Float f32 Overflow Negative", "-1e40:f32", "Float overflow: value exceeds range for f32.") # f64 overflow (extremely large values) self.make_error_test("Float f64 Overflow Positive", "1e310:f64", "Float overflow: value exceeds range for f64.") self.make_error_test("Float f64 Overflow Negative", "-1e310:f64", "Float overflow: value exceeds range for f64.") def generate_precision_tests(self): """Generate tests for precision limits.""" # f32 precision (~7 decimal digits) self.make_success_test("Float f32 Precision Limit", "1.2345678:f32", "f32", 1.2345678) self.make_success_test("Float f32 High Precision", "3.141592653589793:f32", "f32", 3.141592653589793) # f64 precision (~15 decimal digits) self.make_success_test("Float f64 Precision Limit", "1.234567890123456:f64", "f64", 1.234567890123456) self.make_success_test("Float f64 High Precision", "3.141592653589793238:f64", "f64", 3.141592653589793238) # Very close numbers self.make_success_test("Float f64 Close Numbers 1", "1.0000000000000001:f64", "f64", 1.0000000000000001) self.make_success_test("Float f64 Close Numbers 2", "1.0000000000000002:f64", "f64", 1.0000000000000002) def generate_error_tests(self): """Generate error tests.""" # Invalid formats self.make_error_test("Float Invalid Multiple Decimal Points", "3.14.159", "Invalid float literal: unexpected '.' in float.") self.make_error_test("Float Invalid Characters", "3.1a4", "Invalid float literal: unexpected 'a' in float.") if self.ENABLE_EXPONENTIAL_LITERALS: # Invalid scientific notation self.make_error_test("Float Invalid Scientific No Exponent", "3.14e", "Invalid float literal: missing exponent value.") self.make_error_test("Float Invalid Scientific Double E", "3.14e10e5", "Invalid float literal: unexpected 'e' in float.") self.make_error_test("Float Invalid Scientific Invalid Exponent", "3.14eX", "Invalid float literal: unexpected 'X' in float.") # Invalid type annotations self.make_error_test("Float Invalid Type Annotation", "3.14:i32", "Invalid float type: must be of type 'f64' or 'f32'.") self.make_error_test("Float Invalid Type Name", "3.14:f16", "Invalid float type: must be of type 'f64' or 'f32'.") # Comma separators not allowed self.make_error_test("Float Invalid Comma Separator", "1,234.56", "Invalid decimal literal: unexpected ',' in decimal integer.") def generate_whitespace_tests(self): """Generate tests with whitespace.""" self.make_success_test("Float Default Leading Whitespace", " 3.14", "f64", 3.14) self.make_success_test("Float Default Trailing Whitespace", "3.14 ", "f64", 3.14) self.make_success_test("Float Default Both Whitespace", " 3.14 ", "f64", 3.14) self.make_success_test("Float f32 With Whitespace", " 2.718:f32 ", "f32", 2.718) def generate_mathematical_constants_tests(self): """Generate tests for common mathematical constants.""" # Pi self.make_success_test("Float Default Pi Approximate", "3.141592653589793", "f64", 3.141592653589793) self.make_success_test("Float f32 Pi Approximate", "3.1415927:f32", "f32", 3.1415927) # Euler's number self.make_success_test("Float Default Euler Approximate", "2.718281828459045", "f64", 2.718281828459045) self.make_success_test("Float f32 Euler Approximate", "2.7182817:f32", "f32", 2.7182817) # Golden ratio self.make_success_test("Float Default Golden Ratio", "1.618033988749895", "f64", 1.618033988749895) # Square root of 2 self.make_success_test("Float Default Sqrt2", "1.4142135623730951", "f64", 1.4142135623730951) def generate_signed_zero_tests(self): """Generate tests for signed zeros.""" self.make_success_test("Float Default Positive Zero", "0.0", "f64", 0.0) self.make_success_test("Float Default Negative Zero", "-0.0", "f64", -0.0) self.make_success_test("Float f32 Positive Zero", "0.0:f32", "f32", 0.0) self.make_success_test("Float f32 Negative Zero", "-0.0:f32", "f32", -0.0) # Note: In IEEE 754, +0.0 and -0.0 are distinct values but compare equal def generate_all_tests(self) -> List[Dict[str, Any]]: """Generate all test cases.""" # Basic tests self.generate_basic_tests() # Format variations self.generate_format_tests() # Underscores self.generate_underscore_tests() # Special values (inf, nan) # self.generate_special_value_tests() # Edge cases for each type for type_name in ['f32', 'f64']: self.generate_edge_case_tests(type_name) # Overflow tests self.generate_overflow_tests() # Precision tests self.generate_precision_tests() # Error tests self.generate_error_tests() # Whitespace tests self.generate_whitespace_tests() # Mathematical constants self.generate_mathematical_constants_tests() # Signed zeros self.generate_signed_zero_tests() return self.tests