~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/test_weave.py

  • Committer: John Arbash Meinel
  • Date: 2005-09-29 21:13:03 UTC
  • mto: (1393.1.12)
  • mto: This revision was merged to the branch mainline in revision 1396.
  • Revision ID: john@arbash-meinel.com-20050929211303-7f1f9bf969d65dc3
All tests pass.

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
# TODO: tests regarding version names
 
21
 
 
22
 
 
23
 
 
24
"""test suite for weave algorithm"""
 
25
 
 
26
from pprint import pformat
 
27
 
 
28
from bzrlib.weave import Weave, WeaveFormatError, WeaveError
 
29
from bzrlib.weavefile import write_weave, read_weave
 
30
from bzrlib.selftest import TestCase
 
31
from bzrlib.osutils import sha_string
 
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
 
 
42
 
 
43
 
 
44
# texts for use in testing
 
45
TEXT_0 = ["Hello world"]
 
46
TEXT_1 = ["Hello world",
 
47
          "A second line"]
 
48
 
 
49
 
 
50
 
 
51
class TestBase(TestCase):
 
52
    def check_read_write(self, k):
 
53
        """Check the weave k can be written & re-read."""
 
54
        from tempfile import TemporaryFile
 
55
        tf = TemporaryFile()
 
56
 
 
57
        write_weave(k, tf)
 
58
        tf.seek(0)
 
59
        k2 = read_weave(tf)
 
60
 
 
61
        if k != k2:
 
62
            tf.seek(0)
 
63
            self.log('serialized weave:')
 
64
            self.log(tf.read())
 
65
 
 
66
            self.log('')
 
67
            self.log('parents: %s' % (k._parents == k2._parents))
 
68
            self.log('         %r' % k._parents)
 
69
            self.log('         %r' % k2._parents)
 
70
            self.log('')
 
71
 
 
72
            
 
73
            self.fail('read/write check failed')
 
74
        
 
75
        
 
76
 
 
77
 
 
78
class Easy(TestBase):
 
79
    def runTest(self):
 
80
        k = Weave()
 
81
 
 
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
 
 
93
class AnnotateOne(TestBase):
 
94
    def runTest(self):
 
95
        k = Weave()
 
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
 
 
115
 
 
116
class AddWithGivenSha(TestBase):
 
117
    def runTest(self):
 
118
        """Add with caller-supplied SHA-1"""
 
119
        k = Weave()
 
120
 
 
121
        t = 'text0'
 
122
        k.add('text0', [], [t], sha1=sha_string(t))
 
123
 
 
124
 
 
125
 
 
126
class InvalidAdd(TestBase):
 
127
    """Try to use invalid version number during add."""
 
128
    def runTest(self):
 
129
        k = Weave()
 
130
 
 
131
        self.assertRaises(IndexError,
 
132
                          k.add,
 
133
                          'text0',
 
134
                          [69],
 
135
                          ['new text!'])
 
136
 
 
137
 
 
138
class RepeatedAdd(TestBase):
 
139
    """Add the same version twice; harmless."""
 
140
    def runTest(self):
 
141
        k = Weave()
 
142
        idx = k.add('text0', [], TEXT_0)
 
143
        idx2 = k.add('text0', [], TEXT_0)
 
144
        self.assertEqual(idx, idx2)
 
145
 
 
146
 
 
147
 
 
148
class InvalidRepeatedAdd(TestBase):
 
149
    def runTest(self):
 
150
        k = Weave()
 
151
        idx = k.add('text0', [], TEXT_0)
 
152
        self.assertRaises(WeaveError,
 
153
                          k.add,
 
154
                          'text0',
 
155
                          [],
 
156
                          ['not the same text'])
 
157
        self.assertRaises(WeaveError,
 
158
                          k.add,
 
159
                          'text0',
 
160
                          [12],         # not the right parents
 
161
                          TEXT_0)
 
