/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tests/per_intertree/test_compare.py

  • Committer: Jelmer Vernooij
  • Date: 2019-06-02 02:35:46 UTC
  • mfrom: (7309 work)
  • mto: This revision was merged to the branch mainline in revision 7319.
  • Revision ID: jelmer@jelmer.uk-20190602023546-lqco868tnv26d8ow
merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
51
51
def _change_key(change):
52
52
    """Return a valid key for sorting Tree.iter_changes entries."""
53
53
    (file_id, paths, content_changed, versioned, parent, name, kind,
54
 
            executable) = change
 
54
     executable) = change
55
55
    return (file_id or b'', (paths[0] or '', paths[1] or ''), versioned,
56
56
            parent, name, kind, executable)
57
57
 
96
96
        self.assertEqual([('a', b'a-id', 'file'),
97
97
                          ('b', b'b-id', 'directory'),
98
98
                          ('b/c', b'c-id', 'file'),
99
 
                         ], d.added)
 
99
                          ], d.added)
100
100
        self.assertEqual([], d.modified)
101
101
        self.assertEqual([], d.removed)
102
102
        self.assertEqual([], d.renamed)
142
142
        self.assertEqual([('a', tree1.path2id('a'), 'file'),
143
143
                          ('b', tree1.path2id('b'), 'directory'),
144
144
                          ('b/c', tree1.path2id('b/c'), 'file'),
145
 
                         ], d.removed)
 
145
                          ], d.removed)
146
146
        self.assertEqual([], d.renamed)
147
147
        self.assertEqual([], d.unchanged)
148
148
 
155
155
        tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
156
156
        d = self.intertree_class(tree1, tree2).compare()
157
157
        self.assertEqual([], d.added)
158
 
        self.assertEqual([('a', tree1.path2id('a'), 'file', True, False)], d.modified)
 
158
        self.assertEqual(
 
159
            [('a', tree1.path2id('a'), 'file', True, False)], d.modified)
159
160
        self.assertEqual([], d.removed)
160
161
        self.assertEqual([], d.renamed)
161
162
        self.assertEqual([], d.unchanged)
169
170
        tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
170
171
        d = self.intertree_class(tree1, tree2).compare()
171
172
        self.assertEqual([], d.added)
172
 
        self.assertEqual([('b/c', tree1.path2id('b/c'), 'file', False, True)], d.modified)
 
173
        self.assertEqual(
 
174
            [('b/c', tree1.path2id('b/c'), 'file', False, True)], d.modified)
173
175
        self.assertEqual([], d.removed)
174
176
        self.assertEqual([], d.renamed)
175
177
        self.assertEqual([], d.unchanged)
185
187
        self.assertEqual([], d.added)
186
188
        self.assertEqual([], d.modified)
187
189
        self.assertEqual([], d.removed)
188
 
        self.assertEqual([('a', 'd', tree1.path2id('a'), 'file', False, False)], d.renamed)
 
190
        self.assertEqual(
 
191
            [('a', 'd', tree1.path2id('a'), 'file', False, False)], d.renamed)
189
192
        self.assertEqual([], d.unchanged)
190
193
 
191
194
    def test_file_rename_and_modification(self):
199
202
        self.assertEqual([], d.added)
200
203
        self.assertEqual([], d.modified)
201
204
        self.assertEqual([], d.removed)
202
 
        self.assertEqual([('a', 'd', tree1.path2id('a'), 'file', True, False)], d.renamed)
 
205
        self.assertEqual(
 
206
            [('a', 'd', tree1.path2id('a'), 'file', True, False)], d.renamed)
203
207
        self.assertEqual([], d.unchanged)
204
208
 
205
209
    def test_file_rename_and_meta_modification(self):
213
217
        self.assertEqual([], d.added)
214
218
        self.assertEqual([], d.modified)
215
219
        self.assertEqual([], d.removed)
216
 
        self.assertEqual([('b/c', 'e', tree1.path2id('b/c'), 'file', False, True)], d.renamed)
 
220
        self.assertEqual(
 
221
            [('b/c', 'e', tree1.path2id('b/c'), 'file', False, True)], d.renamed)
217
222
        self.assertEqual([], d.unchanged)
218
223
 
219
224
    def test_empty_to_abc_content_a_only(self):
338
343
        tree2 = self.get_tree_no_parents_abc_content(tree2)
339
344
        tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
340
345
        self.assertRaises(errors.PathsNotVersionedError,
341
 
            self.intertree_class(tree1, tree2).compare,
342
 
            specific_files=['d'],
343
 
            require_versioned=True)
 
346
                          self.intertree_class(tree1, tree2).compare,
 
347
                          specific_files=['d'],
 
348
                          require_versioned=True)
344
349
 
345
350
    def test_default_ignores_unversioned_files(self):
346
351
        tree1 = self.make_branch_and_tree('tree1')
355
360
        d = self.intertree_class(tree1, tree2).compare()
356
361
        self.assertEqual([], d.added)
357
362
        self.assertEqual([(u'a', b'a-id', 'file', True, False),
358
 
            (u'c', b'c-id', 'file', True, False)], d.modified)
 
363
                          (u'c', b'c-id', 'file', True, False)], d.modified)
