~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_versionedfile.py

Merge from bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
84
84
    def test_adds_with_parent_texts(self):
85
85
        f = self.get_file()
86
86
        parent_texts = {}
87
 
        parent_texts['r0'] = f.add_lines('r0', [], ['a\n', 'b\n'])
 
87
        _, _, parent_texts['r0'] = f.add_lines('r0', [], ['a\n', 'b\n'])
88
88
        try:
89
 
            parent_texts['r1'] = f.add_lines_with_ghosts('r1',
90
 
                                                         ['r0', 'ghost'], 
91
 
                                                         ['b\n', 'c\n'],
92
 
                                                         parent_texts=parent_texts)
 
89
            _, _, parent_texts['r1'] = f.add_lines_with_ghosts('r1',
 
90
                ['r0', 'ghost'], ['b\n', 'c\n'], parent_texts=parent_texts)
93
91
        except NotImplementedError:
94
92
            # if the format doesn't support ghosts, just add normally.
95
 
            parent_texts['r1'] = f.add_lines('r1',
96
 
                                             ['r0'], 
97
 
                                             ['b\n', 'c\n'],
98
 
                                             parent_texts=parent_texts)
 
93
            _, _, parent_texts['r1'] = f.add_lines('r1',
 
94
                ['r0'], ['b\n', 'c\n'], parent_texts=parent_texts)
99
95
        f.add_lines('r2', ['r1'], ['c\n', 'd\n'], parent_texts=parent_texts)
100
96
        self.assertNotEqual(None, parent_texts['r0'])
101
97
        self.assertNotEqual(None, parent_texts['r1'])
141
137
        vf.add_lines('1', [], ['a\n'])
142
138
        vf.add_lines('2', ['1'], ['a\n', 'a\n', 'a\n'],
143
139
                     left_matching_blocks=[(0, 0, 1), (1, 3, 0)])
144
 
        self.assertEqual([(1, 1, 2, [('2', 'a\n'), ('2', 'a\n')])],
145
 
                         vf.get_delta('2')[3])
 
140
        self.assertEqual(['a\n', 'a\n', 'a\n'], vf.get_lines('2'))
146
141
        vf.add_lines('3', ['1'], ['a\n', 'a\n', 'a\n'],
147
142
                     left_matching_blocks=[(0, 2, 1), (1, 3, 0)])
148
 
        self.assertEqual([(0, 0, 2, [('3', 'a\n'), ('3', 'a\n')])],
149
 
                         vf.get_delta('3')[3])
 
143
        self.assertEqual(['a\n', 'a\n', 'a\n'], vf.get_lines('3'))
150
144
 
151
145
    def test_inline_newline_throws(self):
152
146
        # \r characters are not permitted in lines being added
168
162
        self.assertRaises(errors.ReservedId,
169
163
            vf.add_lines, 'a:', [], ['a\n', 'b\n', 'c\n'])
170
164
 
171
 
        self.assertRaises(errors.ReservedId,
172
 
            vf.add_delta, 'a:', [], None, 'sha1', False, ((0, 0, 0, []),))
 
165
    def test_add_lines_nostoresha(self):
 
166
        """When nostore_sha is supplied using old content raises."""
 
167
        vf = self.get_file()
 
168
        empty_text = ('a', [])
 
169
        sample_text_nl = ('b', ["foo\n", "bar\n"])
 
170
        sample_text_no_nl = ('c', ["foo\n", "bar"])
 
171
        shas = []
 
172
        for version, lines in (empty_text, sample_text_nl, sample_text_no_nl):
 
173
            sha, _, _ = vf.add_lines(version, [], lines)
 
174
            shas.append(sha)
 
175
        # we now have a copy of all the lines in the vf.
 
176
        for sha, (version, lines) in zip(
 
177
            shas, (empty_text, sample_text_nl, sample_text_no_nl)):
 
178
            self.assertRaises(errors.ExistingContent,
 
179
                vf.add_lines, version + "2", [], lines,
 
180
                nostore_sha=sha)
 