162
        
 
163
 
 
164
 
 
165
class InsertLines(TestBase):
 
166
    """Store a revision that adds one line to the original.
 
167
 
 
168
    Look at the annotations to make sure that the first line is matched
 
169
    and not stored repeatedly."""
 
170
    def runTest(self):
 
171
        k = Weave()
 
172
 
 
173
        k.add('text0', [], ['line 1'])
 
174
        k.add('text1', [0], ['line 1', 'line 2'])
 
175
 
 
176
        self.assertEqual(k.annotate(0),
 
177
                         [(0, 'line 1')])
 
178
 
 
179
        self.assertEqual(k.get(1),
 
180
                         ['line 1',
 
181
                          'line 2'])
 
182
 
 
183
        self.assertEqual(k.annotate(1),
 
184
                         [(0, 'line 1'),
 
185
                          (1, 'line 2')])
 
186
 
 
187
        k.add('text2', [0], ['line 1', 'diverged line'])
 
188
 
 
189
        self.assertEqual(k.annotate(2),
 
190
                         [(0, 'line 1'),
 
191
                          (2, 'diverged line')])
 
192
 
 
193
        text3 = ['line 1', 'middle line', 'line 2']
 
194
        k.add('text3',
 
195
              [0, 1],
 
196
              text3)
 
197
 
 
198
        # self.log("changes to text3: " + pformat(list(k._delta(set([0, 1]), text3))))
 
199
 
 
200
        self.log("k._weave=" + pformat(k._weave))
 
201
 
 
202
        self.assertEqual(k.annotate(3),
 
203
                         [(0, 'line 1'),
 
204
                          (3, 'middle line'),
 
205
                          (1, 'line 2')])
 
206
 
 
207
        # now multiple insertions at different places
 
208
        k.add('text4',
 
209
              [0, 1, 3],
 
210
              ['line 1', 'aaa', 'middle line', 'bbb', 'line 2', 'ccc'])
 
211
 
 
212
        self.assertEqual(k.annotate(4), 
 
213
                         [(0, 'line 1'),
 
214
                          (4, 'aaa'),
 
215
                          (3, 'middle line'),
 
216
                          (4, 'bbb'),
 
217
                          (1, 'line 2'),
 
218
                          (4, 'ccc')])
 
219
 
 
220
 
 
221
 
 
222
class DeleteLines(TestBase):
 
223
    """Deletion of lines from existing text.
 
224
 
 
225
    Try various texts all based on a common ancestor."""
 
226
    def runTest(self):
 
227
        k = Weave()
 
228
 
 
229
        base_text = ['one', 'two', 'three', 'four']
 
230
 
 
231
        k.add('text0', [], base_text)
 
232
        
 
233
        texts = [['one', 'two', 'three'],
 
234
                 ['two', 'three', 'four'],
 
235
                 ['one', 'four'],
 
236
                 ['one', 'two', 'three', 'four'],
 
237
                 ]
 
238
 
 
239
        i = 1
 
240
        for t in texts:
 
241
            ver = k.add('text%d' % i,
 
242
                        [0], t)
 
243
            i += 1
 
244
 
 
245
        self.log('final weave:')
 
246
        self.log('k._weave=' + pformat(k._weave))
 
247
 
 
248
        for i in range(len(texts)):
 
249
            self.assertEqual(k.get(i+1),
 
250
                             texts[i])
 
251
            
 
252
 
 
253
 
 
254
 
 
255
class SuicideDelete(TestBase):
 
256
    """Invalid weave which tries to add and delete simultaneously."""
 
257
    def runTest(self):
 
258
        k = Weave()
 
259
 
 
260
        k._parents = [(),
 
261
                ]
 
262
        k._weave = [('{', 0),
 
263
                'first line',
 
264
                ('[', 0),
 
265
                'deleted in 0',
 
266
                (']', 0),
 
267
                ('}', 0),
 
268
                ]
 