359
364
        self.assertEqual([], d.removed)
360
365
        self.assertEqual([], d.renamed)
361
366
        self.assertEqual([], d.unchanged)
431
436
        # when all the ids are unique on both sides.
432
437
        left_dict = dict((item[0], item) for item in left_changes)
433
438
        right_dict = dict((item[0], item) for item in right_changes)
434
 
        if (len(left_dict) != len(left_changes) or
435
 
            len(right_dict) != len(right_changes)):
 
439
        if (len(left_dict) != len(left_changes)
 
440
                or len(right_dict) != len(right_changes)):
436
441
            # Can't do a direct comparison. We could do a sequence diff, but
437
442
            # for now just do a regular assertEqual for now.
438
443
            self.assertEqual(left_changes, right_changes)
446
451
                same.append(str(left_item))
447
452
            else:
448
453
                different.append(" %s\n %s" % (left_item, right_item))
449
 
        self.fail("iter_changes output different. Unchanged items:\n" +
450
 
            "\n".join(same) + "\nChanged items:\n" + "\n".join(different))
 
454
        self.fail("iter_changes output different. Unchanged items:\n"
 
455
                  + "\n".join(same) + "\nChanged items:\n" + "\n".join(different))
451
456
 
452
457
    def do_iter_changes(self, tree1, tree2, **extra_args):
453
458
        """Helper to run iter_changes from tree1 to tree2.
460
465
        with tree1.lock_read(), tree2.lock_read():
461
466
            # sort order of output is not strictly defined
462
467
            return self.sorted(self.intertree_class(tree1, tree2)
463
 
                .iter_changes(**extra_args))
 
468
                               .iter_changes(**extra_args))
464
469
 
465
470
    def check_has_changes(self, expected, tree1, tree2):
466
471
        # has_changes is defined for mutable trees only
472
477
            else:
473
478
                # Neither tree can be used
474
479
                return
475
 
        tree1.lock_read()
476
 
        try:
477
 
            tree2.lock_read()
478
 
            try:
479
 
                return tree2.has_changes(tree1)
480
 
            finally:
481
 
                tree2.unlock()
482
 
        finally:
483
 
            tree1.unlock()
 
480
        with tree1.lock_read(), tree2.lock_read():
 
481
            return tree2.has_changes(tree1)
484
482
 
485
483
    def mutable_trees_to_locked_test_trees(self, tree1, tree2):
486
484
        """Convert the working trees into test trees.
529
527
                'a/a/a/a',
530
528
                'a/a/a/a-a',
531
529
                'a/a/a/a/a',
532
 
               ]
 
530
                ]
533
531
        with_slashes = []
534
532
        paths = []
535
533
        path_ids = []
537
535
            with_slashes.append(base_path + '/' + d + '/')
538
536
            with_slashes.append(base_path + '/' + d + '/f')
539
537
            paths.append(d)
540
 
            paths.append(d+'/f')
 
538
            paths.append(d + '/f')
541
539
            path_ids.append((d.replace('/', '_') + '-id').encode('ascii'))
542
540
            path_ids.append((d.replace('/', '_') + '_f-id').encode('ascii'))
543
541
        self.build_tree(with_slashes)
590
588
        _, to_basename = os.path.split(to_path)
591
589
        # missing files have both paths, but no kind.
592
590
        return (file_id, (from_path, to_path), True, (True, True),
593
 
            (parent_id, parent_id),
594
 
            (from_basename, to_basename), (kind, None), (False, False))
 
591
                (parent_id, parent_id),
 
592
                (from_basename, to_basename), (kind, None), (False, False))
595
593
 
596
594
    def deleted(self, tree, file_id):
597
595
        entry = tree.root_inventory.get_entry(file_id)
604
602
        from_path, from_entry = self.get_path_entry(from_tree, file_id)
605
603
        to_path, to_entry = self.get_path_entry(to_tree, file_id)
606
604
        return (file_id, (from_path, to_path), content_changed, (True, True),
607
 
            (from_entry.parent_id, to_entry.parent_id),
608
 
            (from_entry.name, to_entry.name),
609
 
            (from_entry.kind, to_entry.kind),
610
 
            (from_entry.executable, to_entry.executable))
 
605
                (from_entry.parent_id, to_entry.parent_id),
 
606
                (from_entry.name, to_entry.name),
 
607
                (from_entry.kind, to_entry.kind),
 
608
                (from_entry.executable, to_entry.executable))
611
609
 
612
610
    def unchanged(self, tree, file_id):
613
611
        path, entry = self.get_path_entry(tree, file_id)
616
614
        kind = entry.kind
617
615
        executable = entry.executable
618
616
        return (file_id, (path, path), False, (True, True),
619
 
               (parent, parent), (name, name), (kind, kind),
620
 
               (executable, executable))
 
617
                (parent, parent), (name, name), (kind, kind),
 
618
                (executable, executable))
621
619
 
622
620
    def unversioned(self, tree, path):
623
621
        """Create an unversioned result."""
652
650
        tree2 = self.get_tree_no_parents_abc_content(tree2)
653
651
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
654
652
        self.assertEqual([],
655
 
            self.do_iter_changes(tree1, tree2, specific_files=[]))
 
