/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tests/per_tree/test_transform.py

  • Committer: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2020-07-20 02:17:05 UTC
  • mfrom: (7518.1.2 merge-3.1)
  • Revision ID: breezy.the.bot@gmail.com-20200720021705-5f11tmo1hdqjxm6x
Merge lp:brz/3.1.

Merged from https://code.launchpad.net/~jelmer/brz/merge-3.1/+merge/387628

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006-2012, 2016 Canonical Ltd
 
2
#
 
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.
 
7
#
 
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.
 
12
#
 
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
from io import BytesIO
 
18
import os
 
19
 
 
20
from ... import (
 
21
    revision as _mod_revision,
 
22
    tests,
 
23
    trace,
 
24
    )
 
25
from ...diff import show_diff_trees
 
26
from ...merge import Merger, Merge3Merger
 
27
from ...transform import (
 
28
    ROOT_PARENT,
 
29
    resolve_conflicts,
 
30
    )
 
31
from ...tree import (
 
32
    find_previous_path,
 
33
    )
 
34
 
 
35
 
 
36
from breezy.tests.per_tree import TestCaseWithTree
 
37
 
 
38
 
 
39
from ..features import (
 
40
    HardlinkFeature,
 
41
    SymlinkFeature,
 
42
    UnicodeFilenameFeature,
 
43
    )
 
44
 
 
45
 
 
46
 
 
47
class TestTransformPreview(TestCaseWithTree):
 
48
 
 
49
    def setUp(self):
 
50
        super(TestTransformPreview, self).setUp()
 
51
        if not self.workingtree_format.supports_setting_file_ids:
 
52
            self.skipTest('test not compatible with non-file-id trees yet')
 
53
 
 
54
    def create_tree(self):
 
55
        tree = self.make_branch_and_tree('.')
 
56
        self.build_tree_contents([('a', b'content 1')])
 
57
        tree.add('a')
 
58
        revid1 = tree.commit('rev1')
 
59
        return tree.branch.repository.revision_tree(revid1)
 
60
 
 
61
    def get_empty_preview(self):
 
62
        repository = self.make_repository('repo')
 
63
        tree = repository.revision_tree(_mod_revision.NULL_REVISION)
 
64
        preview = tree.preview_transform()
 
65
        self.addCleanup(preview.finalize)
 
66
        return preview
 
67
 
 
68
    def test_transform_preview(self):
 
69
        revision_tree = self.create_tree()
 
70
        preview = revision_tree.preview_transform()
 
71
        self.addCleanup(preview.finalize)
 
72
 
 
73
    def test_transform_preview_tree(self):
 
74
        revision_tree = self.create_tree()
 
75
        preview = revision_tree.preview_transform()
 
76
        self.addCleanup(preview.finalize)
 
77
        preview.get_preview_tree()
 
78
 
 
79
    def test_transform_new_file(self):
 
80
        revision_tree = self.create_tree()
 
81
        preview = revision_tree.preview_transform()
 
82
        self.addCleanup(preview.finalize)
 
83
        preview.new_file('file2', preview.root, [b'content B\n'], b'file2-id')
 
84
        preview_tree = preview.get_preview_tree()
 
85
        self.assertEqual(preview_tree.kind('file2'), 'file')
 
86
        with preview_tree.get_file('file2') as f:
 
87
            self.assertEqual(f.read(), b'content B\n')
 
88
 
 
89
    def test_diff_preview_tree(self):
 
90
        revision_tree = self.create_tree()
 
91
        preview = revision_tree.preview_transform()
 
92
        self.addCleanup(preview.finalize)
 
93
        preview.new_file('file2', preview.root, [b'content B\n'], b'file2-id')
 
94
        preview_tree = preview.get_preview_tree()
 
95
        out = BytesIO()
 
96
        show_diff_trees(revision_tree, preview_tree, out)
 
97
        lines = out.getvalue().splitlines()
 
98
        self.assertEqual(lines[0], b"=== added file 'file2'")
 
99
        # 3 lines of diff administrivia
 
100
        self.assertEqual(lines[4], b"+content B")
 
101
 
 
102
    def test_unsupported_symlink_diff(self):
 
103
        self.requireFeature(SymlinkFeature)
 
104
        tree = self.make_branch_and_tree('.')
 
105
        self.build_tree_contents([('a', 'content 1')])
 
106
        tree.add('a')
 
107
        os.symlink('a', 'foo')
 
108
        tree.add('foo')
 
109
        revid1 = tree.commit('rev1')
 
110
        revision_tree = tree.branch.repository.revision_tree(revid1)
 
111
        preview = revision_tree.preview_transform()
 
112
        self.addCleanup(preview.finalize)
 
113
        preview.delete_versioned(preview.trans_id_tree_path('foo'))
 
114
        preview_tree = preview.get_preview_tree()
 
115
        out = BytesIO()
 
