/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: Jelmer Vernooij
  • Date: 2020-02-18 01:57:45 UTC
  • mto: This revision was merged to the branch mainline in revision 7493.
  • Revision ID: jelmer@jelmer.uk-20200218015745-q2ss9tsk74h4nh61
drop use of future.

Show diffs side-by-side

added added

removed removed

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