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,
55
55
return (file_id or b'', (paths[0] or '', paths[1] or ''), versioned,
56
56
parent, name, kind, executable)
96
96
self.assertEqual([('a', b'a-id', 'file'),
97
97
('b', b'b-id', 'directory'),
98
98
('b/c', b'c-id', 'file'),
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'),
146
146
self.assertEqual([], d.renamed)
147
147
self.assertEqual([], d.unchanged)
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)
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)
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)
191
[('a', 'd', tree1.path2id('a'), 'file', False, False)], d.renamed)
189
192
self.assertEqual([], d.unchanged)
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)
206
[('a', 'd', tree1.path2id('a'), 'file', True, False)], d.renamed)
203
207
self.assertEqual([], d.unchanged)
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)
221
[('b/c', 'e', tree1.path2id('b/c'), 'file', False, True)], d.renamed)
217
222
self.assertEqual([], d.unchanged)
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)
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))
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))
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))
465
470
def check_has_changes(self, expected, tree1, tree2):
466
471
# has_changes is defined for mutable trees only
537
542
with_slashes.append(base_path + '/' + d + '/')
538
543
with_slashes.append(base_path + '/' + d + '/f')
545
paths.append(d + '/f')
541
546
path_ids.append((d.replace('/', '_') + '-id').encode('ascii'))
542
547
path_ids.append((d.replace('/', '_') + '_f-id').encode('ascii'))
543
548
self.build_tree(with_slashes)
590
595
_, to_basename = os.path.split(to_path)
591
596
# missing files have both paths, but no kind.
592
597
return (file_id, (from_path, to_path), True, (True, True),
593
(parent_id, parent_id),
594
(from_basename, to_basename), (kind, None), (False, False))
598
(parent_id, parent_id),
599
(from_basename, to_basename), (kind, None), (False, False))
596
601
def deleted(self, tree, file_id):
597
602
entry = tree.root_inventory.get_entry(file_id)
604
609
from_path, from_entry = self.get_path_entry(from_tree, file_id)
605
610
to_path, to_entry = self.get_path_entry(to_tree, file_id)
606
611
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))
612
(from_entry.parent_id, to_entry.parent_id),
613
(from_entry.name, to_entry.name),
614
(from_entry.kind, to_entry.kind),
615
(from_entry.executable, to_entry.executable))
612
617
def unchanged(self, tree, file_id):
613
618
path, entry = self.get_path_entry(tree, file_id)
616
621
kind = entry.kind
617
622
executable = entry.executable
618
623
return (file_id, (path, path), False, (True, True),
619
(parent, parent), (name, name), (kind, kind),
620
(executable, executable))
624
(parent, parent), (name, name), (kind, kind),
625
(executable, executable))
622
627
def unversioned(self, tree, path):
623
628
"""Create an unversioned result."""
652
657
tree2 = self.get_tree_no_parents_abc_content(tree2)
653
658
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
654
659
self.assertEqual([],
655
self.do_iter_changes(tree1, tree2, specific_files=[]))
660
self.do_iter_changes(tree1, tree2, specific_files=[]))
657
662
def test_no_specific_files(self):
658
663
tree1 = self.make_branch_and_tree('1')
677
682
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
678
683
self.assertEqual(
679
684
self.sorted([self.added(tree2, b'root-id'),
680
self.added(tree2, b'a-id'),
681
self.deleted(tree1, b'empty-root-id')]),
685
self.added(tree2, b'a-id'),
686
self.deleted(tree1, b'empty-root-id')]),
682
687
self.do_iter_changes(tree1, tree2, specific_files=['a']))
684
689
def test_abc_content_to_empty_a_only(self):
710
715
tree2 = self.get_tree_no_parents_abc_content(tree2)
711
716
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
712
717
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')])
719
tree2, b'a-id'), self.added(tree2, b'b-id'),
720
self.added(tree2, b'c-id'), self.deleted(tree1, b'empty-root-id')])
715
721
self.assertEqual(expected_result,
716
self.do_iter_changes(tree1, tree2, specific_files=['a', 'b/c']))
722
self.do_iter_changes(tree1, tree2, specific_files=['a', 'b/c']))
718
724
def test_abc_content_to_empty(self):
719
725
tree1 = self.make_branch_and_tree('1')
751
757
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
752
758
self.assertEqual([(b'c-id', ('b/c', 'b/c'), False, (True, True),
753
759
(b'b-id', b'b-id'), ('c', 'c'), ('file', 'file'),
755
761
self.do_iter_changes(tree1, tree2))
757
763
def test_empty_dir(self):
800
806
tree1.mkdir('changing/unchanging', b'mid-id')
801
807
tree1.add(['changing/unchanging/file'], [b'file-id'], ['file'])
802
808
tree1.put_file_bytes_non_atomic(
803
'changing/unchanging/file', b'a file', file_id=b'file-id')
809
'changing/unchanging/file', b'a file', file_id=b'file-id')
804
810
tree2 = self.make_to_branch_and_tree('2')
805
811
tree2.set_root_id(tree1.get_root_id())
806
812
tree2.mkdir('changed', b'parent-id')
807
813
tree2.mkdir('changed/unchanging', b'mid-id')
808
814
tree2.add(['changed/unchanging/file'], [b'file-id'], ['file'])
809
815
tree2.put_file_bytes_non_atomic(
810
'changed/unchanging/file', b'changed content', file_id=b'file-id')
816
'changed/unchanging/file', b'changed content', file_id=b'file-id')
811
817
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
812
818
# parent-id has changed, as has file-id
813
819
root_id = tree1.path2id('')
814
820
self.assertEqualIterChanges(
815
821
[self.renamed(tree1, tree2, b'parent-id', False),
816
822
self.renamed(tree1, tree2, b'file-id', True)],
817
self.do_iter_changes(tree1, tree2,
818
specific_files=['changed/unchanging/file']))
823
self.do_iter_changes(tree1, tree2,
824
specific_files=['changed/unchanging/file']))
820
826
def test_specific_content_modification_grabs_parents_root_changes(self):
821
827
# WHen the only direct change to a specified file is a content change,
827
833
tree1.mkdir('changed/unchanging', b'mid-id')
828
834
tree1.add(['changed/unchanging/file'], [b'file-id'], ['file'])
829
835
tree1.put_file_bytes_non_atomic(
830
'changed/unchanging/file', b'a file',
836
'changed/unchanging/file', b'a file',
832
838
tree2 = self.make_to_branch_and_tree('2')
833
839
tree2.set_root_id(b'new')
834
840
tree2.mkdir('changed', b'parent-id')
835
841
tree2.mkdir('changed/unchanging', b'mid-id')
836
842
tree2.add(['changed/unchanging/file'], [b'file-id'], ['file'])
837
843
tree2.put_file_bytes_non_atomic(
838
'changed/unchanging/file', b'changed content', file_id=b'file-id')
844
'changed/unchanging/file', b'changed content', file_id=b'file-id')
839
845
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
840
846
# old is gone, new is added, parent-id has changed(reparented), as has
841
847
# file-id(content)
845
851
self.added(tree2, b'new'),
846
852
self.deleted(tree1, b'old'),
847
853
self.renamed(tree1, tree2, b'file-id', True)],
848
self.do_iter_changes(tree1, tree2,
849
specific_files=['changed/unchanging/file']))
854
self.do_iter_changes(tree1, tree2,
855
specific_files=['changed/unchanging/file']))
851
857
def test_specific_with_rename_under_new_dir_reports_new_dir(self):
852
858
tree1 = self.make_branch_and_tree('1')
854
860
tree1 = self.get_tree_no_parents_abc_content(tree1)
855
861
tree2 = self.get_tree_no_parents_abc_content_7(tree2)
856
862
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
857
# d(d-id) is new, e is b-id renamed.
863
# d(d-id) is new, e is b-id renamed.
858
864
root_id = tree1.path2id('')
859
865
self.assertEqualIterChanges(
860
866
[self.renamed(tree1, tree2, b'b-id', False),
861
867
self.added(tree2, b'd-id')],
862
self.do_iter_changes(tree1, tree2, specific_files=['d/e']))
868
self.do_iter_changes(tree1, tree2, specific_files=['d/e']))
864
870
def test_specific_with_rename_under_dir_under_new_dir_reports_new_dir(self):
865
871
tree1 = self.make_branch_and_tree('1')
868
874
tree2 = self.get_tree_no_parents_abc_content_7(tree2)
869
875
tree2.rename_one('a', 'd/e/a')
870
876
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
877
# d is new, d/e is b-id renamed, d/e/a is a-id renamed
872
878
root_id = tree1.path2id('')
873
879
self.assertEqualIterChanges(
874
880
[self.renamed(tree1, tree2, tree1.path2id('b'), False),
875
881
self.added(tree2, b'd-id'),
876
882
self.renamed(tree1, tree2, b'a-id', False)],
877
self.do_iter_changes(tree1, tree2, specific_files=['d/e/a']))
883
self.do_iter_changes(tree1, tree2, specific_files=['d/e/a']))
879
885
def test_specific_old_parent_same_path_new_parent(self):
880
886
# when a parent is new at its path, if the path was used in the source
893
899
[self.deleted(tree1, b'a-id'),
894
900
self.added(tree2, b'b-id'),
895
901
self.added(tree2, b'c-id')],
896
self.do_iter_changes(tree1, tree2, specific_files=['a/c']))
902
self.do_iter_changes(tree1, tree2, specific_files=['a/c']))
898
904
def test_specific_old_parent_becomes_file(self):
899
905
# When an old parent included because of a path conflict becomes a
916
922
self.added(tree2, b'a-new-id'),
917
923
self.renamed(tree1, tree2, b'reparented-id', False),
918
924
self.deleted(tree1, b'deleted-id')],
919
self.do_iter_changes(tree1, tree2,
920
specific_files=['a/reparented']))
925
self.do_iter_changes(tree1, tree2,
926
specific_files=['a/reparented']))
922
928
def test_specific_old_parent_is_deleted(self):
923
929
# When an old parent included because of a path conflict is removed,
938
944
self.added(tree2, b'a-new-id'),
939
945
self.renamed(tree1, tree2, b'reparented-id', False),
940
946
self.deleted(tree1, b'deleted-id')],
941
self.do_iter_changes(tree1, tree2,
942
specific_files=['a/reparented']))
947
self.do_iter_changes(tree1, tree2,
948
specific_files=['a/reparented']))
944
950
def test_specific_old_parent_child_collides_with_unselected_new(self):
945
951
# When the child of an old parent because of a path conflict becomes a
964
970
self.renamed(tree1, tree2, b'reparented-id', False),
965
971
self.deleted(tree1, b'collides-id'),
966
972
self.added(tree2, b'selected-id')],
967
self.do_iter_changes(tree1, tree2,
968
specific_files=['a/selected']))
973
self.do_iter_changes(tree1, tree2,
974
specific_files=['a/selected']))
970
976
def test_specific_old_parent_child_dir_stops_being_dir(self):
971
977
# When the child of an old parent also stops being a directory, its
994
1000
self.renamed(tree1, tree2, b'reparented-id-2', False),
995
1001
self.deleted(tree1, b'deleted-id-1'),
996
1002
self.deleted(tree1, b'deleted-id-2')],
997
self.do_iter_changes(tree1, tree2,
998
specific_files=['a/reparented']))
1003
self.do_iter_changes(tree1, tree2,
1004
specific_files=['a/reparented']))
1000
1006
def test_file_rename_and_meta_modification(self):
1001
1007
tree1 = self.make_branch_and_tree('1')
1016
1022
# In bug 438569, a file becoming a fifo causes an assert. Fifo's are
1017
1023
# 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
1024
# are detected (because we don't know how far through the code the
1025
# assumption 'fifo's do not exist' goes). In future we could report
1020
1026
# the kind change and have commit refuse to go futher, or something
1021
1027
# similar. One particular reason for choosing this approach is that
1022
# there is no minikind for 'fifo' in dirstate today, so we can't
1028
# there is no minikind for 'fifo' in dirstate today, so we can't
1023
1029
# actually update records that way.
1024
1030
# To add confusion, the totally generic code path works - but it
1025
1031
# doesn't update persistent metadata. So this test permits InterTrees
1090
1096
self.not_applicable_if_missing_in('file', tree1)
1091
1097
root_id = tree1.path2id('')
1092
1098
expected = [(b'file-id', ('file', None), False, (True, False),
1093
(root_id, None), ('file', None), (None, None), (False, None))]
1099
(root_id, None), ('file', None), (None, None), (False, None))]
1094
1100
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
1096
1102
def test_only_in_target_and_missing(self):
1104
1110
self.not_applicable_if_missing_in('file', tree2)
1105
1111
root_id = tree1.path2id('')
1106
1112
expected = [(b'file-id', (None, 'file'), False, (False, True),
1107
(None, root_id), (None, 'file'), (None, None), (None, False))]
1113
(None, root_id), (None, 'file'), (None, None), (None, False))]
1108
1114
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
1110
1116
def test_only_in_target_missing_subtree_specific_bug_367632(self):
1120
1126
root_id = tree1.path2id('')
1122
1128
(b'dir-id', (None, 'a-dir'), False, (False, True),
1123
(None, root_id), (None, 'a-dir'), (None, None), (None, False)),
1129
(None, root_id), (None, 'a-dir'), (None, None), (None, False)),
1124
1130
(b'file-id', (None, 'a-dir/a-file'), False, (False, True),
1125
(None, b'dir-id'), (None, 'a-file'), (None, None), (None, False))
1131
(None, b'dir-id'), (None, 'a-file'), (None, None), (None, False))
1127
1133
# bug 367632 showed that specifying the root broke some code paths,
1128
1134
# so we check this contract with and without it.
1129
1135
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
1130
1136
self.assertEqual(expected,
1131
self.do_iter_changes(tree1, tree2, specific_files=['']))
1137
self.do_iter_changes(tree1, tree2, specific_files=['']))
1133
1139
def test_unchanged_with_renames_and_modifications(self):
1134
1140
"""want_unchanged should generate a list of unchanged entries."""
1138
1144
tree2 = self.get_tree_no_parents_abc_content_5(tree2)
1139
1145
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1140
1146
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))
1147
self.unchanged(tree1, b'b-id'),
1148
(b'a-id', ('a', 'd'), True, (True, True),
1149
(b'root-id', b'root-id'), ('a',
1150
'd'), ('file', 'file'),
1151
(False, False)), self.unchanged(tree1, b'c-id')]),
1152
self.do_iter_changes(tree1, tree2, include_unchanged=True))
1147
1154
def test_compare_subtrees(self):
1148
1155
tree1 = self.make_branch_and_tree('1')
1181
1188
('sub', 'sub'),
1182
1189
('tree-reference', 'tree-reference'),
1183
1190
(False, False))],
1184
list(tree2.iter_changes(tree1,
1185
include_unchanged=True)))
1191
list(tree2.iter_changes(tree1,
1192
include_unchanged=True)))
1187
1194
def test_disk_in_subtrees_skipped(self):
1188
1195
"""subtrees are considered not-in-the-current-tree.
1205
1212
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1206
1213
# this should filter correctly from above
1207
1214
self.assertEqual([self.added(tree2, b'subtree-id')],
1208
self.do_iter_changes(tree1, tree2, want_unversioned=True))
1215
self.do_iter_changes(tree1, tree2, want_unversioned=True))
1209
1216
# and when the path is named
1210
1217
self.assertEqual([self.added(tree2, b'subtree-id')],
1211
self.do_iter_changes(tree1, tree2, specific_files=['sub'],
1212
want_unversioned=True))
1218
self.do_iter_changes(tree1, tree2, specific_files=['sub'],
1219
want_unversioned=True))
1214
1221
def test_default_ignores_unversioned_files(self):
1215
1222
tree1 = self.make_branch_and_tree('tree1')
1251
1258
expected.append(self.unversioned(tree2, 'link'))
1252
1259
expected = self.sorted(expected)
1253
1260
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
1254
want_unversioned=True))
1261
want_unversioned=True))
1256
1263
def test_unversioned_paths_in_tree_specific_files(self):
1257
1264
tree1 = self.make_branch_and_tree('tree1')
1268
1275
self.unversioned(tree2, 'file'),
1269
1276
self.unversioned(tree2, 'dir'),
1271
specific_files=['file', 'dir']
1278
specific_files = ['file', 'dir']
1272
1279
if links_supported:
1273
1280
expected.append(self.unversioned(tree2, 'link'))
1274
1281
specific_files.append('link')
1275
1282
expected = self.sorted(expected)
1276
1283
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
1277
specific_files=specific_files, require_versioned=False,
1278
want_unversioned=True))
1284
specific_files=specific_files, require_versioned=False,
1285
want_unversioned=True))
1280
1287
def test_unversioned_paths_in_target_matching_source_old_names(self):
1281
1288
# its likely that naive implementations of unversioned file support
1289
1296
tree2 = self.make_to_branch_and_tree('tree2')
1290
1297
tree2.set_root_id(tree1.get_root_id())
1291
1298
self.build_tree(['tree2/file', 'tree2/dir/',
1292
'tree1/file', 'tree2/movedfile',
1293
'tree1/dir/', 'tree2/moveddir/'])
1299
'tree1/file', 'tree2/movedfile',
1300
'tree1/dir/', 'tree2/moveddir/'])
1294
1301
if has_symlinks():
1295
1302
os.symlink('target', 'tree1/link')
1296
1303
os.symlink('target', 'tree2/link')
1312
1319
self.unversioned(tree2, 'file'),
1313
1320
self.unversioned(tree2, 'dir'),
1315
specific_files=['file', 'dir']
1322
specific_files = ['file', 'dir']
1316
1323
if links_supported:
1317
1324
expected.append(self.renamed(tree1, tree2, b'link-id', False))
1318
1325
expected.append(self.unversioned(tree2, 'link'))
1321
1328
# run once with, and once without specific files, to catch
1322
1329
# potentially different code paths.
1323
1330
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
1324
require_versioned=False,
1325
want_unversioned=True))
1331
require_versioned=False,
1332
want_unversioned=True))
1326
1333
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
1327
specific_files=specific_files, require_versioned=False,
1328
want_unversioned=True))
1334
specific_files=specific_files, require_versioned=False,
1335
want_unversioned=True))
1330
1337
def test_similar_filenames(self):
1331
1338
"""Test when we have a few files with similar names."""
1347
1354
'tree2/a/b/c/d/',
1349
1356
'tree2/a-c/e/',
1351
1358
tree1.add(['a', 'a/b', 'a/b/c', 'a/b/c/d', 'a-c', 'a-c/e'],
1352
1359
[b'a-id', b'b-id', b'c-id', b'd-id', b'a-c-id', b'e-id'])
1353
1360
tree2.add(['a', 'a/b', 'a/b/c', 'a/b/c/d', 'a-c', 'a-c/e'],
1384
1390
self.unversioned(tree2, 'dir'),
1386
1392
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
1387
want_unversioned=True))
1393
want_unversioned=True))
1389
1395
def make_trees_with_symlinks(self):
1390
1396
tree1 = self.make_branch_and_tree('tree1')
1399
1405
# we make the unchanged link point at unknown to catch incorrect
1400
1406
# symlink-following code in the specified_files test.
1401
1407
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')
1408
os.symlink('new', 'tree2/added')
1409
os.symlink('new', 'tree2/changed')
1410
os.symlink('new', 'tree2/fromfile')
1411
os.symlink('new', 'tree2/fromdir')
1406
1412
os.symlink('unknown', 'tree2/unchanged')
1407
1413
from_paths_and_ids = [
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])
1431
tree1.add(from_paths_and_ids, [p.encode('utf-8')
1432
for p in from_paths_and_ids])
1433
tree2.add(to_paths_and_ids, [p.encode('utf-8')
1434
for p in to_paths_and_ids])
1427
1435
return self.mutable_trees_to_locked_test_trees(tree1, tree2)
1429
1437
def test_versioned_symlinks(self):
1446
1454
expected = self.sorted(expected)
1447
1455
self.assertEqual(expected,
1448
self.do_iter_changes(tree1, tree2, include_unchanged=True,
1449
want_unversioned=True))
1456
self.do_iter_changes(tree1, tree2, include_unchanged=True,
1457
want_unversioned=True))
1450
1458
self.check_has_changes(True, tree1, tree2)
1452
1460
def test_versioned_symlinks_specific_files(self):
1467
1475
# make sure that it is correctly not returned - and neither is the
1468
1476
# unknown path 'unknown' which it points at.
1469
1477
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
1470
specific_files=['added', 'changed', 'fromdir', 'fromfile',
1471
'removed', 'unchanged', 'todir', 'tofile']))
1478
specific_files=['added', 'changed', 'fromdir', 'fromfile',
1479
'removed', 'unchanged', 'todir', 'tofile']))
1472
1480
self.check_has_changes(True, tree1, tree2)
1474
1482
def test_tree_with_special_names(self):
1480
1488
def test_trees_with_special_names(self):
1481
1489
tree1, tree2, paths, path_ids = self.make_trees_with_special_names()
1482
1490
expected = self.sorted(self.content_changed(tree2, f_id) for f_id in path_ids
1483
if f_id.endswith(b'_f-id'))
1491
if f_id.endswith(b'_f-id'))
1484
1492
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
1485
1493
self.check_has_changes(True, tree1, tree2)
1506
1514
self.deleted(tree1, b'e-id'),
1508
1516
self.assertEqualIterChanges(expected,
1509
self.do_iter_changes(tree1, tree2))
1517
self.do_iter_changes(tree1, tree2))
1510
1518
self.check_has_changes(True, tree1, tree2)
1512
1520
def test_added_unicode(self):
1523
1531
self.build_tree([u'tree1/\u03b1/',
1524
1532
u'tree2/\u03b1/',
1525
1533
u'tree2/\u03b1/\u03c9-added',
1527
1535
except UnicodeError:
1528
1536
raise tests.TestSkipped("Could not create Unicode files.")
1529
1537
tree1.add([u'\u03b1'], [a_id])
1552
1560
self.build_tree([u'tree1/\u03b1/',
1553
1561
u'tree1/\u03b1/\u03c9-deleted',
1554
1562
u'tree2/\u03b1/',
1556
1564
except UnicodeError:
1557
1565
raise tests.TestSkipped("Could not create Unicode files.")
1558
1566
tree1.add([u'\u03b1', u'\u03b1/\u03c9-deleted'], [a_id, deleted_id])
1582
1590
u'tree1/\u03b1/\u03c9-modified',
1583
1591
u'tree2/\u03b1/',
1584
1592
u'tree2/\u03b1/\u03c9-modified',
1586
1594
except UnicodeError:
1587
1595
raise tests.TestSkipped("Could not create Unicode files.")
1588
1596
tree1.add([u'\u03b1', u'\u03b1/\u03c9-modified'], [a_id, mod_id])
1611
1619
self.build_tree([u'tree1/\u03b1/',
1612
1620
u'tree2/\u03b1/',
1614
1622
except UnicodeError:
1615
1623
raise tests.TestSkipped("Could not create Unicode files.")
1616
1624
self.build_tree_contents([(u'tree1/\u03c9-source', b'contents\n'),
1617
1625
(u'tree2/\u03b1/\u03c9-target', b'contents\n'),
1619
1627
tree1.add([u'\u03b1', u'\u03c9-source'], [a_id, rename_id])
1620
1628
tree2.add([u'\u03b1', u'\u03b1/\u03c9-target'], [a_id, rename_id])
1673
1681
self.unchanged(tree1, subfile_id),
1675
1683
self.assertEqual(expected,
1676
self.do_iter_changes(tree1, tree2, specific_files=[u'\u03b1'],
1677
include_unchanged=True))
1684
self.do_iter_changes(tree1, tree2, specific_files=[u'\u03b1'],
1685
include_unchanged=True))
1679
1687
def test_unknown_unicode(self):
1680
1688
tree1 = self.make_branch_and_tree('tree1')
1691
1699
u'tree2/\u03b1/unknown_file',
1692
1700
u'tree2/\u03b1/unknown_dir/file',
1693
1701
u'tree2/\u03c9-unknown_root_file',
1695
1703
except UnicodeError:
1696
1704
raise tests.TestSkipped("Could not create Unicode files.")
1697
1705
tree1.add([u'\u03b1'], [a_id])
1712
1720
self.do_iter_changes(tree1, tree2,
1713
1721
require_versioned=False,
1714
1722
want_unversioned=True))
1715
self.assertEqual([], # Without want_unversioned we should get nothing
1723
self.assertEqual([], # Without want_unversioned we should get nothing
1716
1724
self.do_iter_changes(tree1, tree2))
1717
1725
self.check_has_changes(False, tree1, tree2)
1726
1734
specific_files=[u'\u03b1'],
1727
1735
require_versioned=False,
1728
1736
want_unversioned=True))
1729
self.assertEqual([], # Without want_unversioned we should get nothing
1737
self.assertEqual([], # Without want_unversioned we should get nothing
1730
1738
self.do_iter_changes(tree1, tree2,
1731
1739
specific_files=[u'\u03b1']))
1747
1755
# Now create some unknowns in tree2
1748
1756
# We should find both a/file and a/dir as unknown, but we shouldn't
1749
1757
# 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'])
1759
['tree2/a/file', 'tree2/a/dir/', 'tree2/a/dir/subfile'])
1752
1761
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1753
1762
self.not_applicable_if_cannot_represent_unversioned(tree2)
1857
1866
('tree2/d', b'c contents\n'),
1859
1868
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'])
1869
tree2.add(['a', 'b', 'c', 'd'], [
1870
b'b1-id', b'b2-id', b'c2-id', b'c1-id'])
1862
1872
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)