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()
304
302
builder.start_series()
306
304
# Create an empty trunk
307
builder.build_snapshot(None, [
308
('add', (u'', b'root-id', 'directory', ''))],
309
revision_id=b'start')
305
builder.build_snapshot('start', None, [
306
('add', ('', 'root-id', 'directory', ''))])
310
307
# Add a minimal base content
311
308
base_actions = self._get_actions(self._base_actions)()
312
builder.build_snapshot([b'start'], base_actions, revision_id=b'base')
309
builder.build_snapshot('base', ['start'], base_actions)
313
310
# Modify the base content in branch
314
311
actions_other = self._get_actions(self._other['actions'])()
315
builder.build_snapshot([b'base'], actions_other, revision_id=b'other')
312
builder.build_snapshot('other', ['base'], actions_other)
316
313
# Modify the base content in trunk
317
314
actions_this = self._get_actions(self._this['actions'])()
318
builder.build_snapshot([b'base'], actions_this, revision_id=b'this')
315
builder.build_snapshot('this', ['base'], actions_this)
319
316
# builder.get_branch() tip is now 'this'
321
318
builder.finish_series()
379
376
# File modified on both sides
380
377
(dict(_base_actions='create_file',
381
_path='file', _file_id=b'file-id'),
378
_path='file', _file_id='file-id'),
382
379
('filed_modified_A',
383
380
dict(actions='modify_file_A', check='file_has_content_A')),
384
381
('file_modified_B',
385
382
dict(actions='modify_file_B', check='file_has_content_B')),),
386
383
# File modified on both sides in dir
387
384
(dict(_base_actions='create_file_in_dir',
388
_path='dir/file', _file_id=b'file-id'),
385
_path='dir/file', _file_id='file-id'),
389
386
('filed_modified_A_in_dir',
390
dict(actions='modify_file_A_in_dir',
387
dict(actions='modify_file_A',
391
388
check='file_in_dir_has_content_A')),
392
389
('file_modified_B',
393
dict(actions='modify_file_B_in_dir',
390
dict(actions='modify_file_B',
394
391
check='file_in_dir_has_content_B')),),
397
394
def do_create_file(self, path='file'):
398
return [('add', (path, b'file-id', 'file', b'trunk content\n'))]
395
return [('add', (path, 'file-id', 'file', 'trunk content\n'))]
400
397
def do_modify_file_A(self):
401
return [('modify', ('file', b'trunk content\nfeature A\n'))]
398
return [('modify', ('file-id', 'trunk content\nfeature A\n'))]
403
400
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'))]
401
return [('modify', ('file-id', 'trunk content\nfeature B\n'))]
412
403
def check_file_has_content_A(self, path='file'):
413
self.assertFileEqual(b'trunk content\nfeature A\n',
404
self.assertFileEqual('trunk content\nfeature A\n',
414
405
osutils.pathjoin('branch', path))
416
407
def check_file_has_content_B(self, path='file'):
417
self.assertFileEqual(b'trunk content\nfeature B\n',
408
self.assertFileEqual('trunk content\nfeature B\n',
418
409
osutils.pathjoin('branch', path))
420
411
def do_create_file_in_dir(self):
421
return [('add', ('dir', b'dir-id', 'directory', '')),
422
] + self.do_create_file('dir/file')
412
return [('add', ('dir', 'dir-id', 'directory', '')),
413
] + self.do_create_file('dir/file')
424
415
def check_file_in_dir_has_content_A(self):
425
416
self.check_file_has_content_A('dir/file')
450
441
# File modified/deleted
451
442
(dict(_base_actions='create_file',
452
_path='file', _file_id=b'file-id'),
443
_path='file', _file_id='file-id'),
453
444
('file_modified',
454
445
dict(actions='modify_file', check='file_has_more_content')),
456
447
dict(actions='delete_file', check='file_doesnt_exist')),),
457
448
# File renamed-modified/deleted
458
449
(dict(_base_actions='create_file',
459
_path='new-file', _file_id=b'file-id'),
450
_path='new-file', _file_id='file-id'),
460
451
('file_renamed_and_modified',
461
452
dict(actions='modify_and_rename_file',
462
453
check='file_renamed_and_more_content')),
464
455
dict(actions='delete_file', check='file_doesnt_exist')),),
465
456
# File modified/deleted in dir
466
457
(dict(_base_actions='create_file_in_dir',
467
_path='dir/file', _file_id=b'file-id'),
458
_path='dir/file', _file_id='file-id'),
468
459
('file_modified_in_dir',
469
460
dict(actions='modify_file_in_dir',
470
461
check='file_in_dir_has_more_content')),
471
462
('file_deleted_in_dir',
472
dict(actions='delete_file_in_dir',
463
dict(actions='delete_file',
473
464
check='file_in_dir_doesnt_exist')),),
476
467
def do_create_file(self):
477
return [('add', ('file', b'file-id', 'file', b'trunk content\n'))]
468
return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
479
470
def do_modify_file(self):
480
return [('modify', ('file', b'trunk content\nmore content\n'))]
471
return [('modify', ('file-id', 'trunk content\nmore content\n'))]
482
473
def do_modify_and_rename_file(self):
483
return [('modify', ('new-file', b'trunk content\nmore content\n')),
474
return [('modify', ('file-id', 'trunk content\nmore content\n')),
484
475
('rename', ('file', 'new-file'))]
486
477
def check_file_has_more_content(self):
487
self.assertFileEqual(b'trunk content\nmore content\n', 'branch/file')
478
self.assertFileEqual('trunk content\nmore content\n', 'branch/file')
489
480
def check_file_renamed_and_more_content(self):
490
self.assertFileEqual(
491
b'trunk content\nmore content\n', 'branch/new-file')
481
self.assertFileEqual('trunk content\nmore content\n', 'branch/new-file')
493
483
def do_delete_file(self):
494
return [('unversion', 'file')]
496
def do_delete_file_in_dir(self):
497
return [('unversion', 'dir/file')]
484
return [('unversion', 'file-id')]
499
486
def check_file_doesnt_exist(self):
500
487
self.assertPathDoesNotExist('branch/file')
502
489
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'))]
490
return [('add', ('dir', 'dir-id', 'directory', '')),
491
('add', ('dir/file', 'file-id', 'file', 'trunk content\n'))]
506
493
def do_modify_file_in_dir(self):
507
return [('modify', ('dir/file', b'trunk content\nmore content\n'))]
494
return [('modify', ('file-id', 'trunk content\nmore content\n'))]
509
496
def check_file_in_dir_has_more_content(self):
510
self.assertFileEqual(
511
b'trunk content\nmore content\n', 'branch/dir/file')
497
self.assertFileEqual('trunk content\nmore content\n', 'branch/dir/file')
513
499
def check_file_in_dir_doesnt_exist(self):
514
500
self.assertPathDoesNotExist('branch/dir/file')
538
524
(dict(_base_actions='create_file'),
540
526
dict(actions='rename_file', check='file_renamed',
541
path='new-file', file_id=b'file-id')),
527
path='new-file', file_id='file-id')),
543
529
dict(actions='delete_file', check='file_doesnt_exist',
544
530
# PathConflicts deletion handling requires a special
545
531
# hard-coded value
546
path='<deleted>', file_id=b'file-id')),),
532
path='<deleted>', file_id='file-id')),),
547
533
# File renamed/deleted in dir
548
534
(dict(_base_actions='create_file_in_dir'),
549
535
('file_renamed_in_dir',
550
536
dict(actions='rename_file_in_dir', check='file_in_dir_renamed',
551
path='dir/new-file', file_id=b'file-id')),
537
path='dir/new-file', file_id='file-id')),
553
dict(actions='delete_file_in_dir', check='file_in_dir_doesnt_exist',
539
dict(actions='delete_file', check='file_in_dir_doesnt_exist',
554
540
# PathConflicts deletion handling requires a special
555
541
# hard-coded value
556
path='<deleted>', file_id=b'file-id')),),
542
path='<deleted>', file_id='file-id')),),
557
543
# File renamed/renamed differently
558
544
(dict(_base_actions='create_file'),
560
546
dict(actions='rename_file', check='file_renamed',
561
path='new-file', file_id=b'file-id')),
547
path='new-file', file_id='file-id')),
562
548
('file_renamed2',
563
549
dict(actions='rename_file2', check='file_renamed2',
564
path='new-file2', file_id=b'file-id')),),
550
path='new-file2', file_id='file-id')),),
565
551
# Dir renamed/deleted
566
552
(dict(_base_actions='create_dir'),
568
554
dict(actions='rename_dir', check='dir_renamed',
569
path='new-dir', file_id=b'dir-id')),
555
path='new-dir', file_id='dir-id')),
571
557
dict(actions='delete_dir', check='dir_doesnt_exist',
572
558
# PathConflicts deletion handling requires a special
573
559
# hard-coded value
574
path='<deleted>', file_id=b'dir-id')),),
560
path='<deleted>', file_id='dir-id')),),
575
561
# Dir renamed/renamed differently
576
562
(dict(_base_actions='create_dir'),
578
564
dict(actions='rename_dir', check='dir_renamed',
579
path='new-dir', file_id=b'dir-id')),
565
path='new-dir', file_id='dir-id')),
581
567
dict(actions='rename_dir2', check='dir_renamed2',
582
path='new-dir2', file_id=b'dir-id')),),
568
path='new-dir2', file_id='dir-id')),),
585
571
def do_create_file(self):
586
return [('add', ('file', b'file-id', 'file', b'trunk content\n'))]
572
return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
588
574
def do_create_dir(self):
589
return [('add', ('dir', b'dir-id', 'directory', ''))]
575
return [('add', ('dir', 'dir-id', 'directory', ''))]
591
577
def do_rename_file(self):
592
578
return [('rename', ('file', 'new-file'))]
617
603
self.assertPathExists('branch/new-dir2')
619
605
def do_delete_file(self):
620
return [('unversion', 'file')]
622
def do_delete_file_in_dir(self):
623
return [('unversion', 'dir/file')]
606
return [('unversion', 'file-id')]
625
608
def check_file_doesnt_exist(self):
626
609
self.assertPathDoesNotExist('branch/file')
628
611
def do_delete_dir(self):
629
return [('unversion', 'dir')]
612
return [('unversion', 'dir-id')]
631
614
def check_dir_doesnt_exist(self):
632
615
self.assertPathDoesNotExist('branch/dir')
634
617
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'))]
618
return [('add', ('dir', 'dir-id', 'directory', '')),
619
('add', ('dir/file', 'file-id', 'file', 'trunk content\n'))]
638
621
def do_rename_file_in_dir(self):
639
622
return [('rename', ('dir/file', 'dir/new-file'))]
689
672
(dict(_base_actions='nothing'),
690
673
('filea_created',
691
674
dict(actions='create_file_a', check='file_content_a',
692
path='file', file_id=b'file-a-id')),
675
path='file', file_id='file-a-id')),
693
676
('fileb_created',
694
677
dict(actions='create_file_b', check='file_content_b',
695
path='file', file_id=b'file-b-id')),),
678
path='file', file_id='file-b-id')),),
696
679
# File created with different file-ids but deleted on one side
697
680
(dict(_base_actions='create_file_a'),
698
681
('filea_replaced',
699
682
dict(actions='replace_file_a_by_b', check='file_content_b',
700
path='file', file_id=b'file-b-id')),
683
path='file', file_id='file-b-id')),
701
684
('filea_modified',
702
685
dict(actions='modify_file_a', check='file_new_content',
703
path='file', file_id=b'file-a-id')),),
686
path='file', file_id='file-a-id')),),
706
689
def do_nothing(self):
709
692
def do_create_file_a(self):
710
return [('add', ('file', b'file-a-id', 'file', b'file a content\n'))]
693
return [('add', ('file', 'file-a-id', 'file', 'file a content\n'))]
712
695
def check_file_content_a(self):
713
self.assertFileEqual(b'file a content\n', 'branch/file')
696
self.assertFileEqual('file a content\n', 'branch/file')
715
698
def do_create_file_b(self):
716
return [('add', ('file', b'file-b-id', 'file', b'file b content\n'))]
699
return [('add', ('file', 'file-b-id', 'file', 'file b content\n'))]
718
701
def check_file_content_b(self):
719
self.assertFileEqual(b'file b content\n', 'branch/file')
702
self.assertFileEqual('file b content\n', 'branch/file')
721
704
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'))]
705
return [('unversion', 'file-a-id'),
706
('add', ('file', 'file-b-id', 'file', 'file b content\n'))]
725
708
def do_modify_file_a(self):
726
return [('modify', ('file', b'new content\n'))]
709
return [('modify', ('file-a-id', 'new content\n'))]
728
711
def check_file_new_content(self):
729
self.assertFileEqual(b'new content\n', 'branch/file')
712
self.assertFileEqual('new content\n', 'branch/file')
731
714
def _get_resolve_path_arg(self, wt, action):
732
715
return self._this['path']
936
919
(dict(_base_actions='create_dir1_dir2'),
937
920
('dir1_into_dir2',
938
921
dict(actions='move_dir1_into_dir2', check='dir1_moved',
939
dir_id=b'dir1-id', target_id=b'dir2-id', xfail=False)),
922
dir_id='dir1-id', target_id='dir2-id', xfail=False)),
940
923
('dir2_into_dir1',
941
924
dict(actions='move_dir2_into_dir1', check='dir2_moved',
942
dir_id=b'dir2-id', target_id=b'dir1-id', xfail=False))),
925
dir_id='dir2-id', target_id='dir1-id', xfail=False))),
943
926
# Subdirs moved into each other
944
927
(dict(_base_actions='create_dir1_4'),
945
928
('dir1_into_dir4',
946
929
dict(actions='move_dir1_into_dir4', check='dir1_2_moved',
947
dir_id=b'dir1-id', target_id=b'dir4-id', xfail=True)),
930
dir_id='dir1-id', target_id='dir4-id', xfail=True)),
948
931
('dir3_into_dir2',
949
932
dict(actions='move_dir3_into_dir2', check='dir3_4_moved',
950
dir_id=b'dir3-id', target_id=b'dir2-id', xfail=True))),
933
dir_id='dir3-id', target_id='dir2-id', xfail=True))),
953
936
def do_create_dir1_dir2(self):
954
return [('add', ('dir1', b'dir1-id', 'directory', '')),
955
('add', ('dir2', b'dir2-id', 'directory', '')), ]
937
return [('add', ('dir1', 'dir1-id', 'directory', '')),
938
('add', ('dir2', 'dir2-id', 'directory', '')),]
957
940
def do_move_dir1_into_dir2(self):
958
941
return [('rename', ('dir1', 'dir2/dir1'))]
969
952
self.assertPathExists('branch/dir1/dir2')
971
954
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', '')), ]
955
return [('add', ('dir1', 'dir1-id', 'directory', '')),
956
('add', ('dir1/dir2', 'dir2-id', 'directory', '')),
957
('add', ('dir3', 'dir3-id', 'directory', '')),
958
('add', ('dir3/dir4', 'dir4-id', 'directory', '')),]
977
960
def do_move_dir1_into_dir4(self):
978
961
return [('rename', ('dir1', 'dir3/dir4/dir1'))]
1188
1171
def setUp(self):
1189
1172
super(TestResolveActionOption, self).setUp()
1190
1173
self.options = [conflicts.ResolveActionOption()]
1191
self.parser = option.get_optparser(self.options)
1174
self.parser = option.get_optparser(dict((o.name, o)
1175
for o in self.options))
1193
1177
def parse(self, args):
1194
1178
return self.parser.parse_args(args)
1196
1180
def test_unknown_action(self):
1197
self.assertRaises(option.BadOptionValue,
1181
self.assertRaises(errors.BadOptionValue,
1198
1182
self.parse, ['--action', 'take-me-to-the-moon'])
1200
1184
def test_done(self):
1201
1185
opts, args = self.parse(['--action', 'done'])
1202
self.assertEqual({'action': 'done'}, opts)
1186
self.assertEqual({'action':'done'}, opts)
1204
1188
def test_take_this(self):
1205
1189
opts, args = self.parse(['--action', 'take-this'])