@@ -16,6 +16,66 @@ def test_create_scalar_simple():
1616 assert isinstance (QuadPrecision (1 ), QuadPrecision )
1717
1818
19+ @pytest .mark .parametrize ("int_val" , [
20+ # Very large integers that exceed long double range
21+ 2 ** 1024 ,
22+ 2 ** 2048 ,
23+ 10 ** 308 ,
24+ 10 ** 4000 ,
25+ # Edge cases
26+ 0 ,
27+ 1 ,
28+ - 1 ,
29+ # Negative large integers
30+ - (2 ** 1024 ),
31+ ])
32+ def test_create_scalar_from_large_int (int_val ):
33+ """Test that QuadPrecision can handle very large integers beyond long double range.
34+
35+ This test ensures that integers like 2**1024, which overflow standard long double,
36+ are properly converted via string representation to QuadPrecision without raising
37+ overflow errors. The conversion should match the string-based conversion.
38+ """
39+ # Convert large int to QuadPrecision
40+ result = QuadPrecision (int_val )
41+ assert isinstance (result , QuadPrecision )
42+
43+ # String conversion should give the same result
44+ str_val = str (int_val )
45+ result_from_str = QuadPrecision (str_val )
46+
47+ # Both conversions should produce the same value
48+ # (can be inf==inf on some platforms for very large values)
49+ assert result == result_from_str
50+
51+ # For zero and small values, verify exact conversion
52+ if int_val == 0 :
53+ assert float (result ) == 0.0
54+ elif abs (int_val ) == 1 :
55+ assert float (result ) == float (int_val )
56+
57+
58+ def test_create_scalar_from_int_with_broken_str ():
59+ """Test that QuadPrecision handles errors when __str__ fails on large integers.
60+
61+ This test checks the error handling path in scalar.c where PyObject_Str(py_int)
62+ returns NULL. We simulate this by subclassing int with a __str__ method
63+ that raises an exception.
64+ """
65+ class BrokenInt (int ):
66+ def __str__ (self ):
67+ raise RuntimeError ("Intentionally broken __str__ method" )
68+
69+ # Create an instance with a value that will overflow long long (> 2**63 - 1)
70+ # This triggers the string conversion path in quad_from_py_int
71+ broken_int = BrokenInt (2 ** 1024 )
72+
73+ # When PyLong_AsLongLongAndOverflow returns overflow,
74+ # it tries to convert to string, which should fail and propagate the error
75+ with pytest .raises (RuntimeError , match = "Intentionally broken __str__ method" ):
76+ QuadPrecision (broken_int )
77+
78+
1979class TestQuadPrecisionArrayCreation :
2080 """Test suite for QuadPrecision array creation from sequences and arrays."""
2181
@@ -248,6 +308,68 @@ def test_string_roundtrip():
248308 )
249309
250310
311+ def test_string_subclass_parsing ():
312+ """Test that QuadPrecision handles string subclasses correctly.
313+
314+ This tests the PyUnicode_Check path in scalar.c lines 195-209,
315+ verifying that string subclasses work and that parsing errors
316+ are properly handled.
317+ """
318+ class MyString (str ):
319+ """A custom string subclass"""
320+ pass
321+
322+ # Test valid string subclass - should parse correctly
323+ valid_str = MyString ("3.14159265358979323846" )
324+ result = QuadPrecision (valid_str )
325+ assert isinstance (result , QuadPrecision )
326+ expected = QuadPrecision ("3.14159265358979323846" )
327+ assert result == expected
328+
329+ # Test with scientific notation
330+ sci_str = MyString ("1.23e-100" )
331+ result = QuadPrecision (sci_str )
332+ assert isinstance (result , QuadPrecision )
333+
334+ # Test with negative value
335+ neg_str = MyString ("-42.5" )
336+ result = QuadPrecision (neg_str )
337+ assert float (result ) == - 42.5
338+
339+ # Test invalid string - should raise ValueError
340+ invalid_str = MyString ("not a number" )
341+ with pytest .raises (ValueError , match = "Unable to parse string to QuadPrecision" ):
342+ QuadPrecision (invalid_str )
343+
344+ # Test partially valid string (has trailing garbage)
345+ partial_str = MyString ("3.14abc" )
346+ with pytest .raises (ValueError , match = "Unable to parse string to QuadPrecision" ):
347+ QuadPrecision (partial_str )
348+
349+ # Test empty string
350+ empty_str = MyString ("" )
351+ with pytest .raises (ValueError , match = "Unable to parse string to QuadPrecision" ):
352+ QuadPrecision (empty_str )
353+
354+ # Test string with leading garbage
355+ leading_garbage = MyString ("abc3.14" )
356+ with pytest .raises (ValueError , match = "Unable to parse string to QuadPrecision" ):
357+ QuadPrecision (leading_garbage )
358+
359+ # Test special values
360+ inf_str = MyString ("inf" )
361+ result = QuadPrecision (inf_str )
362+ assert np .isinf (float (result ))
363+
364+ neg_inf_str = MyString ("-inf" )
365+ result = QuadPrecision (neg_inf_str )
366+ assert np .isinf (float (result )) and float (result ) < 0
367+
368+ nan_str = MyString ("nan" )
369+ result = QuadPrecision (nan_str )
370+ assert np .isnan (float (result ))
371+
372+
251373@pytest .mark .parametrize ("name,expected" , [("pi" , np .pi ), ("e" , np .e ), ("log2e" , np .log2 (np .e )), ("log10e" , np .log10 (np .e )), ("ln2" , np .log (2.0 )), ("ln10" , np .log (10.0 ))])
252374def test_math_constant (name , expected ):
253375 assert isinstance (getattr (numpy_quaddtype , name ), QuadPrecision )
0 commit comments