181
            # and no new version should have been added.
 
182
            self.assertRaises(errors.RevisionNotPresent, vf.get_lines,
 
183
                version + "2")
 
184
 
 
185
    def test_add_lines_with_ghosts_nostoresha(self):
 
186
        """When nostore_sha is supplied using old content raises."""
 
187
        vf = self.get_file()
 
188
        empty_text = ('a', [])
 
189
        sample_text_nl = ('b', ["foo\n", "bar\n"])
 
190
        sample_text_no_nl = ('c', ["foo\n", "bar"])
 
191
        shas = []
 
192
        for version, lines in (empty_text, sample_text_nl, sample_text_no_nl):
 
193
            sha, _, _ = vf.add_lines(version, [], lines)
 
194
            shas.append(sha)
 
195
        # we now have a copy of all the lines in the vf.
 
196
        # is the test applicable to this vf implementation?
 
197
        try:
 
198
            vf.add_lines_with_ghosts('d', [], [])
 
199
        except NotImplementedError:
 
200
            raise TestSkipped("add_lines_with_ghosts is optional")
 
201
        for sha, (version, lines) in zip(
 
202
            shas, (empty_text, sample_text_nl, sample_text_no_nl)):
 
203
            self.assertRaises(errors.ExistingContent,
 
204
                vf.add_lines_with_ghosts, version + "2", [], lines,
 
205
                nostore_sha=sha)
 
206
            # and no new version should have been added.
 
207
            self.assertRaises(errors.RevisionNotPresent, vf.get_lines,
 
208
                version + "2")
 
209
 
 
210
    def test_add_lines_return_value(self):
 
211
        # add_lines should return the sha1 and the text size.
 
212
        vf = self.get_file()
 
213
        empty_text = ('a', [])
 
214
        sample_text_nl = ('b', ["foo\n", "bar\n"])
 
215
        sample_text_no_nl = ('c', ["foo\n", "bar"])
 
216
        # check results for the three cases:
 
217
        for version, lines in (empty_text, sample_text_nl, sample_text_no_nl):
 
218
            # the first two elements are the same for all versioned files:
 
219
            # - the digest and the size of the text. For some versioned files
 
220
            #   additional data is returned in additional tuple elements.
 
221
            result = vf.add_lines(version, [], lines)
 
222
            self.assertEqual(3, len(result))
 
223
            self.assertEqual((osutils.sha_strings(lines), sum(map(len, lines))),
 
224
                result[0:2])
 
225
        # parents should not affect the result:
 
226
        lines = sample_text_nl[1]
 
227
        self.assertEqual((osutils.sha_strings(lines), sum(map(len, lines))),
 
228
            vf.add_lines('d', ['b', 'c'], lines)[0:2])
173
229
 
174
230
    def test_get_reserved(self):
175
231
        vf = self.get_file()
176
 
        self.assertRaises(errors.ReservedId, vf.get_delta, 'b:')
177
232
        self.assertRaises(errors.ReservedId, vf.get_texts, ['b:'])
178
233
        self.assertRaises(errors.ReservedId, vf.get_lines, 'b:')
179
234
        self.assertRaises(errors.ReservedId, vf.get_text, 'b:')
180
235
 
181
 
    def test_get_delta(self):
182
 
        f = self.get_file()
183
 
        sha1s = self._setup_for_deltas(f)
184
 
        expected_delta = (None, '6bfa09d82ce3e898ad4641ae13dd4fdb9cf0d76b', False, 
185
 
                          [(0, 0, 1, [('base', 'line\n')])])
186
 
        self.assertEqual(expected_delta, f.get_delta('base'))
187
 
        next_parent = 'base'
188
 
        text_name = 'chain1-'
189
 
        for depth in range(26):
190
 
            new_version = text_name + '%s' % depth
191
 
            expected_delta = (next_parent, sha1s[depth], 
192
 
                              False,
193
 
                              [(depth + 1, depth + 1, 1, [(new_version, 'line\n')])])
