~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to testweave.py

  • Committer: mbp at sourcefrog
  • Date: 2005-03-09 04:51:05 UTC
  • Revision ID: mbp@sourcefrog.net-20050309045105-d02cd410a115da2c
import all docs from arch

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
 
 
5
 
# This program is free software; you can redistribute it and/or modify
6
 
# it under the terms of the GNU General Public License as published by
7
 
# the Free Software Foundation; either version 2 of the License, or
8
 
# (at your option) any later version.
9
 
 
10
 
# This program is distributed in the hope that it will be useful,
11
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
# GNU General Public License for more details.
14
 
 
15
 
# You should have received a copy of the GNU General Public License
16
 
# along with this program; if not, write to the Free Software
17
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 
 
19
 
 
20
 
 
21
 
 
22
 
"""test suite for weave algorithm"""
23
 
 
24
 
 
25
 
import testsweet
26
 
from weave import Weave, WeaveFormatError
27
 
from pprint import pformat
28
 
 
29
 
 
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
 
 
40
 
 
41
 
 
42
 
# texts for use in testing
43
 
TEXT_0 = ["Hello world"]
44
 
TEXT_1 = ["Hello world",
45
 
          "A second line"]
46
 
 
47
 
 
48
 
 
49
 
class TestBase(testsweet.TestBase):
50
 
    def check_read_write(self, k):
51
 
        """Check the weave k can be written & re-read."""
52
 
        from tempfile import TemporaryFile
53
 
        from weavefile import write_weave, read_weave
54
 
        tf = TemporaryFile()
55
 
 
56
 
        write_weave(k, tf)
57
 
        tf.seek(0)
58
 
        k2 = read_weave(tf)
59
 
 
60
 
        if k != k2:
61
 
            tf.seek(0)
62
 
            self.log('serialized weave:')
63
 
            self.log(tf.read())
64
 
            self.fail('read/write check failed')
65
 
        
66
 
        
67
 
 
68
 
 
69
 
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([], TEXT_0)
79
 
        self.assertEqual(k.get(idx), TEXT_0)
80
 
        self.assertEqual(idx, 0)
81
 
 
82
 
 
83
 
 
84
 
class AnnotateOne(TestBase):
85
 
    def runTest(self):
86
 
        k = Weave()
87
 
        k.add([], TEXT_0)
88
 
        self.assertEqual(k.annotate(0),
89
 
                         [(0, TEXT_0[0])])
90
 
 
91
 
 
92
 
class StoreTwo(TestBase):
93
 
    def runTest(self):
94
 
        k = Weave()
95
 
 
96
 
        idx = k.add([], TEXT_0)
97
 
        self.assertEqual(idx, 0)
98
 
 
99
 
        idx = k.add([], TEXT_1)
100
 
        self.assertEqual(idx, 1)
101
 
 
102
 
        self.assertEqual(k.get(0), TEXT_0)
103
 
        self.assertEqual(k.get(1), TEXT_1)
104
 
 
105
 
        k.dump(self.TEST_LOG)
106
 
 
107
 
 
108
 
 
109
 
class DeltaAdd(TestBase):
110
 
    """Detection of changes prior to inserting new revision."""
111
 
    def runTest(self):
112
 
        k = Weave()
113
 
        k.add([], ['line 1'])
114
 
 
115
 
        self.assertEqual(k._l,
116
 
                         [('{', 0),
117
 
                          'line 1',
118
 
                          ('}', 0),
119
 
                          ])
120
 
 
121
 
        changes = list(k._delta(set([0]),
122
 
                                ['line 1',
123
 
                                 'new line']))
124
 
 
125
 
        self.log('raw changes: ' + pformat(changes))
126
 
 
127
 
        # currently there are 3 lines in the weave, and we insert after them
128
 
        self.assertEquals(changes,
129
 
                          [(3, 3, ['new line'])])
130
 
 
131
 
        changes = k._delta(set([0]),
132
 
                           ['top line',
133
 
                            'line 1'])
134
 
        
135
 
        self.assertEquals(list(changes),
136
 
                          [(1, 1, ['top line'])])
137
 
 
138
 
        self.check_read_write(k)
139
 
 
140
 
 
141
 
class InvalidAdd(TestBase):
142
 
    """Try to use invalid version number during add."""
143
 
    def runTest(self):
144
 
        k = Weave()