269
        ################################### SKIPPED
 
270
        # Weave.get doesn't trap this anymore
 
271
        return 
 
272
 
 
273
        self.assertRaises(WeaveFormatError,
 
274
                          k.get,
 
275
                          0)        
 
276
 
 
277
 
 
278
 
 
279
class CannedDelete(TestBase):
 
280
    """Unpack canned weave with deleted lines."""
 
281
    def runTest(self):
 
282
        k = Weave()
 
283
 
 
284
        k._parents = [(),
 
285
                frozenset([0]),
 
286
                ]
 
287
        k._weave = [('{', 0),
 
288
                'first line',
 
289
                ('[', 1),
 
290
                'line to be deleted',
 
291
                (']', 1),
 
292
                'last line',
 
293
                ('}', 0),
 
294
                ]
 
295
 
 
296
        self.assertEqual(k.get(0),
 
297
                         ['first line',
 
298
                          'line to be deleted',
 
299
                          'last line',
 
300
                          ])
 
301
 
 
302
        self.assertEqual(k.get(1),
 
303
                         ['first line',
 
304
                          'last line',
 
305
                          ])
 
306
 
 
307
 
 
308
 
 
309
class CannedReplacement(TestBase):
 
310
    """Unpack canned weave with deleted lines."""
 
311
    def runTest(self):
 
312
        k = Weave()
 
313
 
 
314
        k._parents = [frozenset(),
 
315
                frozenset([0]),
 
316
                ]
 
317
        k._weave = [('{', 0),
 
318
                'first line',
 
319
                ('[', 1),
 
320
                'line to be deleted',
 
321
                (']', 1),
 
322
                ('{', 1),
 
323
                'replacement line',                
 
324
                ('}', 1),
 
325
                'last line',
 
326
                ('}', 0),
 
327
                ]
 
328
 
 
329
        self.assertEqual(k.get(0),
 
330
                         ['first line',
 
331
                          'line to be deleted',
 
332
                          'last line',
 
333
                          ])
 
334
 
 
335
        self.assertEqual(k.get(1),
 
336
                         ['first line',
 
337
                          'replacement line',
 
338
                          'last line',
 
339
                          ])
 
340
 
 
341
 
 
342
 
 
343
class BadWeave(TestBase):
 
344
    """Test that we trap an insert which should not occur."""
 
345
    def runTest(self):
 
346
        k = Weave()
 
347
 
 
348
        k._parents = [frozenset(),
 
349
                ]
 
350
        k._weave = ['bad line',
 
351
                ('{', 0),
 
352
                'foo {',
 
353
                ('{', 1),
 
354
                '  added in version 1',
 
355
                ('{', 2),
 
356
                '  added in v2',
 
357
                ('}', 2),
 
358
                '  also from v1',
 
359
                ('}', 1),
 
360
                '}',
 
361
                ('}', 0)]
 
362
 
 
363
        ################################### SKIPPED
 
364
        # Weave.get doesn't trap this anymore
 
365
        return 
 
366
 
 
367
 
 
368
        self.assertRaises(WeaveFormatError,
 
369
                          k.get,
 
370
                          0)
 
371
 
 
372
 
 
373
class BadInsert(TestBase):
 
374
    """Test that we trap an insert which should not occur."""
 
375
    def runTest(self):
 
376
        k = Weave()
 
377
 
 
378
        k._parents = [frozenset(),
 
379
                frozenset([0]),
 
380
                frozenset([0]),
 
381
                frozenset([0,1,2]),
 
382
                ]
 
383
        k._weave = [('{', 0),
 
384
                'foo {',
 
385
                ('{', 1),
 
386
                '  added in version 1',
 
387
                ('{', 1),
 
388
                '  more in 1',
 
389
                ('}', 1),
 
390
                ('}', 1),
 
391
                ('}', 0)]
 
392
 
 
393
 
 
394
        # this is not currently enforced by get
 