653
                         self.do_iter_changes(tree1, tree2, specific_files=[]))
656
654
 
657
655
    def test_no_specific_files(self):
658
656
        tree1 = self.make_branch_and_tree('1')
677
675
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
678
676
        self.assertEqual(
679
677
            self.sorted([self.added(tree2, b'root-id'),
680
 
             self.added(tree2, b'a-id'),
681
 
             self.deleted(tree1, b'empty-root-id')]),
 
678
                         self.added(tree2, b'a-id'),
 
679
                         self.deleted(tree1, b'empty-root-id')]),
682
680
            self.do_iter_changes(tree1, tree2, specific_files=['a']))
683
681
 
684
682
    def test_abc_content_to_empty_a_only(self):
710
708
        tree2 = self.get_tree_no_parents_abc_content(tree2)
711
709
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
712
710
        expected_result = self.sorted([self.added(tree2, b'root-id'),
713
 
            self.added(tree2, b'a-id'), self.added(tree2, b'b-id'),
714
 
            self.added(tree2, b'c-id'), self.deleted(tree1, b'empty-root-id')])
 
711
                                       self.added(
 
712
                                           tree2, b'a-id'), self.added(tree2, b'b-id'),
 
713
                                       self.added(tree2, b'c-id'), self.deleted(tree1, b'empty-root-id')])
715
714
        self.assertEqual(expected_result,
716
 
            self.do_iter_changes(tree1, tree2, specific_files=['a', 'b/c']))
 
715
                         self.do_iter_changes(tree1, tree2, specific_files=['a', 'b/c']))
717
716
 
718
717
    def test_abc_content_to_empty(self):
719
718
        tree1 = self.make_branch_and_tree('1')
751
750
        tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
752
751
        self.assertEqual([(b'c-id', ('b/c', 'b/c'), False, (True, True),
753
752
                           (b'b-id', b'b-id'), ('c', 'c'), ('file', 'file'),
754
 
                          (False, True))],
 
753
                           (False, True))],
755
754
                         self.do_iter_changes(tree1, tree2))
756
755
 
757
756
    def test_empty_dir(self):
800
799
        tree1.mkdir('changing/unchanging', b'mid-id')
801
800
        tree1.add(['changing/unchanging/file'], [b'file-id'], ['file'])
802
801
        tree1.put_file_bytes_non_atomic(
803
 
                'changing/unchanging/file', b'a file', file_id=b'file-id')
 
802
            'changing/unchanging/file', b'a file')
804
803
        tree2 = self.make_to_branch_and_tree('2')
805
804
        tree2.set_root_id(tree1.get_root_id())
806
805
        tree2.mkdir('changed', b'parent-id')
807
806
        tree2.mkdir('changed/unchanging', b'mid-id')
808
807
        tree2.add(['changed/unchanging/file'], [b'file-id'], ['file'])
809
808
        tree2.put_file_bytes_non_atomic(
810
 
                'changed/unchanging/file', b'changed content', file_id=b'file-id')
 
809
            'changed/unchanging/file', b'changed content')
811
810
        tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
812
811
        # parent-id has changed, as has file-id
813
812
        root_id = tree1.path2id('')
814
813
        self.assertEqualIterChanges(
815
814
            [self.renamed(tree1, tree2, b'parent-id', False),
816
815
             self.renamed(tree1, tree2, b'file-id', True)],
817
 
             self.do_iter_changes(tree1, tree2,
818
 
             specific_files=['changed/unchanging/file']))
 
816
            self.do_iter_changes(tree1, tree2,
 
817
                                 specific_files=['changed/unchanging/file']))
819
818
 
820
819
    def test_specific_content_modification_grabs_parents_root_changes(self):
821
820
        # WHen the only direct change to a specified file is a content change,
826
825
        tree1.mkdir('changed', b'parent-id')
827
826
        tree1.mkdir('changed/unchanging', b'mid-id')
828
827
        tree1.add(['changed/unchanging/file'], [b'file-id'], ['file'])
829
 
        tree1.put_file_bytes_non_atomic(
830
 
                'changed/unchanging/file', b'a file',
831
 
                b'file-id')
 
828
        tree1.put_file_bytes_non_atomic('changed/unchanging/file', b'a file')
832
829
        tree2 = self.make_to_branch_and_tree('2')
833
830
        tree2.set_root_id(b'new')
834
831
        tree2.mkdir('changed', b'parent-id')
835
832
        tree2.mkdir('changed/unchanging', b'mid-id')
836
833
        tree2.add(['changed/unchanging/file'], [b'file-id'], ['file'])
837
834
        tree2.put_file_bytes_non_atomic(
838
 
                'changed/unchanging/file', b'changed content', file_id=b'file-id')
 
835
            'changed/unchanging/file', b'changed content')
839
836
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
840
837
        # old is gone, new is added, parent-id has changed(reparented), as has
841
838
        # file-id(content)
845
842
             self.added(tree2, b'new'),
846
843
             self.deleted(tree1, b'old'),
847
844
             self.renamed(tree1, tree2, b'file-id', True)],
