~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_weave.py

  • Committer: Patch Queue Manager
  • Date: 2016-04-21 04:10:52 UTC
  • mfrom: (6616.1.1 fix-en-user-guide)
  • Revision ID: pqm@pqm.ubuntu.com-20160421041052-clcye7ns1qcl2n7w
(richard-wilbur) Ensure build of English use guide always uses English text
 even when user's locale specifies a different language. (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#! /usr/bin/python2.4
2
 
 
3
 
# Copyright (C) 2005 by Canonical Ltd
4
 
 
 
1
# Copyright (C) 2005-2011, 2016 Canonical Ltd
 
2
#
5
3
# This program is free software; you can redistribute it and/or modify
6
4
# it under the terms of the GNU General Public License as published by
7
5
# the Free Software Foundation; either version 2 of the License, or
8
6
# (at your option) any later version.
9
 
 
 
7
#
10
8
# This program is distributed in the hope that it will be useful,
11
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
11
# GNU General Public License for more details.
14
 
 
 
12
#
15
13
# You should have received a copy of the GNU General Public License
16
14
# along with this program; if not, write to the Free Software
17
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
16
 
19
17
 
20
18
# TODO: tests regarding version names
21
 
# TODO: rbc 20050108 test that join does not leave an inconsistent weave 
 
19
# TODO: rbc 20050108 test that join does not leave an inconsistent weave
22
20
#       if it fails.
23
21
 
24
22
"""test suite for weave algorithm"""
25
23
 
26
24
from pprint import pformat
27
25
 
28
 
import bzrlib.errors as errors
29
 
from bzrlib.weave import Weave, WeaveFormatError, WeaveError, reweave
 
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
30
32
from bzrlib.weavefile import write_weave, read_weave
31
 
from bzrlib.selftest import TestCase
32
 
from bzrlib.osutils import sha_string
33
33
 
34
34
 
35
35
# texts for use in testing
38
38
          "A second line"]
39
39
 
40
40
 
41
 
 
42
41
class TestBase(TestCase):
 
42
 
43
43
    def check_read_write(self, k):
44
44
        """Check the weave k can be written & re-read."""
45
45
        from tempfile import TemporaryFile
59
59
            self.log('         %r' % k._parents)
60
60
            self.log('         %r' % k2._parents)
61
61
            self.log('')
62
 
 
63
 
            
64
62
            self.fail('read/write check failed')
65
 
        
66
 
        
 
63
 
 
64
 
 
65
class WeaveContains(TestBase):
 
66
    """Weave __contains__ operator"""
 
67
 
 
68
    def runTest(self):
 
69
        k = Weave(get_scope=lambda:None)
 
70
        self.assertFalse('foo' in k)
 
71
        k.add_lines('foo', [], TEXT_1)
 
72
        self.assertTrue('foo' in k)
67
73
 
68
74
 
69
75
class Easy(TestBase):
70
 
    def runTest(self):
71
 
        k = Weave()
72
 
 
73
 
 
74
 
class StoreText(TestBase):
75
 
    """Store and retrieve a simple text."""
76
 
    def runTest(self):
77
 
        k = Weave()
78
 
        idx = k.add('text0', [], TEXT_0)
79
 
        self.assertEqual(k.get(idx), TEXT_0)
80
 
        self.assertEqual(idx, 0)
81
 
 
 
76
 
 
77
    def runTest(self):
 
78
        k = Weave()
82
79
 
83
80
 
84
81
class AnnotateOne(TestBase):
85
 
    def runTest(self):
86
 
        k = Weave()