395
        return  ##########################################
 
396
 
 
397
        self.assertRaises(WeaveFormatError,
 
398
                          k.get,
 
399
                          0)
 
400
 
 
401
        self.assertRaises(WeaveFormatError,
 
402
                          k.get,
 
403
                          1)
 
404
 
 
405
 
 
406
class InsertNested(TestBase):
 
407
    """Insertion with nested instructions."""
 
408
    def runTest(self):
 
409
        k = Weave()
 
410
 
 
411
        k._parents = [frozenset(),
 
412
                frozenset([0]),
 
413
                frozenset([0]),
 
414
                frozenset([0,1,2]),
 
415
                ]
 
416
        k._weave = [('{', 0),
 
417
                'foo {',
 
418
                ('{', 1),
 
419
                '  added in version 1',
 
420
                ('{', 2),
 
421
                '  added in v2',
 
422
                ('}', 2),
 
423
                '  also from v1',
 
424
                ('}', 1),
 
425
                '}',
 
426
                ('}', 0)]
 
427
 
 
428
        self.assertEqual(k.get(0),
 
429
                         ['foo {',
 
430
                          '}'])
 
431
 
 
432
        self.assertEqual(k.get(1),
 
433
                         ['foo {',
 
434
                          '  added in version 1',
 
435
                          '  also from v1',
 
436
                          '}'])
 
437
                       
 
438
        self.assertEqual(k.get(2),
 
439
                         ['foo {',
 
440
                          '  added in v2',
 
441
                          '}'])
 
442
 
 
443
        self.assertEqual(k.get(3),
 
444
                         ['foo {',
 
445
                          '  added in version 1',
 
446
                          '  added in v2',
 
447
                          '  also from v1',
 
448
                          '}'])
 
449
                         
 
450
 
 
451
 
 
452
class DeleteLines2(TestBase):
 
453
    """Test recording revisions that delete lines.
 
454
 
 
455
    This relies on the weave having a way to represent lines knocked
 
456
    out by a later revision."""
 
457
    def runTest(self):
 
458
        k = Weave()
 
459
 
 
460
        k.add('text0', [], ["line the first",
 
461
                   "line 2",
 
462
                   "line 3",
 
463
                   "fine"])
 
464
 
 
465
        self.assertEqual(len(k.get(0)), 4)
 
466
 
 
467
        k.add('text1', [0], ["line the first",
 
468
                   "fine"])
 
469
 
 
470
        self.assertEqual(k.get(1),
 
471
                         ["line the first",
 
472
                          "fine"])
 
473
 
 
474
        self.assertEqual(k.annotate(1),
 
475
                         [(0, "line the first"),
 
476
                          (0, "fine")])
 
477
 
 
478
 
 
479
 
 
480
class IncludeVersions(TestBase):
 
481
    """Check texts that are stored across multiple revisions.
 
482
 
 
483
    Here we manually create a weave with particular encoding and make
 
484
    sure it unpacks properly.
 
485
 
 
486
    Text 0 includes nothing; text 1 includes text 0 and adds some
 
487
    lines.
 
488
    """
 
489
 
 
490
    def runTest(self):
 
491
        k = Weave()
 
492
 
 
493
        k._parents = [frozenset(), frozenset([0])]
 
494
        k._weave = [('{', 0),
 
495
                "first line",
 
496
                ('}', 0),
 
497
                ('{', 1),
 
498
                "second line",
 
499
                ('}', 1)]
 
500
 
 
501
        self.assertEqual(k.get(1),
 
502
                         ["first line",
 
503
                          "second line"])
 
504
 
 
505
        self.assertEqual(k.get(0),
 
506
                         ["first line"])
 
507
 
 
508
 
 
509
class DivergedIncludes(TestBase):
 
510
    """Weave with two diverged texts based on version 0.
 
511
    """
 
512
    def runTest(self):
 
513
        k = Weave()
 