116
        log = BytesIO()
 
117
        trace.push_log_file(log)
 
118
        os_symlink = getattr(os, 'symlink', None)
 
119
        os.symlink = None
 
120
        try:
 
121
            show_diff_trees(revision_tree, preview_tree, out)
 
122
            lines = out.getvalue().splitlines()
 
123
        finally:
 
124
            os.symlink = os_symlink
 
125
        self.assertContainsRe(
 
126
            log.getvalue(),
 
127
            b'Ignoring "foo" as symlinks are not supported on this filesystem')
 
128
 
 
129
    def test_transform_conflicts(self):
 
130
        revision_tree = self.create_tree()
 
131
        preview = revision_tree.preview_transform()
 
132
        self.addCleanup(preview.finalize)
 
133
        preview.new_file('a', preview.root, [b'content 2'])
 
134
        resolve_conflicts(preview)
 
135
        trans_id = preview.trans_id_tree_path('a')
 
136
        self.assertEqual('a.moved', preview.final_name(trans_id))
 
137
 
 
138
    def get_tree_and_preview_tree(self):
 
139
        revision_tree = self.create_tree()
 
140
        preview = revision_tree.preview_transform()
 
141
        self.addCleanup(preview.finalize)
 
142
        a_trans_id = preview.trans_id_tree_path('a')
 
143
        preview.delete_contents(a_trans_id)
 
144
        preview.create_file([b'b content'], a_trans_id)
 
145
        preview_tree = preview.get_preview_tree()
 
146
        return revision_tree, preview_tree
 
147
 
 
148
    def test_iter_changes(self):
 
149
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
 
150
        root = revision_tree.path2id('')
 
151
        self.assertEqual([(revision_tree.path2id('a'), ('a', 'a'), True, (True, True),
 
152
                           (root, root), ('a', 'a'), ('file', 'file'),
 
153
                           (False, False), False)],
 
154
                         list(preview_tree.iter_changes(revision_tree)))
 
155
 
 
156
    def test_include_unchanged_succeeds(self):
 
157
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
 
158
        changes = preview_tree.iter_changes(revision_tree,
 
159
                                            include_unchanged=True)
 
160
 
 
161
        root_id = revision_tree.path2id('')
 
162
        root_entry = (root_id, ('', ''), False, (True, True), (None, None),
 
163
                      ('', ''), ('directory', 'directory'), (False, False), False)
 
164
        a_entry = (revision_tree.path2id('a'), ('a', 'a'), True, (True, True),
 
165
                   (root_id, root_id), ('a', 'a'), ('file', 'file'),
 
166
                   (False, False), False)
 
167
 
 
168
 
 
169
        self.assertEqual([root_entry, a_entry], list(changes))
 
170
 
 
171
    def test_specific_files(self):
 
172
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
 
173
        changes = preview_tree.iter_changes(revision_tree,
 
174
                                            specific_files=[''])
 
175
        root_id = revision_tree.path2id('')
 
176
        a_entry = (revision_tree.path2id('a'), ('a', 'a'), True, (True, True),
 
177
                   (root_id, root_id), ('a', 'a'), ('file', 'file'),
 
178
                   (False, False), False)
 
179
 
 
180
 
 
181
        self.assertEqual([a_entry], list(changes))
 
182
 
 
183
    def test_want_unversioned(self):
 
184
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
 
185
        changes = preview_tree.iter_changes(revision_tree,
 
186
                                            want_unversioned=True)
 
187
        root_id = revision_tree.path2id('')
 
188
        a_entry = (revision_tree.path2id('a'), ('a', 'a'), True, (True, True),
 
189
                   (root_id, root_id), ('a', 'a'), ('file', 'file'),
 
190
                   (False, False), False)
 
191
 
 
192
        self.assertEqual([a_entry], list(changes))
 
193
 
 
194
    def test_ignore_extra_trees_no_specific_files(self):
 
195
        # extra_trees is harmless without specific_files, so we'll silently
 
196
        # accept it, even though we won't use it.
 
197
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
 
198
        preview_tree.iter_changes(revision_tree, extra_trees=[preview_tree])
 
199
 
 
200
    def test_ignore_require_versioned_no_specific_files(self):
 
201
        # require_versioned is meaningless without specific_files.
 
202
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
 
203
        preview_tree.iter_changes(revision_tree, require_versioned=False)
 
204
 
 
205
    def test_ignore_pb(self):
 
206
        # pb could be supported, but TT.iter_changes doesn't support it.
 
207
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
 
208
        preview_tree.iter_changes(revision_tree)
 
209
 
 
210
    def test_kind(self):
 
211
        revision_tree = self.create_tree()
 
212
        preview = revision_tree.preview_transform()
 
213
        self.addCleanup(preview.finalize)
 
214
        preview.new_file('file', preview.root, [b'contents'], b'file-id')
 
