~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to testweave.py

  • Committer: Martin Pool
  • Date: 2005-06-30 06:51:39 UTC
  • mto: This revision was merged to the branch mainline in revision 852.
  • Revision ID: mbp@sourcefrog.net-20050630065139-807846ee27beaa00
Ignore test.weave

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