194
 
            self.assertEqual(expected_delta, f.get_delta(new_version))
195
 
            next_parent = new_version
196
 
        next_parent = 'base'
197
 
        text_name = 'chain2-'
198
 
        for depth in range(26):
199
 
            new_version = text_name + '%s' % depth
200
 
            expected_delta = (next_parent, sha1s[depth], False,
201
 
                              [(depth + 1, depth + 1, 1, [(new_version, 'line\n')])])
202
 
            self.assertEqual(expected_delta, f.get_delta(new_version))
203
 
            next_parent = new_version
204
 
        # smoke test for eol support
205
 
        expected_delta = ('base', '264f39cab871e4cfd65b3a002f7255888bb5ed97', True, [])
206
 
        self.assertEqual(['line'], f.get_lines('noeol'))
207
 
        self.assertEqual(expected_delta, f.get_delta('noeol'))
208
 
 
209
 
    def test_get_deltas(self):
210
 
        f = self.get_file()
211
 
        sha1s = self._setup_for_deltas(f)
212
 
        deltas = f.get_deltas(f.versions())
213
 
        expected_delta = (None, '6bfa09d82ce3e898ad4641ae13dd4fdb9cf0d76b', False, 
214
 
                          [(0, 0, 1, [('base', 'line\n')])])
215
 
        self.assertEqual(expected_delta, deltas['base'])
216
 
        next_parent = 'base'
217
 
        text_name = 'chain1-'
218
 
        for depth in range(26):
219
 
            new_version = text_name + '%s' % depth
220
 
            expected_delta = (next_parent, sha1s[depth], 
221
 
                              False,
222
 
                              [(depth + 1, depth + 1, 1, [(new_version, 'line\n')])])
223
 
            self.assertEqual(expected_delta, deltas[new_version])
224
 
            next_parent = new_version
225
 
        next_parent = 'base'
226
 
        text_name = 'chain2-'
227
 
        for depth in range(26):
228
 
            new_version = text_name + '%s' % depth
229
 
            expected_delta = (next_parent, sha1s[depth], False,
230
 
                              [(depth + 1, depth + 1, 1, [(new_version, 'line\n')])])
231
 
            self.assertEqual(expected_delta, deltas[new_version])
232
 
            next_parent = new_version
233
 
        # smoke tests for eol support
234
 
        expected_delta = ('base', '264f39cab871e4cfd65b3a002f7255888bb5ed97', True, [])
235
 
        self.assertEqual(['line'], f.get_lines('noeol'))
236
 
        self.assertEqual(expected_delta, deltas['noeol'])
237
 
        # smoke tests for eol support - two noeol in a row same content
238
 
        expected_deltas = (('noeol', '3ad7ee82dbd8f29ecba073f96e43e414b3f70a4d', True, 
239
 
                          [(0, 1, 2, [('noeolsecond', 'line\n'), ('noeolsecond', 'line\n')])]),
240
 
                          ('noeol', '3ad7ee82dbd8f29ecba073f96e43e414b3f70a4d', True, 
241
 
                           [(0, 0, 1, [('noeolsecond', 'line\n')]), (1, 1, 0, [])]))
242
 
        self.assertEqual(['line\n', 'line'], f.get_lines('noeolsecond'))
243
 
        self.assertTrue(deltas['noeolsecond'] in expected_deltas)
244
 
        # two no-eol in a row, different content
245
 
        expected_delta = ('noeolsecond', '8bb553a84e019ef1149db082d65f3133b195223b', True, 
246
 
                          [(1, 2, 1, [('noeolnotshared', 'phone\n')])])
247
 
        self.assertEqual(['line\n', 'phone'], f.get_lines('noeolnotshared'))
248
 
        self.assertEqual(expected_delta, deltas['noeolnotshared'])
249
 
        # eol folling a no-eol with content change
250
 
        expected_delta = ('noeol', 'a61f6fb6cfc4596e8d88c34a308d1e724caf8977', False, 
251
 
                          [(0, 1, 1, [('eol', 'phone\n')])])
