/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to tools/testweave.py

  • Committer: Martin Pool
  • Date: 2005-07-18 11:23:40 UTC
  • Revision ID: mbp@sourcefrog.net-20050718112340-4ffbfa3624bb6ef3
- weavebench should set random seed to make it reproducible

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 Canonical Ltd
2
 
#
 
1
#! /usr/bin/python2.4
 
2
 
 
3
# Copyright (C) 2005 by Canonical Ltd
 
4
 
3
5
# This program is free software; you can redistribute it and/or modify
4
6
# it under the terms of the GNU General Public License as published by
5
7
# the Free Software Foundation; either version 2 of the License, or
6
8
# (at your option) any later version.
7
 
#
 
9
 
8
10
# This program is distributed in the hope that it will be useful,
9
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
13
# GNU General Public License for more details.
12
 
#
 
14
 
13
15
# You should have received a copy of the GNU General Public License
14
16
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
 
18
 
# TODO: tests regarding version names
19
 
# TODO: rbc 20050108 test that join does not leave an inconsistent weave
20
 
#       if it fails.
 
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
18
 
 
19
 
 
20
 
21
21
 
22
22
"""test suite for weave algorithm"""
23
23
 
 
24
 
 
25
import testsweet
 
26
from bzrlib.weave import Weave, WeaveFormatError
 
27
from bzrlib.weavefile import write_weave, read_weave
24
28
from pprint import pformat
25
 
 
26
 
from bzrlib import (
27
 
    errors,
28
 
    )
29
 
from bzrlib.osutils import sha_string
30
 
from bzrlib.tests import TestCase, TestCaseInTempDir
31
 
from bzrlib.weave import Weave, WeaveFormatError, WeaveError
32
 
from bzrlib.weavefile import write_weave, read_weave
 
29
from bzrlib.intset import IntSet
 
30
 
 
31
 
 
32
try:
 
33
    set
 
34
    frozenset
 
35
except NameError:
 
36
    from sets import Set, ImmutableSet
 
37
    set = Set
 
38
    frozenset = ImmutableSet
 
39
    del Set, ImmutableSet
 
40
 
33
41
 
34
42
 
35
43
# texts for use in testing
38
46
          "A second line"]
39
47
 
40
48
 
41
 
class TestBase(TestCase):
42
49
 
 
50
class TestBase(testsweet.TestBase):
43
51
    def check_read_write(self, k):
44
52
        """Check the weave k can be written & re-read."""
45
53
        from tempfile import TemporaryFile
53
61
            tf.seek(0)
54
62
            self.log('serialized weave:')
55
63
            self.log(tf.read())
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
64
            self.fail('read/write check failed')
63
 
 
64
 
 
65
 
class WeaveContains(TestBase):
66
 
    """Weave __contains__ operator"""
67
 
    def runTest(self):
68
 
        k = Weave(get_scope=lambda:None)
69
 
        self.assertFalse('foo' in k)
70
 
        k.add_lines('foo', [], TEXT_1)
71
 
        self.assertTrue('foo' in k)
 
65
        
 
66
        
72
67
 
73
68
 
74
69
class Easy(TestBase):
76
71
        k = Weave()
77
72
 
78
73
 
 
74
class StoreText(TestBase):
 
75
    """Store and retrieve a simple text."""
 
76
    def runTest(self):
 
77
        k = Weave()
 
78
        idx = k.add([], TEXT_0)
 
79
        self.assertEqual(k.get(idx), TEXT_0)
 
80
        self.assertEqual(idx, 0)
 
81
 
 
82
 
 
83
 
79
84
class AnnotateOne(TestBase):
80
85
    def runTest(self):
81
86
        k = Weave()
82
 
        k.add_lines('text0', [], TEXT_0)
83
 
        self.assertEqual(k.annotate('text0'),
84
 
                         [('text0', TEXT_0[0])])
 
87
        k.add([], TEXT_0)
 
88
        self.assertEqual(k.annotate(0),
 
89
                         [(0, TEXT_0[0])])
 
90
 
 
91
 
 
92
class StoreTwo(TestBase):
 
93
    def runTest(self):
 
94
        k = Weave()
 
95
 
 
96
        idx = k.add([], TEXT_0)
 
97
        self.assertEqual(idx, 0)
 
98
 
 
99
        idx = k.add([], TEXT_1)
 
100
        self.assertEqual(idx, 1)
 
101
 
 
102
        self.assertEqual(k.get(0), TEXT_0)
 
103
        self.assertEqual(k.get(1), TEXT_1)
 
104
 
 
105
        k.dump(self.TEST_LOG)
 
106
 
85
107
 
86
108
 
87
109
class InvalidAdd(TestBase):
89
111
    def runTest(self):
90
112
        k = Weave()
91
113
 