848
 
             self.do_iter_changes(tree1, tree2,
849
 
             specific_files=['changed/unchanging/file']))
 
845
            self.do_iter_changes(tree1, tree2,
 
846
                                 specific_files=['changed/unchanging/file']))
850
847
 
851
848
    def test_specific_with_rename_under_new_dir_reports_new_dir(self):
852
849
        tree1 = self.make_branch_and_tree('1')
854
851
        tree1 = self.get_tree_no_parents_abc_content(tree1)
855
852
        tree2 = self.get_tree_no_parents_abc_content_7(tree2)
856
853
        tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
857
 
        # d(d-id) is new, e is b-id renamed. 
 
854
        # d(d-id) is new, e is b-id renamed.
858
855
        root_id = tree1.path2id('')
859
856
        self.assertEqualIterChanges(
860
857
            [self.renamed(tree1, tree2, b'b-id', False),
861
858
             self.added(tree2, b'd-id')],
862
 
             self.do_iter_changes(tree1, tree2, specific_files=['d/e']))
 
859
            self.do_iter_changes(tree1, tree2, specific_files=['d/e']))
863
860
 
864
861
    def test_specific_with_rename_under_dir_under_new_dir_reports_new_dir(self):
865
862
        tree1 = self.make_branch_and_tree('1')
868
865
        tree2 = self.get_tree_no_parents_abc_content_7(tree2)
869
866
        tree2.rename_one('a', 'd/e/a')
870
867
        tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
871
 
        # d is new, d/e is b-id renamed, d/e/a is a-id renamed 
 
868
        # d is new, d/e is b-id renamed, d/e/a is a-id renamed
872
869
        root_id = tree1.path2id('')
873
870
        self.assertEqualIterChanges(
874
871
            [self.renamed(tree1, tree2, tree1.path2id('b'), False),
875
872
             self.added(tree2, b'd-id'),
876
873
             self.renamed(tree1, tree2, b'a-id', False)],
877
 
             self.do_iter_changes(tree1, tree2, specific_files=['d/e/a']))
 
874
            self.do_iter_changes(tree1, tree2, specific_files=['d/e/a']))
878
875
 
879
876
    def test_specific_old_parent_same_path_new_parent(self):
880
877
        # when a parent is new at its path, if the path was used in the source
893
890
            [self.deleted(tree1, b'a-id'),
894
891
             self.added(tree2, b'b-id'),
895
892
             self.added(tree2, b'c-id')],
896
 
             self.do_iter_changes(tree1, tree2, specific_files=['a/c']))
 
893
            self.do_iter_changes(tree1, tree2, specific_files=['a/c']))
897
894
 
898
895
    def test_specific_old_parent_becomes_file(self):
899
896
        # When an old parent included because of a path conflict becomes a
916
913
             self.added(tree2, b'a-new-id'),
917
914
             self.renamed(tree1, tree2, b'reparented-id', False),
918
915
             self.deleted(tree1, b'deleted-id')],
919
 
             self.do_iter_changes(tree1, tree2,
920
 
                specific_files=['a/reparented']))
 
916
            self.do_iter_changes(tree1, tree2,
 
917
                                 specific_files=['a/reparented']))
921
918
 
922
919
    def test_specific_old_parent_is_deleted(self):
923
920
        # When an old parent included because of a path conflict is removed,
938
935
             self.added(tree2, b'a-new-id'),
939
936
             self.renamed(tree1, tree2, b'reparented-id', False),
940
937
             self.deleted(tree1, b'deleted-id')],
941
 
             self.do_iter_changes(tree1, tree2,
942
 
                specific_files=['a/reparented']))
 
938
            self.do_iter_changes(tree1, tree2,
 
939
                                 specific_files=['a/reparented']))
943
940
 
944
941
    def test_specific_old_parent_child_collides_with_unselected_new(self):
945
942
        # When the child of an old parent because of a path conflict becomes a
964
961
             self.renamed(tree1, tree2, b'reparented-id', False),
965
962
             self.deleted(tree1, b'collides-id'),
966
963
             self.added(tree2, b'selected-id')],
967
 
             self.do_iter_changes(tree1, tree2,
968
 
                specific_files=['a/selected']))
 
964
            self.do_iter_changes(tree1, tree2,
 
965
                                 specific_files=['a/selected']))
969
966
 
970
967
    def test_specific_old_parent_child_dir_stops_being_dir(self):
971
968
        # When the child of an old parent also stops being a directory, its
994
991
             self.renamed(tree1, tree2, b'reparented-id-2', False),
995
992
             self.deleted(tree1, b'deleted-id-1'),
996
993
             self.deleted(tree1, b'deleted-id-2')],
997
 
             self.do_iter_changes(tree1, tree2,
998
 
                specific_files=['a/reparented']))
 
994
            self.do_iter_changes(tree1, tree2,
 
995
                                 specific_files=['a/reparented']))
999
996
 
1000
997
    def test_file_rename_and_meta_modification(self):
1001
998
        tree1 = self.make_branch_and_tree('1')
1015
1012
        # trees.
1016
1013
        # In bug 438569, a file becoming a fifo causes an assert. Fifo's are
1017
1014
        # not versionable or diffable. For now, we simply stop cold when they
