~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to tools/testweave.py

  • Committer: Martin Pool
  • Date: 2005-07-22 22:37:53 UTC
  • Revision ID: mbp@sourcefrog.net-20050722223753-7dced4e32d3ce21d
- add the start of a test for inventory file-id matching

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
29
 
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
 
30
 
 
31
try:
 
32
    set
 
33
    frozenset
 
34
except NameError:
 
35
    from sets import Set, ImmutableSet
 
36
    set = Set
 
37
    frozenset = ImmutableSet
 
38
    del Set, ImmutableSet
 
39
 
33
40
 
34
41
 
35
42
# texts for use in testing
38
45
          "A second line"]
39
46
 
40
47
 
41
 
class TestBase(TestCase):
42
48
 
 
49
class TestBase(testsweet.TestBase):
43
50
    def check_read_write(self, k):
44
51
        """Check the weave k can be written & re-read."""
45
52
        from tempfile import TemporaryFile
53
60
            tf.seek(0)
54
61
            self.log('serialized weave:')
55
62
            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
63
            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)
 
64
        
 
65
        
72
66
 
73
67
 
74
68
class Easy(TestBase):
76
70
        k = Weave()
77
71
 
78
72
 
 
73
class StoreText(TestBase):
 
74
    """Store and retrieve a simple text."""
 
75
    def runTest(self):
 
76
        k = Weave()
 
77
        idx = k.add([], TEXT_0)
 
78
        self.assertEqual(k.get(idx), TEXT_0)
 
79
        self.assertEqual(idx, 0)
 
80
 
 
81
 
 
82
 
79
83
class AnnotateOne(TestBase):
80
84
    def runTest(self):
81
85
        k = Weave()
82
 
        k.add_lines('text0', [], TEXT_0)
83
 
        self.assertEqual(k.annotate('text0'),
84
 
                         [('text0', TEXT_0[0])])
 
86
        k.add([], TEXT_0)
 
87
        self.assertEqual(k.annotate(0),
 
88
                         [(0, TEXT_0[0])])
 
89
 
 
90
 
 
91
class StoreTwo(TestBase):
 
92
    def runTest(self):
 
93
        k = Weave()
 
94
 
 
95
        idx = k.add([], TEXT_0)
 
96
        self.assertEqual(idx, 0)
 
97
 
 
98
        idx = k.add([], TEXT_1)
 
99
        self.assertEqual(idx, 1)
 
100
 
 
101
        self.assertEqual(k.get(0), TEXT_0)
 
102
        self.assertEqual(k.get(1), TEXT_1)
 
103
 
 
104
        k.dump(self.TEST_LOG)
 
105
 
85
106
 
86
107
 
87
108
class InvalidAdd(TestBase):
89
110
    def runTest(self):
90
111
        k = Weave()
91
112
 
