Skip to content

Commit 0b3d72e

Browse files
committed
worst case complexity tests
1 parent 29007aa commit 0b3d72e

File tree

1 file changed

+42
-0
lines changed

1 file changed

+42
-0
lines changed

Lib/test/test_difflib.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,48 @@ def test_cross_test_with_autojunk_false(self):
707707
self.assertEqual(blocks1, blocks2)
708708
self.assertAlmostEqual(sm1.ratio(), sm2.ratio(), places=3)
709709

710+
def test_issue_132166(self):
711+
N = 1_000
712+
713+
# 2 sequences of 74K (as in the issue) now take 200ms to run
714+
seq1 = ' [' + '10, ' * N
715+
seq2 = seq1[1:]
716+
isjunk = difflib.IS_CHARACTER_JUNK
717+
sm = difflib.ExactSequenceMatcher(isjunk, seq1, seq2)
718+
blocks = list(sm.get_matching_blocks())
719+
self.assertEqual(list(map(tuple, blocks)), [(1, 0, 4001), (4002, 4001, 0)])
720+
721+
def test_pathological(self):
722+
N = 1_000
723+
724+
# This was taking seconds to run before 1st iteration
725+
chars = ['ab'[i % 2] * (1 + bool(i % 3)) for i in range(N)]
726+
seq1, seq2 = ('+'.join(chars), '-'.join(chars)[::-1])
727+
sm = difflib.ExactSequenceMatcher(None, seq1, seq2)
728+
blocks = list(sm.get_matching_blocks())
729+
self.assertEqual(list(map(tuple, blocks[:3])), [(0, 2, 1), (2, 5, 2), (5, 13, 2)])
730+
731+
# This was taking seconds to run before 2nd iteration
732+
chars1 = [chr(i) * 2 + '+' + chr(i + 1) * 2 for i in range(0, N, 2)]
733+
chars2 = [chr(i + 1) * 2 + '-' + chr(i) * 2 for i in range(0, N, 2)]
734+
seq1, seq2 = ('+'.join(chars1), '-'.join(chars2))
735+
sm = difflib.ExactSequenceMatcher(None, seq1, seq2)
736+
blocks = list(sm.get_matching_blocks())
737+
self.assertEqual(list(map(tuple, blocks[:3])), [(0, 3, 2), (6, 9, 2), (12, 15, 2)])
738+
739+
# This is theoretical current worst case of O(n √n)
740+
chars3 = []
741+
i = 0
742+
s = 0
743+
while s < N:
744+
chars3.append(chr(i) * i)
745+
s += i
746+
i += 1
747+
seq1, seq2 = ('+'.join(chars3), '-'.join(chars3))
748+
sm = difflib.ExactSequenceMatcher(None, seq1, seq2)
749+
blocks = list(sm.get_matching_blocks())
750+
self.assertEqual(list(map(tuple, blocks[:3])), [(1, 1, 1), (3, 3, 2), (6, 6, 3)])
751+
710752

711753
def setUpModule():
712754
difflib.HtmlDiff._default_prefix = 0

0 commit comments

Comments
 (0)