1018
 
        # are detected (because we don't know how far through the code the 
1019
 
        # assumption 'fifo's do not exist' goes). In future we could report 
 
1015
        # are detected (because we don't know how far through the code the
 
1016
        # assumption 'fifo's do not exist' goes). In future we could report
1020
1017
        # the kind change and have commit refuse to go futher, or something
1021
1018
        # similar. One particular reason for choosing this approach is that
1022
 
        # there is no minikind for 'fifo' in dirstate today, so we can't 
 
1019
        # there is no minikind for 'fifo' in dirstate today, so we can't
1023
1020
        # actually update records that way.
1024
1021
        # To add confusion, the totally generic code path works - but it
1025
1022
        # doesn't update persistent metadata. So this test permits InterTrees
1090
1087
        self.not_applicable_if_missing_in('file', tree1)
1091
1088
        root_id = tree1.path2id('')
1092
1089
        expected = [(b'file-id', ('file', None), False, (True, False),
1093
 
            (root_id, None), ('file', None), (None, None), (False, None))]
 
1090
                     (root_id, None), ('file', None), (None, None), (False, None))]
1094
1091
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
1095
1092
 
1096
1093
    def test_only_in_target_and_missing(self):
1104
1101
        self.not_applicable_if_missing_in('file', tree2)
1105
1102
        root_id = tree1.path2id('')
1106
1103
        expected = [(b'file-id', (None, 'file'), False, (False, True),
1107
 
            (None, root_id), (None, 'file'), (None, None), (None, False))]
 
1104
                     (None, root_id), (None, 'file'), (None, None), (None, False))]
1108
1105
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
1109
1106
 
1110
1107
    def test_only_in_target_missing_subtree_specific_bug_367632(self):
1120
1117
        root_id = tree1.path2id('')
1121
1118
        expected = [
1122
1119
            (b'dir-id', (None, 'a-dir'), False, (False, True),
1123
 
            (None, root_id), (None, 'a-dir'), (None, None), (None, False)),
 
1120
             (None, root_id), (None, 'a-dir'), (None, None), (None, False)),
1124
1121
            (b'file-id', (None, 'a-dir/a-file'), False, (False, True),
1125
 
            (None, b'dir-id'), (None, 'a-file'), (None, None), (None, False))
 
1122
             (None, b'dir-id'), (None, 'a-file'), (None, None), (None, False))
1126
1123
            ]
1127
1124
        # bug 367632 showed that specifying the root broke some code paths,
1128
1125
        # so we check this contract with and without it.
1129
1126
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
1130
1127
        self.assertEqual(expected,
1131
 
            self.do_iter_changes(tree1, tree2, specific_files=['']))
 
1128
                         self.do_iter_changes(tree1, tree2, specific_files=['']))
1132
1129
 
1133
1130
    def test_unchanged_with_renames_and_modifications(self):
1134
1131
        """want_unchanged should generate a list of unchanged entries."""
1138
1135
        tree2 = self.get_tree_no_parents_abc_content_5(tree2)
1139
1136
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1140
1137
        self.assertEqual(sorted([self.unchanged(tree1, b'root-id'),
1141
 
            self.unchanged(tree1, b'b-id'),
1142
 
            (b'a-id', ('a', 'd'), True, (True, True),
1143
 
             (b'root-id', b'root-id'), ('a', 'd'), ('file', 'file'),
1144
 
            (False, False)), self.unchanged(tree1, b'c-id')]),
1145
 
            self.do_iter_changes(tree1, tree2, include_unchanged=True))
 
1138
                                 self.unchanged(tree1, b'b-id'),
 
1139
                                 (b'a-id', ('a', 'd'), True, (True, True),
 
1140
                                  (b'root-id', b'root-id'), ('a',
 
1141
                                                             'd'), ('file', 'file'),
 
1142
                                  (False, False)), self.unchanged(tree1, b'c-id')]),
 
1143
                         self.do_iter_changes(tree1, tree2, include_unchanged=True))
1146
1144
 
1147
1145
    def test_compare_subtrees(self):
1148
1146
        tree1 = self.make_branch_and_tree('1')
1181
1179
             ('sub', 'sub'),
1182
1180
             ('tree-reference', 'tree-reference'),
1183
1181
             (False, False))],
1184
 
                         list(tree2.iter_changes(tree1,
1185
 
                             include_unchanged=True)))
 
1182
            list(tree2.iter_changes(tree1,
 
1183
                                    include_unchanged=True)))
1186
1184
 
1187
1185
    def test_disk_in_subtrees_skipped(self):
