~bzr-pqm/bzr/bzr.dev

0.1.55 by Martin Pool
doc
1
#! /usr/bin/python2.4
2
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
3
# Copyright (C) 2005 by Canonical Ltd
4
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
9
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU General Public License for more details.
14
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
19
1083 by Martin Pool
- add space to store revision-id in weave files
20
# TODO: tests regarding version names
1185.13.4 by Robert Collins
make reweave visible as a weave method, and quickly integrate into fetch
21
# TODO: rbc 20050108 test that join does not leave an inconsistent weave 
22
#       if it fails.
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
23
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
24
"""test suite for weave algorithm"""
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
25
1323 by Martin Pool
- caller can pass SHA-1 to Weave.add for efficiency
26
from pprint import pformat
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
27
1185.13.4 by Robert Collins
make reweave visible as a weave method, and quickly integrate into fetch
28
import bzrlib.errors as errors
1393.1.68 by Martin Pool
- add reweave that joins with ghosts
29
from bzrlib.weave import Weave, WeaveFormatError, WeaveError, reweave
872 by Martin Pool
- update testweave
30
from bzrlib.weavefile import write_weave, read_weave
1233 by Martin Pool
- fix up weave tests for new test framework
31
from bzrlib.selftest import TestCase
1323 by Martin Pool
- caller can pass SHA-1 to Weave.add for efficiency
32
from bzrlib.osutils import sha_string
0.1.66 by Martin Pool
Cope without set/frozenset classes
33
34
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
35
# texts for use in testing
0.1.3 by Martin Pool
Change storage of texts for testing
36
TEXT_0 = ["Hello world"]
37
TEXT_1 = ["Hello world",
38
          "A second line"]
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
39
40
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
41
1233 by Martin Pool
- fix up weave tests for new test framework
42
class TestBase(TestCase):
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
43
    def check_read_write(self, k):
44
        """Check the weave k can be written & re-read."""
45
        from tempfile import TemporaryFile
46
        tf = TemporaryFile()
47
48
        write_weave(k, tf)
49
        tf.seek(0)
50
        k2 = read_weave(tf)
51
52
        if k != k2:
53
            tf.seek(0)
54
            self.log('serialized weave:')
55
            self.log(tf.read())
1083 by Martin Pool
- add space to store revision-id in weave files
56
57
            self.log('')
58
            self.log('parents: %s' % (k._parents == k2._parents))
59
            self.log('         %r' % k._parents)
60
            self.log('         %r' % k2._parents)
61
            self.log('')
62
63
            
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
64
            self.fail('read/write check failed')
65
        
66
        
67
68
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
69
class Easy(TestBase):
70
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
71
        k = Weave()
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
72
73
74
class StoreText(TestBase):
75
    """Store and retrieve a simple text."""
76
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
77
        k = Weave()
1083 by Martin Pool
- add space to store revision-id in weave files
78
        idx = k.add('text0', [], TEXT_0)
0.1.4 by Martin Pool
Start indexing knits by both integer and version string.
79
        self.assertEqual(k.get(idx), TEXT_0)
80
        self.assertEqual(idx, 0)
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
81
82
0.1.7 by Martin Pool
Add trivial annotate text
83
84
class AnnotateOne(TestBase):
85
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
86
        k = Weave()
1083 by Martin Pool
- add space to store revision-id in weave files
87
        k.add('text0', [], TEXT_0)
0.1.7 by Martin Pool
Add trivial annotate text
88
        self.assertEqual(k.annotate(0),
89
                         [(0, TEXT_0[0])])
90
91
0.1.5 by Martin Pool
Add test for storing two text versions.
92
class StoreTwo(TestBase):
93
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
94
        k = Weave()
0.1.5 by Martin Pool
Add test for storing two text versions.
95
1083 by Martin Pool
- add space to store revision-id in weave files
96
        idx = k.add('text0', [], TEXT_0)
0.1.5 by Martin Pool
Add test for storing two text versions.
97
        self.assertEqual(idx, 0)
98
1083 by Martin Pool
- add space to store revision-id in weave files
99
        idx = k.add('text1', [], TEXT_1)
0.1.5 by Martin Pool
Add test for storing two text versions.
100
        self.assertEqual(idx, 1)
101
102
        self.assertEqual(k.get(0), TEXT_0)
103
        self.assertEqual(k.get(1), TEXT_1)
104
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
105
0.1.21 by Martin Pool
Start computing a delta to insert a new revision
106
1323 by Martin Pool
- caller can pass SHA-1 to Weave.add for efficiency
107
class AddWithGivenSha(TestBase):
108
    def runTest(self):
109
        """Add with caller-supplied SHA-1"""
110
        k = Weave()
111
112
        t = 'text0'
113
        k.add('text0', [], [t], sha1=sha_string(t))
114
115
116
0.1.27 by Martin Pool
Check that version numbers passed in are reasonable
117
class InvalidAdd(TestBase):
118
    """Try to use invalid version number during add."""
