~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
21
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
22
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
26
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
27
import testsweet
872 by Martin Pool
- update testweave
28
from bzrlib.weave import Weave, WeaveFormatError
29
from bzrlib.weavefile import write_weave, read_weave
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
30
from pprint import pformat
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
31
0.1.66 by Martin Pool
Cope without set/frozenset classes
32
33
try:
34
    set
35
    frozenset
36
except NameError:
37
    from sets import Set, ImmutableSet
38
    set = Set
39
    frozenset = ImmutableSet
0.1.67 by Martin Pool
More fixes to try to run on python2.3
40
    del Set, ImmutableSet
0.1.66 by Martin Pool
Cope without set/frozenset classes
41
42
43
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
44
# texts for use in testing
0.1.3 by Martin Pool
Change storage of texts for testing
45
TEXT_0 = ["Hello world"]
46
TEXT_1 = ["Hello world",
47
          "A second line"]
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
48
49
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
50
51
class TestBase(testsweet.TestBase):
52
    def check_read_write(self, k):
53
        """Check the weave k can be written & re-read."""
54
        from tempfile import TemporaryFile
55
        tf = TemporaryFile()
56
57
        write_weave(k, tf)
58
        tf.seek(0)
59
        k2 = read_weave(tf)
60
61
        if k != k2:
62
            tf.seek(0)
63
            self.log('serialized weave:')
64
            self.log(tf.read())
1083 by Martin Pool
- add space to store revision-id in weave files
65
66
            self.log('')
67
            self.log('parents: %s' % (k._parents == k2._parents))
68
            self.log('         %r' % k._parents)
69
            self.log('         %r' % k2._parents)
70
            self.log('')
71
72
            
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
73
            self.fail('read/write check failed')
74
        
75
        
76
77
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
78
class Easy(TestBase):
79
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
80
        k = Weave()
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
81
82
83
class StoreText(TestBase):
84
    """Store and retrieve a simple text."""
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
        idx = k.add('text0', [], TEXT_0)
0.1.4 by Martin Pool
Start indexing knits by both integer and version string.
88
        self.assertEqual(k.get(idx), TEXT_0)
89
        self.assertEqual(idx, 0)
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
90
91
0.1.7 by Martin Pool
Add trivial annotate text
92
93
class AnnotateOne(TestBase):
94
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
95
        k = Weave()
1083 by Martin Pool
- add space to store revision-id in weave files
96
        k.add('text0', [], TEXT_0)
0.1.7 by Martin Pool
Add trivial annotate text
97
        self.assertEqual(k.annotate(0),
98
                         [(0, TEXT_0[0])])
99
100
0.1.5 by Martin Pool
Add test for storing two text versions.
101
class StoreTwo(TestBase):
102
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
103
        k = Weave()
0.1.5 by Martin Pool
Add test for storing two text versions.
104
1083 by Martin Pool
- add space to store revision-id in weave files
105
        idx = k.add('text0', [], TEXT_0)
0.1.5 by Martin Pool
Add test for storing two text versions.
106
        self.assertEqual(idx, 0)
107
1083 by Martin Pool
- add space to store revision-id in weave files
108
        idx = k.add('text1', [], TEXT_1)
0.1.5 by Martin Pool
Add test for storing two text versions.
109
        self.assertEqual(idx, 1)
110
111
        self.assertEqual(k.get(0), TEXT_0)
112
        self.assertEqual(k.get(1), TEXT_1)
113
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
114
        k.dump(self.TEST_LOG)
115
116
0.1.21 by Martin Pool
Start computing a delta to insert a new revision
117
0.1.27 by Martin Pool
Check that version numbers passed in are reasonable
118
class InvalidAdd(TestBase):
119
    """Try to use invalid version number during add."""
120
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
121
        k = Weave()
0.1.27 by Martin Pool
Check that version numbers passed in are reasonable
122
937 by Martin Pool
- weave raises IndexError when an invalid revision is given
123
        self.assertRaises(IndexError,
0.1.27 by Martin Pool
Check that version numbers passed in are reasonable
124
                          k.add,
1083 by Martin Pool
- add space to store revision-id in weave files
125
                          'text0',
0.1.27 by Martin Pool
Check that version numbers passed in are reasonable
126
                          [69],
127
                          ['new text!'])