1188
1186
        """subtrees are considered not-in-the-current-tree.
1205
1203
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1206
1204
        # this should filter correctly from above
1207
1205
        self.assertEqual([self.added(tree2, b'subtree-id')],
1208
 
            self.do_iter_changes(tree1, tree2, want_unversioned=True))
 
1206
                         self.do_iter_changes(tree1, tree2, want_unversioned=True))
1209
1207
        # and when the path is named
1210
1208
        self.assertEqual([self.added(tree2, b'subtree-id')],
1211
 
            self.do_iter_changes(tree1, tree2, specific_files=['sub'],
1212
 
                want_unversioned=True))
 
1209
                         self.do_iter_changes(tree1, tree2, specific_files=['sub'],
 
1210
                                              want_unversioned=True))
1213
1211
 
1214
1212
    def test_default_ignores_unversioned_files(self):
1215
1213
        tree1 = self.make_branch_and_tree('tree1')
1251
1249
            expected.append(self.unversioned(tree2, 'link'))
1252
1250
        expected = self.sorted(expected)
1253
1251
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
1254
 
            want_unversioned=True))
 
1252
                                                        want_unversioned=True))
1255
1253
 
1256
1254
    def test_unversioned_paths_in_tree_specific_files(self):
1257
1255
        tree1 = self.make_branch_and_tree('tree1')
1268
1266
            self.unversioned(tree2, 'file'),
1269
1267
            self.unversioned(tree2, 'dir'),
1270
1268
            ]
1271
 
        specific_files=['file', 'dir']
 
1269
        specific_files = ['file', 'dir']
1272
1270
        if links_supported:
1273
1271
            expected.append(self.unversioned(tree2, 'link'))
1274
1272
            specific_files.append('link')
1275
1273
        expected = self.sorted(expected)
1276
1274
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
1277
 
            specific_files=specific_files, require_versioned=False,
1278
 
            want_unversioned=True))
 
1275
                                                        specific_files=specific_files, require_versioned=False,
 
1276
                                                        want_unversioned=True))
1279
1277
 
1280
1278
    def test_unversioned_paths_in_target_matching_source_old_names(self):
1281
1279
        # its likely that naive implementations of unversioned file support
1289
1287
        tree2 = self.make_to_branch_and_tree('tree2')
1290
1288
        tree2.set_root_id(tree1.get_root_id())
1291
1289
        self.build_tree(['tree2/file', 'tree2/dir/',
1292
 
            'tree1/file', 'tree2/movedfile',
1293
 
            'tree1/dir/', 'tree2/moveddir/'])
 
1290
                         'tree1/file', 'tree2/movedfile',
 
1291
                         'tree1/dir/', 'tree2/moveddir/'])
1294
1292
        if has_symlinks():
1295
1293
            os.symlink('target', 'tree1/link')
1296
1294
            os.symlink('target', 'tree2/link')
1312
1310
            self.unversioned(tree2, 'file'),
1313
1311
            self.unversioned(tree2, 'dir'),
1314
1312
            ]
1315
 
        specific_files=['file', 'dir']
 
1313
        specific_files = ['file', 'dir']
1316
1314
        if links_supported:
1317
1315
            expected.append(self.renamed(tree1, tree2, b'link-id', False))
1318
1316
            expected.append(self.unversioned(tree2, 'link'))
1321
1319
        # run once with, and once without specific files, to catch
1322
1320
        # potentially different code paths.
1323
1321
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
1324
 
            require_versioned=False,
1325
 
            want_unversioned=True))
 
1322
                                                        require_versioned=False,
 
1323
                                                        want_unversioned=True))
1326
1324
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
1327
 
            specific_files=specific_files, require_versioned=False,
1328
 
            want_unversioned=True))
 
1325
                                                        specific_files=specific_files, require_versioned=False,
 
1326
                                                        want_unversioned=True))
1329
1327
 
1330
1328
    def test_similar_filenames(self):
1331
1329
        """Test when we have a few files with similar names."""
1347
1345
                         'tree2/a/b/c/d/',
1348
1346
                         'tree2/a-c/',
1349
1347
                         'tree2/a-c/e/',
1350
 
                        ])
 
1348
                         ])
1351
1349
        tree1.add(['a', 'a/b', 'a/b/c', 'a/b/c/d', 'a-c', 'a-c/e'],
1352
1350
                  [b'a-id', b'b-id', b'c-id', b'd-id', b'a-c-id', b'e-id'])
1353
1351
        tree2.add(['a', 'a/b', 'a/b/c', 'a/b/c/d', 'a-c', 'a-c/e'],
1372
1370
                                              want_unversioned=True,
1373
1371
                                              include_unchanged=True))
1374
1372
 
1375
 
 
1376
1373
    def test_unversioned_subtree_only_emits_root(self):
1377
1374
        tree1 = self.make_branch_and_tree('tree1')
1378
1375
        tree2 = self.make_to_branch_and_tree('tree2')
1384
1381
            self.unversioned(tree2, 'dir'),
1385
1382
            ]
1386
1383
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
1387
 
            want_unversioned=True))
 
1384
                                                        want_unversioned=True))
1388
1385
 
1389
1386
    def make_trees_with_symlinks(self):
1390
1387
        tree1 = self.make_branch_and_tree('tree1')
1399
1396
        # we make the unchanged link point at unknown to catch incorrect
1400
1397
        # symlink-following code in the specified_files test.
1401
1398
        os.symlink('unknown', 'tree1/unchanged')
1402
 
        os.symlink('new',      'tree2/added')
1403
 
        os.symlink('new',      'tree2/changed')
1404
 
        os.symlink('new',      'tree2/fromfile')
1405
 
        os.symlink('new',      'tree2/fromdir')
 
1399
        os.symlink('new', 'tree2/added')
 
1400
        os.symlink('new', 'tree2/changed')
 
1401
        os.symlink('new', 'tree2/fromfile')
 
1402
        os.symlink('new', 'tree2/fromdir')
1406
1403
        os.symlink('unknown', 'tree2/unchanged')
1407
1404
        from_paths_and_ids = [
1408
1405
            'fromdir',
1422
1419
            'tofile',
1423
1420
            'unchanged',
1424
1421
            ]
1425
 
        tree1.add(from_paths_and_ids, [p.encode('utf-8') for p in from_paths_and_ids])
1426
 
        tree2.add(to_paths_and_ids, [p.encode('utf-8') for p in to_paths_and_ids])
 
1422
        tree1.add(from_paths_and_ids, [p.encode('utf-8')
 
1423
                                       for p in from_paths_and_ids])
 
1424
        tree2.add(to_paths_and_ids, [p.encode('utf-8')
 
1425
                                     for p in to_paths_and_ids])
1427
1426
        return self.mutable_trees_to_locked_test_trees(tree1, tree2)
1428
1427
 
1429
1428
    def test_versioned_symlinks(self):
1445
1444
            ]
1446
1445
        expected = self.sorted(expected)
1447
1446
        self.assertEqual(expected,
1448
 
            self.do_iter_changes(tree1, tree2, include_unchanged=True,
1449
 
                want_unversioned=True))
 
1447
                         self.do_iter_changes(tree1, tree2, include_unchanged=True,
 
1448
                                              want_unversioned=True))
1450
1449
        self.check_has_changes(True, tree1, tree2)
1451
1450
 
1452
1451
    def test_versioned_symlinks_specific_files(self):
1467
1466
        # make sure that it is correctly not returned - and neither is the
1468
1467
        # unknown path 'unknown' which it points at.
1469
1468
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
1470
 
            specific_files=['added', 'changed', 'fromdir', 'fromfile',
1471
 
            'removed', 'unchanged', 'todir', 'tofile']))
 
1469
                                                        specific_files=['added', 'changed', 'fromdir', 'fromfile',
 
1470
                                                                        'removed', 'unchanged', 'todir', 'tofile']))
1472
1471
        self.check_has_changes(True, tree1, tree2)
1473
1472
 
1474
1473
    def test_tree_with_special_names(self):
1480
1479
    def test_trees_with_special_names(self):
1481
1480
        tree1, tree2, paths, path_ids = self.make_trees_with_special_names()
1482
1481
        expected = self.sorted(self.content_changed(tree2, f_id) for f_id in path_ids
1483
 
                          if f_id.endswith(b'_f-id'))
 
1482
                               if f_id.endswith(b'_f-id'))
1484
1483
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
1485
1484
        self.check_has_changes(True, tree1, tree2)
1486
1485
 
1506
1505
            self.deleted(tree1, b'e-id'),
1507
1506
            ]
1508
1507
        self.assertEqualIterChanges(expected,
1509
 
            self.do_iter_changes(tree1, tree2))
 
1508
                                    self.do_iter_changes(tree1, tree2))
1510
1509
        self.check_has_changes(True, tree1, tree2)
1511
1510
 
1512
1511
    def test_added_unicode(self):
1523
1522
            self.build_tree([u'tree1/\u03b1/',
1524
1523
                             u'tree2/\u03b1/',
1525
1524
                             u'tree2/\u03b1/\u03c9-added',
1526
 
                            ])
 
1525
                             ])
1527
1526
        except UnicodeError:
1528
1527
            raise tests.TestSkipped("Could not create Unicode files.")
1529
1528
        tree1.add([u'\u03b1'], [a_id])
1552
1551
            self.build_tree([u'tree1/\u03b1/',
1553
1552
                             u'tree1/\u03b1/\u03c9-deleted',
1554
1553
                             u'tree2/\u03b1/',
1555
 
                            ])
 
1554
                             ])
1556
1555
        except UnicodeError:
1557
1556
            raise tests.TestSkipped("Could not create Unicode files.")
1558
1557
        tree1.add([u'\u03b1', u'\u03b1/\u03c9-deleted'], [a_id, deleted_id])
1582
1581
                             u'tree1/\u03b1/\u03c9-modified',
1583
1582
                             u'tree2/\u03b1/',
1584
1583
                             u'tree2/\u03b1/\u03c9-modified',
1585
 
                            ])
 
1584
                             ])
1586
1585
        except UnicodeError:
1587
1586
            raise tests.TestSkipped("Could not create Unicode files.")
1588
1587
        tree1.add([u'\u03b1', u'\u03b1/\u03c9-modified'], [a_id, mod_id])
1610
1609
        try:
1611
1610
            self.build_tree([u'tree1/\u03b1/',
1612
1611
                             u'tree2/\u03b1/',
1613
 
                            ])
 
1612
                             ])
1614
1613
        except UnicodeError:
1615
1614
            raise tests.TestSkipped("Could not create Unicode files.")
1616
1615
        self.build_tree_contents([(u'tree1/\u03c9-source', b'contents\n'),
1617
1616
                                  (u'tree2/\u03b1/\u03c9-target', b'contents\n'),
1618
 
                                 ])
 
1617
                                  ])
1619
1618
        tree1.add([u'\u03b1', u'\u03c9-source'], [a_id, rename_id])
1620
1619
        tree2.add([u'\u03b1', u'\u03b1/\u03c9-target'], [a_id, rename_id])
1621
1620
 
1641
1640
        try:
1642
1641
            self.build_tree([u'tree1/\u03b1/',
1643
1642
                             u'tree2/\u03b1/',
1644
 
                            ])
 
1643
                             ])
1645
1644
        except UnicodeError:
1646
1645
            raise tests.TestSkipped("Could not create Unicode files.")
1647
1646
        self.build_tree_contents([
1673
1672
            self.unchanged(tree1, subfile_id),
1674
1673
            ])
1675
1674
        self.assertEqual(expected,
1676
 
            self.do_iter_changes(tree1, tree2, specific_files=[u'\u03b1'],
1677
 
                include_unchanged=True))
 
1675
                         self.do_iter_changes(tree1, tree2, specific_files=[u'\u03b1'],
 
1676
                                              include_unchanged=True))
1678
1677
 
1679
1678
    def test_unknown_unicode(self):
1680
1679
        tree1 = self.make_branch_and_tree('tree1')
1691
1690
                             u'tree2/\u03b1/unknown_file',
1692
1691
                             u'tree2/\u03b1/unknown_dir/file',
1693
1692
                             u'tree2/\u03c9-unknown_root_file',
1694
 
                            ])
 
1693
                             ])
1695
1694
        except UnicodeError:
1696
1695
            raise tests.TestSkipped("Could not create Unicode files.")
1697
1696
        tree1.add([u'\u03b1'], [a_id])
1712
1711
                         self.do_iter_changes(tree1, tree2,
1713
1712
                                              require_versioned=False,
1714
1713
                                              want_unversioned=True))
1715
 
        self.assertEqual([], # Without want_unversioned we should get nothing
 
1714
        self.assertEqual([],  # Without want_unversioned we should get nothing
1716
1715
                         self.do_iter_changes(tree1, tree2))
1717
1716
        self.check_has_changes(False, tree1, tree2)
1718
1717
 
1726
1725
                                              specific_files=[u'\u03b1'],
1727
1726
                                              require_versioned=False,
1728
1727
                                              want_unversioned=True))
1729
 
        self.assertEqual([], # Without want_unversioned we should get nothing
 
1728
        self.assertEqual([],  # Without want_unversioned we should get nothing
1730
1729
                         self.do_iter_changes(tree1, tree2,
1731
1730
                                              specific_files=[u'\u03b1']))
1732
1731
 
1747
1746
        # Now create some unknowns in tree2
1748
1747
        # We should find both a/file and a/dir as unknown, but we shouldn't
1749
1748
        # recurse into a/dir to find that a/dir/subfile is also unknown.
1750
 
        self.build_tree(['tree2/a/file', 'tree2/a/dir/', 'tree2/a/dir/subfile'])
 
1749
        self.build_tree(
 
1750
            ['tree2/a/file', 'tree2/a/dir/', 'tree2/a/dir/subfile'])
1751
1751
 
1752
1752
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1753
1753
        self.not_applicable_if_cannot_represent_unversioned(tree2)
1754
1754
 
1755
 
        expected = self.sorted([
1756
 
            self.unversioned(tree2, u'a/file'),
1757
 
            self.unversioned(tree2, u'a/dir'),
1758
 
            ])
1759
 
        self.assertEqual(expected,
1760
 
                         self.do_iter_changes(tree1, tree2,
1761
 
                                              require_versioned=False,
1762
 
                                              want_unversioned=True))
 
1755
        if tree2.has_versioned_directories():
 
1756
            expected = self.sorted([
 
1757
                self.unversioned(tree2, u'a/file'),
 
1758
                self.unversioned(tree2, u'a/dir'),
 
1759
                ])
 
1760
            self.assertEqual(expected,
 
1761
                             self.do_iter_changes(tree1, tree2,
 
1762
                                                  require_versioned=False,
 
1763
                                                  want_unversioned=True))
 
1764
        else:
 
1765
            expected = self.sorted([
 
1766
                self.unversioned(tree2, u'a/file'),
 
1767
                self.unversioned(tree2, u'a/dir/subfile'),
 
1768
                ])
 
1769
            self.assertEqual(expected,
 
1770
                             self.do_iter_changes(tree1, tree2,
 
1771
                                                  require_versioned=False,
 
1772
                                                  want_unversioned=True))
1763
1773
 
1764
1774
    def test_rename_over_deleted(self):
1765
1775
        tree1 = self.make_branch_and_tree('tree1')
1857
1867
            ('tree2/d', b'c contents\n'),
1858
1868
            ])
1859
1869
        tree1.add(['b', 'c'], [b'b1-id', b'c1-id'])
1860
 
        tree2.add(['a', 'b', 'c', 'd'], [b'b1-id', b'b2-id', b'c2-id', b'c1-id'])
 
1870
        tree2.add(['a', 'b', 'c', 'd'], [
 
1871
                  b'b1-id', b'b2-id', b'c2-id', b'c1-id'])
1861
1872
 
1862
1873
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1863
1874