113
106
relpath, shared=shared, format=format)
116
class BrokenRepoScenario(object):
117
"""Base class for defining scenarios for testing check and reconcile.
119
A subclass needs to define the following methods:
120
:populate_repository: a method to use to populate a repository with
121
sample revisions, inventories and file versions.
122
:all_versions_after_reconcile: all the versions in repository after
123
reconcile. run_test verifies that the text of each of these
124
versions of the file is unchanged by the reconcile.
125
:populated_parents: a list of (parents list, revision). Each version
126
of the file is verified to have the given parents before running
127
the reconcile. i.e. this is used to assert that the repo from the
128
factory is what we expect.
129
:corrected_parents: a list of (parents list, revision). Each version
130
of the file is verified to have the given parents after the
131
reconcile. i.e. this is used to assert that reconcile made the
132
changes we expect it to make.
134
A subclass may define the following optional method as well:
135
:corrected_fulltexts: a list of file versions that should be stored as
136
fulltexts (not deltas) after reconcile. run_test will verify that
140
def __init__(self, test_case):
141
self.test_case = test_case
143
def make_one_file_inventory(self, repo, revision, parents,
144
inv_revision=None, root_revision=None,
145
file_contents=None, make_file_version=True):
146
return self.test_case.make_one_file_inventory(
147
repo, revision, parents, inv_revision=inv_revision,
148
root_revision=root_revision, file_contents=file_contents,
149
make_file_version=make_file_version)
151
def add_revision(self, repo, revision_id, inv, parent_ids):
152
return self.test_case.add_revision(repo, revision_id, inv, parent_ids)
154
def corrected_fulltexts(self):
157
def repository_text_key_index(self):
159
if self.versioned_root:
160
result.update(self.versioned_repository_text_keys())
161
result.update(self.repository_text_keys())
165
class UndamagedRepositoryScenario(BrokenRepoScenario):
166
"""A scenario where the repository has no damage.
168
It has a single revision, 'rev1a', with a single file.
171
def all_versions_after_reconcile(self):
174
def populated_parents(self):
175
return (((), 'rev1a'), )
177
def corrected_parents(self):
178
# Same as the populated parents, because there was nothing wrong.
179
return self.populated_parents()
181
def check_regexes(self, repo):
182
return ["0 unreferenced text versions"]
184
def populate_repository(self, repo):
185
# make rev1a: A well-formed revision, containing 'a-file'
186
inv = self.make_one_file_inventory(
187
repo, 'rev1a', [], root_revision='rev1a')
188
self.add_revision(repo, 'rev1a', inv, [])
189
self.versioned_root = repo.supports_rich_root()
191
def repository_text_key_references(self):
193
if self.versioned_root:
194
result.update({('TREE_ROOT', 'rev1a'): True})
195
result.update({('a-file-id', 'rev1a'): True})
198
def repository_text_keys(self):
199
return {('a-file-id', 'rev1a'):[NULL_REVISION]}
201
def versioned_repository_text_keys(self):
202
return {('TREE_ROOT', 'rev1a'):[NULL_REVISION]}
205
class FileParentIsNotInRevisionAncestryScenario(BrokenRepoScenario):
206
"""A scenario where a revision 'rev2' has 'a-file' with a
207
parent 'rev1b' that is not in the revision ancestry.
209
Reconcile should remove 'rev1b' from the parents list of 'a-file' in
210
'rev2', preserving 'rev1a' as a parent.
213
def all_versions_after_reconcile(self):
214
return ('rev1a', 'rev2')
216
def populated_parents(self):
219
((), 'rev1b'), # Will be gc'd
220
(('rev1a', 'rev1b'), 'rev2')) # Will have parents trimmed
222
def corrected_parents(self):
226
(('rev1a',), 'rev2'))
228
def check_regexes(self, repo):
229
return [r"\* a-file-id version rev2 has parents \('rev1a', 'rev1b'\) "
230
r"but should have \('rev1a',\)",
231
"1 unreferenced text versions",
234
def populate_repository(self, repo):
235
# make rev1a: A well-formed revision, containing 'a-file'
236
inv = self.make_one_file_inventory(
237
repo, 'rev1a', [], root_revision='rev1a')
238
self.add_revision(repo, 'rev1a', inv, [])
240
# make rev1b, which has no Revision, but has an Inventory, and
242
inv = self.make_one_file_inventory(
243
repo, 'rev1b', [], root_revision='rev1b')
244
repo.add_inventory('rev1b', inv, [])
246
# make rev2, with a-file.
247
# a-file has 'rev1b' as an ancestor, even though this is not
248
# mentioned by 'rev1a', making it an unreferenced ancestor
249
inv = self.make_one_file_inventory(
250
repo, 'rev2', ['rev1a', 'rev1b'])
251
self.add_revision(repo, 'rev2', inv, ['rev1a'])
252
self.versioned_root = repo.supports_rich_root()
254
def repository_text_key_references(self):
256
if self.versioned_root:
257
result.update({('TREE_ROOT', 'rev1a'): True,
258
('TREE_ROOT', 'rev2'): True})
259
result.update({('a-file-id', 'rev1a'): True,
260
('a-file-id', 'rev2'): True})
263
def repository_text_keys(self):
264
return {('a-file-id', 'rev1a'):[NULL_REVISION],
265
('a-file-id', 'rev2'):[('a-file-id', 'rev1a')]}
267
def versioned_repository_text_keys(self):
268
return {('TREE_ROOT', 'rev1a'):[NULL_REVISION],
269
('TREE_ROOT', 'rev2'):[('TREE_ROOT', 'rev1a')]}
272
class FileParentHasInaccessibleInventoryScenario(BrokenRepoScenario):
273
"""A scenario where a revision 'rev3' containing 'a-file' modified in
274
'rev3', and with a parent which is in the revision ancestory, but whose
275
inventory cannot be accessed at all.
277
Reconcile should remove the file version parent whose inventory is
278
inaccessbile (i.e. remove 'rev1c' from the parents of a-file's rev3).
281
def all_versions_after_reconcile(self):
282
return ('rev2', 'rev3')
284
def populated_parents(self):
287
(('rev1c',), 'rev3'))
289
def corrected_parents(self):
294
def check_regexes(self, repo):
295
return [r"\* a-file-id version rev3 has parents "
296
r"\('rev1c',\) but should have \(\)",
299
def populate_repository(self, repo):
300
# make rev2, with a-file
302
inv = self.make_one_file_inventory(repo, 'rev2', [])
303
self.add_revision(repo, 'rev2', inv, [])
305
# make ghost revision rev1c, with a version of a-file present so
306
# that we generate a knit delta against this version. In real life
307
# the ghost might never have been present or rev3 might have been
308
# generated against a revision that was present at the time. So
309
# currently we have the full history of a-file present even though
310
# the inventory and revision objects are not.
311
self.make_one_file_inventory(repo, 'rev1c', [])
313
# make rev3 with a-file
314
# a-file refers to 'rev1c', which is a ghost in this repository, so
315
# a-file cannot have rev1c as its ancestor.
316
inv = self.make_one_file_inventory(repo, 'rev3', ['rev1c'])
317
self.add_revision(repo, 'rev3', inv, ['rev1c', 'rev1a'])
318
self.versioned_root = repo.supports_rich_root()
320
def repository_text_key_references(self):
322
if self.versioned_root:
323
result.update({('TREE_ROOT', 'rev2'): True,
324
('TREE_ROOT', 'rev3'): True})
325
result.update({('a-file-id', 'rev2'): True,
326
('a-file-id', 'rev3'): True})
329
def repository_text_keys(self):
330
return {('a-file-id', 'rev2'):[NULL_REVISION],
331
('a-file-id', 'rev3'):[NULL_REVISION]}
333
def versioned_repository_text_keys(self):
334
return {('TREE_ROOT', 'rev2'):[NULL_REVISION],
335
('TREE_ROOT', 'rev3'):[NULL_REVISION]}
338
class FileParentsNotReferencedByAnyInventoryScenario(BrokenRepoScenario):
339
"""A scenario where a repository with file 'a-file' which has extra
340
per-file versions that are not referenced by any inventory (even though
341
they have the same ID as actual revisions). The inventory of 'rev2'
342
references 'rev1a' of 'a-file', but there is a 'rev2' of 'some-file' stored
343
and erroneously referenced by later per-file versions (revisions 'rev4' and
346
Reconcile should remove the file parents that are not referenced by any
350
def all_versions_after_reconcile(self):
351
return ('rev1a', 'rev2c', 'rev4', 'rev5')
353
def populated_parents(self):
355
(('rev1a',), 'rev2'),
356
(('rev1a',), 'rev2b'),
359
(('rev2', 'rev2c'), 'rev5')]
361
def corrected_parents(self):
363
# rev2 and rev2b have been removed.
366
# rev3's accessible parent inventories all have rev1a as the last
368
(('rev1a',), 'rev3'),
369
# rev1a features in both rev4's parents but should only appear once
371
(('rev1a',), 'rev4'),
372
# rev2c is the head of rev1a and rev2c, the inventory provided
373
# per-file last-modified revisions.
374
(('rev2c',), 'rev5'))
376
def check_regexes(self, repo):
377
if repo.supports_rich_root():
378
# TREE_ROOT will be wrong; but we're not testing it. so just adjust
379
# the expected count of errors.
385
r"unreferenced version: {rev2} in a-file-id",
386
r"unreferenced version: {rev2b} in a-file-id",
388
r"a-file-id version rev3 has parents \('rev2',\) "
389
r"but should have \('rev1a',\)",
390
r"a-file-id version rev5 has parents \('rev2', 'rev2c'\) "
391
r"but should have \('rev2c',\)",
392
r"a-file-id version rev4 has parents \('rev2',\) "
393
r"but should have \('rev1a',\)",
394
"%d inconsistent parents" % count,
397
def populate_repository(self, repo):
398
# make rev1a: A well-formed revision, containing 'a-file'
399
inv = self.make_one_file_inventory(
400
repo, 'rev1a', [], root_revision='rev1a')
401
self.add_revision(repo, 'rev1a', inv, [])
403
# make rev2, with a-file.
404
# a-file is unmodified from rev1a, and an unreferenced rev2 file
405
# version is present in the repository.
406
self.make_one_file_inventory(
407
repo, 'rev2', ['rev1a'], inv_revision='rev1a')
408
self.add_revision(repo, 'rev2', inv, ['rev1a'])
410
# make rev3 with a-file
411
# a-file has 'rev2' as its ancestor, but the revision in 'rev2' was
412
# rev1a so this is inconsistent with rev2's inventory - it should
413
# be rev1a, and at the revision level 1c is not present - it is a
414
# ghost, so only the details from rev1a are available for
415
# determining whether a delta is acceptable, or a full is needed,
416
# and what the correct parents are.
417
inv = self.make_one_file_inventory(repo, 'rev3', ['rev2'])
418
self.add_revision(repo, 'rev3', inv, ['rev1c', 'rev1a'])
420
# In rev2b, the true last-modifying-revision of a-file is rev1a,
421
# inherited from rev2, but there is a version rev2b of the file, which
422
# reconcile could remove, leaving no rev2b. Most importantly,
423
# revisions descending from rev2b should not have per-file parents of
425
# ??? This is to test deduplication in fixing rev4
426
inv = self.make_one_file_inventory(
427
repo, 'rev2b', ['rev1a'], inv_revision='rev1a')
428
self.add_revision(repo, 'rev2b', inv, ['rev1a'])
430
# rev4 is for testing that when the last modified of a file in
431
# multiple parent revisions is the same, that it only appears once
432
# in the generated per file parents list: rev2 and rev2b both
433
# descend from 1a and do not change the file a-file, so there should
434
# be no version of a-file 'rev2' or 'rev2b', but rev4 does change
435
# a-file, and is a merge of rev2 and rev2b, so it should end up with
436
# a parent of just rev1a - the starting file parents list is simply
438
inv = self.make_one_file_inventory(repo, 'rev4', ['rev2'])
439
self.add_revision(repo, 'rev4', inv, ['rev2', 'rev2b'])
441
# rev2c changes a-file from rev1a, so the version it of a-file it
442
# introduces is a head revision when rev5 is checked.
443
inv = self.make_one_file_inventory(repo, 'rev2c', ['rev1a'])
444
self.add_revision(repo, 'rev2c', inv, ['rev1a'])
446
# rev5 descends from rev2 and rev2c; as rev2 does not alter a-file,
447
# but rev2c does, this should use rev2c as the parent for the per
448
# file history, even though more than one per-file parent is
449
# available, because we use the heads of the revision parents for
450
# the inventory modification revisions of the file to determine the
451
# parents for the per file graph.
452
inv = self.make_one_file_inventory(repo, 'rev5', ['rev2', 'rev2c'])
453
self.add_revision(repo, 'rev5', inv, ['rev2', 'rev2c'])
454
self.versioned_root = repo.supports_rich_root()
456
def repository_text_key_references(self):
458
if self.versioned_root:
459
result.update({('TREE_ROOT', 'rev1a'): True,
460
('TREE_ROOT', 'rev2'): True,
461
('TREE_ROOT', 'rev2b'): True,
462
('TREE_ROOT', 'rev2c'): True,
463
('TREE_ROOT', 'rev3'): True,
464
('TREE_ROOT', 'rev4'): True,
465
('TREE_ROOT', 'rev5'): True})
466
result.update({('a-file-id', 'rev1a'): True,
467
('a-file-id', 'rev2c'): True,
468
('a-file-id', 'rev3'): True,
469
('a-file-id', 'rev4'): True,
470
('a-file-id', 'rev5'): True})
473
def repository_text_keys(self):
474
return {('a-file-id', 'rev1a'): [NULL_REVISION],
475
('a-file-id', 'rev2c'): [('a-file-id', 'rev1a')],
476
('a-file-id', 'rev3'): [('a-file-id', 'rev1a')],
477
('a-file-id', 'rev4'): [('a-file-id', 'rev1a')],
478
('a-file-id', 'rev5'): [('a-file-id', 'rev2c')]}
480
def versioned_repository_text_keys(self):
481
return {('TREE_ROOT', 'rev1a'): [NULL_REVISION],
482
('TREE_ROOT', 'rev2'): [('TREE_ROOT', 'rev1a')],
483
('TREE_ROOT', 'rev2b'): [('TREE_ROOT', 'rev1a')],
484
('TREE_ROOT', 'rev2c'): [('TREE_ROOT', 'rev1a')],
485
('TREE_ROOT', 'rev3'): [('TREE_ROOT', 'rev1a')],
486
('TREE_ROOT', 'rev4'):
487
[('TREE_ROOT', 'rev2'), ('TREE_ROOT', 'rev2b')],
488
('TREE_ROOT', 'rev5'):
489
[('TREE_ROOT', 'rev2'), ('TREE_ROOT', 'rev2c')]}
492
class UnreferencedFileParentsFromNoOpMergeScenario(BrokenRepoScenario):
494
rev1a and rev1b with identical contents
495
rev2 revision has parents of [rev1a, rev1b]
496
There is a a-file:rev2 file version, not referenced by the inventory.
499
def all_versions_after_reconcile(self):
500
return ('rev1a', 'rev1b', 'rev2', 'rev4')
502
def populated_parents(self):
506
(('rev1a', 'rev1b'), 'rev2'),
511
def corrected_parents(self):
520
def corrected_fulltexts(self):
523
def check_regexes(self, repo):
526
def populate_repository(self, repo):
527
# make rev1a: A well-formed revision, containing 'a-file'
528
inv1a = self.make_one_file_inventory(
529
repo, 'rev1a', [], root_revision='rev1a')
530
self.add_revision(repo, 'rev1a', inv1a, [])
532
# make rev1b: A well-formed revision, containing 'a-file'
533
# rev1b of a-file has the exact same contents as rev1a.
534
file_contents = repo.revision_tree('rev1a').get_file_text('a-file-id')
535
inv = self.make_one_file_inventory(
536
repo, 'rev1b', [], root_revision='rev1b',
537
file_contents=file_contents)
538
self.add_revision(repo, 'rev1b', inv, [])
540
# make rev2, a merge of rev1a and rev1b, with a-file.
541
# a-file is unmodified from rev1a and rev1b, but a new version is
542
# wrongly present anyway.
543
inv = self.make_one_file_inventory(
544
repo, 'rev2', ['rev1a', 'rev1b'], inv_revision='rev1a',
545
file_contents=file_contents)
546
self.add_revision(repo, 'rev2', inv, ['rev1a', 'rev1b'])
548
# rev3: a-file unchanged from rev2, but wrongly referencing rev2 of the
549
# file in its inventory.
550
inv = self.make_one_file_inventory(
551
repo, 'rev3', ['rev2'], inv_revision='rev2',
552
file_contents=file_contents, make_file_version=False)
553
self.add_revision(repo, 'rev3', inv, ['rev2'])
555
# rev4: a modification of a-file on top of rev3.
556
inv = self.make_one_file_inventory(repo, 'rev4', ['rev2'])
557
self.add_revision(repo, 'rev4', inv, ['rev3'])
558
self.versioned_root = repo.supports_rich_root()
560
def repository_text_key_references(self):
562
if self.versioned_root:
563
result.update({('TREE_ROOT', 'rev1a'): True,
564
('TREE_ROOT', 'rev1b'): True,
565
('TREE_ROOT', 'rev2'): True,
566
('TREE_ROOT', 'rev3'): True,
567
('TREE_ROOT', 'rev4'): True})
568
result.update({('a-file-id', 'rev1a'): True,
569
('a-file-id', 'rev1b'): True,
570
('a-file-id', 'rev2'): False,
571
('a-file-id', 'rev4'): True})
574
def repository_text_keys(self):
575
return {('a-file-id', 'rev1a'): [NULL_REVISION],
576
('a-file-id', 'rev1b'): [NULL_REVISION],
577
('a-file-id', 'rev2'): [NULL_REVISION],
578
('a-file-id', 'rev4'): [('a-file-id', 'rev2')]}
580
def versioned_repository_text_keys(self):
581
return {('TREE_ROOT', 'rev1a'): [NULL_REVISION],
582
('TREE_ROOT', 'rev1b'): [NULL_REVISION],
583
('TREE_ROOT', 'rev2'):
584
[('TREE_ROOT', 'rev1a'), ('TREE_ROOT', 'rev1b')],
585
('TREE_ROOT', 'rev3'): [('TREE_ROOT', 'rev2')],
586
('TREE_ROOT', 'rev4'): [('TREE_ROOT', 'rev3')]}
589
class TooManyParentsScenario(BrokenRepoScenario):
590
"""A scenario where 'broken-revision' of 'a-file' claims to have parents
591
['good-parent', 'bad-parent']. However 'bad-parent' is in the ancestry of
592
'good-parent', so the correct parent list for that file version are is just
596
def all_versions_after_reconcile(self):
597
return ('bad-parent', 'good-parent', 'broken-revision')
599
def populated_parents(self):
602
(('bad-parent',), 'good-parent'),
603
(('good-parent', 'bad-parent'), 'broken-revision'))
605
def corrected_parents(self):
608
(('bad-parent',), 'good-parent'),
609
(('good-parent',), 'broken-revision'))
611
def check_regexes(self, repo):
612
if repo.supports_rich_root():
613
# TREE_ROOT will be wrong; but we're not testing it. so just adjust
614
# the expected count of errors.
619
' %d inconsistent parents' % count,
620
(r" \* a-file-id version broken-revision has parents "
621
r"\('good-parent', 'bad-parent'\) but "
622
r"should have \('good-parent',\)"))
624
def populate_repository(self, repo):
625
inv = self.make_one_file_inventory(
626
repo, 'bad-parent', (), root_revision='bad-parent')
627
self.add_revision(repo, 'bad-parent', inv, ())
629
inv = self.make_one_file_inventory(
630
repo, 'good-parent', ('bad-parent',))
631
self.add_revision(repo, 'good-parent', inv, ('bad-parent',))
633
inv = self.make_one_file_inventory(
634
repo, 'broken-revision', ('good-parent', 'bad-parent'))
635
self.add_revision(repo, 'broken-revision', inv, ('good-parent',))
636
self.versioned_root = repo.supports_rich_root()
638
def repository_text_key_references(self):
640
if self.versioned_root:
641
result.update({('TREE_ROOT', 'bad-parent'): True,
642
('TREE_ROOT', 'broken-revision'): True,
643
('TREE_ROOT', 'good-parent'): True})
644
result.update({('a-file-id', 'bad-parent'): True,
645
('a-file-id', 'broken-revision'): True,
646
('a-file-id', 'good-parent'): True})
649
def repository_text_keys(self):
650
return {('a-file-id', 'bad-parent'): [NULL_REVISION],
651
('a-file-id', 'broken-revision'):
652
[('a-file-id', 'good-parent')],
653
('a-file-id', 'good-parent'): [('a-file-id', 'bad-parent')]}
655
def versioned_repository_text_keys(self):
656
return {('TREE_ROOT', 'bad-parent'): [NULL_REVISION],
657
('TREE_ROOT', 'broken-revision'):
658
[('TREE_ROOT', 'good-parent')],
659
('TREE_ROOT', 'good-parent'): [('TREE_ROOT', 'bad-parent')]}
662
class ClaimedFileParentDidNotModifyFileScenario(BrokenRepoScenario):
663
"""A scenario where the file parent is the same as the revision parent, but
664
should not be because that revision did not modify the file.
666
Specifically, the parent revision of 'current' is
667
'modified-something-else', which does not modify 'a-file', but the
668
'current' version of 'a-file' erroneously claims that
669
'modified-something-else' is the parent file version.
672
def all_versions_after_reconcile(self):
673
return ('basis', 'current')
675
def populated_parents(self):
678
(('basis',), 'modified-something-else'),
679
(('modified-something-else',), 'current'))
681
def corrected_parents(self):
684
(None, 'modified-something-else'),
685
(('basis',), 'current'))
687
def check_regexes(self, repo):
688
if repo.supports_rich_root():
689
# TREE_ROOT will be wrong; but we're not testing it. so just adjust
690
# the expected count of errors.
695
"%d inconsistent parents" % count,
696
r"\* a-file-id version current has parents "
697
r"\('modified-something-else',\) but should have \('basis',\)",
700
def populate_repository(self, repo):
701
inv = self.make_one_file_inventory(repo, 'basis', ())
702
self.add_revision(repo, 'basis', inv, ())
704
# 'modified-something-else' is a correctly recorded revision, but it
705
# does not modify the file we are looking at, so the inventory for that
706
# file in this revision points to 'basis'.
707
inv = self.make_one_file_inventory(
708
repo, 'modified-something-else', ('basis',), inv_revision='basis')
709
self.add_revision(repo, 'modified-something-else', inv, ('basis',))
711
# The 'current' revision has 'modified-something-else' as its parent,
712
# but the 'current' version of 'a-file' should have 'basis' as its
714
inv = self.make_one_file_inventory(
715
repo, 'current', ('modified-something-else',))
716
self.add_revision(repo, 'current', inv, ('modified-something-else',))
717
self.versioned_root = repo.supports_rich_root()
719
def repository_text_key_references(self):
721
if self.versioned_root:
722
result.update({('TREE_ROOT', 'basis'): True,
723
('TREE_ROOT', 'current'): True,
724
('TREE_ROOT', 'modified-something-else'): True})
725
result.update({('a-file-id', 'basis'): True,
726
('a-file-id', 'current'): True})
729
def repository_text_keys(self):
730
return {('a-file-id', 'basis'): [NULL_REVISION],
731
('a-file-id', 'current'): [('a-file-id', 'basis')]}
733
def versioned_repository_text_keys(self):
734
return {('TREE_ROOT', 'basis'): ['null:'],
735
('TREE_ROOT', 'current'):
736
[('TREE_ROOT', 'modified-something-else')],
737
('TREE_ROOT', 'modified-something-else'):
738
[('TREE_ROOT', 'basis')]}
741
class IncorrectlyOrderedParentsScenario(BrokenRepoScenario):
742
"""A scenario where the set parents of a version of a file are correct, but
743
the order of those parents is incorrect.
745
This defines a 'broken-revision-1-2' and a 'broken-revision-2-1' which both
746
have their file version parents reversed compared to the revision parents,
747
which is invalid. (We use two revisions with opposite orderings of the
748
same parents to make sure that accidentally relying on dictionary/set
749
ordering cannot make the test pass; the assumption is that while dict/set
750
iteration order is arbitrary, it is also consistent within a single test).
753
def all_versions_after_reconcile(self):
754
return ['parent-1', 'parent-2', 'broken-revision-1-2',
755
'broken-revision-2-1']
757
def populated_parents(self):
761
(('parent-2', 'parent-1'), 'broken-revision-1-2'),
762
(('parent-1', 'parent-2'), 'broken-revision-2-1'))
764
def corrected_parents(self):
768
(('parent-1', 'parent-2'), 'broken-revision-1-2'),
769
(('parent-2', 'parent-1'), 'broken-revision-2-1'))
771
def check_regexes(self, repo):
772
if repo.supports_rich_root():
773
# TREE_ROOT will be wrong; but we're not testing it. so just adjust
774
# the expected count of errors.
779
"%d inconsistent parents" % count,
780
r"\* a-file-id version broken-revision-1-2 has parents "
781
r"\('parent-2', 'parent-1'\) but should have "
782
r"\('parent-1', 'parent-2'\)",
783
r"\* a-file-id version broken-revision-2-1 has parents "
784
r"\('parent-1', 'parent-2'\) but should have "
785
r"\('parent-2', 'parent-1'\)")
787
def populate_repository(self, repo):
788
inv = self.make_one_file_inventory(repo, 'parent-1', [])
789
self.add_revision(repo, 'parent-1', inv, [])
791
inv = self.make_one_file_inventory(repo, 'parent-2', [])
792
self.add_revision(repo, 'parent-2', inv, [])
794
inv = self.make_one_file_inventory(
795
repo, 'broken-revision-1-2', ['parent-2', 'parent-1'])
797
repo, 'broken-revision-1-2', inv, ['parent-1', 'parent-2'])
799
inv = self.make_one_file_inventory(
800
repo, 'broken-revision-2-1', ['parent-1', 'parent-2'])
802
repo, 'broken-revision-2-1', inv, ['parent-2', 'parent-1'])
803
self.versioned_root = repo.supports_rich_root()
805
def repository_text_key_references(self):
807
if self.versioned_root:
808
result.update({('TREE_ROOT', 'broken-revision-1-2'): True,
809
('TREE_ROOT', 'broken-revision-2-1'): True,
810
('TREE_ROOT', 'parent-1'): True,
811
('TREE_ROOT', 'parent-2'): True})
812
result.update({('a-file-id', 'broken-revision-1-2'): True,
813
('a-file-id', 'broken-revision-2-1'): True,
814
('a-file-id', 'parent-1'): True,
815
('a-file-id', 'parent-2'): True})
818
def repository_text_keys(self):
819
return {('a-file-id', 'broken-revision-1-2'):
820
[('a-file-id', 'parent-1'), ('a-file-id', 'parent-2')],
821
('a-file-id', 'broken-revision-2-1'):
822
[('a-file-id', 'parent-2'), ('a-file-id', 'parent-1')],
823
('a-file-id', 'parent-1'): [NULL_REVISION],
824
('a-file-id', 'parent-2'): [NULL_REVISION]}
826
def versioned_repository_text_keys(self):
827
return {('TREE_ROOT', 'broken-revision-1-2'):
828
[('TREE_ROOT', 'parent-1'), ('TREE_ROOT', 'parent-2')],
829
('TREE_ROOT', 'broken-revision-2-1'):
830
[('TREE_ROOT', 'parent-2'), ('TREE_ROOT', 'parent-1')],
831
('TREE_ROOT', 'parent-1'): [NULL_REVISION],
832
('TREE_ROOT', 'parent-2'): [NULL_REVISION]}
835
all_broken_scenario_classes = [
836
UndamagedRepositoryScenario,
837
FileParentIsNotInRevisionAncestryScenario,
838
FileParentHasInaccessibleInventoryScenario,
839
FileParentsNotReferencedByAnyInventoryScenario,
840
TooManyParentsScenario,
841
ClaimedFileParentDidNotModifyFileScenario,
842
IncorrectlyOrderedParentsScenario,
843
UnreferencedFileParentsFromNoOpMergeScenario,
847
109
def load_tests(standard_tests, module, loader):
848
110
prefix = 'bzrlib.tests.per_repository.'
849
111
test_repository_modules = [