/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tests/test_weave.py

  • Committer: Martin
  • Date: 2017-06-10 01:57:00 UTC
  • mto: This revision was merged to the branch mainline in revision 6679.
  • Revision ID: gzlist@googlemail.com-20170610015700-o3xeuyaqry2obiay
Go back to native str for urls and many other py3 changes

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005-2011, 2016 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
 
 
18
# TODO: tests regarding version names
 
19
# TODO: rbc 20050108 test that join does not leave an inconsistent weave
 
20
#       if it fails.
 
21
 
 
22
"""test suite for weave algorithm"""
 
23
 
 
24
from pprint import pformat
 
25
 
 
26
from .. import (
 
27
    errors,
 
28
    )
 
29
from ..osutils import sha_string
 
30
from ..sixish import (
 
31
    BytesIO,
 
32
    )
 
33
from . import TestCase, TestCaseInTempDir
 
34
from ..weave import Weave, WeaveFormatError
 
35
from ..weavefile import write_weave, read_weave
 
36
 
 
37
 
 
38
# texts for use in testing
 
39
TEXT_0 = ["Hello world"]
 
40
TEXT_1 = ["Hello world",
 
41
          "A second line"]
 
42
 
 
43
 
 
44
class TestBase(TestCase):
 
45
 
 
46
    def check_read_write(self, k):
 
47
        """Check the weave k can be written & re-read."""
 
48
        from tempfile import TemporaryFile
 
49
        tf = TemporaryFile()
 
50
 
 
51
        write_weave(k, tf)
 
52
        tf.seek(0)
 
53
        k2 = read_weave(tf)
 
54
 
 
55
        if k != k2:
 
56
            tf.seek(0)
 
57
            self.log('serialized weave:')
 
58
            self.log(tf.read())
 
59
 
 
60
            self.log('')
 
61
            self.log('parents: %s' % (k._parents == k2._parents))
 
62
            self.log('         %r' % k._parents)
 
63
            self.log('         %r' % k2._parents)
 
64
            self.log('')
 
65
            self.fail('read/write check failed')
 
66
 
 
67
 
 
68
class WeaveContains(TestBase):
 
69
    """Weave __contains__ operator"""
 
70
 
 
71
    def runTest(self):
 
72
        k = Weave(get_scope=lambda:None)
 
73
        self.assertFalse('foo' in k)
 
74
        k.add_lines('foo', [], TEXT_1)
 
75
        self.assertTrue('foo' in k)
 
76
 
 
77
 
 
78
class Easy(TestBase):
 
79
 
 
80
    def runTest(self):
 
81
        k = Weave()
 
82
 
 
83
 
 
84
class AnnotateOne(TestBase):
 
85
 
 
86
    def runTest(self):
 
87
        k = Weave()
 
88
        k.add_lines('text0', [], TEXT_0)
 
89
        self.assertEqual(k.annotate('text0'),
 
90
                         [('text0', TEXT_0[0])])
 
91
 
 
92
 
 
93
class InvalidAdd(TestBase):
 
94
    """Try to use invalid version number during add."""
 
95
 
 
96
    def runTest(self):
 
97
        k = Weave()
 
98
 
 
99
        self.assertRaises(errors.RevisionNotPresent,
 
100
                          k.add_lines,
 
101
                          'text0',
 
102
                          ['69'],
 
103
                          ['new text!'])
 
104
 
 
105
 
 
106
class RepeatedAdd(TestBase):
 
107
    """Add the same version twice; harmless."""
 
108
 
 
109
    def test_duplicate_add(self):
 
110
        k = Weave()
 
111
        idx = k.add_lines('text0', [], TEXT_0)
 
112
        idx2 = k.add_lines('text0', [], TEXT_0)
 
113
        self.assertEqual(idx, idx2)
 
114
 
 
115
 
 
116
class InvalidRepeatedAdd(TestBase):
 
117
 
 
118
    def runTest(self):
 
119
        k = Weave()
 
120
        k.add_lines('basis', [], TEXT_0)
 
121
        idx = k.add_lines('text0', [], TEXT_0)
 
122
        self.assertRaises(errors.RevisionAlreadyPresent,
 
123
                          k.add_lines,
 
124
                          'text0',
 
125
                          [],
 
126
                          ['not the same text'])
 