215
        preview.new_directory('directory', preview.root, b'dir-id')
 
216
        preview_tree = preview.get_preview_tree()
 
217
        self.assertEqual('file', preview_tree.kind('file'))
 
218
        self.assertEqual('directory', preview_tree.kind('directory'))
 
219
 
 
220
    def test_get_file_mtime(self):
 
221
        preview = self.get_empty_preview()
 
222
        file_trans_id = preview.new_file('file', preview.root, [b'contents'],
 
223
                                         b'file-id')
 
224
        limbo_path = preview._limbo_name(file_trans_id)
 
225
        preview_tree = preview.get_preview_tree()
 
226
        self.assertEqual(os.stat(limbo_path).st_mtime,
 
227
                         preview_tree.get_file_mtime('file'))
 
228
 
 
229
    def test_get_file_mtime_renamed(self):
 
230
        work_tree = self.make_branch_and_tree('tree')
 
231
        self.build_tree(['tree/file'])
 
232
        work_tree.add('file')
 
233
        preview = work_tree.preview_transform()
 
234
        self.addCleanup(preview.finalize)
 
235
        file_trans_id = preview.trans_id_tree_path('file')
 
236
        preview.adjust_path('renamed', preview.root, file_trans_id)
 
237
        preview_tree = preview.get_preview_tree()
 
238
        preview_mtime = preview_tree.get_file_mtime('renamed')
 
239
        work_mtime = work_tree.get_file_mtime('file')
 
240
 
 
241
    def test_get_file_size(self):
 
242
        work_tree = self.make_branch_and_tree('tree')
 
243
        self.build_tree_contents([('tree/old', b'old')])
 
244
        work_tree.add('old')
 
245
        preview = work_tree.preview_transform()
 
246
        self.addCleanup(preview.finalize)
 
247
        preview.new_file('name', preview.root, [b'contents'], b'new-id',
 
248
                         'executable')
 
249
        tree = preview.get_preview_tree()
 
250
        self.assertEqual(len('old'), tree.get_file_size('old'))
 
251
        self.assertEqual(len('contents'), tree.get_file_size('name'))
 
252
 
 
253
    def test_get_file(self):
 
254
        preview = self.get_empty_preview()
 
255
        preview.new_file('file', preview.root, [b'contents'], b'file-id')
 
256
        preview_tree = preview.get_preview_tree()
 
257
        with preview_tree.get_file('file') as tree_file:
 
258
            self.assertEqual(b'contents', tree_file.read())
 
259
 
 
260
    def test_get_symlink_target(self):
 
261
        self.requireFeature(SymlinkFeature)
 
262
        preview = self.get_empty_preview()
 
263
        preview.new_symlink('symlink', preview.root, 'target', b'symlink-id')
 
264
        preview_tree = preview.get_preview_tree()
 
265
        self.assertEqual('target',
 
266
                         preview_tree.get_symlink_target('symlink'))
 
267
 
 
268
    def test_all_file_ids(self):
 
269
        if not self.workingtree_format.supports_setting_file_ids:
 
270
            raise tests.TestNotApplicable(
 
271
                'format does not support setting file ids')
 
272
        tree = self.make_branch_and_tree('tree')
 
273
        self.build_tree(['tree/a', 'tree/b', 'tree/c'])
 
274
        tree.add(['a', 'b', 'c'], [b'a-id', b'b-id', b'c-id'])
 
275
        preview = tree.preview_transform()
 
276
        self.addCleanup(preview.finalize)
 
277
        preview.unversion_file(preview.trans_id_file_id(b'b-id'))
 
278
        c_trans_id = preview.trans_id_file_id(b'c-id')
 
279
        preview.unversion_file(c_trans_id)
 
280
        preview.version_file(c_trans_id, file_id=b'c-id')
 
281
        preview_tree = preview.get_preview_tree()
 
282
        self.assertEqual({b'a-id', b'c-id', tree.path2id('')},
 
283
                         preview_tree.all_file_ids())
 
284
 
 
285
    def test_path2id_deleted_unchanged(self):
 
286
        tree = self.make_branch_and_tree('tree')
 
287
        self.build_tree(['tree/unchanged', 'tree/deleted'])
 
288
        tree.add(['unchanged', 'deleted'])
 
289
        preview = tree.preview_transform()
 
290
        self.addCleanup(preview.finalize)
 
291
        preview.unversion_file(preview.trans_id_tree_path('deleted'))
 
292
        preview_tree = preview.get_preview_tree()
 
293
        self.assertEqual(
 
294
            'unchanged',
 
295
            find_previous_path(preview_tree, tree, 'unchanged'))
 
296
        self.assertFalse(preview_tree.is_versioned('deleted'))
 
297
 
 
298
    def test_path2id_created(self):
 
299
        tree = self.make_branch_and_tree('tree')
 