145
 
 
146
 
        self.assertRaises(IndexError,
147
 
                          k.add,
148
 
                          [69],
149
 
                          ['new text!'])
150
 
 
151
 
 
152
 
class InsertLines(TestBase):
153
 
    """Store a revision that adds one line to the original.
154
 
 
155
 
    Look at the annotations to make sure that the first line is matched
156
 
    and not stored repeatedly."""
157
 
    def runTest(self):
158
 
        k = Weave()
159
 
 
160
 
        k.add([], ['line 1'])
161
 
        k.add([0], ['line 1', 'line 2'])
162
 
 
163
 
        self.assertEqual(k.annotate(0),
164
 
                         [(0, 'line 1')])
165
 
 
166
 
        self.assertEqual(k.get(1),
167
 
                         ['line 1',
168
 
                          'line 2'])
169
 
 
170
 
        self.assertEqual(k.annotate(1),
171
 
                         [(0, 'line 1'),
172
 
                          (1, 'line 2')])
173
 
 
174
 
        k.add([0], ['line 1', 'diverged line'])
175
 
 
176
 
        self.assertEqual(k.annotate(2),
177
 
                         [(0, 'line 1'),
178
 
                          (2, 'diverged line')])
179
 
 
180
 
        text3 = ['line 1', 'middle line', 'line 2']
181
 
        k.add([0, 1],
182
 
              text3)
183
 
 
184
 
        self.log("changes to text3: " + pformat(list(k._delta(set([0, 1]), text3))))
185
 
 
186
 
        self.log("k._l=" + pformat(k._l))
187
 
 
188
 
        self.assertEqual(k.annotate(3),
189
 
                         [(0, 'line 1'),
190
 
                          (3, 'middle line'),
191
 
                          (1, 'line 2')])
192
 
 
193
 
        # now multiple insertions at different places
194
 
        k.add([0, 1, 3],
195
 
              ['line 1', 'aaa', 'middle line', 'bbb', 'line 2', 'ccc'])
196
 
 
197
 
        self.assertEqual(k.annotate(4), 
198
 
                         [(0, 'line 1'),
199
 
                          (4, 'aaa'),
200
 
                          (3, 'middle line'),
201
 
                          (4, 'bbb'),
202
 
                          (1, 'line 2'),
203
 
                          (4, 'ccc')])
204
 
 
205
 
 
206
 
 
207
 
class DeleteLines(TestBase):
208
 
    """Deletion of lines from existing text.
209
 
 
210
 
    Try various texts all based on a common ancestor."""
211
 
    def runTest(self):
212
 
        k = Weave()
213
 
 
214
 
        base_text = ['one', 'two', 'three', 'four']
215
 
 
216
 
        k.add([], base_text)
217
 
        
218
 
        texts = [['one', 'two', 'three'],
219
 
                 ['two', 'three', 'four'],
220
 
                 ['one', 'four'],
221
 
                 ['one', 'two', 'three', 'four'],
222
 
                 ]
223
 
 
224
 
        for t in texts:
225
 
            ver = k.add([0], t)
226
 
 
227
 
        self.log('final weave:')
228
 
        self.log('k._l=' + pformat(k._l))
229
 
 
230
 
        for i in range(len(texts)):
231
 
            self.assertEqual(k.get(i+1),
232
 
                             texts[i])
233
 
            
234
 
 
235
 
 
236
 
 
237
 
class SuicideDelete(TestBase):
238
 
    """Invalid weave which tries to add and delete simultaneously."""
239
 
    def runTest(self):
240
 
        k = Weave()
241
 
 
242
 
        k._v = [(),
243
 
                ]
244
 
        k._l = [('{', 0),
245
 
                'first line',
246
 
                ('[', 0),
247
 
                'deleted in 0',
248
 
                (']', 0),
249
 
                ('}', 0),
250
 
                ]
251
 
 
252
 
        self.assertRaises(WeaveFormatError,
253
 
                          k.get,
254
 
                          0)        
255
 
 
256
 
 
257
 
 
258
 
class CannedDelete(TestBase):
259
 
    """Unpack canned weave with deleted lines."""
260
 
    def runTest(self):
261
 
        k = Weave()
262
 
 
263
 
        k._v = [(),
264
 
                frozenset([0]),
265
 
                ]
266
 
        k._l = [('{', 0),
267
 
                'first line',
268
 
                ('[', 1),
269
 
                'line to be deleted',
270
 
                (']', 1),
271
 
                'last line',
272
 
                ('}', 0),
273
 
                ]