128
129
0.1.26 by Martin Pool
Refactor parameters to add command
130
class InsertLines(TestBase):
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
131
    """Store a revision that adds one line to the original.
132
133
    Look at the annotations to make sure that the first line is matched
134
    and not stored repeatedly."""
135
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
136
        k = Weave()
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
137
1083 by Martin Pool
- add space to store revision-id in weave files
138
        k.add('text0', [], ['line 1'])
139
        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
140
141
        self.assertEqual(k.annotate(0),
142
                         [(0, 'line 1')])
143
0.1.25 by Martin Pool
Handle insertion of new weave layers that insert text on top of the basis
144
        self.assertEqual(k.get(1),
145
                         ['line 1',
146
                          'line 2'])
147
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
148
        self.assertEqual(k.annotate(1),
149
                         [(0, 'line 1'),
150
                          (1, 'line 2')])
151
1083 by Martin Pool
- add space to store revision-id in weave files
152
        k.add('text2', [0], ['line 1', 'diverged line'])
0.1.28 by Martin Pool
More tests for insertion of lines in new versions.
153
154
        self.assertEqual(k.annotate(2),
155
                         [(0, 'line 1'),
156
                          (2, 'diverged line')])
157
0.1.54 by Martin Pool
Fix weave line calculation when making deltas
158
        text3 = ['line 1', 'middle line', 'line 2']
1083 by Martin Pool
- add space to store revision-id in weave files
159
        k.add('text3',
160
              [0, 1],
0.1.54 by Martin Pool
Fix weave line calculation when making deltas
161
              text3)
162
937 by Martin Pool
- weave raises IndexError when an invalid revision is given
163
        # 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
164
944 by Martin Pool
- refactor member names in Weave code
165
        self.log("k._weave=" + pformat(k._weave))
0.1.28 by Martin Pool
More tests for insertion of lines in new versions.
166
167
        self.assertEqual(k.annotate(3),
168
                         [(0, 'line 1'),
169
                          (3, 'middle line'),
170
                          (1, 'line 2')])
171
0.1.31 by Martin Pool
Fix insertion of multiple regions, calculating the right line offset as we go.
172
        # now multiple insertions at different places
1083 by Martin Pool
- add space to store revision-id in weave files
173
        k.add('text4',
174
              [0, 1, 3],
0.1.31 by Martin Pool
Fix insertion of multiple regions, calculating the right line offset as we go.
175
              ['line 1', 'aaa', 'middle line', 'bbb', 'line 2', 'ccc'])
176
177
        self.assertEqual(k.annotate(4), 
178
                         [(0, 'line 1'),
179
                          (4, 'aaa'),
180
                          (3, 'middle line'),
181
                          (4, 'bbb'),
182
                          (1, 'line 2'),
183
                          (4, 'ccc')])
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
184
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
185
0.1.48 by Martin Pool
Basic parsing of delete instructions.
186
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
187
class DeleteLines(TestBase):
188
    """Deletion of lines from existing text.
189
190
    Try various texts all based on a common ancestor."""
191
    def runTest(self):
192
        k = Weave()
193
194
        base_text = ['one', 'two', 'three', 'four']
195
1083 by Martin Pool
- add space to store revision-id in weave files
196
        k.add('text0', [], base_text)
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
197
        
198
        texts = [['one', 'two', 'three'],
199
                 ['two', 'three', 'four'],
200
                 ['one', 'four'],
201
                 ['one', 'two', 'three', 'four'],
202
                 ]
203
1083 by Martin Pool
- add space to store revision-id in weave files
204
        i = 1
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
205
        for t in texts:
1083 by Martin Pool
- add space to store revision-id in weave files
206
            ver = k.add('text%d' % i,
207
                        [0], t)
208
            i += 1
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
209
210
        self.log('final weave:')
944 by Martin Pool
- refactor member names in Weave code
211
        self.log('k._weave=' + pformat(k._weave))
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
212
213
        for i in range(len(texts)):
214
            self.assertEqual(k.get(i+1),
215
                             texts[i])
216
            
