예제 #1
0
 def test_recursive_diff_when_different_lengths(self):
     '''
     Unlike Sequences, we should still attempt recursive diffs when the
     Ordered Mappings are different sizes.
     '''
     d1 = OrderedDict(
         sorted({'a': 1, 'b': [2]}.items(), key=lambda i: i[0]))
     d2 = OrderedDict(
         sorted({'a': 1, 'b': [3], 'c': 4}.items(), key=lambda i: i[0]))
     diff_obj = diff_ordered_mapping(d1, d2)
     nested_diffs = [
         DiffItem(remove, 2, (0, 1, 0, 0)),
         DiffItem(insert, 3, (1, 1, 0, 1))
     ]
     nested_diff_obj = Diff(list, nested_diffs, depth=1)
     nested_diff_obj.context_blocks = [
         nested_diff_obj.ContextBlock(list, nested_diffs, depth=1)
     ]
     diffs = [
         MappingDiffItem(unchanged, 'a', unchanged, 1),
         MappingDiffItem(
             unchanged, 'b', changed, nested_diff_obj),
         MappingDiffItem(insert, 'c', insert, 4)
     ]
     expected_diff = Diff(OrderedDict, diffs)
     expected_diff.context_blocks = [
         expected_diff.ContextBlock(OrderedDict, diffs[1:])
     ]
     self.assertEqual(diff_obj, expected_diff)
     self.assertEqual(patch(d1, diff_obj), d2)
예제 #2
0
 def test_common_keys_diff_order_matters_1(self):
     '''
     There are two possible lcs's for the keys here. ('a', 'b') and
     ('a', 'c') the lcs algorithm picks only one of them (('a', 'b') in this
     case). We therefore get a recursive diff at key 'b'. and an insert and
     remove on key 'c'. If this were a standard Mapping type key 'c' would
     be unchanged.
     '''
     d1 = OrderedDict(sorted(
         {'a': 1, 'b': 'a', 'c': 3}.items(), key=lambda i: i[0]))
     d2 = OrderedDict(sorted({'a': 1, 'c': 3}.items(), key=lambda i: i[0]))
     d2['b'] = 'b'
     diff_obj = diff_ordered_mapping(d1, d2)
     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 = [
         MappingDiffItem(unchanged, 'a', unchanged, 1),
         MappingDiffItem(insert, 'c', insert, 3),
         MappingDiffItem(
             unchanged, 'b', changed, nested_diff),
         MappingDiffItem(remove, 'c', remove, 3)
     ]
     expected_diff = Diff(OrderedDict, diffs)
     expected_diff.context_blocks = [
         expected_diff.ContextBlock(OrderedDict, diffs[1:])
     ]
     self.assertEqual(diff_obj, expected_diff)
     self.assertEqual(patch(d1, diff_obj), d2)
예제 #3
0
 def test_context_not_finished_by_end_of_diffs_list(self):
     diffs = [
         DiffItem(insert, 1),
         DiffItem(unchanged, 0)]
     diff_obj = Diff(list, diffs, context_limit=2)
     self.assertEqual(
         diff_obj._create_context_markers(), [(0, 1)])
예제 #4
0
 def test_contexts_start_and_end_with_modified_items(self):
     # this constraint could change; people may want more context...
     diffs = [
         DiffItem(unchanged, 1),
         DiffItem(insert, 2),
         DiffItem(insert, 2),
         DiffItem(unchanged, 1)]
     diff_obj = Diff(list, diffs)
     self.assertEqual(
         diff_obj._create_context_markers(), [(1, 3)])
예제 #5
0
 def test_context_limit_is_adjustable(self):
     '''The default context limit is 3, if we adjust it to 1 we expect a new
        new context to be started if there is a gap of 2'''
     diffs = [
         DiffItem(insert, 1),
         DiffItem(unchanged, 0),
         DiffItem(unchanged, 0),
         DiffItem(remove, 1)]
     diff_obj = Diff(list, diffs, context_limit=1)
     self.assertEqual(
         diff_obj._create_context_markers(), [(0, 1), (3, 4)])