514
 
 
515
        k._parents = [frozenset(),
 
516
                frozenset([0]),
 
517
                frozenset([0]),
 
518
                ]
 
519
        k._weave = [('{', 0),
 
520
                "first line",
 
521
                ('}', 0),
 
522
                ('{', 1),
 
523
                "second line",
 
524
                ('}', 1),
 
525
                ('{', 2),
 
526
                "alternative second line",
 
527
                ('}', 2),                
 
528
                ]
 
529
 
 
530
        self.assertEqual(k.get(0),
 
531
                         ["first line"])
 
532
 
 
533
        self.assertEqual(k.get(1),
 
534
                         ["first line",
 
535
                          "second line"])
 
536
 
 
537
        self.assertEqual(k.get(2),
 
538
                         ["first line",
 
539
                          "alternative second line"])
 
540
 
 
541
        self.assertEqual(list(k.inclusions([2])),
 
542
                         [0, 2])
 
543
 
 
544
 
 
545
 
 
546
class ReplaceLine(TestBase):
 
547
    def runTest(self):
 
548
        k = Weave()
 
549
 
 
550
        text0 = ['cheddar', 'stilton', 'gruyere']
 
551
        text1 = ['cheddar', 'blue vein', 'neufchatel', 'chevre']
 
552
        
 
553
        k.add('text0', [], text0)
 
554
        k.add('text1', [0], text1)
 
555
 
 
556
        self.log('k._weave=' + pformat(k._weave))
 
557
 
 
558
        self.assertEqual(k.get(0), text0)
 
559
        self.assertEqual(k.get(1), text1)
 
560
 
 
561
 
 
562
 
 
563
class Merge(TestBase):
 
564
    """Storage of versions that merge diverged parents"""
 
565
    def runTest(self):
 
566
        k = Weave()
 
567
 
 
568
        texts = [['header'],
 
569
                 ['header', '', 'line from 1'],
 
570
                 ['header', '', 'line from 2', 'more from 2'],
 
571
                 ['header', '', 'line from 1', 'fixup line', 'line from 2'],
 
572
                 ]
 
573
 
 
574
        k.add('text0', [], texts[0])
 
575
        k.add('text1', [0], texts[1])
 
576
        k.add('text2', [0], texts[2])
 
577
        k.add('merge', [0, 1, 2], texts[3])
 
578
 
 
579
        for i, t in enumerate(texts):
 
580
            self.assertEqual(k.get(i), t)
 
581
 
 
582
        self.assertEqual(k.annotate(3),
 
583
                         [(0, 'header'),
 
584
                          (1, ''),
 
585
                          (1, 'line from 1'),
 
586
                          (3, 'fixup line'),
 
587
                          (2, 'line from 2'),
 
588
                          ])
 
589
 
 
590
        self.assertEqual(list(k.inclusions([3])),
 
591
                         [0, 1, 2, 3])
 
592
 
 
593
        self.log('k._weave=' + pformat(k._weave))
 
594
 
 
595
        self.check_read_write(k)
 
596
 
 
597
 
 
598
class Conflicts(TestBase):
 
599
    """Test detection of conflicting regions during a merge.
 
600
 
 
601
    A base version is inserted, then two descendents try to
 
602
    insert different lines in the same place.  These should be
 
603
    reported as a possible conflict and forwarded to the user."""
 
604
    def runTest(self):
 
605
        return  # NOT RUN
 
606
        k = Weave()
 
607
 
 
608
        k.add([], ['aaa', 'bbb'])
 
609
        k.add([0], ['aaa', '111', 'bbb'])
 
610
        k.add([1], ['aaa', '222', 'bbb'])
 
611
 
 
612
        merged = k.merge([1, 2])
 
613
 
 
614
        self.assertEquals([[['aaa']],
 
615
                           [['111'], ['222']],
 
616
                           [['bbb']]])
 
