185
255
transform3.delete_contents(oz_id)
186
256
self.assertEqual(transform3.find_conflicts(),
187
257
[('missing parent', oz_id)])
188
root_id = transform3.trans_id_tree_file_id('TREE_ROOT')
258
root_id = transform3.root
189
259
tip_id = transform3.trans_id_tree_file_id('tip-id')
190
260
transform3.adjust_path('tip', root_id, tip_id)
191
261
transform3.apply()
263
def test_conflict_on_case_insensitive(self):
264
tree = self.make_branch_and_tree('tree')
265
# Don't try this at home, kids!
266
# Force the tree to report that it is case sensitive, for conflict
268
tree.case_sensitive = True
269
transform = TreeTransform(tree)
270
self.addCleanup(transform.finalize)
271
transform.new_file('file', transform.root, 'content')
272
transform.new_file('FiLe', transform.root, 'content')
273
result = transform.find_conflicts()
274
self.assertEqual([], result)
276
# Force the tree to report that it is case insensitive, for conflict
278
tree.case_sensitive = False
279
transform = TreeTransform(tree)
280
self.addCleanup(transform.finalize)
281
transform.new_file('file', transform.root, 'content')
282
transform.new_file('FiLe', transform.root, 'content')
283
result = transform.find_conflicts()
284
self.assertEqual([('duplicate', 'new-1', 'new-2', 'file')], result)
286
def test_conflict_on_case_insensitive_existing(self):
287
tree = self.make_branch_and_tree('tree')
288
self.build_tree(['tree/FiLe'])
289
# Don't try this at home, kids!
290
# Force the tree to report that it is case sensitive, for conflict
292
tree.case_sensitive = True
293
transform = TreeTransform(tree)
294
self.addCleanup(transform.finalize)
295
transform.new_file('file', transform.root, 'content')
296
result = transform.find_conflicts()
297
self.assertEqual([], result)
299
# Force the tree to report that it is case insensitive, for conflict
301
tree.case_sensitive = False
302
transform = TreeTransform(tree)
303
self.addCleanup(transform.finalize)
304
transform.new_file('file', transform.root, 'content')
305
result = transform.find_conflicts()
306
self.assertEqual([('duplicate', 'new-1', 'new-2', 'file')], result)
308
def test_resolve_case_insensitive_conflict(self):
309
tree = self.make_branch_and_tree('tree')
310
# Don't try this at home, kids!
311
# Force the tree to report that it is case insensitive, for conflict
313
tree.case_sensitive = False
314
transform = TreeTransform(tree)
315
self.addCleanup(transform.finalize)
316
transform.new_file('file', transform.root, 'content')
317
transform.new_file('FiLe', transform.root, 'content')
318
resolve_conflicts(transform)
320
self.failUnlessExists('tree/file')
321
self.failUnlessExists('tree/FiLe.moved')
323
def test_resolve_checkout_case_conflict(self):
324
tree = self.make_branch_and_tree('tree')
325
# Don't try this at home, kids!
326
# Force the tree to report that it is case insensitive, for conflict
328
tree.case_sensitive = False
329
transform = TreeTransform(tree)
330
self.addCleanup(transform.finalize)
331
transform.new_file('file', transform.root, 'content')
332
transform.new_file('FiLe', transform.root, 'content')
333
resolve_conflicts(transform,
334
pass_func=lambda t, c: resolve_checkout(t, c, []))
336
self.failUnlessExists('tree/file')
337
self.failUnlessExists('tree/FiLe.moved')
339
def test_apply_case_conflict(self):
340
"""Ensure that a transform with case conflicts can always be applied"""
341
tree = self.make_branch_and_tree('tree')
342
transform = TreeTransform(tree)
343
self.addCleanup(transform.finalize)
344
transform.new_file('file', transform.root, 'content')
345
transform.new_file('FiLe', transform.root, 'content')
346
dir = transform.new_directory('dir', transform.root)
347
transform.new_file('dirfile', dir, 'content')
348
transform.new_file('dirFiLe', dir, 'content')
349
resolve_conflicts(transform)
351
self.failUnlessExists('tree/file')
352
if not os.path.exists('tree/FiLe.moved'):
353
self.failUnlessExists('tree/FiLe')
354
self.failUnlessExists('tree/dir/dirfile')
355
if not os.path.exists('tree/dir/dirFiLe.moved'):
356
self.failUnlessExists('tree/dir/dirFiLe')
358
def test_case_insensitive_limbo(self):
359
tree = self.make_branch_and_tree('tree')
360
# Don't try this at home, kids!
361
# Force the tree to report that it is case insensitive
362
tree.case_sensitive = False
363
transform = TreeTransform(tree)
364
self.addCleanup(transform.finalize)
365
dir = transform.new_directory('dir', transform.root)
366
first = transform.new_file('file', dir, 'content')
367
second = transform.new_file('FiLe', dir, 'content')
368
self.assertContainsRe(transform._limbo_name(first), 'new-1/file')
369
self.assertNotContainsRe(transform._limbo_name(second), 'new-1/FiLe')
193
371
def test_add_del(self):
194
372
start, root = self.get_transform()
195
373
start.new_directory('a', root, 'a')
479
747
rename.set_executability(True, myfile)
482
def test_find_interesting(self):
483
create, root = self.get_transform()
485
create.new_file('vfile', root, 'myfile-text', 'myfile-id')
486
create.new_file('uvfile', root, 'othertext')
488
self.assertEqual(find_interesting(wt, wt, ['vfile']),
490
self.assertRaises(NotVersionedError, find_interesting, wt, wt,
750
def test_set_executability_order(self):
751
"""Ensure that executability behaves the same, no matter what order.
753
- create file and set executability simultaneously
754
- create file and set executability afterward
755
- unsetting the executability of a file whose executability has not been
756
declared should throw an exception (this may happen when a
757
merge attempts to create a file with a duplicate ID)
759
transform, root = self.get_transform()
762
self.addCleanup(wt.unlock)
763
transform.new_file('set_on_creation', root, 'Set on creation', 'soc',
765
sac = transform.new_file('set_after_creation', root,
766
'Set after creation', 'sac')
767
transform.set_executability(True, sac)
768
uws = transform.new_file('unset_without_set', root, 'Unset badly',
770
self.assertRaises(KeyError, transform.set_executability, None, uws)
772
self.assertTrue(wt.is_executable('soc'))
773
self.assertTrue(wt.is_executable('sac'))
775
def test_preserve_mode(self):
776
"""File mode is preserved when replacing content"""
777
if sys.platform == 'win32':
778
raise TestSkipped('chmod has no effect on win32')
779
transform, root = self.get_transform()
780
transform.new_file('file1', root, 'contents', 'file1-id', True)
783
self.addCleanup(self.wt.unlock)
784
self.assertTrue(self.wt.is_executable('file1-id'))
785
transform, root = self.get_transform()
786
file1_id = transform.trans_id_tree_file_id('file1-id')
787
transform.delete_contents(file1_id)
788
transform.create_file('contents2', file1_id)
790
self.assertTrue(self.wt.is_executable('file1-id'))
792
def test__set_mode_stats_correctly(self):
793
"""_set_mode stats to determine file mode."""
794
if sys.platform == 'win32':
795
raise TestSkipped('chmod has no effect on win32')
799
def instrumented_stat(path):
800
stat_paths.append(path)
801
return real_stat(path)
803
transform, root = self.get_transform()
805
bar1_id = transform.new_file('bar', root, 'bar contents 1\n',
806
file_id='bar-id-1', executable=False)
809
transform, root = self.get_transform()
810
bar1_id = transform.trans_id_tree_path('bar')
811
bar2_id = transform.trans_id_tree_path('bar2')
813
os.stat = instrumented_stat
814
transform.create_file('bar2 contents\n', bar2_id, mode_id=bar1_id)
819
bar1_abspath = self.wt.abspath('bar')
820
self.assertEqual([bar1_abspath], stat_paths)
822
def test_iter_changes(self):
823
self.wt.set_root_id('eert_toor')
824
transform, root = self.get_transform()
825
transform.new_file('old', root, 'blah', 'id-1', True)
827
transform, root = self.get_transform()
829
self.assertEqual([], list(transform.iter_changes()))
830
old = transform.trans_id_tree_file_id('id-1')
831
transform.unversion_file(old)
832
self.assertEqual([('id-1', ('old', None), False, (True, False),
833
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
834
(True, True))], list(transform.iter_changes()))
835
transform.new_directory('new', root, 'id-1')
836
self.assertEqual([('id-1', ('old', 'new'), True, (True, True),
837
('eert_toor', 'eert_toor'), ('old', 'new'),
838
('file', 'directory'),
839
(True, False))], list(transform.iter_changes()))
843
def test_iter_changes_new(self):
844
self.wt.set_root_id('eert_toor')
845
transform, root = self.get_transform()
846
transform.new_file('old', root, 'blah')
848
transform, root = self.get_transform()
850
old = transform.trans_id_tree_path('old')
851
transform.version_file('id-1', old)
852
self.assertEqual([('id-1', (None, 'old'), False, (False, True),
853
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
854
(False, False))], list(transform.iter_changes()))
858
def test_iter_changes_modifications(self):
859
self.wt.set_root_id('eert_toor')
860
transform, root = self.get_transform()
861
transform.new_file('old', root, 'blah', 'id-1')
862
transform.new_file('new', root, 'blah')
863
transform.new_directory('subdir', root, 'subdir-id')
865
transform, root = self.get_transform()
867
old = transform.trans_id_tree_path('old')
868
subdir = transform.trans_id_tree_file_id('subdir-id')
869
new = transform.trans_id_tree_path('new')
870
self.assertEqual([], list(transform.iter_changes()))
873
transform.delete_contents(old)
874
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
875
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', None),
876
(False, False))], list(transform.iter_changes()))
879
transform.create_file('blah', old)
880
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
881
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
882
(False, False))], list(transform.iter_changes()))
883
transform.cancel_deletion(old)
884
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
885
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
886
(False, False))], list(transform.iter_changes()))
887
transform.cancel_creation(old)
889
# move file_id to a different file
890
self.assertEqual([], list(transform.iter_changes()))
891
transform.unversion_file(old)
892
transform.version_file('id-1', new)
893
transform.adjust_path('old', root, new)
894
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
895
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
896
(False, False))], list(transform.iter_changes()))
897
transform.cancel_versioning(new)
898
transform._removed_id = set()
901
self.assertEqual([], list(transform.iter_changes()))
902
transform.set_executability(True, old)
903
self.assertEqual([('id-1', ('old', 'old'), False, (True, True),
904
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
905
(False, True))], list(transform.iter_changes()))
906
transform.set_executability(None, old)
909
self.assertEqual([], list(transform.iter_changes()))
910
transform.adjust_path('new', root, old)
911
transform._new_parent = {}
912
self.assertEqual([('id-1', ('old', 'new'), False, (True, True),
913
('eert_toor', 'eert_toor'), ('old', 'new'), ('file', 'file'),
914
(False, False))], list(transform.iter_changes()))
915
transform._new_name = {}
918
self.assertEqual([], list(transform.iter_changes()))
919
transform.adjust_path('new', subdir, old)
920
transform._new_name = {}
921
self.assertEqual([('id-1', ('old', 'subdir/old'), False,
922
(True, True), ('eert_toor', 'subdir-id'), ('old', 'old'),
923
('file', 'file'), (False, False))],
924
list(transform.iter_changes()))
925
transform._new_path = {}
930
def test_iter_changes_modified_bleed(self):
931
self.wt.set_root_id('eert_toor')
932
"""Modified flag should not bleed from one change to another"""
933
# unfortunately, we have no guarantee that file1 (which is modified)
934
# will be applied before file2. And if it's applied after file2, it
935
# obviously can't bleed into file2's change output. But for now, it
937
transform, root = self.get_transform()
938
transform.new_file('file1', root, 'blah', 'id-1')
939
transform.new_file('file2', root, 'blah', 'id-2')
941
transform, root = self.get_transform()
943
transform.delete_contents(transform.trans_id_file_id('id-1'))
944
transform.set_executability(True,
945
transform.trans_id_file_id('id-2'))
946
self.assertEqual([('id-1', (u'file1', u'file1'), True, (True, True),
947
('eert_toor', 'eert_toor'), ('file1', u'file1'),
948
('file', None), (False, False)),
949
('id-2', (u'file2', u'file2'), False, (True, True),
950
('eert_toor', 'eert_toor'), ('file2', u'file2'),
951
('file', 'file'), (False, True))],
952
list(transform.iter_changes()))
956
def test_iter_changes_move_missing(self):
957
"""Test moving ids with no files around"""
958
self.wt.set_root_id('toor_eert')
959
# Need two steps because versioning a non-existant file is a conflict.
960
transform, root = self.get_transform()
961
transform.new_directory('floater', root, 'floater-id')
963
transform, root = self.get_transform()
964
transform.delete_contents(transform.trans_id_tree_path('floater'))
966
transform, root = self.get_transform()
967
floater = transform.trans_id_tree_path('floater')
969
transform.adjust_path('flitter', root, floater)
970
self.assertEqual([('floater-id', ('floater', 'flitter'), False,
971
(True, True), ('toor_eert', 'toor_eert'), ('floater', 'flitter'),
972
(None, None), (False, False))], list(transform.iter_changes()))
976
def test_iter_changes_pointless(self):
977
"""Ensure that no-ops are not treated as modifications"""
978
self.wt.set_root_id('eert_toor')
979
transform, root = self.get_transform()
980
transform.new_file('old', root, 'blah', 'id-1')
981
transform.new_directory('subdir', root, 'subdir-id')
983
transform, root = self.get_transform()
985
old = transform.trans_id_tree_path('old')
986
subdir = transform.trans_id_tree_file_id('subdir-id')
987
self.assertEqual([], list(transform.iter_changes()))
988
transform.delete_contents(subdir)
989
transform.create_directory(subdir)
990
transform.set_executability(False, old)
991
transform.unversion_file(old)
992
transform.version_file('id-1', old)
993
transform.adjust_path('old', root, old)
994
self.assertEqual([], list(transform.iter_changes()))
998
def test_rename_count(self):
999
transform, root = self.get_transform()
1000
transform.new_file('name1', root, 'contents')
1001
self.assertEqual(transform.rename_count, 0)
1003
self.assertEqual(transform.rename_count, 1)
1004
transform2, root = self.get_transform()
1005
transform2.adjust_path('name2', root,
1006
transform2.trans_id_tree_path('name1'))
1007
self.assertEqual(transform2.rename_count, 0)
1009
self.assertEqual(transform2.rename_count, 2)
1011
def test_change_parent(self):
1012
"""Ensure that after we change a parent, the results are still right.
1014
Renames and parent changes on pending transforms can happen as part
1015
of conflict resolution, and are explicitly permitted by the
1018
This test ensures they work correctly with the rename-avoidance
1021
transform, root = self.get_transform()
1022
parent1 = transform.new_directory('parent1', root)
1023
child1 = transform.new_file('child1', parent1, 'contents')
1024
parent2 = transform.new_directory('parent2', root)
1025
transform.adjust_path('child1', parent2, child1)
1027
self.failIfExists(self.wt.abspath('parent1/child1'))
1028
self.failUnlessExists(self.wt.abspath('parent2/child1'))
1029
# rename limbo/new-1 => parent1, rename limbo/new-3 => parent2
1030
# no rename for child1 (counting only renames during apply)
1031
self.failUnlessEqual(2, transform.rename_count)
1033
def test_cancel_parent(self):
1034
"""Cancelling a parent doesn't cause deletion of a non-empty directory
1036
This is like the test_change_parent, except that we cancel the parent
1037
before adjusting the path. The transform must detect that the
1038
directory is non-empty, and move children to safe locations.
1040
transform, root = self.get_transform()
1041
parent1 = transform.new_directory('parent1', root)
1042
child1 = transform.new_file('child1', parent1, 'contents')
1043
child2 = transform.new_file('child2', parent1, 'contents')
1045
transform.cancel_creation(parent1)
1047
self.fail('Failed to move child1 before deleting parent1')
1048
transform.cancel_creation(child2)
1049
transform.create_directory(parent1)
1051
transform.cancel_creation(parent1)
1052
# If the transform incorrectly believes that child2 is still in
1053
# parent1's limbo directory, it will try to rename it and fail
1054
# because was already moved by the first cancel_creation.
1056
self.fail('Transform still thinks child2 is a child of parent1')
1057
parent2 = transform.new_directory('parent2', root)
1058
transform.adjust_path('child1', parent2, child1)
1060
self.failIfExists(self.wt.abspath('parent1'))
1061
self.failUnlessExists(self.wt.abspath('parent2/child1'))
1062
# rename limbo/new-3 => parent2, rename limbo/new-2 => child1
1063
self.failUnlessEqual(2, transform.rename_count)
1065
def test_adjust_and_cancel(self):
1066
"""Make sure adjust_path keeps track of limbo children properly"""
1067
transform, root = self.get_transform()
1068
parent1 = transform.new_directory('parent1', root)
1069
child1 = transform.new_file('child1', parent1, 'contents')
1070
parent2 = transform.new_directory('parent2', root)
1071
transform.adjust_path('child1', parent2, child1)
1072
transform.cancel_creation(child1)
1074
transform.cancel_creation(parent1)
1075
# if the transform thinks child1 is still in parent1's limbo
1076
# directory, it will attempt to move it and fail.
1078
self.fail('Transform still thinks child1 is a child of parent1')
1079
transform.finalize()
1081
def test_noname_contents(self):
1082
"""TreeTransform should permit deferring naming files."""
1083
transform, root = self.get_transform()
1084
parent = transform.trans_id_file_id('parent-id')
1086
transform.create_directory(parent)
1088
self.fail("Can't handle contents with no name")
1089
transform.finalize()
1091
def test_noname_contents_nested(self):
1092
"""TreeTransform should permit deferring naming files."""
1093
transform, root = self.get_transform()
1094
parent = transform.trans_id_file_id('parent-id')
1096
transform.create_directory(parent)
1098
self.fail("Can't handle contents with no name")
1099
child = transform.new_directory('child', parent)
1100
transform.adjust_path('parent', root, parent)
1102
self.failUnlessExists(self.wt.abspath('parent/child'))
1103
self.assertEqual(1, transform.rename_count)
1105
def test_reuse_name(self):
1106
"""Avoid reusing the same limbo name for different files"""
1107
transform, root = self.get_transform()
1108
parent = transform.new_directory('parent', root)
1109
child1 = transform.new_directory('child', parent)
1111
child2 = transform.new_directory('child', parent)
1113
self.fail('Tranform tried to use the same limbo name twice')
1114
transform.adjust_path('child2', parent, child2)
1116
# limbo/new-1 => parent, limbo/new-3 => parent/child2
1117
# child2 is put into top-level limbo because child1 has already
1118
# claimed the direct limbo path when child2 is created. There is no
1119
# advantage in renaming files once they're in top-level limbo, except
1121
self.assertEqual(2, transform.rename_count)
1123
def test_reuse_when_first_moved(self):
1124
"""Don't avoid direct paths when it is safe to use them"""
1125
transform, root = self.get_transform()
1126
parent = transform.new_directory('parent', root)
1127
child1 = transform.new_directory('child', parent)
1128
transform.adjust_path('child1', parent, child1)
1129
child2 = transform.new_directory('child', parent)
1131
# limbo/new-1 => parent
1132
self.assertEqual(1, transform.rename_count)
1134
def test_reuse_after_cancel(self):
1135
"""Don't avoid direct paths when it is safe to use them"""
1136
transform, root = self.get_transform()
1137
parent2 = transform.new_directory('parent2', root)
1138
child1 = transform.new_directory('child1', parent2)
1139
transform.cancel_creation(parent2)
1140
transform.create_directory(parent2)
1141
child2 = transform.new_directory('child1', parent2)
1142
transform.adjust_path('child2', parent2, child1)
1144
# limbo/new-1 => parent2, limbo/new-2 => parent2/child1
1145
self.assertEqual(2, transform.rename_count)
1147
def test_finalize_order(self):
1148
"""Finalize must be done in child-to-parent order"""
1149
transform, root = self.get_transform()
1150
parent = transform.new_directory('parent', root)
1151
child = transform.new_directory('child', parent)
1153
transform.finalize()
1155
self.fail('Tried to remove parent before child1')
1157
def test_cancel_with_cancelled_child_should_succeed(self):
1158
transform, root = self.get_transform()
1159
parent = transform.new_directory('parent', root)
1160
child = transform.new_directory('child', parent)
1161
transform.cancel_creation(child)
1162
transform.cancel_creation(parent)
1163
transform.finalize()
1165
def test_case_insensitive_clash(self):
1166
self.requireFeature(CaseInsensitiveFilesystemFeature)
1168
wt = self.make_branch_and_tree('.')
1169
tt = TreeTransform(wt) # TreeTransform obtains write lock
1171
tt.new_file('foo', tt.root, 'bar')
1172
tt.new_file('Foo', tt.root, 'spam')
1173
# Lie to tt that we've already resolved all conflicts.
1174
tt.apply(no_conflicts=True)
1178
err = self.assertRaises(errors.FileExists, tt_helper)
1179
self.assertContainsRe(str(err),
1180
"^File exists: .+/foo")
1182
def test_two_directories_clash(self):
1184
wt = self.make_branch_and_tree('.')
1185
tt = TreeTransform(wt) # TreeTransform obtains write lock
1187
foo_1 = tt.new_directory('foo', tt.root)
1188
tt.new_directory('bar', foo_1)
1189
foo_2 = tt.new_directory('foo', tt.root)
1190
tt.new_directory('baz', foo_2)
1191
# Lie to tt that we've already resolved all conflicts.
1192
tt.apply(no_conflicts=True)
1196
err = self.assertRaises(errors.FileExists, tt_helper)
1197
self.assertContainsRe(str(err),
1198
"^File exists: .+/foo")
1200
def test_two_directories_clash_finalize(self):
1202
wt = self.make_branch_and_tree('.')
1203
tt = TreeTransform(wt) # TreeTransform obtains write lock
1205
foo_1 = tt.new_directory('foo', tt.root)
1206
tt.new_directory('bar', foo_1)
1207
foo_2 = tt.new_directory('foo', tt.root)
1208
tt.new_directory('baz', foo_2)
1209
# Lie to tt that we've already resolved all conflicts.
1210
tt.apply(no_conflicts=True)
1214
err = self.assertRaises(errors.FileExists, tt_helper)
1215
self.assertContainsRe(str(err),
1216
"^File exists: .+/foo")
494
1219
class TransformGroup(object):
495
def __init__(self, dirname):
1221
def __init__(self, dirname, root_id):
496
1222
self.name = dirname
497
1223
os.mkdir(dirname)
498
1224
self.wt = BzrDir.create_standalone_workingtree(dirname)
1225
self.wt.set_root_id(root_id)
499
1226
self.b = self.wt.branch
500
1227
self.tt = TreeTransform(self.wt)
501
1228
self.root = self.tt.trans_id_tree_file_id(self.wt.get_root_id())
503
1231
def conflict_text(tree, merge):
504
1232
template = '%s TREE\n%s%s\n%s%s MERGE-SOURCE\n'
505
1233
return template % ('<' * 7, tree, '=' * 7, merge, '>' * 7)
508
1236
class TestTransformMerge(TestCaseInTempDir):
509
1238
def test_text_merge(self):
510
base = TransformGroup("base")
1239
root_id = generate_ids.gen_root_id()
1240
base = TransformGroup("base", root_id)
511
1241
base.tt.new_file('a', base.root, 'a\nb\nc\nd\be\n', 'a')
512
1242
base.tt.new_file('b', base.root, 'b1', 'b')
513
1243
base.tt.new_file('c', base.root, 'c', 'c')
698
1432
a.add(['foo', 'foo/bar', 'foo/baz'])
699
1433
a.commit('initial commit')
700
1434
b = BzrDir.create_standalone_workingtree('b')
701
build_tree(a.basis_tree(), b)
1435
basis = a.basis_tree()
1437
self.addCleanup(basis.unlock)
1438
build_tree(basis, b)
702
1439
self.assertIs(os.path.isdir('b/foo'), True)
703
1440
self.assertEqual(file('b/foo/bar', 'rb').read(), "contents")
704
1441
self.assertEqual(os.readlink('b/foo/baz'), 'a/foo/bar')
1443
def test_build_with_references(self):
1444
tree = self.make_branch_and_tree('source',
1445
format='dirstate-with-subtree')
1446
subtree = self.make_branch_and_tree('source/subtree',
1447
format='dirstate-with-subtree')
1448
tree.add_reference(subtree)
1449
tree.commit('a revision')
1450
tree.branch.create_checkout('target')
1451
self.failUnlessExists('target')
1452
self.failUnlessExists('target/subtree')
1454
def test_file_conflict_handling(self):
1455
"""Ensure that when building trees, conflict handling is done"""
1456
source = self.make_branch_and_tree('source')
1457
target = self.make_branch_and_tree('target')
1458
self.build_tree(['source/file', 'target/file'])
1459
source.add('file', 'new-file')
1460
source.commit('added file')
1461
build_tree(source.basis_tree(), target)
1462
self.assertEqual([DuplicateEntry('Moved existing file to',
1463
'file.moved', 'file', None, 'new-file')],
1465
target2 = self.make_branch_and_tree('target2')
1466
target_file = file('target2/file', 'wb')
1468
source_file = file('source/file', 'rb')
1470
target_file.write(source_file.read())
1475
build_tree(source.basis_tree(), target2)
1476
self.assertEqual([], target2.conflicts())
1478
def test_symlink_conflict_handling(self):
1479
"""Ensure that when building trees, conflict handling is done"""
1480
self.requireFeature(SymlinkFeature)
1481
source = self.make_branch_and_tree('source')
1482
os.symlink('foo', 'source/symlink')
1483
source.add('symlink', 'new-symlink')
1484
source.commit('added file')
1485
target = self.make_branch_and_tree('target')
1486
os.symlink('bar', 'target/symlink')
1487
build_tree(source.basis_tree(), target)
1488
self.assertEqual([DuplicateEntry('Moved existing file to',
1489
'symlink.moved', 'symlink', None, 'new-symlink')],
1491
target = self.make_branch_and_tree('target2')
1492
os.symlink('foo', 'target2/symlink')
1493
build_tree(source.basis_tree(), target)
1494
self.assertEqual([], target.conflicts())
1496
def test_directory_conflict_handling(self):
1497
"""Ensure that when building trees, conflict handling is done"""
1498
source = self.make_branch_and_tree('source')
1499
target = self.make_branch_and_tree('target')
1500
self.build_tree(['source/dir1/', 'source/dir1/file', 'target/dir1/'])
1501
source.add(['dir1', 'dir1/file'], ['new-dir1', 'new-file'])
1502
source.commit('added file')
1503
build_tree(source.basis_tree(), target)
1504
self.assertEqual([], target.conflicts())
1505
self.failUnlessExists('target/dir1/file')
1507
# Ensure contents are merged
1508
target = self.make_branch_and_tree('target2')
1509
self.build_tree(['target2/dir1/', 'target2/dir1/file2'])
1510
build_tree(source.basis_tree(), target)
1511
self.assertEqual([], target.conflicts())
1512
self.failUnlessExists('target2/dir1/file2')
1513
self.failUnlessExists('target2/dir1/file')
1515
# Ensure new contents are suppressed for existing branches
1516
target = self.make_branch_and_tree('target3')
1517
self.make_branch('target3/dir1')
1518
self.build_tree(['target3/dir1/file2'])
1519
build_tree(source.basis_tree(), target)
1520
self.failIfExists('target3/dir1/file')
1521
self.failUnlessExists('target3/dir1/file2')
1522
self.failUnlessExists('target3/dir1.diverted/file')
1523
self.assertEqual([DuplicateEntry('Diverted to',
1524
'dir1.diverted', 'dir1', 'new-dir1', None)],
1527
target = self.make_branch_and_tree('target4')
1528
self.build_tree(['target4/dir1/'])
1529
self.make_branch('target4/dir1/file')
1530
build_tree(source.basis_tree(), target)
1531
self.failUnlessExists('target4/dir1/file')
1532
self.assertEqual('directory', file_kind('target4/dir1/file'))
1533
self.failUnlessExists('target4/dir1/file.diverted')
1534
self.assertEqual([DuplicateEntry('Diverted to',
1535
'dir1/file.diverted', 'dir1/file', 'new-file', None)],
1538
def test_mixed_conflict_handling(self):
1539
"""Ensure that when building trees, conflict handling is done"""
1540
source = self.make_branch_and_tree('source')
1541
target = self.make_branch_and_tree('target')
1542
self.build_tree(['source/name', 'target/name/'])
1543
source.add('name', 'new-name')
1544
source.commit('added file')
1545
build_tree(source.basis_tree(), target)
1546
self.assertEqual([DuplicateEntry('Moved existing file to',
1547
'name.moved', 'name', None, 'new-name')], target.conflicts())
1549
def test_raises_in_populated(self):
1550
source = self.make_branch_and_tree('source')
1551
self.build_tree(['source/name'])
1553
source.commit('added name')
1554
target = self.make_branch_and_tree('target')
1555
self.build_tree(['target/name'])
1557
self.assertRaises(errors.WorkingTreeAlreadyPopulated,
1558
build_tree, source.basis_tree(), target)
1560
def test_build_tree_rename_count(self):
1561
source = self.make_branch_and_tree('source')
1562
self.build_tree(['source/file1', 'source/dir1/'])
1563
source.add(['file1', 'dir1'])
1564
source.commit('add1')
1565
target1 = self.make_branch_and_tree('target1')
1566
transform_result = build_tree(source.basis_tree(), target1)
1567
self.assertEqual(2, transform_result.rename_count)
1569
self.build_tree(['source/dir1/file2'])
1570
source.add(['dir1/file2'])
1571
source.commit('add3')
1572
target2 = self.make_branch_and_tree('target2')
1573
transform_result = build_tree(source.basis_tree(), target2)
1574
# children of non-root directories should not be renamed
1575
self.assertEqual(2, transform_result.rename_count)
1577
def create_ab_tree(self):
1578
"""Create a committed test tree with two files"""
1579
source = self.make_branch_and_tree('source')
1580
self.build_tree_contents([('source/file1', 'A')])
1581
self.build_tree_contents([('source/file2', 'B')])
1582
source.add(['file1', 'file2'], ['file1-id', 'file2-id'])
1583
source.commit('commit files')
1585
self.addCleanup(source.unlock)
1588
def test_build_tree_accelerator_tree(self):
1589
source = self.create_ab_tree()
1590
self.build_tree_contents([('source/file2', 'C')])
1592
real_source_get_file = source.get_file
1593
def get_file(file_id, path=None):
1594
calls.append(file_id)
1595
return real_source_get_file(file_id, path)
1596
source.get_file = get_file
1597
target = self.make_branch_and_tree('target')
1598
revision_tree = source.basis_tree()
1599
revision_tree.lock_read()
1600
self.addCleanup(revision_tree.unlock)
1601
build_tree(revision_tree, target, source)
1602
self.assertEqual(['file1-id'], calls)
1604
self.addCleanup(target.unlock)
1605
self.assertEqual([], list(target.iter_changes(revision_tree)))
1607
def test_build_tree_accelerator_tree_missing_file(self):
1608
source = self.create_ab_tree()
1609
os.unlink('source/file1')
1610
source.remove(['file2'])
1611
target = self.make_branch_and_tree('target')
1612
revision_tree = source.basis_tree()
1613
revision_tree.lock_read()
1614
self.addCleanup(revision_tree.unlock)
1615
build_tree(revision_tree, target, source)
1617
self.addCleanup(target.unlock)
1618
self.assertEqual([], list(target.iter_changes(revision_tree)))
1620
def test_build_tree_accelerator_wrong_kind(self):
1621
self.requireFeature(SymlinkFeature)
1622
source = self.make_branch_and_tree('source')
1623
self.build_tree_contents([('source/file1', '')])
1624
self.build_tree_contents([('source/file2', '')])
1625
source.add(['file1', 'file2'], ['file1-id', 'file2-id'])
1626
source.commit('commit files')
1627
os.unlink('source/file2')
1628
self.build_tree_contents([('source/file2/', 'C')])
1629
os.unlink('source/file1')
1630
os.symlink('file2', 'source/file1')
1632
real_source_get_file = source.get_file
1633
def get_file(file_id, path=None):
1634
calls.append(file_id)
1635
return real_source_get_file(file_id, path)
1636
source.get_file = get_file
1637
target = self.make_branch_and_tree('target')
1638
revision_tree = source.basis_tree()
1639
revision_tree.lock_read()
1640
self.addCleanup(revision_tree.unlock)
1641
build_tree(revision_tree, target, source)
1642
self.assertEqual([], calls)
1644
self.addCleanup(target.unlock)
1645
self.assertEqual([], list(target.iter_changes(revision_tree)))
1647
def test_build_tree_hardlink(self):
1648
self.requireFeature(HardlinkFeature)
1649
source = self.create_ab_tree()
1650
target = self.make_branch_and_tree('target')
1651
revision_tree = source.basis_tree()
1652
revision_tree.lock_read()
1653
self.addCleanup(revision_tree.unlock)
1654
build_tree(revision_tree, target, source, hardlink=True)
1656
self.addCleanup(target.unlock)
1657
self.assertEqual([], list(target.iter_changes(revision_tree)))
1658
source_stat = os.stat('source/file1')
1659
target_stat = os.stat('target/file1')
1660
self.assertEqual(source_stat, target_stat)
1662
# Explicitly disallowing hardlinks should prevent them.
1663
target2 = self.make_branch_and_tree('target2')
1664
build_tree(revision_tree, target2, source, hardlink=False)
1666
self.addCleanup(target2.unlock)
1667
self.assertEqual([], list(target2.iter_changes(revision_tree)))
1668
source_stat = os.stat('source/file1')
1669
target2_stat = os.stat('target2/file1')
1670
self.assertNotEqual(source_stat, target2_stat)
1672
def test_build_tree_accelerator_tree_moved(self):
1673
source = self.make_branch_and_tree('source')
1674
self.build_tree_contents([('source/file1', 'A')])
1675
source.add(['file1'], ['file1-id'])
1676
source.commit('commit files')
1677
source.rename_one('file1', 'file2')
1679
self.addCleanup(source.unlock)
1680
target = self.make_branch_and_tree('target')
1681
revision_tree = source.basis_tree()
1682
revision_tree.lock_read()
1683
self.addCleanup(revision_tree.unlock)
1684
build_tree(revision_tree, target, source)
1686
self.addCleanup(target.unlock)
1687
self.assertEqual([], list(target.iter_changes(revision_tree)))
1689
def test_build_tree_hardlinks_preserve_execute(self):
1690
self.requireFeature(HardlinkFeature)
1691
source = self.create_ab_tree()
1692
tt = TreeTransform(source)
1693
trans_id = tt.trans_id_tree_file_id('file1-id')
1694
tt.set_executability(True, trans_id)
1696
self.assertTrue(source.is_executable('file1-id'))
1697
target = self.make_branch_and_tree('target')
1698
revision_tree = source.basis_tree()
1699
revision_tree.lock_read()
1700
self.addCleanup(revision_tree.unlock)
1701
build_tree(revision_tree, target, source, hardlink=True)
1703
self.addCleanup(target.unlock)
1704
self.assertEqual([], list(target.iter_changes(revision_tree)))
1705
self.assertTrue(source.is_executable('file1-id'))
1707
def test_case_insensitive_build_tree_inventory(self):
1708
source = self.make_branch_and_tree('source')
1709
self.build_tree(['source/file', 'source/FILE'])
1710
source.add(['file', 'FILE'], ['lower-id', 'upper-id'])
1711
source.commit('added files')
1712
# Don't try this at home, kids!
1713
# Force the tree to report that it is case insensitive
1714
target = self.make_branch_and_tree('target')
1715
target.case_sensitive = False
1716
build_tree(source.basis_tree(), target, source, delta_from_tree=True)
1717
self.assertEqual('file.moved', target.id2path('lower-id'))
1718
self.assertEqual('FILE', target.id2path('upper-id'))
706
1721
class MockTransform(object):
708
1723
def has_named_child(self, by_parent, parent_id, name):
732
1749
self.assertEqual(name, 'name.~1~')
733
1750
name = get_backup_name(MockEntry(), {'a':['1', '2', '3']}, 'a', tt)
734
1751
self.assertEqual(name, 'name.~4~')
1754
class TestFileMover(tests.TestCaseWithTransport):
1756
def test_file_mover(self):
1757
self.build_tree(['a/', 'a/b', 'c/', 'c/d'])
1758
mover = _FileMover()
1759
mover.rename('a', 'q')
1760
self.failUnlessExists('q')
1761
self.failIfExists('a')
1762
self.failUnlessExists('q/b')
1763
self.failUnlessExists('c')
1764
self.failUnlessExists('c/d')
1766
def test_pre_delete_rollback(self):
1767
self.build_tree(['a/'])
1768
mover = _FileMover()
1769
mover.pre_delete('a', 'q')
1770
self.failUnlessExists('q')
1771
self.failIfExists('a')
1773
self.failIfExists('q')
1774
self.failUnlessExists('a')
1776
def test_apply_deletions(self):
1777
self.build_tree(['a/', 'b/'])
1778
mover = _FileMover()
1779
mover.pre_delete('a', 'q')
1780
mover.pre_delete('b', 'r')
1781
self.failUnlessExists('q')
1782
self.failUnlessExists('r')
1783
self.failIfExists('a')
1784
self.failIfExists('b')
1785
mover.apply_deletions()
1786
self.failIfExists('q')
1787
self.failIfExists('r')
1788
self.failIfExists('a')
1789
self.failIfExists('b')
1791
def test_file_mover_rollback(self):
1792
self.build_tree(['a/', 'a/b', 'c/', 'c/d/', 'c/e/'])
1793
mover = _FileMover()
1794
mover.rename('c/d', 'c/f')
1795
mover.rename('c/e', 'c/d')
1797
mover.rename('a', 'c')
1798
except errors.FileExists, e:
1800
self.failUnlessExists('a')
1801
self.failUnlessExists('c/d')
1804
class Bogus(Exception):
1808
class TestTransformRollback(tests.TestCaseWithTransport):
1810
class ExceptionFileMover(_FileMover):
1812
def __init__(self, bad_source=None, bad_target=None):
1813
_FileMover.__init__(self)
1814
self.bad_source = bad_source
1815
self.bad_target = bad_target
1817
def rename(self, source, target):
1818
if (self.bad_source is not None and
1819
source.endswith(self.bad_source)):
1821
elif (self.bad_target is not None and
1822
target.endswith(self.bad_target)):
1825
_FileMover.rename(self, source, target)
1827
def test_rollback_rename(self):
1828
tree = self.make_branch_and_tree('.')
1829
self.build_tree(['a/', 'a/b'])
1830
tt = TreeTransform(tree)
1831
self.addCleanup(tt.finalize)
1832
a_id = tt.trans_id_tree_path('a')
1833
tt.adjust_path('c', tt.root, a_id)
1834
tt.adjust_path('d', a_id, tt.trans_id_tree_path('a/b'))
1835
self.assertRaises(Bogus, tt.apply,
1836
_mover=self.ExceptionFileMover(bad_source='a'))
1837
self.failUnlessExists('a')
1838
self.failUnlessExists('a/b')
1840
self.failUnlessExists('c')
1841
self.failUnlessExists('c/d')
1843
def test_rollback_rename_into_place(self):
1844
tree = self.make_branch_and_tree('.')
1845
self.build_tree(['a/', 'a/b'])
1846
tt = TreeTransform(tree)
1847
self.addCleanup(tt.finalize)
1848
a_id = tt.trans_id_tree_path('a')
1849
tt.adjust_path('c', tt.root, a_id)
1850
tt.adjust_path('d', a_id, tt.trans_id_tree_path('a/b'))
1851
self.assertRaises(Bogus, tt.apply,
1852
_mover=self.ExceptionFileMover(bad_target='c/d'))
1853
self.failUnlessExists('a')
1854
self.failUnlessExists('a/b')
1856
self.failUnlessExists('c')
1857
self.failUnlessExists('c/d')
1859
def test_rollback_deletion(self):
1860
tree = self.make_branch_and_tree('.')
1861
self.build_tree(['a/', 'a/b'])
1862
tt = TreeTransform(tree)
1863
self.addCleanup(tt.finalize)
1864
a_id = tt.trans_id_tree_path('a')
1865
tt.delete_contents(a_id)
1866
tt.adjust_path('d', tt.root, tt.trans_id_tree_path('a/b'))
1867
self.assertRaises(Bogus, tt.apply,
1868
_mover=self.ExceptionFileMover(bad_target='d'))
1869
self.failUnlessExists('a')
1870
self.failUnlessExists('a/b')
1872
def test_resolve_no_parent(self):
1873
wt = self.make_branch_and_tree('.')
1874
tt = TreeTransform(wt)
1875
self.addCleanup(tt.finalize)
1876
parent = tt.trans_id_file_id('parent-id')
1877
tt.new_file('file', parent, 'Contents')
1878
resolve_conflicts(tt)
1881
class TestTransformPreview(tests.TestCaseWithTransport):
1883
def create_tree(self):
1884
tree = self.make_branch_and_tree('.')
1885
self.build_tree_contents([('a', 'content 1')])
1886
tree.add('a', 'a-id')
1887
tree.commit('rev1', rev_id='rev1')
1888
return tree.branch.repository.revision_tree('rev1')
1890
def get_empty_preview(self):
1891
repository = self.make_repository('repo')
1892
tree = repository.revision_tree(_mod_revision.NULL_REVISION)
1893
preview = TransformPreview(tree)
1894
self.addCleanup(preview.finalize)
1897
def test_transform_preview(self):
1898
revision_tree = self.create_tree()
1899
preview = TransformPreview(revision_tree)
1900
self.addCleanup(preview.finalize)
1902
def test_transform_preview_tree(self):
1903
revision_tree = self.create_tree()
1904
preview = TransformPreview(revision_tree)
1905
self.addCleanup(preview.finalize)
1906
preview.get_preview_tree()
1908
def test_transform_new_file(self):
1909
revision_tree = self.create_tree()
1910
preview = TransformPreview(revision_tree)
1911
self.addCleanup(preview.finalize)
1912
preview.new_file('file2', preview.root, 'content B\n', 'file2-id')
1913
preview_tree = preview.get_preview_tree()
1914
self.assertEqual(preview_tree.kind('file2-id'), 'file')
1916
preview_tree.get_file('file2-id').read(), 'content B\n')
1918
def test_diff_preview_tree(self):
1919
revision_tree = self.create_tree()
1920
preview = TransformPreview(revision_tree)
1921
self.addCleanup(preview.finalize)
1922
preview.new_file('file2', preview.root, 'content B\n', 'file2-id')
1923
preview_tree = preview.get_preview_tree()
1925
show_diff_trees(revision_tree, preview_tree, out)
1926
lines = out.getvalue().splitlines()
1927
self.assertEqual(lines[0], "=== added file 'file2'")
1928
# 3 lines of diff administrivia
1929
self.assertEqual(lines[4], "+content B")
1931
def test_transform_conflicts(self):
1932
revision_tree = self.create_tree()
1933
preview = TransformPreview(revision_tree)
1934
self.addCleanup(preview.finalize)
1935
preview.new_file('a', preview.root, 'content 2')
1936
resolve_conflicts(preview)
1937
trans_id = preview.trans_id_file_id('a-id')
1938
self.assertEqual('a.moved', preview.final_name(trans_id))
1940
def get_tree_and_preview_tree(self):
1941
revision_tree = self.create_tree()
1942
preview = TransformPreview(revision_tree)
1943
self.addCleanup(preview.finalize)
1944
a_trans_id = preview.trans_id_file_id('a-id')
1945
preview.delete_contents(a_trans_id)
1946
preview.create_file('b content', a_trans_id)
1947
preview_tree = preview.get_preview_tree()
1948
return revision_tree, preview_tree
1950
def test_iter_changes(self):
1951
revision_tree, preview_tree = self.get_tree_and_preview_tree()
1952
root = revision_tree.inventory.root.file_id
1953
self.assertEqual([('a-id', ('a', 'a'), True, (True, True),
1954
(root, root), ('a', 'a'), ('file', 'file'),
1956
list(preview_tree.iter_changes(revision_tree)))
1958
def test_wrong_tree_value_error(self):
1959
revision_tree, preview_tree = self.get_tree_and_preview_tree()
1960
e = self.assertRaises(ValueError, preview_tree.iter_changes,
1962
self.assertEqual('from_tree must be transform source tree.', str(e))
1964
def test_include_unchanged_value_error(self):
1965
revision_tree, preview_tree = self.get_tree_and_preview_tree()
1966
e = self.assertRaises(ValueError, preview_tree.iter_changes,
1967
revision_tree, include_unchanged=True)
1968
self.assertEqual('include_unchanged is not supported', str(e))
1970
def test_specific_files(self):
1971
revision_tree, preview_tree = self.get_tree_and_preview_tree()
1972
e = self.assertRaises(ValueError, preview_tree.iter_changes,
1973
revision_tree, specific_files=['pete'])
1974
self.assertEqual('specific_files is not supported', str(e))
1976
def test_want_unversioned_value_error(self):
1977
revision_tree, preview_tree = self.get_tree_and_preview_tree()
1978
e = self.assertRaises(ValueError, preview_tree.iter_changes,
1979
revision_tree, want_unversioned=True)
1980
self.assertEqual('want_unversioned is not supported', str(e))
1982
def test_ignore_extra_trees_no_specific_files(self):
1983
# extra_trees is harmless without specific_files, so we'll silently
1984
# accept it, even though we won't use it.
1985
revision_tree, preview_tree = self.get_tree_and_preview_tree()
1986
preview_tree.iter_changes(revision_tree, extra_trees=[preview_tree])
1988
def test_ignore_require_versioned_no_specific_files(self):
1989
# require_versioned is meaningless without specific_files.
1990
revision_tree, preview_tree = self.get_tree_and_preview_tree()
1991
preview_tree.iter_changes(revision_tree, require_versioned=False)
1993
def test_ignore_pb(self):
1994
# pb could be supported, but TT.iter_changes doesn't support it.
1995
revision_tree, preview_tree = self.get_tree_and_preview_tree()
1996
preview_tree.iter_changes(revision_tree, pb=progress.DummyProgress())
1998
def test_kind(self):
1999
revision_tree = self.create_tree()
2000
preview = TransformPreview(revision_tree)
2001
self.addCleanup(preview.finalize)
2002
preview.new_file('file', preview.root, 'contents', 'file-id')
2003
preview.new_directory('directory', preview.root, 'dir-id')
2004
preview_tree = preview.get_preview_tree()
2005
self.assertEqual('file', preview_tree.kind('file-id'))
2006
self.assertEqual('directory', preview_tree.kind('dir-id'))
2008
def test_get_file_mtime(self):
2009
preview = self.get_empty_preview()
2010
file_trans_id = preview.new_file('file', preview.root, 'contents',
2012
limbo_path = preview._limbo_name(file_trans_id)
2013
preview_tree = preview.get_preview_tree()
2014
self.assertEqual(os.stat(limbo_path).st_mtime,
2015
preview_tree.get_file_mtime('file-id'))
2017
def test_get_file(self):
2018
preview = self.get_empty_preview()
2019
preview.new_file('file', preview.root, 'contents', 'file-id')
2020
preview_tree = preview.get_preview_tree()
2021
tree_file = preview_tree.get_file('file-id')
2023
self.assertEqual('contents', tree_file.read())
2027
def test_get_symlink_target(self):
2028
self.requireFeature(SymlinkFeature)
2029
preview = self.get_empty_preview()
2030
preview.new_symlink('symlink', preview.root, 'target', 'symlink-id')
2031
preview_tree = preview.get_preview_tree()
2032
self.assertEqual('target',
2033
preview_tree.get_symlink_target('symlink-id'))
2035
def test_all_file_ids(self):
2036
tree = self.make_branch_and_tree('tree')
2037
self.build_tree(['tree/a', 'tree/b', 'tree/c'])
2038
tree.add(['a', 'b', 'c'], ['a-id', 'b-id', 'c-id'])
2039
preview = TransformPreview(tree)
2040
self.addCleanup(preview.finalize)
2041
preview.unversion_file(preview.trans_id_file_id('b-id'))
2042
c_trans_id = preview.trans_id_file_id('c-id')
2043
preview.unversion_file(c_trans_id)
2044
preview.version_file('c-id', c_trans_id)
2045
preview_tree = preview.get_preview_tree()
2046
self.assertEqual(set(['a-id', 'c-id', tree.get_root_id()]),
2047
preview_tree.all_file_ids())
2049
def test_path2id_deleted_unchanged(self):
2050
tree = self.make_branch_and_tree('tree')
2051
self.build_tree(['tree/unchanged', 'tree/deleted'])
2052
tree.add(['unchanged', 'deleted'], ['unchanged-id', 'deleted-id'])
2053
preview = TransformPreview(tree)
2054
self.addCleanup(preview.finalize)
2055
preview.unversion_file(preview.trans_id_file_id('deleted-id'))
2056
preview_tree = preview.get_preview_tree()
2057
self.assertEqual('unchanged-id', preview_tree.path2id('unchanged'))
2058
self.assertIs(None, preview_tree.path2id('deleted'))
2060
def test_path2id_created(self):
2061
tree = self.make_branch_and_tree('tree')
2062
self.build_tree(['tree/unchanged'])
2063
tree.add(['unchanged'], ['unchanged-id'])
2064
preview = TransformPreview(tree)
2065
self.addCleanup(preview.finalize)
2066
preview.new_file('new', preview.trans_id_file_id('unchanged-id'),
2067
'contents', 'new-id')
2068
preview_tree = preview.get_preview_tree()
2069
self.assertEqual('new-id', preview_tree.path2id('unchanged/new'))
2071
def test_path2id_moved(self):
2072
tree = self.make_branch_and_tree('tree')
2073
self.build_tree(['tree/old_parent/', 'tree/old_parent/child'])
2074
tree.add(['old_parent', 'old_parent/child'],
2075
['old_parent-id', 'child-id'])
2076
preview = TransformPreview(tree)
2077
self.addCleanup(preview.finalize)
2078
new_parent = preview.new_directory('new_parent', preview.root,
2080
preview.adjust_path('child', new_parent,
2081
preview.trans_id_file_id('child-id'))
2082
preview_tree = preview.get_preview_tree()
2083
self.assertIs(None, preview_tree.path2id('old_parent/child'))
2084
self.assertEqual('child-id', preview_tree.path2id('new_parent/child'))
2086
def test_path2id_renamed_parent(self):
2087
tree = self.make_branch_and_tree('tree')
2088
self.build_tree(['tree/old_name/', 'tree/old_name/child'])
2089
tree.add(['old_name', 'old_name/child'],
2090
['parent-id', 'child-id'])
2091
preview = TransformPreview(tree)
2092
self.addCleanup(preview.finalize)
2093
preview.adjust_path('new_name', preview.root,
2094
preview.trans_id_file_id('parent-id'))
2095
preview_tree = preview.get_preview_tree()
2096
self.assertIs(None, preview_tree.path2id('old_name/child'))
2097
self.assertEqual('child-id', preview_tree.path2id('new_name/child'))
2099
def assertMatchingIterEntries(self, tt, specific_file_ids=None):
2100
preview_tree = tt.get_preview_tree()
2101
preview_result = list(preview_tree.iter_entries_by_dir(
2105
actual_result = list(tree.iter_entries_by_dir(specific_file_ids))
2106
self.assertEqual(actual_result, preview_result)
2108
def test_iter_entries_by_dir_new(self):
2109
tree = self.make_branch_and_tree('tree')
2110
tt = TreeTransform(tree)
2111
tt.new_file('new', tt.root, 'contents', 'new-id')
2112
self.assertMatchingIterEntries(tt)
2114
def test_iter_entries_by_dir_deleted(self):
2115
tree = self.make_branch_and_tree('tree')
2116
self.build_tree(['tree/deleted'])
2117
tree.add('deleted', 'deleted-id')
2118
tt = TreeTransform(tree)
2119
tt.delete_contents(tt.trans_id_file_id('deleted-id'))
2120
self.assertMatchingIterEntries(tt)
2122
def test_iter_entries_by_dir_unversioned(self):
2123
tree = self.make_branch_and_tree('tree')
2124
self.build_tree(['tree/removed'])
2125
tree.add('removed', 'removed-id')
2126
tt = TreeTransform(tree)
2127
tt.unversion_file(tt.trans_id_file_id('removed-id'))
2128
self.assertMatchingIterEntries(tt)
2130
def test_iter_entries_by_dir_moved(self):
2131
tree = self.make_branch_and_tree('tree')
2132
self.build_tree(['tree/moved', 'tree/new_parent/'])
2133
tree.add(['moved', 'new_parent'], ['moved-id', 'new_parent-id'])
2134
tt = TreeTransform(tree)
2135
tt.adjust_path('moved', tt.trans_id_file_id('new_parent-id'),
2136
tt.trans_id_file_id('moved-id'))
2137
self.assertMatchingIterEntries(tt)
2139
def test_iter_entries_by_dir_specific_file_ids(self):
2140
tree = self.make_branch_and_tree('tree')
2141
tree.set_root_id('tree-root-id')
2142
self.build_tree(['tree/parent/', 'tree/parent/child'])
2143
tree.add(['parent', 'parent/child'], ['parent-id', 'child-id'])
2144
tt = TreeTransform(tree)
2145
self.assertMatchingIterEntries(tt, ['tree-root-id', 'child-id'])
2147
def test_symlink_content_summary(self):
2148
self.requireFeature(SymlinkFeature)
2149
preview = self.get_empty_preview()
2150
preview.new_symlink('path', preview.root, 'target', 'path-id')
2151
summary = preview.get_preview_tree().path_content_summary('path')
2152
self.assertEqual(('symlink', None, None, 'target'), summary)
2154
def test_missing_content_summary(self):
2155
preview = self.get_empty_preview()
2156
summary = preview.get_preview_tree().path_content_summary('path')
2157
self.assertEqual(('missing', None, None, None), summary)
2159
def test_deleted_content_summary(self):
2160
tree = self.make_branch_and_tree('tree')
2161
self.build_tree(['tree/path/'])
2163
preview = TransformPreview(tree)
2164
self.addCleanup(preview.finalize)
2165
preview.delete_contents(preview.trans_id_tree_path('path'))
2166
summary = preview.get_preview_tree().path_content_summary('path')
2167
self.assertEqual(('missing', None, None, None), summary)
2169
def test_file_content_summary_executable(self):
2170
if not osutils.supports_executable():
2171
raise TestNotApplicable()
2172
preview = self.get_empty_preview()
2173
path_id = preview.new_file('path', preview.root, 'contents', 'path-id')
2174
preview.set_executability(True, path_id)
2175
summary = preview.get_preview_tree().path_content_summary('path')
2176
self.assertEqual(4, len(summary))
2177
self.assertEqual('file', summary[0])
2178
# size must be known
2179
self.assertEqual(len('contents'), summary[1])
2181
self.assertEqual(True, summary[2])
2182
# will not have hash (not cheap to determine)
2183
self.assertIs(None, summary[3])
2185
def test_change_executability(self):
2186
if not osutils.supports_executable():
2187
raise TestNotApplicable()
2188
tree = self.make_branch_and_tree('tree')
2189
self.build_tree(['tree/path'])
2191
preview = TransformPreview(tree)
2192
self.addCleanup(preview.finalize)
2193
path_id = preview.trans_id_tree_path('path')
2194
preview.set_executability(True, path_id)
2195
summary = preview.get_preview_tree().path_content_summary('path')
2196
self.assertEqual(True, summary[2])
2198
def test_file_content_summary_non_exec(self):
2199
preview = self.get_empty_preview()
2200
preview.new_file('path', preview.root, 'contents', 'path-id')
2201
summary = preview.get_preview_tree().path_content_summary('path')
2202
self.assertEqual(4, len(summary))
2203
self.assertEqual('file', summary[0])
2204
# size must be known
2205
self.assertEqual(len('contents'), summary[1])
2207
if osutils.supports_executable():
2208
self.assertEqual(False, summary[2])
2210
self.assertEqual(None, summary[2])
2211
# will not have hash (not cheap to determine)
2212
self.assertIs(None, summary[3])
2214
def test_dir_content_summary(self):
2215
preview = self.get_empty_preview()
2216
preview.new_directory('path', preview.root, 'path-id')
2217
summary = preview.get_preview_tree().path_content_summary('path')
2218
self.assertEqual(('directory', None, None, None), summary)
2220
def test_tree_content_summary(self):
2221
preview = self.get_empty_preview()
2222
path = preview.new_directory('path', preview.root, 'path-id')
2223
preview.set_tree_reference('rev-1', path)
2224
summary = preview.get_preview_tree().path_content_summary('path')
2225
self.assertEqual(4, len(summary))
2226
self.assertEqual('tree-reference', summary[0])
2228
def test_annotate(self):
2229
tree = self.make_branch_and_tree('tree')
2230
self.build_tree_contents([('tree/file', 'a\n')])
2231
tree.add('file', 'file-id')
2232
tree.commit('a', rev_id='one')
2233
self.build_tree_contents([('tree/file', 'a\nb\n')])
2234
preview = TransformPreview(tree)
2235
self.addCleanup(preview.finalize)
2236
file_trans_id = preview.trans_id_file_id('file-id')
2237
preview.delete_contents(file_trans_id)
2238
preview.create_file('a\nb\nc\n', file_trans_id)
2239
preview_tree = preview.get_preview_tree()
2245
annotation = preview_tree.annotate_iter('file-id', 'me:')
2246
self.assertEqual(expected, annotation)
2248
def test_annotate_missing(self):
2249
preview = self.get_empty_preview()
2250
preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2251
preview_tree = preview.get_preview_tree()
2257
annotation = preview_tree.annotate_iter('file-id', 'me:')
2258
self.assertEqual(expected, annotation)
2260
def test_annotate_rename(self):
2261
tree = self.make_branch_and_tree('tree')
2262
self.build_tree_contents([('tree/file', 'a\n')])
2263
tree.add('file', 'file-id')
2264
tree.commit('a', rev_id='one')
2265
preview = TransformPreview(tree)
2266
self.addCleanup(preview.finalize)
2267
file_trans_id = preview.trans_id_file_id('file-id')
2268
preview.adjust_path('newname', preview.root, file_trans_id)
2269
preview_tree = preview.get_preview_tree()
2273
annotation = preview_tree.annotate_iter('file-id', 'me:')
2274
self.assertEqual(expected, annotation)
2276
def test_annotate_deleted(self):
2277
tree = self.make_branch_and_tree('tree')
2278
self.build_tree_contents([('tree/file', 'a\n')])
2279
tree.add('file', 'file-id')
2280
tree.commit('a', rev_id='one')
2281
self.build_tree_contents([('tree/file', 'a\nb\n')])
2282
preview = TransformPreview(tree)
2283
self.addCleanup(preview.finalize)
2284
file_trans_id = preview.trans_id_file_id('file-id')
2285
preview.delete_contents(file_trans_id)
2286
preview_tree = preview.get_preview_tree()
2287
annotation = preview_tree.annotate_iter('file-id', 'me:')
2288
self.assertIs(None, annotation)
2290
def test_stored_kind(self):
2291
preview = self.get_empty_preview()
2292
preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2293
preview_tree = preview.get_preview_tree()
2294
self.assertEqual('file', preview_tree.stored_kind('file-id'))
2296
def test_is_executable(self):
2297
preview = self.get_empty_preview()
2298
preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2299
preview.set_executability(True, preview.trans_id_file_id('file-id'))
2300
preview_tree = preview.get_preview_tree()
2301
self.assertEqual(True, preview_tree.is_executable('file-id'))