예제 #6
0
 def setUp(self):
     diffs = [
         DiffItem(insert, 1),
         DiffItem(unchanged, 2),
         DiffItem(unchanged, 2),
         DiffItem(remove, 3)
     ]
     self.base_diff = Diff(list, diffs, context_limit=1, depth=0)
     self.base_diff.create_context_blocks()
     self.expected_diff = Diff(list, diffs, context_limit=1, depth=0)
     self.expected_diff.create_context_blocks()
예제 #7
0
 def test_common_keys_values_not_diffable(self):
     map1 = {'a': 1}
     map2 = {'a': 2}
     diff_obj = diff_mapping(map1, map2)
     diffs = [
         MappingDiffItem(unchanged, 'a', remove, 1),
         MappingDiffItem(unchanged, 'a', insert, 2)]
     expected_diff = Diff(dict, diffs)
     expected_diff.context_blocks = [
         expected_diff.ContextBlock(dict, diffs)]
     self.assertEqual(diff_obj, expected_diff)
     self.assertEqual(patch(map1, diff_obj), map2)
예제 #8
0
 def test_common_keys_values_different_types(self):
     map1 = {'a': (1, 2)}
     map2 = {'a': '1, 2'}
     diff_obj = diff_mapping(map1, map2)
     diffs = [
         MappingDiffItem(unchanged, 'a', remove, (1, 2)),
         MappingDiffItem(unchanged, 'a', insert, '1, 2')]
     expected_diff = Diff(dict, diffs)
     expected_diff.context_blocks = [
         expected_diff.ContextBlock(dict, diffs)]
     self.assertEqual(diff_obj, expected_diff)
     self.assertEqual(patch(map1, diff_obj), map2)
예제 #9
0
 def test_context_limit_max(self):
     '''Once a context is started,so long as the number of contiguous
        unchanged items doesn't exceed the context limit, they remain part of
        the context'''
     diffs = [
         DiffItem(insert, 1),
         DiffItem(unchanged, 0),
         DiffItem(unchanged, 0),
         DiffItem(remove, 1)]
     diff_obj = Diff(list, diffs, context_limit=2)
     self.assertEqual(
         diff_obj._create_context_markers(), [(0, 4)])
예제 #10
0
 def test_context_block_generation(self):
     diffs = [
         DiffItem(insert, 1),
         DiffItem(unchanged, 0),
         DiffItem(unchanged, 0),
         DiffItem(remove, 1)]
     expected = [
         Diff.ContextBlock(list, [diffs[0]]),
         Diff.ContextBlock(list, [diffs[3]])]
     diff_obj = Diff(list, diffs, context_limit=1)
     diff_obj.create_context_blocks()
     self.assertEqual(
         diff_obj.context_blocks, expected)
예제 #11
0
 def test_context_limit_max_plus_one(self):
     '''Once a context is started if the number of contiguous unchanged items
        exceeds the context limit the context is cut off at the last modified
        item and a new context is started'''
     diffs = [
         DiffItem(insert, 1),
         DiffItem(unchanged, 0),
         DiffItem(unchanged, 0),
         DiffItem(unchanged, 0),
         DiffItem(remove, 1)]
     diff_obj = Diff(list, diffs, context_limit=2)
     self.assertEqual(
         diff_obj._create_context_markers(), [(0, 1), (4, 5)])
예제 #12
0
 def test_single_char_edge_case(self):
     d1 = 'a'
     d2 = 'b'
     diff_obj = diff(d1, d2)
     diffs = [
         DiffItem(remove, 'a', (0, 1, 0, 0)),
         DiffItem(insert, 'b', (1, 1, 0, 1)),
     ]
     expected_diff = Diff(str, diffs)
     expected_diff.context_blocks = [
         expected_diff.ContextBlock(str, diffs)
     ]
     self.assertEqual(diff_obj, expected_diff)
     self.assertEqual(patch(d1, diff_obj), d2)
