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
expected_unversioned = [(u'dir', None, 'directory'),
337
(u'file', None, 'file')]
339
expected_unversioned.append((u'link', None, 'symlink'))
340
self.assertEqual(expected_unversioned, d.unversioned)
243
343
class TestIterChanges(TestCaseWithTwoTrees):
244
344
"""Test the comparison iterator"""
346
def do_iter_changes(self, tree1, tree2, **extra_args):
347
"""Helper to run _iter_changes from tree1 to tree2.
349
:param tree1, tree2: The source and target trees. These will be locked
351
:param **extra_args: Extra args to pass to _iter_changes. This is not
352
inspected by this test helper.
357
# sort order of output is not strictly defined
358
return sorted(self.intertree_class(tree1, tree2)
359
._iter_changes(**extra_args))
364
def mutable_trees_to_locked_test_trees(self, tree1, tree2):
365
"""Convert the working trees into test trees.
367
Read lock them, and add the unlock to the cleanup.
369
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
371
self.addCleanup(tree1.unlock)
373
self.addCleanup(tree2.unlock)
376
def make_tree_with_special_names(self):
377
"""Create a tree with filenames chosen to exercise the walk order."""
378
tree1 = self.make_branch_and_tree('tree1')
379
tree2 = self.make_to_branch_and_tree('tree2')
380
tree2.set_root_id(tree1.get_root_id())
381
paths, path_ids = self._create_special_names(tree2, 'tree2')
382
tree2.commit('initial', rev_id='rev-1')
383
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
384
return (tree1, tree2, paths, path_ids)
386
def make_trees_with_special_names(self):
387
"""Both trees will use the special names.
389
But the contents will differ for each file.
391
tree1 = self.make_branch_and_tree('tree1')
392
tree2 = self.make_to_branch_and_tree('tree2')
393
tree2.set_root_id(tree1.get_root_id())
394
paths, path_ids = self._create_special_names(tree1, 'tree1')
395
paths, path_ids = self._create_special_names(tree2, 'tree2')
396
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
397
return (tree1, tree2, paths, path_ids)
399
def _create_special_names(self, tree, base_path):
400
"""Create a tree with paths that expose differences in sort orders."""
401
# Each directory will have a single file named 'f' inside
416
with_slashes.append(base_path + '/' + d + '/')
417
with_slashes.append(base_path + '/' + d + '/f')
420
path_ids.append(d.replace('/', '_') + '-id')
421
path_ids.append(d.replace('/', '_') + '_f-id')
422
self.build_tree(with_slashes)
423
tree.add(paths, path_ids)
424
return paths, path_ids
246
426
def test_compare_empty_trees(self):
247
427
tree1 = self.make_branch_and_tree('1')
248
428
tree2 = self.make_to_branch_and_tree('2')
249
429
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)))
430
tree2 = self.get_tree_no_parents_no_content(tree2)
431
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
432
self.assertEqual([], self.do_iter_changes(tree1, tree2))
253
434
def added(self, tree, file_id):
254
435
entry = tree.inventory[file_id]
255
436
path = tree.id2path(file_id)
256
return (file_id, path, True, (False, True), (None, entry.parent_id),
257
(None, entry.name), (None, entry.kind),
437
return (file_id, (None, path), True, (False, True), (None, entry.parent_id),
438
(None, entry.name), (None, entry.kind),
258
439
(None, entry.executable))
441
def content_changed(self, tree, file_id):
442
entry = tree.inventory[file_id]
443
path = tree.id2path(file_id)
444
return (file_id, (path, path), True, (True, True), (entry.parent_id, entry.parent_id),
445
(entry.name, entry.name), (entry.kind, entry.kind),
446
(entry.executable, entry.executable))
448
def kind_changed(self, from_tree, to_tree, file_id):
449
old_entry = from_tree.inventory[file_id]
450
new_entry = to_tree.inventory[file_id]
451
path = to_tree.id2path(file_id)
452
from_path = from_tree.id2path(file_id)
453
return (file_id, (from_path, path), True, (True, True), (old_entry.parent_id, new_entry.parent_id),
454
(old_entry.name, new_entry.name), (old_entry.kind, new_entry.kind),
455
(old_entry.executable, new_entry.executable))
457
def missing(self, file_id, from_path, to_path, parent_id, kind):
458
_, from_basename = os.path.split(from_path)
459
_, to_basename = os.path.split(to_path)
460
# missing files have both paths, but no kind.
461
return (file_id, (from_path, to_path), True, (True, True),
462
(parent_id, parent_id),
463
(from_basename, to_basename), (kind, None), (False, False))
260
465
def deleted(self, tree, file_id):
261
466
entry = tree.inventory[file_id]
262
467
path = tree.id2path(file_id)
263
return (file_id, path, True, (True, False), (entry.parent_id, None),
264
(entry.name, None), (entry.kind, None),
468
return (file_id, (path, None), True, (True, False), (entry.parent_id, None),
469
(entry.name, None), (entry.kind, None),
265
470
(entry.executable, None))
472
def renamed(self, from_tree, to_tree, file_id, content_changed):
473
from_entry = from_tree.inventory[file_id]
474
to_entry = to_tree.inventory[file_id]
475
from_path = from_tree.id2path(file_id)
476
to_path = to_tree.id2path(file_id)
477
return (file_id, (from_path, to_path), content_changed, (True, True),
478
(from_entry.parent_id, to_entry.parent_id),
479
(from_entry.name, to_entry.name),
480
(from_entry.kind, to_entry.kind),
481
(from_entry.executable, to_entry.executable))
483
def unchanged(self, tree, file_id):
484
entry = tree.inventory[file_id]
485
parent = entry.parent_id
488
executable = entry.executable
489
path = tree.id2path(file_id)
490
return (file_id, (path, path), False, (True, True),
491
(parent, parent), (name, name), (kind, kind),
492
(executable, executable))
494
def unversioned(self, tree, path):
495
"""Create an unversioned result."""
496
_, basename = os.path.split(path)
497
kind = file_kind(tree.abspath(path))
498
return (None, (None, path), True, (False, False), (None, None),
499
(None, basename), (None, kind),
267
502
def test_empty_to_abc_content(self):
268
503
tree1 = self.make_branch_and_tree('1')
269
504
tree2 = self.make_to_branch_and_tree('2')
270
505
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)))
506
tree2 = self.get_tree_no_parents_abc_content(tree2)
507
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
508
expected_results = sorted([
509
self.added(tree2, 'root-id'),
510
self.added(tree2, 'a-id'),
511
self.added(tree2, 'b-id'),
512
self.added(tree2, 'c-id'),
513
self.deleted(tree1, 'empty-root-id')])
514
self.assertEqual(expected_results, self.do_iter_changes(tree1, tree2))
280
516
def test_empty_to_abc_content_a_only(self):
281
517
tree1 = self.make_branch_and_tree('1')
282
518
tree2 = self.make_to_branch_and_tree('2')
283
519
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'])))
520
tree2 = self.get_tree_no_parents_abc_content(tree2)
521
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
523
[self.added(tree2, 'a-id')],
524
self.do_iter_changes(tree1, tree2, specific_files=['a']))
526
def test_abc_content_to_empty_to_abc_content_a_only(self):
527
tree1 = self.make_branch_and_tree('1')
528
tree2 = self.make_to_branch_and_tree('2')
529
tree1 = self.get_tree_no_parents_abc_content(tree1)
530
tree2 = self.get_tree_no_parents_no_content(tree2)
531
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
533
[self.deleted(tree1, 'a-id')],
534
self.do_iter_changes(tree1, tree2, specific_files=['a']))
292
536
def test_empty_to_abc_content_a_and_c_only(self):
293
537
tree1 = self.make_branch_and_tree('1')
294
538
tree2 = self.make_to_branch_and_tree('2')
295
539
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'])
540
tree2 = self.get_tree_no_parents_abc_content(tree2)
541
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
542
expected_result = [self.added(tree2, 'a-id'), self.added(tree2, 'c-id')]
543
self.assertEqual(expected_result,
544
self.do_iter_changes(tree1, tree2, specific_files=['a', 'b/c']))
305
def test_abc_content(self):
546
def test_abc_content_to_empty(self):
306
547
tree1 = self.make_branch_and_tree('1')
307
548
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)
549
tree1 = self.get_tree_no_parents_abc_content(tree1)
550
tree2 = self.get_tree_no_parents_no_content(tree2)
551
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
310
552
def deleted(file_id):
311
entry = tree2.inventory[file_id]
312
path = tree2.id2path(file_id)
313
return (file_id, path, True, (True, False),
553
entry = tree1.inventory[file_id]
554
path = tree1.id2path(file_id)
555
return (file_id, (path, None), True, (True, False),
314
556
(entry.parent_id, None),
315
(entry.name, None), (entry.kind, None),
557
(entry.name, None), (entry.kind, None),
316
558
(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)))
559
expected_results = sorted([
560
self.added(tree2, 'empty-root-id'),
561
deleted('root-id'), deleted('a-id'),
562
deleted('b-id'), deleted('c-id')])
565
self.do_iter_changes(tree1, tree2))
322
567
def test_content_modification(self):
323
568
tree1 = self.make_branch_and_tree('1')
324
569
tree2 = self.make_to_branch_and_tree('2')
325
570
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)))
571
tree2 = self.get_tree_no_parents_abc_content_2(tree2)
572
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
573
root_id = tree1.path2id('')
574
self.assertEqual([('a-id', ('a', 'a'), True, (True, True),
575
(root_id, root_id), ('a', 'a'),
576
('file', 'file'), (False, False))],
577
self.do_iter_changes(tree1, tree2))
333
579
def test_meta_modification(self):
334
580
tree1 = self.make_branch_and_tree('1')
335
581
tree2 = self.make_to_branch_and_tree('2')
336
582
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)))
583
tree2 = self.get_tree_no_parents_abc_content_3(tree2)
584
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
585
self.assertEqual([('c-id', ('b/c', 'b/c'), False, (True, True),
586
('b-id', 'b-id'), ('c', 'c'), ('file', 'file'),
588
self.do_iter_changes(tree1, tree2))
590
def test_empty_dir(self):
591
"""an empty dir should not cause glitches to surrounding files."""
592
tree1 = self.make_branch_and_tree('1')
593
tree2 = self.make_to_branch_and_tree('2')
594
tree1 = self.get_tree_no_parents_abc_content(tree1)
595
tree2 = self.get_tree_no_parents_abc_content(tree2)
596
# the pathname is chosen to fall between 'a' and 'b'.
597
self.build_tree(['1/a-empty/', '2/a-empty/'])
598
tree1.add(['a-empty'], ['a-empty'])
599
tree2.add(['a-empty'], ['a-empty'])
600
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
602
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
342
604
def test_file_rename(self):
343
605
tree1 = self.make_branch_and_tree('1')
344
606
tree2 = self.make_to_branch_and_tree('2')
345
607
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)))
608
tree2 = self.get_tree_no_parents_abc_content_4(tree2)
609
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
610
root_id = tree1.path2id('')
611
self.assertEqual([('a-id', ('a', 'd'), False, (True, True),
612
(root_id, root_id), ('a', 'd'), ('file', 'file'),
614
self.do_iter_changes(tree1, tree2))
352
616
def test_file_rename_and_modification(self):
353
617
tree1 = self.make_branch_and_tree('1')
354
618
tree2 = self.make_to_branch_and_tree('2')
355
619
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)))
620
tree2 = self.get_tree_no_parents_abc_content_5(tree2)
621
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
622
root_id = tree1.path2id('')
623
self.assertEqual([('a-id', ('a', 'd'), True, (True, True),
624
(root_id, root_id), ('a', 'd'), ('file', 'file'),
626
self.do_iter_changes(tree1, tree2))
362
628
def test_file_rename_and_meta_modification(self):
363
629
tree1 = self.make_branch_and_tree('1')
364
630
tree2 = self.make_to_branch_and_tree('2')
365
631
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)))
632
tree2 = self.get_tree_no_parents_abc_content_6(tree2)
633
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
634
root_id = tree1.path2id('')
635
self.assertEqual([('c-id', ('b/c', 'e'), False, (True, True),
636
('b-id', root_id), ('c', 'e'), ('file', 'file'),
638
self.do_iter_changes(tree1, tree2))
640
def test_missing_in_target(self):
641
"""Test with the target files versioned but absent from disk."""
642
tree1 = self.make_branch_and_tree('1')
643
tree2 = self.make_to_branch_and_tree('2')
644
tree1 = self.get_tree_no_parents_abc_content(tree1)
645
tree2 = self.get_tree_no_parents_abc_content(tree2)
648
# TODO ? have a symlink here?
649
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
650
root_id = tree1.path2id('')
652
self.missing('a-id', 'a', 'a', root_id, 'file'),
653
self.missing('b-id', 'b', 'b', root_id, 'directory'),
654
self.missing('c-id', 'b/c', 'b/c', 'b-id', 'file'),
656
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
658
def test_missing_and_renamed(self):
659
tree1 = self.make_branch_and_tree('tree1')
660
tree2 = self.make_to_branch_and_tree('tree2')
661
tree2.set_root_id(tree1.get_root_id())
662
self.build_tree(['tree1/file'])
663
tree1.add(['file'], ['file-id'])
664
self.build_tree(['tree2/directory/'])
665
tree2.add(['directory'], ['file-id'])
666
os.rmdir('tree2/directory')
667
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
669
root_id = tree1.path2id('')
671
self.missing('file-id', 'file', 'directory', root_id, 'file'),
673
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
372
675
def test_unchanged_with_renames_and_modifications(self):
373
676
"""want_unchanged should generate a list of unchanged entries."""
374
677
tree1 = self.make_branch_and_tree('1')
375
678
tree2 = self.make_to_branch_and_tree('2')
376
679
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)))
680
tree2 = self.get_tree_no_parents_abc_content_5(tree2)
681
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
682
root_id = tree1.path2id('')
684
self.assertEqual(sorted([self.unchanged(tree1, root_id),
685
self.unchanged(tree1, 'b-id'),
686
('a-id', ('a', 'd'), True, (True, True),
687
(root_id, root_id), ('a', 'd'), ('file', 'file'),
688
(False, False)), self.unchanged(tree1, 'c-id')]),
689
self.do_iter_changes(tree1, tree2, include_unchanged=True))
691
def test_compare_subtrees(self):
692
tree1 = self.make_branch_and_tree('1')
693
if not tree1.supports_tree_reference():
695
tree1.set_root_id('root-id')
696
subtree1 = self.make_branch_and_tree('1/sub')
697
subtree1.set_root_id('subtree-id')
698
tree1.add_reference(subtree1)
700
tree2 = self.make_to_branch_and_tree('2')
701
if not tree2.supports_tree_reference():
703
tree2.set_root_id('root-id')
704
subtree2 = self.make_to_branch_and_tree('2/sub')
705
subtree2.set_root_id('subtree-id')
706
tree2.add_reference(subtree2)
707
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
709
self.assertEqual([], list(tree2._iter_changes(tree1)))
710
subtree1.commit('commit', rev_id='commit-a')
718
('directory', 'directory'),
724
('root-id', 'root-id'),
726
('tree-reference', 'tree-reference'),
728
list(tree2._iter_changes(tree1,
729
include_unchanged=True)))
731
def test_disk_in_subtrees_skipped(self):
732
"""subtrees are considered not-in-the-current-tree.
734
This test tests the trivial case, where the basis has no paths in the
735
current trees subtree.
737
tree1 = self.make_branch_and_tree('1')
738
tree1.set_root_id('root-id')
739
tree2 = self.make_to_branch_and_tree('2')
740
if not tree2.supports_tree_reference():
742
tree2.set_root_id('root-id')
743
subtree2 = self.make_to_branch_and_tree('2/sub')
744
subtree2.set_root_id('subtree-id')
745
tree2.add(['sub'], ['subtree-id'])
746
self.build_tree(['2/sub/file'])
747
subtree2.add(['file'])
749
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
750
# this should filter correctly from above
751
self.assertEqual([self.added(tree2, 'subtree-id')],
752
self.do_iter_changes(tree1, tree2, want_unversioned=True))
753
# and when the path is named
754
self.assertEqual([self.added(tree2, 'subtree-id')],
755
self.do_iter_changes(tree1, tree2, specific_files=['sub'],
756
want_unversioned=True))
758
def test_default_ignores_unversioned_files(self):
759
tree1 = self.make_branch_and_tree('tree1')
760
tree2 = self.make_to_branch_and_tree('tree2')
761
tree2.set_root_id(tree1.get_root_id())
762
self.build_tree(['tree1/a', 'tree1/c',
763
'tree2/a', 'tree2/b', 'tree2/c'])
764
tree1.add(['a', 'c'], ['a-id', 'c-id'])
765
tree2.add(['a', 'c'], ['a-id', 'c-id'])
767
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
769
# We should ignore the fact that 'b' exists in tree-2
770
# because the want_unversioned parameter was not given.
772
self.content_changed(tree2, 'a-id'),
773
self.content_changed(tree2, 'c-id'),
775
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
777
def test_unversioned_paths_in_tree(self):
778
tree1 = self.make_branch_and_tree('tree1')
779
tree2 = self.make_to_branch_and_tree('tree2')
780
tree2.set_root_id(tree1.get_root_id())
781
self.build_tree(['tree2/file', 'tree2/dir/'])
783
os.symlink('target', 'tree2/link')
784
links_supported = True
786
links_supported = False
787
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
789
self.unversioned(tree2, 'file'),
790
self.unversioned(tree2, 'dir'),
793
expected.append(self.unversioned(tree2, 'link'))
794
expected = sorted(expected)
795
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
796
want_unversioned=True))
798
def test_unversioned_paths_in_tree_specific_files(self):
799
tree1 = self.make_branch_and_tree('tree1')
800
tree2 = self.make_to_branch_and_tree('tree2')
801
self.build_tree(['tree2/file', 'tree2/dir/'])
803
os.symlink('target', 'tree2/link')
804
links_supported = True
806
links_supported = False
807
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
809
self.unversioned(tree2, 'file'),
810
self.unversioned(tree2, 'dir'),
812
specific_files=['file', 'dir']
814
expected.append(self.unversioned(tree2, 'link'))
815
specific_files.append('link')
816
expected = sorted(expected)
817
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
818
specific_files=specific_files, require_versioned=False,
819
want_unversioned=True))
821
def test_unversioned_paths_in_target_matching_source_old_names(self):
822
# its likely that naive implementations of unversioned file support
823
# will fail if the path was versioned, but is not any more,
824
# due to a rename, not due to unversioning it.
825
# That is, if the old tree has a versioned file 'foo', and
826
# the new tree has the same file but versioned as 'bar', and also
827
# has an unknown file 'foo', we should get back output for
829
tree1 = self.make_branch_and_tree('tree1')
830
tree2 = self.make_to_branch_and_tree('tree2')
831
tree2.set_root_id(tree1.get_root_id())
832
self.build_tree(['tree2/file', 'tree2/dir/',
833
'tree1/file', 'tree2/movedfile',
834
'tree1/dir/', 'tree2/moveddir/'])
836
os.symlink('target', 'tree1/link')
837
os.symlink('target', 'tree2/link')
838
os.symlink('target', 'tree2/movedlink')
839
links_supported = True
841
links_supported = False
842
tree1.add(['file', 'dir'], ['file-id', 'dir-id'])
843
tree2.add(['movedfile', 'moveddir'], ['file-id', 'dir-id'])
845
tree1.add(['link'], ['link-id'])
846
tree2.add(['movedlink'], ['link-id'])
847
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
848
root_id = tree1.path2id('')
850
self.renamed(tree1, tree2, 'dir-id', False),
851
self.renamed(tree1, tree2, 'file-id', True),
852
self.unversioned(tree2, 'file'),
853
self.unversioned(tree2, 'dir'),
855
specific_files=['file', 'dir']
857
expected.append(self.renamed(tree1, tree2, 'link-id', False))
858
expected.append(self.unversioned(tree2, 'link'))
859
specific_files.append('link')
860
expected = sorted(expected)
861
# run once with, and once without specific files, to catch
862
# potentially different code paths.
863
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
864
require_versioned=False,
865
want_unversioned=True))
866
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
867
specific_files=specific_files, require_versioned=False,
868
want_unversioned=True))
870
def test_unversioned_subtree_only_emits_root(self):
871
tree1 = self.make_branch_and_tree('tree1')
872
tree2 = self.make_to_branch_and_tree('tree2')
873
tree2.set_root_id(tree1.get_root_id())
874
self.build_tree(['tree2/dir/', 'tree2/dir/file'])
875
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
877
self.unversioned(tree2, 'dir'),
879
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
880
want_unversioned=True))
882
def make_trees_with_symlinks(self):
883
tree1 = self.make_branch_and_tree('tree1')
884
tree2 = self.make_to_branch_and_tree('tree2')
885
tree2.set_root_id(tree1.get_root_id())
886
self.build_tree(['tree1/fromfile', 'tree1/fromdir/'])
887
self.build_tree(['tree2/tofile', 'tree2/todir/', 'tree2/unknown'])
889
os.symlink('original', 'tree1/changed')
890
os.symlink('original', 'tree1/removed')
891
os.symlink('original', 'tree1/tofile')
892
os.symlink('original', 'tree1/todir')
893
# we make the unchanged link point at unknown to catch incorrect
894
# symlink-following code in the specified_files test.
895
os.symlink('unknown', 'tree1/unchanged')
896
os.symlink('new', 'tree2/added')
897
os.symlink('new', 'tree2/changed')
898
os.symlink('new', 'tree2/fromfile')
899
os.symlink('new', 'tree2/fromdir')
900
os.symlink('unknown', 'tree2/unchanged')
901
from_paths_and_ids = [
919
tree1.add(from_paths_and_ids, from_paths_and_ids)
920
tree2.add(to_paths_and_ids, to_paths_and_ids)
922
# raise TestSkipped('OS does not support symlinks')
923
# links_supported = False
924
return self.mutable_trees_to_locked_test_trees(tree1, tree2)
926
def test_versioned_symlinks(self):
927
if not has_symlinks():
928
raise tests.TestSkipped("No symlink support")
929
tree1, tree2 = self.make_trees_with_symlinks()
930
root_id = tree1.path2id('')
932
self.unchanged(tree1, tree1.path2id('')),
933
self.added(tree2, 'added'),
934
self.content_changed(tree2, 'changed'),
935
self.kind_changed(tree1, tree2, 'fromdir'),
936
self.kind_changed(tree1, tree2, 'fromfile'),
937
self.deleted(tree1, 'removed'),
938
self.unchanged(tree2, 'unchanged'),
939
self.unversioned(tree2, 'unknown'),
940
self.kind_changed(tree1, tree2, 'todir'),
941
self.kind_changed(tree1, tree2, 'tofile'),
943
expected = sorted(expected)
944
self.assertEqual(expected,
945
self.do_iter_changes(tree1, tree2, include_unchanged=True,
946
want_unversioned=True))
948
def test_versioned_symlinks_specific_files(self):
949
if not has_symlinks():
950
raise tests.TestSkipped("No symlink support")
951
tree1, tree2 = self.make_trees_with_symlinks()
952
root_id = tree1.path2id('')
954
self.added(tree2, 'added'),
955
self.content_changed(tree2, 'changed'),
956
self.kind_changed(tree1, tree2, 'fromdir'),
957
self.kind_changed(tree1, tree2, 'fromfile'),
958
self.deleted(tree1, 'removed'),
959
self.kind_changed(tree1, tree2, 'todir'),
960
self.kind_changed(tree1, tree2, 'tofile'),
962
expected = sorted(expected)
963
# we should get back just the changed links. We pass in 'unchanged' to
964
# make sure that it is correctly not returned - and neither is the
965
# unknown path 'unknown' which it points at.
966
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
967
specific_files=['added', 'changed', 'fromdir', 'fromfile',
968
'removed', 'unchanged', 'todir', 'tofile']))
970
def test_tree_with_special_names(self):
971
tree1, tree2, paths, path_ids = self.make_tree_with_special_names()
972
expected = sorted(self.added(tree2, f_id) for f_id in path_ids)
973
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
975
def test_trees_with_special_names(self):
976
tree1, tree2, paths, path_ids = self.make_trees_with_special_names()
977
expected = sorted(self.content_changed(tree2, f_id) for f_id in path_ids
978
if f_id.endswith('_f-id'))
979
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
981
def test_trees_with_deleted_dir(self):
982
tree1 = self.make_branch_and_tree('tree1')
983
tree2 = self.make_to_branch_and_tree('tree2')
984
tree2.set_root_id(tree1.get_root_id())
985
self.build_tree(['tree1/a', 'tree1/b/', 'tree1/b/c',
986
'tree1/b/d/', 'tree1/b/d/e', 'tree1/f/', 'tree1/f/g',
987
'tree2/a', 'tree2/f/', 'tree2/f/g'])
988
tree1.add(['a', 'b', 'b/c', 'b/d/', 'b/d/e', 'f', 'f/g'],
989
['a-id', 'b-id', 'c-id', 'd-id', 'e-id', 'f-id', 'g-id'])
990
tree2.add(['a', 'f', 'f/g'], ['a-id', 'f-id', 'g-id'])
992
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
993
# We should notice that 'b' and all its children are deleted
995
self.content_changed(tree2, 'a-id'),
996
self.content_changed(tree2, 'g-id'),
997
self.deleted(tree1, 'b-id'),
998
self.deleted(tree1, 'c-id'),
999
self.deleted(tree1, 'd-id'),
1000
self.deleted(tree1, 'e-id'),
1002
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
1004
def test_added_unicode(self):
1005
tree1 = self.make_branch_and_tree('tree1')
1006
tree2 = self.make_to_branch_and_tree('tree2')
1007
root_id = tree1.get_root_id()
1008
tree2.set_root_id(root_id)
1010
# u'\u03b1' == GREEK SMALL LETTER ALPHA
1011
# u'\u03c9' == GREEK SMALL LETTER OMEGA
1012
a_id = u'\u03b1-id'.encode('utf8')
1013
added_id = u'\u03c9_added_id'.encode('utf8')
1015
self.build_tree([u'tree1/\u03b1/',
1017
u'tree2/\u03b1/\u03c9-added',
1019
except UnicodeError:
1020
raise tests.TestSkipped("Could not create Unicode files.")
1021
tree1.add([u'\u03b1'], [a_id])
1022
tree2.add([u'\u03b1', u'\u03b1/\u03c9-added'], [a_id, added_id])
1024
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1026
self.assertEqual([self.added(tree2, added_id)],
1027
self.do_iter_changes(tree1, tree2))
1028
self.assertEqual([self.added(tree2, added_id)],
1029
self.do_iter_changes(tree1, tree2,
1030
specific_files=[u'\u03b1']))
1032
def test_deleted_unicode(self):
1033
tree1 = self.make_branch_and_tree('tree1')
1034
tree2 = self.make_to_branch_and_tree('tree2')
1035
root_id = tree1.get_root_id()
1036
tree2.set_root_id(root_id)
1038
# u'\u03b1' == GREEK SMALL LETTER ALPHA
1039
# u'\u03c9' == GREEK SMALL LETTER OMEGA
1040
a_id = u'\u03b1-id'.encode('utf8')
1041
deleted_id = u'\u03c9_deleted_id'.encode('utf8')
1043
self.build_tree([u'tree1/\u03b1/',
1044
u'tree1/\u03b1/\u03c9-deleted',
1047
except UnicodeError:
1048
raise tests.TestSkipped("Could not create Unicode files.")
1049
tree1.add([u'\u03b1', u'\u03b1/\u03c9-deleted'], [a_id, deleted_id])
1050
tree2.add([u'\u03b1'], [a_id])
1052
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1054
self.assertEqual([self.deleted(tree1, deleted_id)],
1055
self.do_iter_changes(tree1, tree2))
1056
self.assertEqual([self.deleted(tree1, deleted_id)],
1057
self.do_iter_changes(tree1, tree2,
1058
specific_files=[u'\u03b1']))
1060
def test_modified_unicode(self):
1061
tree1 = self.make_branch_and_tree('tree1')
1062
tree2 = self.make_to_branch_and_tree('tree2')
1063
root_id = tree1.get_root_id()
1064
tree2.set_root_id(root_id)
1066
# u'\u03b1' == GREEK SMALL LETTER ALPHA
1067
# u'\u03c9' == GREEK SMALL LETTER OMEGA
1068
a_id = u'\u03b1-id'.encode('utf8')
1069
mod_id = u'\u03c9_mod_id'.encode('utf8')
1071
self.build_tree([u'tree1/\u03b1/',
1072
u'tree1/\u03b1/\u03c9-modified',
1074
u'tree2/\u03b1/\u03c9-modified',
1076
except UnicodeError:
1077
raise tests.TestSkipped("Could not create Unicode files.")
1078
tree1.add([u'\u03b1', u'\u03b1/\u03c9-modified'], [a_id, mod_id])
1079
tree2.add([u'\u03b1', u'\u03b1/\u03c9-modified'], [a_id, mod_id])
1081
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1083
self.assertEqual([self.content_changed(tree1, mod_id)],
1084
self.do_iter_changes(tree1, tree2))
1085
self.assertEqual([self.content_changed(tree1, mod_id)],
1086
self.do_iter_changes(tree1, tree2,
1087
specific_files=[u'\u03b1']))
1089
def test_renamed_unicode(self):
1090
tree1 = self.make_branch_and_tree('tree1')
1091
tree2 = self.make_to_branch_and_tree('tree2')
1092
root_id = tree1.get_root_id()
1093
tree2.set_root_id(root_id)
1095
# u'\u03b1' == GREEK SMALL LETTER ALPHA
1096
# u'\u03c9' == GREEK SMALL LETTER OMEGA
1097
a_id = u'\u03b1-id'.encode('utf8')
1098
rename_id = u'\u03c9_rename_id'.encode('utf8')
1100
self.build_tree([u'tree1/\u03b1/',
1103
except UnicodeError:
1104
raise tests.TestSkipped("Could not create Unicode files.")
1105
self.build_tree_contents([(u'tree1/\u03c9-source', 'contents\n'),
1106
(u'tree2/\u03b1/\u03c9-target', 'contents\n'),
1108
tree1.add([u'\u03b1', u'\u03c9-source'], [a_id, rename_id])
1109
tree2.add([u'\u03b1', u'\u03b1/\u03c9-target'], [a_id, rename_id])
1111
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1113
self.assertEqual([self.renamed(tree1, tree2, rename_id, False)],
1114
self.do_iter_changes(tree1, tree2))
1115
self.assertEqual([self.renamed(tree1, tree2, rename_id, False)],
1116
self.do_iter_changes(tree1, tree2,
1117
specific_files=[u'\u03b1']))
1119
def test_unchanged_unicode(self):
1120
tree1 = self.make_branch_and_tree('tree1')
1121
tree2 = self.make_to_branch_and_tree('tree2')
1122
root_id = tree1.get_root_id()
1123
tree2.set_root_id(root_id)
1124
# u'\u03b1' == GREEK SMALL LETTER ALPHA
1125
# u'\u03c9' == GREEK SMALL LETTER OMEGA
1126
a_id = u'\u03b1-id'.encode('utf8')
1127
subfile_id = u'\u03c9-subfile-id'.encode('utf8')
1128
rootfile_id = u'\u03c9-root-id'.encode('utf8')
1130
self.build_tree([u'tree1/\u03b1/',
1133
except UnicodeError:
1134
raise tests.TestSkipped("Could not create Unicode files.")
1135
self.build_tree_contents([
1136
(u'tree1/\u03b1/\u03c9-subfile', 'sub contents\n'),
1137
(u'tree2/\u03b1/\u03c9-subfile', 'sub contents\n'),
1138
(u'tree1/\u03c9-rootfile', 'root contents\n'),
1139
(u'tree2/\u03c9-rootfile', 'root contents\n'),
1141
tree1.add([u'\u03b1', u'\u03b1/\u03c9-subfile', u'\u03c9-rootfile'],
1142
[a_id, subfile_id, rootfile_id])
1143
tree2.add([u'\u03b1', u'\u03b1/\u03c9-subfile', u'\u03c9-rootfile'],
1144
[a_id, subfile_id, rootfile_id])
1146
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1149
self.unchanged(tree1, root_id),
1150
self.unchanged(tree1, a_id),
1151
self.unchanged(tree1, subfile_id),
1152
self.unchanged(tree1, rootfile_id),
1154
self.assertEqual(expected,
1155
self.do_iter_changes(tree1, tree2,
1156
include_unchanged=True))
1158
# We should also be able to select just a subset
1160
self.unchanged(tree1, a_id),
1161
self.unchanged(tree1, subfile_id),
1163
self.assertEqual(expected,
1164
self.do_iter_changes(tree1, tree2,
1165
specific_files=[u'\u03b1'],
1166
include_unchanged=True))
1168
def test_unknown_unicode(self):
1169
tree1 = self.make_branch_and_tree('tree1')
1170
tree2 = self.make_to_branch_and_tree('tree2')
1171
root_id = tree1.get_root_id()
1172
tree2.set_root_id(root_id)
1173
# u'\u03b1' == GREEK SMALL LETTER ALPHA
1174
# u'\u03c9' == GREEK SMALL LETTER OMEGA
1175
a_id = u'\u03b1-id'.encode('utf8')
1177
self.build_tree([u'tree1/\u03b1/',
1179
u'tree2/\u03b1/unknown_dir/',
1180
u'tree2/\u03b1/unknown_file',
1181
u'tree2/\u03b1/unknown_dir/file',
1182
u'tree2/\u03c9-unknown_root_file',
1184
except UnicodeError:
1185
raise tests.TestSkipped("Could not create Unicode files.")
1186
tree1.add([u'\u03b1'], [a_id])
1187
tree2.add([u'\u03b1'], [a_id])
1189
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1192
self.unversioned(tree2, u'\u03b1/unknown_dir'),
1193
self.unversioned(tree2, u'\u03b1/unknown_file'),
1194
self.unversioned(tree2, u'\u03c9-unknown_root_file'),
1195
# a/unknown_dir/file should not be included because we should not
1196
# recurse into unknown_dir
1197
# self.unversioned(tree2, 'a/unknown_dir/file'),
1199
self.assertEqual(expected,
1200
self.do_iter_changes(tree1, tree2,
1201
require_versioned=False,
1202
want_unversioned=True))
1203
self.assertEqual([], # Without want_unversioned we should get nothing
1204
self.do_iter_changes(tree1, tree2))
1206
# We should also be able to select just a subset
1208
self.unversioned(tree2, u'\u03b1/unknown_dir'),
1209
self.unversioned(tree2, u'\u03b1/unknown_file'),
1211
self.assertEqual(expected,
1212
self.do_iter_changes(tree1, tree2,
1213
specific_files=[u'\u03b1'],
1214
require_versioned=False,
1215
want_unversioned=True))
1216
self.assertEqual([], # Without want_unversioned we should get nothing
1217
self.do_iter_changes(tree1, tree2,
1218
specific_files=[u'\u03b1']))
1220
def test_unknown_empty_dir(self):
1221
tree1 = self.make_branch_and_tree('tree1')
1222
tree2 = self.make_to_branch_and_tree('tree2')
1223
root_id = tree1.get_root_id()
1224
tree2.set_root_id(root_id)
1226
# Start with 2 identical trees
1227
self.build_tree(['tree1/a/', 'tree1/b/',
1228
'tree2/a/', 'tree2/b/'])
1229
self.build_tree_contents([('tree1/b/file', 'contents\n'),
1230
('tree2/b/file', 'contents\n')])
1231
tree1.add(['a', 'b', 'b/file'], ['a-id', 'b-id', 'b-file-id'])
1232
tree2.add(['a', 'b', 'b/file'], ['a-id', 'b-id', 'b-file-id'])
1234
# Now create some unknowns in tree2
1235
# We should find both a/file and a/dir as unknown, but we shouldn't
1236
# recurse into a/dir to find that a/dir/subfile is also unknown.
1237
self.build_tree(['tree2/a/file', 'tree2/a/dir/', 'tree2/a/dir/subfile'])
1239
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1242
self.unversioned(tree2, u'a/file'),
1243
self.unversioned(tree2, u'a/dir'),
1245
self.assertEqual(expected,
1246
self.do_iter_changes(tree1, tree2,
1247
require_versioned=False,
1248
want_unversioned=True))