252
 
        self.assertEqual(['phone\n'], f.get_lines('eol'))
253
 
        self.assertEqual(expected_delta, deltas['eol'])
254
 
        # eol folling a no-eol with content change
255
 
        expected_delta = ('noeol', '6bfa09d82ce3e898ad4641ae13dd4fdb9cf0d76b', False, 
256
 
                          [(0, 1, 1, [('eolline', 'line\n')])])
257
 
        self.assertEqual(['line\n'], f.get_lines('eolline'))
258
 
        self.assertEqual(expected_delta, deltas['eolline'])
259
 
        # eol with no parents
260
 
        expected_delta = (None, '264f39cab871e4cfd65b3a002f7255888bb5ed97', True, 
261
 
                          [(0, 0, 1, [('noeolbase', 'line\n')])])
262
 
        self.assertEqual(['line'], f.get_lines('noeolbase'))
263
 
        self.assertEqual(expected_delta, deltas['noeolbase'])
264
 
        # eol with two parents, in inverse insertion order
265
 
        expected_deltas = (('noeolbase', '264f39cab871e4cfd65b3a002f7255888bb5ed97', True,
266
 
                            [(0, 1, 1, [('eolbeforefirstparent', 'line\n')])]),
267
 
                           ('noeolbase', '264f39cab871e4cfd65b3a002f7255888bb5ed97', True,
268
 
                            [(0, 1, 1, [('eolbeforefirstparent', 'line\n')])]))
269
 
        self.assertEqual(['line'], f.get_lines('eolbeforefirstparent'))
270
 
        #self.assertTrue(deltas['eolbeforefirstparent'] in expected_deltas)
271
 
 
272
236
    def test_make_mpdiffs(self):
273
237
        from bzrlib import multiparent
274
238
        vf = self.get_file('foo')
282
246
                                 new_vf.get_text(version))
283
247
 
284
248
    def _setup_for_deltas(self, f):
285
 
        self.assertRaises(errors.RevisionNotPresent, f.get_delta, 'base')
 
249
        self.assertFalse(f.has_version('base'))
286
250
        # add texts that should trip the knit maximum delta chain threshold
287
251
        # as well as doing parallel chains of data in knits.
288
252
        # this is done by two chains of 25 insertions
351
315
            next_parent = new_version
352
316
        return sha1s
353
317
 
354
 
    def test_add_delta(self):
355
 
        # tests for the add-delta facility.
356
 
        # at this point, optimising for speed, we assume no checks when deltas are inserted.
357
 
        # this may need to be revisited.
358
 
        source = self.get_file('source')
359
 
        source.add_lines('base', [], ['line\n'])
360
 
        next_parent = 'base'
361
 
        text_name = 'chain1-'
362
 
        text = ['line\n']
363
 
        for depth in range(26):
364
 
            new_version = text_name + '%s' % depth
365
 
            text = text + ['line\n']
366
 
            source.add_lines(new_version, [next_parent], text)
367
 
            next_parent = new_version
368
 
        next_parent = 'base'
369
 
        text_name = 'chain2-'
370
 
        text = ['line\n']
371
 
        for depth in range(26):
372
 
            new_version = text_name + '%s' % depth
373
 
            text = text + ['line\n']
374
 
            source.add_lines(new_version, [next_parent], text)
375
 
            next_parent = new_version
376
 
        source.add_lines('noeol', ['base'], ['line'])
377
 
        
378
 
        target = self.get_file('target')
379
 
        for version in source.versions():
380
 
            parent, sha1, noeol, delta = source.get_delta(version)
381
 
            target.add_delta(version,
382
 
                             source.get_parents(version),
383
 
                             parent,
384
 
                             sha1,
385
 
                             noeol,
386
 
                             delta)
387
 
        self.assertRaises(RevisionAlreadyPresent,
388
 
                          target.add_delta, 'base', [], None, '', False, [])
389
 
        for version in source.versions():
390
 
            self.assertEqual(source.get_lines(version),
391
 
                             target.get_lines(version))