92
 
        self.assertRaises(errors.RevisionNotPresent,
93
 
                          k.add_lines,
94
 
                          'text0',
95
 
                          ['69'],
 
114
        self.assertRaises(ValueError,
 
115
                          k.add,
 
116
                          [69],
96
117
                          ['new text!'])
97
118
 
98
119
 
99
 
class RepeatedAdd(TestBase):
100
 
    """Add the same version twice; harmless."""
101
 
 
102
 
    def test_duplicate_add(self):
103
 
        k = Weave()
104
 
        idx = k.add_lines('text0', [], TEXT_0)
105
 
        idx2 = k.add_lines('text0', [], TEXT_0)
106
 
        self.assertEqual(idx, idx2)
107
 
 
108
 
 
109
 
class InvalidRepeatedAdd(TestBase):
110
 
    def runTest(self):
111
 
        k = Weave()
112
 
        k.add_lines('basis', [], TEXT_0)
113
 
        idx = k.add_lines('text0', [], TEXT_0)
114
 
        self.assertRaises(errors.RevisionAlreadyPresent,
115
 
                          k.add_lines,
116
 
                          'text0',
117
 
                          [],
118
 
                          ['not the same text'])
119
 
        self.assertRaises(errors.RevisionAlreadyPresent,
120
 
                          k.add_lines,
121
 
                          'text0',
122
 
                          ['basis'],         # not the right parents
123
 
                          TEXT_0)
124
 
 
125
 
 
126
120
class InsertLines(TestBase):
127
121
    """Store a revision that adds one line to the original.
128
122
 
131
125
    def runTest(self):
132
126
        k = Weave()
133
127
 
134
 
        k.add_lines('text0', [], ['line 1'])
135
 
        k.add_lines('text1', ['text0'], ['line 1', 'line 2'])
136
 
 
137
 
        self.assertEqual(k.annotate('text0'),
138
 
                         [('text0', 'line 1')])
139
 
 
140
 
        self.assertEqual(k.get_lines(1),
 
128
        k.add([], ['line 1'])
 
129
        k.add([0], ['line 1', 'line 2'])
 
130
 
 
131
        self.assertEqual(k.annotate(0),
 
132
                         [(0, 'line 1')])
 
133
 
 
134
        self.assertEqual(k.get(1),
141
135
                         ['line 1',
142
136
                          'line 2'])
143
137
 
144
 
        self.assertEqual(k.annotate('text1'),
145
 
                         [('text0', 'line 1'),
146
 
                          ('text1', 'line 2')])
147
 
 
148
 
        k.add_lines('text2', ['text0'], ['line 1', 'diverged line'])
149
 
 
150
 
        self.assertEqual(k.annotate('text2'),
151
 
                         [('text0', 'line 1'),
152
 
                          ('text2', 'diverged line')])
 
138
        self.assertEqual(k.annotate(1),
 
139
                         [(0, 'line 1'),
 
140
                          (1, 'line 2')])
 
141
 
 
142
        k.add([0], ['line 1', 'diverged line'])
 
143
 
 
144
        self.assertEqual(k.annotate(2),
 
145
                         [(0, 'line 1'),
 
146
                          (2, 'diverged line')])
153
147
 
154
148
        text3 = ['line 1', 'middle line', 'line 2']
155
 
        k.add_lines('text3',
156
 
              ['text0', 'text1'],
 
149
        k.add([0, 1],
157
150
              text3)
158
151
 
159
 
        # self.log("changes to text3: " + pformat(list(k._delta(set([0, 1]), text3))))
160
 
 
161
 
        self.log("k._weave=" + pformat(k._weave))
162
 
 
163
 
        self.assertEqual(k.annotate('text3'),
164
 
                         [('text0', 'line 1'),
165
 
                          ('text3', 'middle line'),
166
 
                          ('text1', 'line 2')])
 
152
        self.log("changes to text3: " + pformat(list(k._delta(set([0, 1]), text3))))
 
153
 
 
154
        self.log("k._l=" + pformat(k._l))
 
155
 
 
156
        self.assertEqual(k.annotate(3),
 
157
                         [(0, 'line 1'),
 
158
                          (3, 'middle line'),
 
159
                          (1, 'line 2')])
167
160
 
168
161
        # now multiple insertions at different places
169
 
        k.add_lines('text4',
170
 
              ['text0', 'text1', 'text3'],
 
162
        k.add([0, 1, 3],
171
163
              ['line 1', 'aaa', 'middle line', 'bbb', 'line 2', 'ccc'])
172
164
 
173
 
        self.assertEqual(k.annotate('text4'),
174
 
                         [('text0', 'line 1'),
175
 
                          ('text4', 'aaa'),
176
 
                          ('text3', 'middle line'),
177
 
                          ('text4', 'bbb'),
178
 
                          ('text1', 'line 2'),
179
 
                          ('text4', 'ccc')])
 
165
        self.assertEqual(k.annotate(4), 
 
166
                         [(0, 'line 1'),
 
167
                          (4, 'aaa'),
 
168
                          (3, 'middle line'),
 
169
                          (4, 'bbb'),
 
170
                          (1, 'line 2'),
 
171
                          (4, 'ccc')])
 
172
 
180
173
 
181
174
 
182
175
class DeleteLines(TestBase):
188
181
 
189
182
        base_text = ['one', 'two', 'three', 'four']
190
183
 
191
 
        k.add_lines('text0', [], base_text)
192
 
 
 
184
        k.add([], base_text)
 
185
        
193
186
        texts = [['one', 'two', 'three'],
194
187
                 ['two', 'three', 'four'],
195
188
                 ['one', 'four'],
196
189
                 ['one', 'two', 'three', 'four'],
197
190
                 ]
198
191
 
199
 
        i = 1
200
192
        for t in texts:
201
 
            ver = k.add_lines('text%d' % i,
202
 
                        ['text0'], t)
203
 
            i += 1
 
193
            ver = k.add([0], t)
204
194
 
205
195
        self.log('final weave:')
206
 
        self.log('k._weave=' + pformat(k._weave))
 
196
        self.log('k._l=' + pformat(k._l))
207
197
 
208
198
        for i in range(len(texts)):
209
 
            self.assertEqual(k.get_lines(i+1),
 
199
            self.assertEqual(k.get(i+1),
210
200
                             texts[i])
 
201
            
 
202
 
211
203
 
212
204
 
213
205
class SuicideDelete(TestBase):
215
207
    def runTest(self):
216
208
        k = Weave()
217
209
 
218
 
        k._parents = [(),
 
210
        k._v = [(),
219
211
                ]
220
 
        k._weave = [('{', 0),
 
212
        k._l = [('{', 0),
221
213
                'first line',
222
214
                ('[', 0),
223
215
                'deleted in 0',
226
218
                ]
227
219
        ################################### SKIPPED
228
220
        # Weave.get doesn't trap this anymore
229
 
        return
 
221
        return 
230
222
 
231
223
        self.assertRaises(WeaveFormatError,
232
 
                          k.get_lines,
233
 
                          0)
 
224
                          k.get,
 
225
                          0)        
 
226
 
234
227
 
235
228
 
236
229
class CannedDelete(TestBase):
238
231
    def runTest(self):
239
232
        k = Weave()
240
233
 
241
 
        k._parents = [(),
 
234
        k._v = [(),
242
235
                frozenset([0]),
243
236
                ]
244
 
        k._weave = [('{', 0),
 
237
        k._l = [('{', 0),
245
238
                'first line',
246
239
                ('[', 1),
247
240
                'line to be deleted',
249
242
                'last line',
250
243
                ('}', 0),
251
244
                ]
252
 
        k._sha1s = [sha_string('first lineline to be deletedlast line')
253
 
                  , sha_string('first linelast line')]
254
245
 
255
 
        self.assertEqual(k.get_lines(0),
 
246
        self.assertEqual(k.get(0),
256
247
                         ['first line',
257
248
                          'line to be deleted',
258
249
                          'last line',
259
250
                          ])
260
251
 
261
 
        self.assertEqual(k.get_lines(1),
 
252
        self.assertEqual(k.get(1),
262
253
                         ['first line',
263
254
                          'last line',
264
255
                          ])
265
256
 
266
257
 
 
258
 
267
259
class CannedReplacement(TestBase):
268
260
    """Unpack canned weave with deleted lines."""
269
261
    def runTest(self):
270
262
        k = Weave()
271
263
 
272
 
        k._parents = [frozenset(),
 
264
        k._v = [frozenset(),
273
265
                frozenset([0]),
274
266
                ]
275
 
        k._weave = [('{', 0),
 
267
        k._l = [('{', 0),
276
268
                'first line',
277
269
                ('[', 1),
278
270
                'line to be deleted',
279
271
                (']', 1),
280
272
                ('{', 1),
281
 
                'replacement line',
 
273
                'replacement line',                
282
274
                ('}', 1),
283
275
                'last line',
284
276
                ('}', 0),
285
277
                ]
286
 
        k._sha1s = [sha_string('first lineline to be deletedlast line')
287
 
                  , sha_string('first linereplacement linelast line')]
288
278
 
289
 
        self.assertEqual(k.get_lines(0),
 
279
        self.assertEqual(k.get(0),
290
280
                         ['first line',
291
281
                          'line to be deleted',
292
282
                          'last line',
293
283
                          ])
294
284
 
295
 
        self.assertEqual(k.get_lines(1),
 
285
        self.assertEqual(k.get(1),
296
286
                         ['first line',
297
287
                          'replacement line',
298
288
                          'last line',
299
289
                          ])
300
290
 
301
291
 
 
292
 
302
293
class BadWeave(TestBase):
303
294
    """Test that we trap an insert which should not occur."""
304
295
    def runTest(self):
305
296
        k = Weave()
306
297
 
307
 
        k._parents = [frozenset(),
 
298
        k._v = [frozenset(),
308
299
                ]
309
 
        k._weave = ['bad line',
 
300
        k._l = ['bad line',
310
301
                ('{', 0),
311
302
                'foo {',
312
303
                ('{', 1),
321
312
 
322
313
        ################################### SKIPPED
323
314
        # Weave.get doesn't trap this anymore
324
 
        return
 
315
        return 
325
316
 
326
317
 
327
318
        self.assertRaises(WeaveFormatError,
334
325
    def runTest(self):
335
326
        k = Weave()
336
327
 
337
 
        k._parents = [frozenset(),
 
328
        k._v = [frozenset(),
338
329
                frozenset([0]),
339
330
                frozenset([0]),
340
331
                frozenset([0,1,2]),
341
332
                ]
342
 
        k._weave = [('{', 0),
 
333
        k._l = [('{', 0),
343
334
                'foo {',
344
335
                ('{', 1),
345
336
                '  added in version 1',
367
358
    def runTest(self):
368
359
        k = Weave()
369
360
 
370
 
        k._parents = [frozenset(),
 
361
        k._v = [frozenset(),
371
362
                frozenset([0]),
372
363
                frozenset([0]),
373
364
                frozenset([0,1,2]),
374
365
                ]
375
 
        k._weave = [('{', 0),
 
366
        k._l = [('{', 0),
376
367
                'foo {',
377
368
                ('{', 1),
378
369
                '  added in version 1',
384
375
                '}',
385
376
                ('}', 0)]
386
377
 
387
 
        k._sha1s = [sha_string('foo {}')
388
 
                  , sha_string('foo {  added in version 1  also from v1}')
389
 
                  , sha_string('foo {  added in v2}')
390
 
                  , sha_string('foo {  added in version 1  added in v2  also from v1}')
391
 
                  ]
392
 
 
393
 
        self.assertEqual(k.get_lines(0),
394
 
                         ['foo {',
395
 
                          '}'])
396
 
 
397
 
        self.assertEqual(k.get_lines(1),
398
 
                         ['foo {',
399
 
                          '  added in version 1',
400
 
                          '  also from v1',
401
 
                          '}'])
402
 
 
403
 
        self.assertEqual(k.get_lines(2),
404
 
                         ['foo {',
405
 
                          '  added in v2',
406
 
                          '}'])
407
 
 
408
 
        self.assertEqual(k.get_lines(3),
409
 
                         ['foo {',
410
 
                          '  added in version 1',
411
 
                          '  added in v2',
412
 
                          '  also from v1',
413
 
                          '}'])
 
378
        self.assertEqual(k.get(0),
 
379
                         ['foo {',
 
380
                          '}'])
 
381
 
 
382
        self.assertEqual(k.get(1),
 
383
                         ['foo {',
 
384
                          '  added in version 1',
 
385
                          '  also from v1',
 
386
                          '}'])
 
387
                       
 
388
        self.assertEqual(k.get(2),
 
389
                         ['foo {',
 
390
                          '  added in v2',
 
391
                          '}'])
 
392
 
 
393
        self.assertEqual(k.get(3),
 
394
                         ['foo {',
 
395
                          '  added in version 1',
 
396
                          '  added in v2',
 
397
                          '  also from v1',
 
398
                          '}'])
 
399
                         
414
400
 
415
401
 
416
402
class DeleteLines2(TestBase):
421
407
    def runTest(self):
422
408
        k = Weave()
423
409
 
424
 
        k.add_lines('text0', [], ["line the first",
 
410
        k.add([], ["line the first",
425
411
                   "line 2",
426
412
                   "line 3",
427
413
                   "fine"])
428
414
 
429
 
        self.assertEqual(len(k.get_lines(0)), 4)
 
415
        self.assertEqual(len(k.get(0)), 4)
430
416
 
431
 
        k.add_lines('text1', ['text0'], ["line the first",
 
417
        k.add([0], ["line the first",
432
418
                   "fine"])
433
419
 
434
 
        self.assertEqual(k.get_lines(1),
 
420
        self.assertEqual(k.get(1),
435
421
                         ["line the first",
436
422
                          "fine"])
437
423
 
438
 
        self.assertEqual(k.annotate('text1'),
439
 
                         [('text0', "line the first"),
440
 
                          ('text0', "fine")])
 
424
        self.assertEqual(k.annotate(1),
 
425
                         [(0, "line the first"),
 
426
                          (0, "fine")])
 
427
 
441
428
 
442
429
 
443
430
class IncludeVersions(TestBase):
453
440
    def runTest(self):
454
441
        k = Weave()
455
442
 
456
 
        k._parents = [frozenset(), frozenset([0])]
457
 
        k._weave = [('{', 0),
 
443
        k._v = [frozenset(), frozenset([0])]
 
444
        k._l = [('{', 0),
458
445
                "first line",
459
446
                ('}', 0),
460
447
                ('{', 1),
461
448
                "second line",
462
449
                ('}', 1)]
463
450
 
464
 
        k._sha1s = [sha_string('first line')
465
 
                  , sha_string('first linesecond line')]
466
 
 
467
 
        self.assertEqual(k.get_lines(1),
 
451
        self.assertEqual(k.get(1),
468
452
                         ["first line",
469
453
                          "second line"])
470
454
 
471
 
        self.assertEqual(k.get_lines(0),
 
455
        self.assertEqual(k.get(0),
472
456
                         ["first line"])
473
457
 
 
458
        k.dump(self.TEST_LOG)
 
459
 
474
460
 
475
461
class DivergedIncludes(TestBase):
476
462
    """Weave with two diverged texts based on version 0.
477
463
    """
478
464
    def runTest(self):
479
 
        # FIXME make the weave, dont poke at it.
480
465
        k = Weave()
481
466
 
482
 
        k._names = ['0', '1', '2']
483
 
        k._name_map = {'0':0, '1':1, '2':2}
484
 
        k._parents = [frozenset(),
 
467
        k._v = [frozenset(),
485
468
                frozenset([0]),
486
469
                frozenset([0]),
487
470
                ]
488
 
        k._weave = [('{', 0),
 
471
        k._l = [('{', 0),
489
472
                "first line",
490
473
                ('}', 0),
491
474
                ('{', 1),
493
476
                ('}', 1),
494
477
                ('{', 2),
495
478
                "alternative second line",
496
 
                ('}', 2),
 
479
                ('}', 2),                
497
480
                ]
498
481
 
499
 
        k._sha1s = [sha_string('first line')
500
 
                  , sha_string('first linesecond line')
501
 
                  , sha_string('first linealternative second line')]
502
 
 
503
 
        self.assertEqual(k.get_lines(0),
 
482
        self.assertEqual(k.get(0),
504
483
                         ["first line"])
505
484
 
506
 
        self.assertEqual(k.get_lines(1),
 
485
        self.assertEqual(k.get(1),
507
486
                         ["first line",
508
487
                          "second line"])
509
488
 
510
 
        self.assertEqual(k.get_lines('2'),
 
489
        self.assertEqual(k.get(2),
511
490
                         ["first line",
512
491
                          "alternative second line"])
513
492
 
514
 
        self.assertEqual(list(k.get_ancestry(['2'])),
515
 
                         ['0', '2'])
 
493
        self.assertEqual(list(k.inclusions([2])),
 
494
                         [0, 2])
 
495
 
516
496
 
517
497
 
518
498
class ReplaceLine(TestBase):
521
501
 
522
502
        text0 = ['cheddar', 'stilton', 'gruyere']
523
503
        text1 = ['cheddar', 'blue vein', 'neufchatel', 'chevre']
524
 
 
525
 
        k.add_lines('text0', [], text0)
526
 
        k.add_lines('text1', ['text0'], text1)
527
 
 
528
 
        self.log('k._weave=' + pformat(k._weave))
529
 
 
530
 
        self.assertEqual(k.get_lines(0), text0)
531
 
        self.assertEqual(k.get_lines(1), text1)
 
504
        
 
505
        k.add([], text0)
 
506
        k.add([0], text1)
 
507
 
 
508
        self.log('k._l=' + pformat(k._l))
 
509
 
 
510
        self.assertEqual(k.get(0), text0)
 
511
        self.assertEqual(k.get(1), text1)
 
512
 
532
513
 
533
514
 
534
515
class Merge(TestBase):
542
523
                 ['header', '', 'line from 1', 'fixup line', 'line from 2'],
543
524
                 ]
544
525
 
545
 
        k.add_lines('text0', [], texts[0])
546
 
        k.add_lines('text1', ['text0'], texts[1])
547
 
        k.add_lines('text2', ['text0'], texts[2])
548
 
        k.add_lines('merge', ['text0', 'text1', 'text2'], texts[3])
 
526
        k.add([], texts[0])
 
527
        k.add([0], texts[1])
 
528
        k.add([0], texts[2])
 
529
        k.add([0, 1, 2], texts[3])
549
530
 
550
531
        for i, t in enumerate(texts):
551
 
            self.assertEqual(k.get_lines(i), t)
 
532
            self.assertEqual(k.get(i), t)
552
533
 
553
 
        self.assertEqual(k.annotate('merge'),
554
 
                         [('text0', 'header'),
555
 
                          ('text1', ''),
556
 
                          ('text1', 'line from 1'),
557
 
                          ('merge', 'fixup line'),
558
 
                          ('text2', 'line from 2'),
 
534
        self.assertEqual(k.annotate(3),
 
535
                         [(0, 'header'),
 
536
                          (1, ''),
 
537
                          (1, 'line from 1'),
 
538
                          (3, 'fixup line'),
 
539
                          (2, 'line from 2'),
559
540
                          ])
560
541
 
561
 
        self.assertEqual(list(k.get_ancestry(['merge'])),
562
 
                         ['text0', 'text1', 'text2', 'merge'])
 
542
        self.assertEqual(list(k.inclusions([3])),
 
543
                         [0, 1, 2, 3])
563
544
 
564
 
        self.log('k._weave=' + pformat(k._weave))
 
545
        self.log('k._l=' + pformat(k._l))
565
546
 
566
547
        self.check_read_write(k)
567
548
 
576
557
        return  # NOT RUN
577
558
        k = Weave()
578
559
 
579
 
        k.add_lines([], ['aaa', 'bbb'])
580
 
        k.add_lines([0], ['aaa', '111', 'bbb'])
581
 
        k.add_lines([1], ['aaa', '222', 'bbb'])
 
560
        k.add([], ['aaa', 'bbb'])
 
561
        k.add([0], ['aaa', '111', 'bbb'])
 
562
        k.add([1], ['aaa', '222', 'bbb'])
582
563
 
583
564
        merged = k.merge([1, 2])
584
565
 
587
568
                           [['bbb']]])
588
569
 
589
570
 
 
571
 
590
572
class NonConflict(TestBase):
591
573
    """Two descendants insert compatible changes.
592
574
 
595
577
        return  # NOT RUN
596
578
        k = Weave()
597
579
 
598
 
        k.add_lines([], ['aaa', 'bbb'])
599
 
        k.add_lines([0], ['111', 'aaa', 'ccc', 'bbb'])
600
 
        k.add_lines([1], ['aaa', 'ccc', 'bbb', '222'])
 
580
        k.add([], ['aaa', 'bbb'])
 
581
        k.add([0], ['111', 'aaa', 'ccc', 'bbb'])
 
582
        k.add([1], ['aaa', 'ccc', 'bbb', '222'])
 
583
 
 
584
    
 
585
    
 
586
 
 
587
 
 
588
class AutoMerge(TestBase):
 
589
    def runTest(self):
 
590
        k = Weave()
 
591
 
 
592
        texts = [['header', 'aaa', 'bbb'],
 
593
                 ['header', 'aaa', 'line from 1', 'bbb'],
 
594
                 ['header', 'aaa', 'bbb', 'line from 2', 'more from 2'],
 
595
                 ]
 
596
 
 
597
        k.add([], texts[0])
 
598
        k.add([0], texts[1])
 
599
        k.add([0], texts[2])
 
600
 
 
601
        self.log('k._l=' + pformat(k._l))
 
602
 
 
603
        m = list(k.mash_iter([0, 1, 2]))
 
604
 
 
605
        self.assertEqual(m,
 
606
                         ['header', 'aaa',
 
607
                          'line from 1',
 
608
                          'bbb',
 
609
                          'line from 2', 'more from 2'])
 
610
        
601
611
 
602
612
 
603
613
class Khayyam(TestBase):
604
614
    """Test changes to multi-line texts, and read/write"""
605
 
 
606
 
    def test_multi_line_merge(self):
 
615
    def runTest(self):
607
616
        rawtexts = [
608
617
            """A Book of Verses underneath the Bough,
609
618
            A Jug of Wine, a Loaf of Bread, -- and Thou
610
619
            Beside me singing in the Wilderness --
611
620
            Oh, Wilderness were Paradise enow!""",
612
 
 
 
621
            
613
622
            """A Book of Verses underneath the Bough,
614
623
            A Jug of Wine, a Loaf of Bread, -- and Thou
615
624
            Beside me singing in the Wilderness --
633
642
 
634
643
        k = Weave()
635
644
        parents = set()
636
 
        i = 0
637
645
        for t in texts:
638
 
            ver = k.add_lines('text%d' % i,
639
 
                        list(parents), t)
640
 
            parents.add('text%d' % i)
641
 
            i += 1
 
646
            ver = k.add(list(parents), t)
 
647
            parents.add(ver)
642
648
 
643
 
        self.log("k._weave=" + pformat(k._weave))
 
649
        self.log("k._l=" + pformat(k._l))
644
650
 
645
651
        for i, t in enumerate(texts):
646
 
            self.assertEqual(k.get_lines(i), t)
 
652
            self.assertEqual(k.get(i), t)
647
653
 
648
654
        self.check_read_write(k)
649
655
 
650
656
 
651
 
class JoinWeavesTests(TestBase):
652
 
    def setUp(self):
653
 
        super(JoinWeavesTests, self).setUp()
654
 
        self.weave1 = Weave()
655
 
        self.lines1 = ['hello\n']
656
 
        self.lines3 = ['hello\n', 'cruel\n', 'world\n']
657
 
        self.weave1.add_lines('v1', [], self.lines1)
658
 
        self.weave1.add_lines('v2', ['v1'], ['hello\n', 'world\n'])
659
 
        self.weave1.add_lines('v3', ['v2'], self.lines3)
660
657
 
661
 
    def test_written_detection(self):
662
 
        # Test detection of weave file corruption.
663
 
        #
664
 
        # Make sure that we can detect if a weave file has
665
 
        # been corrupted. This doesn't test all forms of corruption,
666
 
        # but it at least helps verify the data you get, is what you want.
 
658
class MergeCases(TestBase):
 
659
    def doMerge(self, base, a, b, mp):
667
660
        from cStringIO import StringIO
 
661
        from textwrap import dedent
668
662
 
 
663
        def addcrlf(x):
 
664
            return x + '\n'
 
665
        
669
666
        w = Weave()
670
 
        w.add_lines('v1', [], ['hello\n'])
671
 
        w.add_lines('v2', ['v1'], ['hello\n', 'there\n'])
 
667
        w.add([], map(addcrlf, base))
 
668
        w.add([0], map(addcrlf, a))
 
669
        w.add([0], map(addcrlf, b))
672
670
 
 
671
        self.log('weave is:')
673
672
        tmpf = StringIO()
674
673
        write_weave(w, tmpf)
675
 
 
676
 
        # Because we are corrupting, we need to make sure we have the exact text
677
 
        self.assertEquals('# bzr weave file v5\n'
678
 
                          'i\n1 f572d396fae9206628714fb2ce00f72e94f2258f\nn v1\n\n'
679
 
                          'i 0\n1 90f265c6e75f1c8f9ab76dcf85528352c5f215ef\nn v2\n\n'
680
 
                          'w\n{ 0\n. hello\n}\n{ 1\n. there\n}\nW\n',
681
 
                          tmpf.getvalue())
682
 
 
683
 
        # Change a single letter
684
 
        tmpf = StringIO('# bzr weave file v5\n'
685
 
                        'i\n1 f572d396fae9206628714fb2ce00f72e94f2258f\nn v1\n\n'
686
 
                        'i 0\n1 90f265c6e75f1c8f9ab76dcf85528352c5f215ef\nn v2\n\n'
687
 
                        'w\n{ 0\n. hello\n}\n{ 1\n. There\n}\nW\n')
688
 
 
689
 
        w = read_weave(tmpf)
690
 
 
691
 
        self.assertEqual('hello\n', w.get_text('v1'))
692
 
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_text, 'v2')
693
 
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_lines, 'v2')
694
 
        self.assertRaises(errors.WeaveInvalidChecksum, w.check)
695
 
 
696
 
        # Change the sha checksum
697
 
        tmpf = StringIO('# bzr weave file v5\n'
698
 
                        'i\n1 f572d396fae9206628714fb2ce00f72e94f2258f\nn v1\n\n'
699
 
                        'i 0\n1 f0f265c6e75f1c8f9ab76dcf85528352c5f215ef\nn v2\n\n'
700
 
                        'w\n{ 0\n. hello\n}\n{ 1\n. there\n}\nW\n')
701
 
 
702
 
        w = read_weave(tmpf)
703
 
 
704
 
        self.assertEqual('hello\n', w.get_text('v1'))
705
 
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_text, 'v2')
706
 
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_lines, 'v2')
707
 
        self.assertRaises(errors.WeaveInvalidChecksum, w.check)
708
 
 
709
 
 
710
 
class TestWeave(TestCase):
711
 
 
712
 
    def test_allow_reserved_false(self):
713
 
        w = Weave('name', allow_reserved=False)
714
 
        # Add lines is checked at the WeaveFile level, not at the Weave level
715
 
        w.add_lines('name:', [], TEXT_1)
716
 
        # But get_lines is checked at this level
717
 
        self.assertRaises(errors.ReservedId, w.get_lines, 'name:')
718
 
 
719
 
    def test_allow_reserved_true(self):
720
 
        w = Weave('name', allow_reserved=True)
721
 
        w.add_lines('name:', [], TEXT_1)
722
 
        self.assertEqual(TEXT_1, w.get_lines('name:'))
723
 
 
724
 
 
725
 
class InstrumentedWeave(Weave):
726
 
    """Keep track of how many times functions are called."""
727
 
 
728
 
    def __init__(self, weave_name=None):
729
 
        self._extract_count = 0
730
 
        Weave.__init__(self, weave_name=weave_name)
731
 
 
732
 
    def _extract(self, versions):
733
 
        self._extract_count += 1
734
 
        return Weave._extract(self, versions)
735
 
 
736
 
 
737
 
class TestNeedsReweave(TestCase):
738
 
    """Internal corner cases for when reweave is needed."""
739
 
 
740
 
    def test_compatible_parents(self):
741
 
        w1 = Weave('a')
742
 
        my_parents = set([1, 2, 3])
743
 
        # subsets are ok
744
 
        self.assertTrue(w1._compatible_parents(my_parents, set([3])))
745
 
        # same sets
746
 
        self.assertTrue(w1._compatible_parents(my_parents, set(my_parents)))
747
 
        # same empty corner case
748
 
        self.assertTrue(w1._compatible_parents(set(), set()))
749
 
        # other cannot contain stuff my_parents does not
750
 
        self.assertFalse(w1._compatible_parents(set(), set([1])))
751
 
        self.assertFalse(w1._compatible_parents(my_parents, set([1, 2, 3, 4])))
752
 
        self.assertFalse(w1._compatible_parents(my_parents, set([4])))
753
 
 
754
 
 
755
 
class TestWeaveFile(TestCaseInTempDir):
756
 
 
757
 
    def test_empty_file(self):
758
 
        f = open('empty.weave', 'wb+')
759
 
        try:
760
 
            self.assertRaises(errors.WeaveFormatError,
761
 
                              read_weave, f)
762
 
        finally:
763
 
            f.close()
 
674
        self.log(tmpf.getvalue())
 
675
 
 
676
        self.log('merge plan:')
 
677
        p = list(w.plan_merge(1, 2))
 
678
        for state, line in p:
 
679
            if line:
 
680
                self.log('%12s | %s' % (state, line[:-1]))
 
681
 
 
682
        self.log('merge:')
 
683
        mt = StringIO()
 
684
        mt.writelines(w.weave_merge(p))
 
685
        mt.seek(0)
 
686
        self.log(mt.getvalue())
 
687
 
 
688
        mp = map(addcrlf, mp)
 
689
        self.assertEqual(mt.readlines(), mp)
 
690
        
 
691
        
 
692
    def testOneInsert(self):
 
693
        self.doMerge([],
 
694
                     ['aa'],
 
695
                     [],
 
696
                     ['aa'])
 
697
 
 
698
    def testSeparateInserts(self):
 
699
        self.doMerge(['aaa', 'bbb', 'ccc'],
 
700
                     ['aaa', 'xxx', 'bbb', 'ccc'],
 
701
                     ['aaa', 'bbb', 'yyy', 'ccc'],
 
702
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
 
703
 
 
704
    def testSameInsert(self):
 
705
        self.doMerge(['aaa', 'bbb', 'ccc'],
 
706
                     ['aaa', 'xxx', 'bbb', 'ccc'],
 
707
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'],
 
708
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
 
709
 
 
710
    def testOverlappedInsert(self):
 
711
        self.doMerge(['aaa', 'bbb'],
 
712
                     ['aaa', 'xxx', 'yyy', 'bbb'],
 
713
                     ['aaa', 'xxx', 'bbb'],
 
714
                     ['aaa', '<<<<', 'xxx', 'yyy', '====', 'xxx', '>>>>', 'bbb'])
 
715
 
 
716
        # really it ought to reduce this to 
 
717
        # ['aaa', 'xxx', 'yyy', 'bbb']
 
718
 
 
719
 
 
720
    def testClashReplace(self):
 
721
        self.doMerge(['aaa'],
 
722
                     ['xxx'],
 
723
                     ['yyy', 'zzz'],
 
724
                     ['<<<<', 'xxx', '====', 'yyy', 'zzz', '>>>>'])
 
725
 
 
726
    def testNonClashInsert(self):
 
727
        self.doMerge(['aaa'],
 
728
                     ['xxx', 'aaa'],
 
729
                     ['yyy', 'zzz'],
 
730
                     ['<<<<', 'xxx', 'aaa', '====', 'yyy', 'zzz', '>>>>'])
 
731
 
 
732
        self.doMerge(['aaa'],
 
733
                     ['aaa'],
 
734
                     ['yyy', 'zzz'],
 
735
                     ['yyy', 'zzz'])
 
736
    
 
737
 
 
738
 
 
739
def testweave():
 
740
    import testsweet
 
741
    from unittest import TestSuite, TestLoader
 
742
    import testweave
 
743
 
 
744
    tl = TestLoader()
 
745
    suite = TestSuite()
 
746
    suite.addTest(tl.loadTestsFromModule(testweave))
 
747
    
 
748
    return int(not testsweet.run_suite(suite)) # for shell 0=true
 
749
 
 
750
 
 
751
if __name__ == '__main__':
 
752
    import sys
 
753
    sys.exit(testweave())
 
754