127
        self.assertRaises(errors.RevisionAlreadyPresent,
 
128
                          k.add_lines,
 
129
                          'text0',
 
130
                          ['basis'],         # not the right parents
 
131
                          TEXT_0)
 
132
 
 
133
 
 
134
class InsertLines(TestBase):
 
135
    """Store a revision that adds one line to the original.
 
136
 
 
137
    Look at the annotations to make sure that the first line is matched
 
138
    and not stored repeatedly."""
 
139
    def runTest(self):
 
140
        k = Weave()
 
141
 
 
142
        k.add_lines('text0', [], ['line 1'])
 
143
        k.add_lines('text1', ['text0'], ['line 1', 'line 2'])
 
144
 
 
145
        self.assertEqual(k.annotate('text0'),
 
146
                         [('text0', 'line 1')])
 
147
 
 
148
        self.assertEqual(k.get_lines(1),
 
149
                         ['line 1',
 
150
                          'line 2'])
 
151
 
 
152
        self.assertEqual(k.annotate('text1'),
 
153
                         [('text0', 'line 1'),
 
154
                          ('text1', 'line 2')])
 
155
 
 
156
        k.add_lines('text2', ['text0'], ['line 1', 'diverged line'])
 
157
 
 
158
        self.assertEqual(k.annotate('text2'),
 
159
                         [('text0', 'line 1'),
 
160
                          ('text2', 'diverged line')])
 
161
 
 
162
        text3 = ['line 1', 'middle line', 'line 2']
 
163
        k.add_lines('text3',
 
164
              ['text0', 'text1'],
 
165
              text3)
 
166
 
 
167
        # self.log("changes to text3: " + pformat(list(k._delta(set([0, 1]), text3))))
 
168
 
 
169
        self.log("k._weave=" + pformat(k._weave))
 
170
 
 
171
        self.assertEqual(k.annotate('text3'),
 
172
                         [('text0', 'line 1'),
 
173
                          ('text3', 'middle line'),
 
174
                          ('text1', 'line 2')])
 
175
 
 
176
        # now multiple insertions at different places
 
177
        k.add_lines('text4',
 
178
              ['text0', 'text1', 'text3'],
 
179
              ['line 1', 'aaa', 'middle line', 'bbb', 'line 2', 'ccc'])
 
180
 
 
181
        self.assertEqual(k.annotate('text4'),
 
182
                         [('text0', 'line 1'),
 
183
                          ('text4', 'aaa'),
 
184
                          ('text3', 'middle line'),
 
185
                          ('text4', 'bbb'),
 
186
                          ('text1', 'line 2'),
 
187
                          ('text4', 'ccc')])
 
188
 
 
189
 
 
190
class DeleteLines(TestBase):
 
191
    """Deletion of lines from existing text.
 
192
 
 
193
    Try various texts all based on a common ancestor."""
 
194
    def runTest(self):
 
195
        k = Weave()
 
196
 
 
197
        base_text = ['one', 'two', 'three', 'four']
 
198
 
 
199
        k.add_lines('text0', [], base_text)
 
200
 
 
201
        texts = [['one', 'two', 'three'],
 
202
                 ['two', 'three', 'four'],
 
203
                 ['one', 'four'],
 
204
                 ['one', 'two', 'three', 'four'],
 
205
                 ]
 
206
 
 
207
        i = 1
 
208
        for t in texts:
 
209
            ver = k.add_lines('text%d' % i,
 
210
                        ['text0'], t)
 
211
            i += 1
 
212
 
 
213
        self.log('final weave:')
 
214
        self.log('k._weave=' + pformat(k._weave))
 
215
 
 
216
        for i in range(len(texts)):
 
217
            self.assertEqual(k.get_lines(i+1),
 
218
                             texts[i])
 
219
 
 
220
 
 
221
class SuicideDelete(TestBase):
 
222
    """Invalid weave which tries to add and delete simultaneously."""
 
223
    def runTest(self):
 
224
        k = Weave()
 
225
 
 
226
        k._parents = [(),
 
227
                ]
 
228
        k._weave = [('{', 0),
 
229
                'first line',
 
230
                ('[', 0),
 
231
                'deleted in 0',
 
232
                (']', 0),
 
233
                ('}', 0),
 
234
                ]
 
