def test_no_differences(self): seq = [1, 2] diff_obj = diff_sequence(seq, seq) diffs = [ DiffItem(unchanged, 1, (0, 1, 0, 1)), DiffItem(unchanged, 2, (1, 2, 1, 2))] expected_diff = Diff(list, diffs) self.assertEqual(diff_obj, expected_diff) self.assertEqual(patch(seq, diff_obj), seq)
def test_context_blocks_provides_slices(self): seq1 = 'um hello there' seq2 = 'yo, I mean hello' diff_obj = diff_sequence(seq1, seq2) cb_1 = diff_obj.context_blocks[0] cb_2 = diff_obj.context_blocks[1] s1_start, s1_end, s2_start, s2_end = cb_1.context self.assertEqual(seq1[s1_start:s1_end], 'um') self.assertEqual(seq2[s2_start:s2_end], 'yo, I mean') s1_start, s1_end, s2_start, s2_end = cb_2.context self.assertEqual(seq1[s1_start:s1_end], ' there') self.assertEqual(seq2[s2_start:s2_end], '')
def test_dont_try_recursive_diff_if_sequences_are_different_lengths(self): seq1 = (1, 'ab', 2, 3) seq2 = (1, 'bc', 2) diff_obj = diff_sequence(seq1, seq2) diffs = [ DiffItem(unchanged, 1, (0, 1, 0, 1)), DiffItem(remove, 'ab', (1, 2, 1, 1)), DiffItem(insert, 'bc', (2, 2, 1, 2)), DiffItem(unchanged, 2, (2, 3, 2, 3)), DiffItem(remove, 3, (3, 4, 3, 3))] expected_diff = Diff(tuple, diffs) expected_diff.context_blocks = [ expected_diff.ContextBlock(tuple, diffs[1:])] self.assertEqual(diff_obj, expected_diff) self.assertEqual(patch(seq1, diff_obj), seq2)
def test_context_limit_is_adjustable(self): seq1 = [2, 3, 4] seq2 = [1, 3, 5] diff_obj = diff_sequence(seq1, seq2, context_limit=0) diffs = [ DiffItem(remove, 2, (0, 1, 0, 0)), DiffItem(insert, 1, (1, 1, 0, 1)), DiffItem(unchanged, 3, (1, 2, 1, 2)), DiffItem(remove, 4, (2, 3, 2, 2)), DiffItem(insert, 5, (3, 3, 2, 3))] expected_diff = Diff(list, diffs, context_limit=0) expected_diff.context_blocks = [ expected_diff.ContextBlock(list, diffs[0:2]), expected_diff.ContextBlock(list, diffs[3:5])] self.assertEqual(diff_obj, expected_diff) self.assertEqual(patch(seq1, diff_obj), seq2)
def test_no_recursion_removal_and_insert_not_same_type(self): '''seq1[1] and seq2[1] would be subject to a recursive diff if they were the same type''' seq1 = [1, (1, 2), 3] seq2 = [1, [1, 2], 3] diff_obj = diff_sequence(seq1, seq2) diffs = [ DiffItem(unchanged, 1, (0, 1, 0, 1)), DiffItem(remove, (1, 2), (1, 2, 1, 1)), DiffItem(insert, [1, 2], (2, 2, 1, 2)), DiffItem(unchanged, 3, (2, 3, 2, 3))] expected_diff = Diff(list, diffs) expected_diff.context_blocks = [ expected_diff.ContextBlock(list, diffs[1:3])] self.assertEqual(diff_obj, expected_diff) self.assertEqual(patch(seq1, diff_obj), seq2)
def test_no_recursion_item_not_diffable(self): '''seq1[1] and seq2[2] would be subject to a recursive diff if they were diffable''' seq1 = [1, 2, 5] seq2 = [1, 3, 5] diff_obj = diff_sequence(seq1, seq2) diffs = [ DiffItem(unchanged, 1, (0, 1, 0, 1)), DiffItem(remove, 2, (1, 2, 1, 1)), DiffItem(insert, 3, (2, 2, 1, 2)), DiffItem(unchanged, 5, (2, 3, 2, 3))] expected_diff = Diff(list, diffs) expected_diff.context_blocks = [ expected_diff.ContextBlock(list, diffs[1:3])] self.assertEqual(diff_obj, expected_diff) self.assertEqual(patch(seq1, diff_obj), seq2)
def test_no_recursion_insert_remove_counts_not_equal_1(self): # nested_diff_input is None seq1 = [1, (1, 2), 0] seq2 = [1, (2, 3), 2] diff_obj = diff_sequence(seq1, seq2) diffs = [ DiffItem(unchanged, 1, (0, 1, 0, 1)), DiffItem(remove, (1, 2), (1, 2, 1, 1)), DiffItem(remove, 0, (2, 3, 1, 1)), DiffItem(insert, (2, 3), (3, 3, 1, 2)), DiffItem(insert, 2, (3, 3, 2, 3))] expected_diff = Diff(list, diffs) expected_diff.context_blocks = [ expected_diff.ContextBlock(list, diffs[1:])] self.assertEqual(diff_obj, expected_diff) self.assertEqual(patch(seq1, diff_obj), seq2)
def test_mainly_inserts(self): seq1 = 'hi' seq2 = 'hello' diff_obj = diff_sequence(seq1, seq2) diffs = [ DiffItem(unchanged, 'h', (0, 1, 0, 1)), DiffItem(remove, 'i', (1, 2, 1, 1)), DiffItem(insert, 'e', (2, 2, 1, 2)), DiffItem(insert, 'l', (2, 2, 2, 3)), DiffItem(insert, 'l', (2, 2, 3, 4)), DiffItem(insert, 'o', (2, 2, 4, 5))] expected_diff = Diff(str, diffs) expected_diff.context_blocks = [ expected_diff.ContextBlock(str, diffs[1:])] self.assertEqual(diff_obj, expected_diff) self.assertEqual(patch(seq1, diff_obj), seq2)
def test_single_char_edgecase_in_str(self): # there should be no attempt at recursively diffing the final characters # ie the diff should be flat. seq1 = 'abc' seq2 = 'abd' diff_obj = diff_sequence(seq1, seq2) diffs = [ DiffItem(unchanged, 'a', (0, 1, 0, 1)), DiffItem(unchanged, 'b', (1, 2, 1, 2)), DiffItem(remove, 'c', (2, 3, 2, 2)), DiffItem(insert, 'd', (3, 3, 2, 3)) ] expected_diff = Diff(str, diffs) expected_diff.context_blocks = [ expected_diff.ContextBlock(str, diffs[2:4]) ] self.assertEqual(diff_obj, expected_diff) self.assertEqual(patch(seq1, diff_obj), seq2)
def test_recursive_diff_before_first_unchanged_item(self): seq1 = [[1], 2] seq2 = [[0], 2] diff_obj = diff_sequence(seq1, seq2) nested_diffs = [ DiffItem(remove, 1, (0, 1, 0, 0)), DiffItem(insert, 0, (1, 1, 0, 1)) ] nested_diff = Diff(list, nested_diffs, depth=1) nested_diff.context_blocks = [ nested_diff.ContextBlock(list, nested_diffs, depth=1)] diffs = [ DiffItem(changed, nested_diff, (0, 1, 0, 1)), DiffItem(unchanged, 2, (1, 2, 1, 2))] expected_diff = Diff(list, diffs) expected_diff.context_blocks = [ expected_diff.ContextBlock(list, [diffs[0]])] self.assertEqual(diff_obj, expected_diff) self.assertEqual(patch(seq1, diff_obj), seq2)
def test_mainly_unchanged(self): seq1 = (1, 2, 3, 4, 5, 6, 7) seq2 = (0, 1, 2, 0, 4, 5, 6) diff_obj = diff_sequence(seq1, seq2) diffs = [ DiffItem(insert, 0, (0, 0, 0, 1)), DiffItem(unchanged, 1, (0, 1, 1, 2)), DiffItem(unchanged, 2, (1, 2, 2, 3)), DiffItem(remove, 3, (2, 3, 3, 3)), DiffItem(insert, 0, (3, 3, 3, 4)), DiffItem(unchanged, 4, (3, 4, 4, 5)), DiffItem(unchanged, 5, (4, 5, 5, 6)), DiffItem(unchanged, 6, (5, 6, 6, 7)), DiffItem(remove, 7, (6, 7, 7, 7))] expected_diff = Diff(tuple, diffs) expected_diff.context_blocks = [ expected_diff.ContextBlock(tuple, diffs)] self.assertEqual(diff_obj, expected_diff) self.assertEqual(patch(seq1, diff_obj), seq2)
def test_successful_recursive_diff(self): # _nested_diff_input matches (unchanged, insert, remove) seq1 = (1, 'ab', 2) seq2 = (1, 'bc', 2) diff_obj = diff_sequence(seq1, seq2) nested_diffs = [ DiffItem(remove, 'a', (0, 1, 0, 0)), DiffItem(unchanged, 'b', (1, 2, 0, 1)), DiffItem(insert, 'c', (2, 2, 1, 2))] nested_diff = Diff(str, nested_diffs, depth=1) nested_diff.context_blocks = [ nested_diff.ContextBlock(str, nested_diffs, depth=1)] diffs = [ DiffItem(unchanged, 1, (0, 1, 0, 1)), DiffItem(changed, nested_diff, (1, 2, 1, 2)), DiffItem(unchanged, 2, (2, 3, 2, 3))] expected_diff = Diff(tuple, diffs) expected_diff.context_blocks = [ expected_diff.ContextBlock(tuple, [diffs[1]])] self.assertEqual(diff_obj, expected_diff) self.assertEqual(patch(seq1, diff_obj), seq2)
def test_single_char_edgecase_in_list(self): seq1 = [1, 2, 'a'] seq2 = [1, 2, 'b'] diff_obj = diff_sequence(seq1, seq2) nested_diffs = [ DiffItem(remove, 'a', (0, 1, 0, 0)), DiffItem(insert, 'b', (1, 1, 0, 1)) ] nested_diff = Diff(str, nested_diffs, depth=1) nested_diff.context_blocks = [ nested_diff.ContextBlock(str, nested_diffs, depth=1) ] diffs = [ DiffItem(unchanged, 1, (0, 1, 0, 1)), DiffItem(unchanged, 2, (1, 2, 1, 2)), DiffItem(changed, nested_diff, (2, 3, 2, 3)), ] expected_diff = Diff(list, diffs) expected_diff.context_blocks = [ expected_diff.ContextBlock(list, diffs[2:]) ] self.assertEqual(diff_obj, expected_diff) self.assertEqual(patch(seq1, diff_obj), seq2)
def test_depth_is_adjustable(self): diff_obj = diff_sequence([1, 2], [1, 2], depth=4) self.assertEqual(diff_obj.depth, 4)
def test_empty_diff(self): seq = [] diff_obj = diff_sequence(seq, seq) expected_diff = Diff(list, seq) self.assertEqual(diff_obj, expected_diff) self.assertEqual(patch(seq, diff_obj), seq)