예제 #13
0
 def test_mostly_inserts(self):
     map1 = {'c': 3}
     map2 = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
     diff_obj = diff_mapping(map1, map2)
     diffs = [
         MappingDiffItem(unchanged, 'c', unchanged, 3),
         MappingDiffItem(insert, 'a', insert, 1),
         MappingDiffItem(insert, 'b', insert, 2),
         MappingDiffItem(insert, 'd', insert, 4)]
     expected_diff = Diff(dict, diffs)
     expected_diff.context_blocks = [
         expected_diff.ContextBlock(dict, diffs[1:])]
     self.assertEqual(diff_obj, expected_diff)
     self.assertEqual(patch(map1, diff_obj), map2)
예제 #14
0
 def test_can_diff_set_type(self):
     fs1 = frozenset([1, 2, 3])
     fs2 = frozenset([2, 3, 4])
     diff_obj = diff(fs1, fs2)
     diffs = [
         DiffItem(remove, 1),
         DiffItem(unchanged, 2),
         DiffItem(unchanged, 3),
         DiffItem(insert, 4)]
     expected_diff = Diff(frozenset, diffs)
     expected_diff.context_blocks = [
         expected_diff.ContextBlock(frozenset, diffs)]
     self.assertEqual(diff_obj, expected_diff)
     self.assertEqual(patch(fs1, diff_obj), fs2)
예제 #15
0
 def test_mostly_insertions(self):
     set1 = {4}
     set2 = {1, 2, 3, 4}
     diff_obj = diff_set(set1, set2)
     diffs = [
         DiffItem(unchanged, 4),
         DiffItem(insert, 1),
         DiffItem(insert, 2),
         DiffItem(insert, 3)]
     expected_diff = Diff(set, diffs)
     expected_diff.context_blocks = [
         expected_diff.ContextBlock(set, diffs[1:])]
     self.assertEqual(diff_obj, expected_diff)
     self.assertEqual(patch(set1, diff_obj), set2)
예제 #16
0
 def test_can_diff_sequence_type(self):
     ThreeDPoint = namedtuple('ThreeDPoint', ['x', 'y', 'z'])
     p1 = ThreeDPoint(0, 0, 0)
     p2 = ThreeDPoint(0, 0, 1)
     diff_obj = diff(p1, p2)
     diffs = [
         DiffItem(unchanged, 0, (0, 1, 0, 1)),
         DiffItem(unchanged, 0, (1, 2, 1, 2)),
         DiffItem(remove, 0, (2, 3, 2, 2)),
         DiffItem(insert, 1, (3, 3, 2, 3))]
     expected_diff = Diff(type(p1), diffs)
     expected_diff.context_blocks = [
         expected_diff.ContextBlock(type(p1), diffs[2:])]
     self.assertEqual(diff_obj, expected_diff)
     self.assertEqual(patch(p1, diff_obj), p2)
예제 #17
0
 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)
예제 #18
0
 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)
예제 #19
0
 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)
예제 #20
0
 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)
예제 #21
0
 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)
예제 #22
0
 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)
예제 #23
0
 def test_can_diff_mapping_type(self):
     d1 = {'d': 1, 'c': 2, 'b': 3}
     d2 = {'d': 1, 'c': 2, 'a': 3}
     # sort by values
     od1 = OrderedDict(sorted(d1.items(), key=lambda i: i[1]))
     od2 = OrderedDict(sorted(d2.items(), key=lambda i: i[1]))
     diff_obj = diff(od1, od2)
     diffs = [
         MappingDiffItem(unchanged, 'd', unchanged, 1),
         MappingDiffItem(unchanged, 'c', unchanged, 2),
         MappingDiffItem(remove, 'b', remove, 3),
         MappingDiffItem(insert, 'a', insert, 3)]
     expected_diff = Diff(OrderedDict, diffs)
     expected_diff.context_blocks = [
         expected_diff.ContextBlock(OrderedDict, diffs[2:])]
     self.assertEqual(diff_obj, expected_diff)
     self.assertEqual(patch(od1, diff_obj), od2)
