~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/test_weave.py

  • Committer: Martin Pool
  • Date: 2005-09-16 07:38:10 UTC
  • Revision ID: mbp@sourcefrog.net-20050916073810-1f358be198c9ed91
- fix bug in committing files that are renamed but not modified

- add test for this

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