119
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
120
        k = Weave()
0.1.27 by Martin Pool
Check that version numbers passed in are reasonable
121
937 by Martin Pool
- weave raises IndexError when an invalid revision is given
122
        self.assertRaises(IndexError,
0.1.27 by Martin Pool
Check that version numbers passed in are reasonable
123
                          k.add,
1083 by Martin Pool
- add space to store revision-id in weave files
124
                          'text0',
0.1.27 by Martin Pool
Check that version numbers passed in are reasonable
125
                          [69],
126
                          ['new text!'])
127
128
1237 by Martin Pool
- allow the same version to be repeatedly added to a weave
129
class RepeatedAdd(TestBase):
130
    """Add the same version twice; harmless."""
131
    def runTest(self):
132
        k = Weave()
133
        idx = k.add('text0', [], TEXT_0)
134
        idx2 = k.add('text0', [], TEXT_0)
135
        self.assertEqual(idx, idx2)
136
137
138
139
class InvalidRepeatedAdd(TestBase):
140
    def runTest(self):
141
        k = Weave()
142
        idx = k.add('text0', [], TEXT_0)
143
        self.assertRaises(WeaveError,
144
                          k.add,
145
                          'text0',
146
                          [],
147
                          ['not the same text'])
148
        self.assertRaises(WeaveError,
149
                          k.add,
150
                          'text0',
151
                          [12],         # not the right parents
152
                          TEXT_0)
153
        
154
155
0.1.26 by Martin Pool
Refactor parameters to add command
156
class InsertLines(TestBase):
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
157
    """Store a revision that adds one line to the original.
158
159
    Look at the annotations to make sure that the first line is matched
160
    and not stored repeatedly."""
161
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
162
        k = Weave()
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
163
1083 by Martin Pool
- add space to store revision-id in weave files
164
        k.add('text0', [], ['line 1'])
165
        k.add('text1', [0], ['line 1', 'line 2'])
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
166
167
        self.assertEqual(k.annotate(0),
168
                         [(0, 'line 1')])
169
0.1.25 by Martin Pool
Handle insertion of new weave layers that insert text on top of the basis
170
        self.assertEqual(k.get(1),
171
                         ['line 1',
172
                          'line 2'])
173
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
174
        self.assertEqual(k.annotate(1),
175
                         [(0, 'line 1'),
176
                          (1, 'line 2')])
177
1083 by Martin Pool
- add space to store revision-id in weave files
178
        k.add('text2', [0], ['line 1', 'diverged line'])
0.1.28 by Martin Pool
More tests for insertion of lines in new versions.
179
180
        self.assertEqual(k.annotate(2),
181
                         [(0, 'line 1'),
182
                          (2, 'diverged line')])
183
0.1.54 by Martin Pool
Fix weave line calculation when making deltas
184
        text3 = ['line 1', 'middle line', 'line 2']
1083 by Martin Pool
- add space to store revision-id in weave files
185
        k.add('text3',
186
              [0, 1],
0.1.54 by Martin Pool
Fix weave line calculation when making deltas
187
              text3)
188
937 by Martin Pool
- weave raises IndexError when an invalid revision is given
189
        # self.log("changes to text3: " + pformat(list(k._delta(set([0, 1]), text3))))
0.1.54 by Martin Pool
Fix weave line calculation when making deltas
190
944 by Martin Pool
- refactor member names in Weave code
191
        self.log("k._weave=" + pformat(k._weave))
0.1.28 by Martin Pool
More tests for insertion of lines in new versions.
192
193
        self.assertEqual(k.annotate(3),
194
                         [(0, 'line 1'),
195
                          (3, 'middle line'),
196
                          (1, 'line 2')])
197
0.1.31 by Martin Pool
Fix insertion of multiple regions, calculating the right line offset as we go.
198
        # now multiple insertions at different places
1083 by Martin Pool
- add space to store revision-id in weave files
199
        k.add('text4',
200
              [0, 1, 3],
0.1.31 by Martin Pool
Fix insertion of multiple regions, calculating the right line offset as we go.
201
              ['line 1', 'aaa', 'middle line', 'bbb', 'line 2', 'ccc'])
202
203
        self.assertEqual(k.annotate(4), 
204
                         [(0, 'line 1'),
205
                          (4, 'aaa'),
206
                          (3, 'middle line'),
207
                          (4, 'bbb'),
208
                          (1, 'line 2'),
209
                          (4, 'ccc')])
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
210
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
211
0.1.48 by Martin Pool
Basic parsing of delete instructions.
212
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
213
class DeleteLines(TestBase):
214
    """Deletion of lines from existing text.
215
216
    Try various texts all based on a common ancestor."""
217
    def runTest(self):
218
        k = Weave()
219
220
        base_text = ['one', 'two', 'three', 'four']
221
1083 by Martin Pool
- add space to store revision-id in weave files
222
        k.add('text0', [], base_text)
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
223
        