217
218
219
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
220
class SuicideDelete(TestBase):
0.1.55 by Martin Pool
doc
221
    """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
222
    def runTest(self):
223
        k = Weave()
224
944 by Martin Pool
- refactor member names in Weave code
225
        k._parents = [(),
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
226
                ]
944 by Martin Pool
- refactor member names in Weave code
227
        k._weave = [('{', 0),
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
228
                'first line',
229
                ('[', 0),
230
                'deleted in 0',
231
                (']', 0),
232
                ('}', 0),
233
                ]
891 by Martin Pool
- fix up refactoring of weave
234
        ################################### SKIPPED
235
        # Weave.get doesn't trap this anymore
236
        return 
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
237
238
        self.assertRaises(WeaveFormatError,
239
                          k.get,
240
                          0)        
241
242
243
0.1.48 by Martin Pool
Basic parsing of delete instructions.
244
class CannedDelete(TestBase):
245
    """Unpack canned weave with deleted lines."""
246
    def runTest(self):
247
        k = Weave()
248
944 by Martin Pool
- refactor member names in Weave code
249
        k._parents = [(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
250
                frozenset([0]),
0.1.48 by Martin Pool
Basic parsing of delete instructions.
251
                ]
944 by Martin Pool
- refactor member names in Weave code
252
        k._weave = [('{', 0),
0.1.48 by Martin Pool
Basic parsing of delete instructions.
253
                'first line',
254
                ('[', 1),
255
                'line to be deleted',
256
                (']', 1),
257
                'last line',
258
                ('}', 0),
259
                ]
260
261
        self.assertEqual(k.get(0),
262
                         ['first line',
263
                          'line to be deleted',
264
                          'last line',
265
                          ])
266
0.1.50 by Martin Pool
Basic implementation of deletion markers
267
        self.assertEqual(k.get(1),
268
                         ['first line',
269
                          'last line',
270
                          ])
271
0.1.48 by Martin Pool
Basic parsing of delete instructions.
272
273
0.1.51 by Martin Pool
Add test for replacement lines
274
class CannedReplacement(TestBase):
275
    """Unpack canned weave with deleted lines."""
276
    def runTest(self):
277
        k = Weave()
278
944 by Martin Pool
- refactor member names in Weave code
279
        k._parents = [frozenset(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
280
                frozenset([0]),
0.1.51 by Martin Pool
Add test for replacement lines
281
                ]
944 by Martin Pool
- refactor member names in Weave code
282
        k._weave = [('{', 0),
0.1.51 by Martin Pool
Add test for replacement lines
283
                'first line',
284
                ('[', 1),
285
                'line to be deleted',
286
                (']', 1),
287
                ('{', 1),
288
                'replacement line',                
289
                ('}', 1),
290
                'last line',
291
                ('}', 0),
292
                ]
293
294
        self.assertEqual(k.get(0),
295
                         ['first line',
296
                          'line to be deleted',
297
                          'last line',
298
                          ])
299
300
        self.assertEqual(k.get(1),
301
                         ['first line',
302
                          'replacement line',
303
                          'last line',
304
                          ])
305
306
307
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
308
class BadWeave(TestBase):
309
    """Test that we trap an insert which should not occur."""
310
    def runTest(self):
311
        k = Weave()
312
944 by Martin Pool
- refactor member names in Weave code
313
        k._parents = [frozenset(),
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
314
                ]
944 by Martin Pool
- refactor member names in Weave code
315
        k._weave = ['bad line',
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
316
                ('{', 0),
317
                'foo {',
318
                ('{', 1),
319
                '  added in version 1',
320
                ('{', 2),
321
                '  added in v2',
322
                ('}', 2),
323
                '  also from v1',
324
                ('}', 1),
325
                '}',
326
                ('}', 0)]
327
891 by Martin Pool
- fix up refactoring of weave
328
        ################################### SKIPPED
329
        # Weave.get doesn't trap this anymore
330
        return 
331
332
0.1.47 by Martin Pool
New WeaveError and WeaveFormatError rather than assertions.
333
        self.assertRaises(WeaveFormatError,
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
334
                          k.get,
335
                          0)
336
337
338
class BadInsert(TestBase):
339
    """Test that we trap an insert which should not occur."""
340
    def runTest(self):
341
        k = Weave()
342
944 by Martin Pool
- refactor member names in Weave code
343
        k._parents = [frozenset(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
344
                frozenset([0]),
345
                frozenset([0]),
346
                frozenset([0,1,2]),
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
347
                ]
944 by Martin Pool
- refactor member names in Weave code
348
        k._weave = [('{', 0),
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
349
                'foo {',
350
                ('{', 1),
351
                '  added in version 1',
352
                ('{', 1),
353
                '  more in 1',
354
                ('}', 1),
355
                ('}', 1),
356
                ('}', 0)]
357
891 by Martin Pool
- fix up refactoring of weave
358
359
        # this is not currently enforced by get
360
        return  ##########################################
361
0.1.47 by Martin Pool
New WeaveError and WeaveFormatError rather than assertions.
362
        self.assertRaises(WeaveFormatError,
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
363
                          k.get,
364
                          0)
365
0.1.47 by Martin Pool
New WeaveError and WeaveFormatError rather than assertions.
366
        self.assertRaises(WeaveFormatError,
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
367
                          k.get,
368
                          1)
369
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
370
371
class InsertNested(TestBase):
372
    """Insertion with nested instructions."""
373
    def runTest(self):
374
        k = Weave()
375
944 by Martin Pool
- refactor member names in Weave code
376
        k._parents = [frozenset(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
377
                frozenset([0]),
378
                frozenset([0]),
379
                frozenset([0,1,2]),
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
380
                ]
944 by Martin Pool
- refactor member names in Weave code
381
        k._weave = [('{', 0),
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
382
                'foo {',
383
                ('{', 1),
384
                '  added in version 1',
0.1.42 by Martin Pool
More tests for nested insert instructions
385
                ('{', 2),
386
                '  added in v2',
387
                ('}', 2),
388
                '  also from v1',
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
389
                ('}', 1),
390
                '}',
391
                ('}', 0)]
392
393
        self.assertEqual(k.get(0),
394
                         ['foo {',
395
                          '}'])
396
397
        self.assertEqual(k.get(1),
398
                         ['foo {',
399
                          '  added in version 1',
0.1.42 by Martin Pool
More tests for nested insert instructions
400
                          '  also from v1',
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
401
                          '}'])
402
                       
0.1.44 by Martin Pool
More tests for nested insert instructions
403
        self.assertEqual(k.get(2),
404
                         ['foo {',
405
                          '  added in v2',
406
                          '}'])
407
408
        self.assertEqual(k.get(3),
409
                         ['foo {',
410
                          '  added in version 1',
411
                          '  added in v2',
412
                          '  also from v1',
413
                          '}'])
414
                         
0.1.45 by Martin Pool
doc
415
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
416
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
417
class DeleteLines2(TestBase):
0.1.30 by Martin Pool
Start adding tests for line deletion
418
    """Test recording revisions that delete lines.