274
 
 
275
 
        self.assertEqual(k.get(0),
276
 
                         ['first line',
277
 
                          'line to be deleted',
278
 
                          'last line',
279
 
                          ])
280
 
 
281
 
        self.assertEqual(k.get(1),
282
 
                         ['first line',
283
 
                          'last line',
284
 
                          ])
285
 
 
286
 
 
287
 
 
288
 
class CannedReplacement(TestBase):
289
 
    """Unpack canned weave with deleted lines."""
290
 
    def runTest(self):
291
 
        k = Weave()
292
 
 
293
 
        k._v = [frozenset(),
294
 
                frozenset([0]),
295
 
                ]
296
 
        k._l = [('{', 0),
297
 
                'first line',
298
 
                ('[', 1),
299
 
                'line to be deleted',
300
 
                (']', 1),
301
 
                ('{', 1),
302
 
                'replacement line',                
303
 
                ('}', 1),
304
 
                'last line',
305
 
                ('}', 0),
306
 
                ]
307
 
 
308
 
        self.assertEqual(k.get(0),
309
 
                         ['first line',
310
 
                          'line to be deleted',
311
 
                          'last line',
312
 
                          ])
313
 
 
314
 
        self.assertEqual(k.get(1),
315
 
                         ['first line',
316
 
                          'replacement line',
317
 
                          'last line',
318
 
                          ])
319
 
 
320
 
 
321
 
 
322
 
class BadWeave(TestBase):
323
 
    """Test that we trap an insert which should not occur."""
324
 
    def runTest(self):
325
 
        k = Weave()
326
 
 
327
 
        k._v = [frozenset(),
328
 
                ]
329
 
        k._l = ['bad line',
330
 
                ('{', 0),
331
 
                'foo {',
332
 
                ('{', 1),
333
 
                '  added in version 1',
334
 
                ('{', 2),
335
 
                '  added in v2',
336
 
                ('}', 2),
337
 
                '  also from v1',
338
 
                ('}', 1),
339
 
                '}',
340
 
                ('}', 0)]
341
 
 
342
 
        self.assertRaises(WeaveFormatError,
343
 
                          k.get,
344
 
                          0)
345
 
 
346
 
 
347
 
class BadInsert(TestBase):
348
 
    """Test that we trap an insert which should not occur."""
349
 
    def runTest(self):
350
 
        k = Weave()
351
 
 
352
 
        k._v = [frozenset(),
353
 
                frozenset([0]),
354
 
                frozenset([0]),
355
 
                frozenset([0,1,2]),
356
 
                ]
357
 
        k._l = [('{', 0),
358
 
                'foo {',
359
 
                ('{', 1),
360
 
                '  added in version 1',
361
 
                ('{', 1),
362
 
                '  more in 1',
363
 
                ('}', 1),
364
 
                ('}', 1),
365
 
                ('}', 0)]
366
 
 
367
 
        self.assertRaises(WeaveFormatError,
368
 
                          k.get,
369
 
                          0)
370
 
 
371
 
        self.assertRaises(WeaveFormatError,
372
 
                          k.get,
373
 
                          1)
374
 
 
375
 
 
376
 
class InsertNested(TestBase):
377
 
    """Insertion with nested instructions."""
378
 
    def runTest(self):
379
 
        k = Weave()
380
 
 
381
 
        k._v = [frozenset(),
382
 
                frozenset([0]),
383
 
                frozenset([0]),
384
 
                frozenset([0,1,2]),
385
 
                ]
386
 
        k._l = [('{', 0),
387
 
                'foo {',
388
 
                ('{', 1),
389
 
                '  added in version 1',
390
 
                ('{', 2),
391
 
                '  added in v2',
392
 
                ('}', 2),
393
 
                '  also from v1',
394
 
                ('}', 1),
395
 
                '}',
396
 
                ('}', 0)]
397
 
 
398
 
        self.assertEqual(k.get(0),
399
 
                         ['foo {',
400
 
                          '}'])
401
 
 
402
 
        self.assertEqual(k.get(1),
403
 
                         ['foo {',
404
 
                          '  added in version 1',
405
 
                          '  also from v1',
406
 
                          '}'])
407
 
                       
408
 
        self.assertEqual(k.get(2),
409
 
                         ['foo {',
410
 
                          '  added in v2',
411
 
                          '}'])