300
        self.build_tree(['tree/unchanged'])
 
301
        tree.add(['unchanged'])
 
302
        preview = tree.preview_transform()
 
303
        self.addCleanup(preview.finalize)
 
304
        preview.new_file('new', preview.trans_id_tree_path('unchanged'),
 
305
                         [b'contents'], b'new-id')
 
306
        preview_tree = preview.get_preview_tree()
 
307
        self.assertEqual(b'new-id', preview_tree.path2id('unchanged/new'))
 
308
 
 
309
    def test_path2id_moved(self):
 
310
        tree = self.make_branch_and_tree('tree')
 
311
        self.build_tree(['tree/old_parent/', 'tree/old_parent/child'])
 
312
        tree.add(['old_parent', 'old_parent/child'])
 
313
        preview = tree.preview_transform()
 
314
        self.addCleanup(preview.finalize)
 
315
        new_parent = preview.new_directory('new_parent', preview.root,
 
316
                                           b'new_parent-id')
 
317
        preview.adjust_path('child', new_parent,
 
318
                            preview.trans_id_tree_path('old_parent/child'))
 
319
        preview_tree = preview.get_preview_tree()
 
320
        self.assertFalse(preview_tree.is_versioned('old_parent/child'))
 
321
        self.assertEqual(
 
322
            'new_parent/child',
 
323
            find_previous_path(tree, preview_tree, 'old_parent/child'))
 
324
        if self.workingtree_format.supports_setting_file_ids:
 
325
            self.assertEqual(
 
326
                tree.path2id('old_parent/child'),
 
327
                preview_tree.path2id('new_parent/child'))
 
328
 
 
329
    def test_path2id_renamed_parent(self):
 
330
        tree = self.make_branch_and_tree('tree')
 
331
        self.build_tree(['tree/old_name/', 'tree/old_name/child'])
 
332
        tree.add(['old_name', 'old_name/child'])
 
333
        preview = tree.preview_transform()
 
334
        self.addCleanup(preview.finalize)
 
335
        preview.adjust_path('new_name', preview.root,
 
336
                            preview.trans_id_tree_path('old_name'))
 
337
        preview_tree = preview.get_preview_tree()
 
338
        self.assertFalse(preview_tree.is_versioned('old_name/child'))
 
339
        self.assertEqual(
 
340
            'new_name/child',
 
341
            find_previous_path(tree, preview_tree, 'old_name/child'))
 
342
        if tree.supports_setting_file_ids:
 
343
            self.assertEqual(
 
344
                tree.path2id('old_name/child'),
 
345
                preview_tree.path2id('new_name/child'))
 
346
 
 
347
    def assertMatchingIterEntries(self, tt, specific_files=None):
 
348
        preview_tree = tt.get_preview_tree()
 
349
        preview_result = list(preview_tree.iter_entries_by_dir(
 
350
                              specific_files=specific_files))
 
351
        tree = tt._tree
 
352
        tt.apply()
 
353
        actual_result = list(tree.iter_entries_by_dir(
 
354
            specific_files=specific_files))
 
355
        self.assertEqual(actual_result, preview_result)
 
356
 
 
357
    def test_iter_entries_by_dir_new(self):
 
358
        tree = self.make_branch_and_tree('tree')
 
359
        tt = tree.transform()
 
360
        tt.new_file('new', tt.root, [b'contents'], b'new-id')
 
361
        self.assertMatchingIterEntries(tt)
 
362
 
 
363
    def test_iter_entries_by_dir_deleted(self):
 
364
        tree = self.make_branch_and_tree('tree')
 
365
        self.build_tree(['tree/deleted'])
 
366
        tree.add('deleted')
 
367
        tt = tree.transform()
 
368
        tt.delete_contents(tt.trans_id_tree_path('deleted'))
 
369
        self.assertMatchingIterEntries(tt)
 
370
 
 
371
    def test_iter_entries_by_dir_unversioned(self):
 
372
        tree = self.make_branch_and_tree('tree')
 
373
        self.build_tree(['tree/removed'])
 
374
        tree.add('removed')
 
375
        tt = tree.transform()
 
376
        tt.unversion_file(tt.trans_id_tree_path('removed'))
 
377
        self.assertMatchingIterEntries(tt)
 
378
 
 
379
    def test_iter_entries_by_dir_moved(self):
 
380
        tree = self.make_branch_and_tree('tree')
 
381
        self.build_tree(['tree/moved', 'tree/new_parent/'])
 
382
        tree.add(['moved', 'new_parent'])
 
383
        tt = tree.transform()
 
384
        tt.adjust_path(
 
385
            'moved', tt.trans_id_tree_path('new_parent'),
 
386
            tt.trans_id_tree_path('moved'))
 
387
        self.assertMatchingIterEntries(tt)
 
388
 
 
389
    def test_iter_entries_by_dir_specific_files(self):
 
