43
42
# '\xc3\xae' == u'\xee' == i with hat
44
43
# So these are u'path' and 'id' only with a circle and a hat. (shappo?)
45
44
example_conflicts = conflicts.ConflictList(
46
[conflicts.MissingParent('Not deleting', u'p\xe5thg', b'\xc3\xaedg'),
47
conflicts.ContentsConflict(u'p\xe5tha', None, b'\xc3\xaeda'),
45
[conflicts.MissingParent('Not deleting', u'p\xe5thg', '\xc3\xaedg'),
46
conflicts.ContentsConflict(u'p\xe5tha', None, '\xc3\xaeda'),
48
47
conflicts.TextConflict(u'p\xe5tha'),
49
conflicts.PathConflict(u'p\xe5thb', u'p\xe5thc', b'\xc3\xaedb'),
48
conflicts.PathConflict(u'p\xe5thb', u'p\xe5thc', '\xc3\xaedb'),
50
49
conflicts.DuplicateID('Unversioned existing file',
51
50
u'p\xe5thc', u'p\xe5thc2',
52
b'\xc3\xaedc', b'\xc3\xaedc'),
53
conflicts.DuplicateEntry('Moved existing file to',
54
u'p\xe5thdd.moved', u'p\xe5thd',
56
conflicts.ParentLoop('Cancelled move', u'p\xe5the', u'p\xe5th2e',
57
None, b'\xc3\xaed2e'),
58
conflicts.UnversionedParent('Versioned directory',
59
u'p\xe5thf', b'\xc3\xaedf'),
60
conflicts.NonDirectoryParent('Created directory',
61
u'p\xe5thg', b'\xc3\xaedg'),
51
'\xc3\xaedc', '\xc3\xaedc'),
52
conflicts.DuplicateEntry('Moved existing file to',
53
u'p\xe5thdd.moved', u'p\xe5thd',
55
conflicts.ParentLoop('Cancelled move', u'p\xe5the', u'p\xe5th2e',
57
conflicts.UnversionedParent('Versioned directory',
58
u'p\xe5thf', '\xc3\xaedf'),
59
conflicts.NonDirectoryParent('Created directory',
60
u'p\xe5thg', '\xc3\xaedg'),
65
64
def vary_by_conflicts():
109
108
check_select(clist(), tree_conflicts,
110
109
['foo'], ignore_misses=True, recurse=True)
111
check_select(tree_conflicts, clist(), ['foo'], ignore_misses=True)
110
check_select (tree_conflicts, clist(), ['foo'], ignore_misses=True)
113
112
def test_resolve_conflicts_recursive(self):
114
113
tree = self.make_branch_and_tree('.')
115
114
self.build_tree(['dir/', 'dir/hello'])
116
115
tree.add(['dir', 'dir/hello'])
118
dirhello = conflicts.ConflictList(
119
[conflicts.TextConflict('dir/hello')])
117
dirhello = conflicts.ConflictList([conflicts.TextConflict('dir/hello')])
120
118
tree.set_conflicts(dirhello)
122
120
conflicts.resolve(tree, ['dir'], recursive=False, ignore_misses=True)
131
129
scenarios = scenarios.multiply_scenarios(vary_by_conflicts())
133
131
def test_stringification(self):
134
text = str(self.conflict)
132
text = unicode(self.conflict)
135
133
self.assertContainsString(text, self.conflict.path)
136
134
self.assertContainsString(text.lower(), "conflict")
137
135
self.assertContainsString(repr(self.conflict),
138
self.conflict.__class__.__name__)
136
self.conflict.__class__.__name__)
140
138
def test_stanza_roundtrip(self):
141
139
p = self.conflict
142
140
o = conflicts.Conflict.factory(**p.as_stanza().as_dict())
143
141
self.assertEqual(o, p)
145
self.assertIsInstance(o.path, str)
143
self.assertIsInstance(o.path, unicode)
147
145
if o.file_id is not None:
148
self.assertIsInstance(o.file_id, bytes)
146
self.assertIsInstance(o.file_id, str)
150
148
conflict_path = getattr(o, 'conflict_path', None)
151
149
if conflict_path is not None:
152
self.assertIsInstance(conflict_path, str)
150
self.assertIsInstance(conflict_path, unicode)
154
152
conflict_file_id = getattr(o, 'conflict_file_id', None)
155
153
if conflict_file_id is not None:
156
self.assertIsInstance(conflict_file_id, bytes)
154
self.assertIsInstance(conflict_file_id, str)
158
156
def test_stanzification(self):
159
157
stanza = self.conflict.as_stanza()
306
304
# Create an empty trunk
307
305
builder.build_snapshot(None, [
308
('add', (u'', b'root-id', 'directory', ''))],
309
revision_id=b'start')
306
('add', ('', 'root-id', 'directory', ''))],
310
308
# Add a minimal base content
311
309
base_actions = self._get_actions(self._base_actions)()
312
builder.build_snapshot([b'start'], base_actions, revision_id=b'base')
310
builder.build_snapshot(['start'], base_actions, revision_id='base')
313
311
# Modify the base content in branch
314
312
actions_other = self._get_actions(self._other['actions'])()
315
builder.build_snapshot([b'base'], actions_other, revision_id=b'other')
313
builder.build_snapshot(['base'], actions_other, revision_id='other')
316
314
# Modify the base content in trunk
317
315
actions_this = self._get_actions(self._this['actions'])()
318
builder.build_snapshot([b'base'], actions_this, revision_id=b'this')
316
builder.build_snapshot(['base'], actions_this, revision_id='this')
319
317
# builder.get_branch() tip is now 'this'
321
319
builder.finish_series()
379
377
# File modified on both sides
380
378
(dict(_base_actions='create_file',
381
_path='file', _file_id=b'file-id'),
379
_path='file', _file_id='file-id'),
382
380
('filed_modified_A',
383
381
dict(actions='modify_file_A', check='file_has_content_A')),
384
382
('file_modified_B',
385
383
dict(actions='modify_file_B', check='file_has_content_B')),),
386
384
# File modified on both sides in dir
387
385
(dict(_base_actions='create_file_in_dir',
388
_path='dir/file', _file_id=b'file-id'),
386
_path='dir/file', _file_id='file-id'),
389
387
('filed_modified_A_in_dir',
390
dict(actions='modify_file_A_in_dir',
388
dict(actions='modify_file_A',
391
389
check='file_in_dir_has_content_A')),
392
390
('file_modified_B',
393
dict(actions='modify_file_B_in_dir',
391
dict(actions='modify_file_B',
394
392
check='file_in_dir_has_content_B')),),
397
395
def do_create_file(self, path='file'):
398
return [('add', (path, b'file-id', 'file', b'trunk content\n'))]
396
return [('add', (path, 'file-id', 'file', 'trunk content\n'))]
400
398
def do_modify_file_A(self):
401
return [('modify', ('file', b'trunk content\nfeature A\n'))]
399
return [('modify', ('file-id', 'trunk content\nfeature A\n'))]
403
401
def do_modify_file_B(self):
404
return [('modify', ('file', b'trunk content\nfeature B\n'))]
406
def do_modify_file_A_in_dir(self):
407
return [('modify', ('dir/file', b'trunk content\nfeature A\n'))]
409
def do_modify_file_B_in_dir(self):
410
return [('modify', ('dir/file', b'trunk content\nfeature B\n'))]
402
return [('modify', ('file-id', 'trunk content\nfeature B\n'))]
412
404
def check_file_has_content_A(self, path='file'):
413
self.assertFileEqual(b'trunk content\nfeature A\n',
405
self.assertFileEqual('trunk content\nfeature A\n',
414
406
osutils.pathjoin('branch', path))
416
408
def check_file_has_content_B(self, path='file'):
417
self.assertFileEqual(b'trunk content\nfeature B\n',
409
self.assertFileEqual('trunk content\nfeature B\n',
418
410
osutils.pathjoin('branch', path))
420
412
def do_create_file_in_dir(self):
421
return [('add', ('dir', b'dir-id', 'directory', '')),
422
] + self.do_create_file('dir/file')
413
return [('add', ('dir', 'dir-id', 'directory', '')),
414
] + self.do_create_file('dir/file')
424
416
def check_file_in_dir_has_content_A(self):
425
417
self.check_file_has_content_A('dir/file')
450
442
# File modified/deleted
451
443
(dict(_base_actions='create_file',
452
_path='file', _file_id=b'file-id'),
444
_path='file', _file_id='file-id'),
453
445
('file_modified',
454
446
dict(actions='modify_file', check='file_has_more_content')),
456
448
dict(actions='delete_file', check='file_doesnt_exist')),),
457
449
# File renamed-modified/deleted
458
450
(dict(_base_actions='create_file',
459
_path='new-file', _file_id=b'file-id'),
451
_path='new-file', _file_id='file-id'),
460
452
('file_renamed_and_modified',
461
453
dict(actions='modify_and_rename_file',
462
454
check='file_renamed_and_more_content')),
464
456
dict(actions='delete_file', check='file_doesnt_exist')),),
465
457
# File modified/deleted in dir
466
458
(dict(_base_actions='create_file_in_dir',
467
_path='dir/file', _file_id=b'file-id'),
459
_path='dir/file', _file_id='file-id'),
468
460
('file_modified_in_dir',
469
461
dict(actions='modify_file_in_dir',
470
462
check='file_in_dir_has_more_content')),
471
463
('file_deleted_in_dir',
472
dict(actions='delete_file_in_dir',
464
dict(actions='delete_file',
473
465
check='file_in_dir_doesnt_exist')),),
476
468
def do_create_file(self):
477
return [('add', ('file', b'file-id', 'file', b'trunk content\n'))]
469
return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
479
471
def do_modify_file(self):
480
return [('modify', ('file', b'trunk content\nmore content\n'))]
472
return [('modify', ('file-id', 'trunk content\nmore content\n'))]
482
474
def do_modify_and_rename_file(self):
483
return [('modify', ('new-file', b'trunk content\nmore content\n')),
475
return [('modify', ('file-id', 'trunk content\nmore content\n')),
484
476
('rename', ('file', 'new-file'))]
486
478
def check_file_has_more_content(self):
487
self.assertFileEqual(b'trunk content\nmore content\n', 'branch/file')
479
self.assertFileEqual('trunk content\nmore content\n', 'branch/file')
489
481
def check_file_renamed_and_more_content(self):
490
self.assertFileEqual(
491
b'trunk content\nmore content\n', 'branch/new-file')
482
self.assertFileEqual('trunk content\nmore content\n', 'branch/new-file')
493
484
def do_delete_file(self):
494
return [('unversion', 'file')]
496
def do_delete_file_in_dir(self):
497
return [('unversion', 'dir/file')]
485
return [('unversion', 'file-id')]
499
487
def check_file_doesnt_exist(self):
500
488
self.assertPathDoesNotExist('branch/file')
502
490
def do_create_file_in_dir(self):
503
return [('add', ('dir', b'dir-id', 'directory', '')),
504
('add', ('dir/file', b'file-id', 'file', b'trunk content\n'))]
491
return [('add', ('dir', 'dir-id', 'directory', '')),
492
('add', ('dir/file', 'file-id', 'file', 'trunk content\n'))]
506
494
def do_modify_file_in_dir(self):
507
return [('modify', ('dir/file', b'trunk content\nmore content\n'))]
495
return [('modify', ('file-id', 'trunk content\nmore content\n'))]
509
497
def check_file_in_dir_has_more_content(self):
510
self.assertFileEqual(
511
b'trunk content\nmore content\n', 'branch/dir/file')
498
self.assertFileEqual('trunk content\nmore content\n', 'branch/dir/file')
513
500
def check_file_in_dir_doesnt_exist(self):
514
501
self.assertPathDoesNotExist('branch/dir/file')
538
525
(dict(_base_actions='create_file'),
540
527
dict(actions='rename_file', check='file_renamed',
541
path='new-file', file_id=b'file-id')),
528
path='new-file', file_id='file-id')),
543
530
dict(actions='delete_file', check='file_doesnt_exist',
544
531
# PathConflicts deletion handling requires a special
545
532
# hard-coded value
546
path='<deleted>', file_id=b'file-id')),),
533
path='<deleted>', file_id='file-id')),),
547
534
# File renamed/deleted in dir
548
535
(dict(_base_actions='create_file_in_dir'),
549
536
('file_renamed_in_dir',
550
537
dict(actions='rename_file_in_dir', check='file_in_dir_renamed',
551
path='dir/new-file', file_id=b'file-id')),
538
path='dir/new-file', file_id='file-id')),
553
dict(actions='delete_file_in_dir', check='file_in_dir_doesnt_exist',
540
dict(actions='delete_file', check='file_in_dir_doesnt_exist',
554
541
# PathConflicts deletion handling requires a special
555
542
# hard-coded value
556
path='<deleted>', file_id=b'file-id')),),
543
path='<deleted>', file_id='file-id')),),
557
544
# File renamed/renamed differently
558
545
(dict(_base_actions='create_file'),
560
547
dict(actions='rename_file', check='file_renamed',
561
path='new-file', file_id=b'file-id')),
548
path='new-file', file_id='file-id')),
562
549
('file_renamed2',
563
550
dict(actions='rename_file2', check='file_renamed2',
564
path='new-file2', file_id=b'file-id')),),
551
path='new-file2', file_id='file-id')),),
565
552
# Dir renamed/deleted
566
553
(dict(_base_actions='create_dir'),
568
555
dict(actions='rename_dir', check='dir_renamed',
569
path='new-dir', file_id=b'dir-id')),
556
path='new-dir', file_id='dir-id')),
571
558
dict(actions='delete_dir', check='dir_doesnt_exist',
572
559
# PathConflicts deletion handling requires a special
573
560
# hard-coded value
574
path='<deleted>', file_id=b'dir-id')),),
561
path='<deleted>', file_id='dir-id')),),
575
562
# Dir renamed/renamed differently
576
563
(dict(_base_actions='create_dir'),
578
565
dict(actions='rename_dir', check='dir_renamed',
579
path='new-dir', file_id=b'dir-id')),
566
path='new-dir', file_id='dir-id')),
581
568
dict(actions='rename_dir2', check='dir_renamed2',
582
path='new-dir2', file_id=b'dir-id')),),
569
path='new-dir2', file_id='dir-id')),),
585
572
def do_create_file(self):
586
return [('add', ('file', b'file-id', 'file', b'trunk content\n'))]
573
return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
588
575
def do_create_dir(self):
589
return [('add', ('dir', b'dir-id', 'directory', ''))]
576
return [('add', ('dir', 'dir-id', 'directory', ''))]
591
578
def do_rename_file(self):
592
579
return [('rename', ('file', 'new-file'))]
617
604
self.assertPathExists('branch/new-dir2')
619
606
def do_delete_file(self):
620
return [('unversion', 'file')]
622
def do_delete_file_in_dir(self):
623
return [('unversion', 'dir/file')]
607
return [('unversion', 'file-id')]
625
609
def check_file_doesnt_exist(self):
626
610
self.assertPathDoesNotExist('branch/file')
628
612
def do_delete_dir(self):
629
return [('unversion', 'dir')]
613
return [('unversion', 'dir-id')]
631
615
def check_dir_doesnt_exist(self):
632
616
self.assertPathDoesNotExist('branch/dir')
634
618
def do_create_file_in_dir(self):
635
return [('add', ('dir', b'dir-id', 'directory', '')),
636
('add', ('dir/file', b'file-id', 'file', b'trunk content\n'))]
619
return [('add', ('dir', 'dir-id', 'directory', '')),
620
('add', ('dir/file', 'file-id', 'file', 'trunk content\n'))]
638
622
def do_rename_file_in_dir(self):
639
623
return [('rename', ('dir/file', 'dir/new-file'))]
689
673
(dict(_base_actions='nothing'),
690
674
('filea_created',
691
675
dict(actions='create_file_a', check='file_content_a',
692
path='file', file_id=b'file-a-id')),
676
path='file', file_id='file-a-id')),
693
677
('fileb_created',
694
678
dict(actions='create_file_b', check='file_content_b',
695
path='file', file_id=b'file-b-id')),),
679
path='file', file_id='file-b-id')),),
696
680
# File created with different file-ids but deleted on one side
697
681
(dict(_base_actions='create_file_a'),
698
682
('filea_replaced',
699
683
dict(actions='replace_file_a_by_b', check='file_content_b',
700
path='file', file_id=b'file-b-id')),
684
path='file', file_id='file-b-id')),
701
685
('filea_modified',
702
686
dict(actions='modify_file_a', check='file_new_content',
703
path='file', file_id=b'file-a-id')),),
687
path='file', file_id='file-a-id')),),
706
690
def do_nothing(self):
709
693
def do_create_file_a(self):
710
return [('add', ('file', b'file-a-id', 'file', b'file a content\n'))]
694
return [('add', ('file', 'file-a-id', 'file', 'file a content\n'))]
712
696
def check_file_content_a(self):
713
self.assertFileEqual(b'file a content\n', 'branch/file')
697
self.assertFileEqual('file a content\n', 'branch/file')
715
699
def do_create_file_b(self):
716
return [('add', ('file', b'file-b-id', 'file', b'file b content\n'))]
700
return [('add', ('file', 'file-b-id', 'file', 'file b content\n'))]
718
702
def check_file_content_b(self):
719
self.assertFileEqual(b'file b content\n', 'branch/file')
703
self.assertFileEqual('file b content\n', 'branch/file')
721
705
def do_replace_file_a_by_b(self):
722
return [('unversion', 'file'),
723
('add', ('file', b'file-b-id', 'file', b'file b content\n'))]
706
return [('unversion', 'file-a-id'),
707
('add', ('file', 'file-b-id', 'file', 'file b content\n'))]
725
709
def do_modify_file_a(self):
726
return [('modify', ('file', b'new content\n'))]
710
return [('modify', ('file-a-id', 'new content\n'))]
728
712
def check_file_new_content(self):
729
self.assertFileEqual(b'new content\n', 'branch/file')
713
self.assertFileEqual('new content\n', 'branch/file')
731
715
def _get_resolve_path_arg(self, wt, action):
732
716
return self._this['path']
936
920
(dict(_base_actions='create_dir1_dir2'),
937
921
('dir1_into_dir2',
938
922
dict(actions='move_dir1_into_dir2', check='dir1_moved',
939
dir_id=b'dir1-id', target_id=b'dir2-id', xfail=False)),
923
dir_id='dir1-id', target_id='dir2-id', xfail=False)),
940
924
('dir2_into_dir1',
941
925
dict(actions='move_dir2_into_dir1', check='dir2_moved',
942
dir_id=b'dir2-id', target_id=b'dir1-id', xfail=False))),
926
dir_id='dir2-id', target_id='dir1-id', xfail=False))),
943
927
# Subdirs moved into each other
944
928
(dict(_base_actions='create_dir1_4'),
945
929
('dir1_into_dir4',
946
930
dict(actions='move_dir1_into_dir4', check='dir1_2_moved',
947
dir_id=b'dir1-id', target_id=b'dir4-id', xfail=True)),
931
dir_id='dir1-id', target_id='dir4-id', xfail=True)),
948
932
('dir3_into_dir2',
949
933
dict(actions='move_dir3_into_dir2', check='dir3_4_moved',
950
dir_id=b'dir3-id', target_id=b'dir2-id', xfail=True))),
934
dir_id='dir3-id', target_id='dir2-id', xfail=True))),
953
937
def do_create_dir1_dir2(self):
954
return [('add', ('dir1', b'dir1-id', 'directory', '')),
955
('add', ('dir2', b'dir2-id', 'directory', '')), ]
938
return [('add', ('dir1', 'dir1-id', 'directory', '')),
939
('add', ('dir2', 'dir2-id', 'directory', '')),]
957
941
def do_move_dir1_into_dir2(self):
958
942
return [('rename', ('dir1', 'dir2/dir1'))]
969
953
self.assertPathExists('branch/dir1/dir2')
971
955
def do_create_dir1_4(self):
972
return [('add', ('dir1', b'dir1-id', 'directory', '')),
973
('add', ('dir1/dir2', b'dir2-id', 'directory', '')),
974
('add', ('dir3', b'dir3-id', 'directory', '')),
975
('add', ('dir3/dir4', b'dir4-id', 'directory', '')), ]
956
return [('add', ('dir1', 'dir1-id', 'directory', '')),
957
('add', ('dir1/dir2', 'dir2-id', 'directory', '')),
958
('add', ('dir3', 'dir3-id', 'directory', '')),
959
('add', ('dir3/dir4', 'dir4-id', 'directory', '')),]
977
961
def do_move_dir1_into_dir4(self):
978
962
return [('rename', ('dir1', 'dir3/dir4/dir1'))]