Skip to content

Commit 27555fb

Browse files
committed
adding edge tests
1 parent 49534b4 commit 27555fb

File tree

1 file changed

+83
-0
lines changed

1 file changed

+83
-0
lines changed

quaddtype/tests/test_quaddtype.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,27 @@ def test_create_scalar_from_large_int(int_val):
5555
assert float(result) == float(int_val)
5656

5757

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+
5879
class TestQuadPrecisionArrayCreation:
5980
"""Test suite for QuadPrecision array creation from sequences and arrays."""
6081

@@ -287,6 +308,68 @@ def test_string_roundtrip():
287308
)
288309

289310

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+
290373
@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))])
291374
def test_math_constant(name, expected):
292375
assert isinstance(getattr(numpy_quaddtype, name), QuadPrecision)

0 commit comments

Comments
 (0)