233
290
tree1 = self.make_branch_and_tree('1')
234
291
tree2 = self.make_to_branch_and_tree('2')
235
292
tree1 = self.get_tree_no_parents_no_content(tree1)
236
tree2 = self.get_to_tree_no_parents_abc_content(tree2)
293
tree2 = self.get_tree_no_parents_abc_content(tree2)
294
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
237
295
self.assertRaises(errors.PathsNotVersionedError,
238
296
self.intertree_class(tree1, tree2).compare,
239
297
specific_files=['d'],
240
298
require_versioned=True)
300
def test_default_ignores_unversioned_files(self):
301
tree1 = self.make_branch_and_tree('tree1')
302
tree2 = self.make_to_branch_and_tree('tree2')
303
tree2.set_root_id(tree1.get_root_id())
304
self.build_tree(['tree1/a', 'tree1/c',
305
'tree2/a', 'tree2/b', 'tree2/c'])
306
tree1.add(['a', 'c'], ['a-id', 'c-id'])
307
tree2.add(['a', 'c'], ['a-id', 'c-id'])
309
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
310
d = self.intertree_class(tree1, tree2).compare()
311
self.assertEqual([], d.added)
312
self.assertEqual([(u'a', 'a-id', 'file', True, False),
313
(u'c', 'c-id', 'file', True, False)], d.modified)
314
self.assertEqual([], d.removed)
315
self.assertEqual([], d.renamed)
316
self.assertEqual([], d.unchanged)
317
self.assertEqual([], d.unversioned)
319
def test_unversioned_paths_in_tree(self):
320
tree1 = self.make_branch_and_tree('tree1')
321
tree2 = self.make_to_branch_and_tree('tree2')
322
tree2.set_root_id(tree1.get_root_id())
323
self.build_tree(['tree2/file', 'tree2/dir/'])
325
os.symlink('target', 'tree2/link')
326
links_supported = True
328
# links_supported = False
329
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
330
d = self.intertree_class(tree1, tree2).compare(want_unversioned=True)
331
self.assertEqual([], d.added)
332
self.assertEqual([], d.modified)
333
self.assertEqual([], d.removed)
334
self.assertEqual([], d.renamed)
335
self.assertEqual([], d.unchanged)
336
self.assertEqual([(u'dir', None, 'directory'), (u'file', None, 'file'),
337
(u'link', None, 'symlink')], d.unversioned)
243
340
class TestIterChanges(TestCaseWithTwoTrees):
244
341
"""Test the comparison iterator"""
343
def do_iter_changes(self, tree1, tree2, **extra_args):
344
"""Helper to run _iter_changes from tree1 to tree2.
346
:param tree1, tree2: The source and target trees. These will be locked
348
:param **extra_args: Extra args to pass to _iter_changes. This is not
349
inspected by this test helper.
354
# sort order of output is not strictly defined
355
return sorted(self.intertree_class(tree1, tree2)
356
._iter_changes(**extra_args))
361
def mutable_trees_to_locked_test_trees(self, tree1, tree2):
362
"""Convert the working trees into test trees.
364
Read lock them, and add the unlock to the cleanup.
366
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
368
self.addCleanup(tree1.unlock)
370
self.addCleanup(tree2.unlock)
373
def make_tree_with_special_names(self):
374
"""Create a tree with filenames chosen to exercise the walk order."""
375
tree1 = self.make_branch_and_tree('tree1')
376
tree2 = self.make_to_branch_and_tree('tree2')
377
tree2.set_root_id(tree1.get_root_id())
378
paths, path_ids = self._create_special_names(tree2, 'tree2')
379
tree2.commit('initial', rev_id='rev-1')
380
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
381
return (tree1, tree2, paths, path_ids)
383
def make_trees_with_special_names(self):
384
"""Both trees will use the special names.
386
But the contents will differ for each file.
388
tree1 = self.make_branch_and_tree('tree1')
389
tree2 = self.make_to_branch_and_tree('tree2')
390
tree2.set_root_id(tree1.get_root_id())
391
paths, path_ids = self._create_special_names(tree1, 'tree1')
392
paths, path_ids = self._create_special_names(tree2, 'tree2')
393
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
394
return (tree1, tree2, paths, path_ids)
396
def _create_special_names(self, tree, base_path):
397
"""Create a tree with paths that expose differences in sort orders."""
398
# Each directory will have a single file named 'f' inside
413
with_slashes.append(base_path + '/' + d + '/')
414
with_slashes.append(base_path + '/' + d + '/f')
417
path_ids.append(d.replace('/', '_') + '-id')
418
path_ids.append(d.replace('/', '_') + '_f-id')
419
self.build_tree(with_slashes)
420
tree.add(paths, path_ids)
421
return paths, path_ids
246
423
def test_compare_empty_trees(self):
247
424
tree1 = self.make_branch_and_tree('1')
248
425
tree2 = self.make_to_branch_and_tree('2')
249
426
tree1 = self.get_tree_no_parents_no_content(tree1)
250
tree2 = self.get_to_tree_no_parents_no_content(tree2)
251
self.assertEqual([], list(tree2._iter_changes(tree1)))
427
tree2 = self.get_tree_no_parents_no_content(tree2)
428
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
429
self.assertEqual([], self.do_iter_changes(tree1, tree2))
253
431
def added(self, tree, file_id):
254
432
entry = tree.inventory[file_id]
255
433
path = tree.id2path(file_id)
256
return (file_id, path, True, (False, True), (None, entry.parent_id),
257
(None, entry.name), (None, entry.kind),
434
return (file_id, (None, path), True, (False, True), (None, entry.parent_id),
435
(None, entry.name), (None, entry.kind),
258
436
(None, entry.executable))
438
def content_changed(self, tree, file_id):
439
entry = tree.inventory[file_id]
440
path = tree.id2path(file_id)
441
return (file_id, (path, path), True, (True, True), (entry.parent_id, entry.parent_id),
442
(entry.name, entry.name), (entry.kind, entry.kind),
443
(entry.executable, entry.executable))
445
def kind_changed(self, from_tree, to_tree, file_id):
446
old_entry = from_tree.inventory[file_id]
447
new_entry = to_tree.inventory[file_id]
448
path = to_tree.id2path(file_id)
449
from_path = from_tree.id2path(file_id)
450
return (file_id, (from_path, path), True, (True, True), (old_entry.parent_id, new_entry.parent_id),
451
(old_entry.name, new_entry.name), (old_entry.kind, new_entry.kind),
452
(old_entry.executable, new_entry.executable))
454
def missing(self, file_id, from_path, to_path, parent_id, kind):
455
_, from_basename = os.path.split(from_path)
456
_, to_basename = os.path.split(to_path)
457
# missing files have both paths, but no kind.
458
return (file_id, (from_path, to_path), True, (True, True),
459
(parent_id, parent_id),
460
(from_basename, to_basename), (kind, None), (False, False))
260
462
def deleted(self, tree, file_id):
261
463
entry = tree.inventory[file_id]
262
464
path = tree.id2path(file_id)
263
return (file_id, path, True, (True, False), (entry.parent_id, None),
264
(entry.name, None), (entry.kind, None),
465
return (file_id, (path, None), True, (True, False), (entry.parent_id, None),
466
(entry.name, None), (entry.kind, None),
265
467
(entry.executable, None))
469
def renamed(self, from_tree, to_tree, file_id, content_changed):
470
from_entry = from_tree.inventory[file_id]
471
to_entry = to_tree.inventory[file_id]
472
from_path = from_tree.id2path(file_id)
473
to_path = to_tree.id2path(file_id)
474
return (file_id, (from_path, to_path), content_changed, (True, True),
475
(from_entry.parent_id, to_entry.parent_id),
476
(from_entry.name, to_entry.name),
477
(from_entry.kind, to_entry.kind),
478
(from_entry.executable, to_entry.executable))
480
def unchanged(self, tree, file_id):
481
entry = tree.inventory[file_id]
482
parent = entry.parent_id
485
executable = entry.executable
486
path = tree.id2path(file_id)
487
return (file_id, (path, path), False, (True, True),
488
(parent, parent), (name, name), (kind, kind),
489
(executable, executable))
491
def unversioned(self, tree, path):
492
"""Create an unversioned result."""
493
_, basename = os.path.split(path)
494
kind = file_kind(tree.abspath(path))
495
return (None, (None, path), True, (False, False), (None, None),
496
(None, basename), (None, kind),
267
499
def test_empty_to_abc_content(self):
268
500
tree1 = self.make_branch_and_tree('1')
269
501
tree2 = self.make_to_branch_and_tree('2')
270
502
tree1 = self.get_tree_no_parents_no_content(tree1)
271
tree2 = self.get_to_tree_no_parents_abc_content(tree2)
273
self.assertEqual([self.added(tree2, 'root-id'),
274
self.added(tree2, 'a-id'),
275
self.added(tree2, 'b-id'),
276
self.added(tree2, 'c-id'),
277
self.deleted(tree1, 'empty-root-id')],
278
list(tree2._iter_changes(tree1)))
503
tree2 = self.get_tree_no_parents_abc_content(tree2)
504
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
505
expected_results = sorted([
506
self.added(tree2, 'root-id'),
507
self.added(tree2, 'a-id'),
508
self.added(tree2, 'b-id'),
509
self.added(tree2, 'c-id'),
510
self.deleted(tree1, 'empty-root-id')])
511
self.assertEqual(expected_results, self.do_iter_changes(tree1, tree2))
280
513
def test_empty_to_abc_content_a_only(self):
281
514
tree1 = self.make_branch_and_tree('1')
282
515
tree2 = self.make_to_branch_and_tree('2')
283
516
tree1 = self.get_tree_no_parents_no_content(tree1)
284
tree2 = self.get_to_tree_no_parents_abc_content(tree2)
285
self.assertEqual([self.added(tree2, 'a-id')],
286
list(tree2._iter_changes(tree1,
287
specific_file_ids=['a-id'])))
288
self.assertEqual([self.deleted(tree2, 'a-id')],
289
list(tree1._iter_changes(tree2,
290
specific_file_ids=['a-id'])))
517
tree2 = self.get_tree_no_parents_abc_content(tree2)
518
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
520
[self.added(tree2, 'a-id')],
521
self.do_iter_changes(tree1, tree2, specific_files=['a']))
523
def test_abc_content_to_empty_to_abc_content_a_only(self):
524
tree1 = self.make_branch_and_tree('1')
525
tree2 = self.make_to_branch_and_tree('2')
526
tree1 = self.get_tree_no_parents_abc_content(tree1)
527
tree2 = self.get_tree_no_parents_no_content(tree2)
528
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
530
[self.deleted(tree1, 'a-id')],
531
self.do_iter_changes(tree1, tree2, specific_files=['a']))
292
533
def test_empty_to_abc_content_a_and_c_only(self):
293
534
tree1 = self.make_branch_and_tree('1')
294
535
tree2 = self.make_to_branch_and_tree('2')
295
536
tree1 = self.get_tree_no_parents_no_content(tree1)
296
tree2 = self.get_to_tree_no_parents_abc_content(tree2)
297
self.assertEqual([self.added(tree2, 'a-id'),
298
self.added(tree2, 'c-id')],
299
list(tree2._iter_changes(tree1,
300
specific_file_ids=['a-id',
302
d = self.intertree_class(tree1, tree2).compare(
303
specific_files=['a', 'b/c'])
537
tree2 = self.get_tree_no_parents_abc_content(tree2)
538
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
539
expected_result = [self.added(tree2, 'a-id'), self.added(tree2, 'c-id')]
540
self.assertEqual(expected_result,
541
self.do_iter_changes(tree1, tree2, specific_files=['a', 'b/c']))
305
def test_abc_content(self):
543
def test_abc_content_to_empty(self):
306
544
tree1 = self.make_branch_and_tree('1')
307
545
tree2 = self.make_to_branch_and_tree('2')
308
tree1 = self.get_tree_no_parents_no_content(tree1)
309
tree2 = self.get_to_tree_no_parents_abc_content(tree2)
546
tree1 = self.get_tree_no_parents_abc_content(tree1)
547
tree2 = self.get_tree_no_parents_no_content(tree2)
548
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
310
549
def deleted(file_id):
311
entry = tree2.inventory[file_id]
312
path = tree2.id2path(file_id)
313
return (file_id, path, True, (True, False),
550
entry = tree1.inventory[file_id]
551
path = tree1.id2path(file_id)
552
return (file_id, (path, None), True, (True, False),
314
553
(entry.parent_id, None),
315
(entry.name, None), (entry.kind, None),
554
(entry.name, None), (entry.kind, None),
316
555
(entry.executable, None))
317
self.assertEqual([self.added(tree1, 'empty-root-id'),
318
deleted('root-id'), deleted('a-id'),
319
deleted('b-id'), deleted('c-id')],
320
list(tree1._iter_changes(tree2)))
556
expected_results = sorted([
557
self.added(tree2, 'empty-root-id'),
558
deleted('root-id'), deleted('a-id'),
559
deleted('b-id'), deleted('c-id')])
562
self.do_iter_changes(tree1, tree2))
322
564
def test_content_modification(self):
323
565
tree1 = self.make_branch_and_tree('1')
324
566
tree2 = self.make_to_branch_and_tree('2')
325
567
tree1 = self.get_tree_no_parents_abc_content(tree1)
326
tree2 = self.get_to_tree_no_parents_abc_content_2(tree2)
327
root_id = tree1.inventory.root.file_id
328
self.assertEqual([('a-id', 'a', True, (True, True),
329
(root_id, root_id), ('a', 'a'),
330
('file', 'file'), (False, False))],
331
list(tree2._iter_changes(tree1)))
568
tree2 = self.get_tree_no_parents_abc_content_2(tree2)
569
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
570
root_id = tree1.path2id('')
571
self.assertEqual([('a-id', ('a', 'a'), True, (True, True),
572
(root_id, root_id), ('a', 'a'),
573
('file', 'file'), (False, False))],
574
self.do_iter_changes(tree1, tree2))
333
576
def test_meta_modification(self):
334
577
tree1 = self.make_branch_and_tree('1')
335
578
tree2 = self.make_to_branch_and_tree('2')
336
579
tree1 = self.get_tree_no_parents_abc_content(tree1)
337
tree2 = self.get_to_tree_no_parents_abc_content_3(tree2)
338
self.assertEqual([('c-id', 'b/c', False, (True, True),
339
('b-id', 'b-id'), ('c', 'c'), ('file', 'file'),
340
(False, True))], list(tree2._iter_changes(tree1)))
580
tree2 = self.get_tree_no_parents_abc_content_3(tree2)
581
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
582
self.assertEqual([('c-id', ('b/c', 'b/c'), False, (True, True),
583
('b-id', 'b-id'), ('c', 'c'), ('file', 'file'),
585
self.do_iter_changes(tree1, tree2))
587
def test_empty_dir(self):
588
"""an empty dir should not cause glitches to surrounding files."""
589
tree1 = self.make_branch_and_tree('1')
590
tree2 = self.make_to_branch_and_tree('2')
591
tree1 = self.get_tree_no_parents_abc_content(tree1)
592
tree2 = self.get_tree_no_parents_abc_content(tree2)
593
# the pathname is chosen to fall between 'a' and 'b'.
594
self.build_tree(['1/a-empty/', '2/a-empty/'])
595
tree1.add(['a-empty'], ['a-empty'])
596
tree2.add(['a-empty'], ['a-empty'])
597
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
599
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
342
601
def test_file_rename(self):
343
602
tree1 = self.make_branch_and_tree('1')
344
603
tree2 = self.make_to_branch_and_tree('2')
345
604
tree1 = self.get_tree_no_parents_abc_content(tree1)
346
tree2 = self.get_to_tree_no_parents_abc_content_4(tree2)
347
root_id = tree1.inventory.root.file_id
348
self.assertEqual([('a-id', 'd', False, (True, True),
349
(root_id, root_id), ('a', 'd'), ('file', 'file'),
350
(False, False))], list(tree2._iter_changes(tree1)))
605
tree2 = self.get_tree_no_parents_abc_content_4(tree2)
606
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
607
root_id = tree1.path2id('')
608
self.assertEqual([('a-id', ('a', 'd'), False, (True, True),
609
(root_id, root_id), ('a', 'd'), ('file', 'file'),
611
self.do_iter_changes(tree1, tree2))
352
613
def test_file_rename_and_modification(self):
353
614
tree1 = self.make_branch_and_tree('1')
354
615
tree2 = self.make_to_branch_and_tree('2')
355
616
tree1 = self.get_tree_no_parents_abc_content(tree1)
356
tree2 = self.get_to_tree_no_parents_abc_content_5(tree2)
357
root_id = tree1.inventory.root.file_id
358
self.assertEqual([('a-id', 'd', True, (True, True),
359
(root_id, root_id), ('a', 'd'), ('file', 'file'),
360
(False, False))], list(tree2._iter_changes(tree1)))
617
tree2 = self.get_tree_no_parents_abc_content_5(tree2)
618
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
619
root_id = tree1.path2id('')
620
self.assertEqual([('a-id', ('a', 'd'), True, (True, True),
621
(root_id, root_id), ('a', 'd'), ('file', 'file'),
623
self.do_iter_changes(tree1, tree2))
362
625
def test_file_rename_and_meta_modification(self):
363
626
tree1 = self.make_branch_and_tree('1')
364
627
tree2 = self.make_to_branch_and_tree('2')
365
628
tree1 = self.get_tree_no_parents_abc_content(tree1)
366
tree2 = self.get_to_tree_no_parents_abc_content_6(tree2)
367
root_id = tree1.inventory.root.file_id
368
self.assertEqual([('c-id', 'e', False, (True, True),
369
('b-id', root_id), ('c', 'e'), ('file', 'file'),
370
(False, True))], list(tree2._iter_changes(tree1)))
629
tree2 = self.get_tree_no_parents_abc_content_6(tree2)
630
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
631
root_id = tree1.path2id('')
632
self.assertEqual([('c-id', ('b/c', 'e'), False, (True, True),
633
('b-id', root_id), ('c', 'e'), ('file', 'file'),
635
self.do_iter_changes(tree1, tree2))
637
def test_missing_in_target(self):
638
"""Test with the target files versioned but absent from disk."""
639
tree1 = self.make_branch_and_tree('1')
640
tree2 = self.make_to_branch_and_tree('2')
641
tree1 = self.get_tree_no_parents_abc_content(tree1)
642
tree2 = self.get_tree_no_parents_abc_content(tree2)
645
# TODO ? have a symlink here?
646
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
647
root_id = tree1.path2id('')
649
self.missing('a-id', 'a', 'a', root_id, 'file'),
650
self.missing('b-id', 'b', 'b', root_id, 'directory'),
651
self.missing('c-id', 'b/c', 'b/c', 'b-id', 'file'),
653
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
655
def test_missing_and_renamed(self):
656
tree1 = self.make_branch_and_tree('tree1')
657
tree2 = self.make_to_branch_and_tree('tree2')
658
tree2.set_root_id(tree1.get_root_id())
659
self.build_tree(['tree1/file'])
660
tree1.add(['file'], ['file-id'])
661
self.build_tree(['tree2/directory/'])
662
tree2.add(['directory'], ['file-id'])
663
os.rmdir('tree2/directory')
664
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
666
root_id = tree1.path2id('')
668
self.missing('file-id', 'file', 'directory', root_id, 'file'),
670
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
372
672
def test_unchanged_with_renames_and_modifications(self):
373
673
"""want_unchanged should generate a list of unchanged entries."""
374
674
tree1 = self.make_branch_and_tree('1')
375
675
tree2 = self.make_to_branch_and_tree('2')
376
676
tree1 = self.get_tree_no_parents_abc_content(tree1)
377
tree2 = self.get_to_tree_no_parents_abc_content_5(tree2)
378
root_id = tree1.inventory.root.file_id
379
def unchanged(file_id):
380
entry = tree1.inventory[file_id]
381
parent = entry.parent_id
384
executable = entry.executable
385
return (file_id, tree1.id2path(file_id), False, (True, True),
386
(parent, parent), (name, name), (kind, kind),
387
(executable, executable))
388
self.assertEqual([unchanged(root_id), unchanged('b-id'),
389
('a-id', 'd', True, (True, True),
390
(root_id, root_id), ('a', 'd'), ('file', 'file'),
391
(False, False)), unchanged('c-id')],
392
list(tree2._iter_changes(tree1,
393
include_unchanged=True)))
677
tree2 = self.get_tree_no_parents_abc_content_5(tree2)
678
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
679
root_id = tree1.path2id('')
681
self.assertEqual(sorted([self.unchanged(tree1, root_id),
682
self.unchanged(tree1, 'b-id'),
683
('a-id', ('a', 'd'), True, (True, True),
684
(root_id, root_id), ('a', 'd'), ('file', 'file'),
685
(False, False)), self.unchanged(tree1, 'c-id')]),
686
self.do_iter_changes(tree1, tree2, include_unchanged=True))
688
def test_compare_subtrees(self):
689
tree1 = self.make_branch_and_tree('1')
690
if not tree1.supports_tree_reference():
692
tree1.set_root_id('root-id')
693
subtree1 = self.make_branch_and_tree('1/sub')
694
subtree1.set_root_id('subtree-id')
695
tree1.add_reference(subtree1)
697
tree2 = self.make_to_branch_and_tree('2')
698
if not tree2.supports_tree_reference():
700
tree2.set_root_id('root-id')
701
subtree2 = self.make_to_branch_and_tree('2/sub')
702
subtree2.set_root_id('subtree-id')
703
tree2.add_reference(subtree2)
704
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
706
self.assertEqual([], list(tree2._iter_changes(tree1)))
707
subtree1.commit('commit', rev_id='commit-a')
715
('directory', 'directory'),
721
('root-id', 'root-id'),
723
('tree-reference', 'tree-reference'),
725
list(tree2._iter_changes(tree1,
726
include_unchanged=True)))
728
def test_disk_in_subtrees_skipped(self):
729
"""subtrees are considered not-in-the-current-tree.
731
This test tests the trivial case, where the basis has no paths in the
732
current trees subtree.
734
tree1 = self.make_branch_and_tree('1')
735
tree1.set_root_id('root-id')
736
tree2 = self.make_to_branch_and_tree('2')
737
if not tree2.supports_tree_reference():
739
tree2.set_root_id('root-id')
740
subtree2 = self.make_to_branch_and_tree('2/sub')
741
subtree2.set_root_id('subtree-id')
742
tree2.add(['sub'], ['subtree-id'])
743
self.build_tree(['2/sub/file'])
744
subtree2.add(['file'])
746
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
747
# this should filter correctly from above
748
self.assertEqual([self.added(tree2, 'subtree-id')],
749
self.do_iter_changes(tree1, tree2, want_unversioned=True))
750
# and when the path is named
751
self.assertEqual([self.added(tree2, 'subtree-id')],
752
self.do_iter_changes(tree1, tree2, specific_files=['sub'],
753
want_unversioned=True))
755
def test_default_ignores_unversioned_files(self):
756
tree1 = self.make_branch_and_tree('tree1')
757
tree2 = self.make_to_branch_and_tree('tree2')
758
tree2.set_root_id(tree1.get_root_id())
759
self.build_tree(['tree1/a', 'tree1/c',
760
'tree2/a', 'tree2/b', 'tree2/c'])
761
tree1.add(['a', 'c'], ['a-id', 'c-id'])
762
tree2.add(['a', 'c'], ['a-id', 'c-id'])
764
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
766
# We should ignore the fact that 'b' exists in tree-2
767
# because the want_unversioned parameter was not given.
769
self.content_changed(tree2, 'a-id'),
770
self.content_changed(tree2, 'c-id'),
772
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
774
def test_unversioned_paths_in_tree(self):
775
tree1 = self.make_branch_and_tree('tree1')
776
tree2 = self.make_to_branch_and_tree('tree2')
777
tree2.set_root_id(tree1.get_root_id())
778
self.build_tree(['tree2/file', 'tree2/dir/'])
780
os.symlink('target', 'tree2/link')
781
links_supported = True
783
# links_supported = False
784
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
786
self.unversioned(tree2, 'file'),
787
self.unversioned(tree2, 'dir'),
790
expected.append(self.unversioned(tree2, 'link'))
791
expected = sorted(expected)
792
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
793
want_unversioned=True))
795
def test_unversioned_paths_in_tree_specific_files(self):
796
tree1 = self.make_branch_and_tree('tree1')
797
tree2 = self.make_to_branch_and_tree('tree2')
798
self.build_tree(['tree2/file', 'tree2/dir/'])
800
os.symlink('target', 'tree2/link')
801
links_supported = True
803
# links_supported = False
804
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
806
self.unversioned(tree2, 'file'),
807
self.unversioned(tree2, 'dir'),
809
specific_files=['file', 'dir']
811
expected.append(self.unversioned(tree2, 'link'))
812
specific_files.append('link')
813
expected = sorted(expected)
814
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
815
specific_files=specific_files, require_versioned=False,
816
want_unversioned=True))
818
def test_unversioned_paths_in_target_matching_source_old_names(self):
819
# its likely that naive implementations of unversioned file support
820
# will fail if the path was versioned, but is not any more,
821
# due to a rename, not due to unversioning it.
822
# That is, if the old tree has a versioned file 'foo', and
823
# the new tree has the same file but versioned as 'bar', and also
824
# has an unknown file 'foo', we should get back output for
826
tree1 = self.make_branch_and_tree('tree1')
827
tree2 = self.make_to_branch_and_tree('tree2')
828
tree2.set_root_id(tree1.get_root_id())
829
self.build_tree(['tree2/file', 'tree2/dir/',
830
'tree1/file', 'tree2/movedfile',
831
'tree1/dir/', 'tree2/moveddir/'])
833
os.symlink('target', 'tree1/link')
834
os.symlink('target', 'tree2/link')
835
os.symlink('target', 'tree2/movedlink')
836
links_supported = True
838
# links_supported = False
839
tree1.add(['file', 'dir', 'link'], ['file-id', 'dir-id', 'link-id'])
840
tree2.add(['movedfile', 'moveddir', 'movedlink'],
841
['file-id', 'dir-id', 'link-id'])
842
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
843
root_id = tree1.path2id('')
845
self.renamed(tree1, tree2, 'dir-id', False),
846
self.renamed(tree1, tree2, 'file-id', True),
847
self.unversioned(tree2, 'file'),
848
self.unversioned(tree2, 'dir'),
850
specific_files=['file', 'dir']
852
expected.append(self.renamed(tree1, tree2, 'link-id', False))
853
expected.append(self.unversioned(tree2, 'link'))
854
specific_files.append('link')
855
expected = sorted(expected)
856
# run once with, and once without specific files, to catch
857
# potentially different code paths.
858
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
859
require_versioned=False,
860
want_unversioned=True))
861
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
862
specific_files=specific_files, require_versioned=False,
863
want_unversioned=True))
865
def test_unversioned_subtree_only_emits_root(self):
866
tree1 = self.make_branch_and_tree('tree1')
867
tree2 = self.make_to_branch_and_tree('tree2')
868
tree2.set_root_id(tree1.get_root_id())
869
self.build_tree(['tree2/dir/', 'tree2/dir/file'])
870
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
872
self.unversioned(tree2, 'dir'),
874
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
875
want_unversioned=True))
877
def make_trees_with_symlinks(self):
878
tree1 = self.make_branch_and_tree('tree1')
879
tree2 = self.make_to_branch_and_tree('tree2')
880
tree2.set_root_id(tree1.get_root_id())
881
self.build_tree(['tree1/fromfile', 'tree1/fromdir/'])
882
self.build_tree(['tree2/tofile', 'tree2/todir/', 'tree2/unknown'])
884
os.symlink('original', 'tree1/changed')
885
os.symlink('original', 'tree1/removed')
886
os.symlink('original', 'tree1/tofile')
887
os.symlink('original', 'tree1/todir')
888
# we make the unchanged link point at unknown to catch incorrect
889
# symlink-following code in the specified_files test.
890
os.symlink('unknown', 'tree1/unchanged')
891
os.symlink('new', 'tree2/added')
892
os.symlink('new', 'tree2/changed')
893
os.symlink('new', 'tree2/fromfile')
894
os.symlink('new', 'tree2/fromdir')
895
os.symlink('unknown', 'tree2/unchanged')
896
from_paths_and_ids = [
914
tree1.add(from_paths_and_ids, from_paths_and_ids)
915
tree2.add(to_paths_and_ids, to_paths_and_ids)
917
# raise TestSkipped('OS does not support symlinks')
918
# links_supported = False
919
return self.mutable_trees_to_locked_test_trees(tree1, tree2)
921
def test_versioned_symlinks(self):
922
if not has_symlinks():
923
raise tests.TestSkipped("No symlink support")
924
tree1, tree2 = self.make_trees_with_symlinks()
925
root_id = tree1.path2id('')
927
self.unchanged(tree1, tree1.path2id('')),
928
self.added(tree2, 'added'),
929
self.content_changed(tree2, 'changed'),
930
self.kind_changed(tree1, tree2, 'fromdir'),
931
self.kind_changed(tree1, tree2, 'fromfile'),
932
self.deleted(tree1, 'removed'),
933
self.unchanged(tree2, 'unchanged'),
934
self.unversioned(tree2, 'unknown'),
935
self.kind_changed(tree1, tree2, 'todir'),
936
self.kind_changed(tree1, tree2, 'tofile'),
938
expected = sorted(expected)
939
self.assertEqual(expected,
940
self.do_iter_changes(tree1, tree2, include_unchanged=True,
941
want_unversioned=True))
943
def test_versioned_symlinks_specific_files(self):
944
if not has_symlinks():
945
raise tests.TestSkipped("No symlink support")
946
tree1, tree2 = self.make_trees_with_symlinks()
947
root_id = tree1.path2id('')
949
self.added(tree2, 'added'),
950
self.content_changed(tree2, 'changed'),
951
self.kind_changed(tree1, tree2, 'fromdir'),
952
self.kind_changed(tree1, tree2, 'fromfile'),
953
self.deleted(tree1, 'removed'),
954
self.kind_changed(tree1, tree2, 'todir'),
955
self.kind_changed(tree1, tree2, 'tofile'),
957
expected = sorted(expected)
958
# we should get back just the changed links. We pass in 'unchanged' to
959
# make sure that it is correctly not returned - and neither is the
960
# unknown path 'unknown' which it points at.
961
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
962
specific_files=['added', 'changed', 'fromdir', 'fromfile',
963
'removed', 'unchanged', 'todir', 'tofile']))
965
def test_tree_with_special_names(self):
966
tree1, tree2, paths, path_ids = self.make_tree_with_special_names()
967
expected = sorted(self.added(tree2, f_id) for f_id in path_ids)
968
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
970
def test_trees_with_special_names(self):
971
tree1, tree2, paths, path_ids = self.make_trees_with_special_names()
972
expected = sorted(self.content_changed(tree2, f_id) for f_id in path_ids
973
if f_id.endswith('_f-id'))
974
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
976
def test_trees_with_deleted_dir(self):
977
tree1 = self.make_branch_and_tree('tree1')
978
tree2 = self.make_to_branch_and_tree('tree2')
979
tree2.set_root_id(tree1.get_root_id())
980
self.build_tree(['tree1/a', 'tree1/b/', 'tree1/b/c',
981
'tree1/b/d/', 'tree1/b/d/e', 'tree1/f/', 'tree1/f/g',
982
'tree2/a', 'tree2/f/', 'tree2/f/g'])
983
tree1.add(['a', 'b', 'b/c', 'b/d/', 'b/d/e', 'f', 'f/g'],
984
['a-id', 'b-id', 'c-id', 'd-id', 'e-id', 'f-id', 'g-id'])
985
tree2.add(['a', 'f', 'f/g'], ['a-id', 'f-id', 'g-id'])
987
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
988
# We should notice that 'b' and all its children are deleted
990
self.content_changed(tree2, 'a-id'),
991
self.content_changed(tree2, 'g-id'),
992
self.deleted(tree1, 'b-id'),
993
self.deleted(tree1, 'c-id'),
994
self.deleted(tree1, 'd-id'),
995
self.deleted(tree1, 'e-id'),
997
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
999
def test_added_unicode(self):
1000
tree1 = self.make_branch_and_tree('tree1')
1001
tree2 = self.make_to_branch_and_tree('tree2')
1002
root_id = tree1.get_root_id()
1003
tree2.set_root_id(root_id)
1005
# u'\u03b1' == GREEK SMALL LETTER ALPHA
1006
# u'\u03c9' == GREEK SMALL LETTER OMEGA
1007
a_id = u'\u03b1-id'.encode('utf8')
1008
added_id = u'\u03c9_added_id'.encode('utf8')
1010
self.build_tree([u'tree1/\u03b1/',
1012
u'tree2/\u03b1/\u03c9-added',
1014
except UnicodeError:
1015
raise tests.TestSkipped("Could not create Unicode files.")
1016
tree1.add([u'\u03b1'], [a_id])
1017
tree2.add([u'\u03b1', u'\u03b1/\u03c9-added'], [a_id, added_id])
1019
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1021
self.assertEqual([self.added(tree2, added_id)],
1022
self.do_iter_changes(tree1, tree2))
1023
self.assertEqual([self.added(tree2, added_id)],
1024
self.do_iter_changes(tree1, tree2,
1025
specific_files=[u'\u03b1']))
1027
def test_deleted_unicode(self):
1028
tree1 = self.make_branch_and_tree('tree1')
1029
tree2 = self.make_to_branch_and_tree('tree2')
1030
root_id = tree1.get_root_id()
1031
tree2.set_root_id(root_id)
1033
# u'\u03b1' == GREEK SMALL LETTER ALPHA
1034
# u'\u03c9' == GREEK SMALL LETTER OMEGA
1035
a_id = u'\u03b1-id'.encode('utf8')
1036
deleted_id = u'\u03c9_deleted_id'.encode('utf8')
1038
self.build_tree([u'tree1/\u03b1/',
1039
u'tree1/\u03b1/\u03c9-deleted',
1042
except UnicodeError:
1043
raise tests.TestSkipped("Could not create Unicode files.")
1044
tree1.add([u'\u03b1', u'\u03b1/\u03c9-deleted'], [a_id, deleted_id])
1045
tree2.add([u'\u03b1'], [a_id])
1047
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1049
self.assertEqual([self.deleted(tree1, deleted_id)],
1050
self.do_iter_changes(tree1, tree2))
1051
self.assertEqual([self.deleted(tree1, deleted_id)],
1052
self.do_iter_changes(tree1, tree2,
1053
specific_files=[u'\u03b1']))
1055
def test_modified_unicode(self):
1056
tree1 = self.make_branch_and_tree('tree1')
1057
tree2 = self.make_to_branch_and_tree('tree2')
1058
root_id = tree1.get_root_id()
1059
tree2.set_root_id(root_id)
1061
# u'\u03b1' == GREEK SMALL LETTER ALPHA
1062
# u'\u03c9' == GREEK SMALL LETTER OMEGA
1063
a_id = u'\u03b1-id'.encode('utf8')
1064
mod_id = u'\u03c9_mod_id'.encode('utf8')
1066
self.build_tree([u'tree1/\u03b1/',
1067
u'tree1/\u03b1/\u03c9-modified',
1069
u'tree2/\u03b1/\u03c9-modified',
1071
except UnicodeError:
1072
raise tests.TestSkipped("Could not create Unicode files.")
1073
tree1.add([u'\u03b1', u'\u03b1/\u03c9-modified'], [a_id, mod_id])
1074
tree2.add([u'\u03b1', u'\u03b1/\u03c9-modified'], [a_id, mod_id])
1076
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1078
self.assertEqual([self.content_changed(tree1, mod_id)],
1079
self.do_iter_changes(tree1, tree2))
1080
self.assertEqual([self.content_changed(tree1, mod_id)],
1081
self.do_iter_changes(tree1, tree2,
1082
specific_files=[u'\u03b1']))
1084
def test_renamed_unicode(self):
1085
tree1 = self.make_branch_and_tree('tree1')
1086
tree2 = self.make_to_branch_and_tree('tree2')
1087
root_id = tree1.get_root_id()
1088
tree2.set_root_id(root_id)
1090
# u'\u03b1' == GREEK SMALL LETTER ALPHA
1091
# u'\u03c9' == GREEK SMALL LETTER OMEGA
1092
a_id = u'\u03b1-id'.encode('utf8')
1093
rename_id = u'\u03c9_rename_id'.encode('utf8')
1095
self.build_tree([u'tree1/\u03b1/',
1098
except UnicodeError:
1099
raise tests.TestSkipped("Could not create Unicode files.")
1100
self.build_tree_contents([(u'tree1/\u03c9-source', 'contents\n'),
1101
(u'tree2/\u03b1/\u03c9-target', 'contents\n'),
1103
tree1.add([u'\u03b1', u'\u03c9-source'], [a_id, rename_id])
1104
tree2.add([u'\u03b1', u'\u03b1/\u03c9-target'], [a_id, rename_id])
1106
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1108
self.assertEqual([self.renamed(tree1, tree2, rename_id, False)],
1109
self.do_iter_changes(tree1, tree2))
1110
self.assertEqual([self.renamed(tree1, tree2, rename_id, False)],
1111
self.do_iter_changes(tree1, tree2,
1112
specific_files=[u'\u03b1']))
1114
def test_unchanged_unicode(self):
1115
tree1 = self.make_branch_and_tree('tree1')
1116
tree2 = self.make_to_branch_and_tree('tree2')
1117
root_id = tree1.get_root_id()
1118
tree2.set_root_id(root_id)
1119
# u'\u03b1' == GREEK SMALL LETTER ALPHA
1120
# u'\u03c9' == GREEK SMALL LETTER OMEGA
1121
a_id = u'\u03b1-id'.encode('utf8')
1122
subfile_id = u'\u03c9-subfile-id'.encode('utf8')
1123
rootfile_id = u'\u03c9-root-id'.encode('utf8')
1125
self.build_tree([u'tree1/\u03b1/',
1128
except UnicodeError:
1129
raise tests.TestSkipped("Could not create Unicode files.")
1130
self.build_tree_contents([
1131
(u'tree1/\u03b1/\u03c9-subfile', 'sub contents\n'),
1132
(u'tree2/\u03b1/\u03c9-subfile', 'sub contents\n'),
1133
(u'tree1/\u03c9-rootfile', 'root contents\n'),
1134
(u'tree2/\u03c9-rootfile', 'root contents\n'),
1136
tree1.add([u'\u03b1', u'\u03b1/\u03c9-subfile', u'\u03c9-rootfile'],
1137
[a_id, subfile_id, rootfile_id])
1138
tree2.add([u'\u03b1', u'\u03b1/\u03c9-subfile', u'\u03c9-rootfile'],
1139
[a_id, subfile_id, rootfile_id])
1141
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1144
self.unchanged(tree1, root_id),
1145
self.unchanged(tree1, a_id),
1146
self.unchanged(tree1, subfile_id),
1147
self.unchanged(tree1, rootfile_id),
1149
self.assertEqual(expected,
1150
self.do_iter_changes(tree1, tree2,
1151
include_unchanged=True))
1153
# We should also be able to select just a subset
1155
self.unchanged(tree1, a_id),
1156
self.unchanged(tree1, subfile_id),
1158
self.assertEqual(expected,
1159
self.do_iter_changes(tree1, tree2,
1160
specific_files=[u'\u03b1'],
1161
include_unchanged=True))
1163
def test_unknown_unicode(self):
1164
tree1 = self.make_branch_and_tree('tree1')
1165
tree2 = self.make_to_branch_and_tree('tree2')
1166
root_id = tree1.get_root_id()
1167
tree2.set_root_id(root_id)
1168
# u'\u03b1' == GREEK SMALL LETTER ALPHA
1169
# u'\u03c9' == GREEK SMALL LETTER OMEGA
1170
a_id = u'\u03b1-id'.encode('utf8')
1172
self.build_tree([u'tree1/\u03b1/',
1174
u'tree2/\u03b1/unknown_dir/',
1175
u'tree2/\u03b1/unknown_file',
1176
u'tree2/\u03b1/unknown_dir/file',
1177
u'tree2/\u03c9-unknown_root_file',
1179
except UnicodeError:
1180
raise tests.TestSkipped("Could not create Unicode files.")
1181
tree1.add([u'\u03b1'], [a_id])
1182
tree2.add([u'\u03b1'], [a_id])
1184
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1187
self.unversioned(tree2, u'\u03b1/unknown_dir'),
1188
self.unversioned(tree2, u'\u03b1/unknown_file'),
1189
self.unversioned(tree2, u'\u03c9-unknown_root_file'),
1190
# a/unknown_dir/file should not be included because we should not
1191
# recurse into unknown_dir
1192
# self.unversioned(tree2, 'a/unknown_dir/file'),
1194
self.assertEqual(expected,
1195
self.do_iter_changes(tree1, tree2,
1196
require_versioned=False,
1197
want_unversioned=True))
1198
self.assertEqual([], # Without want_unversioned we should get nothing
1199
self.do_iter_changes(tree1, tree2))
1201
# We should also be able to select just a subset
1203
self.unversioned(tree2, u'\u03b1/unknown_dir'),
1204
self.unversioned(tree2, u'\u03b1/unknown_file'),
1206
self.assertEqual(expected,
1207
self.do_iter_changes(tree1, tree2,
1208
specific_files=[u'\u03b1'],
1209
require_versioned=False,
1210
want_unversioned=True))
1211
self.assertEqual([], # Without want_unversioned we should get nothing
1212
self.do_iter_changes(tree1, tree2,
1213
specific_files=[u'\u03b1']))