412
 
 
413
 
        self.assertEqual(k.get(3),
414
 
                         ['foo {',
415
 
                          '  added in version 1',
416
 
                          '  added in v2',
417
 
                          '  also from v1',
418
 
                          '}'])
419
 
                         
420
 
 
421
 
 
422
 
class DeleteLines2(TestBase):
423
 
    """Test recording revisions that delete lines.
424
 
 
425
 
    This relies on the weave having a way to represent lines knocked
426
 
    out by a later revision."""
427
 
    def runTest(self):
428
 
        k = Weave()
429
 
 
430
 
        k.add([], ["line the first",
431
 
                   "line 2",
432
 
                   "line 3",
433
 
                   "fine"])
434
 
 
435
 
        self.assertEqual(len(k.get(0)), 4)
436
 
 
437
 
        k.add([0], ["line the first",
438
 
                   "fine"])
439
 
 
440
 
        self.assertEqual(k.get(1),
441
 
                         ["line the first",
442
 
                          "fine"])
443
 
 
444
 
        self.assertEqual(k.annotate(1),
445
 
                         [(0, "line the first"),
446
 
                          (0, "fine")])
447
 
 
448
 
 
449
 
 
450
 
class IncludeVersions(TestBase):
451
 
    """Check texts that are stored across multiple revisions.
452
 
 
453
 
    Here we manually create a weave with particular encoding and make
454
 
    sure it unpacks properly.
455
 
 
456
 
    Text 0 includes nothing; text 1 includes text 0 and adds some
457
 
    lines.
458
 
    """
459
 
 
460
 
    def runTest(self):
461
 
        k = Weave()
462
 
 
463
 
        k._v = [frozenset(), frozenset([0])]
464
 
        k._l = [('{', 0),
465
 
                "first line",
466
 
                ('}', 0),
467
 
                ('{', 1),
468
 
                "second line",
469
 
                ('}', 1)]
470
 
 
471
 
        self.assertEqual(k.get(1),
472
 
                         ["first line",
473
 
                          "second line"])
474
 
 
475
 
        self.assertEqual(k.get(0),
476
 
                         ["first line"])
477
 
 
478
 
        k.dump(self.TEST_LOG)
479
 
 
480
 
 
481
 
class DivergedIncludes(TestBase):
482
 
    """Weave with two diverged texts based on version 0.
483
 
    """
484
 
    def runTest(self):
485
 
        k = Weave()
486
 
 
487
 
        k._v = [frozenset(),
488
 
                frozenset([0]),
489
 
                frozenset([0]),
490
 
                ]
491
 
        k._l = [('{', 0),
492
 
                "first line",
493
 
                ('}', 0),
494
 
                ('{', 1),
495
 
                "second line",
496
 
                ('}', 1),
497
 
                ('{', 2),
498
 
                "alternative second line",
499
 
                ('}', 2),                
500
 
                ]
501
 
 
502
 
        self.assertEqual(k.get(0),
503
 
                         ["first line"])
504
 
 
505
 
        self.assertEqual(k.get(1),
506
 
                         ["first line",
507
 
                          "second line"])
508
 
 
509
 
        self.assertEqual(k.get(2),
510
 
                         ["first line",
511
 
                          "alternative second line"])
512
 
 
513
 
        self.assertEqual(k.inclusions([2]),
514
 
                         set([0, 2]))
515
 
 
516
 
 
517
 
 
518
 
class ReplaceLine(TestBase):
519
 
    def runTest(self):
520
 
        k = Weave()
521
 
 
522
 
        text0 = ['cheddar', 'stilton', 'gruyere']
523
 
        text1 = ['cheddar', 'blue vein', 'neufchatel', 'chevre']
524
 
        
525
 
        k.add([], text0)
526
 
        k.add([0], text1)
527
 
 
528
 
        self.log('k._l=' + pformat(k._l))
529
 
 
530
 
        self.assertEqual(k.get(0), text0)
531
 
        self.assertEqual(k.get(1), text1)
532
 
 
533
 
 
534
 
 
535
 
class Merge(TestBase):
536
 
    """Versions that merge diverged parents"""
537
 
    def runTest(self):
538
 
        k = Weave()
