~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to tools/testweave.py

  • Committer: Martin Pool
  • Date: 2005-08-24 08:59:32 UTC
  • Revision ID: mbp@sourcefrog.net-20050824085932-c61f1f1f1c930e13
- Add a simple UIFactory 

  The idea of this is to let a client of bzrlib set some 
  policy about how output is displayed.

  In this revision all that's done is that progress bars
  are constructed by a policy established by the application
  rather than being randomly constructed in the library 
  or passed down the calls.  This avoids progress bars
  popping up while running the test suite and cleans up
  some code.

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
 
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
18
 
17
19
 
18
20
# TODO: tests regarding version names
19
 
# TODO: rbc 20050108 test that join does not leave an inconsistent weave
20
 
#       if it fails.
 
21
 
 
22
 
21
23
 
22
24
"""test suite for weave algorithm"""
23
25
 
 
26
 
 
27
import testsweet
 
28
from bzrlib.weave import Weave, WeaveFormatError
 
29
from bzrlib.weavefile import write_weave, read_weave
24
30
from pprint import pformat
25
31
 
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
 
32
 
 
33
try:
 
34
    set
 
35
    frozenset
 
36
except NameError:
 
37
    from sets import Set, ImmutableSet
 
38
    set = Set
 
39
    frozenset = ImmutableSet
 
40
    del Set, ImmutableSet
 
41
 
33
42
 
34
43
 
35
44
# texts for use in testing
38
47
          "A second line"]
39
48
 
40
49
 
41
 
class TestBase(TestCase):
42
50
 
 
51
class TestBase(testsweet.TestBase):
43
52
    def check_read_write(self, k):
44
53
        """Check the weave k can be written & re-read."""
45
54
        from tempfile import TemporaryFile
59
68
            self.log('         %r' % k._parents)
60
69
            self.log('         %r' % k2._parents)
61
70
            self.log('')
 
71
 
 
72
            
62
73
            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)
 
74
        
 
75
        
72
76
 
73
77
 
74
78
class Easy(TestBase):
76
80
        k = Weave()
77
81
 
78
82
 
 
83
class StoreText(TestBase):
 
84
    """Store and retrieve a simple text."""
 
85
    def runTest(self):
 
86
        k = Weave()
 
87
        idx = k.add('text0', [], TEXT_0)
 
88
        self.assertEqual(k.get(idx), TEXT_0)
 
89
        self.assertEqual(idx, 0)
 
90
 
 
91
 
 
92
 
79
93
class AnnotateOne(TestBase):
80
94
    def runTest(self):
81
95
        k = Weave()
82
 
        k.add_lines('text0', [], TEXT_0)
83
 
        self.assertEqual(k.annotate('text0'),
84
 
                         [('text0', TEXT_0[0])])
 
96
        k.add('text0', [], TEXT_0)
 
97
        self.assertEqual(k.annotate(0),
 
98
                         [(0, TEXT_0[0])])
 
99
 
 
100
 
 
101
class StoreTwo(TestBase):
 
102
    def runTest(self):
 
103
        k = Weave()
 
104
 
 
105
        idx = k.add('text0', [], TEXT_0)
 
106
        self.assertEqual(idx, 0)
 
107
 
 
108
        idx = k.add('text1', [], TEXT_1)
 
109
        self.assertEqual(idx, 1)
 
110
 
 
111
        self.assertEqual(k.get(0), TEXT_0)
 
112
        self.assertEqual(k.get(1), TEXT_1)
 
113
 
 
114
        k.dump(self.TEST_LOG)
 
115
 
85
116
 
86
117
 
87
118
class InvalidAdd(TestBase):
89
120
    def runTest(self):
90
121
        k = Weave()
91
122
 