419
420
    This relies on the weave having a way to represent lines knocked
421
    out by a later revision."""
422
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
423
        k = Weave()
0.1.30 by Martin Pool
Start adding tests for line deletion
424
1083 by Martin Pool
- add space to store revision-id in weave files
425
        k.add('text0', [], ["line the first",
0.1.30 by Martin Pool
Start adding tests for line deletion
426
                   "line 2",
427
                   "line 3",
428
                   "fine"])
429
430
        self.assertEqual(len(k.get(0)), 4)
431
1083 by Martin Pool
- add space to store revision-id in weave files
432
        k.add('text1', [0], ["line the first",
0.1.30 by Martin Pool
Start adding tests for line deletion
433
                   "fine"])
434
435
        self.assertEqual(k.get(1),
436
                         ["line the first",
437
                          "fine"])
438
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
439
        self.assertEqual(k.annotate(1),
440
                         [(0, "line the first"),
441
                          (0, "fine")])
442
0.1.30 by Martin Pool
Start adding tests for line deletion
443
0.1.26 by Martin Pool
Refactor parameters to add command
444
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
445
class IncludeVersions(TestBase):
446
    """Check texts that are stored across multiple revisions.
447
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
448
    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
449
    sure it unpacks properly.
450
451
    Text 0 includes nothing; text 1 includes text 0 and adds some
452
    lines.
453
    """
454
455
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
456
        k = Weave()
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
457
944 by Martin Pool
- refactor member names in Weave code
458
        k._parents = [frozenset(), frozenset([0])]
459
        k._weave = [('{', 0),
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
460
                "first line",
461
                ('}', 0),
462
                ('{', 1),
463
                "second line",
464
                ('}', 1)]
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
465
466
        self.assertEqual(k.get(1),
467
                         ["first line",
468
                          "second line"])
469
470
        self.assertEqual(k.get(0),
471
                         ["first line"])
472
473
        k.dump(self.TEST_LOG)
474
0.1.5 by Martin Pool
Add test for storing two text versions.
475
0.1.14 by Martin Pool
Another test for version inclusion
476
class DivergedIncludes(TestBase):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
477
    """Weave with two diverged texts based on version 0.
