13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
"""Tests for the InterTree.compare() function."""
22
from bzrlib import errors, tests, workingtree_4
23
27
from bzrlib.osutils import file_kind, has_symlinks
28
from bzrlib.tests import TestNotApplicable
24
29
from bzrlib.tests.intertree_implementations import TestCaseWithTwoTrees
26
31
# TODO: test the include_root option.
63
68
tree2.set_root_id(tree1.get_root_id())
64
69
tree1 = self.get_tree_no_parents_no_content(tree1)
65
70
tree2 = self.get_tree_no_parents_abc_content(tree2)
66
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
71
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
67
72
d = self.intertree_class(tree1, tree2).compare()
68
73
self.assertEqual([('a', 'a-id', 'file'),
69
74
('b', 'b-id', 'directory'),
124
129
tree2.set_root_id(tree1.get_root_id())
125
130
tree1 = self.get_tree_no_parents_abc_content(tree1)
126
131
tree2 = self.get_tree_no_parents_abc_content_2(tree2)
127
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
132
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
128
133
d = self.intertree_class(tree1, tree2).compare()
129
134
self.assertEqual([], d.added)
130
135
self.assertEqual([('a', 'a-id', 'file', True, False)], d.modified)
131
136
self.assertEqual([], d.removed)
132
137
self.assertEqual([], d.renamed)
133
138
self.assertEqual([], d.unchanged)
135
140
def test_meta_modification(self):
136
141
tree1 = self.make_branch_and_tree('1')
137
142
tree2 = self.make_to_branch_and_tree('2')
138
143
tree2.set_root_id(tree1.get_root_id())
139
144
tree1 = self.get_tree_no_parents_abc_content(tree1)
140
145
tree2 = self.get_tree_no_parents_abc_content_3(tree2)
141
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
146
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
142
147
d = self.intertree_class(tree1, tree2).compare()
143
148
self.assertEqual([], d.added)
144
149
self.assertEqual([('b/c', 'c-id', 'file', False, True)], d.modified)
194
199
tree2.set_root_id(tree1.get_root_id())
195
200
tree1 = self.get_tree_no_parents_no_content(tree1)
196
201
tree2 = self.get_tree_no_parents_abc_content(tree2)
197
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
202
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
198
203
d = self.intertree_class(tree1, tree2).compare(specific_files=['a'])
199
204
self.assertEqual([('a', 'a-id', 'file')], d.added)
200
205
self.assertEqual([], d.modified)
224
229
tree2 = self.make_to_branch_and_tree('2')
225
230
tree1 = self.get_tree_no_parents_no_content(tree1)
226
231
tree2 = self.get_tree_no_parents_abc_content(tree2)
227
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
232
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
228
233
d = self.intertree_class(tree1, tree2).compare(specific_files=['b'])
229
234
self.assertEqual(
230
235
[('b', 'b-id', 'directory'),('b/c', 'c-id', 'file')],
285
290
def test_require_versioned(self):
286
291
# this does not quite robustly test, as it is passing in missing paths
287
292
# rather than present-but-not-versioned paths. At the moment there is
288
# no mechanism for managing the test trees (which are readonly) to
293
# no mechanism for managing the test trees (which are readonly) to
289
294
# get present-but-not-versioned files for trees that can do that.
290
295
tree1 = self.make_branch_and_tree('1')
291
296
tree2 = self.make_to_branch_and_tree('2')
292
297
tree1 = self.get_tree_no_parents_no_content(tree1)
293
298
tree2 = self.get_tree_no_parents_abc_content(tree2)
294
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
295
self.assertRaises(errors.PathsNotVersionedError,
299
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
300
self.assertRaises(errors.PathsNotVersionedError,
296
301
self.intertree_class(tree1, tree2).compare,
297
302
specific_files=['d'],
298
303
require_versioned=True)
306
311
tree1.add(['a', 'c'], ['a-id', 'c-id'])
307
312
tree2.add(['a', 'c'], ['a-id', 'c-id'])
309
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
314
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
310
315
d = self.intertree_class(tree1, tree2).compare()
311
316
self.assertEqual([], d.added)
312
317
self.assertEqual([(u'a', 'a-id', 'file', True, False),
428
434
tree2 = self.make_to_branch_and_tree('2')
429
435
tree1 = self.get_tree_no_parents_no_content(tree1)
430
436
tree2 = self.get_tree_no_parents_no_content(tree2)
431
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
437
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
432
438
self.assertEqual([], self.do_iter_changes(tree1, tree2))
434
440
def added(self, tree, file_id):
435
entry = tree.inventory[file_id]
436
path = tree.id2path(file_id)
441
path, entry = self.get_path_entry(tree, file_id)
437
442
return (file_id, (None, path), True, (False, True), (None, entry.parent_id),
438
443
(None, entry.name), (None, entry.kind),
439
444
(None, entry.executable))
447
def get_path_entry(tree, file_id):
448
iterator = tree.iter_entries_by_dir(specific_file_ids=[file_id])
449
return iterator.next()
441
451
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),
452
path, entry = self.get_path_entry(tree, file_id)
453
return (file_id, (path, path), True, (True, True),
454
(entry.parent_id, entry.parent_id),
445
455
(entry.name, entry.name), (entry.kind, entry.kind),
446
456
(entry.executable, entry.executable))
448
458
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),
459
from_path, old_entry = self.get_path_entry(from_tree, file_id)
460
path, new_entry = self.get_path_entry(to_tree, file_id)
461
return (file_id, (from_path, path), True, (True, True),
462
(old_entry.parent_id, new_entry.parent_id),
463
(old_entry.name, new_entry.name),
464
(old_entry.kind, new_entry.kind),
455
465
(old_entry.executable, new_entry.executable))
457
467
def missing(self, file_id, from_path, to_path, parent_id, kind):
470
480
(entry.executable, None))
472
482
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)
483
from_path, from_entry = self.get_path_entry(from_tree, file_id)
484
to_path, to_entry = self.get_path_entry(to_tree, file_id)
477
485
return (file_id, (from_path, to_path), content_changed, (True, True),
478
486
(from_entry.parent_id, to_entry.parent_id),
479
487
(from_entry.name, to_entry.name),
481
489
(from_entry.executable, to_entry.executable))
483
491
def unchanged(self, tree, file_id):
484
entry = tree.inventory[file_id]
492
path, entry = self.get_path_entry(tree, file_id)
485
493
parent = entry.parent_id
486
494
name = entry.name
487
495
kind = entry.kind
488
496
executable = entry.executable
489
path = tree.id2path(file_id)
490
497
return (file_id, (path, path), False, (True, True),
491
498
(parent, parent), (name, name), (kind, kind),
492
499
(executable, executable))
494
501
def unversioned(self, tree, path):
495
502
"""Create an unversioned result."""
496
503
_, basename = os.path.split(path)
497
kind = file_kind(tree.abspath(path))
504
kind = tree._comparison_data(None, path)[0]
498
505
return (None, (None, path), True, (False, False), (None, None),
499
506
(None, basename), (None, kind),
513
520
self.deleted(tree1, 'empty-root-id')])
514
521
self.assertEqual(expected_results, self.do_iter_changes(tree1, tree2))
523
def test_empty_specific_files(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_no_content(tree1)
527
tree2 = self.get_tree_no_parents_abc_content(tree2)
528
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
530
self.do_iter_changes(tree1, tree2, specific_files=[]))
532
def test_no_specific_files(self):
533
tree1 = self.make_branch_and_tree('1')
534
tree2 = self.make_to_branch_and_tree('2')
535
tree1 = self.get_tree_no_parents_no_content(tree1)
536
tree2 = self.get_tree_no_parents_abc_content(tree2)
537
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
538
expected_results = sorted([
539
self.added(tree2, 'root-id'),
540
self.added(tree2, 'a-id'),
541
self.added(tree2, 'b-id'),
542
self.added(tree2, 'c-id'),
543
self.deleted(tree1, 'empty-root-id')])
544
self.assertEqual(expected_results, self.do_iter_changes(tree1, tree2))
516
546
def test_empty_to_abc_content_a_only(self):
517
547
tree1 = self.make_branch_and_tree('1')
518
548
tree2 = self.make_to_branch_and_tree('2')
569
599
tree2 = self.make_to_branch_and_tree('2')
570
600
tree1 = self.get_tree_no_parents_abc_content(tree1)
571
601
tree2 = self.get_tree_no_parents_abc_content_2(tree2)
572
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
602
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
573
603
root_id = tree1.path2id('')
574
604
self.assertEqual([('a-id', ('a', 'a'), True, (True, True),
575
605
(root_id, root_id), ('a', 'a'),
581
611
tree2 = self.make_to_branch_and_tree('2')
582
612
tree1 = self.get_tree_no_parents_abc_content(tree1)
583
613
tree2 = self.get_tree_no_parents_abc_content_3(tree2)
584
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
614
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
585
615
self.assertEqual([('c-id', ('b/c', 'b/c'), False, (True, True),
586
616
('b-id', 'b-id'), ('c', 'c'), ('file', 'file'),
606
636
tree2 = self.make_to_branch_and_tree('2')
607
637
tree1 = self.get_tree_no_parents_abc_content(tree1)
608
638
tree2 = self.get_tree_no_parents_abc_content_4(tree2)
609
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
639
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
610
640
root_id = tree1.path2id('')
611
641
self.assertEqual([('a-id', ('a', 'd'), False, (True, True),
612
642
(root_id, root_id), ('a', 'd'), ('file', 'file'),
618
648
tree2 = self.make_to_branch_and_tree('2')
619
649
tree1 = self.get_tree_no_parents_abc_content(tree1)
620
650
tree2 = self.get_tree_no_parents_abc_content_5(tree2)
621
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
651
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
622
652
root_id = tree1.path2id('')
623
653
self.assertEqual([('a-id', ('a', 'd'), True, (True, True),
624
654
(root_id, root_id), ('a', 'd'), ('file', 'file'),
630
660
tree2 = self.make_to_branch_and_tree('2')
631
661
tree1 = self.get_tree_no_parents_abc_content(tree1)
632
662
tree2 = self.get_tree_no_parents_abc_content_6(tree2)
633
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
663
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
634
664
root_id = tree1.path2id('')
635
665
self.assertEqual([('c-id', ('b/c', 'e'), False, (True, True),
636
666
('b-id', root_id), ('c', 'e'), ('file', 'file'),
647
677
shutil.rmtree('2/b')
648
678
# TODO ? have a symlink here?
649
tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
679
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
680
self.not_applicable_if_missing_in('a', tree2)
681
self.not_applicable_if_missing_in('b', tree2)
650
682
root_id = tree1.path2id('')
651
683
expected = sorted([
652
684
self.missing('a-id', 'a', 'a', root_id, 'file'),
673
706
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
708
def test_only_in_source_and_missing(self):
709
tree1 = self.make_branch_and_tree('tree1')
710
tree2 = self.make_to_branch_and_tree('tree2')
711
tree2.set_root_id(tree1.get_root_id())
712
self.build_tree(['tree1/file'])
713
tree1.add(['file'], ['file-id'])
714
os.unlink('tree1/file')
715
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
716
self.not_applicable_if_missing_in('file', tree1)
717
root_id = tree1.path2id('')
718
expected = [('file-id', ('file', None), False, (True, False),
719
(root_id, None), ('file', None), (None, None), (False, None))]
720
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
722
def test_only_in_target_and_missing(self):
723
tree1 = self.make_branch_and_tree('tree1')
724
tree2 = self.make_to_branch_and_tree('tree2')
725
tree2.set_root_id(tree1.get_root_id())
726
self.build_tree(['tree2/file'])
727
tree2.add(['file'], ['file-id'])
728
os.unlink('tree2/file')
729
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
730
self.not_applicable_if_missing_in('file', tree2)
731
root_id = tree1.path2id('')
732
expected = [('file-id', (None, 'file'), False, (False, True),
733
(None, root_id), (None, 'file'), (None, None), (None, False))]
734
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
675
736
def test_unchanged_with_renames_and_modifications(self):
676
737
"""want_unchanged should generate a list of unchanged entries."""
677
738
tree1 = self.make_branch_and_tree('1')
964
1029
tree1.add(from_paths_and_ids, from_paths_and_ids)
965
1030
tree2.add(to_paths_and_ids, to_paths_and_ids)
967
# raise TestSkipped('OS does not support symlinks')
968
# links_supported = False
969
1031
return self.mutable_trees_to_locked_test_trees(tree1, tree2)
971
1033
def test_versioned_symlinks(self):
972
if not has_symlinks():
973
raise tests.TestSkipped("No symlink support")
1034
self.requireFeature(tests.SymlinkFeature)
974
1035
tree1, tree2 = self.make_trees_with_symlinks()
1036
self.not_applicable_if_cannot_represent_unversioned(tree2)
975
1037
root_id = tree1.path2id('')
977
1039
self.unchanged(tree1, tree1.path2id('')),