390
        tree = self.make_branch_and_tree('tree')
 
391
        self.build_tree(['tree/parent/', 'tree/parent/child'])
 
392
        tree.add(['parent', 'parent/child'])
 
393
        tt = tree.transform()
 
394
        self.assertMatchingIterEntries(tt, ['', 'parent/child'])
 
395
 
 
396
    def test_symlink_content_summary(self):
 
397
        self.requireFeature(SymlinkFeature)
 
398
        preview = self.get_empty_preview()
 
399
        preview.new_symlink('path', preview.root, 'target', b'path-id')
 
400
        summary = preview.get_preview_tree().path_content_summary('path')
 
401
        self.assertEqual(('symlink', None, None, 'target'), summary)
 
402
 
 
403
    def test_missing_content_summary(self):
 
404
        preview = self.get_empty_preview()
 
405
        summary = preview.get_preview_tree().path_content_summary('path')
 
406
        self.assertEqual(('missing', None, None, None), summary)
 
407
 
 
408
    def test_deleted_content_summary(self):
 
409
        tree = self.make_branch_and_tree('tree')
 
410
        self.build_tree(['tree/path/'])
 
411
        tree.add('path')
 
412
        preview = tree.preview_transform()
 
413
        self.addCleanup(preview.finalize)
 
414
        preview.delete_contents(preview.trans_id_tree_path('path'))
 
415
        summary = preview.get_preview_tree().path_content_summary('path')
 
416
        self.assertEqual(('missing', None, None, None), summary)
 
417
 
 
418
    def test_file_content_summary_executable(self):
 
419
        preview = self.get_empty_preview()
 
420
        path_id = preview.new_file('path', preview.root, [
 
421
                                   b'contents'], b'path-id')
 
422
        preview.set_executability(True, path_id)
 
423
        summary = preview.get_preview_tree().path_content_summary('path')
 
424
        self.assertEqual(4, len(summary))
 
425
        self.assertEqual('file', summary[0])
 
426
        # size must be known
 
427
        self.assertEqual(len('contents'), summary[1])
 
428
        # executable
 
429
        self.assertEqual(True, summary[2])
 
430
        # will not have hash (not cheap to determine)
 
431
        self.assertIs(None, summary[3])
 
432
 
 
433
    def test_change_executability(self):
 
434
        tree = self.make_branch_and_tree('tree')
 
435
        self.build_tree(['tree/path'])
 
436
        tree.add('path')
 
437
        preview = tree.preview_transform()
 
438
        self.addCleanup(preview.finalize)
 
439
        path_id = preview.trans_id_tree_path('path')
 
440
        preview.set_executability(True, path_id)
 
441
        summary = preview.get_preview_tree().path_content_summary('path')
 
442
        self.assertEqual(True, summary[2])
 
443
 
 
444
    def test_file_content_summary_non_exec(self):
 
445
        preview = self.get_empty_preview()
 
446
        preview.new_file('path', preview.root, [b'contents'], b'path-id')
 
447
        summary = preview.get_preview_tree().path_content_summary('path')
 
448
        self.assertEqual(4, len(summary))
 
449
        self.assertEqual('file', summary[0])
 
450
        # size must be known
 
451
        self.assertEqual(len('contents'), summary[1])
 
452
        # not executable
 
453
        self.assertEqual(False, summary[2])
 
454
        # will not have hash (not cheap to determine)
 
455
        self.assertIs(None, summary[3])
 
456
 
 
457
    def test_dir_content_summary(self):
 
458
        preview = self.get_empty_preview()
 
459
        preview.new_directory('path', preview.root, b'path-id')
 
460
        summary = preview.get_preview_tree().path_content_summary('path')
 
461
        self.assertEqual(('directory', None, None, None), summary)
 
462
 
 
463
    def test_tree_content_summary(self):
 
464
        preview = self.get_empty_preview()
 
465
        path = preview.new_directory('path', preview.root, b'path-id')
 
466
        preview.set_tree_reference(b'rev-1', path)
 
467
        summary = preview.get_preview_tree().path_content_summary('path')
 
468
        self.assertEqual(4, len(summary))
 
469
        self.assertEqual('tree-reference', summary[0])
 
470
 
 
471
    def test_annotate(self):
 
472
        tree = self.make_branch_and_tree('tree')
 
473
        self.build_tree_contents([('tree/file', b'a\n')])
 
474
        tree.add('file')
 
475
        revid1 = tree.commit('a')
 
476
        self.build_tree_contents([('tree/file', b'a\nb\n')])
 
477
        preview = tree.preview_transform()
 
478
        self.addCleanup(preview.finalize)
 
479
        file_trans_id = preview.trans_id_tree_path('file')
 
480
        preview.delete_contents(file_trans_id)
 
481
        preview.create_file([b'a\nb\nc\n'], file_trans_id)
 
