1
# Copyright (C) 2006, 2007 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
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
17
"""Tests for the InterTree.compare() function."""
22
from bzrlib import errors, tests, workingtree_4
23
from bzrlib.osutils import file_kind, has_symlinks
24
from bzrlib.tests import TestNotApplicable
25
from bzrlib.tests.intertree_implementations import TestCaseWithTwoTrees
27
# TODO: test the include_root option.
28
# TODO: test that renaming a directory x->y does not emit a rename for the
30
# TODO: test that renaming a directory x-> does not emit a rename for the child
31
# x/a -> y/a when a supplied_files argument gives either 'x/' or 'y/a'
32
# -> that is, when the renamed parent is not processed by the function.
33
# TODO: test items are only emitted once when a specific_files list names a dir
34
# whose parent is now a child.
35
# TODO: test specific_files when the target tree has a file and the source a
36
# dir with children, same id and same path.
37
# TODO: test comparisons between trees with different root ids. mbp 20070301
39
# TODO: More comparisons between trees with subtrees in different states.
41
# TODO: Many tests start out by setting the tree roots ids the same, maybe
42
# that should just be the default for these tests, by changing
43
# make_branch_and_tree. mbp 20070307
45
class TestCompare(TestCaseWithTwoTrees):
47
def test_compare_empty_trees(self):
48
tree1 = self.make_branch_and_tree('1')
49
tree2 = self.make_to_branch_and_tree('2')
50
tree2.set_root_id(tree1.get_root_id())
51
tree1 = self.get_tree_no_parents_no_content(tree1)
52
tree2 = self.get_tree_no_parents_no_content(tree2)
53
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
54
d = self.intertree_class(tree1, tree2).compare()
55
self.assertEqual([], d.added)
56
self.assertEqual([], d.modified)
57
self.assertEqual([], d.removed)
58
self.assertEqual([], d.renamed)
59
self.assertEqual([], d.unchanged)
61
def test_empty_to_abc_content(self):
62
tree1 = self.make_branch_and_tree('1')
63
tree2 = self.make_to_branch_and_tree('2')
64
tree2.set_root_id(tree1.get_root_id())
65
tree1 = self.get_tree_no_parents_no_content(tree1)
66
tree2 = self.get_tree_no_parents_abc_content(tree2)
67
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
68
d = self.intertree_class(tree1, tree2).compare()
69
self.assertEqual([('a', 'a-id', 'file'),
70
('b', 'b-id', 'directory'),
71
('b/c', 'c-id', 'file'),
73
self.assertEqual([], d.modified)
74
self.assertEqual([], d.removed)
75
self.assertEqual([], d.renamed)
76
self.assertEqual([], d.unchanged)
78
def test_dangling(self):
79
# This test depends on the ability for some trees to have a difference
80
# between a 'versioned present' and 'versioned not present' (aka
81
# dangling) file. In this test there are two trees each with a separate
82
# dangling file, and the dangling files should be considered absent for
84
tree1 = self.make_branch_and_tree('1')
85
tree2 = self.make_to_branch_and_tree('2')
86
tree2.set_root_id(tree1.get_root_id())
87
self.build_tree(['2/a'])
90
self.build_tree(['1/b'])
93
# the conversion to test trees here will leave the trees intact for the
94
# default intertree, but may perform a commit for other tree types,
95
# which may reduce the validity of the test. XXX: Think about how to
97
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
98
d = self.intertree_class(tree1, tree2).compare()
99
self.assertEqual([], d.added)
100
self.assertEqual([], d.modified)
101
self.assertEqual([], d.removed)
102
self.assertEqual([], d.renamed)
103
self.assertEqual([], d.unchanged)
105
def test_abc_content_to_empty(self):
106
tree1 = self.make_branch_and_tree('1')
107
tree2 = self.make_to_branch_and_tree('2')
108
tree2.set_root_id(tree1.get_root_id())
109
tree1 = self.get_tree_no_parents_abc_content(tree1)
110
tree2 = self.get_tree_no_parents_no_content(tree2)
111
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
112
d = self.intertree_class(tree1, tree2).compare()
113
self.assertEqual([], d.added)
114
self.assertEqual([], d.modified)
115
self.assertEqual([('a', 'a-id', 'file'),
116
('b', 'b-id', 'directory'),
117
('b/c', 'c-id', 'file'),
119
self.assertEqual([], d.renamed)
120
self.assertEqual([], d.unchanged)
122
def test_content_modification(self):
123
tree1 = self.make_branch_and_tree('1')
124
tree2 = self.make_to_branch_and_tree('2')
125
tree2.set_root_id(tree1.get_root_id())
126
tree1 = self.get_tree_no_parents_abc_content(tree1)
127
tree2 = self.get_tree_no_parents_abc_content_2(tree2)
128
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
129
d = self.intertree_class(tree1, tree2).compare()
130
self.assertEqual([], d.added)
131
self.assertEqual([('a', 'a-id', 'file', True, False)], d.modified)
132
self.assertEqual([], d.removed)
133
self.assertEqual([], d.renamed)
134
self.assertEqual([], d.unchanged)
136
def test_meta_modification(self):
137
tree1 = self.make_branch_and_tree('1')
138
tree2 = self.make_to_branch_and_tree('2')
139
tree2.set_root_id(tree1.get_root_id())
140
tree1 = self.get_tree_no_parents_abc_content(tree1)
141
tree2 = self.get_tree_no_parents_abc_content_3(tree2)
142
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
143
d = self.intertree_class(tree1, tree2).compare()
144
self.assertEqual([], d.added)
145
self.assertEqual([('b/c', 'c-id', 'file', False, True)], d.modified)
146
self.assertEqual([], d.removed)
147
self.assertEqual([], d.renamed)
148
self.assertEqual([], d.unchanged)
150
def test_file_rename(self):
151
tree1 = self.make_branch_and_tree('1')
152
tree2 = self.make_to_branch_and_tree('2')
153
tree2.set_root_id(tree1.get_root_id())
154
tree1 = self.get_tree_no_parents_abc_content(tree1)
155
tree2 = self.get_tree_no_parents_abc_content_4(tree2)
156
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
157
d = self.intertree_class(tree1, tree2).compare()
158
self.assertEqual([], d.added)
159
self.assertEqual([], d.modified)
160
self.assertEqual([], d.removed)
161
self.assertEqual([('a', 'd', 'a-id', 'file', False, False)], d.renamed)
162
self.assertEqual([], d.unchanged)
164
def test_file_rename_and_modification(self):
165
tree1 = self.make_branch_and_tree('1')
166
tree2 = self.make_to_branch_and_tree('2')
167
tree2.set_root_id(tree1.get_root_id())
168
tree1 = self.get_tree_no_parents_abc_content(tree1)
169
tree2 = self.get_tree_no_parents_abc_content_5(tree2)
170
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
171
d = self.intertree_class(tree1, tree2).compare()
172
self.assertEqual([], d.added)
173
self.assertEqual([], d.modified)
174
self.assertEqual([], d.removed)
175
self.assertEqual([('a', 'd', 'a-id', 'file', True, False)], d.renamed)
176
self.assertEqual([], d.unchanged)
178
def test_file_rename_and_meta_modification(self):
179
tree1 = self.make_branch_and_tree('1')
180
tree2 = self.make_to_branch_and_tree('2')
181
tree2.set_root_id(tree1.get_root_id())
182
tree1 = self.get_tree_no_parents_abc_content(tree1)
183
tree2 = self.get_tree_no_parents_abc_content_6(tree2)
184
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
185
d = self.intertree_class(tree1, tree2).compare()
186
self.assertEqual([], d.added)
187
self.assertEqual([], d.modified)
188
self.assertEqual([], d.removed)
189
self.assertEqual([('b/c', 'e', 'c-id', 'file', False, True)], d.renamed)
190
self.assertEqual([], d.unchanged)
192
def test_empty_to_abc_content_a_only(self):
193
tree1 = self.make_branch_and_tree('1')
194
tree2 = self.make_to_branch_and_tree('2')
195
tree2.set_root_id(tree1.get_root_id())
196
tree1 = self.get_tree_no_parents_no_content(tree1)
197
tree2 = self.get_tree_no_parents_abc_content(tree2)
198
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
199
d = self.intertree_class(tree1, tree2).compare(specific_files=['a'])
200
self.assertEqual([('a', 'a-id', 'file')], d.added)
201
self.assertEqual([], d.modified)
202
self.assertEqual([], d.removed)
203
self.assertEqual([], d.renamed)
204
self.assertEqual([], d.unchanged)
206
def test_empty_to_abc_content_a_and_c_only(self):
207
tree1 = self.make_branch_and_tree('1')
208
tree2 = self.make_to_branch_and_tree('2')
209
tree1 = self.get_tree_no_parents_no_content(tree1)
210
tree2 = self.get_tree_no_parents_abc_content(tree2)
211
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
212
d = self.intertree_class(tree1, tree2).compare(
213
specific_files=['a', 'b/c'])
215
[('a', 'a-id', 'file'), ('b/c', 'c-id', 'file')],
217
self.assertEqual([], d.modified)
218
self.assertEqual([], d.removed)
219
self.assertEqual([], d.renamed)
220
self.assertEqual([], d.unchanged)
222
def test_empty_to_abc_content_b_only(self):
223
"""Restricting to a dir matches the children of the dir."""
224
tree1 = self.make_branch_and_tree('1')
225
tree2 = self.make_to_branch_and_tree('2')
226
tree1 = self.get_tree_no_parents_no_content(tree1)
227
tree2 = self.get_tree_no_parents_abc_content(tree2)
228
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
229
d = self.intertree_class(tree1, tree2).compare(specific_files=['b'])
231
[('b', 'b-id', 'directory'),('b/c', 'c-id', 'file')],
233
self.assertEqual([], d.modified)
234
self.assertEqual([], d.removed)
235
self.assertEqual([], d.renamed)
236
self.assertEqual([], d.unchanged)
238
def test_unchanged_with_renames_and_modifications(self):
239
"""want_unchanged should generate a list of unchanged entries."""
240
tree1 = self.make_branch_and_tree('1')
241
tree2 = self.make_to_branch_and_tree('2')
242
tree1 = self.get_tree_no_parents_abc_content(tree1)
243
tree2 = self.get_tree_no_parents_abc_content_5(tree2)
244
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
245
d = self.intertree_class(tree1, tree2).compare(want_unchanged=True)
246
self.assertEqual([], d.added)
247
self.assertEqual([], d.modified)
248
self.assertEqual([], d.removed)
249
self.assertEqual([('a', 'd', 'a-id', 'file', True, False)], d.renamed)
251
[(u'b', 'b-id', 'directory'), (u'b/c', 'c-id', 'file')],
254
def test_extra_trees_finds_ids(self):
255
"""Ask for a delta between two trees with a path present in a third."""
256
tree1 = self.make_branch_and_tree('1')
257
tree2 = self.make_to_branch_and_tree('2')
258
tree1 = self.get_tree_no_parents_abc_content(tree1)
259
tree2 = self.get_tree_no_parents_abc_content_3(tree2)
260
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
261
d = self.intertree_class(tree1, tree2).compare(specific_files=['b'])
262
# the type of tree-3 does not matter - it is used as a lookup, not
263
# a dispatch. XXX: For dirstate it does speak to the optimisability of
264
# the lookup, in merged trees it can be fast-pathed. We probably want
265
# two tests: one as is, and one with it as a pending merge.
266
tree3 = self.make_branch_and_tree('3')
267
tree3 = self.get_tree_no_parents_abc_content_6(tree3)
269
self.addCleanup(tree3.unlock)
270
# tree 3 has 'e' which is 'c-id'. Tree 1 has c-id at b/c, and Tree 2
271
# has c-id at b/c with its exec flag toggled.
272
# without extra_trees, we should get no modifications from this
273
# so do one, to be sure the test is valid.
274
d = self.intertree_class(tree1, tree2).compare(
275
specific_files=['e'])
276
self.assertEqual([], d.modified)
277
# now give it an additional lookup:
278
d = self.intertree_class(tree1, tree2).compare(
279
specific_files=['e'], extra_trees=[tree3])
280
self.assertEqual([], d.added)
281
self.assertEqual([('b/c', 'c-id', 'file', False, True)], d.modified)
282
self.assertEqual([], d.removed)
283
self.assertEqual([], d.renamed)
284
self.assertEqual([], d.unchanged)
286
def test_require_versioned(self):
287
# this does not quite robustly test, as it is passing in missing paths
288
# rather than present-but-not-versioned paths. At the moment there is
289
# no mechanism for managing the test trees (which are readonly) to
290
# get present-but-not-versioned files for trees that can do that.
291
tree1 = self.make_branch_and_tree('1')
292
tree2 = self.make_to_branch_and_tree('2')
293
tree1 = self.get_tree_no_parents_no_content(tree1)
294
tree2 = self.get_tree_no_parents_abc_content(tree2)
295
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
296
self.assertRaises(errors.PathsNotVersionedError,
297
self.intertree_class(tree1, tree2).compare,
298
specific_files=['d'],
299
require_versioned=True)
301
def test_default_ignores_unversioned_files(self):
302
tree1 = self.make_branch_and_tree('tree1')
303
tree2 = self.make_to_branch_and_tree('tree2')
304
tree2.set_root_id(tree1.get_root_id())
305
self.build_tree(['tree1/a', 'tree1/c',
306
'tree2/a', 'tree2/b', 'tree2/c'])
307
tree1.add(['a', 'c'], ['a-id', 'c-id'])
308
tree2.add(['a', 'c'], ['a-id', 'c-id'])
310
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
311
d = self.intertree_class(tree1, tree2).compare()
312
self.assertEqual([], d.added)
313
self.assertEqual([(u'a', 'a-id', 'file', True, False),
314
(u'c', 'c-id', 'file', True, False)], d.modified)
315
self.assertEqual([], d.removed)
316
self.assertEqual([], d.renamed)
317
self.assertEqual([], d.unchanged)
318
self.assertEqual([], d.unversioned)
320
def test_unversioned_paths_in_tree(self):
321
tree1 = self.make_branch_and_tree('tree1')
322
tree2 = self.make_to_branch_and_tree('tree2')
323
tree2.set_root_id(tree1.get_root_id())
324
self.build_tree(['tree2/file', 'tree2/dir/'])
326
os.symlink('target', 'tree2/link')
327
links_supported = True
329
links_supported = False
330
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
331
d = self.intertree_class(tree1, tree2).compare(want_unversioned=True)
332
self.assertEqual([], d.added)
333
self.assertEqual([], d.modified)
334
self.assertEqual([], d.removed)
335
self.assertEqual([], d.renamed)
336
self.assertEqual([], d.unchanged)
337
expected_unversioned = [(u'dir', None, 'directory'),
338
(u'file', None, 'file')]
340
expected_unversioned.append((u'link', None, 'symlink'))
341
self.assertEqual(expected_unversioned, d.unversioned)
344
class TestIterChanges(TestCaseWithTwoTrees):
345
"""Test the comparison iterator"""
347
def do_iter_changes(self, tree1, tree2, **extra_args):
348
"""Helper to run iter_changes from tree1 to tree2.
350
:param tree1, tree2: The source and target trees. These will be locked
352
:param **extra_args: Extra args to pass to iter_changes. This is not
353
inspected by this test helper.
358
# sort order of output is not strictly defined
359
return sorted(self.intertree_class(tree1, tree2)
360
.iter_changes(**extra_args))
365
def mutable_trees_to_locked_test_trees(self, tree1, tree2):
366
"""Convert the working trees into test trees.
368
Read lock them, and add the unlock to the cleanup.
370
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
372
self.addCleanup(tree1.unlock)
374
self.addCleanup(tree2.unlock)
377
def make_tree_with_special_names(self):
378
"""Create a tree with filenames chosen to exercise the walk order."""
379
tree1 = self.make_branch_and_tree('tree1')
380
tree2 = self.make_to_branch_and_tree('tree2')
381
tree2.set_root_id(tree1.get_root_id())
382
paths, path_ids = self._create_special_names(tree2, 'tree2')
383
tree2.commit('initial', rev_id='rev-1')
384
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
385
return (tree1, tree2, paths, path_ids)
387
def make_trees_with_special_names(self):
388
"""Both trees will use the special names.
390
But the contents will differ for each file.
392
tree1 = self.make_branch_and_tree('tree1')
393
tree2 = self.make_to_branch_and_tree('tree2')
394
tree2.set_root_id(tree1.get_root_id())
395
paths, path_ids = self._create_special_names(tree1, 'tree1')
396
paths, path_ids = self._create_special_names(tree2, 'tree2')
397
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
398
return (tree1, tree2, paths, path_ids)
400
def _create_special_names(self, tree, base_path):
401
"""Create a tree with paths that expose differences in sort orders."""
402
# Each directory will have a single file named 'f' inside
417
with_slashes.append(base_path + '/' + d + '/')
418
with_slashes.append(base_path + '/' + d + '/f')
421
path_ids.append(d.replace('/', '_') + '-id')
422
path_ids.append(d.replace('/', '_') + '_f-id')
423
self.build_tree(with_slashes)
424
tree.add(paths, path_ids)
425
return paths, path_ids
427
def test_compare_empty_trees(self):
428
tree1 = self.make_branch_and_tree('1')
429
tree2 = self.make_to_branch_and_tree('2')
430
tree1 = self.get_tree_no_parents_no_content(tree1)
431
tree2 = self.get_tree_no_parents_no_content(tree2)
432
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
433
self.assertEqual([], self.do_iter_changes(tree1, tree2))
435
def added(self, tree, file_id):
436
path, entry = self.get_path_entry(tree, file_id)
437
return (file_id, (None, path), True, (False, True), (None, entry.parent_id),
438
(None, entry.name), (None, entry.kind),
439
(None, entry.executable))
442
def get_path_entry(tree, file_id):
443
iterator = tree.iter_entries_by_dir(specific_file_ids=[file_id])
444
return iterator.next()
446
def content_changed(self, tree, file_id):
447
path, entry = self.get_path_entry(tree, file_id)
448
return (file_id, (path, path), True, (True, True),
449
(entry.parent_id, entry.parent_id),
450
(entry.name, entry.name), (entry.kind, entry.kind),
451
(entry.executable, entry.executable))
453
def kind_changed(self, from_tree, to_tree, file_id):
454
from_path, old_entry = self.get_path_entry(from_tree, file_id)
455
path, new_entry = self.get_path_entry(to_tree, file_id)
456
return (file_id, (from_path, path), True, (True, True),
457
(old_entry.parent_id, new_entry.parent_id),
458
(old_entry.name, new_entry.name),
459
(old_entry.kind, new_entry.kind),
460
(old_entry.executable, new_entry.executable))
462
def missing(self, file_id, from_path, to_path, parent_id, kind):
463
_, from_basename = os.path.split(from_path)
464
_, to_basename = os.path.split(to_path)
465
# missing files have both paths, but no kind.
466
return (file_id, (from_path, to_path), True, (True, True),
467
(parent_id, parent_id),
468
(from_basename, to_basename), (kind, None), (False, False))
470
def deleted(self, tree, file_id):
471
entry = tree.inventory[file_id]
472
path = tree.id2path(file_id)
473
return (file_id, (path, None), True, (True, False), (entry.parent_id, None),
474
(entry.name, None), (entry.kind, None),
475
(entry.executable, None))
477
def renamed(self, from_tree, to_tree, file_id, content_changed):
478
from_path, from_entry = self.get_path_entry(from_tree, file_id)
479
to_path, to_entry = self.get_path_entry(to_tree, file_id)
480
return (file_id, (from_path, to_path), content_changed, (True, True),
481
(from_entry.parent_id, to_entry.parent_id),
482
(from_entry.name, to_entry.name),
483
(from_entry.kind, to_entry.kind),
484
(from_entry.executable, to_entry.executable))
486
def unchanged(self, tree, file_id):
487
path, entry = self.get_path_entry(tree, file_id)
488
parent = entry.parent_id
491
executable = entry.executable
492
return (file_id, (path, path), False, (True, True),
493
(parent, parent), (name, name), (kind, kind),
494
(executable, executable))
496
def unversioned(self, tree, path):
497
"""Create an unversioned result."""
498
_, basename = os.path.split(path)
499
kind = tree._comparison_data(None, path)[0]
500
return (None, (None, path), True, (False, False), (None, None),
501
(None, basename), (None, kind),
504
def test_empty_to_abc_content(self):
505
tree1 = self.make_branch_and_tree('1')
506
tree2 = self.make_to_branch_and_tree('2')
507
tree1 = self.get_tree_no_parents_no_content(tree1)
508
tree2 = self.get_tree_no_parents_abc_content(tree2)
509
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
510
expected_results = sorted([
511
self.added(tree2, 'root-id'),
512
self.added(tree2, 'a-id'),
513
self.added(tree2, 'b-id'),
514
self.added(tree2, 'c-id'),
515
self.deleted(tree1, 'empty-root-id')])
516
self.assertEqual(expected_results, self.do_iter_changes(tree1, tree2))
518
def test_empty_specific_files(self):
519
tree1 = self.make_branch_and_tree('1')
520
tree2 = self.make_to_branch_and_tree('2')
521
tree1 = self.get_tree_no_parents_no_content(tree1)
522
tree2 = self.get_tree_no_parents_abc_content(tree2)
523
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
525
self.do_iter_changes(tree1, tree2, specific_files=[]))
527
def test_no_specific_files(self):
528
tree1 = self.make_branch_and_tree('1')
529
tree2 = self.make_to_branch_and_tree('2')
530
tree1 = self.get_tree_no_parents_no_content(tree1)
531
tree2 = self.get_tree_no_parents_abc_content(tree2)
532
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
533
expected_results = sorted([
534
self.added(tree2, 'root-id'),
535
self.added(tree2, 'a-id'),
536
self.added(tree2, 'b-id'),
537
self.added(tree2, 'c-id'),
538
self.deleted(tree1, 'empty-root-id')])
539
self.assertEqual(expected_results, self.do_iter_changes(tree1, tree2))
541
def test_empty_to_abc_content_a_only(self):
542
tree1 = self.make_branch_and_tree('1')
543
tree2 = self.make_to_branch_and_tree('2')
544
tree1 = self.get_tree_no_parents_no_content(tree1)
545
tree2 = self.get_tree_no_parents_abc_content(tree2)
546
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
548
[self.added(tree2, 'a-id')],
549
self.do_iter_changes(tree1, tree2, specific_files=['a']))
551
def test_abc_content_to_empty_to_abc_content_a_only(self):
552
tree1 = self.make_branch_and_tree('1')
553
tree2 = self.make_to_branch_and_tree('2')
554
tree1 = self.get_tree_no_parents_abc_content(tree1)
555
tree2 = self.get_tree_no_parents_no_content(tree2)
556
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
558
[self.deleted(tree1, 'a-id')],
559
self.do_iter_changes(tree1, tree2, specific_files=['a']))
561
def test_empty_to_abc_content_a_and_c_only(self):
562
tree1 = self.make_branch_and_tree('1')
563
tree2 = self.make_to_branch_and_tree('2')
564
tree1 = self.get_tree_no_parents_no_content(tree1)
565
tree2 = self.get_tree_no_parents_abc_content(tree2)
566
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
567
expected_result = [self.added(tree2, 'a-id'), self.added(tree2, 'c-id')]
568
self.assertEqual(expected_result,
569
self.do_iter_changes(tree1, tree2, specific_files=['a', 'b/c']))
571
def test_abc_content_to_empty(self):
572
tree1 = self.make_branch_and_tree('1')
573
tree2 = self.make_to_branch_and_tree('2')
574
tree1 = self.get_tree_no_parents_abc_content(tree1)
575
tree2 = self.get_tree_no_parents_no_content(tree2)
576
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
577
def deleted(file_id):
578
entry = tree1.inventory[file_id]
579
path = tree1.id2path(file_id)
580
return (file_id, (path, None), True, (True, False),
581
(entry.parent_id, None),
582
(entry.name, None), (entry.kind, None),
583
(entry.executable, None))
584
expected_results = sorted([
585
self.added(tree2, 'empty-root-id'),
586
deleted('root-id'), deleted('a-id'),
587
deleted('b-id'), deleted('c-id')])
590
self.do_iter_changes(tree1, tree2))
592
def test_content_modification(self):
593
tree1 = self.make_branch_and_tree('1')
594
tree2 = self.make_to_branch_and_tree('2')
595
tree1 = self.get_tree_no_parents_abc_content(tree1)
596
tree2 = self.get_tree_no_parents_abc_content_2(tree2)
597
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
598
root_id = tree1.path2id('')
599
self.assertEqual([('a-id', ('a', 'a'), True, (True, True),
600
(root_id, root_id), ('a', 'a'),
601
('file', 'file'), (False, False))],
602
self.do_iter_changes(tree1, tree2))
604
def test_meta_modification(self):
605
tree1 = self.make_branch_and_tree('1')
606
tree2 = self.make_to_branch_and_tree('2')
607
tree1 = self.get_tree_no_parents_abc_content(tree1)
608
tree2 = self.get_tree_no_parents_abc_content_3(tree2)
609
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
610
self.assertEqual([('c-id', ('b/c', 'b/c'), False, (True, True),
611
('b-id', 'b-id'), ('c', 'c'), ('file', 'file'),
613
self.do_iter_changes(tree1, tree2))
615
def test_empty_dir(self):
616
"""an empty dir should not cause glitches to surrounding files."""
617
tree1 = self.make_branch_and_tree('1')
618
tree2 = self.make_to_branch_and_tree('2')
619
tree1 = self.get_tree_no_parents_abc_content(tree1)
620
tree2 = self.get_tree_no_parents_abc_content(tree2)
621
# the pathname is chosen to fall between 'a' and 'b'.
622
self.build_tree(['1/a-empty/', '2/a-empty/'])
623
tree1.add(['a-empty'], ['a-empty'])
624
tree2.add(['a-empty'], ['a-empty'])
625
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
627
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
629
def test_file_rename(self):
630
tree1 = self.make_branch_and_tree('1')
631
tree2 = self.make_to_branch_and_tree('2')
632
tree1 = self.get_tree_no_parents_abc_content(tree1)
633
tree2 = self.get_tree_no_parents_abc_content_4(tree2)
634
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
635
root_id = tree1.path2id('')
636
self.assertEqual([('a-id', ('a', 'd'), False, (True, True),
637
(root_id, root_id), ('a', 'd'), ('file', 'file'),
639
self.do_iter_changes(tree1, tree2))
641
def test_file_rename_and_modification(self):
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_5(tree2)
646
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
647
root_id = tree1.path2id('')
648
self.assertEqual([('a-id', ('a', 'd'), True, (True, True),
649
(root_id, root_id), ('a', 'd'), ('file', 'file'),
651
self.do_iter_changes(tree1, tree2))
653
def test_file_rename_and_meta_modification(self):
654
tree1 = self.make_branch_and_tree('1')
655
tree2 = self.make_to_branch_and_tree('2')
656
tree1 = self.get_tree_no_parents_abc_content(tree1)
657
tree2 = self.get_tree_no_parents_abc_content_6(tree2)
658
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
659
root_id = tree1.path2id('')
660
self.assertEqual([('c-id', ('b/c', 'e'), False, (True, True),
661
('b-id', root_id), ('c', 'e'), ('file', 'file'),
663
self.do_iter_changes(tree1, tree2))
665
def test_missing_in_target(self):
666
"""Test with the target files versioned but absent from disk."""
667
tree1 = self.make_branch_and_tree('1')
668
tree2 = self.make_to_branch_and_tree('2')
669
tree1 = self.get_tree_no_parents_abc_content(tree1)
670
tree2 = self.get_tree_no_parents_abc_content(tree2)
673
# TODO ? have a symlink here?
674
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
675
root_id = tree1.path2id('')
677
self.missing('a-id', 'a', 'a', root_id, 'file'),
678
self.missing('b-id', 'b', 'b', root_id, 'directory'),
679
self.missing('c-id', 'b/c', 'b/c', 'b-id', 'file'),
681
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
683
def test_missing_and_renamed(self):
684
tree1 = self.make_branch_and_tree('tree1')
685
tree2 = self.make_to_branch_and_tree('tree2')
686
tree2.set_root_id(tree1.get_root_id())
687
self.build_tree(['tree1/file'])
688
tree1.add(['file'], ['file-id'])
689
self.build_tree(['tree2/directory/'])
690
tree2.add(['directory'], ['file-id'])
691
os.rmdir('tree2/directory')
692
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
694
root_id = tree1.path2id('')
696
self.missing('file-id', 'file', 'directory', root_id, 'file'),
698
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
700
def test_only_in_source_and_missing(self):
701
tree1 = self.make_branch_and_tree('tree1')
702
tree2 = self.make_to_branch_and_tree('tree2')
703
tree2.set_root_id(tree1.get_root_id())
704
self.build_tree(['tree1/file'])
705
tree1.add(['file'], ['file-id'])
706
os.unlink('tree1/file')
707
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
708
root_id = tree1.path2id('')
709
if not tree1.path2id('file'):
710
# The locked test trees conversion could not preserve the missing
711
# file status. This is normal (e.g. InterDirstateTree falls back
712
# to InterTree if the basis is not a DirstateRevisionTree, and
713
# revision trees cannot have missing files.
714
raise TestNotApplicable()
715
expected = [('file-id', ('file', None), False, (True, False),
716
(root_id, None), ('file', None), (None, None), (False, None))]
717
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
719
def test_only_in_target_and_missing(self):
720
tree1 = self.make_branch_and_tree('tree1')
721
tree2 = self.make_to_branch_and_tree('tree2')
722
tree2.set_root_id(tree1.get_root_id())
723
self.build_tree(['tree2/file'])
724
tree2.add(['file'], ['file-id'])
725
os.unlink('tree2/file')
726
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
727
root_id = tree1.path2id('')
728
expected = [('file-id', (None, 'file'), False, (False, True),
729
(None, root_id), (None, 'file'), (None, None), (None, False))]
730
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
732
def test_unchanged_with_renames_and_modifications(self):
733
"""want_unchanged should generate a list of unchanged entries."""
734
tree1 = self.make_branch_and_tree('1')
735
tree2 = self.make_to_branch_and_tree('2')
736
tree1 = self.get_tree_no_parents_abc_content(tree1)
737
tree2 = self.get_tree_no_parents_abc_content_5(tree2)
738
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
739
root_id = tree1.path2id('')
741
self.assertEqual(sorted([self.unchanged(tree1, root_id),
742
self.unchanged(tree1, 'b-id'),
743
('a-id', ('a', 'd'), True, (True, True),
744
(root_id, root_id), ('a', 'd'), ('file', 'file'),
745
(False, False)), self.unchanged(tree1, 'c-id')]),
746
self.do_iter_changes(tree1, tree2, include_unchanged=True))
748
def test_compare_subtrees(self):
749
tree1 = self.make_branch_and_tree('1')
750
if not tree1.supports_tree_reference():
752
tree1.set_root_id('root-id')
753
subtree1 = self.make_branch_and_tree('1/sub')
754
subtree1.set_root_id('subtree-id')
755
tree1.add_reference(subtree1)
757
tree2 = self.make_to_branch_and_tree('2')
758
if not tree2.supports_tree_reference():
760
tree2.set_root_id('root-id')
761
subtree2 = self.make_to_branch_and_tree('2/sub')
762
subtree2.set_root_id('subtree-id')
763
tree2.add_reference(subtree2)
764
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
766
self.assertEqual([], list(tree2.iter_changes(tree1)))
767
subtree1.commit('commit', rev_id='commit-a')
775
('directory', 'directory'),
781
('root-id', 'root-id'),
783
('tree-reference', 'tree-reference'),
785
list(tree2.iter_changes(tree1,
786
include_unchanged=True)))
788
def test_disk_in_subtrees_skipped(self):
789
"""subtrees are considered not-in-the-current-tree.
791
This test tests the trivial case, where the basis has no paths in the
792
current trees subtree.
794
tree1 = self.make_branch_and_tree('1')
795
tree1.set_root_id('root-id')
796
tree2 = self.make_to_branch_and_tree('2')
797
if not tree2.supports_tree_reference():
799
tree2.set_root_id('root-id')
800
subtree2 = self.make_to_branch_and_tree('2/sub')
801
subtree2.set_root_id('subtree-id')
802
tree2.add(['sub'], ['subtree-id'])
803
self.build_tree(['2/sub/file'])
804
subtree2.add(['file'])
806
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
807
# this should filter correctly from above
808
self.assertEqual([self.added(tree2, 'subtree-id')],
809
self.do_iter_changes(tree1, tree2, want_unversioned=True))
810
# and when the path is named
811
self.assertEqual([self.added(tree2, 'subtree-id')],
812
self.do_iter_changes(tree1, tree2, specific_files=['sub'],
813
want_unversioned=True))
815
def test_default_ignores_unversioned_files(self):
816
tree1 = self.make_branch_and_tree('tree1')
817
tree2 = self.make_to_branch_and_tree('tree2')
818
tree2.set_root_id(tree1.get_root_id())
819
self.build_tree(['tree1/a', 'tree1/c',
820
'tree2/a', 'tree2/b', 'tree2/c'])
821
tree1.add(['a', 'c'], ['a-id', 'c-id'])
822
tree2.add(['a', 'c'], ['a-id', 'c-id'])
824
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
826
# We should ignore the fact that 'b' exists in tree-2
827
# because the want_unversioned parameter was not given.
829
self.content_changed(tree2, 'a-id'),
830
self.content_changed(tree2, 'c-id'),
832
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
834
def test_unversioned_paths_in_tree(self):
835
tree1 = self.make_branch_and_tree('tree1')
836
tree2 = self.make_to_branch_and_tree('tree2')
837
tree2.set_root_id(tree1.get_root_id())
838
self.build_tree(['tree2/file', 'tree2/dir/'])
840
os.symlink('target', 'tree2/link')
841
links_supported = True
843
links_supported = False
844
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
846
self.unversioned(tree2, 'file'),
847
self.unversioned(tree2, 'dir'),
850
expected.append(self.unversioned(tree2, 'link'))
851
expected = sorted(expected)
852
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
853
want_unversioned=True))
855
def test_unversioned_paths_in_tree_specific_files(self):
856
tree1 = self.make_branch_and_tree('tree1')
857
tree2 = self.make_to_branch_and_tree('tree2')
858
self.build_tree(['tree2/file', 'tree2/dir/'])
860
os.symlink('target', 'tree2/link')
861
links_supported = True
863
links_supported = False
864
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
866
self.unversioned(tree2, 'file'),
867
self.unversioned(tree2, 'dir'),
869
specific_files=['file', 'dir']
871
expected.append(self.unversioned(tree2, 'link'))
872
specific_files.append('link')
873
expected = sorted(expected)
874
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
875
specific_files=specific_files, require_versioned=False,
876
want_unversioned=True))
878
def test_unversioned_paths_in_target_matching_source_old_names(self):
879
# its likely that naive implementations of unversioned file support
880
# will fail if the path was versioned, but is not any more,
881
# due to a rename, not due to unversioning it.
882
# That is, if the old tree has a versioned file 'foo', and
883
# the new tree has the same file but versioned as 'bar', and also
884
# has an unknown file 'foo', we should get back output for
886
tree1 = self.make_branch_and_tree('tree1')
887
tree2 = self.make_to_branch_and_tree('tree2')
888
tree2.set_root_id(tree1.get_root_id())
889
self.build_tree(['tree2/file', 'tree2/dir/',
890
'tree1/file', 'tree2/movedfile',
891
'tree1/dir/', 'tree2/moveddir/'])
893
os.symlink('target', 'tree1/link')
894
os.symlink('target', 'tree2/link')
895
os.symlink('target', 'tree2/movedlink')
896
links_supported = True
898
links_supported = False
899
tree1.add(['file', 'dir'], ['file-id', 'dir-id'])
900
tree2.add(['movedfile', 'moveddir'], ['file-id', 'dir-id'])
902
tree1.add(['link'], ['link-id'])
903
tree2.add(['movedlink'], ['link-id'])
904
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
905
root_id = tree1.path2id('')
907
self.renamed(tree1, tree2, 'dir-id', False),
908
self.renamed(tree1, tree2, 'file-id', True),
909
self.unversioned(tree2, 'file'),
910
self.unversioned(tree2, 'dir'),
912
specific_files=['file', 'dir']
914
expected.append(self.renamed(tree1, tree2, 'link-id', False))
915
expected.append(self.unversioned(tree2, 'link'))
916
specific_files.append('link')
917
expected = sorted(expected)
918
# run once with, and once without specific files, to catch
919
# potentially different code paths.
920
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
921
require_versioned=False,
922
want_unversioned=True))
923
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
924
specific_files=specific_files, require_versioned=False,
925
want_unversioned=True))
927
def test_similar_filenames(self):
928
"""Test when we have a few files with similar names."""
929
tree1 = self.make_branch_and_tree('tree1')
930
tree2 = self.make_branch_and_tree('tree2')
931
tree2.set_root_id(tree1.get_root_id())
933
# The trees are actually identical, but they happen to contain
934
# similarly named files.
935
self.build_tree(['tree1/a/',
948
tree1.add(['a', 'a/b', 'a/b/c', 'a/b/c/d', 'a-c', 'a-c/e'],
949
['a-id', 'b-id', 'c-id', 'd-id', 'a-c-id', 'e-id'])
950
tree2.add(['a', 'a/b', 'a/b/c', 'a/b/c/d', 'a-c', 'a-c/e'],
951
['a-id', 'b-id', 'c-id', 'd-id', 'a-c-id', 'e-id'])
953
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
955
self.assertEqual([], self.do_iter_changes(tree1, tree2,
956
want_unversioned=True))
958
self.unchanged(tree2, tree2.get_root_id()),
959
self.unchanged(tree2, 'a-id'),
960
self.unchanged(tree2, 'b-id'),
961
self.unchanged(tree2, 'c-id'),
962
self.unchanged(tree2, 'd-id'),
963
self.unchanged(tree2, 'a-c-id'),
964
self.unchanged(tree2, 'e-id'),
966
self.assertEqual(expected,
967
self.do_iter_changes(tree1, tree2,
968
want_unversioned=True,
969
include_unchanged=True))
972
def test_unversioned_subtree_only_emits_root(self):
973
tree1 = self.make_branch_and_tree('tree1')
974
tree2 = self.make_to_branch_and_tree('tree2')
975
tree2.set_root_id(tree1.get_root_id())
976
self.build_tree(['tree2/dir/', 'tree2/dir/file'])
977
tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
979
self.unversioned(tree2, 'dir'),
981
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
982
want_unversioned=True))
984
def make_trees_with_symlinks(self):
985
tree1 = self.make_branch_and_tree('tree1')
986
tree2 = self.make_to_branch_and_tree('tree2')
987
tree2.set_root_id(tree1.get_root_id())
988
self.build_tree(['tree1/fromfile', 'tree1/fromdir/'])
989
self.build_tree(['tree2/tofile', 'tree2/todir/', 'tree2/unknown'])
990
os.symlink('original', 'tree1/changed')
991
os.symlink('original', 'tree1/removed')
992
os.symlink('original', 'tree1/tofile')
993
os.symlink('original', 'tree1/todir')
994
# we make the unchanged link point at unknown to catch incorrect
995
# symlink-following code in the specified_files test.
996
os.symlink('unknown', 'tree1/unchanged')
997
os.symlink('new', 'tree2/added')
998
os.symlink('new', 'tree2/changed')
999
os.symlink('new', 'tree2/fromfile')
1000
os.symlink('new', 'tree2/fromdir')
1001
os.symlink('unknown', 'tree2/unchanged')
1002
from_paths_and_ids = [
1011
to_paths_and_ids = [
1020
tree1.add(from_paths_and_ids, from_paths_and_ids)
1021
tree2.add(to_paths_and_ids, to_paths_and_ids)
1022
return self.mutable_trees_to_locked_test_trees(tree1, tree2)
1024
def test_versioned_symlinks(self):
1025
self.requireFeature(tests.SymlinkFeature)
1026
tree1, tree2 = self.make_trees_with_symlinks()
1027
root_id = tree1.path2id('')
1029
self.unchanged(tree1, tree1.path2id('')),
1030
self.added(tree2, 'added'),
1031
self.content_changed(tree2, 'changed'),
1032
self.kind_changed(tree1, tree2, 'fromdir'),
1033
self.kind_changed(tree1, tree2, 'fromfile'),
1034
self.deleted(tree1, 'removed'),
1035
self.unchanged(tree2, 'unchanged'),
1036
self.unversioned(tree2, 'unknown'),
1037
self.kind_changed(tree1, tree2, 'todir'),
1038
self.kind_changed(tree1, tree2, 'tofile'),
1040
expected = sorted(expected)
1041
self.assertEqual(expected,
1042
self.do_iter_changes(tree1, tree2, include_unchanged=True,
1043
want_unversioned=True))
1045
def test_versioned_symlinks_specific_files(self):
1046
self.requireFeature(tests.SymlinkFeature)
1047
tree1, tree2 = self.make_trees_with_symlinks()
1048
root_id = tree1.path2id('')
1050
self.added(tree2, 'added'),
1051
self.content_changed(tree2, 'changed'),
1052
self.kind_changed(tree1, tree2, 'fromdir'),
1053
self.kind_changed(tree1, tree2, 'fromfile'),
1054
self.deleted(tree1, 'removed'),
1055
self.kind_changed(tree1, tree2, 'todir'),
1056
self.kind_changed(tree1, tree2, 'tofile'),
1058
expected = sorted(expected)
1059
# we should get back just the changed links. We pass in 'unchanged' to
1060
# make sure that it is correctly not returned - and neither is the
1061
# unknown path 'unknown' which it points at.
1062
self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
1063
specific_files=['added', 'changed', 'fromdir', 'fromfile',
1064
'removed', 'unchanged', 'todir', 'tofile']))
1066
def test_tree_with_special_names(self):
1067
tree1, tree2, paths, path_ids = self.make_tree_with_special_names()
1068
expected = sorted(self.added(tree2, f_id) for f_id in path_ids)
1069
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
1071
def test_trees_with_special_names(self):
1072
tree1, tree2, paths, path_ids = self.make_trees_with_special_names()
1073
expected = sorted(self.content_changed(tree2, f_id) for f_id in path_ids
1074
if f_id.endswith('_f-id'))
1075
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
1077
def test_trees_with_deleted_dir(self):
1078
tree1 = self.make_branch_and_tree('tree1')
1079
tree2 = self.make_to_branch_and_tree('tree2')
1080
tree2.set_root_id(tree1.get_root_id())
1081
self.build_tree(['tree1/a', 'tree1/b/', 'tree1/b/c',
1082
'tree1/b/d/', 'tree1/b/d/e', 'tree1/f/', 'tree1/f/g',
1083
'tree2/a', 'tree2/f/', 'tree2/f/g'])
1084
tree1.add(['a', 'b', 'b/c', 'b/d/', 'b/d/e', 'f', 'f/g'],
1085
['a-id', 'b-id', 'c-id', 'd-id', 'e-id', 'f-id', 'g-id'])
1086
tree2.add(['a', 'f', 'f/g'], ['a-id', 'f-id', 'g-id'])
1088
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1089
# We should notice that 'b' and all its children are deleted
1091
self.content_changed(tree2, 'a-id'),
1092
self.content_changed(tree2, 'g-id'),
1093
self.deleted(tree1, 'b-id'),
1094
self.deleted(tree1, 'c-id'),
1095
self.deleted(tree1, 'd-id'),
1096
self.deleted(tree1, 'e-id'),
1098
self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
1100
def test_added_unicode(self):
1101
tree1 = self.make_branch_and_tree('tree1')
1102
tree2 = self.make_to_branch_and_tree('tree2')
1103
root_id = tree1.get_root_id()
1104
tree2.set_root_id(root_id)
1106
# u'\u03b1' == GREEK SMALL LETTER ALPHA
1107
# u'\u03c9' == GREEK SMALL LETTER OMEGA
1108
a_id = u'\u03b1-id'.encode('utf8')
1109
added_id = u'\u03c9_added_id'.encode('utf8')
1111
self.build_tree([u'tree1/\u03b1/',
1113
u'tree2/\u03b1/\u03c9-added',
1115
except UnicodeError:
1116
raise tests.TestSkipped("Could not create Unicode files.")
1117
tree1.add([u'\u03b1'], [a_id])
1118
tree2.add([u'\u03b1', u'\u03b1/\u03c9-added'], [a_id, added_id])
1120
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1122
self.assertEqual([self.added(tree2, added_id)],
1123
self.do_iter_changes(tree1, tree2))
1124
self.assertEqual([self.added(tree2, added_id)],
1125
self.do_iter_changes(tree1, tree2,
1126
specific_files=[u'\u03b1']))
1128
def test_deleted_unicode(self):
1129
tree1 = self.make_branch_and_tree('tree1')
1130
tree2 = self.make_to_branch_and_tree('tree2')
1131
root_id = tree1.get_root_id()
1132
tree2.set_root_id(root_id)
1134
# u'\u03b1' == GREEK SMALL LETTER ALPHA
1135
# u'\u03c9' == GREEK SMALL LETTER OMEGA
1136
a_id = u'\u03b1-id'.encode('utf8')
1137
deleted_id = u'\u03c9_deleted_id'.encode('utf8')
1139
self.build_tree([u'tree1/\u03b1/',
1140
u'tree1/\u03b1/\u03c9-deleted',
1143
except UnicodeError:
1144
raise tests.TestSkipped("Could not create Unicode files.")
1145
tree1.add([u'\u03b1', u'\u03b1/\u03c9-deleted'], [a_id, deleted_id])
1146
tree2.add([u'\u03b1'], [a_id])
1148
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1150
self.assertEqual([self.deleted(tree1, deleted_id)],
1151
self.do_iter_changes(tree1, tree2))
1152
self.assertEqual([self.deleted(tree1, deleted_id)],
1153
self.do_iter_changes(tree1, tree2,
1154
specific_files=[u'\u03b1']))
1156
def test_modified_unicode(self):
1157
tree1 = self.make_branch_and_tree('tree1')
1158
tree2 = self.make_to_branch_and_tree('tree2')
1159
root_id = tree1.get_root_id()
1160
tree2.set_root_id(root_id)
1162
# u'\u03b1' == GREEK SMALL LETTER ALPHA
1163
# u'\u03c9' == GREEK SMALL LETTER OMEGA
1164
a_id = u'\u03b1-id'.encode('utf8')
1165
mod_id = u'\u03c9_mod_id'.encode('utf8')
1167
self.build_tree([u'tree1/\u03b1/',
1168
u'tree1/\u03b1/\u03c9-modified',
1170
u'tree2/\u03b1/\u03c9-modified',
1172
except UnicodeError:
1173
raise tests.TestSkipped("Could not create Unicode files.")
1174
tree1.add([u'\u03b1', u'\u03b1/\u03c9-modified'], [a_id, mod_id])
1175
tree2.add([u'\u03b1', u'\u03b1/\u03c9-modified'], [a_id, mod_id])
1177
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1179
self.assertEqual([self.content_changed(tree1, mod_id)],
1180
self.do_iter_changes(tree1, tree2))
1181
self.assertEqual([self.content_changed(tree1, mod_id)],
1182
self.do_iter_changes(tree1, tree2,
1183
specific_files=[u'\u03b1']))
1185
def test_renamed_unicode(self):
1186
tree1 = self.make_branch_and_tree('tree1')
1187
tree2 = self.make_to_branch_and_tree('tree2')
1188
root_id = tree1.get_root_id()
1189
tree2.set_root_id(root_id)
1191
# u'\u03b1' == GREEK SMALL LETTER ALPHA
1192
# u'\u03c9' == GREEK SMALL LETTER OMEGA
1193
a_id = u'\u03b1-id'.encode('utf8')
1194
rename_id = u'\u03c9_rename_id'.encode('utf8')
1196
self.build_tree([u'tree1/\u03b1/',
1199
except UnicodeError:
1200
raise tests.TestSkipped("Could not create Unicode files.")
1201
self.build_tree_contents([(u'tree1/\u03c9-source', 'contents\n'),
1202
(u'tree2/\u03b1/\u03c9-target', 'contents\n'),
1204
tree1.add([u'\u03b1', u'\u03c9-source'], [a_id, rename_id])
1205
tree2.add([u'\u03b1', u'\u03b1/\u03c9-target'], [a_id, rename_id])
1207
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1209
self.assertEqual([self.renamed(tree1, tree2, rename_id, False)],
1210
self.do_iter_changes(tree1, tree2))
1211
self.assertEqual([self.renamed(tree1, tree2, rename_id, False)],
1212
self.do_iter_changes(tree1, tree2,
1213
specific_files=[u'\u03b1']))
1215
def test_unchanged_unicode(self):
1216
tree1 = self.make_branch_and_tree('tree1')
1217
tree2 = self.make_to_branch_and_tree('tree2')
1218
root_id = tree1.get_root_id()
1219
tree2.set_root_id(root_id)
1220
# u'\u03b1' == GREEK SMALL LETTER ALPHA
1221
# u'\u03c9' == GREEK SMALL LETTER OMEGA
1222
a_id = u'\u03b1-id'.encode('utf8')
1223
subfile_id = u'\u03c9-subfile-id'.encode('utf8')
1224
rootfile_id = u'\u03c9-root-id'.encode('utf8')
1226
self.build_tree([u'tree1/\u03b1/',
1229
except UnicodeError:
1230
raise tests.TestSkipped("Could not create Unicode files.")
1231
self.build_tree_contents([
1232
(u'tree1/\u03b1/\u03c9-subfile', 'sub contents\n'),
1233
(u'tree2/\u03b1/\u03c9-subfile', 'sub contents\n'),
1234
(u'tree1/\u03c9-rootfile', 'root contents\n'),
1235
(u'tree2/\u03c9-rootfile', 'root contents\n'),
1237
tree1.add([u'\u03b1', u'\u03b1/\u03c9-subfile', u'\u03c9-rootfile'],
1238
[a_id, subfile_id, rootfile_id])
1239
tree2.add([u'\u03b1', u'\u03b1/\u03c9-subfile', u'\u03c9-rootfile'],
1240
[a_id, subfile_id, rootfile_id])
1242
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1245
self.unchanged(tree1, root_id),
1246
self.unchanged(tree1, a_id),
1247
self.unchanged(tree1, subfile_id),
1248
self.unchanged(tree1, rootfile_id),
1250
self.assertEqual(expected,
1251
self.do_iter_changes(tree1, tree2,
1252
include_unchanged=True))
1254
# We should also be able to select just a subset
1256
self.unchanged(tree1, a_id),
1257
self.unchanged(tree1, subfile_id),
1259
self.assertEqual(expected,
1260
self.do_iter_changes(tree1, tree2,
1261
specific_files=[u'\u03b1'],
1262
include_unchanged=True))
1264
def test_unknown_unicode(self):
1265
tree1 = self.make_branch_and_tree('tree1')
1266
tree2 = self.make_to_branch_and_tree('tree2')
1267
root_id = tree1.get_root_id()
1268
tree2.set_root_id(root_id)
1269
# u'\u03b1' == GREEK SMALL LETTER ALPHA
1270
# u'\u03c9' == GREEK SMALL LETTER OMEGA
1271
a_id = u'\u03b1-id'.encode('utf8')
1273
self.build_tree([u'tree1/\u03b1/',
1275
u'tree2/\u03b1/unknown_dir/',
1276
u'tree2/\u03b1/unknown_file',
1277
u'tree2/\u03b1/unknown_dir/file',
1278
u'tree2/\u03c9-unknown_root_file',
1280
except UnicodeError:
1281
raise tests.TestSkipped("Could not create Unicode files.")
1282
tree1.add([u'\u03b1'], [a_id])
1283
tree2.add([u'\u03b1'], [a_id])
1285
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1288
self.unversioned(tree2, u'\u03b1/unknown_dir'),
1289
self.unversioned(tree2, u'\u03b1/unknown_file'),
1290
self.unversioned(tree2, u'\u03c9-unknown_root_file'),
1291
# a/unknown_dir/file should not be included because we should not
1292
# recurse into unknown_dir
1293
# self.unversioned(tree2, 'a/unknown_dir/file'),
1295
self.assertEqual(expected,
1296
self.do_iter_changes(tree1, tree2,
1297
require_versioned=False,
1298
want_unversioned=True))
1299
self.assertEqual([], # Without want_unversioned we should get nothing
1300
self.do_iter_changes(tree1, tree2))
1302
# We should also be able to select just a subset
1304
self.unversioned(tree2, u'\u03b1/unknown_dir'),
1305
self.unversioned(tree2, u'\u03b1/unknown_file'),
1307
self.assertEqual(expected,
1308
self.do_iter_changes(tree1, tree2,
1309
specific_files=[u'\u03b1'],
1310
require_versioned=False,
1311
want_unversioned=True))
1312
self.assertEqual([], # Without want_unversioned we should get nothing
1313
self.do_iter_changes(tree1, tree2,
1314
specific_files=[u'\u03b1']))
1316
def test_unknown_empty_dir(self):
1317
tree1 = self.make_branch_and_tree('tree1')
1318
tree2 = self.make_to_branch_and_tree('tree2')
1319
root_id = tree1.get_root_id()
1320
tree2.set_root_id(root_id)
1322
# Start with 2 identical trees
1323
self.build_tree(['tree1/a/', 'tree1/b/',
1324
'tree2/a/', 'tree2/b/'])
1325
self.build_tree_contents([('tree1/b/file', 'contents\n'),
1326
('tree2/b/file', 'contents\n')])
1327
tree1.add(['a', 'b', 'b/file'], ['a-id', 'b-id', 'b-file-id'])
1328
tree2.add(['a', 'b', 'b/file'], ['a-id', 'b-id', 'b-file-id'])
1330
# Now create some unknowns in tree2
1331
# We should find both a/file and a/dir as unknown, but we shouldn't
1332
# recurse into a/dir to find that a/dir/subfile is also unknown.
1333
self.build_tree(['tree2/a/file', 'tree2/a/dir/', 'tree2/a/dir/subfile'])
1335
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1338
self.unversioned(tree2, u'a/file'),
1339
self.unversioned(tree2, u'a/dir'),
1341
self.assertEqual(expected,
1342
self.do_iter_changes(tree1, tree2,
1343
require_versioned=False,
1344
want_unversioned=True))
1346
def test_rename_over_deleted(self):
1347
tree1 = self.make_branch_and_tree('tree1')
1348
tree2 = self.make_to_branch_and_tree('tree2')
1349
root_id = tree1.get_root_id()
1350
tree2.set_root_id(root_id)
1352
# The final changes should be:
1359
self.build_tree_contents([
1360
('tree1/a', 'a contents\n'),
1361
('tree1/b', 'b contents\n'),
1362
('tree1/c', 'c contents\n'),
1363
('tree1/d', 'd contents\n'),
1364
('tree2/a', 'b contents\n'),
1365
('tree2/d', 'c contents\n'),
1367
tree1.add(['a', 'b', 'c', 'd'], ['a-id', 'b-id', 'c-id', 'd-id'])
1368
tree2.add(['a', 'd'], ['b-id', 'c-id'])
1370
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1373
self.deleted(tree1, 'a-id'),
1374
self.deleted(tree1, 'd-id'),
1375
self.renamed(tree1, tree2, 'b-id', False),
1376
self.renamed(tree1, tree2, 'c-id', False),
1378
self.assertEqual(expected,
1379
self.do_iter_changes(tree1, tree2))
1381
def test_deleted_and_unknown(self):
1382
"""Test a file marked removed, but still present on disk."""
1383
tree1 = self.make_branch_and_tree('tree1')
1384
tree2 = self.make_to_branch_and_tree('tree2')
1385
root_id = tree1.get_root_id()
1386
tree2.set_root_id(root_id)
1388
# The final changes should be:
1391
self.build_tree_contents([
1392
('tree1/a', 'a contents\n'),
1393
('tree1/b', 'b contents\n'),
1394
('tree1/c', 'c contents\n'),
1395
('tree2/a', 'a contents\n'),
1396
('tree2/b', 'b contents\n'),
1397
('tree2/c', 'c contents\n'),
1399
tree1.add(['a', 'b', 'c'], ['a-id', 'b-id', 'c-id'])
1400
tree2.add(['a', 'c'], ['a-id', 'c-id'])
1402
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1405
self.deleted(tree1, 'b-id'),
1406
self.unversioned(tree2, 'b'),
1408
self.assertEqual(expected,
1409
self.do_iter_changes(tree1, tree2,
1410
want_unversioned=True))
1412
self.deleted(tree1, 'b-id'),
1414
self.assertEqual(expected,
1415
self.do_iter_changes(tree1, tree2,
1416
want_unversioned=False))
1418
def test_renamed_and_added(self):
1419
"""Test when we have renamed a file, and put another in its place."""
1420
tree1 = self.make_branch_and_tree('tree1')
1421
tree2 = self.make_to_branch_and_tree('tree2')
1422
root_id = tree1.get_root_id()
1423
tree2.set_root_id(root_id)
1425
# The final changes are:
1431
self.build_tree_contents([
1432
('tree1/b', 'b contents\n'),
1433
('tree1/c', 'c contents\n'),
1434
('tree2/a', 'b contents\n'),
1435
('tree2/b', 'new b contents\n'),
1436
('tree2/c', 'new c contents\n'),
1437
('tree2/d', 'c contents\n'),
1439
tree1.add(['b', 'c'], ['b1-id', 'c1-id'])
1440
tree2.add(['a', 'b', 'c', 'd'], ['b1-id', 'b2-id', 'c2-id', 'c1-id'])
1442
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1445
self.renamed(tree1, tree2, 'b1-id', False),
1446
self.renamed(tree1, tree2, 'c1-id', False),
1447
self.added(tree2, 'b2-id'),
1448
self.added(tree2, 'c2-id'),
1450
self.assertEqual(expected,
1451
self.do_iter_changes(tree1, tree2,
1452
want_unversioned=True))
1454
def test_renamed_and_unknown(self):
1455
"""A file was moved on the filesystem, but not in bzr."""
1456
tree1 = self.make_branch_and_tree('tree1')
1457
tree2 = self.make_to_branch_and_tree('tree2')
1458
root_id = tree1.get_root_id()
1459
tree2.set_root_id(root_id)
1461
# The final changes are:
1465
self.build_tree_contents([
1466
('tree1/a', 'a contents\n'),
1467
('tree1/b', 'b contents\n'),
1468
('tree2/a', 'a contents\n'),
1469
('tree2/b', 'b contents\n'),
1471
tree1.add(['a', 'b'], ['a-id', 'b-id'])
1472
tree2.add(['a', 'b'], ['a-id', 'b-id'])
1473
os.rename('tree2/a', 'tree2/a2')
1475
tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1478
self.missing('a-id', 'a', 'a', tree2.get_root_id(), 'file'),
1479
self.unversioned(tree2, 'a2'),
1481
self.assertEqual(expected,
1482
self.do_iter_changes(tree1, tree2,
1483
want_unversioned=True))