1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
1 |
# Copyright (C) 2005, 2006 by Canonical Ltd
|
2 |
#
|
|
3 |
# This program is free software; you can redistribute it and/or modify
|
|
4 |
# it under the terms of the GNU General Public License as published by
|
|
5 |
# the Free Software Foundation; either version 2 of the License, or
|
|
6 |
# (at your option) any later version.
|
|
7 |
#
|
|
8 |
# This program is distributed in the hope that it will be useful,
|
|
9 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11 |
# GNU General Public License for more details.
|
|
12 |
#
|
|
13 |
# You should have received a copy of the GNU General Public License
|
|
14 |
# along with this program; if not, write to the Free Software
|
|
15 |
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
16 |
||
17 |
"""Tests for Knit data structure"""
|
|
18 |
||
19 |
||
20 |
import difflib |
|
21 |
||
22 |
||
1946.2.2
by John Arbash Meinel
test delay_create does the right thing |
23 |
from bzrlib.errors import KnitError, RevisionAlreadyPresent, NoSuchFile |
1684.3.3
by Robert Collins
Add a special cased weaves to knit converter. |
24 |
from bzrlib.knit import ( |
25 |
KnitVersionedFile, |
|
26 |
KnitPlainFactory, |
|
27 |
KnitAnnotateFactory, |
|
28 |
WeaveToKnit) |
|
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
29 |
from bzrlib.osutils import split_lines |
1684.3.3
by Robert Collins
Add a special cased weaves to knit converter. |
30 |
from bzrlib.tests import TestCaseWithTransport |
1685.1.39
by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly. |
31 |
from bzrlib.transport import TransportLogger, get_transport |
1563.2.13
by Robert Collins
InterVersionedFile implemented. |
32 |
from bzrlib.transport.memory import MemoryTransport |
1684.3.3
by Robert Collins
Add a special cased weaves to knit converter. |
33 |
from bzrlib.weave import Weave |
34 |
||
35 |
||
36 |
class KnitTests(TestCaseWithTransport): |
|
37 |
"""Class containing knit test helper routines."""
|
|
1563.2.16
by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable. |
38 |
|
1946.2.1
by John Arbash Meinel
2 changes to knits. Delay creating the .knit or .kndx file until we have actually tried to write data. Because of this, we must allow the Knit to create the prefix directories |
39 |
def make_test_knit(self, annotate=False, delay_create=False): |
1563.2.16
by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable. |
40 |
if not annotate: |
41 |
factory = KnitPlainFactory() |
|
42 |
else: |
|
43 |
factory = None |
|
1946.2.1
by John Arbash Meinel
2 changes to knits. Delay creating the .knit or .kndx file until we have actually tried to write data. Because of this, we must allow the Knit to create the prefix directories |
44 |
return KnitVersionedFile('test', get_transport('.'), access_mode='w', |
45 |
factory=factory, create=True, |
|
46 |
delay_create=delay_create) |
|
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
47 |
|
1684.3.3
by Robert Collins
Add a special cased weaves to knit converter. |
48 |
|
49 |
class BasicKnitTests(KnitTests): |
|
50 |
||
51 |
def add_stock_one_and_one_a(self, k): |
|
52 |
k.add_lines('text-1', [], split_lines(TEXT_1)) |
|
53 |
k.add_lines('text-1a', ['text-1'], split_lines(TEXT_1A)) |
|
54 |
||
55 |
def test_knit_constructor(self): |
|
56 |
"""Construct empty k"""
|
|
57 |
self.make_test_knit() |
|
58 |
||
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
59 |
def test_knit_add(self): |
60 |
"""Store one text in knit and retrieve"""
|
|
1563.2.16
by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable. |
61 |
k = self.make_test_knit() |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
62 |
k.add_lines('text-1', [], split_lines(TEXT_1)) |
63 |
self.assertTrue(k.has_version('text-1')) |
|
64 |
self.assertEqualDiff(''.join(k.get_lines('text-1')), TEXT_1) |
|
65 |
||
66 |
def test_knit_reload(self): |
|
1641.1.2
by Robert Collins
Change knit index files to be robust in the presence of partial writes. |
67 |
# test that the content in a reloaded knit is correct
|
1563.2.16
by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable. |
68 |
k = self.make_test_knit() |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
69 |
k.add_lines('text-1', [], split_lines(TEXT_1)) |
70 |
del k |
|
1685.1.39
by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly. |
71 |
k2 = KnitVersionedFile('test', get_transport('.'), access_mode='r', factory=KnitPlainFactory(), create=True) |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
72 |
self.assertTrue(k2.has_version('text-1')) |
73 |
self.assertEqualDiff(''.join(k2.get_lines('text-1')), TEXT_1) |
|
74 |
||
75 |
def test_knit_several(self): |
|
76 |
"""Store several texts in a knit"""
|
|
1563.2.16
by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable. |
77 |
k = self.make_test_knit() |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
78 |
k.add_lines('text-1', [], split_lines(TEXT_1)) |
79 |
k.add_lines('text-2', [], split_lines(TEXT_2)) |
|
80 |
self.assertEqualDiff(''.join(k.get_lines('text-1')), TEXT_1) |
|
81 |
self.assertEqualDiff(''.join(k.get_lines('text-2')), TEXT_2) |
|
82 |
||
83 |
def test_repeated_add(self): |
|
84 |
"""Knit traps attempt to replace existing version"""
|
|
1563.2.16
by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable. |
85 |
k = self.make_test_knit() |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
86 |
k.add_lines('text-1', [], split_lines(TEXT_1)) |
87 |
self.assertRaises(RevisionAlreadyPresent, |
|
88 |
k.add_lines, |
|
89 |
'text-1', [], split_lines(TEXT_1)) |
|
90 |
||
91 |
def test_empty(self): |
|
1563.2.16
by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable. |
92 |
k = self.make_test_knit(True) |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
93 |
k.add_lines('text-1', [], []) |
94 |
self.assertEquals(k.get_lines('text-1'), []) |
|
95 |
||
96 |
def test_incomplete(self): |
|
97 |
"""Test if texts without a ending line-end can be inserted and
|
|
98 |
extracted."""
|
|
1685.1.39
by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly. |
99 |
k = KnitVersionedFile('test', get_transport('.'), delta=False, create=True) |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
100 |
k.add_lines('text-1', [], ['a\n', 'b' ]) |
101 |
k.add_lines('text-2', ['text-1'], ['a\rb\n', 'b\n']) |
|
1666.1.6
by Robert Collins
Make knit the default format. |
102 |
# reopening ensures maximum room for confusion
|
1685.1.39
by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly. |
103 |
k = KnitVersionedFile('test', get_transport('.'), delta=False, create=True) |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
104 |
self.assertEquals(k.get_lines('text-1'), ['a\n', 'b' ]) |
105 |
self.assertEquals(k.get_lines('text-2'), ['a\rb\n', 'b\n']) |
|
106 |
||
107 |
def test_delta(self): |
|
108 |
"""Expression of knit delta as lines"""
|
|
1563.2.16
by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable. |
109 |
k = self.make_test_knit() |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
110 |
td = list(line_delta(TEXT_1.splitlines(True), |
111 |
TEXT_1A.splitlines(True))) |
|
112 |
self.assertEqualDiff(''.join(td), delta_1_1a) |
|
113 |
out = apply_line_delta(TEXT_1.splitlines(True), td) |
|
114 |
self.assertEqualDiff(''.join(out), TEXT_1A) |
|
115 |
||
116 |
def test_add_with_parents(self): |
|
117 |
"""Store in knit with parents"""
|
|
1563.2.16
by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable. |
118 |
k = self.make_test_knit() |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
119 |
self.add_stock_one_and_one_a(k) |
120 |
self.assertEquals(k.get_parents('text-1'), []) |
|
121 |
self.assertEquals(k.get_parents('text-1a'), ['text-1']) |
|
122 |
||
123 |
def test_ancestry(self): |
|
124 |
"""Store in knit with parents"""
|
|
1563.2.16
by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable. |
125 |
k = self.make_test_knit() |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
126 |
self.add_stock_one_and_one_a(k) |
127 |
self.assertEquals(set(k.get_ancestry(['text-1a'])), set(['text-1a', 'text-1'])) |
|
128 |
||
129 |
def test_add_delta(self): |
|
130 |
"""Store in knit with parents"""
|
|
1685.1.39
by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly. |
131 |
k = KnitVersionedFile('test', get_transport('.'), factory=KnitPlainFactory(), |
1563.2.25
by Robert Collins
Merge in upstream. |
132 |
delta=True, create=True) |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
133 |
self.add_stock_one_and_one_a(k) |
1596.2.7
by Robert Collins
Remove the requirement for reannotation in knit joins. |
134 |
k.clear_cache() |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
135 |
self.assertEqualDiff(''.join(k.get_lines('text-1a')), TEXT_1A) |
136 |
||
137 |
def test_annotate(self): |
|
138 |
"""Annotations"""
|
|
1685.1.39
by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly. |
139 |
k = KnitVersionedFile('knit', get_transport('.'), factory=KnitAnnotateFactory(), |
1563.2.25
by Robert Collins
Merge in upstream. |
140 |
delta=True, create=True) |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
141 |
self.insert_and_test_small_annotate(k) |
142 |
||
143 |
def insert_and_test_small_annotate(self, k): |
|
144 |
"""test annotation with k works correctly."""
|
|
145 |
k.add_lines('text-1', [], ['a\n', 'b\n']) |
|
146 |
k.add_lines('text-2', ['text-1'], ['a\n', 'c\n']) |
|
147 |
||
148 |
origins = k.annotate('text-2') |
|
149 |
self.assertEquals(origins[0], ('text-1', 'a\n')) |
|
150 |
self.assertEquals(origins[1], ('text-2', 'c\n')) |
|
151 |
||
152 |
def test_annotate_fulltext(self): |
|
153 |
"""Annotations"""
|
|
1685.1.39
by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly. |
154 |
k = KnitVersionedFile('knit', get_transport('.'), factory=KnitAnnotateFactory(), |
1563.2.25
by Robert Collins
Merge in upstream. |
155 |
delta=False, create=True) |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
156 |
self.insert_and_test_small_annotate(k) |
157 |
||
158 |
def test_annotate_merge_1(self): |
|
1563.2.16
by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable. |
159 |
k = self.make_test_knit(True) |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
160 |
k.add_lines('text-a1', [], ['a\n', 'b\n']) |
161 |
k.add_lines('text-a2', [], ['d\n', 'c\n']) |
|
162 |
k.add_lines('text-am', ['text-a1', 'text-a2'], ['d\n', 'b\n']) |
|
163 |
origins = k.annotate('text-am') |
|
164 |
self.assertEquals(origins[0], ('text-a2', 'd\n')) |
|
165 |
self.assertEquals(origins[1], ('text-a1', 'b\n')) |
|
166 |
||
167 |
def test_annotate_merge_2(self): |
|
1563.2.16
by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable. |
168 |
k = self.make_test_knit(True) |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
169 |
k.add_lines('text-a1', [], ['a\n', 'b\n', 'c\n']) |
170 |
k.add_lines('text-a2', [], ['x\n', 'y\n', 'z\n']) |
|
171 |
k.add_lines('text-am', ['text-a1', 'text-a2'], ['a\n', 'y\n', 'c\n']) |
|
172 |
origins = k.annotate('text-am') |
|
173 |
self.assertEquals(origins[0], ('text-a1', 'a\n')) |
|
174 |
self.assertEquals(origins[1], ('text-a2', 'y\n')) |
|
175 |
self.assertEquals(origins[2], ('text-a1', 'c\n')) |
|
176 |
||
177 |
def test_annotate_merge_9(self): |
|
1563.2.16
by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable. |
178 |
k = self.make_test_knit(True) |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
179 |
k.add_lines('text-a1', [], ['a\n', 'b\n', 'c\n']) |
180 |
k.add_lines('text-a2', [], ['x\n', 'y\n', 'z\n']) |
|
181 |
k.add_lines('text-am', ['text-a1', 'text-a2'], ['k\n', 'y\n', 'c\n']) |
|
182 |
origins = k.annotate('text-am') |
|
183 |
self.assertEquals(origins[0], ('text-am', 'k\n')) |
|
184 |
self.assertEquals(origins[1], ('text-a2', 'y\n')) |
|
185 |
self.assertEquals(origins[2], ('text-a1', 'c\n')) |
|
186 |
||
187 |
def test_annotate_merge_3(self): |
|
1563.2.16
by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable. |
188 |
k = self.make_test_knit(True) |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
189 |
k.add_lines('text-a1', [], ['a\n', 'b\n', 'c\n']) |
190 |
k.add_lines('text-a2', [] ,['x\n', 'y\n', 'z\n']) |
|
191 |
k.add_lines('text-am', ['text-a1', 'text-a2'], ['k\n', 'y\n', 'z\n']) |
|
192 |
origins = k.annotate('text-am') |
|
193 |
self.assertEquals(origins[0], ('text-am', 'k\n')) |
|
194 |
self.assertEquals(origins[1], ('text-a2', 'y\n')) |
|
195 |
self.assertEquals(origins[2], ('text-a2', 'z\n')) |
|
196 |
||
197 |
def test_annotate_merge_4(self): |
|
1563.2.16
by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable. |
198 |
k = self.make_test_knit(True) |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
199 |
k.add_lines('text-a1', [], ['a\n', 'b\n', 'c\n']) |
200 |
k.add_lines('text-a2', [], ['x\n', 'y\n', 'z\n']) |
|
201 |
k.add_lines('text-a3', ['text-a1'], ['a\n', 'b\n', 'p\n']) |
|
202 |
k.add_lines('text-am', ['text-a2', 'text-a3'], ['a\n', 'b\n', 'z\n']) |
|
203 |
origins = k.annotate('text-am') |
|
204 |
self.assertEquals(origins[0], ('text-a1', 'a\n')) |
|
205 |
self.assertEquals(origins[1], ('text-a1', 'b\n')) |
|
206 |
self.assertEquals(origins[2], ('text-a2', 'z\n')) |
|
207 |
||
208 |
def test_annotate_merge_5(self): |
|
1563.2.16
by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable. |
209 |
k = self.make_test_knit(True) |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
210 |
k.add_lines('text-a1', [], ['a\n', 'b\n', 'c\n']) |
211 |
k.add_lines('text-a2', [], ['d\n', 'e\n', 'f\n']) |
|
212 |
k.add_lines('text-a3', [], ['x\n', 'y\n', 'z\n']) |
|
213 |
k.add_lines('text-am', |
|
214 |
['text-a1', 'text-a2', 'text-a3'], |
|
215 |
['a\n', 'e\n', 'z\n']) |
|
216 |
origins = k.annotate('text-am') |
|
217 |
self.assertEquals(origins[0], ('text-a1', 'a\n')) |
|
218 |
self.assertEquals(origins[1], ('text-a2', 'e\n')) |
|
219 |
self.assertEquals(origins[2], ('text-a3', 'z\n')) |
|
220 |
||
221 |
def test_annotate_file_cherry_pick(self): |
|
1563.2.16
by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable. |
222 |
k = self.make_test_knit(True) |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
223 |
k.add_lines('text-1', [], ['a\n', 'b\n', 'c\n']) |
224 |
k.add_lines('text-2', ['text-1'], ['d\n', 'e\n', 'f\n']) |
|
225 |
k.add_lines('text-3', ['text-2', 'text-1'], ['a\n', 'b\n', 'c\n']) |
|
226 |
origins = k.annotate('text-3') |
|
227 |
self.assertEquals(origins[0], ('text-1', 'a\n')) |
|
228 |
self.assertEquals(origins[1], ('text-1', 'b\n')) |
|
229 |
self.assertEquals(origins[2], ('text-1', 'c\n')) |
|
230 |
||
231 |
def test_knit_join(self): |
|
232 |
"""Store in knit with parents"""
|
|
1685.1.39
by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly. |
233 |
k1 = KnitVersionedFile('test1', get_transport('.'), factory=KnitPlainFactory(), create=True) |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
234 |
k1.add_lines('text-a', [], split_lines(TEXT_1)) |
235 |
k1.add_lines('text-b', ['text-a'], split_lines(TEXT_1)) |
|
236 |
||
237 |
k1.add_lines('text-c', [], split_lines(TEXT_1)) |
|
238 |
k1.add_lines('text-d', ['text-c'], split_lines(TEXT_1)) |
|
239 |
||
240 |
k1.add_lines('text-m', ['text-b', 'text-d'], split_lines(TEXT_1)) |
|
241 |
||
1685.1.39
by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly. |
242 |
k2 = KnitVersionedFile('test2', get_transport('.'), factory=KnitPlainFactory(), create=True) |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
243 |
count = k2.join(k1, version_ids=['text-m']) |
244 |
self.assertEquals(count, 5) |
|
245 |
self.assertTrue(k2.has_version('text-a')) |
|
246 |
self.assertTrue(k2.has_version('text-c')) |
|
247 |
||
248 |
def test_reannotate(self): |
|
1685.1.39
by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly. |
249 |
k1 = KnitVersionedFile('knit1', get_transport('.'), |
1563.2.25
by Robert Collins
Merge in upstream. |
250 |
factory=KnitAnnotateFactory(), create=True) |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
251 |
# 0
|
252 |
k1.add_lines('text-a', [], ['a\n', 'b\n']) |
|
253 |
# 1
|
|
254 |
k1.add_lines('text-b', ['text-a'], ['a\n', 'c\n']) |
|
255 |
||
1685.1.39
by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly. |
256 |
k2 = KnitVersionedFile('test2', get_transport('.'), |
1563.2.25
by Robert Collins
Merge in upstream. |
257 |
factory=KnitAnnotateFactory(), create=True) |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
258 |
k2.join(k1, version_ids=['text-b']) |
259 |
||
260 |
# 2
|
|
261 |
k1.add_lines('text-X', ['text-b'], ['a\n', 'b\n']) |
|
262 |
# 2
|
|
263 |
k2.add_lines('text-c', ['text-b'], ['z\n', 'c\n']) |
|
264 |
# 3
|
|
265 |
k2.add_lines('text-Y', ['text-b'], ['b\n', 'c\n']) |
|
266 |
||
267 |
# test-c will have index 3
|
|
268 |
k1.join(k2, version_ids=['text-c']) |
|
269 |
||
270 |
lines = k1.get_lines('text-c') |
|
271 |
self.assertEquals(lines, ['z\n', 'c\n']) |
|
272 |
||
273 |
origins = k1.annotate('text-c') |
|
1594.2.24
by Robert Collins
Make use of the transaction finalisation warning support to implement in-knit caching. |
274 |
self.assertEquals(origins[0], ('text-c', 'z\n')) |
275 |
self.assertEquals(origins[1], ('text-b', 'c\n')) |
|
276 |
||
1756.3.4
by Aaron Bentley
Fix bug getting texts when line deltas were reused |
277 |
def test_get_line_delta_texts(self): |
278 |
"""Make sure we can call get_texts on text with reused line deltas"""
|
|
279 |
k1 = KnitVersionedFile('test1', get_transport('.'), |
|
280 |
factory=KnitPlainFactory(), create=True) |
|
281 |
for t in range(3): |
|
282 |
if t == 0: |
|
283 |
parents = [] |
|
284 |
else: |
|
285 |
parents = ['%d' % (t-1)] |
|
286 |
k1.add_lines('%d' % t, parents, ['hello\n'] * t) |
|
287 |
k1.get_texts(('%d' % t) for t in range(3)) |
|
1594.3.1
by Robert Collins
Merge transaction finalisation and ensure iter_lines_added_or_present in knits does a old-to-new read in the knit. |
288 |
|
289 |
def test_iter_lines_reads_in_order(self): |
|
290 |
t = MemoryTransport() |
|
291 |
instrumented_t = TransportLogger(t) |
|
292 |
k1 = KnitVersionedFile('id', instrumented_t, create=True, delta=True) |
|
293 |
self.assertEqual([('id.kndx',)], instrumented_t._calls) |
|
294 |
# add texts with no required ordering
|
|
295 |
k1.add_lines('base', [], ['text\n']) |
|
296 |
k1.add_lines('base2', [], ['text2\n']) |
|
297 |
k1.clear_cache() |
|
298 |
instrumented_t._calls = [] |
|
299 |
# request a last-first iteration
|
|
300 |
results = list(k1.iter_lines_added_or_present_in_versions(['base2', 'base'])) |
|
1628.1.2
by Robert Collins
More knit micro-optimisations. |
301 |
self.assertEqual([('id.knit', [(0, 87), (87, 89)])], instrumented_t._calls) |
1594.3.1
by Robert Collins
Merge transaction finalisation and ensure iter_lines_added_or_present in knits does a old-to-new read in the knit. |
302 |
self.assertEqual(['text\n', 'text2\n'], results) |
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
303 |
|
1563.2.13
by Robert Collins
InterVersionedFile implemented. |
304 |
def test_create_empty_annotated(self): |
1563.2.16
by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable. |
305 |
k1 = self.make_test_knit(True) |
1563.2.13
by Robert Collins
InterVersionedFile implemented. |
306 |
# 0
|
307 |
k1.add_lines('text-a', [], ['a\n', 'b\n']) |
|
308 |
k2 = k1.create_empty('t', MemoryTransport()) |
|
309 |
self.assertTrue(isinstance(k2.factory, KnitAnnotateFactory)) |
|
310 |
self.assertEqual(k1.delta, k2.delta) |
|
311 |
# the generic test checks for empty content and file class
|
|
312 |
||
1641.1.2
by Robert Collins
Change knit index files to be robust in the presence of partial writes. |
313 |
def test_knit_format(self): |
314 |
# this tests that a new knit index file has the expected content
|
|
315 |
# and that is writes the data we expect as records are added.
|
|
316 |
knit = self.make_test_knit(True) |
|
1946.2.1
by John Arbash Meinel
2 changes to knits. Delay creating the .knit or .kndx file until we have actually tried to write data. Because of this, we must allow the Knit to create the prefix directories |
317 |
# Now knit files are not created until we first add data to them
|
1666.1.6
by Robert Collins
Make knit the default format. |
318 |
self.assertFileEqual("# bzr knit index 8\n", 'test.kndx') |
1641.1.2
by Robert Collins
Change knit index files to be robust in the presence of partial writes. |
319 |
knit.add_lines_with_ghosts('revid', ['a_ghost'], ['a\n']) |
320 |
self.assertFileEqual( |
|
1666.1.6
by Robert Collins
Make knit the default format. |
321 |
"# bzr knit index 8\n" |
1641.1.2
by Robert Collins
Change knit index files to be robust in the presence of partial writes. |
322 |
"\n" |
323 |
"revid fulltext 0 84 .a_ghost :", |
|
324 |
'test.kndx') |
|
325 |
knit.add_lines_with_ghosts('revid2', ['revid'], ['a\n']) |
|
326 |
self.assertFileEqual( |
|
1666.1.6
by Robert Collins
Make knit the default format. |
327 |
"# bzr knit index 8\n" |
1641.1.2
by Robert Collins
Change knit index files to be robust in the presence of partial writes. |
328 |
"\nrevid fulltext 0 84 .a_ghost :" |
329 |
"\nrevid2 line-delta 84 82 0 :", |
|
330 |
'test.kndx') |
|
331 |
# we should be able to load this file again
|
|
1685.1.39
by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly. |
332 |
knit = KnitVersionedFile('test', get_transport('.'), access_mode='r') |
1641.1.2
by Robert Collins
Change knit index files to be robust in the presence of partial writes. |
333 |
self.assertEqual(['revid', 'revid2'], knit.versions()) |
334 |
# write a short write to the file and ensure that its ignored
|
|
335 |
indexfile = file('test.kndx', 'at') |
|
336 |
indexfile.write('\nrevid3 line-delta 166 82 1 2 3 4 5 .phwoar:demo ') |
|
337 |
indexfile.close() |
|
338 |
# we should be able to load this file again
|
|
1685.1.39
by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly. |
339 |
knit = KnitVersionedFile('test', get_transport('.'), access_mode='w') |
1654.1.5
by Robert Collins
Merge partial index write support for knits, adding a test case per review comments. |
340 |
self.assertEqual(['revid', 'revid2'], knit.versions()) |
341 |
# and add a revision with the same id the failed write had
|
|
342 |
knit.add_lines('revid3', ['revid2'], ['a\n']) |
|
343 |
# and when reading it revid3 should now appear.
|
|
1685.1.39
by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly. |
344 |
knit = KnitVersionedFile('test', get_transport('.'), access_mode='r') |
1654.1.5
by Robert Collins
Merge partial index write support for knits, adding a test case per review comments. |
345 |
self.assertEqual(['revid', 'revid2', 'revid3'], knit.versions()) |
346 |
self.assertEqual(['revid2'], knit.get_parents('revid3')) |
|
347 |
||
1946.2.1
by John Arbash Meinel
2 changes to knits. Delay creating the .knit or .kndx file until we have actually tried to write data. Because of this, we must allow the Knit to create the prefix directories |
348 |
def test_delay_create(self): |
349 |
"""Test that passing delay_create=True creates files late"""
|
|
350 |
knit = self.make_test_knit(annotate=True, delay_create=True) |
|
351 |
self.failIfExists('test.knit') |
|
352 |
self.failIfExists('test.kndx') |
|
353 |
knit.add_lines_with_ghosts('revid', ['a_ghost'], ['a\n']) |
|
354 |
self.failUnlessExists('test.knit') |
|
355 |
self.assertFileEqual( |
|
356 |
"# bzr knit index 8\n" |
|
357 |
"\n" |
|
358 |
"revid fulltext 0 84 .a_ghost :", |
|
359 |
'test.kndx') |
|
360 |
||
1946.2.2
by John Arbash Meinel
test delay_create does the right thing |
361 |
def test_create_parent_dir(self): |
362 |
"""create_parent_dir can create knits in nonexistant dirs"""
|
|
363 |
# Has no effect if we don't set 'delay_create'
|
|
364 |
trans = get_transport('.') |
|
365 |
self.assertRaises(NoSuchFile, KnitVersionedFile, 'dir/test', |
|
366 |
trans, access_mode='w', factory=None, |
|
367 |
create=True, create_parent_dir=True) |
|
368 |
# Nothing should have changed yet
|
|
369 |
knit = KnitVersionedFile('dir/test', trans, access_mode='w', |
|
370 |
factory=None, create=True, |
|
371 |
create_parent_dir=True, |
|
372 |
delay_create=True) |
|
373 |
self.failIfExists('dir/test.knit') |
|
374 |
self.failIfExists('dir/test.kndx') |
|
375 |
self.failIfExists('dir') |
|
376 |
knit.add_lines('revid', [], ['a\n']) |
|
377 |
self.failUnlessExists('dir') |
|
378 |
self.failUnlessExists('dir/test.knit') |
|
379 |
self.assertFileEqual( |
|
380 |
"# bzr knit index 8\n" |
|
381 |
"\n" |
|
382 |
"revid fulltext 0 84 :", |
|
383 |
'dir/test.kndx') |
|
384 |
||
1946.2.13
by John Arbash Meinel
Test that passing modes does the right thing for knits. |
385 |
def test_create_mode_700(self): |
386 |
trans = get_transport('.') |
|
387 |
if not trans._can_roundtrip_unix_modebits(): |
|
388 |
# Can't roundtrip, so no need to run this test
|
|
389 |
return
|
|
390 |
knit = KnitVersionedFile('dir/test', trans, access_mode='w', |
|
391 |
factory=None, create=True, |
|
392 |
create_parent_dir=True, |
|
393 |
delay_create=True, |
|
394 |
file_mode=0600, |
|
395 |
dir_mode=0700) |
|
396 |
knit.add_lines('revid', [], ['a\n']) |
|
397 |
self.assertTransportMode(trans, 'dir', 0700) |
|
398 |
self.assertTransportMode(trans, 'dir/test.knit', 0600) |
|
399 |
self.assertTransportMode(trans, 'dir/test.kndx', 0600) |
|
400 |
||
401 |
def test_create_mode_770(self): |
|
402 |
trans = get_transport('.') |
|
403 |
if not trans._can_roundtrip_unix_modebits(): |
|
404 |
# Can't roundtrip, so no need to run this test
|
|
405 |
return
|
|
406 |
knit = KnitVersionedFile('dir/test', trans, access_mode='w', |
|
407 |
factory=None, create=True, |
|
408 |
create_parent_dir=True, |
|
409 |
delay_create=True, |
|
410 |
file_mode=0660, |
|
411 |
dir_mode=0770) |
|
412 |
knit.add_lines('revid', [], ['a\n']) |
|
413 |
self.assertTransportMode(trans, 'dir', 0770) |
|
414 |
self.assertTransportMode(trans, 'dir/test.knit', 0660) |
|
415 |
self.assertTransportMode(trans, 'dir/test.kndx', 0660) |
|
416 |
||
417 |
def test_create_mode_777(self): |
|
418 |
trans = get_transport('.') |
|
419 |
if not trans._can_roundtrip_unix_modebits(): |
|
420 |
# Can't roundtrip, so no need to run this test
|
|
421 |
return
|
|
422 |
knit = KnitVersionedFile('dir/test', trans, access_mode='w', |
|
423 |
factory=None, create=True, |
|
424 |
create_parent_dir=True, |
|
425 |
delay_create=True, |
|
426 |
file_mode=0666, |
|
427 |
dir_mode=0777) |
|
428 |
knit.add_lines('revid', [], ['a\n']) |
|
429 |
self.assertTransportMode(trans, 'dir', 0777) |
|
430 |
self.assertTransportMode(trans, 'dir/test.knit', 0666) |
|
431 |
self.assertTransportMode(trans, 'dir/test.kndx', 0666) |
|
432 |
||
1664.2.1
by Aaron Bentley
Start work on plan_merge test |
433 |
def test_plan_merge(self): |
434 |
my_knit = self.make_test_knit(annotate=True) |
|
435 |
my_knit.add_lines('text1', [], split_lines(TEXT_1)) |
|
436 |
my_knit.add_lines('text1a', ['text1'], split_lines(TEXT_1A)) |
|
437 |
my_knit.add_lines('text1b', ['text1'], split_lines(TEXT_1B)) |
|
1664.2.3
by Aaron Bentley
Add failing test case |
438 |
plan = list(my_knit.plan_merge('text1a', 'text1b')) |
1664.2.6
by Aaron Bentley
Got plan-merge passing tests |
439 |
for plan_line, expected_line in zip(plan, AB_MERGE): |
440 |
self.assertEqual(plan_line, expected_line) |
|
1641.1.2
by Robert Collins
Change knit index files to be robust in the presence of partial writes. |
441 |
|
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
442 |
|
443 |
TEXT_1 = """\ |
|
444 |
Banana cup cakes:
|
|
445 |
||
446 |
- bananas
|
|
447 |
- eggs
|
|
448 |
- broken tea cups
|
|
449 |
"""
|
|
450 |
||
451 |
TEXT_1A = """\ |
|
452 |
Banana cup cake recipe
|
|
453 |
(serves 6)
|
|
454 |
||
455 |
- bananas
|
|
456 |
- eggs
|
|
457 |
- broken tea cups
|
|
458 |
- self-raising flour
|
|
459 |
"""
|
|
460 |
||
1664.2.1
by Aaron Bentley
Start work on plan_merge test |
461 |
TEXT_1B = """\ |
462 |
Banana cup cake recipe
|
|
463 |
||
464 |
- bananas (do not use plantains!!!)
|
|
465 |
- broken tea cups
|
|
466 |
- flour
|
|
467 |
"""
|
|
468 |
||
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
469 |
delta_1_1a = """\ |
470 |
0,1,2
|
|
471 |
Banana cup cake recipe
|
|
472 |
(serves 6)
|
|
473 |
5,5,1
|
|
474 |
- self-raising flour
|
|
475 |
"""
|
|
476 |
||
477 |
TEXT_2 = """\ |
|
478 |
Boeuf bourguignon
|
|
479 |
||
480 |
- beef
|
|
481 |
- red wine
|
|
482 |
- small onions
|
|
483 |
- carrot
|
|
484 |
- mushrooms
|
|
485 |
"""
|
|
486 |
||
1664.2.3
by Aaron Bentley
Add failing test case |
487 |
AB_MERGE_TEXT="""unchanged|Banana cup cake recipe |
488 |
new-a|(serves 6)
|
|
489 |
unchanged|
|
|
490 |
killed-b|- bananas
|
|
491 |
killed-b|- eggs
|
|
492 |
new-b|- bananas (do not use plantains!!!)
|
|
493 |
unchanged|- broken tea cups
|
|
494 |
new-a|- self-raising flour
|
|
1664.2.6
by Aaron Bentley
Got plan-merge passing tests |
495 |
new-b|- flour
|
496 |
"""
|
|
1664.2.3
by Aaron Bentley
Add failing test case |
497 |
AB_MERGE=[tuple(l.split('|')) for l in AB_MERGE_TEXT.splitlines(True)] |
498 |
||
499 |
||
1563.2.4
by Robert Collins
First cut at including the knit implementation of versioned_file. |
500 |
def line_delta(from_lines, to_lines): |
501 |
"""Generate line-based delta from one text to another"""
|
|
502 |
s = difflib.SequenceMatcher(None, from_lines, to_lines) |
|
503 |
for op in s.get_opcodes(): |
|
504 |
if op[0] == 'equal': |
|
505 |
continue
|
|
506 |
yield '%d,%d,%d\n' % (op[1], op[2], op[4]-op[3]) |
|
507 |
for i in range(op[3], op[4]): |
|
508 |
yield to_lines[i] |
|
509 |
||
510 |
||
511 |
def apply_line_delta(basis_lines, delta_lines): |
|
512 |
"""Apply a line-based perfect diff
|
|
513 |
|
|
514 |
basis_lines -- text to apply the patch to
|
|
515 |
delta_lines -- diff instructions and content
|
|
516 |
"""
|
|
517 |
out = basis_lines[:] |
|
518 |
i = 0 |
|
519 |
offset = 0 |
|
520 |
while i < len(delta_lines): |
|
521 |
l = delta_lines[i] |
|
522 |
a, b, c = map(long, l.split(',')) |
|
523 |
i = i + 1 |
|
524 |
out[offset+a:offset+b] = delta_lines[i:i+c] |
|
525 |
i = i + c |
|
526 |
offset = offset + (b - a) + c |
|
527 |
return out |
|
1684.3.3
by Robert Collins
Add a special cased weaves to knit converter. |
528 |
|
529 |
||
530 |
class TestWeaveToKnit(KnitTests): |
|
531 |
||
532 |
def test_weave_to_knit_matches(self): |
|
533 |
# check that the WeaveToKnit is_compatible function
|
|
534 |
# registers True for a Weave to a Knit.
|
|
535 |
w = Weave() |
|
536 |
k = self.make_test_knit() |
|
537 |
self.failUnless(WeaveToKnit.is_compatible(w, k)) |
|
538 |
self.failIf(WeaveToKnit.is_compatible(k, w)) |
|
539 |
self.failIf(WeaveToKnit.is_compatible(w, w)) |
|
540 |
self.failIf(WeaveToKnit.is_compatible(k, k)) |
|
1863.1.1
by John Arbash Meinel
Allow Versioned files to do caching if explicitly asked, and implement for Knit |
541 |
|
542 |
||
543 |
class TestKnitCaching(KnitTests): |
|
544 |
||
545 |
def create_knit(self, cache_add=False): |
|
546 |
k = self.make_test_knit(True) |
|
547 |
if cache_add: |
|
548 |
k.enable_cache() |
|
549 |
||
550 |
k.add_lines('text-1', [], split_lines(TEXT_1)) |
|
551 |
k.add_lines('text-2', [], split_lines(TEXT_2)) |
|
552 |
return k |
|
553 |
||
554 |
def test_no_caching(self): |
|
555 |
k = self.create_knit() |
|
556 |
# Nothing should be cached without setting 'enable_cache'
|
|
557 |
self.assertEqual({}, k._data._cache) |
|
558 |
||
559 |
def test_cache_add_and_clear(self): |
|
560 |
k = self.create_knit(True) |
|
561 |
||
562 |
self.assertEqual(['text-1', 'text-2'], sorted(k._data._cache.keys())) |
|
563 |
||
564 |
k.clear_cache() |
|
565 |
self.assertEqual({}, k._data._cache) |
|
566 |
||
567 |
def test_cache_data_read_raw(self): |
|
568 |
k = self.create_knit() |
|
569 |
||
570 |
# Now cache and read
|
|
571 |
k.enable_cache() |
|
572 |
||
573 |
def read_one_raw(version): |
|
574 |
pos_map = k._get_components_positions([version]) |
|
575 |
method, pos, size, next = pos_map[version] |
|
576 |
lst = list(k._data.read_records_iter_raw([(version, pos, size)])) |
|
577 |
self.assertEqual(1, len(lst)) |
|
578 |
return lst[0] |
|
579 |
||
580 |
val = read_one_raw('text-1') |
|
1863.1.8
by John Arbash Meinel
Removing disk-backed-cache |
581 |
self.assertEqual({'text-1':val[1]}, k._data._cache) |
1863.1.1
by John Arbash Meinel
Allow Versioned files to do caching if explicitly asked, and implement for Knit |
582 |
|
583 |
k.clear_cache() |
|
584 |
# After clear, new reads are not cached
|
|
585 |
self.assertEqual({}, k._data._cache) |
|
586 |
||
587 |
val2 = read_one_raw('text-1') |
|
588 |
self.assertEqual(val, val2) |
|
589 |
self.assertEqual({}, k._data._cache) |
|
590 |
||
591 |
def test_cache_data_read(self): |
|
592 |
k = self.create_knit() |
|
593 |
||
594 |
def read_one(version): |
|
595 |
pos_map = k._get_components_positions([version]) |
|
596 |
method, pos, size, next = pos_map[version] |
|
597 |
lst = list(k._data.read_records_iter([(version, pos, size)])) |
|
598 |
self.assertEqual(1, len(lst)) |
|
599 |
return lst[0] |
|
600 |
||
601 |
# Now cache and read
|
|
602 |
k.enable_cache() |
|
603 |
||
604 |
val = read_one('text-2') |
|
605 |
self.assertEqual(['text-2'], k._data._cache.keys()) |
|
606 |
self.assertEqual('text-2', val[0]) |
|
607 |
content, digest = k._data._parse_record('text-2', |
|
608 |
k._data._cache['text-2']) |
|
609 |
self.assertEqual(content, val[1]) |
|
610 |
self.assertEqual(digest, val[2]) |
|
611 |
||
612 |
k.clear_cache() |
|
613 |
self.assertEqual({}, k._data._cache) |
|
614 |
||
615 |
val2 = read_one('text-2') |
|
616 |
self.assertEqual(val, val2) |
|
617 |
self.assertEqual({}, k._data._cache) |
|
618 |
||
619 |
def test_cache_read(self): |
|
620 |
k = self.create_knit() |
|
621 |
k.enable_cache() |
|
622 |
||
623 |
text = k.get_text('text-1') |
|
624 |
self.assertEqual(TEXT_1, text) |
|
625 |
self.assertEqual(['text-1'], k._data._cache.keys()) |
|
626 |
||
627 |
k.clear_cache() |
|
628 |
self.assertEqual({}, k._data._cache) |
|
629 |
||
630 |
text = k.get_text('text-1') |
|
631 |
self.assertEqual(TEXT_1, text) |
|
632 |
self.assertEqual({}, k._data._cache) |