392
 
 
393
318
    def test_ancestry(self):
394
319
        f = self.get_file()
395
320
        self.assertEqual([], f.get_ancestry([]))
424
349
    def test_mutate_after_finish(self):
425
350
        f = self.get_file()
426
351
        f.transaction_finished()
427
 
        self.assertRaises(errors.OutSideTransaction, f.add_delta, '', [], '', '', False, [])
428
352
        self.assertRaises(errors.OutSideTransaction, f.add_lines, '', [], [])
429
353
        self.assertRaises(errors.OutSideTransaction, f.add_lines_with_ghosts, '', [], [])
430
 
        self.assertRaises(errors.OutSideTransaction, f.fix_parents, '', [])
431
354
        self.assertRaises(errors.OutSideTransaction, f.join, '')
432
355
        self.assertRaises(errors.OutSideTransaction, f.clone_text, 'base', 'bar', ['foo'])
433
356
        
674
597
        self.assertTrue(lines['child\n'] > 0)
675
598
        self.assertTrue(lines['otherchild\n'] > 0)
676
599
 
677
 
    def test_fix_parents(self):
678
 
        # some versioned files allow incorrect parents to be corrected after
679
 
        # insertion - this may not fix ancestry..
680
 
        # if they do not supported, they just do not implement it.
681
 
        # we test this as an interface test to ensure that those that *do*
682
 
        # implementent it get it right.
683
 
        vf = self.get_file()
684
 
        vf.add_lines('notbase', [], [])
685
 
        vf.add_lines('base', [], [])
686
 
        try:
687
 
            vf.fix_parents('notbase', ['base'])
688
 
        except NotImplementedError:
689
 
            return
690
 
        self.assertEqual(['base'], vf.get_parents('notbase'))
691
 
        # open again, check it stuck.
692
 
        vf = self.get_file()
693
 
        self.assertEqual(['base'], vf.get_parents('notbase'))
694
 
 
695
 
    def test_fix_parents_with_ghosts(self):
696
 
        # when fixing parents, ghosts that are listed should not be ghosts
697
 
        # anymore.
698
 
        vf = self.get_file()
699
 
 
700
 
        try:
701
 
            vf.add_lines_with_ghosts('notbase', ['base', 'stillghost'], [])
702
 
        except NotImplementedError:
703
 
            return
704
 
        vf.add_lines('base', [], [])
705
 
        vf.fix_parents('notbase', ['base', 'stillghost'])
706
 
        self.assertEqual(['base'], vf.get_parents('notbase'))
707
 
        # open again, check it stuck.
708
 
        vf = self.get_file()
709
 
        self.assertEqual(['base'], vf.get_parents('notbase'))
710
 
        # and check the ghosts
711
 
        self.assertEqual(['base', 'stillghost'],
712
 
                         vf.get_parents_with_ghosts('notbase'))
713
 
 
714
600
    def test_add_lines_with_ghosts(self):
715
601
        # some versioned file formats allow lines to be added with parent
716
602
        # information that is > than that in the format. Formats that do
796
682
        factory = self.get_factory()
797
683
        vf = factory('id', transport, 0777, create=True, access_mode='w')
798
684
        vf = factory('id', transport, access_mode='r')
799
 
        self.assertRaises(errors.ReadOnlyError, vf.add_delta, '', [], '', '', False, [])
800
685
        self.assertRaises(errors.ReadOnlyError, vf.add_lines, 'base', [], [])
801
686
        self.assertRaises(errors.ReadOnlyError,
802
687
                          vf.add_lines_with_ghosts,
803
688
                          'base',
804
689
                          [],
805
690
                          [])
806
 
        self.assertRaises(errors.ReadOnlyError, vf.fix_parents, 'base', [])
807
691
        self.assertRaises(errors.ReadOnlyError, vf.join, 'base')
808
692
        self.assertRaises(errors.ReadOnlyError, vf.clone_text, 'base', 'bar', ['foo'])
809
693