bzr branch
http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
| 
2052.3.2
by John Arbash Meinel
 Change Copyright .. by Canonical to Copyright ... Canonical  | 
1  | 
# Copyright (C) 2005 Canonical Ltd
 | 
| 
1563.2.1
by Robert Collins
 Merge in a variation of the versionedfile api from versioned-file.  | 
2  | 
#
 | 
3  | 
# Authors:
 | 
|
4  | 
#   Johan Rydberg <jrydberg@gnu.org>
 | 
|
5  | 
#
 | 
|
6  | 
# This program is free software; you can redistribute it and/or modify
 | 
|
7  | 
# it under the terms of the GNU General Public License as published by
 | 
|
8  | 
# the Free Software Foundation; either version 2 of the License, or
 | 
|
9  | 
# (at your option) any later version.
 | 
|
| 
1887.1.1
by Adeodato Simó
 Do not separate paragraphs in the copyright statement with blank lines,  | 
10  | 
#
 | 
| 
1563.2.1
by Robert Collins
 Merge in a variation of the versionedfile api from versioned-file.  | 
11  | 
# This program is distributed in the hope that it will be useful,
 | 
12  | 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|
13  | 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|
14  | 
# GNU General Public License for more details.
 | 
|
| 
1887.1.1
by Adeodato Simó
 Do not separate paragraphs in the copyright statement with blank lines,  | 
15  | 
#
 | 
| 
1563.2.1
by Robert Collins
 Merge in a variation of the versionedfile api from versioned-file.  | 
16  | 
# You should have received a copy of the GNU General Public License
 | 
17  | 
# along with this program; if not, write to the Free Software
 | 
|
18  | 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
|
19  | 
||
20  | 
||
| 
1704.2.15
by Martin Pool
 Remove TODO about knit testing printed from test suite  | 
21  | 
# TODO: might be nice to create a versionedfile with some type of corruption
 | 
22  | 
# considered typical and check that it can be detected/corrected.
 | 
|
23  | 
||
| 
1664.2.9
by Aaron Bentley
 Ported weave merge test to versionedfile  | 
24  | 
from StringIO import StringIO  | 
25  | 
||
| 
1563.2.6
by Robert Collins
 Start check tests for knits (pending), and remove dead code.  | 