539
 
 
540
 
        texts = [['header'],
541
 
                 ['header', '', 'line from 1'],
542
 
                 ['header', '', 'line from 2', 'more from 2'],
543
 
                 ['header', '', 'line from 1', 'fixup line', 'line from 2'],
544
 
                 ]
545
 
 
546
 
        k.add([], texts[0])
547
 
        k.add([0], texts[1])
548
 
        k.add([0], texts[2])
549
 
        k.add([0, 1, 2], texts[3])
550
 
 
551
 
        for i, t in enumerate(texts):
552
 
            self.assertEqual(k.get(i), t)
553
 
 
554
 
        self.assertEqual(k.annotate(3),
555
 
                         [(0, 'header'),
556
 
                          (1, ''),
557
 
                          (1, 'line from 1'),
558
 
                          (3, 'fixup line'),
559
 
                          (2, 'line from 2'),
560
 
                          ])
561
 
 
562
 
        self.assertEqual(k.inclusions([3]),
563
 
                         set([0, 1, 2, 3]))
564
 
 
565
 
        self.log('k._l=' + pformat(k._l))
566
 
 
567
 
        self.check_read_write(k)
568
 
 
569
 
 
570
 
class AutoMerge(TestBase):
571
 
    def runTest(self):
572
 
        k = Weave()
573
 
 
574
 
        texts = [['header', 'aaa', 'bbb'],
575
 
                 ['header', 'aaa', 'line from 1', 'bbb'],
576
 
                 ['header', 'aaa', 'bbb', 'line from 2', 'more from 2'],
577
 
                 ]
578
 
 
579
 
        k.add([], texts[0])
580
 
        k.add([0], texts[1])
581
 
        k.add([0], texts[2])
582
 
 
583
 
        self.log('k._l=' + pformat(k._l))
584
 
 
585
 
        m = list(k.merge_iter([0, 1, 2]))
586
 
 
587
 
        self.assertEqual(m,
588
 
                         ['header', 'aaa',
589
 
                          'line from 1',
590
 
                          'bbb',
591
 
                          'line from 2', 'more from 2'])
592
 
        
593
 
 
594
 
 
595
 
class Khayyam(TestBase):
596
 
    """Test changes to multi-line texts, and read/write"""
597
 
    def runTest(self):
598
 
        rawtexts = [
599
 
            """A Book of Verses underneath the Bough,
600
 
            A Jug of Wine, a Loaf of Bread, -- and Thou
601
 
            Beside me singing in the Wilderness --
602
 
            Oh, Wilderness were Paradise enow!""",
603
 
            
604
 
            """A Book of Verses underneath the Bough,
605
 
            A Jug of Wine, a Loaf of Bread, -- and Thou
606
 
            Beside me singing in the Wilderness --
607
 
            Oh, Wilderness were Paradise now!""",
608
 
 
609
 
            """A Book of poems underneath the tree,
610
 
            A Jug of Wine, a Loaf of Bread,
611
 
            and Thou
612
 
            Beside me singing in the Wilderness --
613
 
            Oh, Wilderness were Paradise now!
614
 
 
615
 
            -- O. Khayyam""",
616
 
 
617
 
            """A Book of Verses underneath the Bough,
618
 
            A Jug of Wine, a Loaf of Bread,
619
 
            and Thou
620
 
            Beside me singing in the Wilderness --
621
 
            Oh, Wilderness were Paradise now!""",
622
 
            ]
623
 
        texts = [[l.strip() for l in t.split('\n')] for t in rawtexts]
624
 
 
625
 
        k = Weave()
626
 
        parents = set()
627
 
        for t in texts:
628
 
            ver = k.add(list(parents), t)
629
 
            parents.add(ver)
630
 
 
631
 
        self.log("k._l=" + pformat(k._l))
632
 
 
633
 
        for i, t in enumerate(texts):
634
 
            self.assertEqual(k.get(i), t)
635
 
 
636
 
        self.check_read_write(k)
637
 
 
638
 
 
639
 
def testweave():
640
 
    import testsweet
641
 
    from unittest import TestSuite, TestLoader
642
 
    import testweave
643
 
 
644
 
    tl = TestLoader()
645
 
    suite = TestSuite()
646
 
    suite.addTest(tl.loadTestsFromModule(testweave))
647
 
    
648
 
    return int(not testsweet.run_suite(suite)) # for shell 0=true
649
 
 
650
 
 
651
 
if __name__ == '__main__':
652
 
    import sys
653
 
    sys.exit(testweave())
654