482
        preview_tree = preview.get_preview_tree()
 
483
        expected = [
 
484
            (revid1, b'a\n'),
 
485
            (b'me:', b'b\n'),
 
486
            (b'me:', b'c\n'),
 
487
        ]
 
488
        annotation = preview_tree.annotate_iter(
 
489
            'file', default_revision=b'me:')
 
490
        self.assertEqual(expected, annotation)
 
491
 
 
492
    def test_annotate_missing(self):
 
493
        preview = self.get_empty_preview()
 
494
        preview.new_file('file', preview.root, [b'a\nb\nc\n'], b'file-id')
 
495
        preview_tree = preview.get_preview_tree()
 
496
        expected = [
 
497
            (b'me:', b'a\n'),
 
498
            (b'me:', b'b\n'),
 
499
            (b'me:', b'c\n'),
 
500
            ]
 
501
        annotation = preview_tree.annotate_iter(
 
502
            'file', default_revision=b'me:')
 
503
        self.assertEqual(expected, annotation)
 
504
 
 
505
    def test_annotate_rename(self):
 
506
        tree = self.make_branch_and_tree('tree')
 
507
        self.build_tree_contents([('tree/file', b'a\n')])
 
508
        tree.add('file')
 
509
        revid1 = tree.commit('a')
 
510
        preview = tree.preview_transform()
 
511
        self.addCleanup(preview.finalize)
 
512
        file_trans_id = preview.trans_id_tree_path('file')
 
513
        preview.adjust_path('newname', preview.root, file_trans_id)
 
514
        preview_tree = preview.get_preview_tree()
 
515
        expected = [
 
516
            (revid1, b'a\n'),
 
517
        ]
 
518
        annotation = preview_tree.annotate_iter(
 
519
            'file', default_revision=b'me:')
 
520
        self.assertEqual(expected, annotation)
 
521
 
 
522
    def test_annotate_deleted(self):
 
523
        tree = self.make_branch_and_tree('tree')
 
524
        self.build_tree_contents([('tree/file', b'a\n')])
 
525
        tree.add('file')
 
526
        tree.commit('a')
 
527
        self.build_tree_contents([('tree/file', b'a\nb\n')])
 
528
        preview = tree.preview_transform()
 
529
        self.addCleanup(preview.finalize)
 
530
        file_trans_id = preview.trans_id_tree_path('file')
 
531
        preview.delete_contents(file_trans_id)
 
532
        preview_tree = preview.get_preview_tree()
 
533
        annotation = preview_tree.annotate_iter(
 
534
            'file', default_revision=b'me:')
 
535
        self.assertIs(None, annotation)
 
536
 
 
537
    def test_stored_kind(self):
 
538
        preview = self.get_empty_preview()
 
539
        preview.new_file('file', preview.root, [b'a\nb\nc\n'], b'file-id')
 
540
        preview_tree = preview.get_preview_tree()
 
541
        self.assertEqual('file', preview_tree.stored_kind('file'))
 
542
 
 
543
    def test_is_executable(self):
 
544
        preview = self.get_empty_preview()
 
545
        preview.new_file('file', preview.root, [b'a\nb\nc\n'], b'file-id')
 
546
        preview.set_executability(True, preview.trans_id_file_id(b'file-id'))
 
547
        preview_tree = preview.get_preview_tree()
 
548
        self.assertEqual(True, preview_tree.is_executable('file'))
 
549
 
 
550
    def test_get_set_parent_ids(self):
 
551
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
 
552
        self.assertEqual([], preview_tree.get_parent_ids())
 
553
        preview_tree.set_parent_ids([revision_tree.get_revision_id()])
 
554
        self.assertEqual(
 
555
            [revision_tree.get_revision_id()],
 
556
            preview_tree.get_parent_ids())
 
557
 
 
558
    def test_plan_file_merge(self):
 
559
        work_a = self.make_branch_and_tree('wta')
 
560
        self.build_tree_contents([('wta/file', b'a\nb\nc\nd\n')])
 
561
        work_a.add('file')
 
562
        base_id = work_a.commit('base version')
 
563
        tree_b = work_a.controldir.sprout('wtb').open_workingtree()
 
564
        preview = work_a.preview_transform()
 
565
        self.addCleanup(preview.finalize)
 
566
        trans_id = preview.trans_id_tree_path('file')
 
567
        preview.delete_contents(trans_id)
 
568
        preview.create_file([b'b\nc\nd\ne\n'], trans_id)
 
569
        self.build_tree_contents([('wtb/file', b'a\nc\nd\nf\n')])
 
570
        tree_a = preview.get_preview_tree()
 
571
        tree_a.set_parent_ids([base_id])
 
572
        self.addCleanup(tree_b.lock_read().unlock)
 