87
 
        k.add('text0', [], 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('text0', [], TEXT_0)
97
 
        self.assertEqual(idx, 0)
98
 
 
99
 
        idx = k.add('text1', [], 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
 
 
106
 
 
107
 
class AddWithGivenSha(TestBase):
108
 
    def runTest(self):
109
 
        """Add with caller-supplied SHA-1"""
110
 
        k = Weave()
111
 
 
112
 
        t = 'text0'
113
 
        k.add('text0', [], [t], sha1=sha_string(t))
114
 
 
 
82
 
 
83
    def runTest(self):
 
84
        k = Weave()
 
85
        k.add_lines('text0', [], TEXT_0)
 
86
        self.assertEqual(k.annotate('text0'),
 
87
                         [('text0', TEXT_0[0])])
115
88
 
116
89
 
117
90
class InvalidAdd(TestBase):
118
91
    """Try to use invalid version number during add."""
 
92
 
119
93
    def runTest(self):
120
94
        k = Weave()
121
95
 
122
 
        self.assertRaises(IndexError,
123
 
                          k.add,
 
96
        self.assertRaises(errors.RevisionNotPresent,
 
97
                          k.add_lines,
124
98
                          'text0',
125
 
                          [69],
 
99
                          ['69'],
126
100
                          ['new text!'])
127
101
 
128
102
 
129
103
class RepeatedAdd(TestBase):
130
104
    """Add the same version twice; harmless."""
131
 
    def runTest(self):
 
105
 
 
106
    def test_duplicate_add(self):
132
107
        k = Weave()
133
 
        idx = k.add('text0', [], TEXT_0)
134
 
        idx2 = k.add('text0', [], TEXT_0)
 
108
        idx = k.add_lines('text0', [], TEXT_0)
 
109
        idx2 = k.add_lines('text0', [], TEXT_0)
135
110
        self.assertEqual(idx, idx2)
136
111
 
137
112
 
138
 
 
139
113
class InvalidRepeatedAdd(TestBase):
 
114
 
140
115
    def runTest(self):
141
116
        k = Weave()
142
 
        idx = k.add('text0', [], TEXT_0)
143
 
        self.assertRaises(WeaveError,
144
 
                          k.add,
 
117
        k.add_lines('basis', [], TEXT_0)
 
118
        idx = k.add_lines('text0', [], TEXT_0)
 
119
        self.assertRaises(errors.RevisionAlreadyPresent,
 
120
                          k.add_lines,
145
121
                          'text0',
146
122
                          [],
147
123
                          ['not the same text'])
148
 
        self.assertRaises(WeaveError,
149
 
                          k.add,
 
124
        self.assertRaises(errors.RevisionAlreadyPresent,
 
125
                          k.add_lines,
150
126
                          'text0',
151
 
                          [12],         # not the right parents
 
127
                          ['basis'],         # not the right parents
152
128
                          TEXT_0)
153
 
        
154
129
 
155
130
 
156
131
class InsertLines(TestBase):
161
136
    def runTest(self):
162
137
        k = Weave()
163
138
 
164
 
        k.add('text0', [], ['line 1'])
165
 
        k.add('text1', [0], ['line 1', 'line 2'])
166
 
 
167
 
        self.assertEqual(k.annotate(0),
168
 
                         [(0, 'line 1')])
169
 
 
170
 
        self.assertEqual(k.get(1),
 
139
        k.add_lines('text0', [], ['line 1'])
 
140
        k.add_lines('text1', ['text0'], ['line 1', 'line 2'])
 
141
 
 
142
        self.assertEqual(k.annotate('text0'),
 
143
                         [('text0', 'line 1')])
 
144
 
 
145
        self.assertEqual(k.get_lines(1),
171
146
                         ['line 1',
172
147
                          'line 2'])
173
148
 
174
 
        self.assertEqual(k.annotate(1),
175
 
                         [(0, 'line 1'),
176
 
                          (1, 'line 2')])
177
 
 
178
 
        k.add('text2', [0], ['line 1', 'diverged line'])
179
 
 
180
 
        self.assertEqual(k.annotate(2),
181
 
                         [(0, 'line 1'),
182
 
                          (2, 'diverged line')])
 
149
        self.assertEqual(k.annotate('text1'),
 
150
                         [('text0', 'line 1'),
 
151
                          ('text1', 'line 2')])
 
152
 
 
153
        k.add_lines('text2', ['text0'], ['line 1', 'diverged line'])
 
154
 
 
155
        self.assertEqual(k.annotate('text2'),
 
156
                         [('text0', 'line 1'),
 
157
                          ('text2', 'diverged line')])
183
158
 
184
159
        text3 = ['line 1', 'middle line', 'line 2']
185
 
        k.add('text3',
186
 
              [0, 1],
 
160
        k.add_lines('text3',
 
161
              ['text0', 'text1'],
187
162
              text3)
188
163
 
189
164
        # self.log("changes to text3: " + pformat(list(k._delta(set([0, 1]), text3))))
190
165
 
191
166
        self.log("k._weave=" + pformat(k._weave))
192
167
 
193
 
        self.assertEqual(k.annotate(3),
194
 
                         [(0, 'line 1'),
195
 
                          (3, 'middle line'),
196
 
                          (1, 'line 2')])
 
168
        self.assertEqual(k.annotate('text3'),
 
169
                         [('text0', 'line 1'),
 
170
                          ('text3', 'middle line'),
 
171
                          ('text1', 'line 2')])
197
172
 
198
173
        # now multiple insertions at different places
199
 
        k.add('text4',
200
 
              [0, 1, 3],
 
174
        k.add_lines('text4',
 
175
              ['text0', 'text1', 'text3'],
201
176
              ['line 1', 'aaa', 'middle line', 'bbb', 'line 2', 'ccc'])
202
177
 
203
 
        self.assertEqual(k.annotate(4), 
204
 
                         [(0, 'line 1'),
205
 
                          (4, 'aaa'),
206
 
                          (3, 'middle line'),
207
 
                          (4, 'bbb'),
208
 
                          (1, 'line 2'),
209
 
                          (4, 'ccc')])
210
 
 
 
178
        self.assertEqual(k.annotate('text4'),
 
179
                         [('text0', 'line 1'),
 
180
                          ('text4', 'aaa'),
 
181
                          ('text3', 'middle line'),
 
182
                          ('text4', 'bbb'),
 
183
                          ('text1', 'line 2'),
 
184
                          ('text4', 'ccc')])
211
185
 
212
186
 
213
187
class DeleteLines(TestBase):
219
193
 
220
194
        base_text = ['one', 'two', 'three', 'four']
221
195
 
222
 
        k.add('text0', [], base_text)
223
 
        
 
196
        k.add_lines('text0', [], base_text)
 
197
 
224
198
        texts = [['one', 'two', 'three'],
225
199
                 ['two', 'three', 'four'],
226
200
                 ['one', 'four'],
229
203
 
230
204
        i = 1
231
205
        for t in texts:
232
 
            ver = k.add('text%d' % i,
233
 
                        [0], t)
 
206
            ver = k.add_lines('text%d' % i,
 
207
                        ['text0'], t)
234
208
            i += 1
235
209
 
236
210
        self.log('final weave:')
237
211
        self.log('k._weave=' + pformat(k._weave))
238
212
 
239
213
        for i in range(len(texts)):
240
 
            self.assertEqual(k.get(i+1),
 
214
            self.assertEqual(k.get_lines(i+1),
241
215
                             texts[i])
242
 
            
243
 
 
244
216
 
245
217
 
246
218
class SuicideDelete(TestBase):
259
231
                ]
260
232
        ################################### SKIPPED
261
233
        # Weave.get doesn't trap this anymore
262
 
        return 
 
234
        return
263
235
 
264
236
        self.assertRaises(WeaveFormatError,
265
 
                          k.get,
266
 
                          0)        
267
 
 
 
237
                          k.get_lines,
 
238
                          0)
268
239
 
269
240
 
270
241
class CannedDelete(TestBase):
283
254
                'last line',
284
255
                ('}', 0),
285
256
                ]
 
257
        k._sha1s = [sha_string('first lineline to be deletedlast line')
 
258
                  , sha_string('first linelast line')]
286
259
 
287
 
        self.assertEqual(k.get(0),
 
260
        self.assertEqual(k.get_lines(0),
288
261
                         ['first line',
289
262
                          'line to be deleted',
290
263
                          'last line',
291
264
                          ])
292
265
 
293
 
        self.assertEqual(k.get(1),
 
266
        self.assertEqual(k.get_lines(1),
294
267
                         ['first line',
295
268
                          'last line',
296
269
                          ])
297
270
 
298
271
 
299
 
 
300
272
class CannedReplacement(TestBase):
301
273
    """Unpack canned weave with deleted lines."""
302
274
    def runTest(self):
311
283
                'line to be deleted',
312
284
                (']', 1),
313
285
                ('{', 1),
314
 
                'replacement line',                
 
286
                'replacement line',
315
287
                ('}', 1),
316
288
                'last line',
317
289
                ('}', 0),
318
290
                ]
 
291
        k._sha1s = [sha_string('first lineline to be deletedlast line')
 
292
                  , sha_string('first linereplacement linelast line')]
319
293
 
320
 
        self.assertEqual(k.get(0),
 
294
        self.assertEqual(k.get_lines(0),
321
295
                         ['first line',
322
296
                          'line to be deleted',
323
297
                          'last line',
324
298
                          ])
325
299
 
326
 
        self.assertEqual(k.get(1),
 
300
        self.assertEqual(k.get_lines(1),
327
301
                         ['first line',
328
302
                          'replacement line',
329
303
                          'last line',
330
304
                          ])
331
305
 
332
306
 
333
 
 
334
307
class BadWeave(TestBase):
335
308
    """Test that we trap an insert which should not occur."""
336
309
    def runTest(self):
353
326
 
354
327
        ################################### SKIPPED
355
328
        # Weave.get doesn't trap this anymore
356
 
        return 
 
329
        return
357
330
 
358
331
 
359
332
        self.assertRaises(WeaveFormatError,
416
389
                '}',
417
390
                ('}', 0)]
418
391
 
419
 
        self.assertEqual(k.get(0),
420
 
                         ['foo {',
421
 
                          '}'])
422
 
 
423
 
        self.assertEqual(k.get(1),
424
 
                         ['foo {',
425
 
                          '  added in version 1',
426
 
                          '  also from v1',
427
 
                          '}'])
428
 
                       
429
 
        self.assertEqual(k.get(2),
430
 
                         ['foo {',
431
 
                          '  added in v2',
432
 
                          '}'])
433
 
 
434
 
        self.assertEqual(k.get(3),
435
 
                         ['foo {',
436
 
                          '  added in version 1',
437
 
                          '  added in v2',
438
 
                          '  also from v1',
439
 
                          '}'])
440
 
                         
 
392
        k._sha1s = [sha_string('foo {}')
 
393
                  , sha_string('foo {  added in version 1  also from v1}')
 
394
                  , sha_string('foo {  added in v2}')
 
395
                  , sha_string('foo {  added in version 1  added in v2  also from v1}')
 
396
                  ]
 
397
 
 
398
        self.assertEqual(k.get_lines(0),
 
399
                         ['foo {',
 
400
                          '}'])
 
401
 
 
402
        self.assertEqual(k.get_lines(1),
 
403
                         ['foo {',
 
404
                          '  added in version 1',
 
405
                          '  also from v1',
 
406
                          '}'])
 
407
 
 
408
        self.assertEqual(k.get_lines(2),
 
409
                         ['foo {',
 
410
                          '  added in v2',
 
411
                          '}'])
 
412
 
 
413
        self.assertEqual(k.get_lines(3),
 
414
                         ['foo {',
 
415
                          '  added in version 1',
 
416
                          '  added in v2',
 
417
                          '  also from v1',
 
418
                          '}'])
441
419
 
442
420
 
443
421
class DeleteLines2(TestBase):
448
426
    def runTest(self):
449
427
        k = Weave()
450
428
 
451
 
        k.add('text0', [], ["line the first",
 
429
        k.add_lines('text0', [], ["line the first",
452
430
                   "line 2",
453
431
                   "line 3",
454
432
                   "fine"])
455
433
 
456
 
        self.assertEqual(len(k.get(0)), 4)
 
434
        self.assertEqual(len(k.get_lines(0)), 4)
457
435
 
458
 
        k.add('text1', [0], ["line the first",
 
436
        k.add_lines('text1', ['text0'], ["line the first",
459
437
                   "fine"])
460
438
 
461
 
        self.assertEqual(k.get(1),
 
439
        self.assertEqual(k.get_lines(1),
462
440
                         ["line the first",
463
441
                          "fine"])
464
442
 
465
 
        self.assertEqual(k.annotate(1),
466
 
                         [(0, "line the first"),
467
 
                          (0, "fine")])
468
 
 
 
443
        self.assertEqual(k.annotate('text1'),
 
444
                         [('text0', "line the first"),
 
445
                          ('text0', "fine")])
469
446
 
470
447
 
471
448
class IncludeVersions(TestBase):
489
466
                "second line",
490
467
                ('}', 1)]
491
468
 
492
 
        self.assertEqual(k.get(1),
 
469
        k._sha1s = [sha_string('first line')
 
470
                  , sha_string('first linesecond line')]
 
471
 
 
472
        self.assertEqual(k.get_lines(1),
493
473
                         ["first line",
494
474
                          "second line"])
495
475
 
496
 
        self.assertEqual(k.get(0),
 
476
        self.assertEqual(k.get_lines(0),
497
477
                         ["first line"])
498
478
 
499
479
 
501
481
    """Weave with two diverged texts based on version 0.
502
482
    """
503
483
    def runTest(self):
 
484
        # FIXME make the weave, dont poke at it.
504
485
        k = Weave()
505
486
 
 
487
        k._names = ['0', '1', '2']
 
488
        k._name_map = {'0':0, '1':1, '2':2}
506
489
        k._parents = [frozenset(),
507
490
                frozenset([0]),
508
491
                frozenset([0]),
515
498
                ('}', 1),
516
499
                ('{', 2),
517
500
                "alternative second line",
518
 
                ('}', 2),                
 
501
                ('}', 2),
519
502
                ]
520
503
 
521
 
        self.assertEqual(k.get(0),
 
504
        k._sha1s = [sha_string('first line')
 
505
                  , sha_string('first linesecond line')
 
506
                  , sha_string('first linealternative second line')]
 
507
 
 
508
        self.assertEqual(k.get_lines(0),
522
509
                         ["first line"])
523
510
 
524
 
        self.assertEqual(k.get(1),
 
511
        self.assertEqual(k.get_lines(1),
525
512
                         ["first line",
526
513
                          "second line"])
527
514
 
528
 
        self.assertEqual(k.get(2),
 
515
        self.assertEqual(k.get_lines('2'),
529
516
                         ["first line",
530
517
                          "alternative second line"])
531
518
 
532
 
        self.assertEqual(list(k.inclusions([2])),
533
 
                         [0, 2])
534
 
 
 
519
        self.assertEqual(list(k.get_ancestry(['2'])),
 
520
                         ['0', '2'])
535
521
 
536
522
 
537
523
class ReplaceLine(TestBase):
540
526
 
541
527
        text0 = ['cheddar', 'stilton', 'gruyere']
542
528
        text1 = ['cheddar', 'blue vein', 'neufchatel', 'chevre']
543
 
        
544
 
        k.add('text0', [], text0)
545
 
        k.add('text1', [0], text1)
 
529
 
 
530
        k.add_lines('text0', [], text0)
 
531
        k.add_lines('text1', ['text0'], text1)
546
532
 
547
533
        self.log('k._weave=' + pformat(k._weave))
548
534
 
549
 
        self.assertEqual(k.get(0), text0)
550
 
        self.assertEqual(k.get(1), text1)
551
 
 
 
535
        self.assertEqual(k.get_lines(0), text0)
 
536
        self.assertEqual(k.get_lines(1), text1)
552
537
 
553
538
 
554
539
class Merge(TestBase):
555
540
    """Storage of versions that merge diverged parents"""
 
541
 
556
542
    def runTest(self):
557
543
        k = Weave()
558
544
 
562
548
                 ['header', '', 'line from 1', 'fixup line', 'line from 2'],
563
549
                 ]
564
550
 
565
 
        k.add('text0', [], texts[0])
566
 
        k.add('text1', [0], texts[1])
567
 
        k.add('text2', [0], texts[2])
568
 
        k.add('merge', [0, 1, 2], texts[3])
 
551
        k.add_lines('text0', [], texts[0])
 
552
        k.add_lines('text1', ['text0'], texts[1])
 
553
        k.add_lines('text2', ['text0'], texts[2])
 
554
        k.add_lines('merge', ['text0', 'text1', 'text2'], texts[3])
569
555
 
570
556
        for i, t in enumerate(texts):
571
 
            self.assertEqual(k.get(i), t)
 
557
            self.assertEqual(k.get_lines(i), t)
572
558
 
573
 
        self.assertEqual(k.annotate(3),
574
 
                         [(0, 'header'),
575
 
                          (1, ''),
576
 
                          (1, 'line from 1'),
577
 
                          (3, 'fixup line'),
578
 
                          (2, 'line from 2'),
 
559
        self.assertEqual(k.annotate('merge'),
 
560
                         [('text0', 'header'),
 
561
                          ('text1', ''),
 
562
                          ('text1', 'line from 1'),
 
563
                          ('merge', 'fixup line'),
 
564
                          ('text2', 'line from 2'),
579
565
                          ])
580
566
 
581
 
        self.assertEqual(list(k.inclusions([3])),
582
 
                         [0, 1, 2, 3])
 
567
        self.assertEqual(list(k.get_ancestry(['merge'])),
 
568
                         ['text0', 'text1', 'text2', 'merge'])
583
569
 
584
570
        self.log('k._weave=' + pformat(k._weave))
585
571
 
596
582
        return  # NOT RUN
597
583
        k = Weave()
598
584
 
599
 
        k.add([], ['aaa', 'bbb'])
600
 
        k.add([0], ['aaa', '111', 'bbb'])
601
 
        k.add([1], ['aaa', '222', 'bbb'])
 
585
        k.add_lines([], ['aaa', 'bbb'])
 
586
        k.add_lines([0], ['aaa', '111', 'bbb'])
 
587
        k.add_lines([1], ['aaa', '222', 'bbb'])
602
588
 
603
589
        merged = k.merge([1, 2])
604
590
 
605
 
        self.assertEquals([[['aaa']],
 
591
        self.assertEqual([[['aaa']],
606
592
                           [['111'], ['222']],
607
593
                           [['bbb']]])
608
594
 
609
595
 
610
 
 
611
596
class NonConflict(TestBase):
612
597
    """Two descendants insert compatible changes.
613
598
 
616
601
        return  # NOT RUN
617
602
        k = Weave()
618
603
 
619
 
        k.add([], ['aaa', 'bbb'])
620
 
        k.add([0], ['111', 'aaa', 'ccc', 'bbb'])
621
 
        k.add([1], ['aaa', 'ccc', 'bbb', '222'])
622
 
 
623
 
    
624
 
    
625
 
 
626
 
 
627
 
class AutoMerge(TestBase):
628
 
    def runTest(self):
629
 
        k = Weave()
630
 
 
631
 
        texts = [['header', 'aaa', 'bbb'],
632
 
                 ['header', 'aaa', 'line from 1', 'bbb'],
633
 
                 ['header', 'aaa', 'bbb', 'line from 2', 'more from 2'],
634
 
                 ]
635
 
 
636
 
        k.add('text0', [], texts[0])
637
 
        k.add('text1', [0], texts[1])
638
 
        k.add('text2', [0], texts[2])
639
 
 
640
 
        self.log('k._weave=' + pformat(k._weave))
641
 
 
642
 
        m = list(k.mash_iter([0, 1, 2]))
643
 
 
644
 
        self.assertEqual(m,
645
 
                         ['header', 'aaa',
646
 
                          'line from 1',
647
 
                          'bbb',
648
 
                          'line from 2', 'more from 2'])
649
 
        
 
604
        k.add_lines([], ['aaa', 'bbb'])
 
605
        k.add_lines([0], ['111', 'aaa', 'ccc', 'bbb'])
 
606
        k.add_lines([1], ['aaa', 'ccc', 'bbb', '222'])
650
607
 
651
608
 
652
609
class Khayyam(TestBase):
653
610
    """Test changes to multi-line texts, and read/write"""
654
 
    def runTest(self):
 
611
 
 
612
    def test_multi_line_merge(self):
655
613
        rawtexts = [
656
614
            """A Book of Verses underneath the Bough,
657
615
            A Jug of Wine, a Loaf of Bread, -- and Thou
658
616
            Beside me singing in the Wilderness --
659
617
            Oh, Wilderness were Paradise enow!""",
660
 
            
 
618
 
661
619
            """A Book of Verses underneath the Bough,
662
620
            A Jug of Wine, a Loaf of Bread, -- and Thou
663
621
            Beside me singing in the Wilderness --
683
641
        parents = set()
684
642
        i = 0
685
643
        for t in texts:
686
 
            ver = k.add('text%d' % i,
 
644
            ver = k.add_lines('text%d' % i,
687
645
                        list(parents), t)
688
 
            parents.add(ver)
 
646
            parents.add('text%d' % i)
689
647
            i += 1
690
648
 
691
649
        self.log("k._weave=" + pformat(k._weave))
692
650
 
693
651
        for i, t in enumerate(texts):
694
 
            self.assertEqual(k.get(i), t)
 
652
            self.assertEqual(k.get_lines(i), t)
695
653
 
696
654
        self.check_read_write(k)
697
655
 
698
656
 
699
 
 
700
 
class MergeCases(TestBase):
701
 
    def doMerge(self, base, a, b, mp):
702
 
        from cStringIO import StringIO
703
 
        from textwrap import dedent
704
 
 
705
 
        def addcrlf(x):
706
 
            return x + '\n'
707
 
        
708
 
        w = Weave()
709
 
        w.add('text0', [], map(addcrlf, base))
710
 
        w.add('text1', [0], map(addcrlf, a))
711
 
        w.add('text2', [0], map(addcrlf, b))
712
 
 
713
 
        self.log('weave is:')
714
 
        tmpf = StringIO()
715
 
        write_weave(w, tmpf)
716
 
        self.log(tmpf.getvalue())
717
 
 
718
 
        self.log('merge plan:')
719
 
        p = list(w.plan_merge(1, 2))
720
 
        for state, line in p:
721
 
            if line:
722
 
                self.log('%12s | %s' % (state, line[:-1]))
723
 
 
724
 
        self.log('merge:')
725
 
        mt = StringIO()
726
 
        mt.writelines(w.weave_merge(p))
727
 
        mt.seek(0)
728
 
        self.log(mt.getvalue())
729
 
 
730
 
        mp = map(addcrlf, mp)
731
 
        self.assertEqual(mt.readlines(), mp)
732
 
        
733
 
        
734
 
    def testOneInsert(self):
735
 
        self.doMerge([],
736
 
                     ['aa'],
737
 
                     [],
738
 
                     ['aa'])
739
 
 
740
 
    def testSeparateInserts(self):
741
 
        self.doMerge(['aaa', 'bbb', 'ccc'],
742
 
                     ['aaa', 'xxx', 'bbb', 'ccc'],
743
 
                     ['aaa', 'bbb', 'yyy', 'ccc'],
744
 
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
745
 
 
746
 
    def testSameInsert(self):
747
 
        self.doMerge(['aaa', 'bbb', 'ccc'],
748
 
                     ['aaa', 'xxx', 'bbb', 'ccc'],
749
 
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'],
750
 
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
751
 
 
752
 
    def testOverlappedInsert(self):
753
 
        self.doMerge(['aaa', 'bbb'],
754
 
                     ['aaa', 'xxx', 'yyy', 'bbb'],
755
 
                     ['aaa', 'xxx', 'bbb'],
756
 
                     ['aaa', '<<<<', 'xxx', 'yyy', '====', 'xxx', '>>>>', 'bbb'])
757
 
 
758
 
        # really it ought to reduce this to 
759
 
        # ['aaa', 'xxx', 'yyy', 'bbb']
760
 
 
761
 
 
762
 
    def testClashReplace(self):
763
 
        self.doMerge(['aaa'],
764
 
                     ['xxx'],
765
 
                     ['yyy', 'zzz'],
766
 
                     ['<<<<', 'xxx', '====', 'yyy', 'zzz', '>>>>'])
767
 
 
768
 
    def testNonClashInsert(self):
769
 
        self.doMerge(['aaa'],
770
 
                     ['xxx', 'aaa'],
771
 
                     ['yyy', 'zzz'],
772
 
                     ['<<<<', 'xxx', 'aaa', '====', 'yyy', 'zzz', '>>>>'])
773
 
 
774
 
        self.doMerge(['aaa'],
775
 
                     ['aaa'],
776
 
                     ['yyy', 'zzz'],
777
 
                     ['yyy', 'zzz'])
778
 
 
779
 
 
780
 
    def testDeleteAndModify(self):
781
 
        """Clashing delete and modification.
782
 
 
783
 
        If one side modifies a region and the other deletes it then
784
 
        there should be a conflict with one side blank.
785
 
        """
786
 
 
787
 
        #######################################
788
 
        # skippd, not working yet
789
 
        return
790
 
        
791
 
        self.doMerge(['aaa', 'bbb', 'ccc'],
792
 
                     ['aaa', 'ddd', 'ccc'],
793
 
                     ['aaa', 'ccc'],
794
 
                     ['<<<<', 'aaa', '====', '>>>>', 'ccc'])
795
 
 
796
 
 
797
657
class JoinWeavesTests(TestBase):
 
658
 
798
659
    def setUp(self):
799
660
        super(JoinWeavesTests, self).setUp()
800
661
        self.weave1 = Weave()
801
662
        self.lines1 = ['hello\n']
802
663
        self.lines3 = ['hello\n', 'cruel\n', 'world\n']
803
 
        self.weave1.add('v1', [], self.lines1)
804
 
        self.weave1.add('v2', [0], ['hello\n', 'world\n'])
805
 
        self.weave1.add('v3', [1], self.lines3)
806
 
        
807
 
    def test_join_empty(self):
808
 
        """Join two empty weaves."""
809
 
        eq = self.assertEqual
810
 
        w1 = Weave()
811
 
        w2 = Weave()
812
 
        w1.join(w2)
813
 
        eq(w1.numversions(), 0)
814
 
        
815
 
    def test_join_empty_to_nonempty(self):
816
 
        """Join empty weave onto nonempty."""
817
 
        self.weave1.join(Weave())
818
 
        self.assertEqual(len(self.weave1), 3)
819
 
 
820
 
    def test_join_unrelated(self):
821
 
        """Join two weaves with no history in common."""
822
 
        wb = Weave()
823
 
        wb.add('b1', [], ['line from b\n'])
824
 
        w1 = self.weave1
825
 
        w1.join(wb)
826
 
        eq = self.assertEqual
827
 
        eq(len(w1), 4)
828
 
        eq(sorted(list(w1.iter_names())),
829
 
           ['b1', 'v1', 'v2', 'v3'])
830
 
 
831
 
    def test_join_related(self):
832
 
        wa = self.weave1.copy()
833
 
        wb = self.weave1.copy()
834
 
        wa.add('a1', ['v3'], ['hello\n', 'sweet\n', 'world\n'])
835
 
        wb.add('b1', ['v3'], ['hello\n', 'pale blue\n', 'world\n'])
836
 
        eq = self.assertEquals
837
 
        eq(len(wa), 4)
838
 
        eq(len(wb), 4)
839
 
        wa.join(wb)
840
 
        eq(len(wa), 5)
841
 
        eq(wa.get_lines('b1'),
842
 
           ['hello\n', 'pale blue\n', 'world\n'])
843
 
 
844
 
    def test_join_parent_disagreement(self):
845
 
        """Cannot join weaves with different parents for a version."""
846
 
        wa = Weave()
847
 
        wb = Weave()
848
 
        wa.add('v1', [], ['hello\n'])
849
 
        wb.add('v0', [], [])
850
 
        wb.add('v1', ['v0'], ['hello\n'])
851
 
        self.assertRaises(WeaveError,
852
 
                          wa.join, wb)
853
 
 
854
 
    def test_join_text_disagreement(self):
855
 
        """Cannot join weaves with different texts for a version."""
856
 
        wa = Weave()
857
 
        wb = Weave()
858
 
        wa.add('v1', [], ['hello\n'])
859
 
        wb.add('v1', [], ['not\n', 'hello\n'])
860
 
        self.assertRaises(WeaveError,
861
 
                          wa.join, wb)
862
 
 
863
 
    def test_join_unordered(self):
864
 
        """Join weaves where indexes differ.
865
 
        
866
 
        The source weave contains a different version at index 0."""
867
 
        wa = self.weave1.copy()
868
 
        wb = Weave()
869
 
        wb.add('x1', [], ['line from x1\n'])
870
 
        wb.add('v1', [], ['hello\n'])
871
 
        wb.add('v2', ['v1'], ['hello\n', 'world\n'])
872
 
        wa.join(wb)
873
 
        eq = self.assertEquals
874
 
        eq(sorted(wa.iter_names()), ['v1', 'v2', 'v3', 'x1',])
875
 
        eq(wa.get_text('x1'), 'line from x1\n')
876
 
 
877
 
    def test_reweave_with_empty(self):
878
 
        wb = Weave()
879
 
        wr = reweave(self.weave1, wb)
880
 
        eq = self.assertEquals
881
 
        eq(sorted(wr.iter_names()), ['v1', 'v2', 'v3'])
882
 
        eq(wr.get_lines('v3'), ['hello\n', 'cruel\n', 'world\n'])
883
 
        self.weave1.reweave(wb)
884
 
        self.assertEquals(wr, self.weave1)
885
 
 
886
 
    def test_join_with_ghosts_raises_parent_mismatch(self):
887
 
        wa = self.weave1.copy()
888
 
        wb = Weave()
889
 
        wb.add('x1', [], ['line from x1\n'])
890
 
        wb.add('v1', [], ['hello\n'])
891
 
        wb.add('v2', ['v1', 'x1'], ['hello\n', 'world\n'])
892
 
        self.assertRaises(errors.WeaveParentMismatch, wa.join, wb)
893
 
 
894
 
    def test_reweave_with_ghosts(self):
895
 
        """Join that inserts parents of an existing revision.
896
 
 
897
 
        This can happen when merging from another branch who
898
 
        knows about revisions the destination does not.  In 
899
 
        this test the second weave knows of an additional parent of 
900
 
        v2.  Any revisions which are in common still have to have the 
901
 
        same text."""
902
 
        wa = self.weave1.copy()
903
 
        wb = Weave()
904
 
        wb.add('x1', [], ['line from x1\n'])
905
 
        wb.add('v1', [], ['hello\n'])
906
 
        wb.add('v2', ['v1', 'x1'], ['hello\n', 'world\n'])
907
 
        wc = reweave(wa, wb)
908
 
        eq = self.assertEquals
909
 
        eq(sorted(wc.iter_names()), ['v1', 'v2', 'v3', 'x1',])
910
 
        eq(wc.get_text('x1'), 'line from x1\n')
911
 
        eq(wc.get_lines('v2'), ['hello\n', 'world\n'])
912
 
        eq(wc.parent_names('v2'), ['v1', 'x1'])
913
 
        self.weave1.reweave(wb)
914
 
        self.assertEquals(wc, self.weave1)
915
 
 
916
 
 
917
 
if __name__ == '__main__':
918
 
    import sys
919
 
    import unittest
920
 
    sys.exit(unittest.main())
921
 
    
 
664
        self.weave1.add_lines('v1', [], self.lines1)
 
665
        self.weave1.add_lines('v2', ['v1'], ['hello\n', 'world\n'])
 
666
        self.weave1.add_lines('v3', ['v2'], self.lines3)
 
667
 
 
668
    def test_written_detection(self):
 
669
        # Test detection of weave file corruption.
 
670
        #
 
671
        # Make sure that we can detect if a weave file has
 
672
        # been corrupted. This doesn't test all forms of corruption,
 
673
        # but it at least helps verify the data you get, is what you want.
 
674
        from cStringIO import StringIO
 
675
 
 
676
        w = Weave()
 
677
        w.add_lines('v1', [], ['hello\n'])
 
678
        w.add_lines('v2', ['v1'], ['hello\n', 'there\n'])
 
679
 
 
680
        tmpf = StringIO()
 
681
        write_weave(w, tmpf)
 
682
 
 
683
        # Because we are corrupting, we need to make sure we have the exact text
 
684
        self.assertEqual('# 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
                          tmpf.getvalue())
 
689
 
 
690
        # Change a single letter
 
691
        tmpf = StringIO('# bzr weave file v5\n'
 
692
                        'i\n1 f572d396fae9206628714fb2ce00f72e94f2258f\nn v1\n\n'
 
693
                        'i 0\n1 90f265c6e75f1c8f9ab76dcf85528352c5f215ef\nn v2\n\n'
 
694
                        'w\n{ 0\n. hello\n}\n{ 1\n. There\n}\nW\n')
 
695
 
 
696
        w = read_weave(tmpf)
 
697
 
 
698
        self.assertEqual('hello\n', w.get_text('v1'))
 
699
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_text, 'v2')
 
700
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_lines, 'v2')
 
701
        self.assertRaises(errors.WeaveInvalidChecksum, w.check)
 
702
 
 
703
        # Change the sha checksum
 
704
        tmpf = StringIO('# bzr weave file v5\n'
 
705
                        'i\n1 f572d396fae9206628714fb2ce00f72e94f2258f\nn v1\n\n'
 
706
                        'i 0\n1 f0f265c6e75f1c8f9ab76dcf85528352c5f215ef\nn v2\n\n'
 
707
                        'w\n{ 0\n. hello\n}\n{ 1\n. there\n}\nW\n')
 
708
 
 
709
        w = read_weave(tmpf)
 
710
 
 
711
        self.assertEqual('hello\n', w.get_text('v1'))
 
712
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_text, 'v2')
 
713
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_lines, 'v2')
 
714
        self.assertRaises(errors.WeaveInvalidChecksum, w.check)
 
715
 
 
716
 
 
717
class TestWeave(TestCase):
 
718
 
 
719
    def test_allow_reserved_false(self):
 
720
        w = Weave('name', allow_reserved=False)
 
721
        # Add lines is checked at the WeaveFile level, not at the Weave level
 
722
        w.add_lines('name:', [], TEXT_1)
 
723
        # But get_lines is checked at this level
 
724
        self.assertRaises(errors.ReservedId, w.get_lines, 'name:')
 
725
 
 
726
    def test_allow_reserved_true(self):
 
727
        w = Weave('name', allow_reserved=True)
 
728
        w.add_lines('name:', [], TEXT_1)
 
729
        self.assertEqual(TEXT_1, w.get_lines('name:'))
 
730
 
 
731
 
 
732
class InstrumentedWeave(Weave):
 
733
    """Keep track of how many times functions are called."""
 
734
 
 
735
    def __init__(self, weave_name=None):
 
736
        self._extract_count = 0
 
737
        Weave.__init__(self, weave_name=weave_name)
 
738
 
 
739
    def _extract(self, versions):
 
740
        self._extract_count += 1
 
741
        return Weave._extract(self, versions)
 
742
 
 
743
 
 
744
class TestNeedsReweave(TestCase):
 
745
    """Internal corner cases for when reweave is needed."""
 
746
 
 
747
    def test_compatible_parents(self):
 
748
        w1 = Weave('a')
 
749
        my_parents = set([1, 2, 3])
 
750
        # subsets are ok
 
751
        self.assertTrue(w1._compatible_parents(my_parents, set([3])))
 
752
        # same sets
 
753
        self.assertTrue(w1._compatible_parents(my_parents, set(my_parents)))
 
754
        # same empty corner case
 
755
        self.assertTrue(w1._compatible_parents(set(), set()))
 
756
        # other cannot contain stuff my_parents does not
 
757
        self.assertFalse(w1._compatible_parents(set(), set([1])))
 
758
        self.assertFalse(w1._compatible_parents(my_parents, set([1, 2, 3, 4])))
 
759
        self.assertFalse(w1._compatible_parents(my_parents, set([4])))
 
760
 
 
761
 
 
762
class TestWeaveFile(TestCaseInTempDir):
 
763
 
 
764
    def test_empty_file(self):
 
765
        f = open('empty.weave', 'wb+')
 
766
        try:
 
767
            self.assertRaises(errors.WeaveFormatError,
 
768
                              read_weave, f)
 
769
        finally:
 
770
            f.close()