617
 
 
618
 
 
619
 
 
620
class NonConflict(TestBase):
 
621
    """Two descendants insert compatible changes.
 
622
 
 
623
    No conflict should be reported."""
 
624
    def runTest(self):
 
625
        return  # NOT RUN
 
626
        k = Weave()
 
627
 
 
628
        k.add([], ['aaa', 'bbb'])
 
629
        k.add([0], ['111', 'aaa', 'ccc', 'bbb'])
 
630
        k.add([1], ['aaa', 'ccc', 'bbb', '222'])
 
631
 
 
632
    
 
633
    
 
634
 
 
635
 
 
636
class AutoMerge(TestBase):
 
637
    def runTest(self):
 
638
        k = Weave()
 
639
 
 
640
        texts = [['header', 'aaa', 'bbb'],
 
641
                 ['header', 'aaa', 'line from 1', 'bbb'],
 
642
                 ['header', 'aaa', 'bbb', 'line from 2', 'more from 2'],
 
643
                 ]
 
644
 
 
645
        k.add('text0', [], texts[0])
 
646
        k.add('text1', [0], texts[1])
 
647
        k.add('text2', [0], texts[2])
 
648
 
 
649
        self.log('k._weave=' + pformat(k._weave))
 
650
 
 
651
        m = list(k.mash_iter([0, 1, 2]))
 
652
 
 
653
        self.assertEqual(m,
 
654
                         ['header', 'aaa',
 
655
                          'line from 1',
 
656
                          'bbb',
 
657
                          'line from 2', 'more from 2'])
 
658
        
 
659
 
 
660
 
 
661
class Khayyam(TestBase):
 
662
    """Test changes to multi-line texts, and read/write"""
 
663
    def runTest(self):
 
664
        rawtexts = [
 
665
            """A Book of Verses underneath the Bough,
 
666
            A Jug of Wine, a Loaf of Bread, -- and Thou
 
667
            Beside me singing in the Wilderness --
 
668
            Oh, Wilderness were Paradise enow!""",
 
669
            
 
670
            """A Book of Verses underneath the Bough,
 
671
            A Jug of Wine, a Loaf of Bread, -- and Thou
 
672
            Beside me singing in the Wilderness --
 
673
            Oh, Wilderness were Paradise now!""",
 
674
 
 
675
            """A Book of poems underneath the tree,
 
676
            A Jug of Wine, a Loaf of Bread,
 
677
            and Thou
 
678
            Beside me singing in the Wilderness --
 
679
            Oh, Wilderness were Paradise now!
 
680
 
 
681
            -- O. Khayyam""",
 
682
 
 
683
            """A Book of Verses underneath the Bough,
 
684
            A Jug of Wine, a Loaf of Bread,
 
685
            and Thou
 
686
            Beside me singing in the Wilderness --
 
687
            Oh, Wilderness were Paradise now!""",
 
688
            ]
 
689
        texts = [[l.strip() for l in t.split('\n')] for t in rawtexts]
 
690
 
 
691
        k = Weave()
 
692
        parents = set()
 
693
        i = 0
 
694
        for t in texts:
 
695
            ver = k.add('text%d' % i,
 
696
                        list(parents), t)
 
697
            parents.add(ver)
 
698
            i += 1
 
699
 
 
700
        self.log("k._weave=" + pformat(k._weave))
 
701
 
 
702
        for i, t in enumerate(texts):
 
703
            self.assertEqual(k.get(i), t)
 
704
 
 
705
        self.check_read_write(k)
 
706
 
 
707
 
 
708
 
 
709
class MergeCases(TestBase):
 
710
    def doMerge(self, base, a, b, mp):
 
711
        from cStringIO import StringIO
 
712
        from textwrap import dedent
 
713
 
 
714
        def addcrlf(x):
 
715
            return x + '\n'
 
716
        
 
717
        w = Weave()
 
718
        w.add('text0', [], map(addcrlf, base))
 