224
        texts = [['one', 'two', 'three'],
225
                 ['two', 'three', 'four'],
226
                 ['one', 'four'],
227
                 ['one', 'two', 'three', 'four'],
228
                 ]
229
1083 by Martin Pool
- add space to store revision-id in weave files
230
        i = 1
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
231
        for t in texts:
1083 by Martin Pool
- add space to store revision-id in weave files
232
            ver = k.add('text%d' % i,
233
                        [0], t)
234
            i += 1
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
235
236
        self.log('final weave:')
944 by Martin Pool
- refactor member names in Weave code
237
        self.log('k._weave=' + pformat(k._weave))
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
238
239
        for i in range(len(texts)):
240
            self.assertEqual(k.get(i+1),
241
                             texts[i])
242
            
243
244
245
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
246
class SuicideDelete(TestBase):
0.1.55 by Martin Pool
doc
247
    """Invalid weave which tries to add and delete simultaneously."""
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
248
    def runTest(self):
249
        k = Weave()
250
944 by Martin Pool
- refactor member names in Weave code
251
        k._parents = [(),
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
252
                ]
944 by Martin Pool
- refactor member names in Weave code
253
        k._weave = [('{', 0),
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
254
                'first line',
255
                ('[', 0),
256
                'deleted in 0',
257
                (']', 0),
258
                ('}', 0),
259
                ]
891 by Martin Pool
- fix up refactoring of weave
260
        ################################### SKIPPED
261
        # Weave.get doesn't trap this anymore
262
        return 
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
263
264
        self.assertRaises(WeaveFormatError,
265
                          k.get,
266
                          0)        
267
268
269
0.1.48 by Martin Pool
Basic parsing of delete instructions.
270
class CannedDelete(TestBase):
271
    """Unpack canned weave with deleted lines."""
272
    def runTest(self):
273
        k = Weave()