예제 #24
0
 def test_context_limit_is_adjustable(self):
     map1 = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
     map2 = {'a': 2, 'b': 2, 'c': 3, 'e': 4}
     diff_obj = diff(map1, map2, context_limit=1)
     diffs = [
         MappingDiffItem(remove, 'd', remove, 4),
         MappingDiffItem(unchanged, 'a', remove, 1),
         MappingDiffItem(unchanged, 'a', insert, 2),
         MappingDiffItem(unchanged, 'c', unchanged, 3),
         MappingDiffItem(unchanged, 'b', unchanged, 2),
         MappingDiffItem(insert, 'e', insert, 4)]
     expected_diff = Diff(dict, diffs, context_limit=1)
     expected_diff.context_blocks = [
         expected_diff.ContextBlock(dict, diffs[0:3]),
         expected_diff.ContextBlock(dict, diffs[5:])]
     self.assertEqual(diff_obj, expected_diff)
     self.assertEqual(patch(map1, diff_obj), map2)
예제 #25
0
 def test_common_keys_values_different_types(self):
     d1 = {'a': 1, 'b': ['a'], 'c': 3}
     d2 = {'a': 1, 'b': 'a', 'c': 3}
     od1 = OrderedDict(sorted(d1.items(), key=lambda i: i[0]))
     od2 = OrderedDict(sorted(d2.items(), key=lambda i: i[0]))
     diff_obj = diff_ordered_mapping(od1, od2)
     diffs = [
         MappingDiffItem(unchanged, 'a', unchanged, 1),
         MappingDiffItem(unchanged, 'b', remove, ['a']),
         MappingDiffItem(unchanged, 'b', insert, 'a'),
         MappingDiffItem(unchanged, 'c', unchanged, 3)
     ]
     expected_diff = Diff(OrderedDict, diffs)
     expected_diff.context_blocks = [
         expected_diff.ContextBlock(OrderedDict, diffs[1:3])
     ]
     self.assertEqual(diff_obj, expected_diff)
     self.assertEqual(patch(od1, diff_obj), od2)
예제 #26
0
 def test_common_keys_recursive_diff(self):
     map1 = {'a': {'b': 1}}
     map2 = {'a': {'b': 2}}
     diff_obj = diff_mapping(map1, map2)
     nested_diffs = [
         MappingDiffItem(unchanged, 'b', remove, 1),
         MappingDiffItem(unchanged, 'b', insert, 2)]
     nested_diff = Diff(dict, nested_diffs, depth=1)
     nested_diff.context_blocks = [
         nested_diff.ContextBlock(dict, nested_diffs, depth=1)]
     diffs = [
         MappingDiffItem(
             unchanged, 'a', changed, nested_diff)]
     expected_diff = Diff(dict, diffs)
     expected_diff.context_blocks = [
         expected_diff.ContextBlock(dict, diffs)]
     self.assertEqual(diff_obj, expected_diff)
     self.assertEqual(patch(map1, diff_obj), map2)
예제 #27
0
 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)
예제 #28
0
 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)
예제 #29
0
 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)
예제 #30
0
 def test_single_char_edge_case_in_dict(self):
     map1 = {1: 'a'}
     map2 = {1: 'b'}
     diff_obj = diff_mapping(map1, map2)
     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 = [
         MappingDiffItem(unchanged, 1, changed, nested_diff)
     ]
     expected_diff = Diff(dict, diffs)
     expected_diff.context_blocks = [
         expected_diff.ContextBlock(dict, diffs)
     ]
     self.assertEqual(diff_obj, expected_diff)
     self.assertEqual(patch(map1, diff_obj), map2)