92
 
        self.assertRaises(errors.RevisionNotPresent,
93
 
                          k.add_lines,
94
 
                          'text0',
95
 
                          ['69'],
 
113
        self.assertRaises(IndexError,
 
114
                          k.add,
 
115
                          [69],
96
116
                          ['new text!'])
97
117
 
98
118
 
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
119
class InsertLines(TestBase):
127
120
    """Store a revision that adds one line to the original.
128
121
 
131
124
    def runTest(self):
132
125
        k = Weave()
133
126
 
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),
 
127
        k.add([], ['line 1'])
 
128
        k.add([0], ['line 1', 'line 2'])
 
129
 
 
130
        self.assertEqual(k.annotate(0),
 
131
                         [(0, 'line 1')])
 
132
 
 
133
        self.assertEqual(k.get(1),
141
134
                         ['line 1',
142
135
                          'line 2'])
143
136
 
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')])
 
137
        self.assertEqual(k.annotate(1),
 
138
                         [(0, 'line 1'),
 
139
                          (1, 'line 2')])
 
140
 
 
141
        k.add([0], ['line 1', 'diverged line'])
 
142
 
 
143
        self.assertEqual(k.annotate(2),
 
144
                         [(0, 'line 1'),
 
145
                          (2, 'diverged line')])
153
146
 
154
147
        text3 = ['line 1', 'middle line', 'line 2']
155
 
        k.add_lines('text3',
156
 
              ['text0', 'text1'],
 
148
        k.add([0, 1],
157
149
              text3)
158
150
 
159
151
        # self.log("changes to text3: " + pformat(list(k._delta(set([0, 1]), text3))))
160
152
 
161
153
        self.log("k._weave=" + pformat(k._weave))
162
154
 
163
 
        self.assertEqual(k.annotate('text3'),
164
 
                         [('text0', 'line 1'),
165
 
                          ('text3', 'middle line'),
166
 
                          ('text1', 'line 2')])
 
155
        self.assertEqual(k.annotate(3),
 
156
                         [(0, 'line 1'),
 
157
                          (3, 'middle line'),
 
158
                          (1, 'line 2')])
167
159
 
168
160
        # now multiple insertions at different places
169
 
        k.add_lines('text4',
170
 
              ['text0', 'text1', 'text3'],
 
161
        k.add([0, 1, 3],
171
162
              ['line 1', 'aaa', 'middle line', 'bbb', 'line 2', 'ccc'])
172
163
 
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')])
 
164
        self.assertEqual(k.annotate(4), 
 
165
                         [(0, 'line 1'),
 
166
                          (4, 'aaa'),
 
167
                          (3, 'middle line'),
 
168
                          (4, 'bbb'),
 
169
                          (1, 'line 2'),
 
170
                          (4, 'ccc')])
 
171
 
180
172
 
181
173
 
182
174
class DeleteLines(TestBase):
188
180
 
189
181
        base_text = ['one', 'two', 'three', 'four']
190
182
 
191
 
        k.add_lines('text0', [], base_text)
192
 
 
 
183
        k.add([], base_text)
 
184
        
193
185
        texts = [['one', 'two', 'three'],
194
186
                 ['two', 'three', 'four'],
195
187
                 ['one', 'four'],
196
188
                 ['one', 'two', 'three', 'four'],
197
189
                 ]
198
190
 
199
 
        i = 1
200
191
        for t in texts:
201
 
            ver = k.add_lines('text%d' % i,
202
 
                        ['text0'], t)
203
 
            i += 1
 
192
            ver = k.add([0], t)
204
193
 
205
194
        self.log('final weave:')
206
195
        self.log('k._weave=' + pformat(k._weave))
207
196
 
208
197
        for i in range(len(texts)):
209
 
            self.assertEqual(k.get_lines(i+1),
 
198
            self.assertEqual(k.get(i+1),
210
199
                             texts[i])
 
200
            
 
201
 
211
202
 
212
203
 
213
204
class SuicideDelete(TestBase):
226
217
                ]
227
218
        ################################### SKIPPED
228
219
        # Weave.get doesn't trap this anymore
229
 
        return
 
220
        return 
230
221
 
231
222
        self.assertRaises(WeaveFormatError,
232
 
                          k.get_lines,
233
 
                          0)
 
223
                          k.get,
 
224
                          0)        
 
225
 
234
226
 
235
227
 
236
228
class CannedDelete(TestBase):
249
241
                'last line',
250
242
                ('}', 0),
251
243
                ]
252
 
        k._sha1s = [sha_string('first lineline to be deletedlast line')
253
 
                  , sha_string('first linelast line')]
254
244
 
255
 
        self.assertEqual(k.get_lines(0),
 
245
        self.assertEqual(k.get(0),
256
246
                         ['first line',
257
247
                          'line to be deleted',
258
248
                          'last line',
259
249
                          ])
260
250
 
261
 
        self.assertEqual(k.get_lines(1),
 
251
        self.assertEqual(k.get(1),
262
252
                         ['first line',
263
253
                          'last line',
264
254
                          ])
265
255
 
266
256
 
 
257
 
267
258
class CannedReplacement(TestBase):
268
259
    """Unpack canned weave with deleted lines."""
269
260
    def runTest(self):
278
269
                'line to be deleted',
279
270
                (']', 1),
280
271
                ('{', 1),
281
 
                'replacement line',
 
272
                'replacement line',                
282
273
                ('}', 1),
283
274
                'last line',
284
275
                ('}', 0),
285
276
                ]
286
 
        k._sha1s = [sha_string('first lineline to be deletedlast line')
287
 
                  , sha_string('first linereplacement linelast line')]
288
277
 
289
 
        self.assertEqual(k.get_lines(0),
 
278
        self.assertEqual(k.get(0),
290
279
                         ['first line',
291
280
                          'line to be deleted',
292
281
                          'last line',
293
282
                          ])
294
283
 
295
 
        self.assertEqual(k.get_lines(1),
 
284
        self.assertEqual(k.get(1),
296
285
                         ['first line',
297
286
                          'replacement line',
298
287
                          'last line',
299
288
                          ])
300
289
 
301
290
 
 
291
 
302
292
class BadWeave(TestBase):
303
293
    """Test that we trap an insert which should not occur."""
304
294
    def runTest(self):
321
311
 
322
312
        ################################### SKIPPED
323
313
        # Weave.get doesn't trap this anymore
324
 
        return
 
314
        return 
325
315
 
326
316
 
327
317
        self.assertRaises(WeaveFormatError,
384
374
                '}',
385
375
                ('}', 0)]
386
376
 
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
 
                          '}'])
 
377
        self.assertEqual(k.get(0),
 
378
                         ['foo {',
 
379
                          '}'])
 
380
 
 
381
        self.assertEqual(k.get(1),
 
382
                         ['foo {',
 
383
                          '  added in version 1',
 
384
                          '  also from v1',
 
385
                          '}'])
 
386
                       
 
387
        self.assertEqual(k.get(2),
 
388
                         ['foo {',
 
389
                          '  added in v2',
 
390
                          '}'])
 
391
 
 
392
        self.assertEqual(k.get(3),
 
393
                         ['foo {',
 
394
                          '  added in version 1',
 
395
                          '  added in v2',
 
396
                          '  also from v1',
 
397
                          '}'])
 
398
                         
414
399
 
415
400
 
416
401
class DeleteLines2(TestBase):
421
406
    def runTest(self):
422
407
        k = Weave()
423
408
 
424
 
        k.add_lines('text0', [], ["line the first",
 
409
        k.add([], ["line the first",
425
410
                   "line 2",
426
411
                   "line 3",
427
412
                   "fine"])
428
413
 
429
 
        self.assertEqual(len(k.get_lines(0)), 4)
 
414
        self.assertEqual(len(k.get(0)), 4)
430
415
 
431
 
        k.add_lines('text1', ['text0'], ["line the first",
 
416
        k.add([0], ["line the first",
432
417
                   "fine"])
433
418
 
434
 
        self.assertEqual(k.get_lines(1),
 
419
        self.assertEqual(k.get(1),
435
420
                         ["line the first",
436
421
                          "fine"])
437
422
 
438
 
        self.assertEqual(k.annotate('text1'),
439
 
                         [('text0', "line the first"),
440
 
                          ('text0', "fine")])
 
423
        self.assertEqual(k.annotate(1),
 
424
                         [(0, "line the first"),
 
425
                          (0, "fine")])
 
426
 
441
427
 
442
428
 
443
429
class IncludeVersions(TestBase):
461
447
                "second line",
462
448
                ('}', 1)]
463
449
 
464
 
        k._sha1s = [sha_string('first line')
465
 
                  , sha_string('first linesecond line')]
466
 
 
467
 
        self.assertEqual(k.get_lines(1),
 
450
        self.assertEqual(k.get(1),
468
451
                         ["first line",
469
452
                          "second line"])
470
453
 
471
 
        self.assertEqual(k.get_lines(0),
 
454
        self.assertEqual(k.get(0),
472
455
                         ["first line"])
473
456
 
 
457
        k.dump(self.TEST_LOG)
 
458
 
474
459
 
475
460
class DivergedIncludes(TestBase):
476
461
    """Weave with two diverged texts based on version 0.
477
462
    """
478
463
    def runTest(self):
479
 
        # FIXME make the weave, dont poke at it.
480
464
        k = Weave()
481
465
 
482
 
        k._names = ['0', '1', '2']
483
 
        k._name_map = {'0':0, '1':1, '2':2}
484
466
        k._parents = [frozenset(),
485
467
                frozenset([0]),
486
468
                frozenset([0]),
493
475
                ('}', 1),
494
476
                ('{', 2),
495
477
                "alternative second line",
496
 
                ('}', 2),
 
478
                ('}', 2),                
497
479
                ]
498
480
 
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),
 
481
        self.assertEqual(k.get(0),
504
482
                         ["first line"])
505
483
 
506
 
        self.assertEqual(k.get_lines(1),
 
484
        self.assertEqual(k.get(1),
507
485
                         ["first line",
508
486
                          "second line"])
509
487
 
510
 
        self.assertEqual(k.get_lines('2'),
 
488
        self.assertEqual(k.get(2),
511
489
                         ["first line",
512
490
                          "alternative second line"])
513
491
 
514
 
        self.assertEqual(list(k.get_ancestry(['2'])),
515
 
                         ['0', '2'])
 
492
        self.assertEqual(list(k.inclusions([2])),
 
493
                         [0, 2])
 
494
 
516
495
 
517
496
 
518
497
class ReplaceLine(TestBase):
521
500
 
522
501
        text0 = ['cheddar', 'stilton', 'gruyere']
523
502
        text1 = ['cheddar', 'blue vein', 'neufchatel', 'chevre']
524
 
 
525
 
        k.add_lines('text0', [], text0)
526
 
        k.add_lines('text1', ['text0'], text1)
 
503
        
 
504
        k.add([], text0)
 
505
        k.add([0], text1)
527
506
 
528
507
        self.log('k._weave=' + pformat(k._weave))
529
508
 
530
 
        self.assertEqual(k.get_lines(0), text0)
531
 
        self.assertEqual(k.get_lines(1), text1)
 
509
        self.assertEqual(k.get(0), text0)
 
510
        self.assertEqual(k.get(1), text1)
 
511
 
532
512
 
533
513
 
534
514
class Merge(TestBase):
542
522
                 ['header', '', 'line from 1', 'fixup line', 'line from 2'],
543
523
                 ]
544
524
 
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])
 
525
        k.add([], texts[0])
 
526
        k.add([0], texts[1])
 
527
        k.add([0], texts[2])
 
528
        k.add([0, 1, 2], texts[3])
549
529
 
550
530
        for i, t in enumerate(texts):
551
 
            self.assertEqual(k.get_lines(i), t)
 
531
            self.assertEqual(k.get(i), t)
552
532
 
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'),
 
533
        self.assertEqual(k.annotate(3),
 
534
                         [(0, 'header'),
 
535
                          (1, ''),
 
536
                          (1, 'line from 1'),
 
537
                          (3, 'fixup line'),
 
538
                          (2, 'line from 2'),
559
539
                          ])
560
540
 
561
 
        self.assertEqual(list(k.get_ancestry(['merge'])),
562
 
                         ['text0', 'text1', 'text2', 'merge'])
 
541
        self.assertEqual(list(k.inclusions([3])),
 
542
                         [0, 1, 2, 3])
563
543
 
564
544
        self.log('k._weave=' + pformat(k._weave))
565
545
 
576
556
        return  # NOT RUN
577
557
        k = Weave()
578
558
 
579
 
        k.add_lines([], ['aaa', 'bbb'])
580
 
        k.add_lines([0], ['aaa', '111', 'bbb'])
581
 
        k.add_lines([1], ['aaa', '222', 'bbb'])
 
559
        k.add([], ['aaa', 'bbb'])
 
560
        k.add([0], ['aaa', '111', 'bbb'])
 
561
        k.add([1], ['aaa', '222', 'bbb'])
582
562
 
583
563
        merged = k.merge([1, 2])
584
564
 
587
567
                           [['bbb']]])
588
568
 
589
569
 
 
570
 
590
571
class NonConflict(TestBase):
591
572
    """Two descendants insert compatible changes.
592
573
 
595
576
        return  # NOT RUN
596
577
        k = Weave()
597
578
 
598
 
        k.add_lines([], ['aaa', 'bbb'])
599
 
        k.add_lines([0], ['111', 'aaa', 'ccc', 'bbb'])
600
 
        k.add_lines([1], ['aaa', 'ccc', 'bbb', '222'])
 
579
        k.add([], ['aaa', 'bbb'])
 
580
        k.add([0], ['111', 'aaa', 'ccc', 'bbb'])
 
581
        k.add([1], ['aaa', 'ccc', 'bbb', '222'])
 
582
 
 
583
    
 
584
    
 
585
 
 
586
 
 
587
class AutoMerge(TestBase):
 
588
    def runTest(self):
 
589
        k = Weave()
 
590
 
 
591
        texts = [['header', 'aaa', 'bbb'],
 
592
                 ['header', 'aaa', 'line from 1', 'bbb'],
 
593
                 ['header', 'aaa', 'bbb', 'line from 2', 'more from 2'],
 
594
                 ]
 
595
 
 
596
        k.add([], texts[0])
 
597
        k.add([0], texts[1])
 
598
        k.add([0], texts[2])
 
599
 
 
600
        self.log('k._weave=' + pformat(k._weave))
 
601
 
 
602
        m = list(k.mash_iter([0, 1, 2]))
 
603
 
 
604
        self.assertEqual(m,
 
605
                         ['header', 'aaa',
 
606
                          'line from 1',
 
607
                          'bbb',
 
608
                          'line from 2', 'more from 2'])
 
609
        
601
610
 
602
611
 
603
612
class Khayyam(TestBase):
604
613
    """Test changes to multi-line texts, and read/write"""
605
 
 
606
 
    def test_multi_line_merge(self):
 
614
    def runTest(self):
607
615
        rawtexts = [
608
616
            """A Book of Verses underneath the Bough,
609
617
            A Jug of Wine, a Loaf of Bread, -- and Thou
610
618
            Beside me singing in the Wilderness --
611
619
            Oh, Wilderness were Paradise enow!""",
612
 
 
 
620
            
613
621
            """A Book of Verses underneath the Bough,
614
622
            A Jug of Wine, a Loaf of Bread, -- and Thou
615
623
            Beside me singing in the Wilderness --
633
641
 
634
642
        k = Weave()
635
643
        parents = set()
636
 
        i = 0
637
644
        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
 
645
            ver = k.add(list(parents), t)
 
646
            parents.add(ver)
642
647
 
643
648
        self.log("k._weave=" + pformat(k._weave))
644
649
 
645
650
        for i, t in enumerate(texts):
646
 
            self.assertEqual(k.get_lines(i), t)
 
651
            self.assertEqual(k.get(i), t)
647
652
 
648
653
        self.check_read_write(k)
649
654
 
650
655
 
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
656
 
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.
 
657
class MergeCases(TestBase):
 
658
    def doMerge(self, base, a, b, mp):
667
659
        from cStringIO import StringIO
 
660
        from textwrap import dedent
668
661
 
 
662
        def addcrlf(x):
 
663
            return x + '\n'
 
664
        
669
665
        w = Weave()
670
 
        w.add_lines('v1', [], ['hello\n'])
671
 
        w.add_lines('v2', ['v1'], ['hello\n', 'there\n'])
 
666
        w.add([], map(addcrlf, base))
 
667
        w.add([0], map(addcrlf, a))
 
668
        w.add([0], map(addcrlf, b))
672
669
 
 
670
        self.log('weave is:')
673
671
        tmpf = StringIO()
674
672
        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()
 
673
        self.log(tmpf.getvalue())
 
674
 
 
675
        self.log('merge plan:')
 
676
        p = list(w.plan_merge(1, 2))
 
677
        for state, line in p:
 
678
            if line:
 
679
                self.log('%12s | %s' % (state, line[:-1]))
 
680
 
 
681
        self.log('merge:')
 
682
        mt = StringIO()
 
683
        mt.writelines(w.weave_merge(p))
 
684
        mt.seek(0)
 
685
        self.log(mt.getvalue())
 
686
 
 
687
        mp = map(addcrlf, mp)
 
688
        self.assertEqual(mt.readlines(), mp)
 
689
        
 
690
        
 
691
    def testOneInsert(self):
 
692
        self.doMerge([],
 
693
                     ['aa'],
 
694
                     [],
 
695
                     ['aa'])
 
696
 
 
697
    def testSeparateInserts(self):
 
698
        self.doMerge(['aaa', 'bbb', 'ccc'],
 
699
                     ['aaa', 'xxx', 'bbb', 'ccc'],
 
700
                     ['aaa', 'bbb', 'yyy', 'ccc'],
 
701
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
 
702
 
 
703
    def testSameInsert(self):
 
704
        self.doMerge(['aaa', 'bbb', 'ccc'],
 
705
                     ['aaa', 'xxx', 'bbb', 'ccc'],
 
706
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'],
 
707
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
 
708
 
 
709
    def testOverlappedInsert(self):
 
710
        self.doMerge(['aaa', 'bbb'],
 
711
                     ['aaa', 'xxx', 'yyy', 'bbb'],
 
712
                     ['aaa', 'xxx', 'bbb'],
 
713
                     ['aaa', '<<<<', 'xxx', 'yyy', '====', 'xxx', '>>>>', 'bbb'])
 
714
 
 
715
        # really it ought to reduce this to 
 
716
        # ['aaa', 'xxx', 'yyy', 'bbb']
 
717
 
 
718
 
 
719
    def testClashReplace(self):
 
720
        self.doMerge(['aaa'],
 
721
                     ['xxx'],
 
722
                     ['yyy', 'zzz'],
 
723
                     ['<<<<', 'xxx', '====', 'yyy', 'zzz', '>>>>'])
 
724
 
 
725
    def testNonClashInsert(self):
 
726
        self.doMerge(['aaa'],
 
727
                     ['xxx', 'aaa'],
 
728
                     ['yyy', 'zzz'],
 
729
                     ['<<<<', 'xxx', 'aaa', '====', 'yyy', 'zzz', '>>>>'])
 
730
 
 
731
        self.doMerge(['aaa'],
 
732
                     ['aaa'],
 
733
                     ['yyy', 'zzz'],
 
734
                     ['yyy', 'zzz'])
 
735
 
 
736
 
 
737
    def testDeleteAndModify(self):
 
738
        """Clashing delete and modification.
 
739
 
 
740
        If one side modifies a region and the other deletes it then
 
741
        there should be a conflict with one side blank.
 
742
        """
 
743
 
 
744
        #######################################
 
745
        # skippd, not working yet
 
746
        return
 
747
        
 
748
        self.doMerge(['aaa', 'bbb', 'ccc'],
 
749
                     ['aaa', 'ddd', 'ccc'],
 
750
                     ['aaa', 'ccc'],
 
751
                     ['<<<<', 'aaa', '====', '>>>>', 'ccc'])
 
752
    
 
753
 
 
754
 
 
755
def testweave():
 
756
    import testsweet
 
757
    from unittest import TestSuite, TestLoader
 
758
    import testweave
 
759
 
 
760
    tl = TestLoader()
 
761
    suite = TestSuite()
 
762
    suite.addTest(tl.loadTestsFromModule(testweave))
 
763
    
 
764
    return int(not testsweet.run_suite(suite)) # for shell 0=true
 
765
 
 
766
 
 
767
if __name__ == '__main__':
 
768
    import sys
 
769
    sys.exit(testweave())
 
770