274
944 by Martin Pool
- refactor member names in Weave code
275
        k._parents = [(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
276
                frozenset([0]),
0.1.48 by Martin Pool
Basic parsing of delete instructions.
277
                ]
944 by Martin Pool
- refactor member names in Weave code
278
        k._weave = [('{', 0),
0.1.48 by Martin Pool
Basic parsing of delete instructions.
279
                'first line',
280
                ('[', 1),
281
                'line to be deleted',
282
                (']', 1),
283
                'last line',
284
                ('}', 0),
285
                ]
286
287
        self.assertEqual(k.get(0),
288
                         ['first line',
289
                          'line to be deleted',
290
                          'last line',
291
                          ])
292
0.1.50 by Martin Pool
Basic implementation of deletion markers
293
        self.assertEqual(k.get(1),
294
                         ['first line',
295
                          'last line',
296
                          ])
297
0.1.48 by Martin Pool
Basic parsing of delete instructions.
298
299
0.1.51 by Martin Pool
Add test for replacement lines
300
class CannedReplacement(TestBase):
301
    """Unpack canned weave with deleted lines."""
302
    def runTest(self):
303
        k = Weave()
304
944 by Martin Pool
- refactor member names in Weave code
305
        k._parents = [frozenset(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
306
                frozenset([0]),
0.1.51 by Martin Pool
Add test for replacement lines
307
                ]
944 by Martin Pool
- refactor member names in Weave code
308
        k._weave = [('{', 0),
0.1.51 by Martin Pool
Add test for replacement lines
309
                'first line',
310
                ('[', 1),
311
                'line to be deleted',
312
                (']', 1),
313
                ('{', 1),
314
                'replacement line',                
315
                ('}', 1),
316
                'last line',
317
                ('}', 0),
318
                ]
319
320
        self.assertEqual(k.get(0),
321
                         ['first line',
322
                          'line to be deleted',
323
                          'last line',
324
                          ])
325
326
        self.assertEqual(k.get(1),
327
                         ['first line',
328
                          'replacement line',
329
                          'last line',
330
                          ])
331
332
333
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
334
class BadWeave(TestBase):
335
    """Test that we trap an insert which should not occur."""
336
    def runTest(self):
337
        k = Weave()
338
944 by Martin Pool
- refactor member names in Weave code
339
        k._parents = [frozenset(),
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
340
                ]
944 by Martin Pool
- refactor member names in Weave code
341
        k._weave = ['bad line',
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
342
                ('{', 0),
343
                'foo {',
344
                ('{', 1),
345
                '  added in version 1',
346
                ('{', 2),
347
                '  added in v2',
348
                ('}', 2),
349
                '  also from v1',
350
                ('}', 1),
351
                '}',
352
                ('}', 0)]
353
891 by Martin Pool
- fix up refactoring of weave
354
        ################################### SKIPPED
355
        # Weave.get doesn't trap this anymore
356
        return 
357
358
0.1.47 by Martin Pool
New WeaveError and WeaveFormatError rather than assertions.
359
        self.assertRaises(WeaveFormatError,
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
360
                          k.get,
361
                          0)
362
363
364
class BadInsert(TestBase):
365
    """Test that we trap an insert which should not occur."""
366
    def runTest(self):
367
        k = Weave()
368
944 by Martin Pool
- refactor member names in Weave code
369
        k._parents = [frozenset(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
370
                frozenset([0]),
371
                frozenset([0]),
372
                frozenset([0,1,2]),
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
373
                ]
944 by Martin Pool
- refactor member names in Weave code
374
        k._weave = [('{', 0),
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
375
                'foo {',
376
                ('{', 1),
377
                '  added in version 1',
378
                ('{', 1),
379
                '  more in 1',
380
                ('}', 1),
381
                ('}', 1),
382
                ('}', 0)]
383
891 by Martin Pool
- fix up refactoring of weave
384
385
        # this is not currently enforced by get
386
        return  ##########################################
387
0.1.47 by Martin Pool
New WeaveError and WeaveFormatError rather than assertions.
388
        self.assertRaises(WeaveFormatError,
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
389
                          k.get,
390
                          0)
391
0.1.47 by Martin Pool
New WeaveError and WeaveFormatError rather than assertions.
392
        self.assertRaises(WeaveFormatError,
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
393
                          k.get,
394
                          1)
395
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
396
397
class InsertNested(TestBase):
398
    """Insertion with nested instructions."""
399
    def runTest(self):
400
        k = Weave()
401
944 by Martin Pool
- refactor member names in Weave code
402
        k._parents = [frozenset(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
403
                frozenset([0]),
404
                frozenset([0]),
405
                frozenset([0,1,2]),
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
406
                ]
944 by Martin Pool
- refactor member names in Weave code
407
        k._weave = [('{', 0),
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
408
                'foo {',
409
                ('{', 1),
410
                '  added in version 1',
0.1.42 by Martin Pool
More tests for nested insert instructions
411
                ('{', 2),
412
                '  added in v2',
413
                ('}', 2),
414
                '  also from v1',
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
415
                ('}', 1),
416
                '}',
417
                ('}', 0)]
418
419
        self.assertEqual(k.get(0),
420
                         ['foo {',
421
                          '}'])
422
423
        self.assertEqual(k.get(1),
424
                         ['foo {',
425
                          '  added in version 1',
0.1.42 by Martin Pool
More tests for nested insert instructions
426
                          '  also from v1',
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
427
                          '}'])
428
                       
0.1.44 by Martin Pool
More tests for nested insert instructions
429
        self.assertEqual(k.get(2),
430
                         ['foo {',
431
                          '  added in v2',
432
                          '}'])
433
434
        self.assertEqual(k.get(3),
435
                         ['foo {',
436
                          '  added in version 1',
437
                          '  added in v2',
438
                          '  also from v1',
439
                          '}'])
440
                         
0.1.45 by Martin Pool
doc
441
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
442
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
443
class DeleteLines2(TestBase):
0.1.30 by Martin Pool
Start adding tests for line deletion
444
    """Test recording revisions that delete lines.
445
446
    This relies on the weave having a way to represent lines knocked
447
    out by a later revision."""
448
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
449
        k = Weave()
0.1.30 by Martin Pool
Start adding tests for line deletion
450
1083 by Martin Pool
- add space to store revision-id in weave files
451
        k.add('text0', [], ["line the first",
0.1.30 by Martin Pool
Start adding tests for line deletion
452
                   "line 2",
453
                   "line 3",
454
                   "fine"])
455
456
        self.assertEqual(len(k.get(0)), 4)
457
1083 by Martin Pool
- add space to store revision-id in weave files
458
        k.add('text1', [0], ["line the first",
0.1.30 by Martin Pool
Start adding tests for line deletion
459
                   "fine"])
460
461
        self.assertEqual(k.get(1),
462
                         ["line the first",
463
                          "fine"])
464
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
465
        self.assertEqual(k.annotate(1),
466
                         [(0, "line the first"),
467
                          (0, "fine")])
468
0.1.30 by Martin Pool
Start adding tests for line deletion
469
0.1.26 by Martin Pool
Refactor parameters to add command
470
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
471
class IncludeVersions(TestBase):
472
    """Check texts that are stored across multiple revisions.
473
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
474
    Here we manually create a weave with particular encoding and make
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
475
    sure it unpacks properly.
476
477
    Text 0 includes nothing; text 1 includes text 0 and adds some
478
    lines.
479
    """
480
481
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
482
        k = Weave()
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
483
944 by Martin Pool
- refactor member names in Weave code
484
        k._parents = [frozenset(), frozenset([0])]
485
        k._weave = [('{', 0),
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
486
                "first line",
487
                ('}', 0),
488
                ('{', 1),
489
                "second line",
490
                ('}', 1)]
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
491
492
        self.assertEqual(k.get(1),
493
                         ["first line",
494
                          "second line"])
495
496
        self.assertEqual(k.get(0),
497
                         ["first line"])
498
0.1.5 by Martin Pool
Add test for storing two text versions.
499
0.1.14 by Martin Pool
Another test for version inclusion
500
class DivergedIncludes(TestBase):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
501
    """Weave with two diverged texts based on version 0.
0.1.14 by Martin Pool
Another test for version inclusion
502
    """
503
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
504
        k = Weave()
0.1.14 by Martin Pool
Another test for version inclusion
505
944 by Martin Pool
- refactor member names in Weave code
506
        k._parents = [frozenset(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
507
                frozenset([0]),
508
                frozenset([0]),
0.1.17 by Martin Pool
Use objects rather than tuples for tracking VerInfo for
509
                ]
944 by Martin Pool
- refactor member names in Weave code
510
        k._weave = [('{', 0),
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
511
                "first line",
512
                ('}', 0),
513
                ('{', 1),
514
                "second line",
515
                ('}', 1),
516
                ('{', 2),
517
                "alternative second line",
518
                ('}', 2),                
519
                ]
0.1.14 by Martin Pool
Another test for version inclusion
520
521
        self.assertEqual(k.get(0),
522
                         ["first line"])
523
524
        self.assertEqual(k.get(1),
525
                         ["first line",
526
                          "second line"])
527
528
        self.assertEqual(k.get(2),
529
                         ["first line",
530
                          "alternative second line"])
531
924 by Martin Pool
- Add IntSet class
532
        self.assertEqual(list(k.inclusions([2])),
533
                         [0, 2])
0.1.77 by Martin Pool
New Weave.get_included() does transitive expansion
534
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
535
536
537
class ReplaceLine(TestBase):
538
    def runTest(self):
539
        k = Weave()
540
541
        text0 = ['cheddar', 'stilton', 'gruyere']
542
        text1 = ['cheddar', 'blue vein', 'neufchatel', 'chevre']
543
        
1083 by Martin Pool
- add space to store revision-id in weave files
544
        k.add('text0', [], text0)
545
        k.add('text1', [0], text1)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
546
944 by Martin Pool
- refactor member names in Weave code
547
        self.log('k._weave=' + pformat(k._weave))
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
548
0.1.59 by Martin Pool
More modification tests
549
        self.assertEqual(k.get(0), text0)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
550
        self.assertEqual(k.get(1), text1)
551
0.1.64 by Martin Pool
Add test for merging versions
552
553
554
class Merge(TestBase):
0.1.95 by Martin Pool
- preliminary merge conflict detection
555
    """Storage of versions that merge diverged parents"""
0.1.64 by Martin Pool
Add test for merging versions
556
    def runTest(self):
557
        k = Weave()
558
559
        texts = [['header'],
560
                 ['header', '', 'line from 1'],
561
                 ['header', '', 'line from 2', 'more from 2'],
562
                 ['header', '', 'line from 1', 'fixup line', 'line from 2'],
563
                 ]
564
1083 by Martin Pool
- add space to store revision-id in weave files
565
        k.add('text0', [], texts[0])
566
        k.add('text1', [0], texts[1])
567
        k.add('text2', [0], texts[2])
568
        k.add('merge', [0, 1, 2], texts[3])
0.1.64 by Martin Pool
Add test for merging versions
569
570
        for i, t in enumerate(texts):
571
            self.assertEqual(k.get(i), t)
572
573
        self.assertEqual(k.annotate(3),
574
                         [(0, 'header'),
575
                          (1, ''),
576
                          (1, 'line from 1'),
577
                          (3, 'fixup line'),
578
                          (2, 'line from 2'),
579
                          ])
580
924 by Martin Pool
- Add IntSet class
581
        self.assertEqual(list(k.inclusions([3])),
582
                         [0, 1, 2, 3])
0.1.77 by Martin Pool
New Weave.get_included() does transitive expansion
583
944 by Martin Pool
- refactor member names in Weave code
584
        self.log('k._weave=' + pformat(k._weave))
0.1.64 by Martin Pool
Add test for merging versions
585
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
586
        self.check_read_write(k)
0.1.65 by Martin Pool
Add Weave.merge_iter to get automerged lines
587
588
0.1.95 by Martin Pool
- preliminary merge conflict detection
589
class Conflicts(TestBase):
590
    """Test detection of conflicting regions during a merge.
591
592
    A base version is inserted, then two descendents try to
593
    insert different lines in the same place.  These should be
594
    reported as a possible conflict and forwarded to the user."""
595
    def runTest(self):
596
        return  # NOT RUN
597
        k = Weave()
598
599
        k.add([], ['aaa', 'bbb'])
600
        k.add([0], ['aaa', '111', 'bbb'])
601
        k.add([1], ['aaa', '222', 'bbb'])
602
603
        merged = k.merge([1, 2])
604
605
        self.assertEquals([[['aaa']],
606
                           [['111'], ['222']],
607
                           [['bbb']]])
608
609
610
611
class NonConflict(TestBase):
612
    """Two descendants insert compatible changes.
613
614
    No conflict should be reported."""
615
    def runTest(self):
616
        return  # NOT RUN
617
        k = Weave()
618
619
        k.add([], ['aaa', 'bbb'])
620
        k.add([0], ['111', 'aaa', 'ccc', 'bbb'])
621
        k.add([1], ['aaa', 'ccc', 'bbb', '222'])
622
623
    
624
    
625
626
0.1.65 by Martin Pool
Add Weave.merge_iter to get automerged lines
627
class AutoMerge(TestBase):
628
    def runTest(self):
629
        k = Weave()
630
631
        texts = [['header', 'aaa', 'bbb'],
632
                 ['header', 'aaa', 'line from 1', 'bbb'],
633
                 ['header', 'aaa', 'bbb', 'line from 2', 'more from 2'],
634
                 ]
635
1083 by Martin Pool
- add space to store revision-id in weave files
636
        k.add('text0', [], texts[0])
637
        k.add('text1', [0], texts[1])
638
        k.add('text2', [0], texts[2])
0.1.65 by Martin Pool
Add Weave.merge_iter to get automerged lines
639
944 by Martin Pool
- refactor member names in Weave code
640
        self.log('k._weave=' + pformat(k._weave))
0.1.65 by Martin Pool
Add Weave.merge_iter to get automerged lines
641
0.1.95 by Martin Pool
- preliminary merge conflict detection
642
        m = list(k.mash_iter([0, 1, 2]))
0.1.65 by Martin Pool
Add Weave.merge_iter to get automerged lines
643
644
        self.assertEqual(m,
645
                         ['header', 'aaa',
646
                          'line from 1',
647
                          'bbb',
648
                          'line from 2', 'more from 2'])
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
649
        
650
651
652
class Khayyam(TestBase):
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
653
    """Test changes to multi-line texts, and read/write"""
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
654
    def runTest(self):
655
        rawtexts = [
656
            """A Book of Verses underneath the Bough,
657
            A Jug of Wine, a Loaf of Bread, -- and Thou
658
            Beside me singing in the Wilderness --
659
            Oh, Wilderness were Paradise enow!""",
660
            
661
            """A Book of Verses underneath the Bough,
662
            A Jug of Wine, a Loaf of Bread, -- and Thou
663
            Beside me singing in the Wilderness --
664
            Oh, Wilderness were Paradise now!""",
0.1.59 by Martin Pool
More modification tests
665
666
            """A Book of poems underneath the tree,
667
            A Jug of Wine, a Loaf of Bread,
668
            and Thou
669
            Beside me singing in the Wilderness --
670
            Oh, Wilderness were Paradise now!
671
672
            -- O. Khayyam""",
673
674
            """A Book of Verses underneath the Bough,
675
            A Jug of Wine, a Loaf of Bread,
676
            and Thou
677
            Beside me singing in the Wilderness --
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
678
            Oh, Wilderness were Paradise now!""",
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
679
            ]
680
        texts = [[l.strip() for l in t.split('\n')] for t in rawtexts]
681
682
        k = Weave()
683
        parents = set()
1083 by Martin Pool
- add space to store revision-id in weave files
684
        i = 0
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
685
        for t in texts:
1083 by Martin Pool
- add space to store revision-id in weave files
686
            ver = k.add('text%d' % i,
687
                        list(parents), t)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
688
            parents.add(ver)
1083 by Martin Pool
- add space to store revision-id in weave files
689
            i += 1
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
690
944 by Martin Pool
- refactor member names in Weave code
691
        self.log("k._weave=" + pformat(k._weave))
0.1.59 by Martin Pool
More modification tests
692
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
693
        for i, t in enumerate(texts):
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
694
            self.assertEqual(k.get(i), t)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
695
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
696
        self.check_read_write(k)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
697
698
920 by Martin Pool
- add more test cases for weave_merge
699
700
class MergeCases(TestBase):
701
    def doMerge(self, base, a, b, mp):
702
        from cStringIO import StringIO
703
        from textwrap import dedent
704
705
        def addcrlf(x):
706
            return x + '\n'
707
        
708
        w = Weave()
1083 by Martin Pool
- add space to store revision-id in weave files
709
        w.add('text0', [], map(addcrlf, base))
710
        w.add('text1', [0], map(addcrlf, a))
711
        w.add('text2', [0], map(addcrlf, b))
920 by Martin Pool
- add more test cases for weave_merge
712
935 by Martin Pool
- log weave for merge tests to help debugging
713
        self.log('weave is:')
714
        tmpf = StringIO()
715
        write_weave(w, tmpf)
716
        self.log(tmpf.getvalue())
717
920 by Martin Pool
- add more test cases for weave_merge
718
        self.log('merge plan:')
719
        p = list(w.plan_merge(1, 2))
720
        for state, line in p:
721
            if line:
722
                self.log('%12s | %s' % (state, line[:-1]))
723
724
        self.log('merge:')
725
        mt = StringIO()
726
        mt.writelines(w.weave_merge(p))
727
        mt.seek(0)
728
        self.log(mt.getvalue())
729
730
        mp = map(addcrlf, mp)
731
        self.assertEqual(mt.readlines(), mp)
732
        
733
        
734
    def testOneInsert(self):
735
        self.doMerge([],
736
                     ['aa'],
737
                     [],
738
                     ['aa'])
739
740
    def testSeparateInserts(self):
741
        self.doMerge(['aaa', 'bbb', 'ccc'],
742
                     ['aaa', 'xxx', 'bbb', 'ccc'],
743
                     ['aaa', 'bbb', 'yyy', 'ccc'],
744
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
745
746
    def testSameInsert(self):
747
        self.doMerge(['aaa', 'bbb', 'ccc'],
748
                     ['aaa', 'xxx', 'bbb', 'ccc'],
749
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'],
750
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
751
752
    def testOverlappedInsert(self):
753
        self.doMerge(['aaa', 'bbb'],
754
                     ['aaa', 'xxx', 'yyy', 'bbb'],
755
                     ['aaa', 'xxx', 'bbb'],
756
                     ['aaa', '<<<<', 'xxx', 'yyy', '====', 'xxx', '>>>>', 'bbb'])
757
758
        # really it ought to reduce this to 
759
        # ['aaa', 'xxx', 'yyy', 'bbb']
760
761
762
    def testClashReplace(self):
763
        self.doMerge(['aaa'],
764
                     ['xxx'],
765
                     ['yyy', 'zzz'],
766
                     ['<<<<', 'xxx', '====', 'yyy', 'zzz', '>>>>'])
767
768
    def testNonClashInsert(self):
769
        self.doMerge(['aaa'],
770
                     ['xxx', 'aaa'],
771
                     ['yyy', 'zzz'],
772
                     ['<<<<', 'xxx', 'aaa', '====', 'yyy', 'zzz', '>>>>'])
773
774
        self.doMerge(['aaa'],
775
                     ['aaa'],
776
                     ['yyy', 'zzz'],
777
                     ['yyy', 'zzz'])
945 by Martin Pool
- add stubbed-out test for clashing replace and delete
778
779
780
    def testDeleteAndModify(self):
781
        """Clashing delete and modification.
782
783
        If one side modifies a region and the other deletes it then
784
        there should be a conflict with one side blank.
785
        """
786
787
        #######################################
788
        # skippd, not working yet
789
        return
790
        
791
        self.doMerge(['aaa', 'bbb', 'ccc'],
792
                     ['aaa', 'ddd', 'ccc'],
793
                     ['aaa', 'ccc'],
794
                     ['<<<<', 'aaa', '====', '>>>>', 'ccc'])
1393.1.48 by Martin Pool
- Add stub Weave.join() method
795
796
797
class JoinWeavesTests(TestBase):
1393.1.50 by Martin Pool
- more development of Weave.join()
798
    def setUp(self):
799
        super(JoinWeavesTests, self).setUp()
800
        self.weave1 = Weave()
801
        self.lines1 = ['hello\n']
802
        self.lines3 = ['hello\n', 'cruel\n', 'world\n']
803
        self.weave1.add('v1', [], self.lines1)
804
        self.weave1.add('v2', [0], ['hello\n', 'world\n'])
805
        self.weave1.add('v3', [1], self.lines3)
806
        
1393.1.48 by Martin Pool
- Add stub Weave.join() method
807
    def test_join_empty(self):
808
        """Join two empty weaves."""
809
        eq = self.assertEqual
810
        w1 = Weave()
811
        w2 = Weave()
812
        w1.join(w2)
813
        eq(w1.numversions(), 0)
814
        
1393.1.50 by Martin Pool
- more development of Weave.join()
815
    def test_join_empty_to_nonempty(self):
816
        """Join empty weave onto nonempty."""
817
        self.weave1.join(Weave())
818
        self.assertEqual(len(self.weave1), 3)
819
820
    def test_join_unrelated(self):
821
        """Join two weaves with no history in common."""
822
        wb = Weave()
823
        wb.add('b1', [], ['line from b\n'])
824
        w1 = self.weave1
825
        w1.join(wb)
826
        eq = self.assertEqual
827
        eq(len(w1), 4)
828
        eq(sorted(list(w1.iter_names())),
829
           ['b1', 'v1', 'v2', 'v3'])
920 by Martin Pool
- add more test cases for weave_merge
830
1393.1.51 by Martin Pool
- new Weave.copy()
831
    def test_join_related(self):
832
        wa = self.weave1.copy()
833
        wb = self.weave1.copy()
834
        wa.add('a1', ['v3'], ['hello\n', 'sweet\n', 'world\n'])
835
        wb.add('b1', ['v3'], ['hello\n', 'pale blue\n', 'world\n'])
836
        eq = self.assertEquals
837
        eq(len(wa), 4)
838
        eq(len(wb), 4)
839
        wa.join(wb)
840
        eq(len(wa), 5)
841
        eq(wa.get_lines('b1'),
842
           ['hello\n', 'pale blue\n', 'world\n'])
843
1393.1.67 by Martin Pool
- test that we cannot join weaves with different ancestry
844
    def test_join_parent_disagreement(self):
845
        """Cannot join weaves with different parents for a version."""
846
        wa = Weave()
847
        wb = Weave()
848
        wa.add('v1', [], ['hello\n'])
849
        wb.add('v0', [], [])
850
        wb.add('v1', ['v0'], ['hello\n'])
851
        self.assertRaises(WeaveError,
852
                          wa.join, wb)
853
854
    def test_join_text_disagreement(self):
855
        """Cannot join weaves with different texts for a version."""
856
        wa = Weave()
857
        wb = Weave()
858
        wa.add('v1', [], ['hello\n'])
859
        wb.add('v1', [], ['not\n', 'hello\n'])
860
        self.assertRaises(WeaveError,
861
                          wa.join, wb)
862
1393.1.66 by Martin Pool
- fix join of weaves where parents occur at different offsets
863
    def test_join_unordered(self):
864
        """Join weaves where indexes differ.
865
        
866
        The source weave contains a different version at index 0."""
867
        wa = self.weave1.copy()
868
        wb = Weave()
869
        wb.add('x1', [], ['line from x1\n'])
870
        wb.add('v1', [], ['hello\n'])
871
        wb.add('v2', ['v1'], ['hello\n', 'world\n'])
872
        wa.join(wb)
873
        eq = self.assertEquals
874
        eq(sorted(wa.iter_names()), ['v1', 'v2', 'v3', 'x1',])
875
        eq(wa.get_text('x1'), 'line from x1\n')
876
1393.1.68 by Martin Pool
- add reweave that joins with ghosts
877
    def test_reweave_with_empty(self):
878
        wb = Weave()
879
        wr = reweave(self.weave1, wb)
880
        eq = self.assertEquals
881
        eq(sorted(wr.iter_names()), ['v1', 'v2', 'v3'])
882
        eq(wr.get_lines('v3'), ['hello\n', 'cruel\n', 'world\n'])
1185.13.4 by Robert Collins
make reweave visible as a weave method, and quickly integrate into fetch
883
        self.weave1.reweave(wb)
884
        self.assertEquals(wr, self.weave1)
885
886
    def test_join_with_ghosts_raises_parent_mismatch(self):
887
        wa = self.weave1.copy()
888
        wb = Weave()
889
        wb.add('x1', [], ['line from x1\n'])
890
        wb.add('v1', [], ['hello\n'])
891
        wb.add('v2', ['v1', 'x1'], ['hello\n', 'world\n'])
892
        self.assertRaises(errors.WeaveParentMismatch, wa.join, wb)
1393.1.68 by Martin Pool
- add reweave that joins with ghosts
893
894
    def test_reweave_with_ghosts(self):
1393.1.66 by Martin Pool
- fix join of weaves where parents occur at different offsets
895
        """Join that inserts parents of an existing revision.
896
897
        This can happen when merging from another branch who
898
        knows about revisions the destination does not.  In 
899
        this test the second weave knows of an additional parent of 
900
        v2.  Any revisions which are in common still have to have the 
901
        same text."""
1393.1.67 by Martin Pool
- test that we cannot join weaves with different ancestry
902
        wa = self.weave1.copy()
903
        wb = Weave()
904
        wb.add('x1', [], ['line from x1\n'])
905
        wb.add('v1', [], ['hello\n'])
906
        wb.add('v2', ['v1', 'x1'], ['hello\n', 'world\n'])
1393.1.68 by Martin Pool
- add reweave that joins with ghosts
907
        wc = reweave(wa, wb)
1393.1.67 by Martin Pool
- test that we cannot join weaves with different ancestry
908
        eq = self.assertEquals
1393.1.68 by Martin Pool
- add reweave that joins with ghosts
909
        eq(sorted(wc.iter_names()), ['v1', 'v2', 'v3', 'x1',])
910
        eq(wc.get_text('x1'), 'line from x1\n')
1393.1.70 by Martin Pool
- more tests for reweave
911
        eq(wc.get_lines('v2'), ['hello\n', 'world\n'])
912
        eq(wc.parent_names('v2'), ['v1', 'x1'])
1185.13.4 by Robert Collins
make reweave visible as a weave method, and quickly integrate into fetch
913
        self.weave1.reweave(wb)
914
        self.assertEquals(wc, self.weave1)
1393.1.66 by Martin Pool
- fix join of weaves where parents occur at different offsets
915
920 by Martin Pool
- add more test cases for weave_merge
916
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
917
if __name__ == '__main__':
918
    import sys
1233 by Martin Pool
- fix up weave tests for new test framework
919
    import unittest
920
    sys.exit(unittest.main())
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
921