235
        ################################### SKIPPED
 
236
        # Weave.get doesn't trap this anymore
 
237
        return
 
238
 
 
239
        self.assertRaises(WeaveFormatError,
 
240
                          k.get_lines,
 
241
                          0)
 
242
 
 
243
 
 
244
class CannedDelete(TestBase):
 
245
    """Unpack canned weave with deleted lines."""
 
246
    def runTest(self):
 
247
        k = Weave()
 
248
 
 
249
        k._parents = [(),
 
250
                frozenset([0]),
 
251
                ]
 
252
        k._weave = [('{', 0),
 
253
                'first line',
 
254
                ('[', 1),
 
255
                'line to be deleted',
 
256
                (']', 1),
 
257
                'last line',
 
258
                ('}', 0),
 
259
                ]
 
260
        k._sha1s = [sha_string('first lineline to be deletedlast line')
 
261
                  , sha_string('first linelast line')]
 
262
 
 
263
        self.assertEqual(k.get_lines(0),
 
264
                         ['first line',
 
265
                          'line to be deleted',
 
266
                          'last line',
 
267
                          ])
 
268
 
 
269
        self.assertEqual(k.get_lines(1),
 
270
                         ['first line',
 
271
                          'last line',
 
272
                          ])
 
273
 
 
274
 
 
275
class CannedReplacement(TestBase):
 
276
    """Unpack canned weave with deleted lines."""
 
277
    def runTest(self):
 
278
        k = Weave()
 
279
 
 
280
        k._parents = [frozenset(),
 
281
                frozenset([0]),
 
282
                ]
 
283
        k._weave = [('{', 0),
 
284
                'first line',
 
285
                ('[', 1),
 
286
                'line to be deleted',
 
287
                (']', 1),
 
288
                ('{', 1),
 
289
                'replacement line',
 
290
                ('}', 1),
 
291
                'last line',
 
292
                ('}', 0),
 
293
                ]
 
294
        k._sha1s = [sha_string('first lineline to be deletedlast line')
 
295
                  , sha_string('first linereplacement linelast line')]
 
296
 
 
297
        self.assertEqual(k.get_lines(0),
 
298
                         ['first line',
 
299
                          'line to be deleted',
 
300
                          'last line',
 
301
                          ])
 
302
 
 
303
        self.assertEqual(k.get_lines(1),
 
304
                         ['first line',
 
305
                          'replacement line',
 
306
                          'last line',
 
307
                          ])
 
308
 
 
309
 
 
310
class BadWeave(TestBase):
 
311
    """Test that we trap an insert which should not occur."""
 
312
    def runTest(self):
 
313
        k = Weave()
 
314
 
 
315
        k._parents = [frozenset(),
 
316
                ]
 
317
        k._weave = ['bad line',
 
318
                ('{', 0),
 
319
                'foo {',
 
320
                ('{', 1),
 
321
                '  added in version 1',
 
322
                ('{', 2),
 
323
                '  added in v2',
 
324
                ('}', 2),
 
325
                '  also from v1',
 
326
                ('}', 1),
 
327
                '}',
 
328
                ('}', 0)]
 
329
 
 
330
        ################################### SKIPPED
 
331
        # Weave.get doesn't trap this anymore
 
332
        return
 
333
 
 
334
 
 
335
        self.assertRaises(WeaveFormatError,
 
336
                          k.get,
 
337
                          0)
 
338
 
 
339
 
 
340
class BadInsert(TestBase):
 
341
    """Test that we trap an insert which should not occur."""
 
342
    def runTest(self):
 
343
        k = Weave()
 
344
 
 
345
        k._parents = [frozenset(),
 
346
                frozenset([0]),
 
347
                frozenset([0]),
 
348
                frozenset([0,1,2]),
 
349
                ]
 
350
        k._weave = [('{', 0),
 
351
                'foo {',
 
352
                ('{', 1),
 
353
                '  added in version 1',
 
354
                ('{', 1),
 
355
                '  more in 1',
 
356
                ('}', 1),
 
357
                ('}', 1),
 
358
                ('}', 0)]
 
359
 
 
360
 
 
361
        # this is not currently enforced by get
 
