YREA-SLS/SLS_Tests/generate_tests/float_tests.py

315 lines
14 KiB
Python

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)
# 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)
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)
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)
# 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]
# 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."""
# 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 No Decimal Point",
"42",
"Not a valid float literal: missing decimal point.")
self.make_error_test("Float Invalid Multiple Decimal Points",
"3.14.159",
"Invalid float literal: multiple decimal points.")
self.make_error_test("Float Invalid Only Decimal Point",
".",
"Invalid float literal: no digits before or after decimal point.")
self.make_error_test("Float Invalid Characters",
"3.1a4",
"Invalid float literal: unexpected 'a' in float.")
# 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: multiple exponent markers.")
self.make_error_test("Float Invalid Scientific Invalid Exponent",
"3.14eX",
"Invalid float literal: invalid exponent 'X'.")
# Invalid underscores
self.make_error_test("Float Invalid Leading Underscore",
"_3.14",
"Invalid float literal: leading underscore.")
self.make_error_test("Float Invalid Underscore Before Decimal",
"3_.14",
"Invalid float literal: underscore before decimal point.")
self.make_error_test("Float Invalid Underscore After Decimal",
"3._14",
"Invalid float literal: underscore after decimal point.")
# Invalid type annotations
self.make_error_test("Float Invalid Type Annotation",
"3.14:i32",
"Type mismatch: float literal cannot be annotated as integer type.")
self.make_error_test("Float Invalid Type Name",
"3.14:f16",
"Invalid type annotation: unknown type 'f16'.")
# Comma separators not allowed
self.make_error_test("Float Invalid Comma Separator",
"1,234.56",
"Invalid float literal: unexpected ',' in float.")
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