0.1.14 by Martin Pool
Another test for version inclusion
478
    """
479
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
480
        k = Weave()
0.1.14 by Martin Pool
Another test for version inclusion
481
944 by Martin Pool
- refactor member names in Weave code
482
        k._parents = [frozenset(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
483
                frozenset([0]),
484
                frozenset([0]),
0.1.17 by Martin Pool
Use objects rather than tuples for tracking VerInfo for
485
                ]
944 by Martin Pool
- refactor member names in Weave code
486
        k._weave = [('{', 0),
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
487
                "first line",
488
                ('}', 0),
489
                ('{', 1),
490
                "second line",
491
                ('}', 1),
492
                ('{', 2),
493
                "alternative second line",
494
                ('}', 2),                
495
                ]
0.1.14 by Martin Pool
Another test for version inclusion
496
497
        self.assertEqual(k.get(0),
498
                         ["first line"])
499
500
        self.assertEqual(k.get(1),
501
                         ["first line",
502
                          "second line"])
503
504
        self.assertEqual(k.get(2),
505
                         ["first line",
506
                          "alternative second line"])
507
924 by Martin Pool
- Add IntSet class
508
        self.assertEqual(list(k.inclusions([2])),
509
                         [0, 2])
0.1.77 by Martin Pool
New Weave.get_included() does transitive expansion
510
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
511
512
513
class ReplaceLine(TestBase):
514
    def runTest(self):
515
        k = Weave()
516
517
        text0 = ['cheddar', 'stilton', 'gruyere']
518
        text1 = ['cheddar', 'blue vein', 'neufchatel', 'chevre']
519
        
1083 by Martin Pool
- add space to store revision-id in weave files
520
        k.add('text0', [], text0)
521
        k.add('text1', [0], text1)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
522
944 by Martin Pool
- refactor member names in Weave code
523
        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
524
0.1.59 by Martin Pool
More modification tests
525
        self.assertEqual(k.get(0), text0)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
526
        self.assertEqual(k.get(1), text1)
527
0.1.64 by Martin Pool
Add test for merging versions
528
529
530
class Merge(TestBase):
0.1.95 by Martin Pool
- preliminary merge conflict detection
531
    """Storage of versions that merge diverged parents"""
0.1.64 by Martin Pool
Add test for merging versions
532
    def runTest(self):
533
        k = Weave()
534
535
        texts = [['header'],
536
                 ['header', '', 'line from 1'],
537
                 ['header', '', 'line from 2', 'more from 2'],
538
                 ['header', '', 'line from 1', 'fixup line', 'line from 2'],
539
                 ]
540
1083 by Martin Pool
- add space to store revision-id in weave files
541
        k.add('text0', [], texts[0])
542
        k.add('text1', [0], texts[1])
543
        k.add('text2', [0], texts[2])
544
        k.add('merge', [0, 1, 2], texts[3])
0.1.64 by Martin Pool
Add test for merging versions
545
546
        for i, t in enumerate(texts):
547
            self.assertEqual(k.get(i), t)
548
549
        self.assertEqual(k.annotate(3),
550
                         [(0, 'header'),
551
                          (1, ''),
552
                          (1, 'line from 1'),
553
                          (3, 'fixup line'),
554
                          (2, 'line from 2'),
555
                          ])
556
924 by Martin Pool
- Add IntSet class
557
        self.assertEqual(list(k.inclusions([3])),
558
                         [0, 1, 2, 3])
0.1.77 by Martin Pool
New Weave.get_included() does transitive expansion
559
944 by Martin Pool
- refactor member names in Weave code
560
        self.log('k._weave=' + pformat(k._weave))
0.1.64 by Martin Pool
Add test for merging versions
561
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
562
        self.check_read_write(k)
0.1.65 by Martin Pool
Add Weave.merge_iter to get automerged lines
563
564
0.1.95 by Martin Pool
- preliminary merge conflict detection
565
class Conflicts(TestBase):
566
    """Test detection of conflicting regions during a merge.
567
568
    A base version is inserted, then two descendents try to
569
    insert different lines in the same place.  These should be