362
        return  ##########################################
 
363
 
 
364
        self.assertRaises(WeaveFormatError,
 
365
                          k.get,
 
366
                          0)
 
367
 
 
368
        self.assertRaises(WeaveFormatError,
 
369
                          k.get,
 
370
                          1)
 
371
 
 
372
 
 
373
class InsertNested(TestBase):
 
374
    """Insertion with nested instructions."""
 
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
                ('{', 2),
 
388
                '  added in v2',
 
389
                ('}', 2),
 
390
                '  also from v1',
 
391
                ('}', 1),
 
392
                '}',
 
393
                ('}', 0)]
 
394
 
 
395
        k._sha1s = [sha_string('foo {}')
 
396
                  , sha_string('foo {  added in version 1  also from v1}')
 
397
                  , sha_string('foo {  added in v2}')
 
398
                  , sha_string('foo {  added in version 1  added in v2  also from v1}')
 
399
                  ]
 
400
 
 
401
        self.assertEqual(k.get_lines(0),
 
402
                         ['foo {',
 
403
                          '}'])
 
404
 
 
405
        self.assertEqual(k.get_lines(1),
 
406
                         ['foo {',
 
407
                          '  added in version 1',
 
408
                          '  also from v1',
 
409
                          '}'])
 
410
 
 
411
        self.assertEqual(k.get_lines(2),
 
412
                         ['foo {',
 
413
                          '  added in v2',
 
414
                          '}'])
 
415
 
 
416
        self.assertEqual(k.get_lines(3),
 
417
                         ['foo {',
 
418
                          '  added in version 1',
 
419
                          '  added in v2',
 
420
                          '  also from v1',
 
421
                          '}'])
 
422
 
 
423
 
 
424
class DeleteLines2(TestBase):
 
425
    """Test recording revisions that delete lines.
 
426
 
 
427
    This relies on the weave having a way to represent lines knocked
 
428
    out by a later revision."""
 
429
    def runTest(self):
 
430
        k = Weave()
 
431
 
 
432
        k.add_lines('text0', [], ["line the first",
 
433
                   "line 2",
 
434
                   "line 3",
 
435
                   "fine"])
 
436
 
 
437
        self.assertEqual(len(k.get_lines(0)), 4)
 
438
 
 
439
        k.add_lines('text1', ['text0'], ["line the first",
 
440
                   "fine"])
 
441
 
 
442
        self.assertEqual(k.get_lines(1),
 
443
                         ["line the first",
 
444
                          "fine"])
 
445
 
 
446
        self.assertEqual(k.annotate('text1'),
 
447
                         [('text0', "line the first"),
 
448
                          ('text0', "fine")])
 
449
 
 
450
 
 
451
class IncludeVersions(TestBase):
 
452
    """Check texts that are stored across multiple revisions.
 
453
 
 
454
    Here we manually create a weave with particular encoding and make
 
455
    sure it unpacks properly.
 
456
 
 
457
    Text 0 includes nothing; text 1 includes text 0 and adds some
 
458
    lines.
 
459
    """
 
460
 
 
461
    def runTest(self):
 
462
        k = Weave()
 
463
 
 
464
        k._parents = [frozenset(), frozenset([0])]
 
465
        k._weave = [('{', 0),
 
466
                "first line",
 
467
                ('}', 0),
 
468
                ('{', 1),
 
469
                "second line",
 
470
                ('}', 1)]
 
471
 
 
472
        k._sha1s = [sha_string('first line')
 
473
                  , sha_string('first linesecond line')]
 
474
 
 
475
        self.assertEqual(k.get_lines(1),
 
476
                         ["first line",
 
477
                          "second line"])
 
478
 
 
479
        self.assertEqual(k.get_lines(0),
 
480
                         ["first line"])
 
481
 
 
482
 
 
483
class DivergedIncludes(TestBase):
 
484
    """Weave with two diverged texts based on version 0.
 
485
    """
 
486
    def runTest(self):
 
487
        # FIXME make the weave, dont poke at it.
 
488
        k = Weave()
 
489
 
 
490
        k._names = ['0', '1', '2']
 
491
        k._name_map = {'0':0, '1':1, '2':2}
 