573
        self.assertEqual([
 
574
            ('killed-a', b'a\n'),
 
575
            ('killed-b', b'b\n'),
 
576
            ('unchanged', b'c\n'),
 
577
            ('unchanged', b'd\n'),
 
578
            ('new-a', b'e\n'),
 
579
            ('new-b', b'f\n'),
 
580
        ], list(tree_a.plan_file_merge('file', tree_b)))
 
581
 
 
582
    def test_plan_file_merge_revision_tree(self):
 
583
        work_a = self.make_branch_and_tree('wta')
 
584
        self.build_tree_contents([('wta/file', b'a\nb\nc\nd\n')])
 
585
        work_a.add('file')
 
586
        base_id = work_a.commit('base version')
 
587
        tree_b = work_a.controldir.sprout('wtb').open_workingtree()
 
588
        preview = work_a.basis_tree().preview_transform()
 
589
        self.addCleanup(preview.finalize)
 
590
        trans_id = preview.trans_id_tree_path('file')
 
591
        preview.delete_contents(trans_id)
 
592
        preview.create_file([b'b\nc\nd\ne\n'], trans_id)
 
593
        self.build_tree_contents([('wtb/file', b'a\nc\nd\nf\n')])
 
594
        tree_a = preview.get_preview_tree()
 
595
        tree_a.set_parent_ids([base_id])
 
596
        self.addCleanup(tree_b.lock_read().unlock)
 
597
        self.assertEqual([
 
598
            ('killed-a', b'a\n'),
 
599
            ('killed-b', b'b\n'),
 
600
            ('unchanged', b'c\n'),
 
601
            ('unchanged', b'd\n'),
 
602
            ('new-a', b'e\n'),
 
603
            ('new-b', b'f\n'),
 
604
        ], list(tree_a.plan_file_merge('file', tree_b)))
 
605
 
 
606
    def test_walkdirs(self):
 
607
        preview = self.get_empty_preview()
 
608
        preview.new_directory('', ROOT_PARENT, b'tree-root')
 
609
        # FIXME: new_directory should mark root.
 
610
        preview.fixup_new_roots()
 
611
        preview_tree = preview.get_preview_tree()
 
612
        preview.new_file('a', preview.root, [b'contents'], b'a-id')
 
613
        expected = [(('', b'tree-root'),
 
614
                     [('a', 'a', 'file', None, b'a-id', 'file')])]
 
615
        self.assertEqual(expected, list(preview_tree.walkdirs()))
 
616
 
 
617
    def test_extras(self):
 
618
        work_tree = self.make_branch_and_tree('tree')
 
619
        self.build_tree(['tree/removed-file', 'tree/existing-file',
 
620
                         'tree/not-removed-file'])
 
621
        work_tree.add(['removed-file', 'not-removed-file'])
 
622
        preview = work_tree.preview_transform()
 
623
        self.addCleanup(preview.finalize)
 
624
        preview.new_file('new-file', preview.root, [b'contents'])
 
625
        preview.new_file('new-versioned-file', preview.root, [b'contents'],
 
626
                         b'new-versioned-id')
 
627
        tree = preview.get_preview_tree()
 
628
        preview.unversion_file(preview.trans_id_tree_path('removed-file'))
 
629
        self.assertEqual({'new-file', 'removed-file', 'existing-file'},
 
630
                         set(tree.extras()))
 
631
 
 
632
    def test_merge_into_preview(self):
 
633
        work_tree = self.make_branch_and_tree('tree')
 
634
        self.build_tree_contents([('tree/file', b'b\n')])
 
635
        work_tree.add('file')
 
636
        work_tree.commit('first commit')
 
637
        child_tree = work_tree.controldir.sprout('child').open_workingtree()
 
638
        self.build_tree_contents([('child/file', b'b\nc\n')])
 
639
        child_tree.commit('child commit')
 
640
        child_tree.lock_write()
 
641
        self.addCleanup(child_tree.unlock)
 
642
        work_tree.lock_write()
 
643
        self.addCleanup(work_tree.unlock)
 
644
        preview = work_tree.preview_transform()
 
645
        self.addCleanup(preview.finalize)
 
646
        file_trans_id = preview.trans_id_tree_path('file')
 
647
        preview.delete_contents(file_trans_id)
 
648
        preview.create_file([b'a\nb\n'], file_trans_id)
 
649
        preview_tree = preview.get_preview_tree()
 
650
        merger = Merger.from_revision_ids(preview_tree,
 
651
                                          child_tree.branch.last_revision(),
 
652
                                          other_branch=child_tree.branch,
 
653
                                          tree_branch=work_tree.branch)
 
654
        merger.merge_type = Merge3Merger
 
655
        tt = merger.make_merger().make_preview_transform()
 
656
        self.addCleanup(tt.finalize)
 
657
        final_tree = tt.get_preview_tree()
 
658
        self.assertEqual(
 
659
            b'a\nb\nc\n',
 
660
            final_tree.get_file_text('file'))
 