570
    reported as a possible conflict and forwarded to the user."""
571
    def runTest(self):
572
        return  # NOT RUN
573
        k = Weave()
574
575
        k.add([], ['aaa', 'bbb'])
576
        k.add([0], ['aaa', '111', 'bbb'])
577
        k.add([1], ['aaa', '222', 'bbb'])
578
579
        merged = k.merge([1, 2])
580
581
        self.assertEquals([[['aaa']],
582
                           [['111'], ['222']],
583
                           [['bbb']]])
584
585
586
587
class NonConflict(TestBase):
588
    """Two descendants insert compatible changes.
589
590
    No conflict should be reported."""
591
    def runTest(self):
592
        return  # NOT RUN
593
        k = Weave()
594
595
        k.add([], ['aaa', 'bbb'])
596
        k.add([0], ['111', 'aaa', 'ccc', 'bbb'])
597
        k.add([1], ['aaa', 'ccc', 'bbb', '222'])
598
599
    
600
    
601
602
0.1.65 by Martin Pool
Add Weave.merge_iter to get automerged lines
603
class AutoMerge(TestBase):
604
    def runTest(self):
605
        k = Weave()
606
607
        texts = [['header', 'aaa', 'bbb'],
608
                 ['header', 'aaa', 'line from 1', 'bbb'],
609
                 ['header', 'aaa', 'bbb', 'line from 2', 'more from 2'],
610
                 ]
611
1083 by Martin Pool
- add space to store revision-id in weave files
612
        k.add('text0', [], texts[0])
613
        k.add('text1', [0], texts[1])
614
        k.add('text2', [0], texts[2])
0.1.65 by Martin Pool
Add Weave.merge_iter to get automerged lines
615
944 by Martin Pool
- refactor member names in Weave code
616
        self.log('k._weave=' + pformat(k._weave))
0.1.65 by Martin Pool
Add Weave.merge_iter to get automerged lines
617
0.1.95 by Martin Pool
- preliminary merge conflict detection
618
        m = list(k.mash_iter([0, 1, 2]))
0.1.65 by Martin Pool
Add Weave.merge_iter to get automerged lines
619
620
        self.assertEqual(m,
621
                         ['header', 'aaa',
622
                          'line from 1',
623
                          'bbb',
624
                          'line from 2', 'more from 2'])
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
625
        
626
627
628
class Khayyam(TestBase):
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
629
    """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
630
    def runTest(self):
631
        rawtexts = [
632
            """A Book of Verses underneath the Bough,
633
            A Jug of Wine, a Loaf of Bread, -- and Thou
634
            Beside me singing in the Wilderness --
635
            Oh, Wilderness were Paradise enow!""",
636
            
637
            """A Book of Verses underneath the Bough,
638
            A Jug of Wine, a Loaf of Bread, -- and Thou
639
            Beside me singing in the Wilderness --
640
            Oh, Wilderness were Paradise now!""",
0.1.59 by Martin Pool
More modification tests
641
642
            """A Book of poems underneath the tree,
643
            A Jug of Wine, a Loaf of Bread,
644
            and Thou
645
            Beside me singing in the Wilderness --
646
            Oh, Wilderness were Paradise now!
647
648
            -- O. Khayyam""",
649
650
            """A Book of Verses underneath the Bough,
651
            A Jug of Wine, a Loaf of Bread,
652
            and Thou
653
            Beside me singing in the Wilderness --
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
654
            Oh, Wilderness were Paradise now!""",
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
655
            ]
656
        texts = [[l.strip() for l in t.split('\n')] for t in rawtexts]
657
658
        k = Weave()
659
        parents = set()
1083 by Martin Pool
- add space to store revision-id in weave files
660
        i = 0
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
661
        for t in texts:
1083 by Martin Pool
- add space to store revision-id in weave files
662
            ver = k.add('text%d' % i,
663
                        list(parents), t)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
664
            parents.add(ver)
1083 by Martin Pool
- add space to store revision-id in weave files
665
            i += 1
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
666
944 by Martin Pool
- refactor member names in Weave code
667
        self.log("k._weave=" + pformat(k._weave))
0.1.59 by Martin Pool
More modification tests
668
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
669
        for i, t in enumerate(texts):
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
670
            self.assertEqual(k.get(i), t)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
671
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
672
        self.check_read_write(k)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
673
674
920 by Martin Pool
- add more test cases for weave_merge
675
676
class MergeCases(TestBase):
677
    def doMerge(self, base, a, b, mp):
678
        from cStringIO import StringIO
679
        from textwrap import dedent