492
        k._parents = [frozenset(),
 
493
                frozenset([0]),
 
494
                frozenset([0]),
 
495
                ]
 
496
        k._weave = [('{', 0),
 
497
                "first line",
 
498
                ('}', 0),
 
499
                ('{', 1),
 
500
                "second line",
 
501
                ('}', 1),
 
502
                ('{', 2),
 
503
                "alternative second line",
 
504
                ('}', 2),
 
505
                ]
 
506
 
 
507
        k._sha1s = [sha_string('first line')
 
508
                  , sha_string('first linesecond line')
 
509
                  , sha_string('first linealternative second line')]
 
510
 
 
511
        self.assertEqual(k.get_lines(0),
 
512
                         ["first line"])
 
513
 
 
514
        self.assertEqual(k.get_lines(1),
 
515
                         ["first line",
 
516
                          "second line"])
 
517
 
 
518
        self.assertEqual(k.get_lines('2'),
 
519
                         ["first line",
 
520
                          "alternative second line"])
 
521
 
 
522
        self.assertEqual(list(k.get_ancestry(['2'])),
 
523
                         ['0', '2'])
 
524
 
 
525
 
 
526
class ReplaceLine(TestBase):
 
527
    def runTest(self):
 
528
        k = Weave()
 
529
 
 
530
        text0 = ['cheddar', 'stilton', 'gruyere']
 
531
        text1 = ['cheddar', 'blue vein', 'neufchatel', 'chevre']
 
532
 
 
533
        k.add_lines('text0', [], text0)
 
534
        k.add_lines('text1', ['text0'], text1)
 
535
 
 
536
        self.log('k._weave=' + pformat(k._weave))
 
537
 
 
538
        self.assertEqual(k.get_lines(0), text0)
 
539
        self.assertEqual(k.get_lines(1), text1)
 
540
 
 
541
 
 
542
class Merge(TestBase):
 
543
    """Storage of versions that merge diverged parents"""
 
544
 
 
545
    def runTest(self):
 
546
        k = Weave()
 
547
 
 
548
        texts = [['header'],
 
549
                 ['header', '', 'line from 1'],
 
550
                 ['header', '', 'line from 2', 'more from 2'],
 
551
                 ['header', '', 'line from 1', 'fixup line', 'line from 2'],
 
552
                 ]
 
553
 
 
554
        k.add_lines('text0', [], texts[0])
 
555
        k.add_lines('text1', ['text0'], texts[1])
 
556
        k.add_lines('text2', ['text0'], texts[2])
 
557
        k.add_lines('merge', ['text0', 'text1', 'text2'], texts[3])
 
558
 
 
559
        for i, t in enumerate(texts):
 
560
            self.assertEqual(k.get_lines(i), t)
 
561
 
 
562
        self.assertEqual(k.annotate('merge'),
 
563
                         [('text0', 'header'),
 
564
                          ('text1', ''),
 
565
                          ('text1', 'line from 1'),
 
566
                          ('merge', 'fixup line'),
 
567
                          ('text2', 'line from 2'),
 
568
                          ])
 
569
 
 
570
        self.assertEqual(list(k.get_ancestry(['merge'])),
 
571
                         ['text0', 'text1', 'text2', 'merge'])
 
572
 
 
573
        self.log('k._weave=' + pformat(k._weave))
 
574
 
 
575
        self.check_read_write(k)
 
576
 
 
577
 
 
578
class Conflicts(TestBase):
 
579
    """Test detection of conflicting regions during a merge.
 
580
 
 
581
    A base version is inserted, then two descendents try to
 
582
    insert different lines in the same place.  These should be
 
583
    reported as a possible conflict and forwarded to the user."""
 
584
    def runTest(self):
 
585
        return  # NOT RUN
 
586
        k = Weave()
 
587
 
 
588
        k.add_lines([], ['aaa', 'bbb'])
 
589
        k.add_lines([0], ['aaa', '111', 'bbb'])
 
590
        k.add_lines([1], ['aaa', '222', 'bbb'])
 
591
 
 
592
        merged = k.merge([1, 2])
 
593
 
 
594
        self.assertEqual([[['aaa']],
 
595
                           [['111'], ['222']],
 
596
                           [['bbb']]])
 