92
 
        self.assertRaises(errors.RevisionNotPresent,
93
 
                          k.add_lines,
 
123
        self.assertRaises(IndexError,
 
124
                          k.add,
94
125
                          'text0',
95
 
                          ['69'],
 
126
                          [69],
96
127
                          ['new text!'])
97
128
 
98
129
 
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
130
class InsertLines(TestBase):
127
131
    """Store a revision that adds one line to the original.
128
132
 
131
135
    def runTest(self):
132
136
        k = Weave()
133
137
 
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),
 
138
        k.add('text0', [], ['line 1'])
 
139
        k.add('text1', [0], ['line 1', 'line 2'])
 
140
 
 
141
        self.assertEqual(k.annotate(0),
 
142
                         [(0, 'line 1')])
 
143
 
 
144
        self.assertEqual(k.get(1),
141
145
                         ['line 1',
142
146
                          'line 2'])
143
147
 
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')])
 
148
        self.assertEqual(k.annotate(1),
 
149
                         [(0, 'line 1'),
 
150
                          (1, 'line 2')])
 
151
 
 
152
        k.add('text2', [0], ['line 1', 'diverged line'])
 
153
 
 
154
        self.assertEqual(k.annotate(2),
 
155
                         [(0, 'line 1'),
 
156
                          (2, 'diverged line')])
153
157
 
154
158
        text3 = ['line 1', 'middle line', 'line 2']
155
 
        k.add_lines('text3',
156
 
              ['text0', 'text1'],
 
159
        k.add('text3',
 
160
              [0, 1],
157
161
              text3)
158
162
 
159
163
        # self.log("changes to text3: " + pformat(list(k._delta(set([0, 1]), text3))))
160
164
 
161
165
        self.log("k._weave=" + pformat(k._weave))
162
166
 
163
 
        self.assertEqual(k.annotate('text3'),
164
 
                         [('text0', 'line 1'),
165
 
                          ('text3', 'middle line'),
166
 
                          ('text1', 'line 2')])
 
167
        self.assertEqual(k.annotate(3),
 
168
                         [(0, 'line 1'),
 
169
                          (3, 'middle line'),
 
170
                          (1, 'line 2')])
167
171
 
168
172
        # now multiple insertions at different places
169
 
        k.add_lines('text4',
170
 
              ['text0', 'text1', 'text3'],
 
173
        k.add('text4',
 
174
              [0, 1, 3],
171
175
              ['line 1', 'aaa', 'middle line', 'bbb', 'line 2', 'ccc'])
172
176
 
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')])
 
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')])
 
184
 
180
185
 
181
186
 
182
187
class DeleteLines(TestBase):
188
193
 
189
194
        base_text = ['one', 'two', 'three', 'four']
190
195
 
191
 
        k.add_lines('text0', [], base_text)
192
 
 
 
196
        k.add('text0', [], base_text)
 
197
        
193
198
        texts = [['one', 'two', 'three'],
194
199
                 ['two', 'three', 'four'],
195
200
                 ['one', 'four'],
198
203
 
199
204
        i = 1
200
205
        for t in texts:
201
 
            ver = k.add_lines('text%d' % i,
202
 
                        ['text0'], t)
 
206
            ver = k.add('text%d' % i,
 
207
                        [0], t)
203
208
            i += 1
204
209
 
205
210
        self.log('final weave:')
206
211
        self.log('k._weave=' + pformat(k._weave))
207
212
 
208
213
        for i in range(len(texts)):
209
 
            self.assertEqual(k.get_lines(i+1),
 
214
            self.assertEqual(k.get(i+1),
210
215
                             texts[i])
 
216
            
 
217
 
211
218
 
212
219
 
213
220
class SuicideDelete(TestBase):
226
233
                ]
227
234
        ################################### SKIPPED
228
235
        # Weave.get doesn't trap this anymore
229
 
        return
 
236
        return 
230
237
 
231
238
        self.assertRaises(WeaveFormatError,
232
 
                          k.get_lines,
233
 
                          0)
 
239
                          k.get,
 
240
                          0)        
 
241
 
234
242
 
235
243
 
236
244
class CannedDelete(TestBase):
249
257
                'last line',
250
258
                ('}', 0),
251
259
                ]
252
 
        k._sha1s = [sha_string('first lineline to be deletedlast line')
253
 
                  , sha_string('first linelast line')]
254
260
 
255
 
        self.assertEqual(k.get_lines(0),
 
261
        self.assertEqual(k.get(0),
256
262
                         ['first line',
257
263
                          'line to be deleted',
258
264
                          'last line',
259
265
                          ])
260
266
 
261
 
        self.assertEqual(k.get_lines(1),
 
267
        self.assertEqual(k.get(1),
262
268
                         ['first line',
263
269
                          'last line',
264
270
                          ])
265
271
 
266
272
 
 
273
 
267
274
class CannedReplacement(TestBase):
268
275
    """Unpack canned weave with deleted lines."""
269
276
    def runTest(self):
278
285
                'line to be deleted',
279
286
                (']', 1),
280
287
                ('{', 1),
281
 
                'replacement line',
 
288
                'replacement line',                
282
289
                ('}', 1),
283
290
                'last line',
284
291
                ('}', 0),
285
292
                ]
286
 
        k._sha1s = [sha_string('first lineline to be deletedlast line')
287
 
                  , sha_string('first linereplacement linelast line')]
288
293
 
289
 
        self.assertEqual(k.get_lines(0),
 
294
        self.assertEqual(k.get(0),
290
295
                         ['first line',
291
296
                          'line to be deleted',
292
297
                          'last line',
293
298
                          ])
294
299
 
295
 
        self.assertEqual(k.get_lines(1),
 
300
        self.assertEqual(k.get(1),
296
301
                         ['first line',
297
302
                          'replacement line',
298
303
                          'last line',
299
304
                          ])
300
305
 
301
306
 
 
307
 
302
308
class BadWeave(TestBase):
303
309
    """Test that we trap an insert which should not occur."""
304
310
    def runTest(self):
321
327
 
322
328
        ################################### SKIPPED
323
329
        # Weave.get doesn't trap this anymore
324
 
        return
 
330
        return 
325
331
 
326
332
 
327
333
        self.assertRaises(WeaveFormatError,
384
390
                '}',
385
391
                ('}', 0)]
386
392
 
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
 
                          '}'])
 
393
        self.assertEqual(k.get(0),
 
394
                         ['foo {',
 
395
                          '}'])
 
396
 
 
397
        self.assertEqual(k.get(1),
 
398
                         ['foo {',
 
399
                          '  added in version 1',
 
400
                          '  also from v1',
 
401
                          '}'])
 
402
                       
 
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
                         
414
415
 
415
416
 
416
417
class DeleteLines2(TestBase):
421
422
    def runTest(self):
422
423
        k = Weave()
423
424
 
424
 
        k.add_lines('text0', [], ["line the first",
 
425
        k.add('text0', [], ["line the first",
425
426
                   "line 2",
426
427
                   "line 3",
427
428
                   "fine"])
428
429
 
429
 
        self.assertEqual(len(k.get_lines(0)), 4)
 
430
        self.assertEqual(len(k.get(0)), 4)
430
431
 
431
 
        k.add_lines('text1', ['text0'], ["line the first",
 
432
        k.add('text1', [0], ["line the first",
432
433
                   "fine"])
433
434
 
434
 
        self.assertEqual(k.get_lines(1),
 
435
        self.assertEqual(k.get(1),
435
436
                         ["line the first",
436
437
                          "fine"])
437
438
 
438
 
        self.assertEqual(k.annotate('text1'),
439
 
                         [('text0', "line the first"),
440
 
                          ('text0', "fine")])
 
439
        self.assertEqual(k.annotate(1),
 
440
                         [(0, "line the first"),
 
441
                          (0, "fine")])
 
442
 
441
443
 
442
444
 
443
445
class IncludeVersions(TestBase):
461
463
                "second line",
462
464
                ('}', 1)]
463
465
 
464
 
        k._sha1s = [sha_string('first line')
465
 
                  , sha_string('first linesecond line')]
466
 
 
467
 
        self.assertEqual(k.get_lines(1),
 
466
        self.assertEqual(k.get(1),
468
467
                         ["first line",
469
468
                          "second line"])
470
469
 
471
 
        self.assertEqual(k.get_lines(0),
 
470
        self.assertEqual(k.get(0),
472
471
                         ["first line"])
473
472
 
 
473
        k.dump(self.TEST_LOG)
 
474
 
474
475
 
475
476
class DivergedIncludes(TestBase):
476
477
    """Weave with two diverged texts based on version 0.
477
478
    """
478
479
    def runTest(self):
479
 
        # FIXME make the weave, dont poke at it.
480
480
        k = Weave()
481
481
 
482
 
        k._names = ['0', '1', '2']
483
 
        k._name_map = {'0':0, '1':1, '2':2}
484
482
        k._parents = [frozenset(),
485
483
                frozenset([0]),
486
484
                frozenset([0]),
493
491
                ('}', 1),
494
492
                ('{', 2),
495
493
                "alternative second line",
496
 
                ('}', 2),
 
494
                ('}', 2),                
497
495
                ]
498
496
 
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),
 
497
        self.assertEqual(k.get(0),
504
498
                         ["first line"])
505
499
 
506
 
        self.assertEqual(k.get_lines(1),
 
500
        self.assertEqual(k.get(1),
507
501
                         ["first line",
508
502
                          "second line"])
509
503
 
510
 
        self.assertEqual(k.get_lines('2'),
 
504
        self.assertEqual(k.get(2),
511
505
                         ["first line",
512
506
                          "alternative second line"])
513
507
 
514
 
        self.assertEqual(list(k.get_ancestry(['2'])),
515
 
                         ['0', '2'])
 
508
        self.assertEqual(list(k.inclusions([2])),
 
509
                         [0, 2])
 
510
 
516
511
 
517
512
 
518
513
class ReplaceLine(TestBase):
521
516
 
522
517
        text0 = ['cheddar', 'stilton', 'gruyere']
523
518
        text1 = ['cheddar', 'blue vein', 'neufchatel', 'chevre']
524
 
 
525
 
        k.add_lines('text0', [], text0)
526
 
        k.add_lines('text1', ['text0'], text1)
 
519
        
 
520
        k.add('text0', [], text0)
 
521
        k.add('text1', [0], text1)
527
522
 
528
523
        self.log('k._weave=' + pformat(k._weave))
529
524
 
530
 
        self.assertEqual(k.get_lines(0), text0)
531
 
        self.assertEqual(k.get_lines(1), text1)
 
525
        self.assertEqual(k.get(0), text0)
 
526
        self.assertEqual(k.get(1), text1)
 
527
 
532
528
 
533
529
 
534
530
class Merge(TestBase):
542
538
                 ['header', '', 'line from 1', 'fixup line', 'line from 2'],
543
539
                 ]
544
540
 
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])
 
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])
549
545
 
550
546
        for i, t in enumerate(texts):
551
 
            self.assertEqual(k.get_lines(i), t)
 
547
            self.assertEqual(k.get(i), t)
552
548
 
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'),
 
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'),
559
555
                          ])
560
556
 
561
 
        self.assertEqual(list(k.get_ancestry(['merge'])),
562
 
                         ['text0', 'text1', 'text2', 'merge'])
 
557
        self.assertEqual(list(k.inclusions([3])),
 
558
                         [0, 1, 2, 3])
563
559
 
564
560
        self.log('k._weave=' + pformat(k._weave))
565
561
 
576
572
        return  # NOT RUN
577
573
        k = Weave()
578
574
 
579
 
        k.add_lines([], ['aaa', 'bbb'])
580
 
        k.add_lines([0], ['aaa', '111', 'bbb'])
581
 
        k.add_lines([1], ['aaa', '222', 'bbb'])
 
575
        k.add([], ['aaa', 'bbb'])
 
576
        k.add([0], ['aaa', '111', 'bbb'])
 
577
        k.add([1], ['aaa', '222', 'bbb'])
582
578
 
583
579
        merged = k.merge([1, 2])
584
580
 
587
583
                           [['bbb']]])
588
584
 
589
585
 
 
586
 
590
587
class NonConflict(TestBase):
591
588
    """Two descendants insert compatible changes.
592
589
 
595
592
        return  # NOT RUN
596
593
        k = Weave()
597
594
 
598
 
        k.add_lines([], ['aaa', 'bbb'])
599
 
        k.add_lines([0], ['111', 'aaa', 'ccc', 'bbb'])
600
 
        k.add_lines([1], ['aaa', 'ccc', 'bbb', '222'])
 
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
 
 
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
 
 
612
        k.add('text0', [], texts[0])
 
613
        k.add('text1', [0], texts[1])
 
614
        k.add('text2', [0], texts[2])
 
615
 
 
616
        self.log('k._weave=' + pformat(k._weave))
 
617
 
 
618
        m = list(k.mash_iter([0, 1, 2]))
 
619
 
 
620
        self.assertEqual(m,
 
621
                         ['header', 'aaa',
 
622
                          'line from 1',
 
623
                          'bbb',
 
624
                          'line from 2', 'more from 2'])
 
625
        
601
626
 
602
627
 
603
628
class Khayyam(TestBase):
604
629
    """Test changes to multi-line texts, and read/write"""
605
 
 
606
 
    def test_multi_line_merge(self):
 
630
    def runTest(self):
607
631
        rawtexts = [
608
632
            """A Book of Verses underneath the Bough,
609
633
            A Jug of Wine, a Loaf of Bread, -- and Thou
610
634
            Beside me singing in the Wilderness --
611
635
            Oh, Wilderness were Paradise enow!""",
612
 
 
 
636
            
613
637
            """A Book of Verses underneath the Bough,
614
638
            A Jug of Wine, a Loaf of Bread, -- and Thou
615
639
            Beside me singing in the Wilderness --
635
659
        parents = set()
636
660
        i = 0
637
661
        for t in texts:
638
 
            ver = k.add_lines('text%d' % i,
 
662
            ver = k.add('text%d' % i,
639
663
                        list(parents), t)
640
 
            parents.add('text%d' % i)
 
664
            parents.add(ver)
641
665
            i += 1
642
666
 
643
667
        self.log("k._weave=" + pformat(k._weave))
644
668
 
645
669
        for i, t in enumerate(texts):
646
 
            self.assertEqual(k.get_lines(i), t)
 
670
            self.assertEqual(k.get(i), t)
647
671
 
648
672
        self.check_read_write(k)
649
673
 
650
674
 
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
675
 
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.
 
676
class MergeCases(TestBase):
 
677
    def doMerge(self, base, a, b, mp):
667
678
        from cStringIO import StringIO
 
679
        from textwrap import dedent
668
680
 
 
681
        def addcrlf(x):
 
682
            return x + '\n'
 
683
        
669
684
        w = Weave()
670
 
        w.add_lines('v1', [], ['hello\n'])
671
 
        w.add_lines('v2', ['v1'], ['hello\n', 'there\n'])
 
685
        w.add('text0', [], map(addcrlf, base))
 
686
        w.add('text1', [0], map(addcrlf, a))
 
687
        w.add('text2', [0], map(addcrlf, b))
672
688
 
 
689
        self.log('weave is:')
673
690
        tmpf = StringIO()
674
691
        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()
 
692
        self.log(tmpf.getvalue())
 
693
 
 
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'])
 
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'])
 
771
    
 
772
 
 
773
 
 
774
def testweave():
 
775
    import testsweet
 
776
    from unittest import TestSuite, TestLoader
 
777
    import testweave
 
778
 
 
779
    tl = TestLoader()
 
780
    suite = TestSuite()
 
781
    suite.addTest(tl.loadTestsFromModule(testweave))
 
782
    
 
783
    return int(not testsweet.run_suite(suite)) # for shell 0=true
 
784
 
 
785
 
 
786
if __name__ == '__main__':
 
787
    import sys
 
788
    sys.exit(testweave())
 
789