719
        w.add('text1', [0], map(addcrlf, a))
 
720
        w.add('text2', [0], map(addcrlf, b))
 
721
 
 
722
        self.log('weave is:')
 
723
        tmpf = StringIO()
 
724
        write_weave(w, tmpf)
 
725
        self.log(tmpf.getvalue())
 
726
 
 
727
        self.log('merge plan:')
 
728
        p = list(w.plan_merge(1, 2))
 
729
        for state, line in p:
 
730
            if line:
 
731
                self.log('%12s | %s' % (state, line[:-1]))
 
732
 
 
733
        self.log('merge:')
 
734
        mt = StringIO()
 
735
        mt.writelines(w.weave_merge(p))
 
736
        mt.seek(0)
 
737
        self.log(mt.getvalue())
 
738
 
 
739
        mp = map(addcrlf, mp)
 
740
        self.assertEqual(mt.readlines(), mp)
 
741
        
 
742
        
 
743
    def testOneInsert(self):
 
744
        self.doMerge([],
 
745
                     ['aa'],
 
746
                     [],
 
747
                     ['aa'])
 
748
 
 
749
    def testSeparateInserts(self):
 
750
        self.doMerge(['aaa', 'bbb', 'ccc'],
 
751
                     ['aaa', 'xxx', 'bbb', 'ccc'],
 
752
                     ['aaa', 'bbb', 'yyy', 'ccc'],
 
753
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
 
754
 
 
755
    def testSameInsert(self):
 
756
        self.doMerge(['aaa', 'bbb', 'ccc'],
 
757
                     ['aaa', 'xxx', 'bbb', 'ccc'],
 
758
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'],
 
759
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
 
760
 
 
761
    def testOverlappedInsert(self):
 
762
        self.doMerge(['aaa', 'bbb'],
 
763
                     ['aaa', 'xxx', 'yyy', 'bbb'],
 
764
                     ['aaa', 'xxx', 'bbb'],
 
765
                     ['aaa', '<<<<', 'xxx', 'yyy', '====', 'xxx', '>>>>', 'bbb'])
 
766
 
 
767
        # really it ought to reduce this to 
 
768
        # ['aaa', 'xxx', 'yyy', 'bbb']
 
769
 
 
770
 
 
771
    def testClashReplace(self):
 
772
        self.doMerge(['aaa'],
 
773
                     ['xxx'],
 
774
                     ['yyy', 'zzz'],
 
775
                     ['<<<<', 'xxx', '====', 'yyy', 'zzz', '>>>>'])
 
776
 
 
777
    def testNonClashInsert(self):
 
778
        self.doMerge(['aaa'],
 
779
                     ['xxx', 'aaa'],
 
780
                     ['yyy', 'zzz'],
 
781
                     ['<<<<', 'xxx', 'aaa', '====', 'yyy', 'zzz', '>>>>'])
 
782
 
 
783
        self.doMerge(['aaa'],
 
784
                     ['aaa'],
 
785
                     ['yyy', 'zzz'],
 
786
                     ['yyy', 'zzz'])
 
787
 
 
788
 
 
789
    def testDeleteAndModify(self):
 
790
        """Clashing delete and modification.
 
791
 
 
792
        If one side modifies a region and the other deletes it then
 
793
        there should be a conflict with one side blank.
 
794
        """
 
795
 
 
796
        #######################################
 
797
        # skippd, not working yet
 
798
        return
 
799
        
 
800
        self.doMerge(['aaa', 'bbb', 'ccc'],
 
801
                     ['aaa', 'ddd', 'ccc'],
 
802
                     ['aaa', 'ccc'],
 
803
                     ['<<<<', 'aaa', '====', '>>>>', 'ccc'])
 
804
    
 
805
 
 
806
 
 
807
if __name__ == '__main__':
 
808
    import sys
 
809
    import unittest
 
810
    sys.exit(unittest.main())
 
811