597
 
 
598
 
 
599
class NonConflict(TestBase):
 
600
    """Two descendants insert compatible changes.
 
601
 
 
602
    No conflict should be reported."""
 
603
    def runTest(self):
 
604
        return  # NOT RUN
 
605
        k = Weave()
 
606
 
 
607
        k.add_lines([], ['aaa', 'bbb'])
 
608
        k.add_lines([0], ['111', 'aaa', 'ccc', 'bbb'])
 
609
        k.add_lines([1], ['aaa', 'ccc', 'bbb', '222'])
 
610
 
 
611
 
 
612
class Khayyam(TestBase):
 
613
    """Test changes to multi-line texts, and read/write"""
 
614
 
 
615
    def test_multi_line_merge(self):
 
616
        rawtexts = [
 
617
            """A Book of Verses underneath the Bough,
 
618
            A Jug of Wine, a Loaf of Bread, -- and Thou
 
619
            Beside me singing in the Wilderness --
 
620
            Oh, Wilderness were Paradise enow!""",
 
621
 
 
622
            """A Book of Verses underneath the Bough,
 
623
            A Jug of Wine, a Loaf of Bread, -- and Thou
 
624
            Beside me singing in the Wilderness --
 
625
            Oh, Wilderness were Paradise now!""",
 
626
 
 
627
            """A Book of poems underneath the tree,
 
628
            A Jug of Wine, a Loaf of Bread,
 
629
            and Thou
 
630
            Beside me singing in the Wilderness --
 
631
            Oh, Wilderness were Paradise now!
 
632
 
 
633
            -- O. Khayyam""",
 
634
 
 
635
            """A Book of Verses underneath the Bough,
 
636
            A Jug of Wine, a Loaf of Bread,
 
637
            and Thou
 
638
            Beside me singing in the Wilderness --
 
639
            Oh, Wilderness were Paradise now!""",
 
640
            ]
 
641
        texts = [[l.strip() for l in t.split('\n')] for t in rawtexts]
 
642
 
 
643
        k = Weave()
 
644
        parents = set()
 
645
        i = 0
 
646
        for t in texts:
 
647
            ver = k.add_lines('text%d' % i,
 
648
                        list(parents), t)
 
649
            parents.add('text%d' % i)
 
650
            i += 1
 
651
 
 
652
        self.log("k._weave=" + pformat(k._weave))
 
653
 
 
654
        for i, t in enumerate(texts):
 
655
            self.assertEqual(k.get_lines(i), t)
 
656
 
 
657
        self.check_read_write(k)
 
658
 
 
659
 
 
660
class JoinWeavesTests(TestBase):
 
661
 
 
662
    def setUp(self):
 
663
        super(JoinWeavesTests, self).setUp()
 
664
        self.weave1 = Weave()
 
665
        self.lines1 = ['hello\n']
 
666
        self.lines3 = ['hello\n', 'cruel\n', 'world\n']
 
667
        self.weave1.add_lines('v1', [], self.lines1)
 
668
        self.weave1.add_lines('v2', ['v1'], ['hello\n', 'world\n'])
 
669
        self.weave1.add_lines('v3', ['v2'], self.lines3)
 
670
 
 
671
    def test_written_detection(self):
 
672
        # Test detection of weave file corruption.
 
673
        #
 
674
        # Make sure that we can detect if a weave file has
 
675
        # been corrupted. This doesn't test all forms of corruption,
 
676
        # but it at least helps verify the data you get, is what you want.
 
677
 
 
678
        w = Weave()
 
679
        w.add_lines('v1', [], ['hello\n'])
 
680
        w.add_lines('v2', ['v1'], ['hello\n', 'there\n'])
 
681
 
 
682
        tmpf = BytesIO()
 
683
        write_weave(w, tmpf)
 
684
 
 
685
        # Because we are corrupting, we need to make sure we have the exact text
 
686
        self.assertEqual('# bzr weave file v5\n'
 
687
                          'i\n1 f572d396fae9206628714fb2ce00f72e94f2258f\nn v1\n\n'
 
688
                          'i 0\n1 90f265c6e75f1c8f9ab76dcf85528352c5f215ef\nn v2\n\n'
 
689
                          'w\n{ 0\n. hello\n}\n{ 1\n. there\n}\nW\n',
 
690
                          tmpf.getvalue())
 