680
681
        def addcrlf(x):
682
            return x + '\n'
683
        
684
        w = Weave()
1083 by Martin Pool
- add space to store revision-id in weave files
685
        w.add('text0', [], map(addcrlf, base))
686
        w.add('text1', [0], map(addcrlf, a))
687
        w.add('text2', [0], map(addcrlf, b))
920 by Martin Pool
- add more test cases for weave_merge
688
935 by Martin Pool
- log weave for merge tests to help debugging
689
        self.log('weave is:')
690
        tmpf = StringIO()
691
        write_weave(w, tmpf)
692
        self.log(tmpf.getvalue())
693
920 by Martin Pool
- add more test cases for weave_merge
694
        self.log('merge plan:')
695
        p = list(w.plan_merge(1, 2))
696
        for state, line in p:
697
            if line:
698
                self.log('%12s | %s' % (state, line[:-1]))
699
700
        self.log('merge:')
701
        mt = StringIO()
702
        mt.writelines(w.weave_merge(p))
703
        mt.seek(0)
704
        self.log(mt.getvalue())
705
706
        mp = map(addcrlf, mp)
707
        self.assertEqual(mt.readlines(), mp)
708
        
709
        
710
    def testOneInsert(self):
711
        self.doMerge([],
712
                     ['aa'],
713
                     [],
714
                     ['aa'])
715
716
    def testSeparateInserts(self):
717
        self.doMerge(['aaa', 'bbb', 'ccc'],
718
                     ['aaa', 'xxx', 'bbb', 'ccc'],
719
                     ['aaa', 'bbb', 'yyy', 'ccc'],
720
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
721
722
    def testSameInsert(self):
723
        self.doMerge(['aaa', 'bbb', 'ccc'],
724
                     ['aaa', 'xxx', 'bbb', 'ccc'],
725
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'],
726
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
727
728
    def testOverlappedInsert(self):
729
        self.doMerge(['aaa', 'bbb'],
730
                     ['aaa', 'xxx', 'yyy', 'bbb'],
731
                     ['aaa', 'xxx', 'bbb'],
732
                     ['aaa', '<<<<', 'xxx', 'yyy', '====', 'xxx', '>>>>', 'bbb'])
733
734
        # really it ought to reduce this to 
735
        # ['aaa', 'xxx', 'yyy', 'bbb']
736
737
738
    def testClashReplace(self):
739
        self.doMerge(['aaa'],
740
                     ['xxx'],
741
                     ['yyy', 'zzz'],
742
                     ['<<<<', 'xxx', '====', 'yyy', 'zzz', '>>>>'])
743
744
    def testNonClashInsert(self):
745
        self.doMerge(['aaa'],
746
                     ['xxx', 'aaa'],
747
                     ['yyy', 'zzz'],
748
                     ['<<<<', 'xxx', 'aaa', '====', 'yyy', 'zzz', '>>>>'])
749
750
        self.doMerge(['aaa'],
751
                     ['aaa'],
752
                     ['yyy', 'zzz'],
753
                     ['yyy', 'zzz'])
945 by Martin Pool
- add stubbed-out test for clashing replace and delete
754
755
756
    def testDeleteAndModify(self):
757
        """Clashing delete and modification.
758
759
        If one side modifies a region and the other deletes it then
760
        there should be a conflict with one side blank.
761
        """
762
763
        #######################################
764
        # skippd, not working yet
765
        return
766
        
767
        self.doMerge(['aaa', 'bbb', 'ccc'],
768
                     ['aaa', 'ddd', 'ccc'],
769
                     ['aaa', 'ccc'],
770
                     ['<<<<', 'aaa', '====', '>>>>', 'ccc'])
920 by Martin Pool
- add more test cases for weave_merge
771
    
772
773
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
774
def testweave():
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
775
    import testsweet
776
    from unittest import TestSuite, TestLoader
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
777
    import testweave
945 by Martin Pool
- add stubbed-out test for clashing replace and delete
778
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
779
    tl = TestLoader()
780
    suite = TestSuite()
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
781
    suite.addTest(tl.loadTestsFromModule(testweave))
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
782
    
0.1.15 by Martin Pool
Fix inverted shell return code for testknit
783
    return int(not testsweet.run_suite(suite)) # for shell 0=true
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
784
785
786
if __name__ == '__main__':
787
    import sys
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
788
    sys.exit(testweave())
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
789