Skip to content

Commit 5afe1ad

Browse files
committed
improve test assertions
1 parent a3fc3b3 commit 5afe1ad

File tree

1 file changed

+35
-13
lines changed

1 file changed

+35
-13
lines changed

Lib/test/test_pyexpat.py

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -847,44 +847,67 @@ def exponential_expansion_payload(self, ncols, nrows, text='.'):
847847
<doc>&row{nrows};</doc>
848848
"""
849849

850+
# With the default Expat configuration, the billion laughs protection may
851+
# hit before the allocation limiter if exponential_expansion_payload() is
852+
# not carefully parametrized. In particular, use the following assert_*()
853+
# methods to check the error message of the active protection.
854+
855+
def assert_root_parser_failure(self, func, /, *args, **kwargs):
856+
"""Check that func(*args, **kwargs) is invalid for a sub-parser."""
857+
msg = "parser must be a root parser"
858+
self.assertRaisesRegex(expat.ExpatError, msg, func, *args, **kwargs)
859+
860+
def assert_alloc_limit_reached(self, func, /, *args, **kwargs):
861+
"""Check that fnuc(*args, **kwargs) hits the allocation limit."""
862+
msg = r"out of memory: line \d+, column \d+"
863+
self.assertRaisesRegex(expat.ExpatError, msg, func, *args, **kwargs)
864+
850865
def test_set_alloc_tracker_maximum_amplification(self):
851866
# On WASI, the maximum amplification factor of the payload may differ,
852867
# so we craft a payload that is likely to yield an amplification factor
853-
# way larger than 1.0 and way smaller than 10^5.
868+
# way larger than 1.0 and way smaller than 10^4.
854869
payload = self.exponential_expansion_payload(1, 2)
855870

856871
p = expat.ParserCreate()
857872
# Unconditionally enable maximum amplification factor.
858873
p.SetAllocTrackerActivationThreshold(0)
859874
# Use a max amplification factor likely to be below the real one.
860875
self.assertIsNone(p.SetAllocTrackerMaximumAmplification(1.0))
861-
msg = r"out of memory: line \d+, column \d+"
862-
self.assertRaisesRegex(expat.ExpatError, msg, p.Parse, payload, True)
876+
self.assert_alloc_limit_reached(p.Parse, payload, True)
863877

864878
# Re-create a parser as the current parser is now in an error state.
865879
p = expat.ParserCreate()
866880
# Unconditionally enable maximum amplification factor.
867881
p.SetAllocTrackerActivationThreshold(0)
882+
# Use a max amplification factor likely to be above the real one.
868883
self.assertIsNone(p.SetAllocTrackerMaximumAmplification(10_000))
869884
self.assertIsNotNone(p.Parse(payload, True))
870885

871886
def test_set_alloc_tracker_maximum_amplification_infinity(self):
872-
inf = float('inf') # an 'inf' threshold is allowed
887+
inf = float('inf') # an 'inf' threshold is allowed by Expat
873888
parser = expat.ParserCreate()
874889
self.assertIsNone(parser.SetAllocTrackerMaximumAmplification(inf))
875890

876-
def test_set_alloc_tracker_maximum_amplification_fail_for_subparser(self):
891+
def test_set_alloc_tracker_maximum_amplification_arg_invalid_type(self):
892+
parser = expat.ParserCreate()
893+
f = parser.SetAllocTrackerMaximumAmplification
894+
895+
self.assertRaises(TypeError, f, None)
896+
self.assertRaises(TypeError, f, 'abc')
897+
898+
def test_set_alloc_tracker_maximum_amplification_arg_invalid_range(self):
877899
parser = expat.ParserCreate()
878900
f = parser.SetAllocTrackerMaximumAmplification
879901

880902
msg = re.escape("'max_factor' must be at least 1.0")
881903
self.assertRaisesRegex(expat.ExpatError, msg, f, float('nan'))
882904
self.assertRaisesRegex(expat.ExpatError, msg, f, 0.99)
883905

906+
def test_set_alloc_tracker_maximum_amplification_fail_for_subparser(self):
907+
parser = expat.ParserCreate()
884908
subparser = parser.ExternalEntityParserCreate(None)
885909
fsub = subparser.SetAllocTrackerMaximumAmplification
886-
msg = "parser must be a root parser"
887-
self.assertRaisesRegex(expat.ExpatError, msg, fsub, 1.0)
910+
self.assert_root_parser_failure(fsub, 123.45)
888911

889912
def test_set_alloc_tracker_activation_threshold(self):
890913
# The payload is expected to have a peak allocation of
@@ -901,17 +924,17 @@ def test_set_alloc_tracker_activation_threshold(self):
901924
p.SetAllocTrackerActivationThreshold(2)
902925
# Check that we always reach the activation threshold.
903926
self.assertIsNone(p.SetAllocTrackerMaximumAmplification(1.0))
904-
msg = r"out of memory: line \d+, column \d+"
905-
self.assertRaisesRegex(expat.ExpatError, msg, p.Parse, payload, True)
927+
self.assert_alloc_limit_reached(p.Parse, payload, True)
906928

907-
def test_set_alloc_tracker_activation_threshold_arg_invalid(self):
929+
def test_set_alloc_tracker_activation_threshold_arg_invalid_type(self):
908930
parser = expat.ParserCreate()
909931
f = parser.SetAllocTrackerActivationThreshold
932+
910933
self.assertRaises(TypeError, f, 1.0)
911934
self.assertRaises(TypeError, f, -1.5)
912935
self.assertRaises(ValueError, f, -5)
913936

914-
def test_set_alloc_tracker_activation_threshold_arg_overflow(self):
937+
def test_set_alloc_tracker_activation_threshold_arg_invalid_range(self):
915938
_testcapi = import_helper.import_module("_testcapi")
916939
parser = expat.ParserCreate()
917940
f = parser.SetAllocTrackerActivationThreshold
@@ -921,8 +944,7 @@ def test_set_alloc_tracker_activation_threshold_fail_for_subparser(self):
921944
parser = expat.ParserCreate()
922945
subparser = parser.ExternalEntityParserCreate(None)
923946
fsub = subparser.SetAllocTrackerActivationThreshold
924-
msg = "parser must be a root parser"
925-
self.assertRaisesRegex(expat.ExpatError, msg, fsub, 12345)
947+
self.assert_root_parser_failure(fsub, 12345)
926948

927949

928950
if __name__ == "__main__":

0 commit comments

Comments
 (0)