691
 
 
692
        # Change a single letter
 
693
        tmpf = BytesIO(b'# bzr weave file v5\n'
 
694
                       b'i\n1 f572d396fae9206628714fb2ce00f72e94f2258f\nn v1\n\n'
 
695
                       b'i 0\n1 90f265c6e75f1c8f9ab76dcf85528352c5f215ef\nn v2\n\n'
 
696
                       b'w\n{ 0\n. hello\n}\n{ 1\n. There\n}\nW\n')
 
697
 
 
698
        w = read_weave(tmpf)
 
699
 
 
700
        self.assertEqual('hello\n', w.get_text('v1'))
 
701
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_text, 'v2')
 
702
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_lines, 'v2')
 
703
        self.assertRaises(errors.WeaveInvalidChecksum, w.check)
 
704
 
 
705
        # Change the sha checksum
 
706
        tmpf = BytesIO(b'# bzr weave file v5\n'
 
707
                       b'i\n1 f572d396fae9206628714fb2ce00f72e94f2258f\nn v1\n\n'
 
708
                       b'i 0\n1 f0f265c6e75f1c8f9ab76dcf85528352c5f215ef\nn v2\n\n'
 
709
                       b'w\n{ 0\n. hello\n}\n{ 1\n. there\n}\nW\n')
 
710
 
 
711
        w = read_weave(tmpf)
 
712
 
 
713
        self.assertEqual('hello\n', w.get_text('v1'))
 
714
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_text, 'v2')
 
715
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_lines, 'v2')
 
716
        self.assertRaises(errors.WeaveInvalidChecksum, w.check)
 
717
 
 
718
 
 
719
class TestWeave(TestCase):
 
720
 
 
721
    def test_allow_reserved_false(self):
 
722
        w = Weave('name', allow_reserved=False)
 
723
        # Add lines is checked at the WeaveFile level, not at the Weave level
 
724
        w.add_lines('name:', [], TEXT_1)
 
725
        # But get_lines is checked at this level
 
726
        self.assertRaises(errors.ReservedId, w.get_lines, 'name:')
 
727
 
 
728
    def test_allow_reserved_true(self):
 
729
        w = Weave('name', allow_reserved=True)
 
730
        w.add_lines('name:', [], TEXT_1)
 
731
        self.assertEqual(TEXT_1, w.get_lines('name:'))
 
732
 
 
733
 
 
734
class InstrumentedWeave(Weave):
 
735
    """Keep track of how many times functions are called."""
 
736
 
 
737
    def __init__(self, weave_name=None):
 
738
        self._extract_count = 0
 
739
        Weave.__init__(self, weave_name=weave_name)
 
740
 
 
741
    def _extract(self, versions):
 
742
        self._extract_count += 1
 
743
        return Weave._extract(self, versions)
 
744
 
 
745
 
 
746
class TestNeedsReweave(TestCase):
 
747
    """Internal corner cases for when reweave is needed."""
 
748
 
 
749
    def test_compatible_parents(self):
 
750
        w1 = Weave('a')
 
751
        my_parents = {1, 2, 3}
 
752
        # subsets are ok
 
753
        self.assertTrue(w1._compatible_parents(my_parents, {3}))
 
754
        # same sets
 
755
        self.assertTrue(w1._compatible_parents(my_parents, set(my_parents)))
 
756
        # same empty corner case
 
757
        self.assertTrue(w1._compatible_parents(set(), set()))
 
758
        # other cannot contain stuff my_parents does not
 
759
        self.assertFalse(w1._compatible_parents(set(), {1}))
 
760
        self.assertFalse(w1._compatible_parents(my_parents, {1, 2, 3, 4}))
 
761
        self.assertFalse(w1._compatible_parents(my_parents, {4}))
 
762
 
 
763
 
 
764
class TestWeaveFile(TestCaseInTempDir):
 
765
 
 
766
    def test_empty_file(self):
 
767
        f = open('empty.weave', 'wb+')
 
768
        try:
 
769
            self.assertRaises(errors.WeaveFormatError,
 
770
                              read_weave, f)
 
771
        finally:
 
772
            f.close()