26  | 
import bzrlib  | 
| 
2039.1.1
by Aaron Bentley
 Clean up progress properly when interrupted during fetch (#54000)  | 
27  | 
from bzrlib import (  | 
28  | 
errors,  | 
|
| 
2309.4.7
by John Arbash Meinel
 Update VersionedFile tests to ensure that they can take Unicode,  | 
29  | 
osutils,  | 
| 
2039.1.1
by Aaron Bentley
 Clean up progress properly when interrupted during fetch (#54000)  | 
30  | 
progress,  | 
31  | 
    )
 | 
|
| 
1563.2.11
by Robert Collins
 Consolidate reweave and join as we have no separate usage, make reweave tests apply to all versionedfile implementations and deprecate the old reweave apis.  | 
32  | 
from bzrlib.errors import (  | 
33  | 
RevisionNotPresent,  | 
|
34  | 
RevisionAlreadyPresent,  | 
|
35  | 
                           WeaveParentMismatch
 | 
|
36  | 
                           )
 | 
|
| 
2770.1.1
by Aaron Bentley
 Initial implmentation of plain knit annotation  | 
37  | 
from bzrlib.knit import (  | 
38  | 
KnitVersionedFile,  | 
|
39  | 
KnitAnnotateFactory,  | 
|
| 
2770.1.10
by Aaron Bentley
 Merge bzr.dev  | 
40  | 
KnitPlainFactory,  | 
| 
2770.1.1
by Aaron Bentley
 Initial implmentation of plain knit annotation  | 
41  | 
    )
 | 
| 
2535.3.48
by Andrew Bennetts
 Merge from bzr.dev.  | 
42  | 
from bzrlib.tests import TestCaseWithMemoryTransport, TestSkipped  | 
| 
1666.1.1
by Robert Collins
 Add trivial http-using test for versioned files.  | 
43  | 
from bzrlib.tests.HTTPTestUtil import TestCaseWithWebserver  | 
| 
1563.2.1
by Robert Collins
 Merge in a variation of the versionedfile api from versioned-file.  | 
44  | 
from bzrlib.trace import mutter  | 
| 
1563.2.16
by Robert Collins
 Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.  | 
45  | 
from bzrlib.transport import get_transport  | 
| 
1563.2.13
by Robert Collins
 InterVersionedFile implemented.  | 
46  | 
from bzrlib.transport.memory import MemoryTransport  | 
| 
1684.3.1
by Robert Collins
 Fix versioned file joins with empty targets.  | 
47  | 
from bzrlib.tsort import topo_sort  | 
| 
1563.2.12
by Robert Collins
 Checkpointing: created InterObject to factor out common inter object worker code, added InterVersionedFile and tests to allow making join work between any versionedfile.  | 
48  | 
import bzrlib.versionedfile as versionedfile  | 
| 
1563.2.9
by Robert Collins
 Update versionedfile api tests to ensure that data is available after every operation.  | 
49  | 
from bzrlib.weave import WeaveFile  | 
| 
1664.2.9
by Aaron Bentley
 Ported weave merge test to versionedfile  | 
50  | 
from bzrlib.weavefile import read_weave, write_weave  | 
| 
1563.2.1
by Robert Collins
 Merge in a variation of the versionedfile api from versioned-file.  | 
51  | 
|
52  | 
||
53  | 
class VersionedFileTestMixIn(object):  | 
|
54  | 
"""A mixin test class for testing VersionedFiles.  | 
|
55  | 
||
56  | 
    This is not an adaptor-style test at this point because
 | 
|
57  | 
    theres no dynamic substitution of versioned file implementations,
 | 
|
58  | 
    they are strictly controlled by their owning repositories.
 | 
|
59  | 
    """
 | 
|
60  | 
||
61  | 
def test_add(self):  | 
|
62  | 
f = self.get_file()  | 
|
63  | 
f.add_lines('r0', [], ['a\n', 'b\n'])  | 
|
64  | 
f.add_lines('r1', ['r0'], ['b\n', 'c\n'])  | 
|
| 
1563.2.9
by Robert Collins
 Update versionedfile api tests to ensure that data is available after every operation.  | 
65  | 
def verify_file(f):  | 
66  | 
versions = f.versions()  | 
|
67  | 
self.assertTrue('r0' in versions)  | 
|
68  | 
self.assertTrue('r1' in versions)  | 
|
69  | 
self.assertEquals(f.get_lines('r0'), ['a\n', 'b\n'])  | 
|
70  | 
self.assertEquals(f.get_text('r0'), 'a\nb\n')  | 
|
71  | 
self.assertEquals(f.get_lines('r1'), ['b\n', 'c\n'])  | 
|
| 
1563.2.18
by Robert Collins
 get knit repositories really using knits for text storage.  | 
72  | 
self.assertEqual(2, len(f))  | 
73  | 
self.assertEqual(2, f.num_versions())  | 
|
| 
1563.2.9
by Robert Collins
 Update versionedfile api tests to ensure that data is available after every operation.  | 
74  | 
|
75  | 
self.assertRaises(RevisionNotPresent,  | 
|
76  | 
f.add_lines, 'r2', ['foo'], [])  | 
|
77  | 
self.assertRaises(RevisionAlreadyPresent,  | 
|
78  | 
f.add_lines, 'r1', [], [])  | 
|
79  | 
verify_file(f)  | 
|
| 
1666.1.6
by Robert Collins
 Make knit the default format.  | 
80  | 
        # this checks that reopen with create=True does not break anything.
 | 
81  | 
f = self.reopen_file(create=True)  | 
|
| 
1563.2.9
by Robert Collins
 Update versionedfile api tests to ensure that data is available after every operation.  | 
82  | 
verify_file(f)  | 
| 
1563.2.1
by Robert Collins
 Merge in a variation of the versionedfile api from versioned-file.  | 
83  | 
|
| 
1596.2.32
by Robert Collins
 Reduce re-extraction of texts during weave to knit joins by providing a memoisation facility.  | 
84  | 
def test_adds_with_parent_texts(self):  | 
85  | 
f = self.get_file()  | 
|
86  | 
parent_texts = {}  | 
|
| 
2776.1.1
by Robert Collins
 * The ``add_lines`` methods on ``VersionedFile`` implementations has changed  | 
87  | 
_, _, parent_texts['r0'] = f.add_lines('r0', [], ['a\n', 'b\n'])  | 
| 
1596.2.32
by Robert Collins
 Reduce re-extraction of texts during weave to knit joins by providing a memoisation facility.  | 
88  | 
try:  | 
| 
2776.1.1
by Robert Collins
 * The ``add_lines`` methods on ``VersionedFile`` implementations has changed  | 
89  | 
_, _, parent_texts['r1'] = f.add_lines_with_ghosts('r1',  | 
90  | 
['r0', 'ghost'], ['b\n', 'c\n'], parent_texts=parent_texts)  | 
|
| 
1596.2.32
by Robert Collins
 Reduce re-extraction of texts during weave to knit joins by providing a memoisation facility.  | 
91  | 
except NotImplementedError:  | 
92  | 
            # if the format doesn't support ghosts, just add normally.
 | 
|
| 
2776.1.1
by Robert Collins
 * The ``add_lines`` methods on ``VersionedFile`` implementations has changed  | 
93  | 
_, _, parent_texts['r1'] = f.add_lines('r1',  | 
94  | 
['r0'], ['b\n', 'c\n'], parent_texts=parent_texts)  | 
|
| 
1596.2.32
by Robert Collins
 Reduce re-extraction of texts during weave to knit joins by providing a memoisation facility.  | 
95  | 
f.add_lines('r2', ['r1'], ['c\n', 'd\n'], parent_texts=parent_texts)  | 
96  | 
self.assertNotEqual(None, parent_texts['r0'])  | 
|
97  | 
self.assertNotEqual(None, parent_texts['r1'])  | 
|
98  | 
def verify_file(f):  | 
|
99  | 
versions = f.versions()  | 
|
100  | 
self.assertTrue('r0' in versions)  | 
|
101  | 
self.assertTrue('r1' in versions)  | 
|
102  | 
self.assertTrue('r2' in versions)  | 
|
103  | 
self.assertEquals(f.get_lines('r0'), ['a\n', 'b\n'])  | 
|
104  | 
self.assertEquals(f.get_lines('r1'), ['b\n', 'c\n'])  | 
|
105  | 
self.assertEquals(f.get_lines('r2'), ['c\n', 'd\n'])  | 
|
106  | 
self.assertEqual(3, f.num_versions())  | 
|
107  | 
origins = f.annotate('r1')  | 
|
108  | 
self.assertEquals(origins[0][0], 'r0')  | 
|
109  | 
self.assertEquals(origins[1][0], 'r1')  | 
|
110  | 
origins = f.annotate('r2')  | 
|
111  | 
self.assertEquals(origins[0][0], 'r1')  | 
|
112  | 
self.assertEquals(origins[1][0], 'r2')  | 
|
113  | 
||
114  | 
verify_file(f)  | 
|
115  | 
f = self.reopen_file()  | 
|
116  | 
verify_file(f)  | 
|
117  | 
||
| 
2805.6.7
by Robert Collins
 Review feedback.  | 
118  | 
def test_add_unicode_content(self):  | 
119  | 
        # unicode content is not permitted in versioned files. 
 | 
|
120  | 
        # versioned files version sequences of bytes only.
 | 
|
121  | 
vf = self.get_file()  | 
|
122  | 
self.assertRaises(errors.BzrBadParameterUnicode,  | 
|
123  | 
vf.add_lines, 'a', [], ['a\n', u'b\n', 'c\n'])  | 
|
124  | 
self.assertRaises(  | 
|
125  | 
(errors.BzrBadParameterUnicode, NotImplementedError),  | 
|
126  | 
vf.add_lines_with_ghosts, 'a', [], ['a\n', u'b\n', 'c\n'])  | 
|
127  | 
||
| 
2520.4.150
by Aaron Bentley
 Test that non-Weave uses left_matching_blocks for add_lines  | 
128  | 
def test_add_follows_left_matching_blocks(self):  | 
129  | 
"""If we change left_matching_blocks, delta changes  | 
|
130  | 
||
131  | 
        Note: There are multiple correct deltas in this case, because
 | 
|
132  | 
        we start with 1 "a" and we get 3.
 | 
|
133  | 
        """
 | 
|
134  | 
vf = self.get_file()  | 
|
135  | 
if isinstance(vf, WeaveFile):  | 
|
136  | 
raise TestSkipped("WeaveFile ignores left_matching_blocks")  | 
|
137  | 
vf.add_lines('1', [], ['a\n'])  | 
|
138  | 
vf.add_lines('2', ['1'], ['a\n', 'a\n', 'a\n'],  | 
|
139  | 
left_matching_blocks=[(0, 0, 1), (1, 3, 0)])  | 
|
| 
2794.1.2
by Robert Collins
 Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.  | 
140  | 
self.assertEqual(['a\n', 'a\n', 'a\n'], vf.get_lines('2'))  | 
| 
2520.4.150
by Aaron Bentley
 Test that non-Weave uses left_matching_blocks for add_lines  | 
141  | 
vf.add_lines('3', ['1'], ['a\n', 'a\n', 'a\n'],  | 
142  | 
left_matching_blocks=[(0, 2, 1), (1, 3, 0)])  | 
|
| 
2794.1.2
by Robert Collins
 Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.  | 
143  | 
self.assertEqual(['a\n', 'a\n', 'a\n'], vf.get_lines('3'))  | 
| 
2520.4.150
by Aaron Bentley
 Test that non-Weave uses left_matching_blocks for add_lines  | 
144  | 
|
| 
2805.6.7
by Robert Collins
 Review feedback.  | 
145  | 
def test_inline_newline_throws(self):  | 
146  | 
        # \r characters are not permitted in lines being added
 | 
|
147  | 
vf = self.get_file()  | 
|
148  | 
self.assertRaises(errors.BzrBadParameterContainsNewline,  | 
|
149  | 
vf.add_lines, 'a', [], ['a\n\n'])  | 
|
150  | 
self.assertRaises(  | 
|
151  | 
(errors.BzrBadParameterContainsNewline, NotImplementedError),  | 
|
152  | 
vf.add_lines_with_ghosts, 'a', [], ['a\n\n'])  | 
|
153  | 
        # but inline CR's are allowed
 | 
|
154  | 
vf.add_lines('a', [], ['a\r\n'])  | 
|
155  | 
try:  | 
|
156  | 
vf.add_lines_with_ghosts('b', [], ['a\r\n'])  | 
|
157  | 
except NotImplementedError:  | 
|
158  | 
            pass
 | 
|
159  | 
||
| 
2229.2.1
by Aaron Bentley
 Reject reserved ids in versiondfile, tree, branch and repository  | 
160  | 
def test_add_reserved(self):  | 
161  | 
vf = self.get_file()  | 
|
162  | 
self.assertRaises(errors.ReservedId,  | 
|
163  | 
vf.add_lines, 'a:', [], ['a\n', 'b\n', 'c\n'])  | 
|
164  | 
||
| 
2794.1.1
by Robert Collins
 Allow knits to be instructed not to add a text based on a sha, for commit.  | 
165  | 
def test_add_lines_nostoresha(self):  | 
166  | 
"""When nostore_sha is supplied using old content raises."""  | 
|
167  | 
vf = self.get_file()  | 
|
168  | 
empty_text = ('a', [])  | 
|
169  | 
sample_text_nl = ('b', ["foo\n", "bar\n"])  | 
|
170  | 
sample_text_no_nl = ('c', ["foo\n", "bar"])  | 
|
171  | 
shas = []  | 
|
172  | 
for version, lines in (empty_text, sample_text_nl, sample_text_no_nl):  | 
|
173  | 
sha, _, _ = vf.add_lines(version, [], lines)  | 
|
174  | 
shas.append(sha)  | 
|
175  | 
        # we now have a copy of all the lines in the vf.
 | 
|
176  | 
for sha, (version, lines) in zip(  | 
|
177  | 
shas, (empty_text, sample_text_nl, sample_text_no_nl)):  | 
|
178  | 
self.assertRaises(errors.ExistingContent,  | 
|
179  | 
vf.add_lines, version + "2", [], lines,  | 
|
180  | 
nostore_sha=sha)  | 
|
181  | 
            # and no new version should have been added.
 | 
|
182  | 
self.assertRaises(errors.RevisionNotPresent, vf.get_lines,  | 
|
183  | 
version + "2")  | 
|
184  | 
||
| 
2803.1.1
by Robert Collins
 Fix typo in ghosts version of test_add_lines_nostoresha.  | 
185  | 
def test_add_lines_with_ghosts_nostoresha(self):  | 
| 
2794.1.1
by Robert Collins
 Allow knits to be instructed not to add a text based on a sha, for commit.  | 
186  | 
"""When nostore_sha is supplied using old content raises."""  | 
187  | 
vf = self.get_file()  | 
|
188  | 
empty_text = ('a', [])  | 
|
189  | 
sample_text_nl = ('b', ["foo\n", "bar\n"])  | 
|
190  | 
sample_text_no_nl = ('c', ["foo\n", "bar"])  | 
|
191  | 
shas = []  | 
|
192  | 
for version, lines in (empty_text, sample_text_nl, sample_text_no_nl):  | 
|
193  | 
sha, _, _ = vf.add_lines(version, [], lines)  | 
|
194  | 
shas.append(sha)  | 
|
195  | 
        # we now have a copy of all the lines in the vf.
 | 
|
196  | 
        # is the test applicable to this vf implementation?
 | 
|
197  | 
try:  | 
|
198  | 
vf.add_lines_with_ghosts('d', [], [])  | 
|
199  | 
except NotImplementedError:  | 
|
200  | 
raise TestSkipped("add_lines_with_ghosts is optional")  | 
|
201  | 
for sha, (version, lines) in zip(  | 
|
202  | 
shas, (empty_text, sample_text_nl, sample_text_no_nl)):  | 
|
203  | 
self.assertRaises(errors.ExistingContent,  | 
|
204  | 
vf.add_lines_with_ghosts, version + "2", [], lines,  | 
|
205  | 
nostore_sha=sha)  | 
|
206  | 
            # and no new version should have been added.
 | 
|
207  | 
self.assertRaises(errors.RevisionNotPresent, vf.get_lines,  | 
|
208  | 
version + "2")  | 
|
209  | 
||
| 
2776.1.1
by Robert Collins
 * The ``add_lines`` methods on ``VersionedFile`` implementations has changed  | 
210  | 
def test_add_lines_return_value(self):  | 
211  | 
        # add_lines should return the sha1 and the text size.
 | 
|
212  | 
vf = self.get_file()  | 
|
213  | 
empty_text = ('a', [])  | 
|
214  | 
sample_text_nl = ('b', ["foo\n", "bar\n"])  | 
|
215  | 
sample_text_no_nl = ('c', ["foo\n", "bar"])  | 
|
216  | 
        # check results for the three cases:
 | 
|
217  | 
for version, lines in (empty_text, sample_text_nl, sample_text_no_nl):  | 
|
218  | 
            # the first two elements are the same for all versioned files:
 | 
|
219  | 
            # - the digest and the size of the text. For some versioned files
 | 
|
220  | 
            #   additional data is returned in additional tuple elements.
 | 
|
221  | 
result = vf.add_lines(version, [], lines)  | 
|
222  | 
self.assertEqual(3, len(result))  | 
|
223  | 
self.assertEqual((osutils.sha_strings(lines), sum(map(len, lines))),  | 
|
224  | 
result[0:2])  | 
|
225  | 
        # parents should not affect the result:
 | 
|
226  | 
lines = sample_text_nl[1]  | 
|
227  | 
self.assertEqual((osutils.sha_strings(lines), sum(map(len, lines))),  | 
|
228  | 
vf.add_lines('d', ['b', 'c'], lines)[0:2])  | 
|
229  | 
||
| 
2229.2.1
by Aaron Bentley
 Reject reserved ids in versiondfile, tree, branch and repository  | 
230  | 
def test_get_reserved(self):  | 
231  | 
vf = self.get_file()  | 
|
232  | 
self.assertRaises(errors.ReservedId, vf.get_texts, ['b:'])  | 
|
233  | 
self.assertRaises(errors.ReservedId, vf.get_lines, 'b:')  | 
|
234  | 
self.assertRaises(errors.ReservedId, vf.get_text, 'b:')  | 
|
235  | 
||
| 
2520.4.85
by Aaron Bentley
 Get all test passing (which just proves there aren't enough tests!)  | 
236  | 
def test_make_mpdiffs(self):  | 
| 
2520.4.3
by Aaron Bentley
 Implement plain strategy for extracting and installing multiparent diffs  | 
237  | 
from bzrlib import multiparent  | 
238  | 
vf = self.get_file('foo')  | 
|
239  | 
sha1s = self._setup_for_deltas(vf)  | 
|
240  | 
new_vf = self.get_file('bar')  | 
|
241  | 
for version in multiparent.topo_iter(vf):  | 
|
| 
2520.4.85
by Aaron Bentley
 Get all test passing (which just proves there aren't enough tests!)  | 
242  | 
mpdiff = vf.make_mpdiffs([version])[0]  | 
243  | 
new_vf.add_mpdiffs([(version, vf.get_parents(version),  | 
|
244  | 
vf.get_sha1(version), mpdiff)])  | 
|
| 
2520.4.3
by Aaron Bentley
 Implement plain strategy for extracting and installing multiparent diffs  | 
245  | 
self.assertEqualDiff(vf.get_text(version),  | 
246  | 
new_vf.get_text(version))  | 
|
247  | 
||
| 
1596.2.38
by Robert Collins
 rollback from using deltas to using fulltexts - deltas need more work to be ready.  | 
248  | 
def _setup_for_deltas(self, f):  | 
| 
2794.1.2
by Robert Collins
 Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.  | 
249  | 
self.assertFalse(f.has_version('base'))  | 
| 
1596.2.36
by Robert Collins
 add a get_delta api to versioned_file.  | 
250  | 
        # add texts that should trip the knit maximum delta chain threshold
 | 
251  | 
        # as well as doing parallel chains of data in knits.
 | 
|
252  | 
        # this is done by two chains of 25 insertions
 | 
|
253  | 
f.add_lines('base', [], ['line\n'])  | 
|
| 
1596.2.38
by Robert Collins
 rollback from using deltas to using fulltexts - deltas need more work to be ready.  | 
254  | 
f.add_lines('noeol', ['base'], ['line'])  | 
255  | 
        # detailed eol tests:
 | 
|
256  | 
        # shared last line with parent no-eol
 | 
|
257  | 
f.add_lines('noeolsecond', ['noeol'], ['line\n', 'line'])  | 
|
258  | 
        # differing last line with parent, both no-eol
 | 
|
259  | 
f.add_lines('noeolnotshared', ['noeolsecond'], ['line\n', 'phone'])  | 
|
260  | 
        # add eol following a noneol parent, change content
 | 
|
261  | 
f.add_lines('eol', ['noeol'], ['phone\n'])  | 
|
262  | 
        # add eol following a noneol parent, no change content
 | 
|
263  | 
f.add_lines('eolline', ['noeol'], ['line\n'])  | 
|
264  | 
        # noeol with no parents:
 | 
|
265  | 
f.add_lines('noeolbase', [], ['line'])  | 
|
266  | 
        # noeol preceeding its leftmost parent in the output:
 | 
|
267  | 
        # this is done by making it a merge of two parents with no common
 | 
|
268  | 
        # anestry: noeolbase and noeol with the 
 | 
|
269  | 
        # later-inserted parent the leftmost.
 | 
|
270  | 
f.add_lines('eolbeforefirstparent', ['noeolbase', 'noeol'], ['line'])  | 
|
271  | 
        # two identical eol texts
 | 
|
272  | 
f.add_lines('noeoldup', ['noeol'], ['line'])  | 
|
| 
1596.2.36
by Robert Collins
 add a get_delta api to versioned_file.  | 
273  | 
next_parent = 'base'  | 
274  | 
text_name = 'chain1-'  | 
|
275  | 
text = ['line\n']  | 
|
276  | 
sha1s = {0 :'da6d3141cb4a5e6f464bf6e0518042ddc7bfd079',  | 
|
277  | 
1 :'45e21ea146a81ea44a821737acdb4f9791c8abe7',  | 
|
278  | 
2 :'e1f11570edf3e2a070052366c582837a4fe4e9fa',  | 
|
279  | 
3 :'26b4b8626da827088c514b8f9bbe4ebf181edda1',  | 
|
280  | 
4 :'e28a5510be25ba84d31121cff00956f9970ae6f6',  | 
|
281  | 
5 :'d63ec0ce22e11dcf65a931b69255d3ac747a318d',  | 
|
282  | 
6 :'2c2888d288cb5e1d98009d822fedfe6019c6a4ea',  | 
|
283  | 
7 :'95c14da9cafbf828e3e74a6f016d87926ba234ab',  | 
|
284  | 
8 :'779e9a0b28f9f832528d4b21e17e168c67697272',  | 
|
285  | 
9 :'1f8ff4e5c6ff78ac106fcfe6b1e8cb8740ff9a8f',  | 
|
286  | 
10:'131a2ae712cf51ed62f143e3fbac3d4206c25a05',  | 
|
287  | 
11:'c5a9d6f520d2515e1ec401a8f8a67e6c3c89f199',  | 
|
288  | 
12:'31a2286267f24d8bedaa43355f8ad7129509ea85',  | 
|
289  | 
13:'dc2a7fe80e8ec5cae920973973a8ee28b2da5e0a',  | 
|
290  | 
14:'2c4b1736566b8ca6051e668de68650686a3922f2',  | 
|
291  | 
15:'5912e4ecd9b0c07be4d013e7e2bdcf9323276cde',  | 
|
292  | 
16:'b0d2e18d3559a00580f6b49804c23fea500feab3',  | 
|
293  | 
17:'8e1d43ad72f7562d7cb8f57ee584e20eb1a69fc7',  | 
|
294  | 
18:'5cf64a3459ae28efa60239e44b20312d25b253f3',  | 
|
295  | 
19:'1ebed371807ba5935958ad0884595126e8c4e823',  | 
|
296  | 
20:'2aa62a8b06fb3b3b892a3292a068ade69d5ee0d3',  | 
|
297  | 
21:'01edc447978004f6e4e962b417a4ae1955b6fe5d',  | 
|
298  | 
22:'d8d8dc49c4bf0bab401e0298bb5ad827768618bb',  | 
|
299  | 
23:'c21f62b1c482862983a8ffb2b0c64b3451876e3f',  | 
|
300  | 
24:'c0593fe795e00dff6b3c0fe857a074364d5f04fc',  | 
|
301  | 
25:'dd1a1cf2ba9cc225c3aff729953e6364bf1d1855',  | 
|
302  | 
                 }
 | 
|
303  | 
for depth in range(26):  | 
|
304  | 
new_version = text_name + '%s' % depth  | 
|
305  | 
text = text + ['line\n']  | 
|
306  | 
f.add_lines(new_version, [next_parent], text)  | 
|
307  | 
next_parent = new_version  | 
|
308  | 
next_parent = 'base'  | 
|
309  | 
text_name = 'chain2-'  | 
|
310  | 
text = ['line\n']  | 
|
311  | 
for depth in range(26):  | 
|
312  | 
new_version = text_name + '%s' % depth  | 
|
313  | 
text = text + ['line\n']  | 
|
314  | 
f.add_lines(new_version, [next_parent], text)  | 
|
315  | 
next_parent = new_version  | 
|
| 
1596.2.38
by Robert Collins
 rollback from using deltas to using fulltexts - deltas need more work to be ready.  | 
316  | 
return sha1s  | 
| 
1596.2.37
by Robert Collins
 Switch to delta based content copying in the generic versioned file copier.  | 
317  | 
|
| 
1563.2.1
by Robert Collins
 Merge in a variation of the versionedfile api from versioned-file.  | 
318  | 
def test_ancestry(self):  | 
319  | 
f = self.get_file()  | 
|
| 
1563.2.29
by Robert Collins
 Remove all but fetch references to repository.revision_store.  | 
320  | 
self.assertEqual([], f.get_ancestry([]))  | 
| 
1563.2.1
by Robert Collins
 Merge in a variation of the versionedfile api from versioned-file.  | 
321  | 
f.add_lines('r0', [], ['a\n', 'b\n'])  | 
322  | 
f.add_lines('r1', ['r0'], ['b\n', 'c\n'])  | 
|
323  | 
f.add_lines('r2', ['r0'], ['b\n', 'c\n'])  | 
|
324  | 
f.add_lines('r3', ['r2'], ['b\n', 'c\n'])  | 
|
325  | 
f.add_lines('rM', ['r1', 'r2'], ['b\n', 'c\n'])  | 
|
| 
1563.2.29
by Robert Collins
 Remove all but fetch references to repository.revision_store.  | 
326  | 
self.assertEqual([], f.get_ancestry([]))  | 
| 
1563.2.35
by Robert Collins
 cleanup deprecation warnings and finish conversion so the inventory is knit based too.  | 
327  | 
versions = f.get_ancestry(['rM'])  | 
328  | 
        # there are some possibilities:
 | 
|
329  | 
        # r0 r1 r2 rM r3
 | 
|
330  | 
        # r0 r1 r2 r3 rM
 | 
|
331  | 
        # etc
 | 
|
332  | 
        # so we check indexes
 | 
|
333  | 
r0 = versions.index('r0')  | 
|
334  | 
r1 = versions.index('r1')  | 
|
335  | 
r2 = versions.index('r2')  | 
|
336  | 
self.assertFalse('r3' in versions)  | 
|
337  | 
rM = versions.index('rM')  | 
|
338  | 
self.assertTrue(r0 < r1)  | 
|
339  | 
self.assertTrue(r0 < r2)  | 
|
340  | 
self.assertTrue(r1 < rM)  | 
|
341  | 
self.assertTrue(r2 < rM)  | 
|
| 
1563.2.1
by Robert Collins
 Merge in a variation of the versionedfile api from versioned-file.  | 
342  | 
|
343  | 
self.assertRaises(RevisionNotPresent,  | 
|
344  | 
f.get_ancestry, ['rM', 'rX'])  | 
|
| 
1594.2.21
by Robert Collins
 Teach versioned files to prevent mutation after finishing.  | 
345  | 
|
| 
2530.1.1
by Aaron Bentley
 Make topological sorting optional for get_ancestry  | 
346  | 
self.assertEqual(set(f.get_ancestry('rM')),  | 
347  | 
set(f.get_ancestry('rM', topo_sorted=False)))  | 
|
348  | 
||
| 
1594.2.21
by Robert Collins
 Teach versioned files to prevent mutation after finishing.  | 
349  | 
def test_mutate_after_finish(self):  | 
350  | 
f = self.get_file()  | 
|
351  | 
f.transaction_finished()  | 
|
352  | 
self.assertRaises(errors.OutSideTransaction, f.add_lines, '', [], [])  | 
|
353  | 
self.assertRaises(errors.OutSideTransaction, f.add_lines_with_ghosts, '', [], [])  | 
|
354  | 
self.assertRaises(errors.OutSideTransaction, f.join, '')  | 
|
| 
1594.2.24
by Robert Collins
 Make use of the transaction finalisation warning support to implement in-knit caching.  | 
355  | 
self.assertRaises(errors.OutSideTransaction, f.clone_text, 'base', 'bar', ['foo'])  | 
| 
1563.2.7
by Robert Collins
 add versioned file clear_cache entry.  | 
356  | 
|
357  | 
def test_clear_cache(self):  | 
|
358  | 
f = self.get_file()  | 
|
359  | 
        # on a new file it should not error
 | 
|
360  | 
f.clear_cache()  | 
|
361  | 
        # and after adding content, doing a clear_cache and a get should work.
 | 
|
362  | 
f.add_lines('0', [], ['a'])  | 
|
363  | 
f.clear_cache()  | 
|
364  | 
self.assertEqual(['a'], f.get_lines('0'))  | 
|
| 
1563.2.1
by Robert Collins
 Merge in a variation of the versionedfile api from versioned-file.  | 
365  | 
|
366  | 
def test_clone_text(self):  | 
|
367  | 
f = self.get_file()  | 
|
368  | 
f.add_lines('r0', [], ['a\n', 'b\n'])  | 
|
| 
1563.2.5
by Robert Collins
 Remove unused transaction references from knit.py and the versionedfile interface.  | 
369  | 
f.clone_text('r1', 'r0', ['r0'])  | 
| 
1563.2.9
by Robert Collins
 Update versionedfile api tests to ensure that data is available after every operation.  | 
370  | 
def verify_file(f):  | 
371  | 
self.assertEquals(f.get_lines('r1'), f.get_lines('r0'))  | 
|
372  | 
self.assertEquals(f.get_lines('r1'), ['a\n', 'b\n'])  | 
|
373  | 
self.assertEquals(f.get_parents('r1'), ['r0'])  | 
|
374  | 
||
375  | 
self.assertRaises(RevisionNotPresent,  | 
|
376  | 
f.clone_text, 'r2', 'rX', [])  | 
|
377  | 
self.assertRaises(RevisionAlreadyPresent,  | 
|
378  | 
f.clone_text, 'r1', 'r0', [])  | 
|
379  | 
verify_file(f)  | 
|
380  | 
verify_file(self.reopen_file())  | 
|
| 
1563.2.1
by Robert Collins
 Merge in a variation of the versionedfile api from versioned-file.  | 
381  | 
|
| 
1563.2.13
by Robert Collins
 InterVersionedFile implemented.  | 
382  | 
def test_create_empty(self):  | 
383  | 
f = self.get_file()  | 
|
384  | 
f.add_lines('0', [], ['a\n'])  | 
|
385  | 
new_f = f.create_empty('t', MemoryTransport())  | 
|
386  | 
        # smoke test, specific types should check it is honoured correctly for
 | 
|
387  | 
        # non type attributes
 | 
|
388  | 
self.assertEqual([], new_f.versions())  | 
|
389  | 
self.assertTrue(isinstance(new_f, f.__class__))  | 
|
390  | 
||
| 
1563.2.15
by Robert Collins
 remove the weavestore assumptions about the number and nature of files it manages.  | 
391  | 
def test_copy_to(self):  | 
392  | 
f = self.get_file()  | 
|
393  | 
f.add_lines('0', [], ['a\n'])  | 
|
394  | 
t = MemoryTransport()  | 
|
395  | 
f.copy_to('foo', t)  | 
|
396  | 
for suffix in f.__class__.get_suffixes():  | 
|
397  | 
self.assertTrue(t.has('foo' + suffix))  | 
|
398  | 
||
399  | 
def test_get_suffixes(self):  | 
|
400  | 
f = self.get_file()  | 
|
401  | 
        # should be the same
 | 
|
402  | 
self.assertEqual(f.__class__.get_suffixes(), f.__class__.get_suffixes())  | 
|
403  | 
        # and should be a list
 | 
|
404  | 
self.assertTrue(isinstance(f.__class__.get_suffixes(), list))  | 
|
405  | 
||
| 
1684.3.1
by Robert Collins
 Fix versioned file joins with empty targets.  | 
406  | 
def build_graph(self, file, graph):  | 
407  | 
for node in topo_sort(graph.items()):  | 
|
408  | 
file.add_lines(node, graph[node], [])  | 
|
409  | 
||
| 
1563.2.13
by Robert Collins
 InterVersionedFile implemented.  | 
410  | 
def test_get_graph(self):  | 
411  | 
f = self.get_file()  | 
|
| 
1684.3.1
by Robert Collins
 Fix versioned file joins with empty targets.  | 
412  | 
graph = {  | 
| 
2592.3.43
by Robert Collins
 A knit iter_parents API.  | 
413  | 
'v1': (),  | 
414  | 
'v2': ('v1', ),  | 
|
415  | 
'v3': ('v2', )}  | 
|
| 
1684.3.1
by Robert Collins
 Fix versioned file joins with empty targets.  | 
416  | 
self.build_graph(f, graph)  | 
417  | 
self.assertEqual(graph, f.get_graph())  | 
|
418  | 
||
419  | 
def test_get_graph_partial(self):  | 
|
420  | 
f = self.get_file()  | 
|
421  | 
complex_graph = {}  | 
|
422  | 
simple_a = {  | 
|
| 
2592.3.43
by Robert Collins
 A knit iter_parents API.  | 
423  | 
'c': (),  | 
424  | 
'b': ('c', ),  | 
|
425  | 
'a': ('b', ),  | 
|
| 
1684.3.1
by Robert Collins
 Fix versioned file joins with empty targets.  | 
426  | 
            }
 | 
427  | 
complex_graph.update(simple_a)  | 
|
428  | 
simple_b = {  | 
|
| 
2592.3.43
by Robert Collins
 A knit iter_parents API.  | 
429  | 
'c': (),  | 
430  | 
'b': ('c', ),  | 
|
| 
1684.3.1
by Robert Collins
 Fix versioned file joins with empty targets.  | 
431  | 
            }
 | 
432  | 
complex_graph.update(simple_b)  | 
|
433  | 
simple_gam = {  | 
|
| 
2592.3.43
by Robert Collins
 A knit iter_parents API.  | 
434  | 
'c': (),  | 
435  | 
'oo': (),  | 
|
436  | 
'bar': ('oo', 'c'),  | 
|
437  | 
'gam': ('bar', ),  | 
|
| 
1684.3.1
by Robert Collins
 Fix versioned file joins with empty targets.  | 
438  | 
            }
 | 
439  | 
complex_graph.update(simple_gam)  | 
|
440  | 
simple_b_gam = {}  | 
|
441  | 
simple_b_gam.update(simple_gam)  | 
|
442  | 
simple_b_gam.update(simple_b)  | 
|
443  | 
self.build_graph(f, complex_graph)  | 
|
444  | 
self.assertEqual(simple_a, f.get_graph(['a']))  | 
|
445  | 
self.assertEqual(simple_b, f.get_graph(['b']))  | 
|
446  | 
self.assertEqual(simple_gam, f.get_graph(['gam']))  | 
|
447  | 
self.assertEqual(simple_b_gam, f.get_graph(['b', 'gam']))  | 
|
| 
1563.2.13
by Robert Collins
 InterVersionedFile implemented.  | 
448  | 
|
| 
1563.2.1
by Robert Collins
 Merge in a variation of the versionedfile api from versioned-file.  | 
449  | 
def test_get_parents(self):  | 
450  | 
f = self.get_file()  | 
|
451  | 
f.add_lines('r0', [], ['a\n', 'b\n'])  | 
|
452  | 
f.add_lines('r1', [], ['a\n', 'b\n'])  | 
|
453  | 
f.add_lines('r2', [], ['a\n', 'b\n'])  | 
|
454  | 
f.add_lines('r3', [], ['a\n', 'b\n'])  | 
|
455  | 
f.add_lines('m', ['r0', 'r1', 'r2', 'r3'], ['a\n', 'b\n'])  | 
|
456  | 
self.assertEquals(f.get_parents('m'), ['r0', 'r1', 'r2', 'r3'])  | 
|
457  | 
||
458  | 
self.assertRaises(RevisionNotPresent,  | 
|
459  | 
f.get_parents, 'y')  | 
|
460  | 
||
461  | 
def test_annotate(self):  | 
|
462  | 
f = self.get_file()  | 
|
463  | 
f.add_lines('r0', [], ['a\n', 'b\n'])  | 
|
464  | 
f.add_lines('r1', ['r0'], ['c\n', 'b\n'])  | 
|
465  | 
origins = f.annotate('r1')  | 
|
466  | 
self.assertEquals(origins[0][0], 'r1')  | 
|
467  | 
self.assertEquals(origins[1][0], 'r0')  | 
|
468  | 
||
469  | 
self.assertRaises(RevisionNotPresent,  | 
|
470  | 
f.annotate, 'foo')  | 
|
471  | 
||
| 
1563.2.6
by Robert Collins
 Start check tests for knits (pending), and remove dead code.  | 
472  | 
def test_detection(self):  | 
473  | 
        # Test weaves detect corruption.
 | 
|
474  | 
        #
 | 
|
475  | 
        # Weaves contain a checksum of their texts.
 | 
|
476  | 
        # When a text is extracted, this checksum should be
 | 
|
477  | 
        # verified.
 | 
|
478  | 
||
479  | 
w = self.get_file_corrupted_text()  | 
|
480  | 
||
481  | 
self.assertEqual('hello\n', w.get_text('v1'))  | 
|
482  | 
self.assertRaises(errors.WeaveInvalidChecksum, w.get_text, 'v2')  | 
|
483  | 
self.assertRaises(errors.WeaveInvalidChecksum, w.get_lines, 'v2')  | 
|
484  | 
self.assertRaises(errors.WeaveInvalidChecksum, w.check)  | 
|
485  | 
||
486  | 
w = self.get_file_corrupted_checksum()  | 
|
487  | 
||
488  | 
self.assertEqual('hello\n', w.get_text('v1'))  | 
|
489  | 
self.assertRaises(errors.WeaveInvalidChecksum, w.get_text, 'v2')  | 
|
490  | 
self.assertRaises(errors.WeaveInvalidChecksum, w.get_lines, 'v2')  | 
|
491  | 
self.assertRaises(errors.WeaveInvalidChecksum, w.check)  | 
|
492  | 
||
493  | 
def get_file_corrupted_text(self):  | 
|
494  | 
"""Return a versioned file with corrupt text but valid metadata."""  | 
|
495  | 
raise NotImplementedError(self.get_file_corrupted_text)  | 
|
496  | 
||
| 
1563.2.9
by Robert Collins
 Update versionedfile api tests to ensure that data is available after every operation.  | 
497  | 
def reopen_file(self, name='foo'):  | 
498  | 
"""Open the versioned file from disk again."""  | 
|
499  | 
raise NotImplementedError(self.reopen_file)  | 
|
500  | 
||
| 
2592.3.43
by Robert Collins
 A knit iter_parents API.  | 
501  | 
def test_iter_parents(self):  | 
502  | 
"""iter_parents returns the parents for many nodes."""  | 
|
503  | 
f = self.get_file()  | 
|
504  | 
        # sample data:
 | 
|
505  | 
        # no parents
 | 
|
506  | 
f.add_lines('r0', [], ['a\n', 'b\n'])  | 
|
507  | 
        # 1 parents
 | 
|
508  | 
f.add_lines('r1', ['r0'], ['a\n', 'b\n'])  | 
|
509  | 
        # 2 parents
 | 
|
510  | 
f.add_lines('r2', ['r1', 'r0'], ['a\n', 'b\n'])  | 
|
511  | 
        # XXX TODO a ghost
 | 
|
512  | 
        # cases: each sample data individually:
 | 
|
513  | 
self.assertEqual(set([('r0', ())]),  | 
|
514  | 
set(f.iter_parents(['r0'])))  | 
|
515  | 
self.assertEqual(set([('r1', ('r0', ))]),  | 
|
516  | 
set(f.iter_parents(['r1'])))  | 
|
517  | 
self.assertEqual(set([('r2', ('r1', 'r0'))]),  | 
|
518  | 
set(f.iter_parents(['r2'])))  | 
|
519  | 
        # no nodes returned for a missing node
 | 
|
520  | 
self.assertEqual(set(),  | 
|
521  | 
set(f.iter_parents(['missing'])))  | 
|
522  | 
        # 1 node returned with missing nodes skipped
 | 
|
523  | 
self.assertEqual(set([('r1', ('r0', ))]),  | 
|
524  | 
set(f.iter_parents(['ghost1', 'r1', 'ghost'])))  | 
|
525  | 
        # 2 nodes returned
 | 
|
526  | 
self.assertEqual(set([('r0', ()), ('r1', ('r0', ))]),  | 
|
527  | 
set(f.iter_parents(['r0', 'r1'])))  | 
|
528  | 
        # 2 nodes returned, missing skipped
 | 
|
529  | 
self.assertEqual(set([('r0', ()), ('r1', ('r0', ))]),  | 
|
530  | 
set(f.iter_parents(['a', 'r0', 'b', 'r1', 'c'])))  | 
|
531  | 
||
| 
1594.2.6
by Robert Collins
 Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.  | 
532  | 
def test_iter_lines_added_or_present_in_versions(self):  | 
533  | 
        # test that we get at least an equalset of the lines added by
 | 
|
534  | 
        # versions in the weave 
 | 
|
535  | 
        # the ordering here is to make a tree so that dumb searches have
 | 
|
536  | 
        # more changes to muck up.
 | 
|
| 
2039.1.1
by Aaron Bentley
 Clean up progress properly when interrupted during fetch (#54000)  | 
537  | 
|
538  | 
class InstrumentedProgress(progress.DummyProgress):  | 
|
539  | 
||
540  | 
def __init__(self):  | 
|
541  | 
||
542  | 
progress.DummyProgress.__init__(self)  | 
|
543  | 
self.updates = []  | 
|
544  | 
||
545  | 
def update(self, msg=None, current=None, total=None):  | 
|
546  | 
self.updates.append((msg, current, total))  | 
|
547  | 
||
| 
1594.2.6
by Robert Collins
 Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.  | 
548  | 
vf = self.get_file()  | 
549  | 
        # add a base to get included
 | 
|
550  | 
vf.add_lines('base', [], ['base\n'])  | 
|
551  | 
        # add a ancestor to be included on one side
 | 
|
552  | 
vf.add_lines('lancestor', [], ['lancestor\n'])  | 
|
553  | 
        # add a ancestor to be included on the other side
 | 
|
554  | 
vf.add_lines('rancestor', ['base'], ['rancestor\n'])  | 
|
555  | 
        # add a child of rancestor with no eofile-nl
 | 
|
556  | 
vf.add_lines('child', ['rancestor'], ['base\n', 'child\n'])  | 
|
557  | 
        # add a child of lancestor and base to join the two roots
 | 
|
558  | 
vf.add_lines('otherchild',  | 
|
559  | 
['lancestor', 'base'],  | 
|
560  | 
['base\n', 'lancestor\n', 'otherchild\n'])  | 
|
| 
2039.1.1
by Aaron Bentley
 Clean up progress properly when interrupted during fetch (#54000)  | 
561  | 
def iter_with_versions(versions, expected):  | 
| 
1594.2.6
by Robert Collins
 Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.  | 
562  | 
            # now we need to see what lines are returned, and how often.
 | 
| 
2975.3.1
by Robert Collins
 Change (without backwards compatibility) the  | 
563  | 
lines = {}  | 
| 
2039.1.1
by Aaron Bentley
 Clean up progress properly when interrupted during fetch (#54000)  | 
564  | 
progress = InstrumentedProgress()  | 
| 
1594.2.6
by Robert Collins
 Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.  | 
565  | 
            # iterate over the lines
 | 
| 
2975.3.1
by Robert Collins
 Change (without backwards compatibility) the  | 
566  | 
for line in vf.iter_lines_added_or_present_in_versions(versions,  | 
| 
2039.1.1
by Aaron Bentley
 Clean up progress properly when interrupted during fetch (#54000)  | 
567  | 
pb=progress):  | 
| 
2975.3.1
by Robert Collins
 Change (without backwards compatibility) the  | 
568  | 
lines.setdefault(line, 0)  | 
| 
1594.2.6
by Robert Collins
 Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.  | 
569  | 
lines[line] += 1  | 
| 
2975.3.1
by Robert Collins
 Change (without backwards compatibility) the  | 
570  | 
if []!= progress.updates:  | 
| 
2039.1.2
by Aaron Bentley
 Tweak test to avoid catching assert  | 
571  | 
self.assertEqual(expected, progress.updates)  | 
| 
1594.2.6
by Robert Collins
 Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.  | 
572  | 
return lines  | 
| 
2147.1.3
by John Arbash Meinel
 In knit.py we were re-using a variable in 2 loops, causing bogus progress messages to be generated.  | 
573  | 
lines = iter_with_versions(['child', 'otherchild'],  | 
574  | 
[('Walking content.', 0, 2),  | 
|
575  | 
('Walking content.', 1, 2),  | 
|
| 
2039.1.1
by Aaron Bentley
 Clean up progress properly when interrupted during fetch (#54000)  | 
576  | 
('Walking content.', 2, 2)])  | 
| 
1594.2.6
by Robert Collins
 Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.  | 
577  | 
        # we must see child and otherchild
 | 
| 
2975.3.1
by Robert Collins
 Change (without backwards compatibility) the  | 
578  | 
self.assertTrue(lines[('child\n', 'child')] > 0)  | 
579  | 
self.assertTrue(lines[('otherchild\n', 'otherchild')] > 0)  | 
|
| 
1594.2.6
by Robert Collins
 Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.  | 
580  | 
        # we dont care if we got more than that.
 | 
581  | 
||
582  | 
        # test all lines
 | 
|
| 
2147.1.3
by John Arbash Meinel
 In knit.py we were re-using a variable in 2 loops, causing bogus progress messages to be generated.  | 
583  | 
lines = iter_with_versions(None, [('Walking content.', 0, 5),  | 
584  | 
('Walking content.', 1, 5),  | 
|
585  | 
('Walking content.', 2, 5),  | 
|
586  | 
('Walking content.', 3, 5),  | 
|
587  | 
('Walking content.', 4, 5),  | 
|
| 
2039.1.1
by Aaron Bentley
 Clean up progress properly when interrupted during fetch (#54000)  | 
588  | 
('Walking content.', 5, 5)])  | 
| 
1594.2.6
by Robert Collins
 Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.  | 
589  | 
        # all lines must be seen at least once
 | 
| 
2975.3.1
by Robert Collins
 Change (without backwards compatibility) the  | 
590  | 
self.assertTrue(lines[('base\n', 'base')] > 0)  | 
591  | 
self.assertTrue(lines[('lancestor\n', 'lancestor')] > 0)  | 
|
592  | 
self.assertTrue(lines[('rancestor\n', 'rancestor')] > 0)  | 
|
593  | 
self.assertTrue(lines[('child\n', 'child')] > 0)  | 
|
594  | 
self.assertTrue(lines[('otherchild\n', 'otherchild')] > 0)  | 
|
| 
1594.2.7
by Robert Collins
 Add versionedfile.fix_parents api for correcting data post hoc.  | 
595  | 
|
| 
1594.2.8
by Robert Collins
 add ghost aware apis to knits.  | 
596  | 
def test_add_lines_with_ghosts(self):  | 
597  | 
        # some versioned file formats allow lines to be added with parent
 | 
|
598  | 
        # information that is > than that in the format. Formats that do
 | 
|
599  | 
        # not support this need to raise NotImplementedError on the
 | 
|
600  | 
        # add_lines_with_ghosts api.
 | 
|
601  | 
vf = self.get_file()  | 
|
602  | 
        # add a revision with ghost parents
 | 
|
| 
2249.5.12
by John Arbash Meinel
 Change the APIs for VersionedFile, Store, and some of Repository into utf-8  | 
603  | 
        # The preferred form is utf8, but we should translate when needed
 | 
604  | 
parent_id_unicode = u'b\xbfse'  | 
|
605  | 
parent_id_utf8 = parent_id_unicode.encode('utf8')  | 
|
| 
1594.2.8
by Robert Collins
 add ghost aware apis to knits.  | 
606  | 
try:  | 
| 
2309.4.7
by John Arbash Meinel
 Update VersionedFile tests to ensure that they can take Unicode,  | 
607  | 
vf.add_lines_with_ghosts('notbxbfse', [parent_id_utf8], [])  | 
| 
1594.2.8
by Robert Collins
 add ghost aware apis to knits.  | 
608  | 
except NotImplementedError:  | 
609  | 
            # check the other ghost apis are also not implemented
 | 
|
610  | 
self.assertRaises(NotImplementedError, vf.has_ghost, 'foo')  | 
|
611  | 
self.assertRaises(NotImplementedError, vf.get_ancestry_with_ghosts, ['foo'])  | 
|
612  | 
self.assertRaises(NotImplementedError, vf.get_parents_with_ghosts, 'foo')  | 
|
613  | 
self.assertRaises(NotImplementedError, vf.get_graph_with_ghosts)  | 
|
614  | 
            return
 | 
|
| 
2150.2.1
by Robert Collins
 Correctly decode utf8 revision ids from knits when parsing, fixes a regression where a unicode revision id is stored correctly, but then indexed by the utf8 value on the next invocation of bzr, rather than the unicode value.  | 
615  | 
vf = self.reopen_file()  | 
| 
1594.2.8
by Robert Collins
 add ghost aware apis to knits.  | 
616  | 
        # test key graph related apis: getncestry, _graph, get_parents
 | 
617  | 
        # has_version
 | 
|
618  | 
        # - these are ghost unaware and must not be reflect ghosts
 | 
|
| 
2249.5.12
by John Arbash Meinel
 Change the APIs for VersionedFile, Store, and some of Repository into utf-8  | 
619  | 
self.assertEqual(['notbxbfse'], vf.get_ancestry('notbxbfse'))  | 
620  | 
self.assertEqual([], vf.get_parents('notbxbfse'))  | 
|
| 
2592.3.43
by Robert Collins
 A knit iter_parents API.  | 
621  | 
self.assertEqual({'notbxbfse':()}, vf.get_graph())  | 
| 
2249.5.12
by John Arbash Meinel
 Change the APIs for VersionedFile, Store, and some of Repository into utf-8  | 
622  | 
self.assertFalse(vf.has_version(parent_id_utf8))  | 
| 
1594.2.8
by Robert Collins
 add ghost aware apis to knits.  | 
623  | 
        # we have _with_ghost apis to give us ghost information.
 | 
| 
2249.5.12
by John Arbash Meinel
 Change the APIs for VersionedFile, Store, and some of Repository into utf-8  | 
624  | 
self.assertEqual([parent_id_utf8, 'notbxbfse'], vf.get_ancestry_with_ghosts(['notbxbfse']))  | 
625  | 
self.assertEqual([parent_id_utf8], vf.get_parents_with_ghosts('notbxbfse'))  | 
|
626  | 
self.assertEqual({'notbxbfse':[parent_id_utf8]}, vf.get_graph_with_ghosts())  | 
|
627  | 
self.assertTrue(vf.has_ghost(parent_id_utf8))  | 
|
| 
1594.2.8
by Robert Collins
 add ghost aware apis to knits.  | 
628  | 
        # if we add something that is a ghost of another, it should correct the
 | 
629  | 
        # results of the prior apis
 | 
|
| 
2858.2.1
by Martin Pool
 Remove most calls to safe_file_id and safe_revision_id.  | 
630  | 
vf.add_lines(parent_id_utf8, [], [])  | 
| 
2249.5.12
by John Arbash Meinel
 Change the APIs for VersionedFile, Store, and some of Repository into utf-8  | 
631  | 
self.assertEqual([parent_id_utf8, 'notbxbfse'], vf.get_ancestry(['notbxbfse']))  | 
632  | 
self.assertEqual([parent_id_utf8], vf.get_parents('notbxbfse'))  | 
|
| 
2592.3.43
by Robert Collins
 A knit iter_parents API.  | 
633  | 
self.assertEqual({parent_id_utf8:(),  | 
634  | 
'notbxbfse':(parent_id_utf8, ),  | 
|
| 
1594.2.8
by Robert Collins
 add ghost aware apis to knits.  | 
635  | 
                          },
 | 
636  | 
vf.get_graph())  | 
|
| 
2249.5.12
by John Arbash Meinel
 Change the APIs for VersionedFile, Store, and some of Repository into utf-8  | 
637  | 
self.assertTrue(vf.has_version(parent_id_utf8))  | 
| 
1594.2.8
by Robert Collins
 add ghost aware apis to knits.  | 
638  | 
        # we have _with_ghost apis to give us ghost information.
 | 
| 
2858.2.1
by Martin Pool
 Remove most calls to safe_file_id and safe_revision_id.  | 
639  | 
self.assertEqual([parent_id_utf8, 'notbxbfse'],  | 
640  | 
vf.get_ancestry_with_ghosts(['notbxbfse']))  | 
|
| 
2249.5.12
by John Arbash Meinel
 Change the APIs for VersionedFile, Store, and some of Repository into utf-8  | 
641  | 
self.assertEqual([parent_id_utf8], vf.get_parents_with_ghosts('notbxbfse'))  | 
642  | 
self.assertEqual({parent_id_utf8:[],  | 
|
643  | 
'notbxbfse':[parent_id_utf8],  | 
|
| 
1594.2.8
by Robert Collins
 add ghost aware apis to knits.  | 
644  | 
                          },
 | 
645  | 
vf.get_graph_with_ghosts())  | 
|
| 
2249.5.12
by John Arbash Meinel
 Change the APIs for VersionedFile, Store, and some of Repository into utf-8  | 
646  | 
self.assertFalse(vf.has_ghost(parent_id_utf8))  | 
| 
1594.2.8
by Robert Collins
 add ghost aware apis to knits.  | 
647  | 
|
| 
1594.2.9
by Robert Collins
 Teach Knit repositories how to handle ghosts without corrupting at all.  | 
648  | 
def test_add_lines_with_ghosts_after_normal_revs(self):  | 
649  | 
        # some versioned file formats allow lines to be added with parent
 | 
|
650  | 
        # information that is > than that in the format. Formats that do
 | 
|
651  | 
        # not support this need to raise NotImplementedError on the
 | 
|
652  | 
        # add_lines_with_ghosts api.
 | 
|
653  | 
vf = self.get_file()  | 
|
654  | 
        # probe for ghost support
 | 
|
655  | 
try:  | 
|
656  | 
vf.has_ghost('hoo')  | 
|
657  | 
except NotImplementedError:  | 
|
658  | 
            return
 | 
|
659  | 
vf.add_lines_with_ghosts('base', [], ['line\n', 'line_b\n'])  | 
|
660  | 
vf.add_lines_with_ghosts('references_ghost',  | 
|
661  | 
['base', 'a_ghost'],  | 
|
662  | 
['line\n', 'line_b\n', 'line_c\n'])  | 
|
663  | 
origins = vf.annotate('references_ghost')  | 
|
664  | 
self.assertEquals(('base', 'line\n'), origins[0])  | 
|
665  | 
self.assertEquals(('base', 'line_b\n'), origins[1])  | 
|
666  | 
self.assertEquals(('references_ghost', 'line_c\n'), origins[2])  | 
|
| 
1594.2.23
by Robert Collins
 Test versioned file storage handling of clean/dirty status for accessed versioned files.  | 
667  | 
|
668  | 
def test_readonly_mode(self):  | 
|
669  | 
transport = get_transport(self.get_url('.'))  | 
|
670  | 
factory = self.get_factory()  | 
|
671  | 
vf = factory('id', transport, 0777, create=True, access_mode='w')  | 
|
672  | 
vf = factory('id', transport, access_mode='r')  | 
|
673  | 
self.assertRaises(errors.ReadOnlyError, vf.add_lines, 'base', [], [])  | 
|
674  | 
self.assertRaises(errors.ReadOnlyError,  | 
|
675  | 
vf.add_lines_with_ghosts,  | 
|
676  | 
'base',  | 
|
677  | 
                          [],
 | 
|
678  | 
                          [])
 | 
|
679  | 
self.assertRaises(errors.ReadOnlyError, vf.join, 'base')  | 
|
| 
1594.2.24
by Robert Collins
 Make use of the transaction finalisation warning support to implement in-knit caching.  | 
680  | 
self.assertRaises(errors.ReadOnlyError, vf.clone_text, 'base', 'bar', ['foo'])  | 
| 
1666.1.6
by Robert Collins
 Make knit the default format.  | 
681  | 
|
682  | 
def test_get_sha1(self):  | 
|
683  | 
        # check the sha1 data is available
 | 
|
684  | 
vf = self.get_file()  | 
|
685  | 
        # a simple file
 | 
|
686  | 
vf.add_lines('a', [], ['a\n'])  | 
|
687  | 
        # the same file, different metadata
 | 
|
688  | 
vf.add_lines('b', ['a'], ['a\n'])  | 
|
689  | 
        # a file differing only in last newline.
 | 
|
690  | 
vf.add_lines('c', [], ['a'])  | 
|
691  | 
self.assertEqual(  | 
|
692  | 
'3f786850e387550fdab836ed7e6dc881de23001b', vf.get_sha1('a'))  | 
|
693  | 
self.assertEqual(  | 
|
694  | 
'3f786850e387550fdab836ed7e6dc881de23001b', vf.get_sha1('b'))  | 
|
695  | 
self.assertEqual(  | 
|
696  | 
'86f7e437faa5a7fce15d1ddcb9eaeaea377667b8', vf.get_sha1('c'))  | 
|
| 
2520.4.89
by Aaron Bentley
 Add get_sha1s to weaves  | 
697  | 
|
698  | 
self.assertEqual(['3f786850e387550fdab836ed7e6dc881de23001b',  | 
|
699  | 
'86f7e437faa5a7fce15d1ddcb9eaeaea377667b8',  | 
|
700  | 
'3f786850e387550fdab836ed7e6dc881de23001b'],  | 
|
701  | 
vf.get_sha1s(['a', 'c', 'b']))  | 
|
| 
1594.2.9
by Robert Collins
 Teach Knit repositories how to handle ghosts without corrupting at all.  | 
702  | 
|
| 
1563.2.1
by Robert Collins
 Merge in a variation of the versionedfile api from versioned-file.  | 
703  | 
|
| 
2535.3.1
by Andrew Bennetts
 Add get_format_signature to VersionedFile  | 
704  | 
class TestWeave(TestCaseWithMemoryTransport, VersionedFileTestMixIn):  | 
| 
1563.2.1
by Robert Collins
 Merge in a variation of the versionedfile api from versioned-file.  | 
705  | 
|
706  | 
def get_file(self, name='foo'):  | 
|
| 
1563.2.25
by Robert Collins
 Merge in upstream.  | 
707  | 
return WeaveFile(name, get_transport(self.get_url('.')), create=True)  | 
| 
1563.2.1
by Robert Collins
 Merge in a variation of the versionedfile api from versioned-file.  | 
708  | 
|
| 
1563.2.6
by Robert Collins
 Start check tests for knits (pending), and remove dead code.  | 
709  | 
def get_file_corrupted_text(self):  | 
| 
1563.2.25
by Robert Collins
 Merge in upstream.  | 
710  | 
w = WeaveFile('foo', get_transport(self.get_url('.')), create=True)  | 
| 
1563.2.13
by Robert Collins
 InterVersionedFile implemented.  | 
711  | 
w.add_lines('v1', [], ['hello\n'])  | 
712  | 
w.add_lines('v2', ['v1'], ['hello\n', 'there\n'])  | 
|
| 
1563.2.6
by Robert Collins
 Start check tests for knits (pending), and remove dead code.  | 
713  | 
|
714  | 
        # We are going to invasively corrupt the text
 | 
|
715  | 
        # Make sure the internals of weave are the same
 | 
|
716  | 
self.assertEqual([('{', 0)  | 
|
717  | 
, 'hello\n'  | 
|
718  | 
, ('}', None)  | 
|
719  | 
, ('{', 1)  | 
|
720  | 
, 'there\n'  | 
|
721  | 
, ('}', None)  | 
|
722  | 
], w._weave)  | 
|
723  | 
||
724  | 
self.assertEqual(['f572d396fae9206628714fb2ce00f72e94f2258f'  | 
|
725  | 
, '90f265c6e75f1c8f9ab76dcf85528352c5f215ef'  | 
|
726  | 
], w._sha1s)  | 
|
727  | 
w.check()  | 
|
728  | 
||
729  | 
        # Corrupted
 | 
|
730  | 
w._weave[4] = 'There\n'  | 
|
731  | 
return w  | 
|
732  | 
||
733  | 
def get_file_corrupted_checksum(self):  | 
|
734  | 
w = self.get_file_corrupted_text()  | 
|
735  | 
        # Corrected
 | 
|
736  | 
w._weave[4] = 'there\n'  | 
|
737  | 
self.assertEqual('hello\nthere\n', w.get_text('v2'))  | 
|
738  | 
||
739  | 
        #Invalid checksum, first digit changed
 | 
|
740  | 
w._sha1s[1] = 'f0f265c6e75f1c8f9ab76dcf85528352c5f215ef'  | 
|
741  | 
return w  | 
|
742  | 
||
| 
1666.1.6
by Robert Collins
 Make knit the default format.  | 
743  | 
def reopen_file(self, name='foo', create=False):  | 
744  | 
return WeaveFile(name, get_transport(self.get_url('.')), create=create)  | 
|
| 
1563.2.9
by Robert Collins
 Update versionedfile api tests to ensure that data is available after every operation.  | 
745  | 
|
| 
1563.2.25
by Robert Collins
 Merge in upstream.  | 
746  | 
def test_no_implicit_create(self):  | 
747  | 
self.assertRaises(errors.NoSuchFile,  | 
|
748  | 
WeaveFile,  | 
|
749  | 
'foo',  | 
|
750  | 
get_transport(self.get_url('.')))  | 
|
751  | 
||
| 
1594.2.23
by Robert Collins
 Test versioned file storage handling of clean/dirty status for accessed versioned files.  | 
752  | 
def get_factory(self):  | 
753  | 
return WeaveFile  | 
|
754  | 
||
| 
1563.2.1
by Robert Collins
 Merge in a variation of the versionedfile api from versioned-file.  | 
755  | 
|
| 
2535.3.1
by Andrew Bennetts
 Add get_format_signature to VersionedFile  | 
756  | 
class TestKnit(TestCaseWithMemoryTransport, VersionedFileTestMixIn):  | 
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
757  | 
|
758  | 
def get_file(self, name='foo'):  | 
|
| 
2770.1.1
by Aaron Bentley
 Initial implmentation of plain knit annotation  | 
759  | 
return self.get_factory()(name, get_transport(self.get_url('.')),  | 
760  | 
delta=True, create=True)  | 
|
| 
1563.2.6
by Robert Collins
 Start check tests for knits (pending), and remove dead code.  | 
761  | 
|
| 
1594.2.23
by Robert Collins
 Test versioned file storage handling of clean/dirty status for accessed versioned files.  | 
762  | 
def get_factory(self):  | 
763  | 
return KnitVersionedFile  | 
|
764  | 
||
| 
1563.2.6
by Robert Collins
 Start check tests for knits (pending), and remove dead code.  | 
765  | 
def get_file_corrupted_text(self):  | 
766  | 
knit = self.get_file()  | 
|
767  | 
knit.add_lines('v1', [], ['hello\n'])  | 
|
768  | 
knit.add_lines('v2', ['v1'], ['hello\n', 'there\n'])  | 
|
769  | 
return knit  | 
|
| 
1563.2.9
by Robert Collins
 Update versionedfile api tests to ensure that data is available after every operation.  | 
770  | 
|
| 
1666.1.6
by Robert Collins
 Make knit the default format.  | 
771  | 
def reopen_file(self, name='foo', create=False):  | 
| 
2770.1.1
by Aaron Bentley
 Initial implmentation of plain knit annotation  | 
772  | 
return self.get_factory()(name, get_transport(self.get_url('.')),  | 
| 
1666.1.6
by Robert Collins
 Make knit the default format.  | 
773  | 
delta=True,  | 
774  | 
create=create)  | 
|
| 
1563.2.10
by Robert Collins
 Change weave store to be a versioned store, using WeaveFiles which maintain integrity without needing explicit 'put' operations.  | 
775  | 
|
776  | 
def test_detection(self):  | 
|
| 
1563.2.19
by Robert Collins
 stub out a check for knits.  | 
777  | 
knit = self.get_file()  | 
778  | 
knit.check()  | 
|
| 
1563.2.12
by Robert Collins
 Checkpointing: created InterObject to factor out common inter object worker code, added InterVersionedFile and tests to allow making join work between any versionedfile.  | 
779  | 
|
| 
1563.2.25
by Robert Collins
 Merge in upstream.  | 
780  | 
def test_no_implicit_create(self):  | 
781  | 
self.assertRaises(errors.NoSuchFile,  | 
|
782  | 
KnitVersionedFile,  | 
|
783  | 
'foo',  | 
|
784  | 
get_transport(self.get_url('.')))  | 
|
785  | 
||
| 
1563.2.12
by Robert Collins
 Checkpointing: created InterObject to factor out common inter object worker code, added InterVersionedFile and tests to allow making join work between any versionedfile.  | 
786  | 
|
| 
2770.1.1
by Aaron Bentley
 Initial implmentation of plain knit annotation  | 
787  | 
class TestPlaintextKnit(TestKnit):  | 
788  | 
"""Test a knit with no cached annotations"""  | 
|
789  | 
||
790  | 
def _factory(self, name, transport, file_mode=None, access_mode=None,  | 
|
791  | 
delta=True, create=False):  | 
|
792  | 
return KnitVersionedFile(name, transport, file_mode, access_mode,  | 
|
793  | 
KnitPlainFactory(), delta=delta,  | 
|
794  | 
create=create)  | 
|
795  | 
||
796  | 
def get_factory(self):  | 
|
797  | 
return self._factory  | 
|
798  | 
||
799  | 
||
| 
3062.1.9
by Aaron Bentley
 Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile  | 
800  | 
class TestPlanMergeVersionedFile(TestCaseWithMemoryTransport):  | 
801  | 
||
802  | 
def setUp(self):  | 
|
803  | 
TestCaseWithMemoryTransport.setUp(self)  | 
|
804  | 
self.vf1 = KnitVersionedFile('root', self.get_transport(), create=True)  | 
|
805  | 
self.vf2 = KnitVersionedFile('root', self.get_transport(), create=True)  | 
|
806  | 
self.plan_merge_vf = versionedfile._PlanMergeVersionedFile('root',  | 
|
807  | 
[self.vf1, self.vf2])  | 
|
808  | 
||
809  | 
def test_add_lines(self):  | 
|
810  | 
self.plan_merge_vf.add_lines('a:', [], [])  | 
|
811  | 
self.assertRaises(ValueError, self.plan_merge_vf.add_lines, 'a', [],  | 
|
812  | 
                          [])
 | 
|
813  | 
self.assertRaises(ValueError, self.plan_merge_vf.add_lines, 'a:', None,  | 
|
814  | 
                          [])
 | 
|
815  | 
self.assertRaises(ValueError, self.plan_merge_vf.add_lines, 'a:', [],  | 
|
816  | 
None)  | 
|
817  | 
||
818  | 
def test_ancestry(self):  | 
|
819  | 
self.vf1.add_lines('A', [], [])  | 
|
820  | 
self.vf1.add_lines('B', ['A'], [])  | 
|
821  | 
self.plan_merge_vf.add_lines('C:', ['B'], [])  | 
|
822  | 
self.plan_merge_vf.add_lines('D:', ['C:'], [])  | 
|
823  | 
self.assertEqual(set(['A', 'B', 'C:', 'D:']),  | 
|
| 
3062.1.14
by Aaron Bentley
 Use topo_sorted=False with get_ancestry  | 
824  | 
self.plan_merge_vf.get_ancestry('D:', topo_sorted=False))  | 
| 
3062.1.9
by Aaron Bentley
 Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile  | 
825  | 
|
826  | 
def setup_abcde(self):  | 
|
827  | 
self.vf1.add_lines('A', [], ['a'])  | 
|
828  | 
self.vf1.add_lines('B', ['A'], ['b'])  | 
|
829  | 
self.vf2.add_lines('C', [], ['c'])  | 
|
830  | 
self.vf2.add_lines('D', ['C'], ['d'])  | 
|
831  | 
self.plan_merge_vf.add_lines('E:', ['B', 'D'], ['e'])  | 
|
832  | 
||
833  | 
def test_ancestry_uses_all_versionedfiles(self):  | 
|
834  | 
self.setup_abcde()  | 
|
835  | 
self.assertEqual(set(['A', 'B', 'C', 'D', 'E:']),  | 
|
| 
3062.1.14
by Aaron Bentley
 Use topo_sorted=False with get_ancestry  | 
836  | 
self.plan_merge_vf.get_ancestry('E:', topo_sorted=False))  | 
| 
3062.1.9
by Aaron Bentley
 Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile  | 
837  | 
|
838  | 
def test_ancestry_raises_revision_not_present(self):  | 
|
839  | 
error = self.assertRaises(errors.RevisionNotPresent,  | 
|
| 
3062.1.14
by Aaron Bentley
 Use topo_sorted=False with get_ancestry  | 
840  | 
self.plan_merge_vf.get_ancestry, 'E:', False)  | 
| 
3062.1.9
by Aaron Bentley
 Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile  | 
841  | 
self.assertContainsRe(str(error), '{E:} not present in "root"')  | 
842  | 
||
843  | 
def test_get_parents(self):  | 
|
844  | 
self.setup_abcde()  | 
|
845  | 
self.assertEqual(['A'], self.plan_merge_vf.get_parents('B'))  | 
|
846  | 
self.assertEqual(['C'], self.plan_merge_vf.get_parents('D'))  | 
|
847  | 
self.assertEqual(['B', 'D'], self.plan_merge_vf.get_parents('E:'))  | 
|
848  | 
error = self.assertRaises(errors.RevisionNotPresent,  | 
|
849  | 
self.plan_merge_vf.get_parents, 'F')  | 
|
850  | 
self.assertContainsRe(str(error), '{F} not present in "root"')  | 
|
851  | 
||
852  | 
def test_get_lines(self):  | 
|
853  | 
self.setup_abcde()  | 
|
854  | 
self.assertEqual(['a'], self.plan_merge_vf.get_lines('A'))  | 
|
855  | 
self.assertEqual(['c'], self.plan_merge_vf.get_lines('C'))  | 
|
856  | 
self.assertEqual(['e'], self.plan_merge_vf.get_lines('E:'))  | 
|
857  | 
error = self.assertRaises(errors.RevisionNotPresent,  | 
|
858  | 
self.plan_merge_vf.get_lines, 'F')  | 
|
859  | 
self.assertContainsRe(str(error), '{F} not present in "root"')  | 
|
860  | 
||
861  | 
||
| 
1563.2.12
by Robert Collins
 Checkpointing: created InterObject to factor out common inter object worker code, added InterVersionedFile and tests to allow making join work between any versionedfile.  | 
862  | 
class InterString(versionedfile.InterVersionedFile):  | 
863  | 
"""An inter-versionedfile optimised code path for strings.  | 
|
864  | 
||
865  | 
    This is for use during testing where we use strings as versionedfiles
 | 
|
866  | 
    so that none of the default regsitered interversionedfile classes will
 | 
|
867  | 
    match - which lets us test the match logic.
 | 
|
868  | 
    """
 | 
|
869  | 
||
870  | 
    @staticmethod
 | 
|
871  | 
def is_compatible(source, target):  | 
|
872  | 
"""InterString is compatible with strings-as-versionedfiles."""  | 
|
873  | 
return isinstance(source, str) and isinstance(target, str)  | 
|
874  | 
||
875  | 
||
876  | 
# TODO this and the InterRepository core logic should be consolidatable
 | 
|
877  | 
# if we make the registry a separate class though we still need to 
 | 
|
878  | 
# test the behaviour in the active registry to catch failure-to-handle-
 | 
|
879  | 
# stange-objects
 | 
|
| 
2535.3.1
by Andrew Bennetts
 Add get_format_signature to VersionedFile  | 
880  | 
class TestInterVersionedFile(TestCaseWithMemoryTransport):  | 
| 
1563.2.12
by Robert Collins
 Checkpointing: created InterObject to factor out common inter object worker code, added InterVersionedFile and tests to allow making join work between any versionedfile.  | 
881  | 
|
882  | 
def test_get_default_inter_versionedfile(self):  | 
|
883  | 
        # test that the InterVersionedFile.get(a, b) probes
 | 
|
884  | 
        # for a class where is_compatible(a, b) returns
 | 
|
885  | 
        # true and returns a default interversionedfile otherwise.
 | 
|
886  | 
        # This also tests that the default registered optimised interversionedfile
 | 
|
887  | 
        # classes do not barf inappropriately when a surprising versionedfile type
 | 
|
888  | 
        # is handed to them.
 | 
|
889  | 
dummy_a = "VersionedFile 1."  | 
|
890  | 
dummy_b = "VersionedFile 2."  | 
|
891  | 
self.assertGetsDefaultInterVersionedFile(dummy_a, dummy_b)  | 
|
892  | 
||
893  | 
def assertGetsDefaultInterVersionedFile(self, a, b):  | 
|
894  | 
"""Asserts that InterVersionedFile.get(a, b) -> the default."""  | 
|
895  | 
inter = versionedfile.InterVersionedFile.get(a, b)  | 
|
896  | 
self.assertEqual(versionedfile.InterVersionedFile,  | 
|
897  | 
inter.__class__)  | 
|
898  | 
self.assertEqual(a, inter.source)  | 
|
899  | 
self.assertEqual(b, inter.target)  | 
|
900  | 
||
901  | 
def test_register_inter_versionedfile_class(self):  | 
|
902  | 
        # test that a optimised code path provider - a
 | 
|
903  | 
        # InterVersionedFile subclass can be registered and unregistered
 | 
|
904  | 
        # and that it is correctly selected when given a versionedfile
 | 
|
905  | 
        # pair that it returns true on for the is_compatible static method
 | 
|
906  | 
        # check
 | 
|
907  | 
dummy_a = "VersionedFile 1."  | 
|
908  | 
dummy_b = "VersionedFile 2."  | 
|
909  | 
versionedfile.InterVersionedFile.register_optimiser(InterString)  | 
|
910  | 
try:  | 
|
911  | 
            # we should get the default for something InterString returns False
 | 
|
912  | 
            # to
 | 
|
913  | 
self.assertFalse(InterString.is_compatible(dummy_a, None))  | 
|
914  | 
self.assertGetsDefaultInterVersionedFile(dummy_a, None)  | 
|
915  | 
            # and we should get an InterString for a pair it 'likes'
 | 
|
916  | 
self.assertTrue(InterString.is_compatible(dummy_a, dummy_b))  | 
|
917  | 
inter = versionedfile.InterVersionedFile.get(dummy_a, dummy_b)  | 
|
918  | 
self.assertEqual(InterString, inter.__class__)  | 
|
919  | 
self.assertEqual(dummy_a, inter.source)  | 
|
920  | 
self.assertEqual(dummy_b, inter.target)  | 
|
921  | 
finally:  | 
|
922  | 
versionedfile.InterVersionedFile.unregister_optimiser(InterString)  | 
|
923  | 
        # now we should get the default InterVersionedFile object again.
 | 
|
924  | 
self.assertGetsDefaultInterVersionedFile(dummy_a, dummy_b)  | 
|
| 
1666.1.1
by Robert Collins
 Add trivial http-using test for versioned files.  | 
925  | 
|
926  | 
||
927  | 
class TestReadonlyHttpMixin(object):  | 
|
928  | 
||
929  | 
def test_readonly_http_works(self):  | 
|
930  | 
        # we should be able to read from http with a versioned file.
 | 
|
931  | 
vf = self.get_file()  | 
|
| 
1666.1.6
by Robert Collins
 Make knit the default format.  | 
932  | 
        # try an empty file access
 | 
933  | 
readonly_vf = self.get_factory()('foo', get_transport(self.get_readonly_url('.')))  | 
|
934  | 
self.assertEqual([], readonly_vf.versions())  | 
|
935  | 
        # now with feeling.
 | 
|
| 
1666.1.1
by Robert Collins
 Add trivial http-using test for versioned files.  | 
936  | 
vf.add_lines('1', [], ['a\n'])  | 
937  | 
vf.add_lines('2', ['1'], ['b\n', 'a\n'])  | 
|
938  | 
readonly_vf = self.get_factory()('foo', get_transport(self.get_readonly_url('.')))  | 
|
| 
1666.1.6
by Robert Collins
 Make knit the default format.  | 
939  | 
self.assertEqual(['1', '2'], vf.versions())  | 
| 
1666.1.1
by Robert Collins
 Add trivial http-using test for versioned files.  | 
940  | 
for version in readonly_vf.versions():  | 
941  | 
readonly_vf.get_lines(version)  | 
|
942  | 
||
943  | 
||
944  | 
class TestWeaveHTTP(TestCaseWithWebserver, TestReadonlyHttpMixin):  | 
|
945  | 
||
946  | 
def get_file(self):  | 
|
947  | 
return WeaveFile('foo', get_transport(self.get_url('.')), create=True)  | 
|
948  | 
||
949  | 
def get_factory(self):  | 
|
950  | 
return WeaveFile  | 
|
951  | 
||
952  | 
||
953  | 
class TestKnitHTTP(TestCaseWithWebserver, TestReadonlyHttpMixin):  | 
|
954  | 
||
955  | 
def get_file(self):  | 
|
956  | 
return KnitVersionedFile('foo', get_transport(self.get_url('.')),  | 
|
957  | 
delta=True, create=True)  | 
|
958  | 
||
959  | 
def get_factory(self):  | 
|
960  | 
return KnitVersionedFile  | 
|
| 
1664.2.9
by Aaron Bentley
 Ported weave merge test to versionedfile  | 
961  | 
|
962  | 
||
963  | 
class MergeCasesMixin(object):  | 
|
964  | 
||
965  | 
def doMerge(self, base, a, b, mp):  | 
|
966  | 
from cStringIO import StringIO  | 
|
967  | 
from textwrap import dedent  | 
|
968  | 
||
969  | 
def addcrlf(x):  | 
|
970  | 
return x + '\n'  | 
|
971  | 
||
972  | 
w = self.get_file()  | 
|
973  | 
w.add_lines('text0', [], map(addcrlf, base))  | 
|
974  | 
w.add_lines('text1', ['text0'], map(addcrlf, a))  | 
|
975  | 
w.add_lines('text2', ['text0'], map(addcrlf, b))  | 
|
976  | 
||
977  | 
self.log_contents(w)  | 
|
978  | 
||
979  | 
self.log('merge plan:')  | 
|
980  | 
p = list(w.plan_merge('text1', 'text2'))  | 
|
981  | 
for state, line in p:  | 
|
982  | 
if line:  | 
|
983  | 
self.log('%12s | %s' % (state, line[:-1]))  | 
|
984  | 
||
985  | 
self.log('merge:')  | 
|
986  | 
mt = StringIO()  | 
|
987  | 
mt.writelines(w.weave_merge(p))  | 
|
988  | 
mt.seek(0)  | 
|
989  | 
self.log(mt.getvalue())  | 
|
990  | 
||
991  | 
mp = map(addcrlf, mp)  | 
|
992  | 
self.assertEqual(mt.readlines(), mp)  | 
|
993  | 
||
994  | 
||
995  | 
def testOneInsert(self):  | 
|
996  | 
self.doMerge([],  | 
|
997  | 
['aa'],  | 
|
998  | 
                     [],
 | 
|
999  | 
['aa'])  | 
|
1000  | 
||
1001  | 
def testSeparateInserts(self):  | 
|
1002  | 
self.doMerge(['aaa', 'bbb', 'ccc'],  | 
|
1003  | 
['aaa', 'xxx', 'bbb', 'ccc'],  | 
|
1004  | 
['aaa', 'bbb', 'yyy', 'ccc'],  | 
|
1005  | 
['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])  | 
|
1006  | 
||
1007  | 
def testSameInsert(self):  | 
|
1008  | 
self.doMerge(['aaa', 'bbb', 'ccc'],  | 
|
1009  | 
['aaa', 'xxx', 'bbb', 'ccc'],  | 
|
1010  | 
['aaa', 'xxx', 'bbb', 'yyy', 'ccc'],  | 
|
1011  | 
['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])  | 
|
1012  | 
overlappedInsertExpected = ['aaa', 'xxx', 'yyy', 'bbb']  | 
|
1013  | 
def testOverlappedInsert(self):  | 
|
1014  | 
self.doMerge(['aaa', 'bbb'],  | 
|
1015  | 
['aaa', 'xxx', 'yyy', 'bbb'],  | 
|
1016  | 
['aaa', 'xxx', 'bbb'], self.overlappedInsertExpected)  | 
|
1017  | 
||
1018  | 
        # really it ought to reduce this to 
 | 
|
1019  | 
        # ['aaa', 'xxx', 'yyy', 'bbb']
 | 
|
1020  | 
||
1021  | 
||
1022  | 
def testClashReplace(self):  | 
|
1023  | 
self.doMerge(['aaa'],  | 
|
1024  | 
['xxx'],  | 
|
1025  | 
['yyy', 'zzz'],  | 
|
1026  | 
['<<<<<<< ', 'xxx', '=======', 'yyy', 'zzz',  | 
|
1027  | 
'>>>>>>> '])  | 
|
1028  | 
||
1029  | 
def testNonClashInsert1(self):  | 
|
1030  | 
self.doMerge(['aaa'],  | 
|
1031  | 
['xxx', 'aaa'],  | 
|
1032  | 
['yyy', 'zzz'],  | 
|
1033  | 
['<<<<<<< ', 'xxx', 'aaa', '=======', 'yyy', 'zzz',  | 
|
1034  | 
'>>>>>>> '])  | 
|
1035  | 
||
1036  | 
def testNonClashInsert2(self):  | 
|
1037  | 
self.doMerge(['aaa'],  | 
|
1038  | 
['aaa'],  | 
|
1039  | 
['yyy', 'zzz'],  | 
|
1040  | 
['yyy', 'zzz'])  | 
|
1041  | 
||
1042  | 
||
1043  | 
def testDeleteAndModify(self):  | 
|
1044  | 
"""Clashing delete and modification.  | 
|
1045  | 
||
1046  | 
        If one side modifies a region and the other deletes it then
 | 
|
1047  | 
        there should be a conflict with one side blank.
 | 
|
1048  | 
        """
 | 
|
1049  | 
||
1050  | 
        #######################################
 | 
|
1051  | 
        # skippd, not working yet
 | 
|
1052  | 
        return
 | 
|
1053  | 
||
1054  | 
self.doMerge(['aaa', 'bbb', 'ccc'],  | 
|
1055  | 
['aaa', 'ddd', 'ccc'],  | 
|
1056  | 
['aaa', 'ccc'],  | 
|
1057  | 
['<<<<<<<< ', 'aaa', '=======', '>>>>>>> ', 'ccc'])  | 
|
1058  | 
||
1059  | 
def _test_merge_from_strings(self, base, a, b, expected):  | 
|
1060  | 
w = self.get_file()  | 
|
1061  | 
w.add_lines('text0', [], base.splitlines(True))  | 
|
1062  | 
w.add_lines('text1', ['text0'], a.splitlines(True))  | 
|
1063  | 
w.add_lines('text2', ['text0'], b.splitlines(True))  | 
|
1064  | 
self.log('merge plan:')  | 
|
1065  | 
p = list(w.plan_merge('text1', 'text2'))  | 
|
1066  | 
for state, line in p:  | 
|
1067  | 
if line:  | 
|
1068  | 
self.log('%12s | %s' % (state, line[:-1]))  | 
|
1069  | 
self.log('merge result:')  | 
|
1070  | 
result_text = ''.join(w.weave_merge(p))  | 
|
1071  | 
self.log(result_text)  | 
|
1072  | 
self.assertEqualDiff(result_text, expected)  | 
|
1073  | 
||
1074  | 
def test_weave_merge_conflicts(self):  | 
|
1075  | 
        # does weave merge properly handle plans that end with unchanged?
 | 
|
1076  | 
result = ''.join(self.get_file().weave_merge([('new-a', 'hello\n')]))  | 
|
1077  | 
self.assertEqual(result, 'hello\n')  | 
|
1078  | 
||
1079  | 
def test_deletion_extended(self):  | 
|
1080  | 
"""One side deletes, the other deletes more.  | 
|
1081  | 
        """
 | 
|
1082  | 
base = """\  | 
|
1083  | 
            line 1
 | 
|
1084  | 
            line 2
 | 
|
1085  | 
            line 3
 | 
|
1086  | 
            """
 | 
|
1087  | 
a = """\  | 
|
1088  | 
            line 1
 | 
|
1089  | 
            line 2
 | 
|
1090  | 
            """
 | 
|
1091  | 
b = """\  | 
|
1092  | 
            line 1
 | 
|
1093  | 
            """
 | 
|
1094  | 
result = """\  | 
|
1095  | 
            line 1
 | 
|
1096  | 
            """
 | 
|
1097  | 
self._test_merge_from_strings(base, a, b, result)  | 
|
1098  | 
||
1099  | 
def test_deletion_overlap(self):  | 
|
1100  | 
"""Delete overlapping regions with no other conflict.  | 
|
1101  | 
||
1102  | 
        Arguably it'd be better to treat these as agreement, rather than 
 | 
|
1103  | 
        conflict, but for now conflict is safer.
 | 
|
1104  | 
        """
 | 
|
1105  | 
base = """\  | 
|
1106  | 
            start context
 | 
|
1107  | 
int a() {}  | 
|
1108  | 
int b() {}  | 
|
1109  | 
int c() {}  | 
|
1110  | 
            end context
 | 
|
1111  | 
            """
 | 
|
1112  | 
a = """\  | 
|
1113  | 
            start context
 | 
|
1114  | 
int a() {}  | 
|
1115  | 
            end context
 | 
|
1116  | 
            """
 | 
|
1117  | 
b = """\  | 
|
1118  | 
            start context
 | 
|
1119  | 
int c() {}  | 
|
1120  | 
            end context
 | 
|
1121  | 
            """
 | 
|
1122  | 
result = """\  | 
|
1123  | 
            start context
 | 
|
1124  | 
<<<<<<< 
 | 
|
1125  | 
int a() {}  | 
|
1126  | 
=======
 | 
|
1127  | 
int c() {}  | 
|
1128  | 
>>>>>>> 
 | 
|
1129  | 
            end context
 | 
|
1130  | 
            """
 | 
|
1131  | 
self._test_merge_from_strings(base, a, b, result)  | 
|
1132  | 
||
1133  | 
def test_agreement_deletion(self):  | 
|
1134  | 
"""Agree to delete some lines, without conflicts."""  | 
|
1135  | 
base = """\  | 
|
1136  | 
            start context
 | 
|
1137  | 
            base line 1
 | 
|
1138  | 
            base line 2
 | 
|
1139  | 
            end context
 | 
|
1140  | 
            """
 | 
|
1141  | 
a = """\  | 
|
1142  | 
            start context
 | 
|
1143  | 
            base line 1
 | 
|
1144  | 
            end context
 | 
|
1145  | 
            """
 | 
|
1146  | 
b = """\  | 
|
1147  | 
            start context
 | 
|
1148  | 
            base line 1
 | 
|
1149  | 
            end context
 | 
|
1150  | 
            """
 | 
|
1151  | 
result = """\  | 
|
1152  | 
            start context
 | 
|
1153  | 
            base line 1
 | 
|
1154  | 
            end context
 | 
|
1155  | 
            """
 | 
|
1156  | 
self._test_merge_from_strings(base, a, b, result)  | 
|
1157  | 
||
1158  | 
def test_sync_on_deletion(self):  | 
|
1159  | 
"""Specific case of merge where we can synchronize incorrectly.  | 
|
1160  | 
        
 | 
|
1161  | 
        A previous version of the weave merge concluded that the two versions
 | 
|
1162  | 
        agreed on deleting line 2, and this could be a synchronization point.
 | 
|
1163  | 
        Line 1 was then considered in isolation, and thought to be deleted on 
 | 
|
1164  | 
        both sides.
 | 
|
1165  | 
||
1166  | 
        It's better to consider the whole thing as a disagreement region.
 | 
|
1167  | 
        """
 | 
|
1168  | 
base = """\  | 
|
1169  | 
            start context
 | 
|
1170  | 
            base line 1
 | 
|
1171  | 
            base line 2
 | 
|
1172  | 
            end context
 | 
|
1173  | 
            """
 | 
|
1174  | 
a = """\  | 
|
1175  | 
            start context
 | 
|
1176  | 
            base line 1
 | 
|
1177  | 
            a's replacement line 2
 | 
|
1178  | 
            end context
 | 
|
1179  | 
            """
 | 
|
1180  | 
b = """\  | 
|
1181  | 
            start context
 | 
|
1182  | 
            b replaces
 | 
|
1183  | 
            both lines
 | 
|
1184  | 
            end context
 | 
|
1185  | 
            """
 | 
|
1186  | 
result = """\  | 
|
1187  | 
            start context
 | 
|
1188  | 
<<<<<<< 
 | 
|
1189  | 
            base line 1
 | 
|
1190  | 
            a's replacement line 2
 | 
|
1191  | 
=======
 | 
|
1192  | 
            b replaces
 | 
|
1193  | 
            both lines
 | 
|
1194  | 
>>>>>>> 
 | 
|
1195  | 
            end context
 | 
|
1196  | 
            """
 | 
|
1197  | 
self._test_merge_from_strings(base, a, b, result)  | 
|
1198  | 
||
1199  | 
||
| 
2535.3.1
by Andrew Bennetts
 Add get_format_signature to VersionedFile  | 
1200  | 
class TestKnitMerge(TestCaseWithMemoryTransport, MergeCasesMixin):  | 
| 
1664.2.9
by Aaron Bentley
 Ported weave merge test to versionedfile  | 
1201  | 
|
1202  | 
def get_file(self, name='foo'):  | 
|
1203  | 
return KnitVersionedFile(name, get_transport(self.get_url('.')),  | 
|
1204  | 
delta=True, create=True)  | 
|
1205  | 
||
1206  | 
def log_contents(self, w):  | 
|
1207  | 
        pass
 | 
|
1208  | 
||
1209  | 
||
| 
2535.3.1
by Andrew Bennetts
 Add get_format_signature to VersionedFile  | 
1210  | 
class TestWeaveMerge(TestCaseWithMemoryTransport, MergeCasesMixin):  | 
| 
1664.2.9
by Aaron Bentley
 Ported weave merge test to versionedfile  | 
1211  | 
|
1212  | 
def get_file(self, name='foo'):  | 
|
1213  | 
return WeaveFile(name, get_transport(self.get_url('.')), create=True)  | 
|
1214  | 
||
1215  | 
def log_contents(self, w):  | 
|
1216  | 
self.log('weave is:')  | 
|
1217  | 
tmpf = StringIO()  | 
|
1218  | 
write_weave(w, tmpf)  | 
|
1219  | 
self.log(tmpf.getvalue())  | 
|
1220  | 
||
1221  | 
overlappedInsertExpected = ['aaa', '<<<<<<< ', 'xxx', 'yyy', '=======',  | 
|
1222  | 
'xxx', '>>>>>>> ', 'bbb']  | 
|
| 
2535.3.1
by Andrew Bennetts
 Add get_format_signature to VersionedFile  | 
1223  | 
|
1224  | 
||
1225  | 
class TestFormatSignatures(TestCaseWithMemoryTransport):  | 
|
1226  | 
||
| 
2535.3.17
by Andrew Bennetts
 [broken] Closer to a working Repository.fetch_revisions smart request.  | 
1227  | 
def get_knit_file(self, name, annotated):  | 
| 
2535.3.1
by Andrew Bennetts
 Add get_format_signature to VersionedFile  | 
1228  | 
if annotated:  | 
1229  | 
factory = KnitAnnotateFactory()  | 
|
1230  | 
else:  | 
|
1231  | 
factory = KnitPlainFactory()  | 
|
1232  | 
return KnitVersionedFile(  | 
|
| 
2535.3.17
by Andrew Bennetts
 [broken] Closer to a working Repository.fetch_revisions smart request.  | 
1233  | 
name, get_transport(self.get_url('.')), create=True,  | 
| 
2535.3.1
by Andrew Bennetts
 Add get_format_signature to VersionedFile  | 
1234  | 
factory=factory)  | 
1235  | 
||
1236  | 
def test_knit_format_signatures(self):  | 
|
1237  | 
"""Different formats of knit have different signature strings."""  | 
|
| 
2535.3.17
by Andrew Bennetts
 [broken] Closer to a working Repository.fetch_revisions smart request.  | 
1238  | 
knit = self.get_knit_file('a', True)  | 
1239  | 
self.assertEqual('knit-annotated', knit.get_format_signature())  | 
|
1240  | 
knit = self.get_knit_file('p', False)  | 
|
1241  | 
self.assertEqual('knit-plain', knit.get_format_signature())  | 
|
| 
2535.3.1
by Andrew Bennetts
 Add get_format_signature to VersionedFile  | 
1242  |