~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/test_weave.py

  • Committer: Robert Collins
  • Date: 2005-09-29 02:01:49 UTC
  • Revision ID: robertc@robertcollins.net-20050929020149-1ff16722c6a01b2c
reenable remotebranch tests

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