/brz/remove-bazaar

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

« back to all changes in this revision

Viewing changes to breezy/tests/test_transform.py

  • Committer: Jelmer Vernooij
  • Date: 2020-03-22 01:35:14 UTC
  • mfrom: (7490.7.6 work)
  • mto: This revision was merged to the branch mainline in revision 7499.
  • Revision ID: jelmer@jelmer.uk-20200322013514-7vw1ntwho04rcuj3
merge lp:brz/3.1.

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