/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 brzlib/tests/test_transform.py

  • Committer: Jelmer Vernooij
  • Date: 2017-05-21 12:41:27 UTC
  • mto: This revision was merged to the branch mainline in revision 6623.
  • Revision ID: jelmer@jelmer.uk-20170521124127-iv8etg0vwymyai6y
s/bzr/brz/ in apport config.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
import codecs
18
17
import errno
19
 
from io import BytesIO, StringIO
20
18
import os
 
19
from StringIO import StringIO
21
20
import sys
22
21
import time
23
22
 
24
 
from .. import (
 
23
from brzlib import (
25
24
    bencode,
26
25
    errors,
27
26
    filters,
 
27
    generate_ids,
28
28
    osutils,
29
29
    revision as _mod_revision,
30
30
    rules,
 
31
    symbol_versioning,
31
32
    tests,
32
33
    trace,
33
34
    transform,
34
35
    urlutils,
35
36
    )
36
 
from ..bzr import (
37
 
    generate_ids,
38
 
    )
39
 
from ..conflicts import (
 
37
from brzlib.conflicts import (
40
38
    DeletingParent,
41
39
    DuplicateEntry,
42
40
    DuplicateID,
45
43
    ParentLoop,
46
44
    UnversionedParent,
47
45
)
48
 
from ..controldir import ControlDir
49
 
from ..diff import show_diff_trees
50
 
from ..errors import (
 
46
from brzlib.controldir import ControlDir
 
47
from brzlib.diff import show_diff_trees
 
48
from brzlib.errors import (
51
49
    DuplicateKey,
52
50
    ExistingLimbo,
53
51
    ExistingPendingDeletion,
57
55
    MalformedTransform,
58
56
    ReusingTransform,
59
57
)
60
 
from ..osutils import (
 
58
from brzlib.osutils import (
61
59
    file_kind,
62
60
    pathjoin,
63
61
)
64
 
from ..merge import Merge3Merger, Merger
65
 
from ..mutabletree import MutableTree
66
 
from . import (
 
62
from brzlib.merge import Merge3Merger, Merger
 
63
from brzlib.mutabletree import MutableTree
 
64
from brzlib.tests import (
67
65
    features,
68
66
    TestCaseInTempDir,
69
67
    TestSkipped,
70
68
    )
71
 
from .features import (
 
69
from brzlib.tests.features import (
72
70
    HardlinkFeature,
73
71
    SymlinkFeature,
74
72
    )
75
 
from ..transform import (
 
73
from brzlib.transform import (
76
74
    build_tree,
77
75
    create_from_tree,
78
76
    cook_conflicts,
102
100
        trans, root = self.get_transform()
103
101
        self.wt.lock_tree_write()
104
102
        self.addCleanup(self.wt.unlock)
105
 
        contents = [b'just some content\n']
 
103
        contents = ['just some content\n']
106
104
        sha1 = osutils.sha_strings(contents)
107
105
        # Roll back the clock
108
106
        trans._creation_mtime = time.time() - 20.0
142
140
        self.assertEqual(imaginary_id, imaginary_id2)
143
141
        self.assertEqual(root, transform.get_tree_parent(imaginary_id))
144
142
        self.assertEqual('directory', transform.final_kind(root))
145
 
        self.assertEqual(self.wt.path2id(''), transform.final_file_id(root))
 
143
        self.assertEqual(self.wt.get_root_id(), transform.final_file_id(root))
146
144
        trans_id = transform.create_path('name', root)
147
145
        self.assertIs(transform.final_file_id(trans_id), None)
148
146
        self.assertIs(None, transform.final_kind(trans_id))
149
 
        transform.create_file([b'contents'], trans_id)
 
147
        transform.create_file('contents', trans_id)
150
148
        transform.set_executability(True, trans_id)
151
 
        transform.version_file(b'my_pretties', trans_id)
 
149
        transform.version_file('my_pretties', trans_id)
152
150
        self.assertRaises(DuplicateKey, transform.version_file,
153
 
                          b'my_pretties', trans_id)
154
 
        self.assertEqual(transform.final_file_id(trans_id), b'my_pretties')
 
151
                          'my_pretties', trans_id)
 
152
        self.assertEqual(transform.final_file_id(trans_id), 'my_pretties')
155
153
        self.assertEqual(transform.final_parent(trans_id), root)
156
154
        self.assertIs(transform.final_parent(root), ROOT_PARENT)
157
155
        self.assertIs(transform.get_tree_parent(root), ROOT_PARENT)
158
156
        oz_id = transform.create_path('oz', root)
159
157
        transform.create_directory(oz_id)
160
 
        transform.version_file(b'ozzie', oz_id)
 
158
        transform.version_file('ozzie', oz_id)
161
159
        trans_id2 = transform.create_path('name2', root)
162
 
        transform.create_file([b'contents'], trans_id2)
 
160
        transform.create_file('contents', trans_id2)
163
161
        transform.set_executability(False, trans_id2)
164
 
        transform.version_file(b'my_pretties2', trans_id2)
 
162
        transform.version_file('my_pretties2', trans_id2)
165
163
        modified_paths = transform.apply().modified_paths
166
 
        with self.wt.get_file('name') as f:
167
 
            self.assertEqual(b'contents', f.read())
168
 
        self.assertEqual(self.wt.path2id('name'), b'my_pretties')
169
 
        self.assertIs(self.wt.is_executable('name'), True)
170
 
        self.assertIs(self.wt.is_executable('name2'), False)
 
164
        self.assertEqual('contents', self.wt.get_file_byname('name').read())
 
165
        self.assertEqual(self.wt.path2id('name'), 'my_pretties')
 
166
        self.assertIs(self.wt.is_executable('my_pretties'), True)
 
167
        self.assertIs(self.wt.is_executable('my_pretties2'), False)
171
168
        self.assertEqual('directory', file_kind(self.wt.abspath('oz')))
172
169
        self.assertEqual(len(modified_paths), 3)
173
 
        tree_mod_paths = [self.wt.abspath(self.wt.id2path(f)) for f in
174
 
                          (b'ozzie', b'my_pretties', b'my_pretties2')]
 
170
        tree_mod_paths = [self.wt.id2abspath(f) for f in
 
171
                          ('ozzie', 'my_pretties', 'my_pretties2')]
175
172
        self.assertSubset(tree_mod_paths, modified_paths)
176
173
        # is it safe to finalize repeatedly?
177
174
        transform.finalize()
179
176
 
180
177
    def test_apply_informs_tree_of_observed_sha1(self):
181
178
        trans, root, contents, sha1 = self.get_transform_for_sha1_test()
182
 
        trans_id = trans.new_file('file1', root, contents, file_id=b'file1-id',
 
179
        trans_id = trans.new_file('file1', root, contents, file_id='file1-id',
183
180
                                  sha1=sha1)
184
181
        calls = []
185
182
        orig = self.wt._observed_sha1
186
 
 
187
183
        def _observed_sha1(*args):
188
184
            calls.append(args)
189
185
            orig(*args)
190
186
        self.wt._observed_sha1 = _observed_sha1
191
187
        trans.apply()
192
 
        self.assertEqual([('file1', trans._observed_sha1s[trans_id])],
 
188
        self.assertEqual([(None, 'file1', trans._observed_sha1s[trans_id])],
193
189
                         calls)
194
190
 
195
191
    def test_create_file_caches_sha1(self):
224
220
 
225
221
    def test_new_file_caches_sha1(self):
226
222
        trans, root, contents, sha1 = self.get_transform_for_sha1_test()
227
 
        trans_id = trans.new_file('file1', root, contents, file_id=b'file1-id',
 
223
        trans_id = trans.new_file('file1', root, contents, file_id='file1-id',
228
224
                                  sha1=sha1)
229
225
        st_val = osutils.lstat(trans._limbo_name(trans_id))
230
226
        o_sha1, o_st_val = trans._observed_sha1s[trans_id]
233
229
 
234
230
    def test_cancel_creation_removes_observed_sha1(self):
235
231
        trans, root, contents, sha1 = self.get_transform_for_sha1_test()
236
 
        trans_id = trans.new_file('file1', root, contents, file_id=b'file1-id',
 
232
        trans_id = trans.new_file('file1', root, contents, file_id='file1-id',
237
233
                                  sha1=sha1)
238
234
        self.assertTrue(trans_id in trans._observed_sha1s)
239
235
        trans.cancel_creation(trans_id)
246
242
        # Roll back the clock, so that we know everything is being set to the
247
243
        # exact time
248
244
        transform._creation_mtime = creation_mtime = time.time() - 20.0
249
 
        transform.create_file([b'content-one'],
 
245
        transform.create_file('content-one',
250
246
                              transform.create_path('one', root))
251
 
        time.sleep(1)  # *ugly*
252
 
        transform.create_file([b'content-two'],
 
247
        time.sleep(1) # *ugly*
 
248
        transform.create_file('content-two',
253
249
                              transform.create_path('two', root))
254
250
        transform.apply()
255
 
        fo, st1 = self.wt.get_file_with_stat('one', filtered=False)
 
251
        fo, st1 = self.wt.get_file_with_stat(None, path='one', filtered=False)
256
252
        fo.close()
257
 
        fo, st2 = self.wt.get_file_with_stat('two', filtered=False)
 
253
        fo, st2 = self.wt.get_file_with_stat(None, path='two', filtered=False)
258
254
        fo.close()
259
255
        # We only guarantee 2s resolution
260
 
        self.assertTrue(
261
 
            abs(creation_mtime - st1.st_mtime) < 2.0,
 
256
        self.assertTrue(abs(creation_mtime - st1.st_mtime) < 2.0,
262
257
            "%s != %s within 2 seconds" % (creation_mtime, st1.st_mtime))
263
258
        # But if we have more than that, all files should get the same result
264
259
        self.assertEqual(st1.st_mtime, st2.st_mtime)
265
260
 
266
261
    def test_change_root_id(self):
267
262
        transform, root = self.get_transform()
268
 
        self.assertNotEqual(b'new-root-id', self.wt.path2id(''))
269
 
        transform.new_directory('', ROOT_PARENT, b'new-root-id')
 
263
        self.assertNotEqual('new-root-id', self.wt.get_root_id())
 
264
        transform.new_directory('', ROOT_PARENT, 'new-root-id')
270
265
        transform.delete_contents(root)
271
266
        transform.unversion_file(root)
272
267
        transform.fixup_new_roots()
273
268
        transform.apply()
274
 
        self.assertEqual(b'new-root-id', self.wt.path2id(''))
 
269
        self.assertEqual('new-root-id', self.wt.get_root_id())
275
270
 
276
271
    def test_change_root_id_add_files(self):
277
272
        transform, root = self.get_transform()
278
 
        self.assertNotEqual(b'new-root-id', self.wt.path2id(''))
279
 
        new_trans_id = transform.new_directory('', ROOT_PARENT, b'new-root-id')
280
 
        transform.new_file('file', new_trans_id, [b'new-contents\n'],
281
 
                           b'new-file-id')
 
273
        self.assertNotEqual('new-root-id', self.wt.get_root_id())
 
274
        new_trans_id = transform.new_directory('', ROOT_PARENT, 'new-root-id')
 
275
        transform.new_file('file', new_trans_id, ['new-contents\n'],
 
276
                           'new-file-id')
282
277
        transform.delete_contents(root)
283
278
        transform.unversion_file(root)
284
279
        transform.fixup_new_roots()
285
280
        transform.apply()
286
 
        self.assertEqual(b'new-root-id', self.wt.path2id(''))
287
 
        self.assertEqual(b'new-file-id', self.wt.path2id('file'))
288
 
        self.assertFileEqual(b'new-contents\n', self.wt.abspath('file'))
 
281
        self.assertEqual('new-root-id', self.wt.get_root_id())
 
282
        self.assertEqual('new-file-id', self.wt.path2id('file'))
 
283
        self.assertFileEqual('new-contents\n', self.wt.abspath('file'))
289
284
 
290
285
    def test_add_two_roots(self):
291
286
        transform, root = self.get_transform()
292
 
        transform.new_directory('', ROOT_PARENT, b'new-root-id')
293
 
        transform.new_directory('', ROOT_PARENT, b'alt-root-id')
 
287
        new_trans_id = transform.new_directory('', ROOT_PARENT, 'new-root-id')
 
288
        new_trans_id = transform.new_directory('', ROOT_PARENT, 'alt-root-id')
294
289
        self.assertRaises(ValueError, transform.fixup_new_roots)
295
290
 
296
291
    def test_retain_existing_root(self):
297
292
        tt, root = self.get_transform()
298
293
        with tt:
299
 
            tt.new_directory('', ROOT_PARENT, b'new-root-id')
 
294
            tt.new_directory('', ROOT_PARENT, 'new-root-id')
300
295
            tt.fixup_new_roots()
301
 
            self.assertNotEqual(b'new-root-id', tt.final_file_id(tt.root))
 
296
            self.assertNotEqual('new-root-id', tt.final_file_id(tt.root))
302
297
 
303
298
    def test_retain_existing_root_added_file(self):
304
299
        tt, root = self.get_transform()
305
 
        new_trans_id = tt.new_directory('', ROOT_PARENT, b'new-root-id')
306
 
        child = tt.new_directory('child', new_trans_id, b'child-id')
 
300
        new_trans_id = tt.new_directory('', ROOT_PARENT, 'new-root-id')
 
301
        child = tt.new_directory('child', new_trans_id, 'child-id')
307
302
        tt.fixup_new_roots()
308
303
        self.assertEqual(tt.root, tt.final_parent(child))
309
304
 
310
305
    def test_add_unversioned_root(self):
311
306
        transform, root = self.get_transform()
312
 
        transform.new_directory('', ROOT_PARENT, None)
 
307
        new_trans_id = transform.new_directory('', ROOT_PARENT, None)
313
308
        transform.delete_contents(transform.root)
314
309
        transform.fixup_new_roots()
315
310
        self.assertNotIn(transform.root, transform._new_id)
316
311
 
317
312
    def test_remove_root_fixup(self):
318
313
        transform, root = self.get_transform()
319
 
        old_root_id = self.wt.path2id('')
320
 
        self.assertNotEqual(b'new-root-id', old_root_id)
 
314
        old_root_id = self.wt.get_root_id()
 
315
        self.assertNotEqual('new-root-id', old_root_id)
321
316
        transform.delete_contents(root)
322
317
        transform.unversion_file(root)
323
318
        transform.fixup_new_roots()
324
319
        transform.apply()
325
 
        self.assertEqual(old_root_id, self.wt.path2id(''))
 
320
        self.assertEqual(old_root_id, self.wt.get_root_id())
326
321
 
327
322
        transform, root = self.get_transform()
328
 
        transform.new_directory('', ROOT_PARENT, b'new-root-id')
329
 
        transform.new_directory('', ROOT_PARENT, b'alt-root-id')
 
323
        new_trans_id = transform.new_directory('', ROOT_PARENT, 'new-root-id')
 
324
        new_trans_id = transform.new_directory('', ROOT_PARENT, 'alt-root-id')
330
325
        self.assertRaises(ValueError, transform.fixup_new_roots)
331
326
 
332
327
    def test_fixup_new_roots_permits_empty_tree(self):
353
348
        old_root_id = transform.tree_file_id(root)
354
349
        transform.unversion_file(root)
355
350
        transform.apply()
356
 
        self.assertEqual(old_root_id, self.wt.path2id(''))
 
351
        self.assertEqual(old_root_id, self.wt.get_root_id())
357
352
 
358
353
    def test_hardlink(self):
359
354
        self.requireFeature(HardlinkFeature)
360
355
        transform, root = self.get_transform()
361
 
        transform.new_file('file1', root, [b'contents'])
 
356
        transform.new_file('file1', root, 'contents')
362
357
        transform.apply()
363
358
        target = self.make_branch_and_tree('target')
364
359
        target_transform = TreeTransform(target)
374
369
        transform, root = self.get_transform()
375
370
        self.wt.lock_tree_write()
376
371
        self.addCleanup(self.wt.unlock)
377
 
        transform.new_file('name', root, [b'contents'], b'my_pretties', True)
378
 
        oz = transform.new_directory('oz', root, b'oz-id')
379
 
        dorothy = transform.new_directory('dorothy', oz, b'dorothy-id')
380
 
        transform.new_file('toto', dorothy, [b'toto-contents'], b'toto-id',
381
 
                           False)
 
372
        trans_id = transform.new_file('name', root, 'contents',
 
373
                                      'my_pretties', True)
 
374
        oz = transform.new_directory('oz', root, 'oz-id')
 
375
        dorothy = transform.new_directory('dorothy', oz, 'dorothy-id')
 
376
        toto = transform.new_file('toto', dorothy, 'toto-contents',
 
377
                                  'toto-id', False)
382
378
 
383
379
        self.assertEqual(len(transform.find_conflicts()), 0)
384
380
        transform.apply()
385
381
        self.assertRaises(ReusingTransform, transform.find_conflicts)
386
 
        with open(self.wt.abspath('name'), 'r') as f:
387
 
            self.assertEqual('contents', f.read())
388
 
        self.assertEqual(self.wt.path2id('name'), b'my_pretties')
389
 
        self.assertIs(self.wt.is_executable('name'), True)
390
 
        self.assertEqual(self.wt.path2id('oz'), b'oz-id')
391
 
        self.assertEqual(self.wt.path2id('oz/dorothy'), b'dorothy-id')
392
 
        self.assertEqual(self.wt.path2id('oz/dorothy/toto'), b'toto-id')
 
382
        self.assertEqual('contents', file(self.wt.abspath('name')).read())
 
383
        self.assertEqual(self.wt.path2id('name'), 'my_pretties')
 
384
        self.assertIs(self.wt.is_executable('my_pretties'), True)
 
385
        self.assertEqual(self.wt.path2id('oz'), 'oz-id')
 
386
        self.assertEqual(self.wt.path2id('oz/dorothy'), 'dorothy-id')
 
387
        self.assertEqual(self.wt.path2id('oz/dorothy/toto'), 'toto-id')
393
388
 
394
 
        self.assertEqual(b'toto-contents',
395
 
                         self.wt.get_file('oz/dorothy/toto').read())
396
 
        self.assertIs(self.wt.is_executable('oz/dorothy/toto'), False)
 
389
        self.assertEqual('toto-contents',
 
390
                         self.wt.get_file_byname('oz/dorothy/toto').read())
 
391
        self.assertIs(self.wt.is_executable('toto-id'), False)
397
392
 
398
393
    def test_tree_reference(self):
399
394
        transform, root = self.get_transform()
400
395
        tree = transform._tree
401
 
        trans_id = transform.new_directory('reference', root, b'subtree-id')
402
 
        transform.set_tree_reference(b'subtree-revision', trans_id)
 
396
        trans_id = transform.new_directory('reference', root, 'subtree-id')
 
397
        transform.set_tree_reference('subtree-revision', trans_id)
403
398
        transform.apply()
404
399
        tree.lock_read()
405
400
        self.addCleanup(tree.unlock)
406
 
        self.assertEqual(
407
 
            b'subtree-revision',
408
 
            tree.root_inventory.get_entry(b'subtree-id').reference_revision)
 
401
        self.assertEqual('subtree-revision',
 
402
                         tree.root_inventory['subtree-id'].reference_revision)
409
403
 
410
404
    def test_conflicts(self):
411
405
        transform, root = self.get_transform()
412
 
        trans_id = transform.new_file('name', root, [b'contents'],
413
 
                                      b'my_pretties')
 
406
        trans_id = transform.new_file('name', root, 'contents',
 
407
                                      'my_pretties')
414
408
        self.assertEqual(len(transform.find_conflicts()), 0)
415
 
        trans_id2 = transform.new_file('name', root, [b'Crontents'], b'toto')
 
409
        trans_id2 = transform.new_file('name', root, 'Crontents', 'toto')
416
410
        self.assertEqual(transform.find_conflicts(),
417
411
                         [('duplicate', trans_id, trans_id2, 'name')])
418
412
        self.assertRaises(MalformedTransform, transform.apply)
432
426
        self.assertEqual(transform.find_conflicts(),
433
427
                         [('unversioned parent', lion_id),
434
428
                          ('missing parent', lion_id)])
435
 
        transform.version_file(b"Courage", lion_id)
 
429
        transform.version_file("Courage", lion_id)
436
430
        self.assertEqual(transform.find_conflicts(),
437
431
                         [('missing parent', lion_id),
438
432
                          ('versioning no contents', lion_id)])
439
433
        transform.adjust_path('name2', root, trans_id2)
440
434
        self.assertEqual(transform.find_conflicts(),
441
435
                         [('versioning no contents', lion_id)])
442
 
        transform.create_file([b'Contents, okay?'], lion_id)
 
436
        transform.create_file('Contents, okay?', lion_id)
443
437
        transform.adjust_path('name2', trans_id2, trans_id2)
444
438
        self.assertEqual(transform.find_conflicts(),
445
439
                         [('parent loop', trans_id2),
449
443
        transform.set_executability(True, oz_id)
450
444
        self.assertEqual(transform.find_conflicts(),
451
445
                         [('unversioned executability', oz_id)])
452
 
        transform.version_file(b'oz-id', oz_id)
 
446
        transform.version_file('oz-id', oz_id)
453
447
        self.assertEqual(transform.find_conflicts(),
454
448
                         [('non-file executability', oz_id)])
455
449
        transform.set_executability(None, oz_id)
456
 
        tip_id = transform.new_file('tip', oz_id, [b'ozma'], b'tip-id')
 
450
        tip_id = transform.new_file('tip', oz_id, 'ozma', 'tip-id')
457
451
        transform.apply()
458
 
        self.assertEqual(self.wt.path2id('name'), b'my_pretties')
459
 
        with open(self.wt.abspath('name'), 'rb') as f:
460
 
            self.assertEqual(b'contents', f.read())
 
452
        self.assertEqual(self.wt.path2id('name'), 'my_pretties')
 
453
        self.assertEqual('contents', file(self.wt.abspath('name')).read())
461
454
        transform2, root = self.get_transform()
462
 
        oz_id = transform2.trans_id_tree_path('oz')
463
 
        newtip = transform2.new_file('tip', oz_id, [b'other'], b'tip-id')
 
455
        oz_id = transform2.trans_id_tree_file_id('oz-id')
 
456
        newtip = transform2.new_file('tip', oz_id, 'other', 'tip-id')
464
457
        result = transform2.find_conflicts()
465
458
        fp = FinalPaths(transform2)
466
459
        self.assertTrue('oz/tip' in transform2._tree_path_ids)
473
466
        transform2.finalize()
474
467
        transform3 = TreeTransform(self.wt)
475
468
        self.addCleanup(transform3.finalize)
476
 
        oz_id = transform3.trans_id_tree_path('oz')
 
469
        oz_id = transform3.trans_id_tree_file_id('oz-id')
477
470
        transform3.delete_contents(oz_id)
478
471
        self.assertEqual(transform3.find_conflicts(),
479
472
                         [('missing parent', oz_id)])
480
473
        root_id = transform3.root
481
 
        tip_id = transform3.trans_id_tree_path('oz/tip')
 
474
        tip_id = transform3.trans_id_tree_file_id('tip-id')
482
475
        transform3.adjust_path('tip', root_id, tip_id)
483
476
        transform3.apply()
484
477
 
490
483
        tree.case_sensitive = True
491
484
        transform = TreeTransform(tree)
492
485
        self.addCleanup(transform.finalize)
493
 
        transform.new_file('file', transform.root, [b'content'])
494
 
        transform.new_file('FiLe', transform.root, [b'content'])
 
486
        transform.new_file('file', transform.root, 'content')
 
487
        transform.new_file('FiLe', transform.root, 'content')
495
488
        result = transform.find_conflicts()
496
489
        self.assertEqual([], result)
497
490
        transform.finalize()
500
493
        tree.case_sensitive = False
501
494
        transform = TreeTransform(tree)
502
495
        self.addCleanup(transform.finalize)
503
 
        transform.new_file('file', transform.root, [b'content'])
504
 
        transform.new_file('FiLe', transform.root, [b'content'])
 
496
        transform.new_file('file', transform.root, 'content')
 
497
        transform.new_file('FiLe', transform.root, 'content')
505
498
        result = transform.find_conflicts()
506
499
        self.assertEqual([('duplicate', 'new-1', 'new-2', 'file')], result)
507
500
 
514
507
        tree.case_sensitive = True
515
508
        transform = TreeTransform(tree)
516
509
        self.addCleanup(transform.finalize)
517
 
        transform.new_file('file', transform.root, [b'content'])
 
510
        transform.new_file('file', transform.root, 'content')
518
511
        result = transform.find_conflicts()
519
512
        self.assertEqual([], result)
520
513
        transform.finalize()
523
516
        tree.case_sensitive = False
524
517
        transform = TreeTransform(tree)
525
518
        self.addCleanup(transform.finalize)
526
 
        transform.new_file('file', transform.root, [b'content'])
 
519
        transform.new_file('file', transform.root, 'content')
527
520
        result = transform.find_conflicts()
528
521
        self.assertEqual([('duplicate', 'new-1', 'new-2', 'file')], result)
529
522
 
535
528
        tree.case_sensitive = False
536
529
        transform = TreeTransform(tree)
537
530
        self.addCleanup(transform.finalize)
538
 
        transform.new_file('file', transform.root, [b'content'])
539
 
        transform.new_file('FiLe', transform.root, [b'content'])
 
531
        transform.new_file('file', transform.root, 'content')
 
532
        transform.new_file('FiLe', transform.root, 'content')
540
533
        resolve_conflicts(transform)
541
534
        transform.apply()
542
535
        self.assertPathExists('tree/file')
550
543
        tree.case_sensitive = False
551
544
        transform = TreeTransform(tree)
552
545
        self.addCleanup(transform.finalize)
553
 
        transform.new_file('file', transform.root, [b'content'])
554
 
        transform.new_file('FiLe', transform.root, [b'content'])
 
546
        transform.new_file('file', transform.root, 'content')
 
547
        transform.new_file('FiLe', transform.root, 'content')
555
548
        resolve_conflicts(transform,
556
549
                          pass_func=lambda t, c: resolve_checkout(t, c, []))
557
550
        transform.apply()
563
556
        tree = self.make_branch_and_tree('tree')
564
557
        transform = TreeTransform(tree)
565
558
        self.addCleanup(transform.finalize)
566
 
        transform.new_file('file', transform.root, [b'content'])
567
 
        transform.new_file('FiLe', transform.root, [b'content'])
 
559
        transform.new_file('file', transform.root, 'content')
 
560
        transform.new_file('FiLe', transform.root, 'content')
568
561
        dir = transform.new_directory('dir', transform.root)
569
 
        transform.new_file('dirfile', dir, [b'content'])
570
 
        transform.new_file('dirFiLe', dir, [b'content'])
 
562
        transform.new_file('dirfile', dir, 'content')
 
563
        transform.new_file('dirFiLe', dir, 'content')
571
564
        resolve_conflicts(transform)
572
565
        transform.apply()
573
566
        self.assertPathExists('tree/file')
585
578
        transform = TreeTransform(tree)
586
579
        self.addCleanup(transform.finalize)
587
580
        dir = transform.new_directory('dir', transform.root)
588
 
        first = transform.new_file('file', dir, [b'content'])
589
 
        second = transform.new_file('FiLe', dir, [b'content'])
 
581
        first = transform.new_file('file', dir, 'content')
 
582
        second = transform.new_file('FiLe', dir, 'content')
590
583
        self.assertContainsRe(transform._limbo_name(first), 'new-1/file')
591
584
        self.assertNotContainsRe(transform._limbo_name(second), 'new-1/FiLe')
592
585
 
604
597
 
605
598
    def test_add_del(self):
606
599
        start, root = self.get_transform()
607
 
        start.new_directory('a', root, b'a')
 
600
        start.new_directory('a', root, 'a')
608
601
        start.apply()
609
602
        transform, root = self.get_transform()
610
 
        transform.delete_versioned(transform.trans_id_tree_path('a'))
611
 
        transform.new_directory('a', root, b'a')
 
603
        transform.delete_versioned(transform.trans_id_tree_file_id('a'))
 
604
        transform.new_directory('a', root, 'a')
612
605
        transform.apply()
613
606
 
614
607
    def test_unversioning(self):
615
608
        create_tree, root = self.get_transform()
616
 
        parent_id = create_tree.new_directory('parent', root, b'parent-id')
617
 
        create_tree.new_file('child', parent_id, [b'child'], b'child-id')
 
609
        parent_id = create_tree.new_directory('parent', root, 'parent-id')
 
610
        create_tree.new_file('child', parent_id, 'child', 'child-id')
618
611
        create_tree.apply()
619
612
        unversion = TreeTransform(self.wt)
620
613
        self.addCleanup(unversion.finalize)
622
615
        unversion.unversion_file(parent)
623
616
        self.assertEqual(unversion.find_conflicts(),
624
617
                         [('unversioned parent', parent_id)])
625
 
        file_id = unversion.trans_id_tree_path('parent/child')
 
618
        file_id = unversion.trans_id_tree_file_id('child-id')
626
619
        unversion.unversion_file(file_id)
627
620
        unversion.apply()
628
621
 
630
623
        create_tree, root = self.get_transform()
631
624
        # prepare tree
632
625
        root = create_tree.root
633
 
        create_tree.new_file('name1', root, [b'hello1'], b'name1')
634
 
        create_tree.new_file('name2', root, [b'hello2'], b'name2')
635
 
        ddir = create_tree.new_directory('dying_directory', root, b'ddir')
636
 
        create_tree.new_file('dying_file', ddir, [b'goodbye1'], b'dfile')
637
 
        create_tree.new_file('moving_file', ddir, [b'later1'], b'mfile')
638
 
        create_tree.new_file('moving_file2', root, [b'later2'], b'mfile2')
 
626
        create_tree.new_file('name1', root, 'hello1', 'name1')
 
627
        create_tree.new_file('name2', root, 'hello2', 'name2')
 
628
        ddir = create_tree.new_directory('dying_directory', root, 'ddir')
 
629
        create_tree.new_file('dying_file', ddir, 'goodbye1', 'dfile')
 
630
        create_tree.new_file('moving_file', ddir, 'later1', 'mfile')
 
631
        create_tree.new_file('moving_file2', root, 'later2', 'mfile2')
639
632
        create_tree.apply()
640
633
 
641
 
        mangle_tree, root = self.get_transform()
 
634
        mangle_tree,root = self.get_transform()
642
635
        root = mangle_tree.root
643
 
        # swap names
644
 
        name1 = mangle_tree.trans_id_tree_path('name1')
645
 
        name2 = mangle_tree.trans_id_tree_path('name2')
 
636
        #swap names
 
637
        name1 = mangle_tree.trans_id_tree_file_id('name1')
 
638
        name2 = mangle_tree.trans_id_tree_file_id('name2')
646
639
        mangle_tree.adjust_path('name2', root, name1)
647
640
        mangle_tree.adjust_path('name1', root, name2)
648
641
 
649
 
        # tests for deleting parent directories
650
 
        ddir = mangle_tree.trans_id_tree_path('dying_directory')
 
642
        #tests for deleting parent directories
 
643
        ddir = mangle_tree.trans_id_tree_file_id('ddir')
651
644
        mangle_tree.delete_contents(ddir)
652
 
        dfile = mangle_tree.trans_id_tree_path('dying_directory/dying_file')
 
645
        dfile = mangle_tree.trans_id_tree_file_id('dfile')
653
646
        mangle_tree.delete_versioned(dfile)
654
647
        mangle_tree.unversion_file(dfile)
655
 
        mfile = mangle_tree.trans_id_tree_path('dying_directory/moving_file')
 
648
        mfile = mangle_tree.trans_id_tree_file_id('mfile')
656
649
        mangle_tree.adjust_path('mfile', root, mfile)
657
650
 
658
 
        # tests for adding parent directories
659
 
        newdir = mangle_tree.new_directory('new_directory', root, b'newdir')
660
 
        mfile2 = mangle_tree.trans_id_tree_path('moving_file2')
 
651
        #tests for adding parent directories
 
652
        newdir = mangle_tree.new_directory('new_directory', root, 'newdir')
 
653
        mfile2 = mangle_tree.trans_id_tree_file_id('mfile2')
661
654
        mangle_tree.adjust_path('mfile2', newdir, mfile2)
662
 
        mangle_tree.new_file('newfile', newdir, [b'hello3'], b'dfile')
663
 
        self.assertEqual(mangle_tree.final_file_id(mfile2), b'mfile2')
 
655
        mangle_tree.new_file('newfile', newdir, 'hello3', 'dfile')
 
656
        self.assertEqual(mangle_tree.final_file_id(mfile2), 'mfile2')
664
657
        self.assertEqual(mangle_tree.final_parent(mfile2), newdir)
665
 
        self.assertEqual(mangle_tree.final_file_id(mfile2), b'mfile2')
 
658
        self.assertEqual(mangle_tree.final_file_id(mfile2), 'mfile2')
666
659
        mangle_tree.apply()
667
 
        with open(self.wt.abspath('name1'), 'r') as f:
668
 
            self.assertEqual(f.read(), 'hello2')
669
 
        with open(self.wt.abspath('name2'), 'r') as f:
670
 
            self.assertEqual(f.read(), 'hello1')
671
 
        mfile2_path = self.wt.abspath(pathjoin('new_directory', 'mfile2'))
 
660
        self.assertEqual(file(self.wt.abspath('name1')).read(), 'hello2')
 
661
        self.assertEqual(file(self.wt.abspath('name2')).read(), 'hello1')
 
662
        mfile2_path = self.wt.abspath(pathjoin('new_directory','mfile2'))
672
663
        self.assertEqual(mangle_tree.final_parent(mfile2), newdir)
673
 
        with open(mfile2_path, 'r') as f:
674
 
            self.assertEqual(f.read(), 'later2')
675
 
        self.assertEqual(self.wt.id2path(b'mfile2'), 'new_directory/mfile2')
676
 
        self.assertEqual(self.wt.path2id('new_directory/mfile2'), b'mfile2')
677
 
        newfile_path = self.wt.abspath(pathjoin('new_directory', 'newfile'))
678
 
        with open(newfile_path, 'r') as f:
679
 
            self.assertEqual(f.read(), 'hello3')
680
 
        self.assertEqual(self.wt.path2id('dying_directory'), b'ddir')
 
664
        self.assertEqual(file(mfile2_path).read(), 'later2')
 
665
        self.assertEqual(self.wt.id2path('mfile2'), 'new_directory/mfile2')
 
666
        self.assertEqual(self.wt.path2id('new_directory/mfile2'), 'mfile2')
 
667
        newfile_path = self.wt.abspath(pathjoin('new_directory','newfile'))
 
668
        self.assertEqual(file(newfile_path).read(), 'hello3')
 
669
        self.assertEqual(self.wt.path2id('dying_directory'), 'ddir')
681
670
        self.assertIs(self.wt.path2id('dying_directory/dying_file'), None)
682
 
        mfile2_path = self.wt.abspath(pathjoin('new_directory', 'mfile2'))
 
671
        mfile2_path = self.wt.abspath(pathjoin('new_directory','mfile2'))
683
672
 
684
673
    def test_both_rename(self):
685
 
        create_tree, root = self.get_transform()
686
 
        newdir = create_tree.new_directory('selftest', root, b'selftest-id')
687
 
        create_tree.new_file('blackbox.py', newdir, [
688
 
                             b'hello1'], b'blackbox-id')
 
674
        create_tree,root = self.get_transform()
 
675
        newdir = create_tree.new_directory('selftest', root, 'selftest-id')
 
676
        create_tree.new_file('blackbox.py', newdir, 'hello1', 'blackbox-id')
689
677
        create_tree.apply()
690
 
        mangle_tree, root = self.get_transform()
691
 
        selftest = mangle_tree.trans_id_tree_path('selftest')
692
 
        blackbox = mangle_tree.trans_id_tree_path('selftest/blackbox.py')
 
678
        mangle_tree,root = self.get_transform()
 
679
        selftest = mangle_tree.trans_id_tree_file_id('selftest-id')
 
680
        blackbox = mangle_tree.trans_id_tree_file_id('blackbox-id')
693
681
        mangle_tree.adjust_path('test', root, selftest)
694
682
        mangle_tree.adjust_path('test_too_much', root, selftest)
695
683
        mangle_tree.set_executability(True, blackbox)
696
684
        mangle_tree.apply()
697
685
 
698
686
    def test_both_rename2(self):
699
 
        create_tree, root = self.get_transform()
700
 
        breezy = create_tree.new_directory('breezy', root, b'breezy-id')
701
 
        tests = create_tree.new_directory('tests', breezy, b'tests-id')
702
 
        blackbox = create_tree.new_directory('blackbox', tests, b'blackbox-id')
703
 
        create_tree.new_file('test_too_much.py', blackbox, [b'hello1'],
704
 
                             b'test_too_much-id')
 
687
        create_tree,root = self.get_transform()
 
688
        brzlib = create_tree.new_directory('brzlib', root, 'bzrlib-id')
 
689
        tests = create_tree.new_directory('tests', brzlib, 'tests-id')
 
690
        blackbox = create_tree.new_directory('blackbox', tests, 'blackbox-id')
 
691
        create_tree.new_file('test_too_much.py', blackbox, 'hello1',
 
692
                             'test_too_much-id')
705
693
        create_tree.apply()
706
 
        mangle_tree, root = self.get_transform()
707
 
        breezy = mangle_tree.trans_id_tree_path('breezy')
708
 
        tests = mangle_tree.trans_id_tree_path('breezy/tests')
709
 
        test_too_much = mangle_tree.trans_id_tree_path(
710
 
            'breezy/tests/blackbox/test_too_much.py')
711
 
        mangle_tree.adjust_path('selftest', breezy, tests)
 
694
        mangle_tree,root = self.get_transform()
 
695
        brzlib = mangle_tree.trans_id_tree_file_id('brzlib-id')
 
696
        tests = mangle_tree.trans_id_tree_file_id('tests-id')
 
697
        test_too_much = mangle_tree.trans_id_tree_file_id('test_too_much-id')
 
698
        mangle_tree.adjust_path('selftest', brzlib, tests)
712
699
        mangle_tree.adjust_path('blackbox.py', tests, test_too_much)
713
700
        mangle_tree.set_executability(True, test_too_much)
714
701
        mangle_tree.apply()
715
702
 
716
703
    def test_both_rename3(self):
717
 
        create_tree, root = self.get_transform()
718
 
        tests = create_tree.new_directory('tests', root, b'tests-id')
719
 
        create_tree.new_file('test_too_much.py', tests, [b'hello1'],
720
 
                             b'test_too_much-id')
 
704
        create_tree,root = self.get_transform()
 
705
        tests = create_tree.new_directory('tests', root, 'tests-id')
 
706
        create_tree.new_file('test_too_much.py', tests, 'hello1',
 
707
                             'test_too_much-id')
721
708
        create_tree.apply()
722
 
        mangle_tree, root = self.get_transform()
723
 
        tests = mangle_tree.trans_id_tree_path('tests')
724
 
        test_too_much = mangle_tree.trans_id_tree_path(
725
 
            'tests/test_too_much.py')
 
709
        mangle_tree,root = self.get_transform()
 
710
        tests = mangle_tree.trans_id_tree_file_id('tests-id')
 
711
        test_too_much = mangle_tree.trans_id_tree_file_id('test_too_much-id')
726
712
        mangle_tree.adjust_path('selftest', root, tests)
727
713
        mangle_tree.adjust_path('blackbox.py', tests, test_too_much)
728
714
        mangle_tree.set_executability(True, test_too_much)
732
718
        create_tree, root = self.get_transform()
733
719
        # prepare tree
734
720
        root = create_tree.root
735
 
        create_tree.new_file('name1', root, [b'hello1'], b'name1')
 
721
        create_tree.new_file('name1', root, 'hello1', 'name1')
736
722
        create_tree.apply()
737
723
        delete_contents, root = self.get_transform()
738
 
        file = delete_contents.trans_id_tree_path('name1')
 
724
        file = delete_contents.trans_id_tree_file_id('name1')
739
725
        delete_contents.delete_contents(file)
740
726
        delete_contents.apply()
741
727
        move_id, root = self.get_transform()
742
 
        name1 = move_id.trans_id_tree_path('name1')
743
 
        newdir = move_id.new_directory('dir', root, b'newdir')
 
728
        name1 = move_id.trans_id_tree_file_id('name1')
 
729
        newdir = move_id.new_directory('dir', root, 'newdir')
744
730
        move_id.adjust_path('name2', newdir, name1)
745
731
        move_id.apply()
746
732
 
748
734
        create_tree, root = self.get_transform()
749
735
        # prepare tree
750
736
        root = create_tree.root
751
 
        create_tree.new_file('name1', root, [b'hello1'], b'name1')
 
737
        create_tree.new_file('name1', root, 'hello1', 'name1')
752
738
        create_tree.apply()
753
739
        delete_contents = TreeTransform(self.wt)
754
740
        self.addCleanup(delete_contents.finalize)
755
 
        file = delete_contents.trans_id_tree_path('name1')
 
741
        file = delete_contents.trans_id_tree_file_id('name1')
756
742
        delete_contents.delete_contents(file)
757
743
        delete_contents.apply()
758
744
        delete_contents.finalize()
759
745
        replace = TreeTransform(self.wt)
760
746
        self.addCleanup(replace.finalize)
761
 
        name2 = replace.new_file('name2', root, [b'hello2'], b'name1')
 
747
        name2 = replace.new_file('name2', root, 'hello2', 'name1')
762
748
        conflicts = replace.find_conflicts()
763
 
        name1 = replace.trans_id_tree_path('name1')
 
749
        name1 = replace.trans_id_tree_file_id('name1')
764
750
        self.assertEqual(conflicts, [('duplicate id', name1, name2)])
765
751
        resolve_conflicts(replace)
766
752
        replace.apply()
767
753
 
768
 
    def _test_symlinks(self, link_name1, link_target1,
 
754
    def _test_symlinks(self, link_name1,link_target1,
769
755
                       link_name2, link_target2):
770
756
 
771
 
        def ozpath(p):
772
 
            return 'oz/' + p
 
757
        def ozpath(p): return 'oz/' + p
773
758
 
774
759
        self.requireFeature(SymlinkFeature)
775
760
        transform, root = self.get_transform()
776
 
        oz_id = transform.new_directory('oz', root, b'oz-id')
777
 
        transform.new_symlink(link_name1, oz_id, link_target1, b'wizard-id')
 
761
        oz_id = transform.new_directory('oz', root, 'oz-id')
 
762
        wizard = transform.new_symlink(link_name1, oz_id, link_target1,
 
763
                                       'wizard-id')
778
764
        wiz_id = transform.create_path(link_name2, oz_id)
779
765
        transform.create_symlink(link_target2, wiz_id)
780
 
        transform.version_file(b'wiz-id2', wiz_id)
 
766
        transform.version_file('wiz-id2', wiz_id)
781
767
        transform.set_executability(True, wiz_id)
782
768
        self.assertEqual(transform.find_conflicts(),
783
769
                         [('non-file executability', wiz_id)])
784
770
        transform.set_executability(None, wiz_id)
785
771
        transform.apply()
786
 
        self.assertEqual(self.wt.path2id(ozpath(link_name1)), b'wizard-id')
 
772
        self.assertEqual(self.wt.path2id(ozpath(link_name1)), 'wizard-id')
787
773
        self.assertEqual('symlink',
788
774
                         file_kind(self.wt.abspath(ozpath(link_name1))))
789
775
        self.assertEqual(link_target2,
802
788
                            u'\N{Euro Sign}wizard2',
803
789
                            u'b\N{Euro Sign}hind_curtain')
804
790
 
805
 
    def test_unsupported_symlink_no_conflict(self):
 
791
    def test_unable_create_symlink(self):
806
792
        def tt_helper():
807
793
            wt = self.make_branch_and_tree('.')
808
 
            tt = TreeTransform(wt)
809
 
            self.addCleanup(tt.finalize)
810
 
            tt.new_symlink('foo', tt.root, 'bar')
811
 
            result = tt.find_conflicts()
812
 
            self.assertEqual([], result)
 
794
            tt = TreeTransform(wt)  # TreeTransform obtains write lock
 
795
            try:
 
796
                tt.new_symlink('foo', tt.root, 'bar')
 
797
                tt.apply()
 
798
            finally:
 
799
                wt.unlock()
813
800
        os_symlink = getattr(os, 'symlink', None)
814
801
        os.symlink = None
815
802
        try:
816
 
            tt_helper()
 
803
            err = self.assertRaises(errors.UnableCreateSymlink, tt_helper)
 
804
            self.assertEqual(
 
805
                "Unable to create symlink 'foo' on this platform",
 
806
                str(err))
817
807
        finally:
818
808
            if os_symlink:
819
809
                os.symlink = os_symlink
820
810
 
821
811
    def get_conflicted(self):
822
 
        create, root = self.get_transform()
823
 
        create.new_file('dorothy', root, [b'dorothy'], b'dorothy-id')
824
 
        oz = create.new_directory('oz', root, b'oz-id')
825
 
        create.new_directory('emeraldcity', oz, b'emerald-id')
 
812
        create,root = self.get_transform()
 
813
        create.new_file('dorothy', root, 'dorothy', 'dorothy-id')
 
814
        oz = create.new_directory('oz', root, 'oz-id')
 
815
        create.new_directory('emeraldcity', oz, 'emerald-id')
826
816
        create.apply()
827
 
        conflicts, root = self.get_transform()
 
817
        conflicts,root = self.get_transform()
828
818
        # set up duplicate entry, duplicate id
829
 
        new_dorothy = conflicts.new_file('dorothy', root, [b'dorothy'],
830
 
                                         b'dorothy-id')
831
 
        old_dorothy = conflicts.trans_id_tree_path('dorothy')
832
 
        oz = conflicts.trans_id_tree_path('oz')
 
819
        new_dorothy = conflicts.new_file('dorothy', root, 'dorothy',
 
820
                                         'dorothy-id')
 
821
        old_dorothy = conflicts.trans_id_tree_file_id('dorothy-id')
 
822
        oz = conflicts.trans_id_tree_file_id('oz-id')
833
823
        # set up DeletedParent parent conflict
834
824
        conflicts.delete_versioned(oz)
835
 
        emerald = conflicts.trans_id_tree_path('oz/emeraldcity')
 
825
        emerald = conflicts.trans_id_tree_file_id('emerald-id')
836
826
        # set up MissingParent conflict
837
 
        munchkincity = conflicts.trans_id_file_id(b'munchkincity-id')
 
827
        munchkincity = conflicts.trans_id_file_id('munchkincity-id')
838
828
        conflicts.adjust_path('munchkincity', root, munchkincity)
839
 
        conflicts.new_directory('auntem', munchkincity, b'auntem-id')
 
829
        conflicts.new_directory('auntem', munchkincity, 'auntem-id')
840
830
        # set up parent loop
841
831
        conflicts.adjust_path('emeraldcity', emerald, emerald)
842
832
        return conflicts, emerald, oz, old_dorothy, new_dorothy
848
838
        self.assertEqual(conflicts.final_name(old_dorothy), 'dorothy.moved')
849
839
        self.assertIs(conflicts.final_file_id(old_dorothy), None)
850
840
        self.assertEqual(conflicts.final_name(new_dorothy), 'dorothy')
851
 
        self.assertEqual(conflicts.final_file_id(new_dorothy), b'dorothy-id')
 
841
        self.assertEqual(conflicts.final_file_id(new_dorothy), 'dorothy-id')
852
842
        self.assertEqual(conflicts.final_parent(emerald), oz)
853
843
        conflicts.apply()
854
844
 
857
847
        raw_conflicts = resolve_conflicts(tt)
858
848
        cooked_conflicts = cook_conflicts(raw_conflicts, tt)
859
849
        duplicate = DuplicateEntry('Moved existing file to', 'dorothy.moved',
860
 
                                   'dorothy', None, b'dorothy-id')
 
850
                                   'dorothy', None, 'dorothy-id')
861
851
        self.assertEqual(cooked_conflicts[0], duplicate)
862
852
        duplicate_id = DuplicateID('Unversioned existing file',
863
853
                                   'dorothy.moved', 'dorothy', None,
864
 
                                   b'dorothy-id')
 
854
                                   'dorothy-id')
865
855
        self.assertEqual(cooked_conflicts[1], duplicate_id)
866
856
        missing_parent = MissingParent('Created directory', 'munchkincity',
867
 
                                       b'munchkincity-id')
868
 
        deleted_parent = DeletingParent('Not deleting', 'oz', b'oz-id')
 
857
                                       'munchkincity-id')
 
858
        deleted_parent = DeletingParent('Not deleting', 'oz', 'oz-id')
869
859
        self.assertEqual(cooked_conflicts[2], missing_parent)
870
860
        unversioned_parent = UnversionedParent('Versioned directory',
871
861
                                               'munchkincity',
872
 
                                               b'munchkincity-id')
 
862
                                               'munchkincity-id')
873
863
        unversioned_parent2 = UnversionedParent('Versioned directory', 'oz',
874
 
                                                b'oz-id')
 
864
                                               'oz-id')
875
865
        self.assertEqual(cooked_conflicts[3], unversioned_parent)
876
 
        parent_loop = ParentLoop(
877
 
            'Cancelled move', 'oz/emeraldcity',
878
 
            'oz/emeraldcity', b'emerald-id', b'emerald-id')
 
866
        parent_loop = ParentLoop('Cancelled move', 'oz/emeraldcity',
 
867
                                 'oz/emeraldcity', 'emerald-id', 'emerald-id')
879
868
        self.assertEqual(cooked_conflicts[4], deleted_parent)
880
869
        self.assertEqual(cooked_conflicts[5], unversioned_parent2)
881
870
        self.assertEqual(cooked_conflicts[6], parent_loop)
887
876
        raw_conflicts = resolve_conflicts(tt)
888
877
        cooked_conflicts = cook_conflicts(raw_conflicts, tt)
889
878
        tt.finalize()
890
 
        conflicts_s = [str(c) for c in cooked_conflicts]
 
879
        conflicts_s = [unicode(c) for c in cooked_conflicts]
891
880
        self.assertEqual(len(cooked_conflicts), len(conflicts_s))
892
881
        self.assertEqual(conflicts_s[0], 'Conflict adding file dorothy.  '
893
882
                                         'Moved existing file to '
900
889
        self.assertEqual(conflicts_s[3], 'Conflict because munchkincity is not'
901
890
                                         ' versioned, but has versioned'
902
891
                                         ' children.  Versioned directory.')
903
 
        self.assertEqualDiff(
904
 
            conflicts_s[4], "Conflict: can't delete oz because it"
905
 
                            " is not empty.  Not deleting.")
 
892
        self.assertEqualDiff(conflicts_s[4], "Conflict: can't delete oz because it"
 
893
                                         " is not empty.  Not deleting.")
906
894
        self.assertEqual(conflicts_s[5], 'Conflict because oz is not'
907
895
                                         ' versioned, but has versioned'
908
896
                                         ' children.  Versioned directory.')
911
899
 
912
900
    def prepare_wrong_parent_kind(self):
913
901
        tt, root = self.get_transform()
914
 
        tt.new_file('parent', root, [b'contents'], b'parent-id')
 
902
        tt.new_file('parent', root, 'contents', 'parent-id')
915
903
        tt.apply()
916
904
        tt, root = self.get_transform()
917
 
        parent_id = tt.trans_id_file_id(b'parent-id')
918
 
        tt.new_file('child,', parent_id, [b'contents2'], b'file-id')
 
905
        parent_id = tt.trans_id_file_id('parent-id')
 
906
        tt.new_file('child,', parent_id, 'contents2', 'file-id')
919
907
        return tt
920
908
 
921
909
    def test_find_conflicts_wrong_parent_kind(self):
925
913
    def test_resolve_conflicts_wrong_existing_parent_kind(self):
926
914
        tt = self.prepare_wrong_parent_kind()
927
915
        raw_conflicts = resolve_conflicts(tt)
928
 
        self.assertEqual({('non-directory parent', 'Created directory',
929
 
                           'new-3')}, raw_conflicts)
 
916
        self.assertEqual(set([('non-directory parent', 'Created directory',
 
917
                         'new-3')]), raw_conflicts)
930
918
        cooked_conflicts = cook_conflicts(raw_conflicts, tt)
931
919
        self.assertEqual([NonDirectoryParent('Created directory', 'parent.new',
932
 
                                             b'parent-id')], cooked_conflicts)
 
920
        'parent-id')], cooked_conflicts)
933
921
        tt.apply()
934
 
        self.assertFalse(self.wt.is_versioned('parent'))
935
 
        self.assertEqual(b'parent-id', self.wt.path2id('parent.new'))
 
922
        self.assertEqual(None, self.wt.path2id('parent'))
 
923
        self.assertEqual('parent-id', self.wt.path2id('parent.new'))
936
924
 
937
925
    def test_resolve_conflicts_wrong_new_parent_kind(self):
938
926
        tt, root = self.get_transform()
939
 
        parent_id = tt.new_directory('parent', root, b'parent-id')
940
 
        tt.new_file('child,', parent_id, [b'contents2'], b'file-id')
 
927
        parent_id = tt.new_directory('parent', root, 'parent-id')
 
928
        tt.new_file('child,', parent_id, 'contents2', 'file-id')
941
929
        tt.apply()
942
930
        tt, root = self.get_transform()
943
 
        parent_id = tt.trans_id_file_id(b'parent-id')
 
931
        parent_id = tt.trans_id_file_id('parent-id')
944
932
        tt.delete_contents(parent_id)
945
 
        tt.create_file([b'contents'], parent_id)
 
933
        tt.create_file('contents', parent_id)
946
934
        raw_conflicts = resolve_conflicts(tt)
947
 
        self.assertEqual({('non-directory parent', 'Created directory',
948
 
                           'new-3')}, raw_conflicts)
 
935
        self.assertEqual(set([('non-directory parent', 'Created directory',
 
936
                         'new-3')]), raw_conflicts)
949
937
        tt.apply()
950
 
        self.assertFalse(self.wt.is_versioned('parent'))
951
 
        self.assertEqual(b'parent-id', self.wt.path2id('parent.new'))
 
938
        self.assertEqual(None, self.wt.path2id('parent'))
 
939
        self.assertEqual('parent-id', self.wt.path2id('parent.new'))
952
940
 
953
941
    def test_resolve_conflicts_wrong_parent_kind_unversioned(self):
954
942
        tt, root = self.get_transform()
955
943
        parent_id = tt.new_directory('parent', root)
956
 
        tt.new_file('child,', parent_id, [b'contents2'])
 
944
        tt.new_file('child,', parent_id, 'contents2')
957
945
        tt.apply()
958
946
        tt, root = self.get_transform()
959
947
        parent_id = tt.trans_id_tree_path('parent')
960
948
        tt.delete_contents(parent_id)
961
 
        tt.create_file([b'contents'], parent_id)
 
949
        tt.create_file('contents', parent_id)
962
950
        resolve_conflicts(tt)
963
951
        tt.apply()
964
 
        self.assertFalse(self.wt.is_versioned('parent'))
965
 
        self.assertFalse(self.wt.is_versioned('parent.new'))
 
952
        self.assertIs(None, self.wt.path2id('parent'))
 
953
        self.assertIs(None, self.wt.path2id('parent.new'))
966
954
 
967
955
    def test_resolve_conflicts_missing_parent(self):
968
956
        wt = self.make_branch_and_tree('.')
969
957
        tt = TreeTransform(wt)
970
958
        self.addCleanup(tt.finalize)
971
 
        parent = tt.trans_id_file_id(b'parent-id')
972
 
        tt.new_file('file', parent, [b'Contents'])
 
959
        parent = tt.trans_id_file_id('parent-id')
 
960
        tt.new_file('file', parent, 'Contents')
973
961
        raw_conflicts = resolve_conflicts(tt)
974
962
        # Since the directory doesn't exist it's seen as 'missing'.  So
975
963
        # 'resolve_conflicts' create a conflict asking for it to be created.
981
969
 
982
970
    def test_moving_versioned_directories(self):
983
971
        create, root = self.get_transform()
984
 
        kansas = create.new_directory('kansas', root, b'kansas-id')
985
 
        create.new_directory('house', kansas, b'house-id')
986
 
        create.new_directory('oz', root, b'oz-id')
 
972
        kansas = create.new_directory('kansas', root, 'kansas-id')
 
973
        create.new_directory('house', kansas, 'house-id')
 
974
        create.new_directory('oz', root, 'oz-id')
987
975
        create.apply()
988
976
        cyclone, root = self.get_transform()
989
 
        oz = cyclone.trans_id_tree_path('oz')
990
 
        house = cyclone.trans_id_tree_path('house')
 
977
        oz = cyclone.trans_id_tree_file_id('oz-id')
 
978
        house = cyclone.trans_id_tree_file_id('house-id')
991
979
        cyclone.adjust_path('house', oz, house)
992
980
        cyclone.apply()
993
981
 
994
982
    def test_moving_root(self):
995
983
        create, root = self.get_transform()
996
 
        fun = create.new_directory('fun', root, b'fun-id')
997
 
        create.new_directory('sun', root, b'sun-id')
998
 
        create.new_directory('moon', root, b'moon')
 
984
        fun = create.new_directory('fun', root, 'fun-id')
 
985
        create.new_directory('sun', root, 'sun-id')
 
986
        create.new_directory('moon', root, 'moon')
999
987
        create.apply()
1000
988
        transform, root = self.get_transform()
1001
989
        transform.adjust_root_path('oldroot', fun)
1002
990
        new_root = transform.trans_id_tree_path('')
1003
 
        transform.version_file(b'new-root', new_root)
 
991
        transform.version_file('new-root', new_root)
1004
992
        transform.apply()
1005
993
 
1006
994
    def test_renames(self):
1007
995
        create, root = self.get_transform()
1008
 
        old = create.new_directory('old-parent', root, b'old-id')
1009
 
        intermediate = create.new_directory('intermediate', old, b'im-id')
1010
 
        myfile = create.new_file('myfile', intermediate, [b'myfile-text'],
1011
 
                                 b'myfile-id')
 
996
        old = create.new_directory('old-parent', root, 'old-id')
 
997
        intermediate = create.new_directory('intermediate', old, 'im-id')
 
998
        myfile = create.new_file('myfile', intermediate, 'myfile-text',
 
999
                                 'myfile-id')
1012
1000
        create.apply()
1013
1001
        rename, root = self.get_transform()
1014
 
        old = rename.trans_id_file_id(b'old-id')
 
1002
        old = rename.trans_id_file_id('old-id')
1015
1003
        rename.adjust_path('new', root, old)
1016
 
        myfile = rename.trans_id_file_id(b'myfile-id')
 
1004
        myfile = rename.trans_id_file_id('myfile-id')
1017
1005
        rename.set_executability(True, myfile)
1018
1006
        rename.apply()
1019
1007
 
1021
1009
        self.requireFeature(features.not_running_as_root)
1022
1010
        # see https://bugs.launchpad.net/bzr/+bug/491763
1023
1011
        create, root_id = self.get_transform()
1024
 
        create.new_directory('first-dir', root_id, b'first-id')
1025
 
        create.new_file('myfile', root_id, [b'myfile-text'], b'myfile-id')
 
1012
        first_dir = create.new_directory('first-dir', root_id, 'first-id')
 
1013
        myfile = create.new_file('myfile', root_id, 'myfile-text',
 
1014
                                 'myfile-id')
1026
1015
        create.apply()
1027
1016
        if os.name == "posix" and sys.platform != "cygwin":
1028
1017
            # posix filesystems fail on renaming if the readonly bit is set
1029
1018
            osutils.make_readonly(self.wt.abspath('first-dir'))
1030
1019
        elif os.name == "nt":
1031
1020
            # windows filesystems fail on renaming open files
1032
 
            self.addCleanup(open(self.wt.abspath('myfile')).close)
 
1021
            self.addCleanup(file(self.wt.abspath('myfile')).close)
1033
1022
        else:
1034
 
            self.skipTest("Can't force a permissions error on rename")
 
1023
            self.skip("Don't know how to force a permissions error on rename")
1035
1024
        # now transform to rename
1036
1025
        rename_transform, root_id = self.get_transform()
1037
 
        file_trans_id = rename_transform.trans_id_file_id(b'myfile-id')
1038
 
        dir_id = rename_transform.trans_id_file_id(b'first-id')
 
1026
        file_trans_id = rename_transform.trans_id_file_id('myfile-id')
 
1027
        dir_id = rename_transform.trans_id_file_id('first-id')
1039
1028
        rename_transform.adjust_path('newname', dir_id, file_trans_id)
1040
1029
        e = self.assertRaises(errors.TransformRenameFailed,
1041
 
                              rename_transform.apply)
1042
 
        # On nix looks like:
 
1030
            rename_transform.apply)
 
1031
        # On nix looks like: 
1043
1032
        # "Failed to rename .../work/.bzr/checkout/limbo/new-1
1044
1033
        # to .../first-dir/newname: [Errno 13] Permission denied"
1045
1034
        # On windows looks like:
1046
 
        # "Failed to rename .../work/myfile to
 
1035
        # "Failed to rename .../work/myfile to 
1047
1036
        # .../work/.bzr/checkout/limbo/new-1: [Errno 13] Permission denied"
1048
1037
        # This test isn't concerned with exactly what the error looks like,
1049
1038
        # and the strerror will vary across OS and locales, but the assert
1059
1048
 
1060
1049
        - create file and set executability simultaneously
1061
1050
        - create file and set executability afterward
1062
 
        - unsetting the executability of a file whose executability has not
1063
 
          been
 
1051
        - unsetting the executability of a file whose executability has not been
1064
1052
        declared should throw an exception (this may happen when a
1065
1053
        merge attempts to create a file with a duplicate ID)
1066
1054
        """
1068
1056
        wt = transform._tree
1069
1057
        wt.lock_read()
1070
1058
        self.addCleanup(wt.unlock)
1071
 
        transform.new_file('set_on_creation', root, [b'Set on creation'],
1072
 
                           b'soc', True)
 
1059
        transform.new_file('set_on_creation', root, 'Set on creation', 'soc',
 
1060
                           True)
1073
1061
        sac = transform.new_file('set_after_creation', root,
1074
 
                                 [b'Set after creation'], b'sac')
 
1062
                                 'Set after creation', 'sac')
1075
1063
        transform.set_executability(True, sac)
1076
 
        uws = transform.new_file('unset_without_set', root, [b'Unset badly'],
1077
 
                                 b'uws')
 
1064
        uws = transform.new_file('unset_without_set', root, 'Unset badly',
 
1065
                                 'uws')
1078
1066
        self.assertRaises(KeyError, transform.set_executability, None, uws)
1079
1067
        transform.apply()
1080
 
        self.assertTrue(wt.is_executable('set_on_creation'))
1081
 
        self.assertTrue(wt.is_executable('set_after_creation'))
 
1068
        self.assertTrue(wt.is_executable('soc'))
 
1069
        self.assertTrue(wt.is_executable('sac'))
1082
1070
 
1083
1071
    def test_preserve_mode(self):
1084
1072
        """File mode is preserved when replacing content"""
1085
1073
        if sys.platform == 'win32':
1086
1074
            raise TestSkipped('chmod has no effect on win32')
1087
1075
        transform, root = self.get_transform()
1088
 
        transform.new_file('file1', root, [b'contents'], b'file1-id', True)
 
1076
        transform.new_file('file1', root, 'contents', 'file1-id', True)
1089
1077
        transform.apply()
1090
1078
        self.wt.lock_write()
1091
1079
        self.addCleanup(self.wt.unlock)
1092
 
        self.assertTrue(self.wt.is_executable('file1'))
 
1080
        self.assertTrue(self.wt.is_executable('file1-id'))
1093
1081
        transform, root = self.get_transform()
1094
 
        file1_id = transform.trans_id_tree_path('file1')
 
1082
        file1_id = transform.trans_id_tree_file_id('file1-id')
1095
1083
        transform.delete_contents(file1_id)
1096
 
        transform.create_file([b'contents2'], file1_id)
 
1084
        transform.create_file('contents2', file1_id)
1097
1085
        transform.apply()
1098
 
        self.assertTrue(self.wt.is_executable('file1'))
 
1086
        self.assertTrue(self.wt.is_executable('file1-id'))
1099
1087
 
1100
1088
    def test__set_mode_stats_correctly(self):
1101
1089
        """_set_mode stats to determine file mode."""
1104
1092
 
1105
1093
        stat_paths = []
1106
1094
        real_stat = os.stat
1107
 
 
1108
1095
        def instrumented_stat(path):
1109
1096
            stat_paths.append(path)
1110
1097
            return real_stat(path)
1111
1098
 
1112
1099
        transform, root = self.get_transform()
1113
1100
 
1114
 
        bar1_id = transform.new_file('bar', root, [b'bar contents 1\n'],
1115
 
                                     file_id=b'bar-id-1', executable=False)
 
1101
        bar1_id = transform.new_file('bar', root, 'bar contents 1\n',
 
1102
                                     file_id='bar-id-1', executable=False)
1116
1103
        transform.apply()
1117
1104
 
1118
1105
        transform, root = self.get_transform()
1120
1107
        bar2_id = transform.trans_id_tree_path('bar2')
1121
1108
        try:
1122
1109
            os.stat = instrumented_stat
1123
 
            transform.create_file([b'bar2 contents\n'],
1124
 
                                  bar2_id, mode_id=bar1_id)
 
1110
            transform.create_file('bar2 contents\n', bar2_id, mode_id=bar1_id)
1125
1111
        finally:
1126
1112
            os.stat = real_stat
1127
1113
            transform.finalize()
1130
1116
        self.assertEqual([bar1_abspath], stat_paths)
1131
1117
 
1132
1118
    def test_iter_changes(self):
1133
 
        self.wt.set_root_id(b'eert_toor')
 
1119
        self.wt.set_root_id('eert_toor')
1134
1120
        transform, root = self.get_transform()
1135
 
        transform.new_file('old', root, [b'blah'], b'id-1', True)
 
1121
        transform.new_file('old', root, 'blah', 'id-1', True)
1136
1122
        transform.apply()
1137
1123
        transform, root = self.get_transform()
1138
1124
        try:
1139
1125
            self.assertEqual([], list(transform.iter_changes()))
1140
 
            old = transform.trans_id_tree_path('old')
 
1126
            old = transform.trans_id_tree_file_id('id-1')
1141
1127
            transform.unversion_file(old)
1142
 
            self.assertEqual([(b'id-1', ('old', None), False, (True, False),
1143
 
                               (b'eert_toor', b'eert_toor'),
1144
 
                               ('old', 'old'), ('file', 'file'),
1145
 
                               (True, True), False)],
1146
 
                             list(transform.iter_changes()))
1147
 
            transform.new_directory('new', root, b'id-1')
1148
 
            self.assertEqual([(b'id-1', ('old', 'new'), True, (True, True),
1149
 
                               (b'eert_toor', b'eert_toor'), ('old', 'new'),
1150
 
                               ('file', 'directory'),
1151
 
                               (True, False), False)],
1152
 
                             list(transform.iter_changes()))
 
1128
            self.assertEqual([('id-1', ('old', None), False, (True, False),
 
1129
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
 
1130
                (True, True))], list(transform.iter_changes()))
 
1131
            transform.new_directory('new', root, 'id-1')
 
1132
            self.assertEqual([('id-1', ('old', 'new'), True, (True, True),
 
1133
                ('eert_toor', 'eert_toor'), ('old', 'new'),
 
1134
                ('file', 'directory'),
 
1135
                (True, False))], list(transform.iter_changes()))
1153
1136
        finally:
1154
1137
            transform.finalize()
1155
1138
 
1156
1139
    def test_iter_changes_new(self):
1157
 
        self.wt.set_root_id(b'eert_toor')
 
1140
        self.wt.set_root_id('eert_toor')
1158
1141
        transform, root = self.get_transform()
1159
 
        transform.new_file('old', root, [b'blah'])
 
1142
        transform.new_file('old', root, 'blah')
1160
1143
        transform.apply()
1161
1144
        transform, root = self.get_transform()
1162
1145
        try:
1163
1146
            old = transform.trans_id_tree_path('old')
1164
 
            transform.version_file(b'id-1', old)
1165
 
            self.assertEqual([(b'id-1', (None, 'old'), False, (False, True),
1166
 
                               (b'eert_toor', b'eert_toor'),
1167
 
                               ('old', 'old'), ('file', 'file'),
1168
 
                               (False, False), False)],
1169
 
                             list(transform.iter_changes()))
 
1147
            transform.version_file('id-1', old)
 
1148
            self.assertEqual([('id-1', (None, 'old'), False, (False, True),
 
1149
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
 
1150
                (False, False))], list(transform.iter_changes()))
1170
1151
        finally:
1171
1152
            transform.finalize()
1172
1153
 
1173
1154
    def test_iter_changes_modifications(self):
1174
 
        self.wt.set_root_id(b'eert_toor')
 
1155
        self.wt.set_root_id('eert_toor')
1175
1156
        transform, root = self.get_transform()
1176
 
        transform.new_file('old', root, [b'blah'], b'id-1')
1177
 
        transform.new_file('new', root, [b'blah'])
1178
 
        transform.new_directory('subdir', root, b'subdir-id')
 
1157
        transform.new_file('old', root, 'blah', 'id-1')
 
1158
        transform.new_file('new', root, 'blah')
 
1159
        transform.new_directory('subdir', root, 'subdir-id')
1179
1160
        transform.apply()
1180
1161
        transform, root = self.get_transform()
1181
1162
        try:
1182
1163
            old = transform.trans_id_tree_path('old')
1183
 
            subdir = transform.trans_id_tree_path('subdir')
 
1164
            subdir = transform.trans_id_tree_file_id('subdir-id')
1184
1165
            new = transform.trans_id_tree_path('new')
1185
1166
            self.assertEqual([], list(transform.iter_changes()))
1186
1167
 
1187
 
            # content deletion
 
1168
            #content deletion
1188
1169
            transform.delete_contents(old)
1189
 
            self.assertEqual([(b'id-1', ('old', 'old'), True, (True, True),
1190
 
                               (b'eert_toor', b'eert_toor'),
1191
 
                               ('old', 'old'), ('file', None),
1192
 
                               (False, False), False)],
1193
 
                             list(transform.iter_changes()))
 
1170
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
 
1171
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', None),
 
1172
                (False, False))], list(transform.iter_changes()))
1194
1173
 
1195
 
            # content change
1196
 
            transform.create_file([b'blah'], old)
1197
 
            self.assertEqual([(b'id-1', ('old', 'old'), True, (True, True),
1198
 
                               (b'eert_toor', b'eert_toor'),
1199
 
                               ('old', 'old'), ('file', 'file'),
1200
 
                               (False, False), False)],
1201
 
                             list(transform.iter_changes()))
 
1174
            #content change
 
1175
            transform.create_file('blah', old)
 
1176
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
 
1177
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
 
1178
                (False, False))], list(transform.iter_changes()))
1202
1179
            transform.cancel_deletion(old)
1203
 
            self.assertEqual([(b'id-1', ('old', 'old'), True, (True, True),
1204
 
                               (b'eert_toor', b'eert_toor'),
1205
 
                               ('old', 'old'), ('file', 'file'),
1206
 
                               (False, False), False)],
1207
 
                             list(transform.iter_changes()))
 
1180
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
 
1181
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
 
1182
                (False, False))], list(transform.iter_changes()))
1208
1183
            transform.cancel_creation(old)
1209
1184
 
1210
1185
            # move file_id to a different file
1211
1186
            self.assertEqual([], list(transform.iter_changes()))
1212
1187
            transform.unversion_file(old)
1213
 
            transform.version_file(b'id-1', new)
 
1188
            transform.version_file('id-1', new)
1214
1189
            transform.adjust_path('old', root, new)
1215
 
            self.assertEqual([(b'id-1', ('old', 'old'), True, (True, True),
1216
 
                               (b'eert_toor', b'eert_toor'),
1217
 
                               ('old', 'old'), ('file', 'file'),
1218
 
                               (False, False), False)],
1219
 
                             list(transform.iter_changes()))
 
1190
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
 
1191
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
 
1192
                (False, False))], list(transform.iter_changes()))
1220
1193
            transform.cancel_versioning(new)
1221
1194
            transform._removed_id = set()
1222
1195
 
1223
 
            # execute bit
 
1196
            #execute bit
1224
1197
            self.assertEqual([], list(transform.iter_changes()))
1225
1198
            transform.set_executability(True, old)
1226
 
            self.assertEqual([(b'id-1', ('old', 'old'), False, (True, True),
1227
 
                               (b'eert_toor', b'eert_toor'),
1228
 
                               ('old', 'old'), ('file', 'file'),
1229
 
                               (False, True), False)],
1230
 
                             list(transform.iter_changes()))
 
1199
            self.assertEqual([('id-1', ('old', 'old'), False, (True, True),
 
1200
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
 
1201
                (False, True))], list(transform.iter_changes()))
1231
1202
            transform.set_executability(None, old)
1232
1203
 
1233
1204
            # filename
1234
1205
            self.assertEqual([], list(transform.iter_changes()))
1235
1206
            transform.adjust_path('new', root, old)
1236
1207
            transform._new_parent = {}
1237
 
            self.assertEqual([(b'id-1', ('old', 'new'), False, (True, True),
1238
 
                               (b'eert_toor', b'eert_toor'),
1239
 
                               ('old', 'new'), ('file', 'file'),
1240
 
                               (False, False), False)],
1241
 
                             list(transform.iter_changes()))
 
1208
            self.assertEqual([('id-1', ('old', 'new'), False, (True, True),
 
1209
                ('eert_toor', 'eert_toor'), ('old', 'new'), ('file', 'file'),
 
1210
                (False, False))], list(transform.iter_changes()))
1242
1211
            transform._new_name = {}
1243
1212
 
1244
1213
            # parent directory
1245
1214
            self.assertEqual([], list(transform.iter_changes()))
1246
1215
            transform.adjust_path('new', subdir, old)
1247
1216
            transform._new_name = {}
1248
 
            self.assertEqual([(b'id-1', ('old', 'subdir/old'), False,
1249
 
                               (True, True), (b'eert_toor',
1250
 
                                              b'subdir-id'), ('old', 'old'),
1251
 
                               ('file', 'file'), (False, False), False)],
1252
 
                             list(transform.iter_changes()))
 
1217
            self.assertEqual([('id-1', ('old', 'subdir/old'), False,
 
1218
                (True, True), ('eert_toor', 'subdir-id'), ('old', 'old'),
 
1219
                ('file', 'file'), (False, False))],
 
1220
                list(transform.iter_changes()))
1253
1221
            transform._new_path = {}
1254
1222
 
1255
1223
        finally:
1256
1224
            transform.finalize()
1257
1225
 
1258
1226
    def test_iter_changes_modified_bleed(self):
1259
 
        self.wt.set_root_id(b'eert_toor')
 
1227
        self.wt.set_root_id('eert_toor')
1260
1228
        """Modified flag should not bleed from one change to another"""
1261
1229
        # unfortunately, we have no guarantee that file1 (which is modified)
1262
1230
        # will be applied before file2.  And if it's applied after file2, it
1263
1231
        # obviously can't bleed into file2's change output.  But for now, it
1264
1232
        # works.
1265
1233
        transform, root = self.get_transform()
1266
 
        transform.new_file('file1', root, [b'blah'], b'id-1')
1267
 
        transform.new_file('file2', root, [b'blah'], b'id-2')
 
1234
        transform.new_file('file1', root, 'blah', 'id-1')
 
1235
        transform.new_file('file2', root, 'blah', 'id-2')
1268
1236
        transform.apply()
1269
1237
        transform, root = self.get_transform()
1270
1238
        try:
1271
 
            transform.delete_contents(transform.trans_id_file_id(b'id-1'))
 
1239
            transform.delete_contents(transform.trans_id_file_id('id-1'))
1272
1240
            transform.set_executability(True,
1273
 
                                        transform.trans_id_file_id(b'id-2'))
1274
 
            self.assertEqual(
1275
 
                [(b'id-1', (u'file1', u'file1'), True, (True, True),
1276
 
                 (b'eert_toor', b'eert_toor'), ('file1', u'file1'),
1277
 
                 ('file', None), (False, False), False),
1278
 
                 (b'id-2', (u'file2', u'file2'), False, (True, True),
1279
 
                 (b'eert_toor', b'eert_toor'), ('file2', u'file2'),
1280
 
                 ('file', 'file'), (False, True), False)],
 
1241
            transform.trans_id_file_id('id-2'))
 
1242
            self.assertEqual([('id-1', (u'file1', u'file1'), True, (True, True),
 
1243
                ('eert_toor', 'eert_toor'), ('file1', u'file1'),
 
1244
                ('file', None), (False, False)),
 
1245
                ('id-2', (u'file2', u'file2'), False, (True, True),
 
1246
                ('eert_toor', 'eert_toor'), ('file2', u'file2'),
 
1247
                ('file', 'file'), (False, True))],
1281
1248
                list(transform.iter_changes()))
1282
1249
        finally:
1283
1250
            transform.finalize()
1284
1251
 
1285
1252
    def test_iter_changes_move_missing(self):
1286
1253
        """Test moving ids with no files around"""
1287
 
        self.wt.set_root_id(b'toor_eert')
 
1254
        self.wt.set_root_id('toor_eert')
1288
1255
        # Need two steps because versioning a non-existant file is a conflict.
1289
1256
        transform, root = self.get_transform()
1290
 
        transform.new_directory('floater', root, b'floater-id')
 
1257
        transform.new_directory('floater', root, 'floater-id')
1291
1258
        transform.apply()
1292
1259
        transform, root = self.get_transform()
1293
1260
        transform.delete_contents(transform.trans_id_tree_path('floater'))
1296
1263
        floater = transform.trans_id_tree_path('floater')
1297
1264
        try:
1298
1265
            transform.adjust_path('flitter', root, floater)
1299
 
            self.assertEqual([(b'floater-id', ('floater', 'flitter'), False,
1300
 
                               (True, True),
1301
 
                               (b'toor_eert', b'toor_eert'),
1302
 
                               ('floater', 'flitter'),
1303
 
                               (None, None), (False, False), False)],
1304
 
                             list(transform.iter_changes()))
 
1266
            self.assertEqual([('floater-id', ('floater', 'flitter'), False,
 
1267
            (True, True), ('toor_eert', 'toor_eert'), ('floater', 'flitter'),
 
1268
            (None, None), (False, False))], list(transform.iter_changes()))
1305
1269
        finally:
1306
1270
            transform.finalize()
1307
1271
 
1308
1272
    def test_iter_changes_pointless(self):
1309
1273
        """Ensure that no-ops are not treated as modifications"""
1310
 
        self.wt.set_root_id(b'eert_toor')
 
1274
        self.wt.set_root_id('eert_toor')
1311
1275
        transform, root = self.get_transform()
1312
 
        transform.new_file('old', root, [b'blah'], b'id-1')
1313
 
        transform.new_directory('subdir', root, b'subdir-id')
 
1276
        transform.new_file('old', root, 'blah', 'id-1')
 
1277
        transform.new_directory('subdir', root, 'subdir-id')
1314
1278
        transform.apply()
1315
1279
        transform, root = self.get_transform()
1316
1280
        try:
1317
1281
            old = transform.trans_id_tree_path('old')
1318
 
            subdir = transform.trans_id_tree_path('subdir')
 
1282
            subdir = transform.trans_id_tree_file_id('subdir-id')
1319
1283
            self.assertEqual([], list(transform.iter_changes()))
1320
1284
            transform.delete_contents(subdir)
1321
1285
            transform.create_directory(subdir)
1322
1286
            transform.set_executability(False, old)
1323
1287
            transform.unversion_file(old)
1324
 
            transform.version_file(b'id-1', old)
 
1288
            transform.version_file('id-1', old)
1325
1289
            transform.adjust_path('old', root, old)
1326
1290
            self.assertEqual([], list(transform.iter_changes()))
1327
1291
        finally:
1329
1293
 
1330
1294
    def test_rename_count(self):
1331
1295
        transform, root = self.get_transform()
1332
 
        transform.new_file('name1', root, [b'contents'])
 
1296
        transform.new_file('name1', root, 'contents')
1333
1297
        self.assertEqual(transform.rename_count, 0)
1334
1298
        transform.apply()
1335
1299
        self.assertEqual(transform.rename_count, 1)
1352
1316
        """
1353
1317
        transform, root = self.get_transform()
1354
1318
        parent1 = transform.new_directory('parent1', root)
1355
 
        child1 = transform.new_file('child1', parent1, [b'contents'])
 
1319
        child1 = transform.new_file('child1', parent1, 'contents')
1356
1320
        parent2 = transform.new_directory('parent2', root)
1357
1321
        transform.adjust_path('child1', parent2, child1)
1358
1322
        transform.apply()
1371
1335
        """
1372
1336
        transform, root = self.get_transform()
1373
1337
        parent1 = transform.new_directory('parent1', root)
1374
 
        child1 = transform.new_file('child1', parent1, [b'contents'])
1375
 
        child2 = transform.new_file('child2', parent1, [b'contents'])
 
1338
        child1 = transform.new_file('child1', parent1, 'contents')
 
1339
        child2 = transform.new_file('child2', parent1, 'contents')
1376
1340
        try:
1377
1341
            transform.cancel_creation(parent1)
1378
1342
        except OSError:
1398
1362
        """Make sure adjust_path keeps track of limbo children properly"""
1399
1363
        transform, root = self.get_transform()
1400
1364
        parent1 = transform.new_directory('parent1', root)
1401
 
        child1 = transform.new_file('child1', parent1, [b'contents'])
 
1365
        child1 = transform.new_file('child1', parent1, 'contents')
1402
1366
        parent2 = transform.new_directory('parent2', root)
1403
1367
        transform.adjust_path('child1', parent2, child1)
1404
1368
        transform.cancel_creation(child1)
1413
1377
    def test_noname_contents(self):
1414
1378
        """TreeTransform should permit deferring naming files."""
1415
1379
        transform, root = self.get_transform()
1416
 
        parent = transform.trans_id_file_id(b'parent-id')
 
1380
        parent = transform.trans_id_file_id('parent-id')
1417
1381
        try:
1418
1382
            transform.create_directory(parent)
1419
1383
        except KeyError:
1423
1387
    def test_noname_contents_nested(self):
1424
1388
        """TreeTransform should permit deferring naming files."""
1425
1389
        transform, root = self.get_transform()
1426
 
        parent = transform.trans_id_file_id(b'parent-id')
 
1390
        parent = transform.trans_id_file_id('parent-id')
1427
1391
        try:
1428
1392
            transform.create_directory(parent)
1429
1393
        except KeyError:
1430
1394
            self.fail("Can't handle contents with no name")
1431
 
        transform.new_directory('child', parent)
 
1395
        child = transform.new_directory('child', parent)
1432
1396
        transform.adjust_path('parent', root, parent)
1433
1397
        transform.apply()
1434
1398
        self.assertPathExists(self.wt.abspath('parent/child'))
1438
1402
        """Avoid reusing the same limbo name for different files"""
1439
1403
        transform, root = self.get_transform()
1440
1404
        parent = transform.new_directory('parent', root)
1441
 
        transform.new_directory('child', parent)
 
1405
        child1 = transform.new_directory('child', parent)
1442
1406
        try:
1443
1407
            child2 = transform.new_directory('child', parent)
1444
1408
        except OSError:
1458
1422
        parent = transform.new_directory('parent', root)
1459
1423
        child1 = transform.new_directory('child', parent)
1460
1424
        transform.adjust_path('child1', parent, child1)
1461
 
        transform.new_directory('child', parent)
 
1425
        child2 = transform.new_directory('child', parent)
1462
1426
        transform.apply()
1463
1427
        # limbo/new-1 => parent
1464
1428
        self.assertEqual(1, transform.rename_count)
1470
1434
        child1 = transform.new_directory('child1', parent2)
1471
1435
        transform.cancel_creation(parent2)
1472
1436
        transform.create_directory(parent2)
1473
 
        transform.new_directory('child1', parent2)
 
1437
        child2 = transform.new_directory('child1', parent2)
1474
1438
        transform.adjust_path('child2', parent2, child1)
1475
1439
        transform.apply()
1476
1440
        # limbo/new-1 => parent2, limbo/new-2 => parent2/child1
1480
1444
        """Finalize must be done in child-to-parent order"""
1481
1445
        transform, root = self.get_transform()
1482
1446
        parent = transform.new_directory('parent', root)
1483
 
        transform.new_directory('child', parent)
 
1447
        child = transform.new_directory('child', parent)
1484
1448
        try:
1485
1449
            transform.finalize()
1486
1450
        except OSError:
1500
1464
            tt = TreeTransform(wt)  # TreeTransform obtains write lock
1501
1465
            try:
1502
1466
                foo = tt.new_directory('foo', tt.root)
1503
 
                tt.new_file('bar', foo, [b'foobar'])
 
1467
                tt.new_file('bar', foo, 'foobar')
1504
1468
                baz = tt.new_directory('baz', tt.root)
1505
 
                tt.new_file('qux', baz, [b'quux'])
 
1469
                tt.new_file('qux', baz, 'quux')
1506
1470
                # Ask for a rename 'foo' -> 'baz'
1507
1471
                tt.adjust_path('baz', tt.root, foo)
1508
1472
                # Lie to tt that we've already resolved all conflicts.
1509
1473
                tt.apply(no_conflicts=True)
1510
 
            except BaseException:
 
1474
            except:
1511
1475
                wt.unlock()
1512
1476
                raise
1513
1477
        # The rename will fail because the target directory is not empty (but
1527
1491
                tt.new_directory('baz', foo_2)
1528
1492
                # Lie to tt that we've already resolved all conflicts.
1529
1493
                tt.apply(no_conflicts=True)
1530
 
            except BaseException:
 
1494
            except:
1531
1495
                wt.unlock()
1532
1496
                raise
1533
1497
        err = self.assertRaises(errors.FileExists, tt_helper)
1545
1509
                tt.new_directory('baz', foo_2)
1546
1510
                # Lie to tt that we've already resolved all conflicts.
1547
1511
                tt.apply(no_conflicts=True)
1548
 
            except BaseException:
 
1512
            except:
1549
1513
                tt.finalize()
1550
1514
                raise
1551
1515
        err = self.assertRaises(errors.FileExists, tt_helper)
1562
1526
        tt.delete_contents(foo_trans_id)
1563
1527
        tt.create_directory(foo_trans_id)
1564
1528
        bar_trans_id = tt.trans_id_tree_path("foo/bar")
1565
 
        tt.create_file([b"aa\n"], bar_trans_id)
1566
 
        tt.version_file(b"bar-1", bar_trans_id)
 
1529
        tt.create_file(["aa\n"], bar_trans_id)
 
1530
        tt.version_file("bar-1", bar_trans_id)
1567
1531
        tt.apply()
1568
1532
        self.assertPathExists("foo/bar")
1569
1533
        wt.lock_read()
1570
1534
        try:
1571
 
            self.assertEqual(wt.kind("foo"), "directory")
 
1535
            self.assertEqual(wt.kind(wt.path2id("foo")), "directory")
1572
1536
        finally:
1573
1537
            wt.unlock()
1574
1538
        wt.commit("two")
1590
1554
        self.assertPathExists("foo")
1591
1555
        wt.lock_read()
1592
1556
        self.addCleanup(wt.unlock)
1593
 
        self.assertEqual(wt.kind("foo"), "symlink")
1594
 
 
1595
 
    def test_file_to_symlink_unsupported(self):
1596
 
        wt = self.make_branch_and_tree('.')
1597
 
        self.build_tree(['foo'])
1598
 
        wt.add(['foo'])
1599
 
        wt.commit("one")
1600
 
        self.overrideAttr(osutils, 'supports_symlinks', lambda p: False)
1601
 
        tt = TreeTransform(wt)
1602
 
        self.addCleanup(tt.finalize)
1603
 
        foo_trans_id = tt.trans_id_tree_path("foo")
1604
 
        tt.delete_contents(foo_trans_id)
1605
 
        log = BytesIO()
1606
 
        trace.push_log_file(log)
1607
 
        tt.create_symlink("bar", foo_trans_id)
1608
 
        tt.apply()
1609
 
        self.assertContainsRe(
1610
 
            log.getvalue(),
1611
 
            b'Unable to create symlink "foo" on this filesystem')
 
1557
        self.assertEqual(wt.kind(wt.path2id("foo")), "symlink")
1612
1558
 
1613
1559
    def test_dir_to_file(self):
1614
1560
        wt = self.make_branch_and_tree('.')
1621
1567
        bar_trans_id = tt.trans_id_tree_path("foo/bar")
1622
1568
        tt.delete_contents(foo_trans_id)
1623
1569
        tt.delete_versioned(bar_trans_id)
1624
 
        tt.create_file([b"aa\n"], foo_trans_id)
 
1570
        tt.create_file(["aa\n"], foo_trans_id)
1625
1571
        tt.apply()
1626
1572
        self.assertPathExists("foo")
1627
1573
        wt.lock_read()
1628
1574
        self.addCleanup(wt.unlock)
1629
 
        self.assertEqual(wt.kind("foo"), "file")
 
1575
        self.assertEqual(wt.kind(wt.path2id("foo")), "file")
1630
1576
 
1631
1577
    def test_dir_to_hardlink(self):
1632
1578
        self.requireFeature(HardlinkFeature)
1647
1593
        self.assertPathExists("baz")
1648
1594
        wt.lock_read()
1649
1595
        self.addCleanup(wt.unlock)
1650
 
        self.assertEqual(wt.kind("foo"), "file")
 
1596
        self.assertEqual(wt.kind(wt.path2id("foo")), "file")
1651
1597
 
1652
1598
    def test_no_final_path(self):
1653
1599
        transform, root = self.get_transform()
1654
 
        trans_id = transform.trans_id_file_id(b'foo')
1655
 
        transform.create_file([b'bar'], trans_id)
 
1600
        trans_id = transform.trans_id_file_id('foo')
 
1601
        transform.create_file('bar', trans_id)
1656
1602
        transform.cancel_creation(trans_id)
1657
1603
        transform.apply()
1658
1604
 
1659
1605
    def test_create_from_tree(self):
1660
1606
        tree1 = self.make_branch_and_tree('tree1')
1661
 
        self.build_tree_contents([('tree1/foo/',), ('tree1/bar', b'baz')])
1662
 
        tree1.add(['foo', 'bar'], [b'foo-id', b'bar-id'])
 
1607
        self.build_tree_contents([('tree1/foo/',), ('tree1/bar', 'baz')])
 
1608
        tree1.add(['foo', 'bar'], ['foo-id', 'bar-id'])
1663
1609
        tree2 = self.make_branch_and_tree('tree2')
1664
1610
        tt = TreeTransform(tree2)
1665
1611
        foo_trans_id = tt.create_path('foo', tt.root)
1666
 
        create_from_tree(tt, foo_trans_id, tree1, 'foo')
 
1612
        create_from_tree(tt, foo_trans_id, tree1, 'foo-id')
1667
1613
        bar_trans_id = tt.create_path('bar', tt.root)
1668
 
        create_from_tree(tt, bar_trans_id, tree1, 'bar')
 
1614
        create_from_tree(tt, bar_trans_id, tree1, 'bar-id')
1669
1615
        tt.apply()
1670
1616
        self.assertEqual('directory', osutils.file_kind('tree2/foo'))
1671
 
        self.assertFileEqual(b'baz', 'tree2/bar')
 
1617
        self.assertFileEqual('baz', 'tree2/bar')
1672
1618
 
1673
1619
    def test_create_from_tree_bytes(self):
1674
1620
        """Provided lines are used instead of tree content."""
1675
1621
        tree1 = self.make_branch_and_tree('tree1')
1676
 
        self.build_tree_contents([('tree1/foo', b'bar'), ])
1677
 
        tree1.add('foo', b'foo-id')
 
1622
        self.build_tree_contents([('tree1/foo', 'bar'),])
 
1623
        tree1.add('foo', 'foo-id')
1678
1624
        tree2 = self.make_branch_and_tree('tree2')
1679
1625
        tt = TreeTransform(tree2)
1680
1626
        foo_trans_id = tt.create_path('foo', tt.root)
1681
 
        create_from_tree(tt, foo_trans_id, tree1, 'foo', chunks=[b'qux'])
 
1627
        create_from_tree(tt, foo_trans_id, tree1, 'foo-id', bytes='qux')
1682
1628
        tt.apply()
1683
 
        self.assertFileEqual(b'qux', 'tree2/foo')
 
1629
        self.assertFileEqual('qux', 'tree2/foo')
1684
1630
 
1685
1631
    def test_create_from_tree_symlink(self):
1686
1632
        self.requireFeature(SymlinkFeature)
1687
1633
        tree1 = self.make_branch_and_tree('tree1')
1688
1634
        os.symlink('bar', 'tree1/foo')
1689
 
        tree1.add('foo', b'foo-id')
 
1635
        tree1.add('foo', 'foo-id')
1690
1636
        tt = TreeTransform(self.make_branch_and_tree('tree2'))
1691
1637
        foo_trans_id = tt.create_path('foo', tt.root)
1692
 
        create_from_tree(tt, foo_trans_id, tree1, 'foo')
 
1638
        create_from_tree(tt, foo_trans_id, tree1, 'foo-id')
1693
1639
        tt.apply()
1694
1640
        self.assertEqual('bar', os.readlink('tree2/foo'))
1695
1641
 
1703
1649
        self.wt.set_root_id(root_id)
1704
1650
        self.b = self.wt.branch
1705
1651
        self.tt = TreeTransform(self.wt)
1706
 
        self.root = self.tt.trans_id_tree_path('')
 
1652
        self.root = self.tt.trans_id_tree_file_id(self.wt.get_root_id())
1707
1653
 
1708
1654
 
1709
1655
def conflict_text(tree, merge):
1710
 
    template = b'%s TREE\n%s%s\n%s%s MERGE-SOURCE\n'
1711
 
    return template % (b'<' * 7, tree, b'=' * 7, merge, b'>' * 7)
 
1656
    template = '%s TREE\n%s%s\n%s%s MERGE-SOURCE\n'
 
1657
    return template % ('<' * 7, tree, '=' * 7, merge, '>' * 7)
1712
1658
 
1713
1659
 
1714
1660
class TestInventoryAltered(tests.TestCaseWithTransport):
1716
1662
    def test_inventory_altered_unchanged(self):
1717
1663
        tree = self.make_branch_and_tree('tree')
1718
1664
        self.build_tree(['tree/foo'])
1719
 
        tree.add('foo', b'foo-id')
 
1665
        tree.add('foo', 'foo-id')
1720
1666
        with TransformPreview(tree) as tt:
1721
1667
            self.assertEqual([], tt._inventory_altered())
1722
1668
 
1723
1669
    def test_inventory_altered_changed_parent_id(self):
1724
1670
        tree = self.make_branch_and_tree('tree')
1725
1671
        self.build_tree(['tree/foo'])
1726
 
        tree.add('foo', b'foo-id')
 
1672
        tree.add('foo', 'foo-id')
1727
1673
        with TransformPreview(tree) as tt:
1728
1674
            tt.unversion_file(tt.root)
1729
 
            tt.version_file(b'new-id', tt.root)
1730
 
            foo_trans_id = tt.trans_id_tree_path('foo')
 
1675
            tt.version_file('new-id', tt.root)
 
1676
            foo_trans_id = tt.trans_id_tree_file_id('foo-id')
1731
1677
            foo_tuple = ('foo', foo_trans_id)
1732
1678
            root_tuple = ('', tt.root)
1733
1679
            self.assertEqual([root_tuple, foo_tuple], tt._inventory_altered())
1735
1681
    def test_inventory_altered_noop_changed_parent_id(self):
1736
1682
        tree = self.make_branch_and_tree('tree')
1737
1683
        self.build_tree(['tree/foo'])
1738
 
        tree.add('foo', b'foo-id')
 
1684
        tree.add('foo', 'foo-id')
1739
1685
        with TransformPreview(tree) as tt:
1740
1686
            tt.unversion_file(tt.root)
1741
 
            tt.version_file(tree.path2id(''), tt.root)
1742
 
            tt.trans_id_tree_path('foo')
 
1687
            tt.version_file(tree.get_root_id(), tt.root)
 
1688
            foo_trans_id = tt.trans_id_tree_file_id('foo-id')
1743
1689
            self.assertEqual([], tt._inventory_altered())
1744
1690
 
1745
1691
 
1748
1694
    def test_text_merge(self):
1749
1695
        root_id = generate_ids.gen_root_id()
1750
1696
        base = TransformGroup("base", root_id)
1751
 
        base.tt.new_file('a', base.root, [b'a\nb\nc\nd\be\n'], b'a')
1752
 
        base.tt.new_file('b', base.root, [b'b1'], b'b')
1753
 
        base.tt.new_file('c', base.root, [b'c'], b'c')
1754
 
        base.tt.new_file('d', base.root, [b'd'], b'd')
1755
 
        base.tt.new_file('e', base.root, [b'e'], b'e')
1756
 
        base.tt.new_file('f', base.root, [b'f'], b'f')
1757
 
        base.tt.new_directory('g', base.root, b'g')
1758
 
        base.tt.new_directory('h', base.root, b'h')
 
1697
        base.tt.new_file('a', base.root, 'a\nb\nc\nd\be\n', 'a')
 
1698
        base.tt.new_file('b', base.root, 'b1', 'b')
 
1699
        base.tt.new_file('c', base.root, 'c', 'c')
 
1700
        base.tt.new_file('d', base.root, 'd', 'd')
 
1701
        base.tt.new_file('e', base.root, 'e', 'e')
 
1702
        base.tt.new_file('f', base.root, 'f', 'f')
 
1703
        base.tt.new_directory('g', base.root, 'g')
 
1704
        base.tt.new_directory('h', base.root, 'h')
1759
1705
        base.tt.apply()
1760
1706
        other = TransformGroup("other", root_id)
1761
 
        other.tt.new_file('a', other.root, [b'y\nb\nc\nd\be\n'], b'a')
1762
 
        other.tt.new_file('b', other.root, [b'b2'], b'b')
1763
 
        other.tt.new_file('c', other.root, [b'c2'], b'c')
1764
 
        other.tt.new_file('d', other.root, [b'd'], b'd')
1765
 
        other.tt.new_file('e', other.root, [b'e2'], b'e')
1766
 
        other.tt.new_file('f', other.root, [b'f'], b'f')
1767
 
        other.tt.new_file('g', other.root, [b'g'], b'g')
1768
 
        other.tt.new_file('h', other.root, [b'h\ni\nj\nk\n'], b'h')
1769
 
        other.tt.new_file('i', other.root, [b'h\ni\nj\nk\n'], b'i')
 
1707
        other.tt.new_file('a', other.root, 'y\nb\nc\nd\be\n', 'a')
 
1708
        other.tt.new_file('b', other.root, 'b2', 'b')
 
1709
        other.tt.new_file('c', other.root, 'c2', 'c')
 
1710
        other.tt.new_file('d', other.root, 'd', 'd')
 
1711
        other.tt.new_file('e', other.root, 'e2', 'e')
 
1712
        other.tt.new_file('f', other.root, 'f', 'f')
 
1713
        other.tt.new_file('g', other.root, 'g', 'g')
 
1714
        other.tt.new_file('h', other.root, 'h\ni\nj\nk\n', 'h')
 
1715
        other.tt.new_file('i', other.root, 'h\ni\nj\nk\n', 'i')
1770
1716
        other.tt.apply()
1771
1717
        this = TransformGroup("this", root_id)
1772
 
        this.tt.new_file('a', this.root, [b'a\nb\nc\nd\bz\n'], b'a')
1773
 
        this.tt.new_file('b', this.root, [b'b'], b'b')
1774
 
        this.tt.new_file('c', this.root, [b'c'], b'c')
1775
 
        this.tt.new_file('d', this.root, [b'd2'], b'd')
1776
 
        this.tt.new_file('e', this.root, [b'e2'], b'e')
1777
 
        this.tt.new_file('f', this.root, [b'f'], b'f')
1778
 
        this.tt.new_file('g', this.root, [b'g'], b'g')
1779
 
        this.tt.new_file('h', this.root, [b'1\n2\n3\n4\n'], b'h')
1780
 
        this.tt.new_file('i', this.root, [b'1\n2\n3\n4\n'], b'i')
 
1718
        this.tt.new_file('a', this.root, 'a\nb\nc\nd\bz\n', 'a')
 
1719
        this.tt.new_file('b', this.root, 'b', 'b')
 
1720
        this.tt.new_file('c', this.root, 'c', 'c')
 
1721
        this.tt.new_file('d', this.root, 'd2', 'd')
 
1722
        this.tt.new_file('e', this.root, 'e2', 'e')
 
1723
        this.tt.new_file('f', this.root, 'f', 'f')
 
1724
        this.tt.new_file('g', this.root, 'g', 'g')
 
1725
        this.tt.new_file('h', this.root, '1\n2\n3\n4\n', 'h')
 
1726
        this.tt.new_file('i', this.root, '1\n2\n3\n4\n', 'i')
1781
1727
        this.tt.apply()
1782
1728
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
1783
1729
 
1784
1730
        # textual merge
1785
 
        with this.wt.get_file(this.wt.id2path(b'a')) as f:
1786
 
            self.assertEqual(f.read(), b'y\nb\nc\nd\bz\n')
 
1731
        self.assertEqual(this.wt.get_file('a').read(), 'y\nb\nc\nd\bz\n')
1787
1732
        # three-way text conflict
1788
 
        with this.wt.get_file(this.wt.id2path(b'b')) as f:
1789
 
            self.assertEqual(f.read(), conflict_text(b'b', b'b2'))
 
1733
        self.assertEqual(this.wt.get_file('b').read(),
 
1734
                         conflict_text('b', 'b2'))
1790
1735
        # OTHER wins
1791
 
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'c')).read(), b'c2')
 
1736
        self.assertEqual(this.wt.get_file('c').read(), 'c2')
1792
1737
        # THIS wins
1793
 
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'd')).read(), b'd2')
 
1738
        self.assertEqual(this.wt.get_file('d').read(), 'd2')
1794
1739
        # Ambigious clean merge
1795
 
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'e')).read(), b'e2')
 
1740
        self.assertEqual(this.wt.get_file('e').read(), 'e2')
1796
1741
        # No change
1797
 
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'f')).read(), b'f')
 
1742
        self.assertEqual(this.wt.get_file('f').read(), 'f')
1798
1743
        # Correct correct results when THIS == OTHER
1799
 
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'g')).read(), b'g')
 
1744
        self.assertEqual(this.wt.get_file('g').read(), 'g')
1800
1745
        # Text conflict when THIS & OTHER are text and BASE is dir
1801
 
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'h')).read(),
1802
 
                         conflict_text(b'1\n2\n3\n4\n', b'h\ni\nj\nk\n'))
1803
 
        self.assertEqual(this.wt.get_file('h.THIS').read(),
1804
 
                         b'1\n2\n3\n4\n')
1805
 
        self.assertEqual(this.wt.get_file('h.OTHER').read(),
1806
 
                         b'h\ni\nj\nk\n')
 
1746
        self.assertEqual(this.wt.get_file('h').read(),
 
1747
                         conflict_text('1\n2\n3\n4\n', 'h\ni\nj\nk\n'))
 
1748
        self.assertEqual(this.wt.get_file_byname('h.THIS').read(),
 
1749
                         '1\n2\n3\n4\n')
 
1750
        self.assertEqual(this.wt.get_file_byname('h.OTHER').read(),
 
1751
                         'h\ni\nj\nk\n')
1807
1752
        self.assertEqual(file_kind(this.wt.abspath('h.BASE')), 'directory')
1808
 
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'i')).read(),
1809
 
                         conflict_text(b'1\n2\n3\n4\n', b'h\ni\nj\nk\n'))
1810
 
        self.assertEqual(this.wt.get_file('i.THIS').read(),
1811
 
                         b'1\n2\n3\n4\n')
1812
 
        self.assertEqual(this.wt.get_file('i.OTHER').read(),
1813
 
                         b'h\ni\nj\nk\n')
 
1753
        self.assertEqual(this.wt.get_file('i').read(),
 
1754
                         conflict_text('1\n2\n3\n4\n', 'h\ni\nj\nk\n'))
 
1755
        self.assertEqual(this.wt.get_file_byname('i.THIS').read(),
 
1756
                         '1\n2\n3\n4\n')
 
1757
        self.assertEqual(this.wt.get_file_byname('i.OTHER').read(),
 
1758
                         'h\ni\nj\nk\n')
1814
1759
        self.assertEqual(os.path.exists(this.wt.abspath('i.BASE')), False)
1815
1760
        modified = ['a', 'b', 'c', 'h', 'i']
1816
1761
        merge_modified = this.wt.merge_modified()
1817
1762
        self.assertSubset(merge_modified, modified)
1818
1763
        self.assertEqual(len(merge_modified), len(modified))
1819
 
        with open(this.wt.abspath(this.wt.id2path(b'a')), 'wb') as f:
1820
 
            f.write(b'booga')
 
1764
        with file(this.wt.id2abspath('a'), 'wb') as f: f.write('booga')
1821
1765
        modified.pop(0)
1822
1766
        merge_modified = this.wt.merge_modified()
1823
1767
        self.assertSubset(merge_modified, modified)
1832
1776
        this = TransformGroup("THIS", root_id)
1833
1777
        other = TransformGroup("OTHER", root_id)
1834
1778
        for tg in this, base, other:
1835
 
            tg.tt.new_directory('a', tg.root, b'a')
1836
 
            tg.tt.new_symlink('b', tg.root, 'b', b'b')
1837
 
            tg.tt.new_file('c', tg.root, [b'c'], b'c')
1838
 
            tg.tt.new_symlink('d', tg.root, tg.name, b'd')
 
1779
            tg.tt.new_directory('a', tg.root, 'a')
 
1780
            tg.tt.new_symlink('b', tg.root, 'b', 'b')
 
1781
            tg.tt.new_file('c', tg.root, 'c', 'c')
 
1782
            tg.tt.new_symlink('d', tg.root, tg.name, 'd')
1839
1783
        targets = ((base, 'base-e', 'base-f', None, None),
1840
1784
                   (this, 'other-e', 'this-f', 'other-g', 'this-h'),
1841
1785
                   (other, 'other-e', None, 'other-g', 'other-h'))
1843
1787
            for link, target in (('e', e_target), ('f', f_target),
1844
1788
                                 ('g', g_target), ('h', h_target)):
1845
1789
                if target is not None:
1846
 
                    tg.tt.new_symlink(link, tg.root, target,
1847
 
                                      link.encode('ascii'))
 
1790
                    tg.tt.new_symlink(link, tg.root, target, link)
1848
1791
 
1849
1792
        for tg in this, base, other:
1850
1793
            tg.tt.apply()
1853
1796
        self.assertIs(os.path.islink(this.wt.abspath('b')), True)
1854
1797
        self.assertIs(os.path.isfile(this.wt.abspath('c')), True)
1855
1798
        for suffix in ('THIS', 'BASE', 'OTHER'):
1856
 
            self.assertEqual(os.readlink(
1857
 
                this.wt.abspath('d.' + suffix)), suffix)
 
1799
            self.assertEqual(os.readlink(this.wt.abspath('d.'+suffix)), suffix)
1858
1800
        self.assertIs(os.path.lexists(this.wt.abspath('d')), False)
1859
 
        self.assertEqual(this.wt.id2path(b'd'), 'd.OTHER')
1860
 
        self.assertEqual(this.wt.id2path(b'f'), 'f.THIS')
 
1801
        self.assertEqual(this.wt.id2path('d'), 'd.OTHER')
 
1802
        self.assertEqual(this.wt.id2path('f'), 'f.THIS')
1861
1803
        self.assertEqual(os.readlink(this.wt.abspath('e')), 'other-e')
1862
1804
        self.assertIs(os.path.lexists(this.wt.abspath('e.THIS')), False)
1863
1805
        self.assertIs(os.path.lexists(this.wt.abspath('e.OTHER')), False)
1874
1816
        base = TransformGroup("BASE", root_id)
1875
1817
        this = TransformGroup("THIS", root_id)
1876
1818
        other = TransformGroup("OTHER", root_id)
1877
 
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, b'a')
1878
 
                                   for t in [base, this, other]]
1879
 
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, b'b')
1880
 
                                   for t in [base, this, other]]
1881
 
        base.tt.new_directory('c', base_a, b'c')
1882
 
        this.tt.new_directory('c1', this_a, b'c')
1883
 
        other.tt.new_directory('c', other_b, b'c')
1884
 
 
1885
 
        base.tt.new_directory('d', base_a, b'd')
1886
 
        this.tt.new_directory('d1', this_b, b'd')
1887
 
        other.tt.new_directory('d', other_a, b'd')
1888
 
 
1889
 
        base.tt.new_directory('e', base_a, b'e')
1890
 
        this.tt.new_directory('e', this_a, b'e')
1891
 
        other.tt.new_directory('e1', other_b, b'e')
1892
 
 
1893
 
        base.tt.new_directory('f', base_a, b'f')
1894
 
        this.tt.new_directory('f1', this_b, b'f')
1895
 
        other.tt.new_directory('f1', other_b, b'f')
 
1819
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, 'a')
 
1820
                                   for t in [base, this, other]]
 
1821
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, 'b')
 
1822
                                   for t in [base, this, other]]
 
1823
        base.tt.new_directory('c', base_a, 'c')
 
1824
        this.tt.new_directory('c1', this_a, 'c')
 
1825
        other.tt.new_directory('c', other_b, 'c')
 
1826
 
 
1827
        base.tt.new_directory('d', base_a, 'd')
 
1828
        this.tt.new_directory('d1', this_b, 'd')
 
1829
        other.tt.new_directory('d', other_a, 'd')
 
1830
 
 
1831
        base.tt.new_directory('e', base_a, 'e')
 
1832
        this.tt.new_directory('e', this_a, 'e')
 
1833
        other.tt.new_directory('e1', other_b, 'e')
 
1834
 
 
1835
        base.tt.new_directory('f', base_a, 'f')
 
1836
        this.tt.new_directory('f1', this_b, 'f')
 
1837
        other.tt.new_directory('f1', other_b, 'f')
1896
1838
 
1897
1839
        for tg in [this, base, other]:
1898
1840
            tg.tt.apply()
1899
1841
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
1900
 
        self.assertEqual(this.wt.id2path(b'c'), pathjoin('b/c1'))
1901
 
        self.assertEqual(this.wt.id2path(b'd'), pathjoin('b/d1'))
1902
 
        self.assertEqual(this.wt.id2path(b'e'), pathjoin('b/e1'))
1903
 
        self.assertEqual(this.wt.id2path(b'f'), pathjoin('b/f1'))
 
1842
        self.assertEqual(this.wt.id2path('c'), pathjoin('b/c1'))
 
1843
        self.assertEqual(this.wt.id2path('d'), pathjoin('b/d1'))
 
1844
        self.assertEqual(this.wt.id2path('e'), pathjoin('b/e1'))
 
1845
        self.assertEqual(this.wt.id2path('f'), pathjoin('b/f1'))
1904
1846
 
1905
1847
    def test_filename_merge_conflicts(self):
1906
1848
        root_id = generate_ids.gen_root_id()
1907
1849
        base = TransformGroup("BASE", root_id)
1908
1850
        this = TransformGroup("THIS", root_id)
1909
1851
        other = TransformGroup("OTHER", root_id)
1910
 
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, b'a')
1911
 
                                   for t in [base, this, other]]
1912
 
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, b'b')
1913
 
                                   for t in [base, this, other]]
1914
 
 
1915
 
        base.tt.new_file('g', base_a, [b'g'], b'g')
1916
 
        other.tt.new_file('g1', other_b, [b'g1'], b'g')
1917
 
 
1918
 
        base.tt.new_file('h', base_a, [b'h'], b'h')
1919
 
        this.tt.new_file('h1', this_b, [b'h1'], b'h')
1920
 
 
1921
 
        base.tt.new_file('i', base.root, [b'i'], b'i')
1922
 
        other.tt.new_directory('i1', this_b, b'i')
 
1852
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, 'a')
 
1853
                                   for t in [base, this, other]]
 
1854
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, 'b')
 
1855
                                   for t in [base, this, other]]
 
1856
 
 
1857
        base.tt.new_file('g', base_a, 'g', 'g')
 
1858
        other.tt.new_file('g1', other_b, 'g1', 'g')
 
1859
 
 
1860
        base.tt.new_file('h', base_a, 'h', 'h')
 
1861
        this.tt.new_file('h1', this_b, 'h1', 'h')
 
1862
 
 
1863
        base.tt.new_file('i', base.root, 'i', 'i')
 
1864
        other.tt.new_directory('i1', this_b, 'i')
1923
1865
 
1924
1866
        for tg in [this, base, other]:
1925
1867
            tg.tt.apply()
1926
1868
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
1927
1869
 
1928
 
        self.assertEqual(this.wt.id2path(b'g'), pathjoin('b/g1.OTHER'))
 
1870
        self.assertEqual(this.wt.id2path('g'), pathjoin('b/g1.OTHER'))
1929
1871
        self.assertIs(os.path.lexists(this.wt.abspath('b/g1.BASE')), True)
1930
1872
        self.assertIs(os.path.lexists(this.wt.abspath('b/g1.THIS')), False)
1931
 
        self.assertEqual(this.wt.id2path(b'h'), pathjoin('b/h1.THIS'))
 
1873
        self.assertEqual(this.wt.id2path('h'), pathjoin('b/h1.THIS'))
1932
1874
        self.assertIs(os.path.lexists(this.wt.abspath('b/h1.BASE')), True)
1933
1875
        self.assertIs(os.path.lexists(this.wt.abspath('b/h1.OTHER')), False)
1934
 
        self.assertEqual(this.wt.id2path(b'i'), pathjoin('b/i1.OTHER'))
 
1876
        self.assertEqual(this.wt.id2path('i'), pathjoin('b/i1.OTHER'))
1935
1877
 
1936
1878
 
1937
1879
class TestBuildTree(tests.TestCaseWithTransport):
1941
1883
        os.mkdir('a')
1942
1884
        a = ControlDir.create_standalone_workingtree('a')
1943
1885
        os.mkdir('a/foo')
1944
 
        with open('a/foo/bar', 'wb') as f:
1945
 
            f.write(b'contents')
 
1886
        with file('a/foo/bar', 'wb') as f: f.write('contents')
1946
1887
        os.symlink('a/foo/bar', 'a/foo/baz')
1947
1888
        a.add(['foo', 'foo/bar', 'foo/baz'])
1948
1889
        a.commit('initial commit')
1952
1893
        self.addCleanup(basis.unlock)
1953
1894
        build_tree(basis, b)
1954
1895
        self.assertIs(os.path.isdir('b/foo'), True)
1955
 
        with open('b/foo/bar', 'rb') as f:
1956
 
            self.assertEqual(f.read(), b"contents")
 
1896
        self.assertEqual(file('b/foo/bar', 'rb').read(), "contents")
1957
1897
        self.assertEqual(os.readlink('b/foo/baz'), 'a/foo/bar')
1958
1898
 
1959
1899
    def test_build_with_references(self):
1960
1900
        tree = self.make_branch_and_tree('source',
1961
 
                                         format='development-subtree')
 
1901
            format='development-subtree')
1962
1902
        subtree = self.make_branch_and_tree('source/subtree',
1963
 
                                            format='development-subtree')
 
1903
            format='development-subtree')
1964
1904
        tree.add_reference(subtree)
1965
1905
        tree.commit('a revision')
1966
1906
        tree.branch.create_checkout('target')
1972
1912
        source = self.make_branch_and_tree('source')
1973
1913
        target = self.make_branch_and_tree('target')
1974
1914
        self.build_tree(['source/file', 'target/file'])
1975
 
        source.add('file', b'new-file')
 
1915
        source.add('file', 'new-file')
1976
1916
        source.commit('added file')
1977
1917
        build_tree(source.basis_tree(), target)
1978
 
        self.assertEqual(
1979
 
            [DuplicateEntry('Moved existing file to', 'file.moved',
1980
 
                            'file', None, 'new-file')],
1981
 
            target.conflicts())
 
1918
        self.assertEqual([DuplicateEntry('Moved existing file to',
 
1919
                          'file.moved', 'file', None, 'new-file')],
 
1920
                         target.conflicts())
1982
1921
        target2 = self.make_branch_and_tree('target2')
1983
 
        with open('target2/file', 'wb') as target_file, \
1984
 
                open('source/file', 'rb') as source_file:
1985
 
            target_file.write(source_file.read())
 
1922
        target_file = file('target2/file', 'wb')
 
1923
        try:
 
1924
            source_file = file('source/file', 'rb')
 
1925
            try:
 
1926
                target_file.write(source_file.read())
 
1927
            finally:
 
1928
                source_file.close()
 
1929
        finally:
 
1930
            target_file.close()
1986
1931
        build_tree(source.basis_tree(), target2)
1987
1932
        self.assertEqual([], target2.conflicts())
1988
1933
 
1991
1936
        self.requireFeature(SymlinkFeature)
1992
1937
        source = self.make_branch_and_tree('source')
1993
1938
        os.symlink('foo', 'source/symlink')
1994
 
        source.add('symlink', b'new-symlink')
 
1939
        source.add('symlink', 'new-symlink')
1995
1940
        source.commit('added file')
1996
1941
        target = self.make_branch_and_tree('target')
1997
1942
        os.symlink('bar', 'target/symlink')
1998
1943
        build_tree(source.basis_tree(), target)
1999
 
        self.assertEqual(
2000
 
            [DuplicateEntry('Moved existing file to', 'symlink.moved',
2001
 
                            'symlink', None, 'new-symlink')],
 
1944
        self.assertEqual([DuplicateEntry('Moved existing file to',
 
1945
            'symlink.moved', 'symlink', None, 'new-symlink')],
2002
1946
            target.conflicts())
2003
1947
        target = self.make_branch_and_tree('target2')
2004
1948
        os.symlink('foo', 'target2/symlink')
2010
1954
        source = self.make_branch_and_tree('source')
2011
1955
        target = self.make_branch_and_tree('target')
2012
1956
        self.build_tree(['source/dir1/', 'source/dir1/file', 'target/dir1/'])
2013
 
        source.add(['dir1', 'dir1/file'], [b'new-dir1', b'new-file'])
 
1957
        source.add(['dir1', 'dir1/file'], ['new-dir1', 'new-file'])
2014
1958
        source.commit('added file')
2015
1959
        build_tree(source.basis_tree(), target)
2016
1960
        self.assertEqual([], target.conflicts())
2032
1976
        self.assertPathDoesNotExist('target3/dir1/file')
2033
1977
        self.assertPathExists('target3/dir1/file2')
2034
1978
        self.assertPathExists('target3/dir1.diverted/file')
2035
 
        self.assertEqual(
2036
 
            [DuplicateEntry('Diverted to', 'dir1.diverted',
2037
 
                            'dir1', 'new-dir1', None)],
 
1979
        self.assertEqual([DuplicateEntry('Diverted to',
 
1980
            'dir1.diverted', 'dir1', 'new-dir1', None)],
2038
1981
            target.conflicts())
2039
1982
 
2040
1983
        target = self.make_branch_and_tree('target4')
2044
1987
        self.assertPathExists('target4/dir1/file')
2045
1988
        self.assertEqual('directory', file_kind('target4/dir1/file'))
2046
1989
        self.assertPathExists('target4/dir1/file.diverted')
2047
 
        self.assertEqual(
2048
 
            [DuplicateEntry('Diverted to', 'dir1/file.diverted',
2049
 
                            'dir1/file', 'new-file', None)],
 
1990
        self.assertEqual([DuplicateEntry('Diverted to',
 
1991
            'dir1/file.diverted', 'dir1/file', 'new-file', None)],
2050
1992
            target.conflicts())
2051
1993
 
2052
1994
    def test_mixed_conflict_handling(self):
2054
1996
        source = self.make_branch_and_tree('source')
2055
1997
        target = self.make_branch_and_tree('target')
2056
1998
        self.build_tree(['source/name', 'target/name/'])
2057
 
        source.add('name', b'new-name')
 
1999
        source.add('name', 'new-name')
2058
2000
        source.commit('added file')
2059
2001
        build_tree(source.basis_tree(), target)
2060
 
        self.assertEqual(
2061
 
            [DuplicateEntry('Moved existing file to',
2062
 
                            'name.moved', 'name', None, 'new-name')],
2063
 
            target.conflicts())
 
2002
        self.assertEqual([DuplicateEntry('Moved existing file to',
 
2003
            'name.moved', 'name', None, 'new-name')], target.conflicts())
2064
2004
 
2065
2005
    def test_raises_in_populated(self):
2066
2006
        source = self.make_branch_and_tree('source')
2071
2011
        self.build_tree(['target/name'])
2072
2012
        target.add('name')
2073
2013
        self.assertRaises(errors.WorkingTreeAlreadyPopulated,
2074
 
                          build_tree, source.basis_tree(), target)
 
2014
            build_tree, source.basis_tree(), target)
2075
2015
 
2076
2016
    def test_build_tree_rename_count(self):
2077
2017
        source = self.make_branch_and_tree('source')
2093
2033
    def create_ab_tree(self):
2094
2034
        """Create a committed test tree with two files"""
2095
2035
        source = self.make_branch_and_tree('source')
2096
 
        self.build_tree_contents([('source/file1', b'A')])
2097
 
        self.build_tree_contents([('source/file2', b'B')])
2098
 
        source.add(['file1', 'file2'], [b'file1-id', b'file2-id'])
 
2036
        self.build_tree_contents([('source/file1', 'A')])
 
2037
        self.build_tree_contents([('source/file2', 'B')])
 
2038
        source.add(['file1', 'file2'], ['file1-id', 'file2-id'])
2099
2039
        source.commit('commit files')
2100
2040
        source.lock_write()
2101
2041
        self.addCleanup(source.unlock)
2103
2043
 
2104
2044
    def test_build_tree_accelerator_tree(self):
2105
2045
        source = self.create_ab_tree()
2106
 
        self.build_tree_contents([('source/file2', b'C')])
 
2046
        self.build_tree_contents([('source/file2', 'C')])
2107
2047
        calls = []
2108
2048
        real_source_get_file = source.get_file
2109
 
 
2110
 
        def get_file(path):
2111
 
            calls.append(path)
2112
 
            return real_source_get_file(path)
 
2049
        def get_file(file_id, path=None):
 
2050
            calls.append(file_id)
 
2051
            return real_source_get_file(file_id, path)
2113
2052
        source.get_file = get_file
2114
2053
        target = self.make_branch_and_tree('target')
2115
2054
        revision_tree = source.basis_tree()
2116
2055
        revision_tree.lock_read()
2117
2056
        self.addCleanup(revision_tree.unlock)
2118
2057
        build_tree(revision_tree, target, source)
2119
 
        self.assertEqual(['file1'], calls)
 
2058
        self.assertEqual(['file1-id'], calls)
2120
2059
        target.lock_read()
2121
2060
        self.addCleanup(target.unlock)
2122
2061
        self.assertEqual([], list(target.iter_changes(revision_tree)))
2123
2062
 
2124
2063
    def test_build_tree_accelerator_tree_observes_sha1(self):
2125
2064
        source = self.create_ab_tree()
2126
 
        sha1 = osutils.sha_string(b'A')
 
2065
        sha1 = osutils.sha_string('A')
2127
2066
        target = self.make_branch_and_tree('target')
2128
2067
        target.lock_write()
2129
2068
        self.addCleanup(target.unlock)
2130
2069
        state = target.current_dirstate()
2131
2070
        state._cutoff_time = time.time() + 60
2132
2071
        build_tree(source.basis_tree(), target, source)
2133
 
        entry = state._get_entry(0, path_utf8=b'file1')
 
2072
        entry = state._get_entry(0, path_utf8='file1')
2134
2073
        self.assertEqual(sha1, entry[1][0][1])
2135
2074
 
2136
2075
    def test_build_tree_accelerator_tree_missing_file(self):
2149
2088
    def test_build_tree_accelerator_wrong_kind(self):
2150
2089
        self.requireFeature(SymlinkFeature)
2151
2090
        source = self.make_branch_and_tree('source')
2152
 
        self.build_tree_contents([('source/file1', b'')])
2153
 
        self.build_tree_contents([('source/file2', b'')])
2154
 
        source.add(['file1', 'file2'], [b'file1-id', b'file2-id'])
 
2091
        self.build_tree_contents([('source/file1', '')])
 
2092
        self.build_tree_contents([('source/file2', '')])
 
2093
        source.add(['file1', 'file2'], ['file1-id', 'file2-id'])
2155
2094
        source.commit('commit files')
2156
2095
        os.unlink('source/file2')
2157
 
        self.build_tree_contents([('source/file2/', b'C')])
 
2096
        self.build_tree_contents([('source/file2/', 'C')])
2158
2097
        os.unlink('source/file1')
2159
2098
        os.symlink('file2', 'source/file1')
2160
2099
        calls = []
2161
2100
        real_source_get_file = source.get_file
2162
 
 
2163
 
        def get_file(path):
2164
 
            calls.append(path)
2165
 
            return real_source_get_file(path)
 
2101
        def get_file(file_id, path=None):
 
2102
            calls.append(file_id)
 
2103
            return real_source_get_file(file_id, path)
2166
2104
        source.get_file = get_file
2167
2105
        target = self.make_branch_and_tree('target')
2168
2106
        revision_tree = source.basis_tree()
2201
2139
 
2202
2140
    def test_build_tree_accelerator_tree_moved(self):
2203
2141
        source = self.make_branch_and_tree('source')
2204
 
        self.build_tree_contents([('source/file1', b'A')])
2205
 
        source.add(['file1'], [b'file1-id'])
 
2142
        self.build_tree_contents([('source/file1', 'A')])
 
2143
        source.add(['file1'], ['file1-id'])
2206
2144
        source.commit('commit files')
2207
2145
        source.rename_one('file1', 'file2')
2208
2146
        source.lock_read()
2220
2158
        self.requireFeature(HardlinkFeature)
2221
2159
        source = self.create_ab_tree()
2222
2160
        tt = TreeTransform(source)
2223
 
        trans_id = tt.trans_id_tree_path('file1')
 
2161
        trans_id = tt.trans_id_tree_file_id('file1-id')
2224
2162
        tt.set_executability(True, trans_id)
2225
2163
        tt.apply()
2226
 
        self.assertTrue(source.is_executable('file1'))
 
2164
        self.assertTrue(source.is_executable('file1-id'))
2227
2165
        target = self.make_branch_and_tree('target')
2228
2166
        revision_tree = source.basis_tree()
2229
2167
        revision_tree.lock_read()
2232
2170
        target.lock_read()
2233
2171
        self.addCleanup(target.unlock)
2234
2172
        self.assertEqual([], list(target.iter_changes(revision_tree)))
2235
 
        self.assertTrue(source.is_executable('file1'))
 
2173
        self.assertTrue(source.is_executable('file1-id'))
2236
2174
 
2237
2175
    def install_rot13_content_filter(self, pattern):
2238
2176
        # We could use
2240
2178
        # below, but that looks a bit... hard to read even if it's exactly
2241
2179
        # the same thing.
2242
2180
        original_registry = filters._reset_registry()
2243
 
 
2244
2181
        def restore_registry():
2245
2182
            filters._reset_registry(original_registry)
2246
2183
        self.addCleanup(restore_registry)
2247
 
 
2248
2184
        def rot13(chunks, context=None):
2249
 
            return [
2250
 
                codecs.encode(chunk.decode('ascii'), 'rot13').encode('ascii')
2251
 
                for chunk in chunks]
 
2185
            return [''.join(chunks).encode('rot13')]
2252
2186
        rot13filter = filters.ContentFilter(rot13, rot13)
2253
2187
        filters.filter_stacks_registry.register(
2254
2188
            'rot13', {'yes': [rot13filter]}.get)
2255
2189
        os.mkdir(self.test_home_dir + '/.bazaar')
2256
2190
        rules_filename = self.test_home_dir + '/.bazaar/rules'
2257
 
        with open(rules_filename, 'wb') as f:
2258
 
            f.write(b'[name %s]\nrot13=yes\n' % (pattern,))
2259
 
 
 
2191
        f = open(rules_filename, 'wb')
 
2192
        f.write('[name %s]\nrot13=yes\n' % (pattern,))
 
2193
        f.close()
2260
2194
        def uninstall_rules():
2261
2195
            os.remove(rules_filename)
2262
2196
            rules.reset_rules()
2269
2203
        if it can).
2270
2204
        """
2271
2205
        self.requireFeature(HardlinkFeature)
2272
 
        self.install_rot13_content_filter(b'file1')
 
2206
        self.install_rot13_content_filter('file1')
2273
2207
        source = self.create_ab_tree()
2274
2208
        target = self.make_branch_and_tree('target')
2275
2209
        revision_tree = source.basis_tree()
2288
2222
 
2289
2223
    def test_case_insensitive_build_tree_inventory(self):
2290
2224
        if (features.CaseInsensitiveFilesystemFeature.available()
2291
 
                or features.CaseInsCasePresFilenameFeature.available()):
 
2225
            or features.CaseInsCasePresFilenameFeature.available()):
2292
2226
            raise tests.UnavailableFeature('Fully case sensitive filesystem')
2293
2227
        source = self.make_branch_and_tree('source')
2294
2228
        self.build_tree(['source/file', 'source/FILE'])
2295
 
        source.add(['file', 'FILE'], [b'lower-id', b'upper-id'])
 
2229
        source.add(['file', 'FILE'], ['lower-id', 'upper-id'])
2296
2230
        source.commit('added files')
2297
2231
        # Don't try this at home, kids!
2298
2232
        # Force the tree to report that it is case insensitive
2299
2233
        target = self.make_branch_and_tree('target')
2300
2234
        target.case_sensitive = False
2301
2235
        build_tree(source.basis_tree(), target, source, delta_from_tree=True)
2302
 
        self.assertEqual('file.moved', target.id2path(b'lower-id'))
2303
 
        self.assertEqual('FILE', target.id2path(b'upper-id'))
 
2236
        self.assertEqual('file.moved', target.id2path('lower-id'))
 
2237
        self.assertEqual('FILE', target.id2path('upper-id'))
2304
2238
 
2305
2239
    def test_build_tree_observes_sha(self):
2306
2240
        source = self.make_branch_and_tree('source')
2307
2241
        self.build_tree(['source/file1', 'source/dir/', 'source/dir/file2'])
2308
2242
        source.add(['file1', 'dir', 'dir/file2'],
2309
 
                   [b'file1-id', b'dir-id', b'file2-id'])
 
2243
                   ['file1-id', 'dir-id', 'file2-id'])
2310
2244
        source.commit('new files')
2311
2245
        target = self.make_branch_and_tree('target')
2312
2246
        target.lock_write()
2321
2255
        # entry[1] is the state information, entry[1][0] is the state of the
2322
2256
        # working tree, entry[1][0][1] is the sha value for the current working
2323
2257
        # tree
2324
 
        entry1 = state._get_entry(0, path_utf8=b'file1')
 
2258
        entry1 = state._get_entry(0, path_utf8='file1')
2325
2259
        self.assertEqual(entry1_sha, entry1[1][0][1])
2326
2260
        # The 'size' field must also be set.
2327
2261
        self.assertEqual(25, entry1[1][0][2])
2328
2262
        entry1_state = entry1[1][0]
2329
 
        entry2 = state._get_entry(0, path_utf8=b'dir/file2')
 
2263
        entry2 = state._get_entry(0, path_utf8='dir/file2')
2330
2264
        self.assertEqual(entry2_sha, entry2[1][0][1])
2331
2265
        self.assertEqual(29, entry2[1][0][2])
2332
2266
        entry2_state = entry2[1][0]
2333
2267
        # Now, make sure that we don't have to re-read the content. The
2334
2268
        # packed_stat should match exactly.
2335
 
        self.assertEqual(entry1_sha, target.get_file_sha1('file1'))
2336
 
        self.assertEqual(entry2_sha, target.get_file_sha1('dir/file2'))
 
2269
        self.assertEqual(entry1_sha, target.get_file_sha1('file1-id', 'file1'))
 
2270
        self.assertEqual(entry2_sha,
 
2271
                         target.get_file_sha1('file2-id', 'dir/file2'))
2337
2272
        self.assertEqual(entry1_state, entry1[1][0])
2338
2273
        self.assertEqual(entry2_state, entry2[1][0])
2339
2274
 
2372
2307
 
2373
2308
    def test_merge_parents(self):
2374
2309
        branch, tt = self.get_branch_and_transform()
2375
 
        tt.commit(branch, 'my message', [b'rev1b', b'rev1c'])
2376
 
        self.assertEqual([b'rev1b', b'rev1c'],
 
2310
        rev = tt.commit(branch, 'my message', ['rev1b', 'rev1c'])
 
2311
        self.assertEqual(['rev1b', 'rev1c'],
2377
2312
                         branch.basis_tree().get_parent_ids()[1:])
2378
2313
 
2379
2314
    def test_first_commit(self):
2382
2317
        self.addCleanup(branch.unlock)
2383
2318
        tt = TransformPreview(branch.basis_tree())
2384
2319
        self.addCleanup(tt.finalize)
2385
 
        tt.new_directory('', ROOT_PARENT, b'TREE_ROOT')
2386
 
        tt.commit(branch, 'my message')
 
2320
        tt.new_directory('', ROOT_PARENT, 'TREE_ROOT')
 
2321
        rev = tt.commit(branch, 'my message')
2387
2322
        self.assertEqual([], branch.basis_tree().get_parent_ids())
2388
2323
        self.assertNotEqual(_mod_revision.NULL_REVISION,
2389
2324
                            branch.last_revision())
2395
2330
        tt = TransformPreview(branch.basis_tree())
2396
2331
        self.addCleanup(tt.finalize)
2397
2332
        e = self.assertRaises(ValueError, tt.commit, branch,
2398
 
                              'my message', [b'rev1b-id'])
 
2333
                          'my message', ['rev1b-id'])
2399
2334
        self.assertEqual('Cannot supply merge parents for first commit.',
2400
2335
                         str(e))
2401
2336
        self.assertEqual(_mod_revision.NULL_REVISION, branch.last_revision())
2402
2337
 
2403
2338
    def test_add_files(self):
2404
2339
        branch, tt = self.get_branch_and_transform()
2405
 
        tt.new_file('file', tt.root, [b'contents'], b'file-id')
2406
 
        trans_id = tt.new_directory('dir', tt.root, b'dir-id')
 
2340
        tt.new_file('file', tt.root, 'contents', 'file-id')
 
2341
        trans_id = tt.new_directory('dir', tt.root, 'dir-id')
2407
2342
        if SymlinkFeature.available():
2408
 
            tt.new_symlink('symlink', trans_id, 'target', b'symlink-id')
2409
 
        tt.commit(branch, 'message')
 
2343
            tt.new_symlink('symlink', trans_id, 'target', 'symlink-id')
 
2344
        rev = tt.commit(branch, 'message')
2410
2345
        tree = branch.basis_tree()
2411
 
        self.assertEqual('file', tree.id2path(b'file-id'))
2412
 
        self.assertEqual(b'contents', tree.get_file_text('file'))
2413
 
        self.assertEqual('dir', tree.id2path(b'dir-id'))
 
2346
        self.assertEqual('file', tree.id2path('file-id'))
 
2347
        self.assertEqual('contents', tree.get_file_text('file-id'))
 
2348
        self.assertEqual('dir', tree.id2path('dir-id'))
2414
2349
        if SymlinkFeature.available():
2415
 
            self.assertEqual('dir/symlink', tree.id2path(b'symlink-id'))
2416
 
            self.assertEqual('target', tree.get_symlink_target('dir/symlink'))
 
2350
            self.assertEqual('dir/symlink', tree.id2path('symlink-id'))
 
2351
            self.assertEqual('target', tree.get_symlink_target('symlink-id'))
2417
2352
 
2418
2353
    def test_add_unversioned(self):
2419
2354
        branch, tt = self.get_branch_and_transform()
2420
 
        tt.new_file('file', tt.root, [b'contents'])
 
2355
        tt.new_file('file', tt.root, 'contents')
2421
2356
        self.assertRaises(errors.StrictCommitFailed, tt.commit, branch,
2422
2357
                          'message', strict=True)
2423
2358
 
2424
2359
    def test_modify_strict(self):
2425
2360
        branch, tt = self.get_branch_and_transform()
2426
 
        tt.new_file('file', tt.root, [b'contents'], b'file-id')
 
2361
        tt.new_file('file', tt.root, 'contents', 'file-id')
2427
2362
        tt.commit(branch, 'message', strict=True)
2428
2363
        tt = TransformPreview(branch.basis_tree())
2429
2364
        self.addCleanup(tt.finalize)
2430
 
        trans_id = tt.trans_id_file_id(b'file-id')
 
2365
        trans_id = tt.trans_id_file_id('file-id')
2431
2366
        tt.delete_contents(trans_id)
2432
 
        tt.create_file([b'contents'], trans_id)
 
2367
        tt.create_file('contents', trans_id)
2433
2368
        tt.commit(branch, 'message', strict=True)
2434
2369
 
2435
2370
    def test_commit_malformed(self):
2438
2373
        In this case, we are adding a file without adding its parent.
2439
2374
        """
2440
2375
        branch, tt = self.get_branch_and_transform()
2441
 
        parent_id = tt.trans_id_file_id(b'parent-id')
2442
 
        tt.new_file('file', parent_id, [b'contents'], b'file-id')
 
2376
        parent_id = tt.trans_id_file_id('parent-id')
 
2377
        tt.new_file('file', parent_id, 'contents', 'file-id')
2443
2378
        self.assertRaises(errors.MalformedTransform, tt.commit, branch,
2444
2379
                          'message')
2445
2380
 
2447
2382
        branch, tt = self.get_branch_and_transform()
2448
2383
        rev_id = tt.commit(branch, 'message', timestamp=1, timezone=43201,
2449
2384
                           committer='me <me@example.com>',
2450
 
                           revprops={u'foo': 'bar'}, revision_id=b'revid-1',
 
2385
                           revprops={'foo': 'bar'}, revision_id='revid-1',
2451
2386
                           authors=['Author1 <author1@example.com>',
2452
 
                                    'Author2 <author2@example.com>',
2453
 
                                    ])
2454
 
        self.assertEqual(b'revid-1', rev_id)
 
2387
                              'Author2 <author2@example.com>',
 
2388
                               ])
 
2389
        self.assertEqual('revid-1', rev_id)
2455
2390
        revision = branch.repository.get_revision(rev_id)
2456
2391
        self.assertEqual(1, revision.timestamp)
2457
2392
        self.assertEqual(43201, revision.timezone)
2520
2455
        mover.rename('c/e', 'c/d')
2521
2456
        try:
2522
2457
            mover.rename('a', 'c')
2523
 
        except errors.FileExists:
 
2458
        except errors.FileExists, e:
2524
2459
            mover.rollback()
2525
2460
        self.assertPathExists('a')
2526
2461
        self.assertPathExists('c/d')
2541
2476
 
2542
2477
        def rename(self, source, target):
2543
2478
            if (self.bad_source is not None and
2544
 
                    source.endswith(self.bad_source)):
 
2479
                source.endswith(self.bad_source)):
2545
2480
                raise Bogus
2546
2481
            elif (self.bad_target is not None and
2547
 
                  target.endswith(self.bad_target)):
 
2482
                target.endswith(self.bad_target)):
2548
2483
                raise Bogus
2549
2484
            else:
2550
2485
                _FileMover.rename(self, source, target)
2601
2536
    def _override_globals_in_method(self, instance, method_name, globals):
2602
2537
        """Replace method on instance with one with updated globals"""
2603
2538
        import types
2604
 
        func = getattr(instance, method_name).__func__
2605
 
        new_globals = dict(func.__globals__)
 
2539
        func = getattr(instance, method_name).im_func
 
2540
        new_globals = dict(func.func_globals)
2606
2541
        new_globals.update(globals)
2607
 
        new_func = types.FunctionType(func.__code__, new_globals,
2608
 
                                      func.__name__, func.__defaults__)
 
2542
        new_func = types.FunctionType(func.func_code, new_globals,
 
2543
            func.func_name, func.func_defaults)
2609
2544
        setattr(instance, method_name,
2610
 
                types.MethodType(new_func, instance))
 
2545
            types.MethodType(new_func, instance, instance.__class__))
2611
2546
        self.addCleanup(delattr, instance, method_name)
2612
2547
 
2613
2548
    @staticmethod
2639
2574
 
2640
2575
    def test_root_create_file_open_raises_before_creation(self):
2641
2576
        tt, trans_id = self.create_transform_and_root_trans_id()
2642
 
        self._override_globals_in_method(
2643
 
            tt, "create_file", {"open": self._fake_open_raises_before})
2644
 
        self.assertRaises(RuntimeError, tt.create_file,
2645
 
                          [b"contents"], trans_id)
 
2577
        self._override_globals_in_method(tt, "create_file",
 
2578
            {"open": self._fake_open_raises_before})
 
2579
        self.assertRaises(RuntimeError, tt.create_file, ["contents"], trans_id)
2646
2580
        path = tt._limbo_name(trans_id)
2647
2581
        self.assertPathDoesNotExist(path)
2648
2582
        tt.finalize()
2650
2584
 
2651
2585
    def test_root_create_file_open_raises_after_creation(self):
2652
2586
        tt, trans_id = self.create_transform_and_root_trans_id()
2653
 
        self._override_globals_in_method(
2654
 
            tt, "create_file", {"open": self._fake_open_raises_after})
2655
 
        self.assertRaises(RuntimeError, tt.create_file,
2656
 
                          [b"contents"], trans_id)
 
2587
        self._override_globals_in_method(tt, "create_file",
 
2588
            {"open": self._fake_open_raises_after})
 
2589
        self.assertRaises(RuntimeError, tt.create_file, ["contents"], trans_id)
2657
2590
        path = tt._limbo_name(trans_id)
2658
2591
        self.assertPathExists(path)
2659
2592
        tt.finalize()
2662
2595
 
2663
2596
    def test_subdir_create_file_open_raises_before_creation(self):
2664
2597
        tt, trans_id = self.create_transform_and_subdir_trans_id()
2665
 
        self._override_globals_in_method(
2666
 
            tt, "create_file", {"open": self._fake_open_raises_before})
2667
 
        self.assertRaises(RuntimeError, tt.create_file,
2668
 
                          [b"contents"], trans_id)
 
2598
        self._override_globals_in_method(tt, "create_file",
 
2599
            {"open": self._fake_open_raises_before})
 
2600
        self.assertRaises(RuntimeError, tt.create_file, ["contents"], trans_id)
2669
2601
        path = tt._limbo_name(trans_id)
2670
2602
        self.assertPathDoesNotExist(path)
2671
2603
        tt.finalize()
2673
2605
 
2674
2606
    def test_subdir_create_file_open_raises_after_creation(self):
2675
2607
        tt, trans_id = self.create_transform_and_subdir_trans_id()
2676
 
        self._override_globals_in_method(
2677
 
            tt, "create_file", {"open": self._fake_open_raises_after})
2678
 
        self.assertRaises(RuntimeError, tt.create_file,
2679
 
                          [b"contents"], trans_id)
 
2608
        self._override_globals_in_method(tt, "create_file",
 
2609
            {"open": self._fake_open_raises_after})
 
2610
        self.assertRaises(RuntimeError, tt.create_file, ["contents"], trans_id)
2680
2611
        path = tt._limbo_name(trans_id)
2681
2612
        self.assertPathExists(path)
2682
2613
        tt.finalize()
2686
2617
    def test_rename_in_limbo_rename_raises_after_rename(self):
2687
2618
        tt, trans_id = self.create_transform_and_root_trans_id()
2688
2619
        parent1 = tt.new_directory('parent1', tt.root)
2689
 
        child1 = tt.new_file('child1', parent1, [b'contents'])
 
2620
        child1 = tt.new_file('child1', parent1, 'contents')
2690
2621
        parent2 = tt.new_directory('parent2', tt.root)
2691
2622
 
2692
2623
        class FakeOSModule(object):
2694
2625
                os.rename(old, new)
2695
2626
                raise RuntimeError
2696
2627
        self._override_globals_in_method(tt, "_rename_in_limbo",
2697
 
                                         {"os": FakeOSModule()})
 
2628
            {"os": FakeOSModule()})
2698
2629
        self.assertRaises(
2699
2630
            RuntimeError, tt.adjust_path, "child1", parent2, child1)
2700
2631
        path = osutils.pathjoin(tt._limbo_name(parent2), "child1")
2706
2637
    def test_rename_in_limbo_rename_raises_before_rename(self):
2707
2638
        tt, trans_id = self.create_transform_and_root_trans_id()
2708
2639
        parent1 = tt.new_directory('parent1', tt.root)
2709
 
        child1 = tt.new_file('child1', parent1, [b'contents'])
 
2640
        child1 = tt.new_file('child1', parent1, 'contents')
2710
2641
        parent2 = tt.new_directory('parent2', tt.root)
2711
2642
 
2712
2643
        class FakeOSModule(object):
2713
2644
            def rename(self, old, new):
2714
2645
                raise RuntimeError
2715
2646
        self._override_globals_in_method(tt, "_rename_in_limbo",
2716
 
                                         {"os": FakeOSModule()})
 
2647
            {"os": FakeOSModule()})
2717
2648
        self.assertRaises(
2718
2649
            RuntimeError, tt.adjust_path, "child1", parent2, child1)
2719
2650
        path = osutils.pathjoin(tt._limbo_name(parent1), "child1")
2727
2658
 
2728
2659
    def make_tt_with_versioned_dir(self):
2729
2660
        wt = self.make_branch_and_tree('.')
2730
 
        self.build_tree(['dir/', ])
2731
 
        wt.add(['dir'], [b'dir-id'])
 
2661
        self.build_tree(['dir/',])
 
2662
        wt.add(['dir'], ['dir-id'])
2732
2663
        wt.commit('Create dir')
2733
2664
        tt = TreeTransform(wt)
2734
2665
        self.addCleanup(tt.finalize)
2736
2667
 
2737
2668
    def test_resolve_create_parent_for_versioned_file(self):
2738
2669
        wt, tt = self.make_tt_with_versioned_dir()
2739
 
        dir_tid = tt.trans_id_tree_path('dir')
2740
 
        tt.new_file('file', dir_tid, [b'Contents'], file_id=b'file-id')
 
2670
        dir_tid = tt.trans_id_tree_file_id('dir-id')
 
2671
        file_tid = tt.new_file('file', dir_tid, 'Contents', file_id='file-id')
2741
2672
        tt.delete_contents(dir_tid)
2742
2673
        tt.unversion_file(dir_tid)
2743
2674
        conflicts = resolve_conflicts(tt)
2747
2678
 
2748
2679
    def test_non_versioned_file_create_conflict(self):
2749
2680
        wt, tt = self.make_tt_with_versioned_dir()
2750
 
        dir_tid = tt.trans_id_tree_path('dir')
2751
 
        tt.new_file('file', dir_tid, [b'Contents'])
 
2681
        dir_tid = tt.trans_id_tree_file_id('dir-id')
 
2682
        tt.new_file('file', dir_tid, 'Contents')
2752
2683
        tt.delete_contents(dir_tid)
2753
2684
        tt.unversion_file(dir_tid)
2754
2685
        conflicts = resolve_conflicts(tt)
2758
2689
                         conflicts.pop())
2759
2690
 
2760
2691
 
2761
 
A_ENTRY = (b'a-id', ('a', 'a'), True, (True, True),
2762
 
           (b'TREE_ROOT', b'TREE_ROOT'), ('a', 'a'), ('file', 'file'),
2763
 
           (False, False), False)
2764
 
ROOT_ENTRY = (b'TREE_ROOT', ('', ''), False, (True, True), (None, None),
2765
 
              ('', ''), ('directory', 'directory'), (False, False), False)
 
2692
A_ENTRY = ('a-id', ('a', 'a'), True, (True, True),
 
2693
                  ('TREE_ROOT', 'TREE_ROOT'), ('a', 'a'), ('file', 'file'),
 
2694
                  (False, False))
 
2695
ROOT_ENTRY = ('TREE_ROOT', ('', ''), False, (True, True), (None, None),
 
2696
              ('', ''), ('directory', 'directory'), (False, False))
2766
2697
 
2767
2698
 
2768
2699
class TestTransformPreview(tests.TestCaseWithTransport):
2769
2700
 
2770
2701
    def create_tree(self):
2771
2702
        tree = self.make_branch_and_tree('.')
2772
 
        self.build_tree_contents([('a', b'content 1')])
2773
 
        tree.set_root_id(b'TREE_ROOT')
2774
 
        tree.add('a', b'a-id')
2775
 
        tree.commit('rev1', rev_id=b'rev1')
2776
 
        return tree.branch.repository.revision_tree(b'rev1')
 
2703
        self.build_tree_contents([('a', 'content 1')])
 
2704
        tree.set_root_id('TREE_ROOT')
 
2705
        tree.add('a', 'a-id')
 
2706
        tree.commit('rev1', rev_id='rev1')
 
2707
        return tree.branch.repository.revision_tree('rev1')
2777
2708
 
2778
2709
    def get_empty_preview(self):
2779
2710
        repository = self.make_repository('repo')
2797
2728
        revision_tree = self.create_tree()
2798
2729
        preview = TransformPreview(revision_tree)
2799
2730
        self.addCleanup(preview.finalize)
2800
 
        preview.new_file('file2', preview.root, [b'content B\n'], b'file2-id')
 
2731
        preview.new_file('file2', preview.root, 'content B\n', 'file2-id')
2801
2732
        preview_tree = preview.get_preview_tree()
2802
 
        self.assertEqual(preview_tree.kind('file2'), 'file')
2803
 
        with preview_tree.get_file('file2') as f:
2804
 
            self.assertEqual(f.read(), b'content B\n')
 
2733
        self.assertEqual(preview_tree.kind('file2-id'), 'file')
 
2734
        self.assertEqual(
 
2735
            preview_tree.get_file('file2-id').read(), 'content B\n')
2805
2736
 
2806
2737
    def test_diff_preview_tree(self):
2807
2738
        revision_tree = self.create_tree()
2808
2739
        preview = TransformPreview(revision_tree)
2809
2740
        self.addCleanup(preview.finalize)
2810
 
        preview.new_file('file2', preview.root, [b'content B\n'], b'file2-id')
 
2741
        preview.new_file('file2', preview.root, 'content B\n', 'file2-id')
2811
2742
        preview_tree = preview.get_preview_tree()
2812
 
        out = BytesIO()
 
2743
        out = StringIO()
2813
2744
        show_diff_trees(revision_tree, preview_tree, out)
2814
2745
        lines = out.getvalue().splitlines()
2815
 
        self.assertEqual(lines[0], b"=== added file 'file2'")
 
2746
        self.assertEqual(lines[0], "=== added file 'file2'")
2816
2747
        # 3 lines of diff administrivia
2817
 
        self.assertEqual(lines[4], b"+content B")
2818
 
 
2819
 
    def test_unsupported_symlink_diff(self):
2820
 
        self.requireFeature(SymlinkFeature)
2821
 
        tree = self.make_branch_and_tree('.')
2822
 
        self.build_tree_contents([('a', 'content 1')])
2823
 
        tree.set_root_id(b'TREE_ROOT')
2824
 
        tree.add('a', b'a-id')
2825
 
        os.symlink('a', 'foo')
2826
 
        tree.add('foo', b'foo-id')
2827
 
        tree.commit('rev1', rev_id=b'rev1')
2828
 
        revision_tree = tree.branch.repository.revision_tree(b'rev1')
2829
 
        preview = TransformPreview(revision_tree)
2830
 
        self.addCleanup(preview.finalize)
2831
 
        preview.delete_versioned(preview.trans_id_tree_path('foo'))
2832
 
        preview_tree = preview.get_preview_tree()
2833
 
        out = BytesIO()
2834
 
        log = BytesIO()
2835
 
        trace.push_log_file(log)
2836
 
        os_symlink = getattr(os, 'symlink', None)
2837
 
        os.symlink = None
2838
 
        try:
2839
 
            show_diff_trees(revision_tree, preview_tree, out)
2840
 
            lines = out.getvalue().splitlines()
2841
 
        finally:
2842
 
            os.symlink = os_symlink
2843
 
        self.assertContainsRe(
2844
 
            log.getvalue(),
2845
 
            b'Ignoring "foo" as symlinks are not supported on this filesystem')
 
2748
        self.assertEqual(lines[4], "+content B")
2846
2749
 
2847
2750
    def test_transform_conflicts(self):
2848
2751
        revision_tree = self.create_tree()
2849
2752
        preview = TransformPreview(revision_tree)
2850
2753
        self.addCleanup(preview.finalize)
2851
 
        preview.new_file('a', preview.root, [b'content 2'])
 
2754
        preview.new_file('a', preview.root, 'content 2')
2852
2755
        resolve_conflicts(preview)
2853
 
        trans_id = preview.trans_id_file_id(b'a-id')
 
2756
        trans_id = preview.trans_id_file_id('a-id')
2854
2757
        self.assertEqual('a.moved', preview.final_name(trans_id))
2855
2758
 
2856
2759
    def get_tree_and_preview_tree(self):
2857
2760
        revision_tree = self.create_tree()
2858
2761
        preview = TransformPreview(revision_tree)
2859
2762
        self.addCleanup(preview.finalize)
2860
 
        a_trans_id = preview.trans_id_file_id(b'a-id')
 
2763
        a_trans_id = preview.trans_id_file_id('a-id')
2861
2764
        preview.delete_contents(a_trans_id)
2862
 
        preview.create_file([b'b content'], a_trans_id)
 
2765
        preview.create_file('b content', a_trans_id)
2863
2766
        preview_tree = preview.get_preview_tree()
2864
2767
        return revision_tree, preview_tree
2865
2768
 
2866
2769
    def test_iter_changes(self):
2867
2770
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2868
 
        root = revision_tree.path2id('')
2869
 
        self.assertEqual([(b'a-id', ('a', 'a'), True, (True, True),
2870
 
                           (root, root), ('a', 'a'), ('file', 'file'),
2871
 
                           (False, False), False)],
2872
 
                         list(preview_tree.iter_changes(revision_tree)))
 
2771
        root = revision_tree.get_root_id()
 
2772
        self.assertEqual([('a-id', ('a', 'a'), True, (True, True),
 
2773
                          (root, root), ('a', 'a'), ('file', 'file'),
 
2774
                          (False, False))],
 
2775
                          list(preview_tree.iter_changes(revision_tree)))
2873
2776
 
2874
2777
    def test_include_unchanged_succeeds(self):
2875
2778
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2876
2779
        changes = preview_tree.iter_changes(revision_tree,
2877
2780
                                            include_unchanged=True)
 
2781
        root = revision_tree.get_root_id()
 
2782
 
2878
2783
        self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
2879
2784
 
2880
2785
    def test_specific_files(self):
2909
2814
        revision_tree = self.create_tree()
2910
2815
        preview = TransformPreview(revision_tree)
2911
2816
        self.addCleanup(preview.finalize)
2912
 
        preview.new_file('file', preview.root, [b'contents'], b'file-id')
2913
 
        preview.new_directory('directory', preview.root, b'dir-id')
 
2817
        preview.new_file('file', preview.root, 'contents', 'file-id')
 
2818
        preview.new_directory('directory', preview.root, 'dir-id')
2914
2819
        preview_tree = preview.get_preview_tree()
2915
 
        self.assertEqual('file', preview_tree.kind('file'))
2916
 
        self.assertEqual('directory', preview_tree.kind('directory'))
 
2820
        self.assertEqual('file', preview_tree.kind('file-id'))
 
2821
        self.assertEqual('directory', preview_tree.kind('dir-id'))
2917
2822
 
2918
2823
    def test_get_file_mtime(self):
2919
2824
        preview = self.get_empty_preview()
2920
 
        file_trans_id = preview.new_file('file', preview.root, [b'contents'],
2921
 
                                         b'file-id')
 
2825
        file_trans_id = preview.new_file('file', preview.root, 'contents',
 
2826
                                         'file-id')
2922
2827
        limbo_path = preview._limbo_name(file_trans_id)
2923
2828
        preview_tree = preview.get_preview_tree()
2924
2829
        self.assertEqual(os.stat(limbo_path).st_mtime,
2925
 
                         preview_tree.get_file_mtime('file'))
 
2830
                         preview_tree.get_file_mtime('file-id'))
2926
2831
 
2927
2832
    def test_get_file_mtime_renamed(self):
2928
2833
        work_tree = self.make_branch_and_tree('tree')
2929
2834
        self.build_tree(['tree/file'])
2930
 
        work_tree.add('file', b'file-id')
 
2835
        work_tree.add('file', 'file-id')
2931
2836
        preview = TransformPreview(work_tree)
2932
2837
        self.addCleanup(preview.finalize)
2933
 
        file_trans_id = preview.trans_id_tree_path('file')
 
2838
        file_trans_id = preview.trans_id_tree_file_id('file-id')
2934
2839
        preview.adjust_path('renamed', preview.root, file_trans_id)
2935
2840
        preview_tree = preview.get_preview_tree()
2936
 
        preview_mtime = preview_tree.get_file_mtime('renamed')
2937
 
        work_mtime = work_tree.get_file_mtime('file')
 
2841
        preview_mtime = preview_tree.get_file_mtime('file-id', 'renamed')
 
2842
        work_mtime = work_tree.get_file_mtime('file-id', 'file')
2938
2843
 
2939
2844
    def test_get_file_size(self):
2940
2845
        work_tree = self.make_branch_and_tree('tree')
2941
 
        self.build_tree_contents([('tree/old', b'old')])
2942
 
        work_tree.add('old', b'old-id')
 
2846
        self.build_tree_contents([('tree/old', 'old')])
 
2847
        work_tree.add('old', 'old-id')
2943
2848
        preview = TransformPreview(work_tree)
2944
2849
        self.addCleanup(preview.finalize)
2945
 
        preview.new_file('name', preview.root, [b'contents'], b'new-id',
2946
 
                         'executable')
 
2850
        new_id = preview.new_file('name', preview.root, 'contents', 'new-id',
 
2851
                                  'executable')
2947
2852
        tree = preview.get_preview_tree()
2948
 
        self.assertEqual(len('old'), tree.get_file_size('old'))
2949
 
        self.assertEqual(len('contents'), tree.get_file_size('name'))
 
2853
        self.assertEqual(len('old'), tree.get_file_size('old-id'))
 
2854
        self.assertEqual(len('contents'), tree.get_file_size('new-id'))
2950
2855
 
2951
2856
    def test_get_file(self):
2952
2857
        preview = self.get_empty_preview()
2953
 
        preview.new_file('file', preview.root, [b'contents'], b'file-id')
 
2858
        preview.new_file('file', preview.root, 'contents', 'file-id')
2954
2859
        preview_tree = preview.get_preview_tree()
2955
 
        with preview_tree.get_file('file') as tree_file:
2956
 
            self.assertEqual(b'contents', tree_file.read())
 
2860
        tree_file = preview_tree.get_file('file-id')
 
2861
        try:
 
2862
            self.assertEqual('contents', tree_file.read())
 
2863
        finally:
 
2864
            tree_file.close()
2957
2865
 
2958
2866
    def test_get_symlink_target(self):
2959
2867
        self.requireFeature(SymlinkFeature)
2960
2868
        preview = self.get_empty_preview()
2961
 
        preview.new_symlink('symlink', preview.root, 'target', b'symlink-id')
 
2869
        preview.new_symlink('symlink', preview.root, 'target', 'symlink-id')
2962
2870
        preview_tree = preview.get_preview_tree()
2963
2871
        self.assertEqual('target',
2964
 
                         preview_tree.get_symlink_target('symlink'))
 
2872
                         preview_tree.get_symlink_target('symlink-id'))
2965
2873
 
2966
2874
    def test_all_file_ids(self):
2967
2875
        tree = self.make_branch_and_tree('tree')
2968
2876
        self.build_tree(['tree/a', 'tree/b', 'tree/c'])
2969
 
        tree.add(['a', 'b', 'c'], [b'a-id', b'b-id', b'c-id'])
 
2877
        tree.add(['a', 'b', 'c'], ['a-id', 'b-id', 'c-id'])
2970
2878
        preview = TransformPreview(tree)
2971
2879
        self.addCleanup(preview.finalize)
2972
 
        preview.unversion_file(preview.trans_id_file_id(b'b-id'))
2973
 
        c_trans_id = preview.trans_id_file_id(b'c-id')
 
2880
        preview.unversion_file(preview.trans_id_file_id('b-id'))
 
2881
        c_trans_id = preview.trans_id_file_id('c-id')
2974
2882
        preview.unversion_file(c_trans_id)
2975
 
        preview.version_file(b'c-id', c_trans_id)
 
2883
        preview.version_file('c-id', c_trans_id)
2976
2884
        preview_tree = preview.get_preview_tree()
2977
 
        self.assertEqual({b'a-id', b'c-id', tree.path2id('')},
 
2885
        self.assertEqual(set(['a-id', 'c-id', tree.get_root_id()]),
2978
2886
                         preview_tree.all_file_ids())
2979
2887
 
2980
2888
    def test_path2id_deleted_unchanged(self):
2981
2889
        tree = self.make_branch_and_tree('tree')
2982
2890
        self.build_tree(['tree/unchanged', 'tree/deleted'])
2983
 
        tree.add(['unchanged', 'deleted'], [b'unchanged-id', b'deleted-id'])
 
2891
        tree.add(['unchanged', 'deleted'], ['unchanged-id', 'deleted-id'])
2984
2892
        preview = TransformPreview(tree)
2985
2893
        self.addCleanup(preview.finalize)
2986
 
        preview.unversion_file(preview.trans_id_file_id(b'deleted-id'))
 
2894
        preview.unversion_file(preview.trans_id_file_id('deleted-id'))
2987
2895
        preview_tree = preview.get_preview_tree()
2988
 
        self.assertEqual(b'unchanged-id', preview_tree.path2id('unchanged'))
2989
 
        self.assertFalse(preview_tree.is_versioned('deleted'))
 
2896
        self.assertEqual('unchanged-id', preview_tree.path2id('unchanged'))
 
2897
        self.assertIs(None, preview_tree.path2id('deleted'))
2990
2898
 
2991
2899
    def test_path2id_created(self):
2992
2900
        tree = self.make_branch_and_tree('tree')
2993
2901
        self.build_tree(['tree/unchanged'])
2994
 
        tree.add(['unchanged'], [b'unchanged-id'])
 
2902
        tree.add(['unchanged'], ['unchanged-id'])
2995
2903
        preview = TransformPreview(tree)
2996
2904
        self.addCleanup(preview.finalize)
2997
 
        preview.new_file('new', preview.trans_id_file_id(b'unchanged-id'),
2998
 
                         [b'contents'], b'new-id')
 
2905
        preview.new_file('new', preview.trans_id_file_id('unchanged-id'),
 
2906
            'contents', 'new-id')
2999
2907
        preview_tree = preview.get_preview_tree()
3000
 
        self.assertEqual(b'new-id', preview_tree.path2id('unchanged/new'))
 
2908
        self.assertEqual('new-id', preview_tree.path2id('unchanged/new'))
3001
2909
 
3002
2910
    def test_path2id_moved(self):
3003
2911
        tree = self.make_branch_and_tree('tree')
3004
2912
        self.build_tree(['tree/old_parent/', 'tree/old_parent/child'])
3005
2913
        tree.add(['old_parent', 'old_parent/child'],
3006
 
                 [b'old_parent-id', b'child-id'])
 
2914
                 ['old_parent-id', 'child-id'])
3007
2915
        preview = TransformPreview(tree)
3008
2916
        self.addCleanup(preview.finalize)
3009
2917
        new_parent = preview.new_directory('new_parent', preview.root,
3010
 
                                           b'new_parent-id')
 
2918
                                           'new_parent-id')
3011
2919
        preview.adjust_path('child', new_parent,
3012
 
                            preview.trans_id_file_id(b'child-id'))
 
2920
                            preview.trans_id_file_id('child-id'))
3013
2921
        preview_tree = preview.get_preview_tree()
3014
 
        self.assertFalse(preview_tree.is_versioned('old_parent/child'))
3015
 
        self.assertEqual(b'child-id', preview_tree.path2id('new_parent/child'))
 
2922
        self.assertIs(None, preview_tree.path2id('old_parent/child'))
 
2923
        self.assertEqual('child-id', preview_tree.path2id('new_parent/child'))
3016
2924
 
3017
2925
    def test_path2id_renamed_parent(self):
3018
2926
        tree = self.make_branch_and_tree('tree')
3019
2927
        self.build_tree(['tree/old_name/', 'tree/old_name/child'])
3020
2928
        tree.add(['old_name', 'old_name/child'],
3021
 
                 [b'parent-id', b'child-id'])
 
2929
                 ['parent-id', 'child-id'])
3022
2930
        preview = TransformPreview(tree)
3023
2931
        self.addCleanup(preview.finalize)
3024
2932
        preview.adjust_path('new_name', preview.root,
3025
 
                            preview.trans_id_file_id(b'parent-id'))
 
2933
                            preview.trans_id_file_id('parent-id'))
3026
2934
        preview_tree = preview.get_preview_tree()
3027
 
        self.assertFalse(preview_tree.is_versioned('old_name/child'))
3028
 
        self.assertEqual(b'child-id', preview_tree.path2id('new_name/child'))
 
2935
        self.assertIs(None, preview_tree.path2id('old_name/child'))
 
2936
        self.assertEqual('child-id', preview_tree.path2id('new_name/child'))
3029
2937
 
3030
 
    def assertMatchingIterEntries(self, tt, specific_files=None):
 
2938
    def assertMatchingIterEntries(self, tt, specific_file_ids=None):
3031
2939
        preview_tree = tt.get_preview_tree()
3032
2940
        preview_result = list(preview_tree.iter_entries_by_dir(
3033
 
                              specific_files=specific_files))
 
2941
                              specific_file_ids))
3034
2942
        tree = tt._tree
3035
2943
        tt.apply()
3036
 
        actual_result = list(tree.iter_entries_by_dir(
3037
 
            specific_files=specific_files))
 
2944
        actual_result = list(tree.iter_entries_by_dir(specific_file_ids))
3038
2945
        self.assertEqual(actual_result, preview_result)
3039
2946
 
3040
2947
    def test_iter_entries_by_dir_new(self):
3041
2948
        tree = self.make_branch_and_tree('tree')
3042
2949
        tt = TreeTransform(tree)
3043
 
        tt.new_file('new', tt.root, [b'contents'], b'new-id')
 
2950
        tt.new_file('new', tt.root, 'contents', 'new-id')
3044
2951
        self.assertMatchingIterEntries(tt)
3045
2952
 
3046
2953
    def test_iter_entries_by_dir_deleted(self):
3047
2954
        tree = self.make_branch_and_tree('tree')
3048
2955
        self.build_tree(['tree/deleted'])
3049
 
        tree.add('deleted', b'deleted-id')
 
2956
        tree.add('deleted', 'deleted-id')
3050
2957
        tt = TreeTransform(tree)
3051
 
        tt.delete_contents(tt.trans_id_file_id(b'deleted-id'))
 
2958
        tt.delete_contents(tt.trans_id_file_id('deleted-id'))
3052
2959
        self.assertMatchingIterEntries(tt)
3053
2960
 
3054
2961
    def test_iter_entries_by_dir_unversioned(self):
3055
2962
        tree = self.make_branch_and_tree('tree')
3056
2963
        self.build_tree(['tree/removed'])
3057
 
        tree.add('removed', b'removed-id')
 
2964
        tree.add('removed', 'removed-id')
3058
2965
        tt = TreeTransform(tree)
3059
 
        tt.unversion_file(tt.trans_id_file_id(b'removed-id'))
 
2966
        tt.unversion_file(tt.trans_id_file_id('removed-id'))
3060
2967
        self.assertMatchingIterEntries(tt)
3061
2968
 
3062
2969
    def test_iter_entries_by_dir_moved(self):
3063
2970
        tree = self.make_branch_and_tree('tree')
3064
2971
        self.build_tree(['tree/moved', 'tree/new_parent/'])
3065
 
        tree.add(['moved', 'new_parent'], [b'moved-id', b'new_parent-id'])
 
2972
        tree.add(['moved', 'new_parent'], ['moved-id', 'new_parent-id'])
3066
2973
        tt = TreeTransform(tree)
3067
 
        tt.adjust_path('moved', tt.trans_id_file_id(b'new_parent-id'),
3068
 
                       tt.trans_id_file_id(b'moved-id'))
 
2974
        tt.adjust_path('moved', tt.trans_id_file_id('new_parent-id'),
 
2975
                       tt.trans_id_file_id('moved-id'))
3069
2976
        self.assertMatchingIterEntries(tt)
3070
2977
 
3071
 
    def test_iter_entries_by_dir_specific_files(self):
 
2978
    def test_iter_entries_by_dir_specific_file_ids(self):
3072
2979
        tree = self.make_branch_and_tree('tree')
3073
 
        tree.set_root_id(b'tree-root-id')
 
2980
        tree.set_root_id('tree-root-id')
3074
2981
        self.build_tree(['tree/parent/', 'tree/parent/child'])
3075
 
        tree.add(['parent', 'parent/child'], [b'parent-id', b'child-id'])
 
2982
        tree.add(['parent', 'parent/child'], ['parent-id', 'child-id'])
3076
2983
        tt = TreeTransform(tree)
3077
 
        self.assertMatchingIterEntries(tt, ['', 'parent/child'])
 
2984
        self.assertMatchingIterEntries(tt, ['tree-root-id', 'child-id'])
3078
2985
 
3079
2986
    def test_symlink_content_summary(self):
3080
2987
        self.requireFeature(SymlinkFeature)
3081
2988
        preview = self.get_empty_preview()
3082
 
        preview.new_symlink('path', preview.root, 'target', b'path-id')
 
2989
        preview.new_symlink('path', preview.root, 'target', 'path-id')
3083
2990
        summary = preview.get_preview_tree().path_content_summary('path')
3084
2991
        self.assertEqual(('symlink', None, None, 'target'), summary)
3085
2992
 
3100
3007
 
3101
3008
    def test_file_content_summary_executable(self):
3102
3009
        preview = self.get_empty_preview()
3103
 
        path_id = preview.new_file('path', preview.root, [
3104
 
                                   b'contents'], b'path-id')
 
3010
        path_id = preview.new_file('path', preview.root, 'contents', 'path-id')
3105
3011
        preview.set_executability(True, path_id)
3106
3012
        summary = preview.get_preview_tree().path_content_summary('path')
3107
3013
        self.assertEqual(4, len(summary))
3126
3032
 
3127
3033
    def test_file_content_summary_non_exec(self):
3128
3034
        preview = self.get_empty_preview()
3129
 
        preview.new_file('path', preview.root, [b'contents'], b'path-id')
 
3035
        preview.new_file('path', preview.root, 'contents', 'path-id')
3130
3036
        summary = preview.get_preview_tree().path_content_summary('path')
3131
3037
        self.assertEqual(4, len(summary))
3132
3038
        self.assertEqual('file', summary[0])
3139
3045
 
3140
3046
    def test_dir_content_summary(self):
3141
3047
        preview = self.get_empty_preview()
3142
 
        preview.new_directory('path', preview.root, b'path-id')
 
3048
        preview.new_directory('path', preview.root, 'path-id')
3143
3049
        summary = preview.get_preview_tree().path_content_summary('path')
3144
3050
        self.assertEqual(('directory', None, None, None), summary)
3145
3051
 
3146
3052
    def test_tree_content_summary(self):
3147
3053
        preview = self.get_empty_preview()
3148
 
        path = preview.new_directory('path', preview.root, b'path-id')
3149
 
        preview.set_tree_reference(b'rev-1', path)
 
3054
        path = preview.new_directory('path', preview.root, 'path-id')
 
3055
        preview.set_tree_reference('rev-1', path)
3150
3056
        summary = preview.get_preview_tree().path_content_summary('path')
3151
3057
        self.assertEqual(4, len(summary))
3152
3058
        self.assertEqual('tree-reference', summary[0])
3153
3059
 
3154
3060
    def test_annotate(self):
3155
3061
        tree = self.make_branch_and_tree('tree')
3156
 
        self.build_tree_contents([('tree/file', b'a\n')])
3157
 
        tree.add('file', b'file-id')
3158
 
        tree.commit('a', rev_id=b'one')
3159
 
        self.build_tree_contents([('tree/file', b'a\nb\n')])
 
3062
        self.build_tree_contents([('tree/file', 'a\n')])
 
3063
        tree.add('file', 'file-id')
 
3064
        tree.commit('a', rev_id='one')
 
3065
        self.build_tree_contents([('tree/file', 'a\nb\n')])
3160
3066
        preview = TransformPreview(tree)
3161
3067
        self.addCleanup(preview.finalize)
3162
 
        file_trans_id = preview.trans_id_file_id(b'file-id')
 
3068
        file_trans_id = preview.trans_id_file_id('file-id')
3163
3069
        preview.delete_contents(file_trans_id)
3164
 
        preview.create_file([b'a\nb\nc\n'], file_trans_id)
 
3070
        preview.create_file('a\nb\nc\n', file_trans_id)
3165
3071
        preview_tree = preview.get_preview_tree()
3166
3072
        expected = [
3167
 
            (b'one', b'a\n'),
3168
 
            (b'me:', b'b\n'),
3169
 
            (b'me:', b'c\n'),
 
3073
            ('one', 'a\n'),
 
3074
            ('me:', 'b\n'),
 
3075
            ('me:', 'c\n'),
3170
3076
        ]
3171
 
        annotation = preview_tree.annotate_iter(
3172
 
            'file', default_revision=b'me:')
 
3077
        annotation = preview_tree.annotate_iter('file-id', 'me:')
3173
3078
        self.assertEqual(expected, annotation)
3174
3079
 
3175
3080
    def test_annotate_missing(self):
3176
3081
        preview = self.get_empty_preview()
3177
 
        preview.new_file('file', preview.root, [b'a\nb\nc\n'], b'file-id')
 
3082
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
3178
3083
        preview_tree = preview.get_preview_tree()
3179
3084
        expected = [
3180
 
            (b'me:', b'a\n'),
3181
 
            (b'me:', b'b\n'),
3182
 
            (b'me:', b'c\n'),
3183
 
            ]
3184
 
        annotation = preview_tree.annotate_iter(
3185
 
            'file', default_revision=b'me:')
 
3085
            ('me:', 'a\n'),
 
3086
            ('me:', 'b\n'),
 
3087
            ('me:', 'c\n'),
 
3088
         ]
 
3089
        annotation = preview_tree.annotate_iter('file-id', 'me:')
3186
3090
        self.assertEqual(expected, annotation)
3187
3091
 
3188
3092
    def test_annotate_rename(self):
3189
3093
        tree = self.make_branch_and_tree('tree')
3190
 
        self.build_tree_contents([('tree/file', b'a\n')])
3191
 
        tree.add('file', b'file-id')
3192
 
        tree.commit('a', rev_id=b'one')
 
3094
        self.build_tree_contents([('tree/file', 'a\n')])
 
3095
        tree.add('file', 'file-id')
 
3096
        tree.commit('a', rev_id='one')
3193
3097
        preview = TransformPreview(tree)
3194
3098
        self.addCleanup(preview.finalize)
3195
 
        file_trans_id = preview.trans_id_file_id(b'file-id')
 
3099
        file_trans_id = preview.trans_id_file_id('file-id')
3196
3100
        preview.adjust_path('newname', preview.root, file_trans_id)
3197
3101
        preview_tree = preview.get_preview_tree()
3198
3102
        expected = [
3199
 
            (b'one', b'a\n'),
 
3103
            ('one', 'a\n'),
3200
3104
        ]
3201
 
        annotation = preview_tree.annotate_iter(
3202
 
            'file', default_revision=b'me:')
 
3105
        annotation = preview_tree.annotate_iter('file-id', 'me:')
3203
3106
        self.assertEqual(expected, annotation)
3204
3107
 
3205
3108
    def test_annotate_deleted(self):
3206
3109
        tree = self.make_branch_and_tree('tree')
3207
 
        self.build_tree_contents([('tree/file', b'a\n')])
3208
 
        tree.add('file', b'file-id')
3209
 
        tree.commit('a', rev_id=b'one')
3210
 
        self.build_tree_contents([('tree/file', b'a\nb\n')])
 
3110
        self.build_tree_contents([('tree/file', 'a\n')])
 
3111
        tree.add('file', 'file-id')
 
3112
        tree.commit('a', rev_id='one')
 
3113
        self.build_tree_contents([('tree/file', 'a\nb\n')])
3211
3114
        preview = TransformPreview(tree)
3212
3115
        self.addCleanup(preview.finalize)
3213
 
        file_trans_id = preview.trans_id_file_id(b'file-id')
 
3116
        file_trans_id = preview.trans_id_file_id('file-id')
3214
3117
        preview.delete_contents(file_trans_id)
3215
3118
        preview_tree = preview.get_preview_tree()
3216
 
        annotation = preview_tree.annotate_iter(
3217
 
            'file', default_revision=b'me:')
 
3119
        annotation = preview_tree.annotate_iter('file-id', 'me:')
3218
3120
        self.assertIs(None, annotation)
3219
3121
 
3220
3122
    def test_stored_kind(self):
3221
3123
        preview = self.get_empty_preview()
3222
 
        preview.new_file('file', preview.root, [b'a\nb\nc\n'], b'file-id')
 
3124
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
3223
3125
        preview_tree = preview.get_preview_tree()
3224
 
        self.assertEqual('file', preview_tree.stored_kind('file'))
 
3126
        self.assertEqual('file', preview_tree.stored_kind('file-id'))
3225
3127
 
3226
3128
    def test_is_executable(self):
3227
3129
        preview = self.get_empty_preview()
3228
 
        preview.new_file('file', preview.root, [b'a\nb\nc\n'], b'file-id')
3229
 
        preview.set_executability(True, preview.trans_id_file_id(b'file-id'))
 
3130
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
 
3131
        preview.set_executability(True, preview.trans_id_file_id('file-id'))
3230
3132
        preview_tree = preview.get_preview_tree()
3231
 
        self.assertEqual(True, preview_tree.is_executable('file'))
 
3133
        self.assertEqual(True, preview_tree.is_executable('file-id'))
3232
3134
 
3233
3135
    def test_get_set_parent_ids(self):
3234
3136
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3235
3137
        self.assertEqual([], preview_tree.get_parent_ids())
3236
 
        preview_tree.set_parent_ids([b'rev-1'])
3237
 
        self.assertEqual([b'rev-1'], preview_tree.get_parent_ids())
 
3138
        preview_tree.set_parent_ids(['rev-1'])
 
3139
        self.assertEqual(['rev-1'], preview_tree.get_parent_ids())
3238
3140
 
3239
3141
    def test_plan_file_merge(self):
3240
3142
        work_a = self.make_branch_and_tree('wta')
3241
 
        self.build_tree_contents([('wta/file', b'a\nb\nc\nd\n')])
3242
 
        work_a.add('file', b'file-id')
 
3143
        self.build_tree_contents([('wta/file', 'a\nb\nc\nd\n')])
 
3144
        work_a.add('file', 'file-id')
3243
3145
        base_id = work_a.commit('base version')
3244
 
        tree_b = work_a.controldir.sprout('wtb').open_workingtree()
 
3146
        tree_b = work_a.bzrdir.sprout('wtb').open_workingtree()
3245
3147
        preview = TransformPreview(work_a)
3246
3148
        self.addCleanup(preview.finalize)
3247
 
        trans_id = preview.trans_id_file_id(b'file-id')
 
3149
        trans_id = preview.trans_id_file_id('file-id')
3248
3150
        preview.delete_contents(trans_id)
3249
 
        preview.create_file([b'b\nc\nd\ne\n'], trans_id)
3250
 
        self.build_tree_contents([('wtb/file', b'a\nc\nd\nf\n')])
 
3151
        preview.create_file('b\nc\nd\ne\n', trans_id)
 
3152
        self.build_tree_contents([('wtb/file', 'a\nc\nd\nf\n')])
3251
3153
        tree_a = preview.get_preview_tree()
3252
3154
        tree_a.set_parent_ids([base_id])
3253
3155
        self.assertEqual([
3254
 
            ('killed-a', b'a\n'),
3255
 
            ('killed-b', b'b\n'),
3256
 
            ('unchanged', b'c\n'),
3257
 
            ('unchanged', b'd\n'),
3258
 
            ('new-a', b'e\n'),
3259
 
            ('new-b', b'f\n'),
3260
 
        ], list(tree_a.plan_file_merge('file', tree_b)))
 
3156
            ('killed-a', 'a\n'),
 
3157
            ('killed-b', 'b\n'),
 
3158
            ('unchanged', 'c\n'),
 
3159
            ('unchanged', 'd\n'),
 
3160
            ('new-a', 'e\n'),
 
3161
            ('new-b', 'f\n'),
 
3162
        ], list(tree_a.plan_file_merge('file-id', tree_b)))
3261
3163
 
3262
3164
    def test_plan_file_merge_revision_tree(self):
3263
3165
        work_a = self.make_branch_and_tree('wta')
3264
 
        self.build_tree_contents([('wta/file', b'a\nb\nc\nd\n')])
3265
 
        work_a.add('file', b'file-id')
 
3166
        self.build_tree_contents([('wta/file', 'a\nb\nc\nd\n')])
 
3167
        work_a.add('file', 'file-id')
3266
3168
        base_id = work_a.commit('base version')
3267
 
        tree_b = work_a.controldir.sprout('wtb').open_workingtree()
 
3169
        tree_b = work_a.bzrdir.sprout('wtb').open_workingtree()
3268
3170
        preview = TransformPreview(work_a.basis_tree())
3269
3171
        self.addCleanup(preview.finalize)
3270
 
        trans_id = preview.trans_id_file_id(b'file-id')
 
3172
        trans_id = preview.trans_id_file_id('file-id')
3271
3173
        preview.delete_contents(trans_id)
3272
 
        preview.create_file([b'b\nc\nd\ne\n'], trans_id)
3273
 
        self.build_tree_contents([('wtb/file', b'a\nc\nd\nf\n')])
 
3174
        preview.create_file('b\nc\nd\ne\n', trans_id)
 
3175
        self.build_tree_contents([('wtb/file', 'a\nc\nd\nf\n')])
3274
3176
        tree_a = preview.get_preview_tree()
3275
3177
        tree_a.set_parent_ids([base_id])
3276
3178
        self.assertEqual([
3277
 
            ('killed-a', b'a\n'),
3278
 
            ('killed-b', b'b\n'),
3279
 
            ('unchanged', b'c\n'),
3280
 
            ('unchanged', b'd\n'),
3281
 
            ('new-a', b'e\n'),
3282
 
            ('new-b', b'f\n'),
3283
 
        ], list(tree_a.plan_file_merge('file', tree_b)))
 
3179
            ('killed-a', 'a\n'),
 
3180
            ('killed-b', 'b\n'),
 
3181
            ('unchanged', 'c\n'),
 
3182
            ('unchanged', 'd\n'),
 
3183
            ('new-a', 'e\n'),
 
3184
            ('new-b', 'f\n'),
 
3185
        ], list(tree_a.plan_file_merge('file-id', tree_b)))
3284
3186
 
3285
3187
    def test_walkdirs(self):
3286
3188
        preview = self.get_empty_preview()
3287
 
        preview.new_directory('', ROOT_PARENT, b'tree-root')
 
3189
        root = preview.new_directory('', ROOT_PARENT, 'tree-root')
3288
3190
        # FIXME: new_directory should mark root.
3289
3191
        preview.fixup_new_roots()
3290
3192
        preview_tree = preview.get_preview_tree()
3291
 
        preview.new_file('a', preview.root, [b'contents'], b'a-id')
3292
 
        expected = [(('', b'tree-root'),
3293
 
                     [('a', 'a', 'file', None, b'a-id', 'file')])]
 
3193
        file_trans_id = preview.new_file('a', preview.root, 'contents',
 
3194
                                         'a-id')
 
3195
        expected = [(('', 'tree-root'),
 
3196
                    [('a', 'a', 'file', None, 'a-id', 'file')])]
3294
3197
        self.assertEqual(expected, list(preview_tree.walkdirs()))
3295
3198
 
3296
3199
    def test_extras(self):
3300
3203
        work_tree.add(['removed-file', 'not-removed-file'])
3301
3204
        preview = TransformPreview(work_tree)
3302
3205
        self.addCleanup(preview.finalize)
3303
 
        preview.new_file('new-file', preview.root, [b'contents'])
3304
 
        preview.new_file('new-versioned-file', preview.root, [b'contents'],
3305
 
                         b'new-versioned-id')
 
3206
        preview.new_file('new-file', preview.root, 'contents')
 
3207
        preview.new_file('new-versioned-file', preview.root, 'contents',
 
3208
                         'new-versioned-id')
3306
3209
        tree = preview.get_preview_tree()
3307
3210
        preview.unversion_file(preview.trans_id_tree_path('removed-file'))
3308
 
        self.assertEqual({'new-file', 'removed-file', 'existing-file'},
 
3211
        self.assertEqual(set(['new-file', 'removed-file', 'existing-file']),
3309
3212
                         set(tree.extras()))
3310
3213
 
3311
3214
    def test_merge_into_preview(self):
3312
3215
        work_tree = self.make_branch_and_tree('tree')
3313
 
        self.build_tree_contents([('tree/file', b'b\n')])
3314
 
        work_tree.add('file', b'file-id')
 
3216
        self.build_tree_contents([('tree/file','b\n')])
 
3217
        work_tree.add('file', 'file-id')
3315
3218
        work_tree.commit('first commit')
3316
 
        child_tree = work_tree.controldir.sprout('child').open_workingtree()
3317
 
        self.build_tree_contents([('child/file', b'b\nc\n')])
 
3219
        child_tree = work_tree.bzrdir.sprout('child').open_workingtree()
 
3220
        self.build_tree_contents([('child/file','b\nc\n')])
3318
3221
        child_tree.commit('child commit')
3319
3222
        child_tree.lock_write()
3320
3223
        self.addCleanup(child_tree.unlock)
3322
3225
        self.addCleanup(work_tree.unlock)
3323
3226
        preview = TransformPreview(work_tree)
3324
3227
        self.addCleanup(preview.finalize)
3325
 
        file_trans_id = preview.trans_id_file_id(b'file-id')
 
3228
        file_trans_id = preview.trans_id_file_id('file-id')
3326
3229
        preview.delete_contents(file_trans_id)
3327
 
        preview.create_file([b'a\nb\n'], file_trans_id)
 
3230
        preview.create_file('a\nb\n', file_trans_id)
3328
3231
        preview_tree = preview.get_preview_tree()
3329
 
        merger = Merger.from_revision_ids(preview_tree,
 
3232
        merger = Merger.from_revision_ids(None, preview_tree,
3330
3233
                                          child_tree.branch.last_revision(),
3331
3234
                                          other_branch=child_tree.branch,
3332
3235
                                          tree_branch=work_tree.branch)
3334
3237
        tt = merger.make_merger().make_preview_transform()
3335
3238
        self.addCleanup(tt.finalize)
3336
3239
        final_tree = tt.get_preview_tree()
3337
 
        self.assertEqual(
3338
 
            b'a\nb\nc\n',
3339
 
            final_tree.get_file_text(final_tree.id2path(b'file-id')))
 
3240
        self.assertEqual('a\nb\nc\n', final_tree.get_file_text('file-id'))
3340
3241
 
3341
3242
    def test_merge_preview_into_workingtree(self):
3342
3243
        tree = self.make_branch_and_tree('tree')
3343
 
        tree.set_root_id(b'TREE_ROOT')
 
3244
        tree.set_root_id('TREE_ROOT')
3344
3245
        tt = TransformPreview(tree)
3345
3246
        self.addCleanup(tt.finalize)
3346
 
        tt.new_file('name', tt.root, [b'content'], b'file-id')
 
3247
        tt.new_file('name', tt.root, 'content', 'file-id')
3347
3248
        tree2 = self.make_branch_and_tree('tree2')
3348
 
        tree2.set_root_id(b'TREE_ROOT')
 
3249
        tree2.set_root_id('TREE_ROOT')
3349
3250
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
3350
 
                                         tree.basis_tree())
 
3251
                                         None, tree.basis_tree())
3351
3252
        merger.merge_type = Merge3Merger
3352
3253
        merger.do_merge()
3353
3254
 
3354
3255
    def test_merge_preview_into_workingtree_handles_conflicts(self):
3355
3256
        tree = self.make_branch_and_tree('tree')
3356
 
        self.build_tree_contents([('tree/foo', b'bar')])
3357
 
        tree.add('foo', b'foo-id')
 
3257
        self.build_tree_contents([('tree/foo', 'bar')])
 
3258
        tree.add('foo', 'foo-id')
3358
3259
        tree.commit('foo')
3359
3260
        tt = TransformPreview(tree)
3360
3261
        self.addCleanup(tt.finalize)
3361
 
        trans_id = tt.trans_id_file_id(b'foo-id')
 
3262
        trans_id = tt.trans_id_file_id('foo-id')
3362
3263
        tt.delete_contents(trans_id)
3363
 
        tt.create_file([b'baz'], trans_id)
3364
 
        tree2 = tree.controldir.sprout('tree2').open_workingtree()
3365
 
        self.build_tree_contents([('tree2/foo', b'qux')])
 
3264
        tt.create_file('baz', trans_id)
 
3265
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
 
3266
        self.build_tree_contents([('tree2/foo', 'qux')])
 
3267
        pb = None
3366
3268
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
3367
 
                                         tree.basis_tree())
 
3269
                                         pb, tree.basis_tree())
3368
3270
        merger.merge_type = Merge3Merger
3369
3271
        merger.do_merge()
3370
3272
 
3374
3276
        tt = TransformPreview(wt)
3375
3277
        removed_id = tt.trans_id_tree_path('removed')
3376
3278
        tt.delete_contents(removed_id)
3377
 
        tt.new_file('new', tt.root, [b'contents'])
 
3279
        tt.new_file('new', tt.root, 'contents')
3378
3280
        modified_id = tt.trans_id_tree_path('modified')
3379
3281
        tt.delete_contents(modified_id)
3380
 
        tt.create_file([b'modified-contents'], modified_id)
 
3282
        tt.create_file('modified-contents', modified_id)
3381
3283
        self.addCleanup(tt.finalize)
3382
3284
        tree = tt.get_preview_tree()
3383
3285
        self.assertTrue(tree.has_filename('unmodified'))
3390
3292
        tree = self.make_branch_and_tree('tree')
3391
3293
        preview = TransformPreview(tree)
3392
3294
        self.addCleanup(preview.finalize)
3393
 
        preview.new_file('foo', preview.root, [b'bar'], b'baz-id')
 
3295
        preview.new_file('foo', preview.root, 'bar', 'baz-id')
3394
3296
        preview_tree = preview.get_preview_tree()
3395
 
        self.assertEqual(False, preview_tree.is_executable('tree/foo'))
 
3297
        self.assertEqual(False, preview_tree.is_executable('baz-id',
 
3298
                                                           'tree/foo'))
 
3299
        self.assertEqual(False, preview_tree.is_executable('baz-id'))
3396
3300
 
3397
3301
    def test_commit_preview_tree(self):
3398
3302
        tree = self.make_branch_and_tree('tree')
3400
3304
        tree.branch.lock_write()
3401
3305
        self.addCleanup(tree.branch.unlock)
3402
3306
        tt = TransformPreview(tree)
3403
 
        tt.new_file('file', tt.root, [b'contents'], b'file_id')
 
3307
        tt.new_file('file', tt.root, 'contents', 'file_id')
3404
3308
        self.addCleanup(tt.finalize)
3405
3309
        preview = tt.get_preview_tree()
3406
3310
        preview.set_parent_ids([rev_id])
3409
3313
        builder.finish_inventory()
3410
3314
        rev2_id = builder.commit('rev2')
3411
3315
        rev2_tree = tree.branch.repository.revision_tree(rev2_id)
3412
 
        self.assertEqual(b'contents', rev2_tree.get_file_text('file'))
 
3316
        self.assertEqual('contents', rev2_tree.get_file_text('file_id'))
3413
3317
 
3414
3318
    def test_ascii_limbo_paths(self):
3415
3319
        self.requireFeature(features.UnicodeFilenameFeature)
3418
3322
        tt = TransformPreview(tree)
3419
3323
        self.addCleanup(tt.finalize)
3420
3324
        foo_id = tt.new_directory('', ROOT_PARENT)
3421
 
        bar_id = tt.new_file(u'\u1234bar', foo_id, [b'contents'])
 
3325
        bar_id = tt.new_file(u'\u1234bar', foo_id, 'contents')
3422
3326
        limbo_path = tt._limbo_name(bar_id)
3423
 
        self.assertEqual(limbo_path, limbo_path)
 
3327
        self.assertEqual(limbo_path.encode('ascii', 'replace'), limbo_path)
3424
3328
 
3425
3329
 
3426
3330
class FakeSerializer(object):
3451
3355
    @staticmethod
3452
3356
    def default_attribs():
3453
3357
        return {
3454
 
            b'_id_number': 1,
3455
 
            b'_new_name': {},
3456
 
            b'_new_parent': {},
3457
 
            b'_new_executability': {},
3458
 
            b'_new_id': {},
3459
 
            b'_tree_path_ids': {b'': b'new-0'},
3460
 
            b'_removed_id': [],
3461
 
            b'_removed_contents': [],
3462
 
            b'_non_present_ids': {},
 
3358
            '_id_number': 1,
 
3359
            '_new_name': {},
 
3360
            '_new_parent': {},
 
3361
            '_new_executability': {},
 
3362
            '_new_id': {},
 
3363
            '_tree_path_ids': {'': 'new-0'},
 
3364
            '_removed_id': [],
 
3365
            '_removed_contents': [],
 
3366
            '_non_present_ids': {},
3463
3367
            }
3464
3368
 
3465
3369
    def make_records(self, attribs, contents):
3466
3370
        records = [
3467
 
            ((((b'attribs'),),), bencode.bencode(attribs))]
 
3371
            (((('attribs'),),), bencode.bencode(attribs))]
3468
3372
        records.extend([(((n, k),), c) for n, k, c in contents])
3469
3373
        return records
3470
3374
 
3471
3375
    def creation_records(self):
3472
3376
        attribs = self.default_attribs()
3473
 
        attribs[b'_id_number'] = 3
3474
 
        attribs[b'_new_name'] = {
3475
 
            b'new-1': u'foo\u1234'.encode('utf-8'), b'new-2': b'qux'}
3476
 
        attribs[b'_new_id'] = {b'new-1': b'baz', b'new-2': b'quxx'}
3477
 
        attribs[b'_new_parent'] = {b'new-1': b'new-0', b'new-2': b'new-0'}
3478
 
        attribs[b'_new_executability'] = {b'new-1': 1}
 
3377
        attribs['_id_number'] = 3
 
3378
        attribs['_new_name'] = {
 
3379
            'new-1': u'foo\u1234'.encode('utf-8'), 'new-2': 'qux'}
 
3380
        attribs['_new_id'] = {'new-1': 'baz', 'new-2': 'quxx'}
 
3381
        attribs['_new_parent'] = {'new-1': 'new-0', 'new-2': 'new-0'}
 
3382
        attribs['_new_executability'] = {'new-1': 1}
3479
3383
        contents = [
3480
 
            (b'new-1', b'file', b'i 1\nbar\n'),
3481
 
            (b'new-2', b'directory', b''),
 
3384
            ('new-1', 'file', 'i 1\nbar\n'),
 
3385
            ('new-2', 'directory', ''),
3482
3386
            ]
3483
3387
        return self.make_records(attribs, contents)
3484
3388
 
3485
3389
    def test_serialize_creation(self):
3486
3390
        tt = self.get_preview()
3487
 
        tt.new_file(u'foo\u1234', tt.root, [b'bar'], b'baz', True)
3488
 
        tt.new_directory('qux', tt.root, b'quxx')
 
3391
        tt.new_file(u'foo\u1234', tt.root, 'bar', 'baz', True)
 
3392
        tt.new_directory('qux', tt.root, 'quxx')
3489
3393
        self.assertSerializesTo(self.creation_records(), tt)
3490
3394
 
3491
3395
    def test_deserialize_creation(self):
3494
3398
        self.assertEqual(3, tt._id_number)
3495
3399
        self.assertEqual({'new-1': u'foo\u1234',
3496
3400
                          'new-2': 'qux'}, tt._new_name)
3497
 
        self.assertEqual({'new-1': b'baz', 'new-2': b'quxx'}, tt._new_id)
 
3401
        self.assertEqual({'new-1': 'baz', 'new-2': 'quxx'}, tt._new_id)
3498
3402
        self.assertEqual({'new-1': tt.root, 'new-2': tt.root}, tt._new_parent)
3499
 
        self.assertEqual({b'baz': 'new-1', b'quxx': 'new-2'}, tt._r_new_id)
 
3403
        self.assertEqual({'baz': 'new-1', 'quxx': 'new-2'}, tt._r_new_id)
3500
3404
        self.assertEqual({'new-1': True}, tt._new_executability)
3501
3405
        self.assertEqual({'new-1': 'file',
3502
3406
                          'new-2': 'directory'}, tt._new_contents)
3505
3409
            foo_content = foo_limbo.read()
3506
3410
        finally:
3507
3411
            foo_limbo.close()
3508
 
        self.assertEqual(b'bar', foo_content)
 
3412
        self.assertEqual('bar', foo_content)
3509
3413
 
3510
3414
    def symlink_creation_records(self):
3511
3415
        attribs = self.default_attribs()
3512
 
        attribs[b'_id_number'] = 2
3513
 
        attribs[b'_new_name'] = {b'new-1': u'foo\u1234'.encode('utf-8')}
3514
 
        attribs[b'_new_parent'] = {b'new-1': b'new-0'}
3515
 
        contents = [(b'new-1', b'symlink', u'bar\u1234'.encode('utf-8'))]
 
3416
        attribs['_id_number'] = 2
 
3417
        attribs['_new_name'] = {'new-1': u'foo\u1234'.encode('utf-8')}
 
3418
        attribs['_new_parent'] = {'new-1': 'new-0'}
 
3419
        contents = [('new-1', 'symlink', u'bar\u1234'.encode('utf-8'))]
3516
3420
        return self.make_records(attribs, contents)
3517
3421
 
3518
3422
    def test_serialize_symlink_creation(self):
3532
3436
    def make_destruction_preview(self):
3533
3437
        tree = self.make_branch_and_tree('.')
3534
3438
        self.build_tree([u'foo\u1234', 'bar'])
3535
 
        tree.add([u'foo\u1234', 'bar'], [b'foo-id', b'bar-id'])
 
3439
        tree.add([u'foo\u1234', 'bar'], ['foo-id', 'bar-id'])
3536
3440
        return self.get_preview(tree)
3537
3441
 
3538
3442
    def destruction_records(self):
3539
3443
        attribs = self.default_attribs()
3540
 
        attribs[b'_id_number'] = 3
3541
 
        attribs[b'_removed_id'] = [b'new-1']
3542
 
        attribs[b'_removed_contents'] = [b'new-2']
3543
 
        attribs[b'_tree_path_ids'] = {
3544
 
            b'': b'new-0',
3545
 
            u'foo\u1234'.encode('utf-8'): b'new-1',
3546
 
            b'bar': b'new-2',
 
3444
        attribs['_id_number'] = 3
 
3445
        attribs['_removed_id'] = ['new-1']
 
3446
        attribs['_removed_contents'] = ['new-2']
 
3447
        attribs['_tree_path_ids'] = {
 
3448
            '': 'new-0',
 
3449
            u'foo\u1234'.encode('utf-8'): 'new-1',
 
3450
            'bar': 'new-2',
3547
3451
            }
3548
3452
        return self.make_records(attribs, [])
3549
3453
 
3550
3454
    def test_serialize_destruction(self):
3551
3455
        tt = self.make_destruction_preview()
3552
 
        foo_trans_id = tt.trans_id_tree_path(u'foo\u1234')
 
3456
        foo_trans_id = tt.trans_id_tree_file_id('foo-id')
3553
3457
        tt.unversion_file(foo_trans_id)
3554
 
        bar_trans_id = tt.trans_id_tree_path('bar')
 
3458
        bar_trans_id = tt.trans_id_tree_file_id('bar-id')
3555
3459
        tt.delete_contents(bar_trans_id)
3556
3460
        self.assertSerializesTo(self.destruction_records(), tt)
3557
3461
 
3564
3468
        self.assertEqual({'new-1': u'foo\u1234',
3565
3469
                          'new-2': 'bar',
3566
3470
                          tt.root: ''}, tt._tree_id_paths)
3567
 
        self.assertEqual({'new-1'}, tt._removed_id)
3568
 
        self.assertEqual({'new-2'}, tt._removed_contents)
 
3471
        self.assertEqual(set(['new-1']), tt._removed_id)
 
3472
        self.assertEqual(set(['new-2']), tt._removed_contents)
3569
3473
 
3570
3474
    def missing_records(self):
3571
3475
        attribs = self.default_attribs()
3572
 
        attribs[b'_id_number'] = 2
3573
 
        attribs[b'_non_present_ids'] = {
3574
 
            b'boo': b'new-1', }
 
3476
        attribs['_id_number'] = 2
 
3477
        attribs['_non_present_ids'] = {
 
3478
            'boo': 'new-1',}
3575
3479
        return self.make_records(attribs, [])
3576
3480
 
3577
3481
    def test_serialize_missing(self):
3578
3482
        tt = self.get_preview()
3579
 
        tt.trans_id_file_id(b'boo')
 
3483
        boo_trans_id = tt.trans_id_file_id('boo')
3580
3484
        self.assertSerializesTo(self.missing_records(), tt)
3581
3485
 
3582
3486
    def test_deserialize_missing(self):
3583
3487
        tt = self.get_preview()
3584
3488
        tt.deserialize(iter(self.missing_records()))
3585
 
        self.assertEqual({b'boo': 'new-1'}, tt._non_present_ids)
 
3489
        self.assertEqual({'boo': 'new-1'}, tt._non_present_ids)
3586
3490
 
3587
3491
    def make_modification_preview(self):
3588
 
        LINES_ONE = b'aa\nbb\ncc\ndd\n'
3589
 
        LINES_TWO = b'z\nbb\nx\ndd\n'
 
3492
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
 
3493
        LINES_TWO = 'z\nbb\nx\ndd\n'
3590
3494
        tree = self.make_branch_and_tree('tree')
3591
3495
        self.build_tree_contents([('tree/file', LINES_ONE)])
3592
 
        tree.add('file', b'file-id')
3593
 
        return self.get_preview(tree), [LINES_TWO]
 
3496
        tree.add('file', 'file-id')
 
3497
        return self.get_preview(tree), LINES_TWO
3594
3498
 
3595
3499
    def modification_records(self):
3596
3500
        attribs = self.default_attribs()
3597
 
        attribs[b'_id_number'] = 2
3598
 
        attribs[b'_tree_path_ids'] = {
3599
 
            b'file': b'new-1',
3600
 
            b'': b'new-0', }
3601
 
        attribs[b'_removed_contents'] = [b'new-1']
3602
 
        contents = [(b'new-1', b'file',
3603
 
                     b'i 1\nz\n\nc 0 1 1 1\ni 1\nx\n\nc 0 3 3 1\n')]
 
3501
        attribs['_id_number'] = 2
 
3502
        attribs['_tree_path_ids'] = {
 
3503
            'file': 'new-1',
 
3504
            '': 'new-0',}
 
3505
        attribs['_removed_contents'] = ['new-1']
 
3506
        contents = [('new-1', 'file',
 
3507
                     'i 1\nz\n\nc 0 1 1 1\ni 1\nx\n\nc 0 3 3 1\n')]
3604
3508
        return self.make_records(attribs, contents)
3605
3509
 
3606
3510
    def test_serialize_modification(self):
3607
3511
        tt, LINES = self.make_modification_preview()
3608
 
        trans_id = tt.trans_id_file_id(b'file-id')
 
3512
        trans_id = tt.trans_id_file_id('file-id')
3609
3513
        tt.delete_contents(trans_id)
3610
3514
        tt.create_file(LINES, trans_id)
3611
3515
        self.assertSerializesTo(self.modification_records(), tt)
3613
3517
    def test_deserialize_modification(self):
3614
3518
        tt, LINES = self.make_modification_preview()
3615
3519
        tt.deserialize(iter(self.modification_records()))
3616
 
        self.assertFileEqual(b''.join(LINES), tt._limbo_name('new-1'))
 
3520
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
3617
3521
 
3618
3522
    def make_kind_change_preview(self):
3619
 
        LINES = b'a\nb\nc\nd\n'
 
3523
        LINES = 'a\nb\nc\nd\n'
3620
3524
        tree = self.make_branch_and_tree('tree')
3621
3525
        self.build_tree(['tree/foo/'])
3622
 
        tree.add('foo', b'foo-id')
3623
 
        return self.get_preview(tree), [LINES]
 
3526
        tree.add('foo', 'foo-id')
 
3527
        return self.get_preview(tree), LINES
3624
3528
 
3625
3529
    def kind_change_records(self):
3626
3530
        attribs = self.default_attribs()
3627
 
        attribs[b'_id_number'] = 2
3628
 
        attribs[b'_tree_path_ids'] = {
3629
 
            b'foo': b'new-1',
3630
 
            b'': b'new-0', }
3631
 
        attribs[b'_removed_contents'] = [b'new-1']
3632
 
        contents = [(b'new-1', b'file',
3633
 
                     b'i 4\na\nb\nc\nd\n\n')]
 
3531
        attribs['_id_number'] = 2
 
3532
        attribs['_tree_path_ids'] = {
 
3533
            'foo': 'new-1',
 
3534
            '': 'new-0',}
 
3535
        attribs['_removed_contents'] = ['new-1']
 
3536
        contents = [('new-1', 'file',
 
3537
                     'i 4\na\nb\nc\nd\n\n')]
3634
3538
        return self.make_records(attribs, contents)
3635
3539
 
3636
3540
    def test_serialize_kind_change(self):
3637
3541
        tt, LINES = self.make_kind_change_preview()
3638
 
        trans_id = tt.trans_id_file_id(b'foo-id')
 
3542
        trans_id = tt.trans_id_file_id('foo-id')
3639
3543
        tt.delete_contents(trans_id)
3640
3544
        tt.create_file(LINES, trans_id)
3641
3545
        self.assertSerializesTo(self.kind_change_records(), tt)
3643
3547
    def test_deserialize_kind_change(self):
3644
3548
        tt, LINES = self.make_kind_change_preview()
3645
3549
        tt.deserialize(iter(self.kind_change_records()))
3646
 
        self.assertFileEqual(b''.join(LINES), tt._limbo_name('new-1'))
 
3550
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
3647
3551
 
3648
3552
    def make_add_contents_preview(self):
3649
 
        LINES = b'a\nb\nc\nd\n'
 
3553
        LINES = 'a\nb\nc\nd\n'
3650
3554
        tree = self.make_branch_and_tree('tree')
3651
3555
        self.build_tree(['tree/foo'])
3652
3556
        tree.add('foo')
3655
3559
 
3656
3560
    def add_contents_records(self):
3657
3561
        attribs = self.default_attribs()
3658
 
        attribs[b'_id_number'] = 2
3659
 
        attribs[b'_tree_path_ids'] = {
3660
 
            b'foo': b'new-1',
3661
 
            b'': b'new-0', }
3662
 
        contents = [(b'new-1', b'file',
3663
 
                     b'i 4\na\nb\nc\nd\n\n')]
 
3562
        attribs['_id_number'] = 2
 
3563
        attribs['_tree_path_ids'] = {
 
3564
            'foo': 'new-1',
 
3565
            '': 'new-0',}
 
3566
        contents = [('new-1', 'file',
 
3567
                     'i 4\na\nb\nc\nd\n\n')]
3664
3568
        return self.make_records(attribs, contents)
3665
3569
 
3666
3570
    def test_serialize_add_contents(self):
3667
3571
        tt, LINES = self.make_add_contents_preview()
3668
3572
        trans_id = tt.trans_id_tree_path('foo')
3669
 
        tt.create_file([LINES], trans_id)
 
3573
        tt.create_file(LINES, trans_id)
3670
3574
        self.assertSerializesTo(self.add_contents_records(), tt)
3671
3575
 
3672
3576
    def test_deserialize_add_contents(self):
3675
3579
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
3676
3580
 
3677
3581
    def test_get_parents_lines(self):
3678
 
        LINES_ONE = b'aa\nbb\ncc\ndd\n'
 
3582
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
 
3583
        LINES_TWO = 'z\nbb\nx\ndd\n'
3679
3584
        tree = self.make_branch_and_tree('tree')
3680
3585
        self.build_tree_contents([('tree/file', LINES_ONE)])
3681
 
        tree.add('file', b'file-id')
 
3586
        tree.add('file', 'file-id')
3682
3587
        tt = self.get_preview(tree)
3683
3588
        trans_id = tt.trans_id_tree_path('file')
3684
 
        self.assertEqual(([b'aa\n', b'bb\n', b'cc\n', b'dd\n'],),
3685
 
                         tt._get_parents_lines(trans_id))
 
3589
        self.assertEqual((['aa\n', 'bb\n', 'cc\n', 'dd\n'],),
 
3590
            tt._get_parents_lines(trans_id))
3686
3591
 
3687
3592
    def test_get_parents_texts(self):
3688
 
        LINES_ONE = b'aa\nbb\ncc\ndd\n'
 
3593
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
 
3594
        LINES_TWO = 'z\nbb\nx\ndd\n'
3689
3595
        tree = self.make_branch_and_tree('tree')
3690
3596
        self.build_tree_contents([('tree/file', LINES_ONE)])
3691
 
        tree.add('file', b'file-id')
 
3597
        tree.add('file', 'file-id')
3692
3598
        tt = self.get_preview(tree)
3693
3599
        trans_id = tt.trans_id_tree_path('file')
3694
3600
        self.assertEqual((LINES_ONE,),
3695
 
                         tt._get_parents_texts(trans_id))
 
3601
            tt._get_parents_texts(trans_id))
3696
3602
 
3697
3603
 
3698
3604
class TestOrphan(tests.TestCaseWithTransport):
3704
3610
        self.assertRaises(NotImplementedError, tt.new_orphan, 'foo', 'bar')
3705
3611
 
3706
3612
    def _set_orphan_policy(self, wt, policy):
3707
 
        wt.branch.get_config_stack().set('transform.orphan_policy',
3708
 
                                         policy)
 
3613
        wt.branch.get_config_stack().set('bzr.transform.orphan_policy',
 
3614
                                               policy)
3709
3615
 
3710
3616
    def _prepare_orphan(self, wt):
3711
3617
        self.build_tree(['dir/', 'dir/file', 'dir/foo'])
3712
 
        wt.add(['dir', 'dir/file'], [b'dir-id', b'file-id'])
 
3618
        wt.add(['dir', 'dir/file'], ['dir-id', 'file-id'])
3713
3619
        wt.commit('add dir and file ignoring foo')
3714
3620
        tt = transform.TreeTransform(wt)
3715
3621
        self.addCleanup(tt.finalize)
3732
3638
        self._set_orphan_policy(wt, 'move')
3733
3639
        tt, orphan_tid = self._prepare_orphan(wt)
3734
3640
        warnings = []
3735
 
 
3736
3641
        def warning(*args):
3737
3642
            warnings.append(args[0] % args[1:])
3738
3643
        self.overrideAttr(trace, 'warning', warning)
3739
3644
        remaining_conflicts = resolve_conflicts(tt)
3740
 
        self.assertEqual(['dir/foo has been orphaned in brz-orphans'],
3741
 
                         warnings)
 
3645
        self.assertEqual(['dir/foo has been orphaned in bzr-orphans'],
 
3646
                          warnings)
3742
3647
        # Yeah for resolved conflicts !
3743
3648
        self.assertLength(0, remaining_conflicts)
3744
3649
        # We have a new orphan
3745
3650
        self.assertEqual('foo.~1~', tt.final_name(orphan_tid))
3746
 
        self.assertEqual('brz-orphans',
3747
 
                         tt.final_name(tt.final_parent(orphan_tid)))
 
3651
        self.assertEqual('bzr-orphans',
 
3652
                          tt.final_name(tt.final_parent(orphan_tid)))
3748
3653
 
3749
3654
    def test_never_orphan(self):
3750
3655
        wt = self.make_branch_and_tree('.')
3775
3680
        self._set_orphan_policy(wt, 'donttouchmypreciouuus')
3776
3681
        tt, orphan_tid = self._prepare_orphan(wt)
3777
3682
        warnings = []
3778
 
 
3779
3683
        def warning(*args):
3780
3684
            warnings.append(args[0] % args[1:])
3781
3685
        self.overrideAttr(trace, 'warning', warning)
3802
3706
 
3803
3707
    def test_pre_commit_hooks(self):
3804
3708
        calls = []
3805
 
 
3806
3709
        def record_pre_transform(tree, tt):
3807
3710
            calls.append((tree, tt))
3808
 
        MutableTree.hooks.install_named_hook(
3809
 
            'pre_transform', record_pre_transform, "Pre transform")
 
3711
        MutableTree.hooks.install_named_hook('pre_transform',
 
3712
            record_pre_transform, "Pre transform")
3810
3713
        transform, root = self.get_transform()
3811
3714
        old_root_id = transform.tree_file_id(root)
3812
3715
        transform.apply()
3813
 
        self.assertEqual(old_root_id, self.wt.path2id(''))
 
3716
        self.assertEqual(old_root_id, self.wt.get_root_id())
3814
3717
        self.assertEqual([(self.wt, transform)], calls)
3815
3718
 
3816
3719
    def test_post_commit_hooks(self):
3817
3720
        calls = []
3818
 
 
3819
3721
        def record_post_transform(tree, tt):
3820
3722
            calls.append((tree, tt))
3821
 
        MutableTree.hooks.install_named_hook(
3822
 
            'post_transform', record_post_transform, "Post transform")
 
3723
        MutableTree.hooks.install_named_hook('post_transform',
 
3724
            record_post_transform, "Post transform")
3823
3725
        transform, root = self.get_transform()
3824
3726
        old_root_id = transform.tree_file_id(root)
3825
3727
        transform.apply()
3826
 
        self.assertEqual(old_root_id, self.wt.path2id(''))
 
3728
        self.assertEqual(old_root_id, self.wt.get_root_id())
3827
3729
        self.assertEqual([(self.wt, transform)], calls)
3828
 
 
3829
 
 
3830
 
class TestLinkTree(tests.TestCaseWithTransport):
3831
 
 
3832
 
    _test_needs_features = [HardlinkFeature]
3833
 
 
3834
 
    def setUp(self):
3835
 
        tests.TestCaseWithTransport.setUp(self)
3836
 
        self.parent_tree = self.make_branch_and_tree('parent')
3837
 
        self.parent_tree.lock_write()
3838
 
        self.addCleanup(self.parent_tree.unlock)
3839
 
        self.build_tree_contents([('parent/foo', b'bar')])
3840
 
        self.parent_tree.add('foo')
3841
 
        self.parent_tree.commit('added foo')
3842
 
        child_controldir = self.parent_tree.controldir.sprout('child')
3843
 
        self.child_tree = child_controldir.open_workingtree()
3844
 
 
3845
 
    def hardlinked(self):
3846
 
        parent_stat = os.lstat(self.parent_tree.abspath('foo'))
3847
 
        child_stat = os.lstat(self.child_tree.abspath('foo'))
3848
 
        return parent_stat.st_ino == child_stat.st_ino
3849
 
 
3850
 
    def test_link_fails_if_modified(self):
3851
 
        """If the file to be linked has modified text, don't link."""
3852
 
        self.build_tree_contents([('child/foo', b'baz')])
3853
 
        transform.link_tree(self.child_tree, self.parent_tree)
3854
 
        self.assertFalse(self.hardlinked())
3855
 
 
3856
 
    def test_link_fails_if_execute_bit_changed(self):
3857
 
        """If the file to be linked has modified execute bit, don't link."""
3858
 
        tt = TreeTransform(self.child_tree)
3859
 
        try:
3860
 
            trans_id = tt.trans_id_tree_path('foo')
3861
 
            tt.set_executability(True, trans_id)
3862
 
            tt.apply()
3863
 
        finally:
3864
 
            tt.finalize()
3865
 
        transform.link_tree(self.child_tree, self.parent_tree)
3866
 
        self.assertFalse(self.hardlinked())
3867
 
 
3868
 
    def test_link_succeeds_if_unmodified(self):
3869
 
        """If the file to be linked is unmodified, link"""
3870
 
        transform.link_tree(self.child_tree, self.parent_tree)
3871
 
        self.assertTrue(self.hardlinked())