661
 
 
662
    def test_merge_preview_into_workingtree(self):
 
663
        tree = self.make_branch_and_tree('tree')
 
664
        if tree.supports_setting_file_ids():
 
665
            tree.set_root_id(b'TREE_ROOT')
 
666
        tt = tree.preview_transform()
 
667
        self.addCleanup(tt.finalize)
 
668
        tt.new_file('name', tt.root, [b'content'], b'file-id')
 
669
        tree2 = self.make_branch_and_tree('tree2')
 
670
        if tree.supports_setting_file_ids():
 
671
            tree2.set_root_id(b'TREE_ROOT')
 
672
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
 
673
                                         tree.basis_tree())
 
674
        merger.merge_type = Merge3Merger
 
675
        merger.do_merge()
 
676
 
 
677
    def test_merge_preview_into_workingtree_handles_conflicts(self):
 
678
        tree = self.make_branch_and_tree('tree')
 
679
        self.build_tree_contents([('tree/foo', b'bar')])
 
680
        tree.add('foo')
 
681
        tree.commit('foo')
 
682
        tt = tree.preview_transform()
 
683
        self.addCleanup(tt.finalize)
 
684
        trans_id = tt.trans_id_tree_path('foo')
 
685
        tt.delete_contents(trans_id)
 
686
        tt.create_file([b'baz'], trans_id)
 
687
        tree2 = tree.controldir.sprout('tree2').open_workingtree()
 
688
        self.build_tree_contents([('tree2/foo', b'qux')])
 
689
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
 
690
                                         tree.basis_tree())
 
691
        merger.merge_type = Merge3Merger
 
692
        merger.do_merge()
 
693
 
 
694
    def test_has_filename(self):
 
695
        wt = self.make_branch_and_tree('tree')
 
696
        self.build_tree(['tree/unmodified', 'tree/removed', 'tree/modified'])
 
697
        tt = wt.preview_transform()
 
698
        removed_id = tt.trans_id_tree_path('removed')
 
699
        tt.delete_contents(removed_id)
 
700
        tt.new_file('new', tt.root, [b'contents'])
 
701
        modified_id = tt.trans_id_tree_path('modified')
 
702
        tt.delete_contents(modified_id)
 
703
        tt.create_file([b'modified-contents'], modified_id)
 
704
        self.addCleanup(tt.finalize)
 
705
        tree = tt.get_preview_tree()
 
706
        self.assertTrue(tree.has_filename('unmodified'))
 
707
        self.assertFalse(tree.has_filename('not-present'))
 
708
        self.assertFalse(tree.has_filename('removed'))
 
709
        self.assertTrue(tree.has_filename('new'))
 
710
        self.assertTrue(tree.has_filename('modified'))
 
711
 
 
712
    def test_is_executable2(self):
 
713
        tree = self.make_branch_and_tree('tree')
 
714
        preview = tree.preview_transform()
 
715
        self.addCleanup(preview.finalize)
 
716
        preview.new_file('foo', preview.root, [b'bar'], b'baz-id')
 
717
        preview_tree = preview.get_preview_tree()
 
718
        self.assertEqual(False, preview_tree.is_executable('tree/foo'))
 
719
 
 
720
    def test_commit_preview_tree(self):
 
721
        tree = self.make_branch_and_tree('tree')
 
722
        rev_id = tree.commit('rev1')
 
723
        tree.branch.lock_write()
 
724
        self.addCleanup(tree.branch.unlock)
 
725
        tt = tree.preview_transform()
 
726
        tt.new_file('file', tt.root, [b'contents'], b'file_id')
 
727
        self.addCleanup(tt.finalize)
 
728
        preview = tt.get_preview_tree()
 
729
        preview.set_parent_ids([rev_id])
 
730
        builder = tree.branch.get_commit_builder([rev_id])
 
731
        list(builder.record_iter_changes(preview, rev_id, tt.iter_changes()))
 
732
        builder.finish_inventory()
 
733
        rev2_id = builder.commit('rev2')
 
734
        rev2_tree = tree.branch.repository.revision_tree(rev2_id)
 
735
        self.assertEqual(b'contents', rev2_tree.get_file_text('file'))
 
736
 
 
737
    def test_ascii_limbo_paths(self):
 
738
        self.requireFeature(UnicodeFilenameFeature)
 
739
        branch = self.make_branch('any')
 
740
        tree = branch.repository.revision_tree(_mod_revision.NULL_REVISION)
 
741
        tt = tree.preview_transform()
 
742
        self.addCleanup(tt.finalize)
 
743
        foo_id = tt.new_directory('', ROOT_PARENT)
 
744
        bar_id = tt.new_file(u'\u1234bar', foo_id, [b'contents'])
 
745
        limbo_path = tt._limbo_name(bar_id)
 
746
        self.assertEqual(limbo_path, limbo_path)