/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_knit.py

  • Committer: Jelmer Vernooij
  • Date: 2017-12-21 16:44:19 UTC
  • mto: This revision was merged to the branch mainline in revision 6842.
  • Revision ID: jelmer@jelmer.uk-20171221164419-wn90kwu2uismpznf
Revert custom gmtime implementation without tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-2011 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
16
16
 
17
17
"""Tests for Knit data structure"""
18
18
 
19
 
from cStringIO import StringIO
20
 
import difflib
21
19
import gzip
22
20
import sys
23
21
 
24
 
from bzrlib import (
 
22
from .. import (
25
23
    errors,
26
 
    generate_ids,
27
 
    knit,
28
24
    multiparent,
29
25
    osutils,
 
26
    tests,
 
27
    transport,
 
28
    )
 
29
from ..bzr import (
 
30
    knit,
30
31
    pack,
31
 
    tests,
32
 
    )
33
 
from bzrlib.errors import (
34
 
    RevisionAlreadyPresent,
35
 
    KnitHeaderError,
36
 
    RevisionNotPresent,
37
 
    NoSuchFile,
38
 
    )
39
 
from bzrlib.index import *
40
 
from bzrlib.knit import (
 
32
    )
 
33
from ..bzr.index import *
 
34
from ..bzr.knit import (
41
35
    AnnotatedKnitContent,
42
36
    KnitContent,
43
 
    KnitSequenceMatcher,
 
37
    KnitCorrupt,
 
38
    KnitDataStreamIncompatible,
 
39
    KnitDataStreamUnknown,
 
40
    KnitHeaderError,
 
41
    KnitIndexUnknownMethod,
44
42
    KnitVersionedFiles,
45
43
    PlainKnitContent,
46
44
    _VFContentMapGenerator,
47
 
    _DirectPackAccess,
48
45
    _KndxIndex,
49
46
    _KnitGraphIndex,
50
47
    _KnitKeyAccess,
51
48
    make_file_factory,
52
49
    )
53
 
from bzrlib.repofmt import pack_repo
54
 
from bzrlib.tests import (
55
 
    Feature,
56
 
    KnownFailure,
 
50
from ..patiencediff import PatienceSequenceMatcher
 
51
from ..bzr import (
 
52
    knitpack_repo,
 
53
    pack_repo,
 
54
    )
 
55
from ..sixish import (
 
56
    BytesIO,
 
57
    )
 
58
from . import (
57
59
    TestCase,
58
60
    TestCaseWithMemoryTransport,
59
61
    TestCaseWithTransport,
60
62
    TestNotApplicable,
61
63
    )
62
 
from bzrlib.transport import get_transport
63
 
from bzrlib.transport.memory import MemoryTransport
64
 
from bzrlib.tuned_gzip import GzipFile
65
 
from bzrlib.versionedfile import (
 
64
from ..bzr.versionedfile import (
66
65
    AbsentContentFactory,
67
66
    ConstantMapper,
68
67
    network_bytes_to_kind_and_offset,
69
68
    RecordingVersionedFilesDecorator,
70
69
    )
71
 
 
72
 
 
73
 
compiled_knit_feature = tests.ModuleAvailableFeature(
74
 
                            'bzrlib._knit_load_data_pyx')
 
70
from . import (
 
71
    features,
 
72
    )
 
73
 
 
74
 
 
75
compiled_knit_feature = features.ModuleAvailableFeature(
 
76
    'breezy.bzr._knit_load_data_pyx')
 
77
 
 
78
 
 
79
class ErrorTests(TestCase):
 
80
 
 
81
    def test_knit_data_stream_incompatible(self):
 
82
        error = KnitDataStreamIncompatible(
 
83
            'stream format', 'target format')
 
84
        self.assertEqual('Cannot insert knit data stream of format '
 
85
                         '"stream format" into knit of format '
 
86
                         '"target format".', str(error))
 
87
 
 
88
    def test_knit_data_stream_unknown(self):
 
89
        error = KnitDataStreamUnknown(
 
90
            'stream format')
 
91
        self.assertEqual('Cannot parse knit data stream of format '
 
92
                         '"stream format".', str(error))
 
93
 
 
94
    def test_knit_header_error(self):
 
95
        error = KnitHeaderError('line foo\n', 'path/to/file')
 
96
        self.assertEqual("Knit header error: 'line foo\\n' unexpected"
 
97
                         " for file \"path/to/file\".", str(error))
 
98
 
 
99
    def test_knit_index_unknown_method(self):
 
100
        error = KnitIndexUnknownMethod('http://host/foo.kndx',
 
101
                                       ['bad', 'no-eol'])
 
102
        self.assertEqual("Knit index http://host/foo.kndx does not have a"
 
103
                         " known method in options: ['bad', 'no-eol']",
 
104
                         str(error))
75
105
 
76
106
 
77
107
class KnitContentTestsMixin(object):
106
136
        line_delta = source_content.line_delta(target_content)
107
137
        delta_blocks = list(KnitContent.get_line_delta_blocks(line_delta,
108
138
            source_lines, target_lines))
109
 
        matcher = KnitSequenceMatcher(None, source_lines, target_lines)
110
 
        matcher_blocks = list(list(matcher.get_matching_blocks()))
 
139
        matcher = PatienceSequenceMatcher(None, source_lines, target_lines)
 
140
        matcher_blocks = list(matcher.get_matching_blocks())
111
141
        self.assertEqual(matcher_blocks, delta_blocks)
112
142
 
113
143
    def test_get_line_delta_blocks(self):
206
236
        content1 = self._make_content([("", "a"), ("", "b")])
207
237
        content2 = self._make_content([("", "a"), ("", "a"), ("", "c")])
208
238
        it = content1.line_delta_iter(content2)
209
 
        self.assertEqual(it.next(), (1, 2, 2, ["a", "c"]))
210
 
        self.assertRaises(StopIteration, it.next)
 
239
        self.assertEqual(next(it), (1, 2, 2, ["a", "c"]))
 
240
        self.assertRaises(StopIteration, next, it)
211
241
 
212
242
 
213
243
class TestAnnotatedKnitContent(TestCase, KnitContentTestsMixin):
233
263
        content1 = self._make_content([("", "a"), ("", "b")])
234
264
        content2 = self._make_content([("", "a"), ("", "a"), ("", "c")])
235
265
        it = content1.line_delta_iter(content2)
236
 
        self.assertEqual(it.next(), (1, 2, 2, [("", "a"), ("", "c")]))
237
 
        self.assertRaises(StopIteration, it.next)
 
266
        self.assertEqual(next(it), (1, 2, 2, [("", "a"), ("", "c")]))
 
267
        self.assertRaises(StopIteration, next, it)
238
268
 
239
269
 
240
270
class MockTransport(object):
247
277
 
248
278
    def get(self, filename):
249
279
        if self.file_lines is None:
250
 
            raise NoSuchFile(filename)
 
280
            raise errors.NoSuchFile(filename)
251
281
        else:
252
 
            return StringIO("\n".join(self.file_lines))
 
282
            return BytesIO(b"\n".join(self.file_lines))
253
283
 
254
284
    def readv(self, relpath, offsets):
255
285
        fp = self.get(relpath)
333
363
            transport.append_bytes(packname, bytes)
334
364
        writer = pack.ContainerWriter(write_data)
335
365
        writer.begin()
336
 
        access = _DirectPackAccess({})
 
366
        access = pack_repo._DirectPackAccess({})
337
367
        access.set_writer(writer, index, (transport, packname))
338
368
        return access, writer
339
369
 
346
376
        writer.end()
347
377
        return memos
348
378
 
 
379
    def test_pack_collection_pack_retries(self):
 
380
        """An explicit pack of a pack collection succeeds even when a
 
381
        concurrent pack happens.
 
382
        """
 
383
        builder = self.make_branch_builder('.')
 
384
        builder.start_series()
 
385
        builder.build_snapshot(None, [
 
386
            ('add', ('', 'root-id', 'directory', None)),
 
387
            ('add', ('file', 'file-id', 'file', 'content\nrev 1\n')),
 
388
            ], revision_id='rev-1')
 
389
        builder.build_snapshot(['rev-1'], [
 
390
            ('modify', ('file-id', 'content\nrev 2\n')),
 
391
            ], revision_id='rev-2')
 
392
        builder.build_snapshot(['rev-2'], [
 
393
            ('modify', ('file-id', 'content\nrev 3\n')),
 
394
            ], revision_id='rev-3')
 
395
        self.addCleanup(builder.finish_series)
 
396
        b = builder.get_branch()
 
397
        self.addCleanup(b.lock_write().unlock)
 
398
        repo = b.repository
 
399
        collection = repo._pack_collection
 
400
        # Concurrently repack the repo.
 
401
        reopened_repo = repo.controldir.open_repository()
 
402
        reopened_repo.pack()
 
403
        # Pack the new pack.
 
404
        collection.pack()
 
405
 
349
406
    def make_vf_for_retrying(self):
350
407
        """Create 3 packs and a reload function.
351
408
 
358
415
        """
359
416
        builder = self.make_branch_builder('.', format="1.9")
360
417
        builder.start_series()
361
 
        builder.build_snapshot('rev-1', None, [
 
418
        builder.build_snapshot(None, [
362
419
            ('add', ('', 'root-id', 'directory', None)),
363
420
            ('add', ('file', 'file-id', 'file', 'content\nrev 1\n')),
364
 
            ])
365
 
        builder.build_snapshot('rev-2', ['rev-1'], [
 
421
            ], revision_id='rev-1')
 
422
        builder.build_snapshot(['rev-1'], [
366
423
            ('modify', ('file-id', 'content\nrev 2\n')),
367
 
            ])
368
 
        builder.build_snapshot('rev-3', ['rev-2'], [
 
424
            ], revision_id='rev-2')
 
425
        builder.build_snapshot(['rev-2'], [
369
426
            ('modify', ('file-id', 'content\nrev 3\n')),
370
 
            ])
 
427
            ], revision_id='rev-3')
371
428
        builder.finish_series()
372
429
        b = builder.get_branch()
373
430
        b.lock_write()
378
435
        collection = repo._pack_collection
379
436
        collection.ensure_loaded()
380
437
        orig_packs = collection.packs
381
 
        packer = pack_repo.Packer(collection, orig_packs, '.testpack')
 
438
        packer = knitpack_repo.KnitPacker(collection, orig_packs, '.testpack')
382
439
        new_pack = packer.pack()
383
440
        # forget about the new pack
384
441
        collection.reset()
420
477
        # populated
421
478
        try:
422
479
            raise _TestException('foobar')
423
 
        except _TestException, e:
 
480
        except _TestException as e:
424
481
            retry_exc = errors.RetryWithNewPacks(None, reload_occurred=False,
425
482
                                                 exc_info=sys.exc_info())
 
483
        # GZ 2010-08-10: Cycle with exc_info affects 3 tests
426
484
        return retry_exc
427
485
 
428
486
    def test_read_from_several_packs(self):
437
495
        memos.extend(access.add_raw_records([('key', 5)], 'alpha'))
438
496
        writer.end()
439
497
        transport = self.get_transport()
440
 
        access = _DirectPackAccess({"FOO":(transport, 'packfile'),
 
498
        access = pack_repo._DirectPackAccess({"FOO":(transport, 'packfile'),
441
499
            "FOOBAR":(transport, 'pack2'),
442
500
            "BAZ":(transport, 'pack3')})
443
501
        self.assertEqual(['1234567890', '12345', 'alpha'],
453
511
 
454
512
    def test_set_writer(self):
455
513
        """The writer should be settable post construction."""
456
 
        access = _DirectPackAccess({})
 
514
        access = pack_repo._DirectPackAccess({})
457
515
        transport = self.get_transport()
458
516
        packname = 'packfile'
459
517
        index = 'foo'
471
529
        transport = self.get_transport()
472
530
        reload_called, reload_func = self.make_reload_func()
473
531
        # Note that the index key has changed from 'foo' to 'bar'
474
 
        access = _DirectPackAccess({'bar':(transport, 'packname')},
 
532
        access = pack_repo._DirectPackAccess({'bar':(transport, 'packname')},
475
533
                                   reload_func=reload_func)
476
534
        e = self.assertListRaises(errors.RetryWithNewPacks,
477
535
                                  access.get_raw_records, memos)
486
544
        memos = self.make_pack_file()
487
545
        transport = self.get_transport()
488
546
        # Note that the index key has changed from 'foo' to 'bar'
489
 
        access = _DirectPackAccess({'bar':(transport, 'packname')})
 
547
        access = pack_repo._DirectPackAccess({'bar':(transport, 'packname')})
490
548
        e = self.assertListRaises(KeyError, access.get_raw_records, memos)
491
549
 
492
550
    def test_missing_file_raises_retry(self):
494
552
        transport = self.get_transport()
495
553
        reload_called, reload_func = self.make_reload_func()
496
554
        # Note that the 'filename' has been changed to 'different-packname'
497
 
        access = _DirectPackAccess({'foo':(transport, 'different-packname')},
498
 
                                   reload_func=reload_func)
 
555
        access = pack_repo._DirectPackAccess(
 
556
            {'foo':(transport, 'different-packname')},
 
557
            reload_func=reload_func)
499
558
        e = self.assertListRaises(errors.RetryWithNewPacks,
500
559
                                  access.get_raw_records, memos)
501
560
        # The file has gone missing, so we assume we need to reload
509
568
        memos = self.make_pack_file()
510
569
        transport = self.get_transport()
511
570
        # Note that the 'filename' has been changed to 'different-packname'
512
 
        access = _DirectPackAccess({'foo':(transport, 'different-packname')})
 
571
        access = pack_repo._DirectPackAccess(
 
572
            {'foo': (transport, 'different-packname')})
513
573
        e = self.assertListRaises(errors.NoSuchFile,
514
574
                                  access.get_raw_records, memos)
515
575
 
519
579
        failing_transport = MockReadvFailingTransport(
520
580
                                [transport.get_bytes('packname')])
521
581
        reload_called, reload_func = self.make_reload_func()
522
 
        access = _DirectPackAccess({'foo':(failing_transport, 'packname')},
523
 
                                   reload_func=reload_func)
 
582
        access = pack_repo._DirectPackAccess(
 
583
            {'foo': (failing_transport, 'packname')},
 
584
            reload_func=reload_func)
524
585
        # Asking for a single record will not trigger the Mock failure
525
586
        self.assertEqual(['1234567890'],
526
587
            list(access.get_raw_records(memos[:1])))
542
603
        failing_transport = MockReadvFailingTransport(
543
604
                                [transport.get_bytes('packname')])
544
605
        reload_called, reload_func = self.make_reload_func()
545
 
        access = _DirectPackAccess({'foo':(failing_transport, 'packname')})
 
606
        access = pack_repo._DirectPackAccess(
 
607
            {'foo':(failing_transport, 'packname')})
546
608
        # Asking for a single record will not trigger the Mock failure
547
609
        self.assertEqual(['1234567890'],
548
610
            list(access.get_raw_records(memos[:1])))
553
615
                                  access.get_raw_records, memos)
554
616
 
555
617
    def test_reload_or_raise_no_reload(self):
556
 
        access = _DirectPackAccess({}, reload_func=None)
 
618
        access = pack_repo._DirectPackAccess({}, reload_func=None)
557
619
        retry_exc = self.make_retry_exception()
558
620
        # Without a reload_func, we will just re-raise the original exception
559
621
        self.assertRaises(_TestException, access.reload_or_raise, retry_exc)
560
622
 
561
623
    def test_reload_or_raise_reload_changed(self):
562
624
        reload_called, reload_func = self.make_reload_func(return_val=True)
563
 
        access = _DirectPackAccess({}, reload_func=reload_func)
 
625
        access = pack_repo._DirectPackAccess({}, reload_func=reload_func)
564
626
        retry_exc = self.make_retry_exception()
565
627
        access.reload_or_raise(retry_exc)
566
628
        self.assertEqual([1], reload_called)
570
632
 
571
633
    def test_reload_or_raise_reload_no_change(self):
572
634
        reload_called, reload_func = self.make_reload_func(return_val=False)
573
 
        access = _DirectPackAccess({}, reload_func=reload_func)
 
635
        access = pack_repo._DirectPackAccess({}, reload_func=reload_func)
574
636
        retry_exc = self.make_retry_exception()
575
637
        # If reload_occurred is False, then we consider it an error to have
576
638
        # reload_func() return False (no changes).
595
657
            self.fail('Annotation was not identical with reloading.')
596
658
        # Now delete the packs-in-use, which should trigger another reload, but
597
659
        # this time we just raise an exception because we can't recover
598
 
        for trans, name in vf._access._indices.itervalues():
 
660
        for trans, name in vf._access._indices.values():
599
661
            trans.delete(name)
600
662
        self.assertRaises(errors.NoSuchFile, vf.annotate, key)
601
663
        self.assertEqual([2, 1, 1], reload_counter)
608
670
        self.assertEqual([1, 1, 0], reload_counter)
609
671
        # Now delete the packs-in-use, which should trigger another reload, but
610
672
        # this time we just raise an exception because we can't recover
611
 
        for trans, name in vf._access._indices.itervalues():
 
673
        for trans, name in vf._access._indices.values():
612
674
            trans.delete(name)
613
675
        self.assertRaises(errors.NoSuchFile, vf._get_record_map, keys)
614
676
        self.assertEqual([2, 1, 1], reload_counter)
617
679
        vf, reload_counter = self.make_vf_for_retrying()
618
680
        keys = [('rev-1',), ('rev-2',), ('rev-3',)]
619
681
        record_stream = vf.get_record_stream(keys, 'topological', False)
620
 
        record = record_stream.next()
 
682
        record = next(record_stream)
621
683
        self.assertEqual(('rev-1',), record.key)
622
684
        self.assertEqual([0, 0, 0], reload_counter)
623
 
        record = record_stream.next()
 
685
        record = next(record_stream)
624
686
        self.assertEqual(('rev-2',), record.key)
625
687
        self.assertEqual([1, 1, 0], reload_counter)
626
 
        record = record_stream.next()
 
688
        record = next(record_stream)
627
689
        self.assertEqual(('rev-3',), record.key)
628
690
        self.assertEqual([1, 1, 0], reload_counter)
629
691
        # Now delete all pack files, and see that we raise the right error
630
 
        for trans, name in vf._access._indices.itervalues():
 
692
        for trans, name in vf._access._indices.values():
631
693
            trans.delete(name)
632
694
        self.assertListRaises(errors.NoSuchFile,
633
695
            vf.get_record_stream, keys, 'topological', False)
651
713
        self.assertEqual(plain_lines, reload_lines)
652
714
        self.assertEqual(21, len(plain_lines))
653
715
        # Now delete all pack files, and see that we raise the right error
654
 
        for trans, name in vf._access._indices.itervalues():
 
716
        for trans, name in vf._access._indices.values():
655
717
            trans.delete(name)
656
718
        self.assertListRaises(errors.NoSuchFile,
657
719
            vf.iter_lines_added_or_present_in_keys, keys)
699
761
class LowLevelKnitDataTests(TestCase):
700
762
 
701
763
    def create_gz_content(self, text):
702
 
        sio = StringIO()
 
764
        sio = BytesIO()
703
765
        gz_file = gzip.GzipFile(mode='wb', fileobj=sio)
704
766
        gz_file.write(text)
705
767
        gz_file.close()
707
769
 
708
770
    def make_multiple_records(self):
709
771
        """Create the content for multiple records."""
710
 
        sha1sum = osutils.sha('foo\nbar\n').hexdigest()
 
772
        sha1sum = osutils.sha_string('foo\nbar\n')
711
773
        total_txt = []
712
774
        gz_txt = self.create_gz_content('version rev-id-1 2 %s\n'
713
775
                                        'foo\n'
716
778
                                        % (sha1sum,))
717
779
        record_1 = (0, len(gz_txt), sha1sum)
718
780
        total_txt.append(gz_txt)
719
 
        sha1sum = osutils.sha('baz\n').hexdigest()
 
781
        sha1sum = osutils.sha_string('baz\n')
720
782
        gz_txt = self.create_gz_content('version rev-id-2 1 %s\n'
721
783
                                        'baz\n'
722
784
                                        'end rev-id-2\n'
726
788
        return total_txt, record_1, record_2
727
789
 
728
790
    def test_valid_knit_data(self):
729
 
        sha1sum = osutils.sha('foo\nbar\n').hexdigest()
 
791
        sha1sum = osutils.sha_string('foo\nbar\n')
730
792
        gz_txt = self.create_gz_content('version rev-id-1 2 %s\n'
731
793
                                        'foo\n'
732
794
                                        'bar\n'
763
825
                         raw_contents)
764
826
 
765
827
    def test_not_enough_lines(self):
766
 
        sha1sum = osutils.sha('foo\n').hexdigest()
 
828
        sha1sum = osutils.sha_string('foo\n')
767
829
        # record says 2 lines data says 1
768
830
        gz_txt = self.create_gz_content('version rev-id-1 2 %s\n'
769
831
                                        'foo\n'
773
835
        access = _KnitKeyAccess(transport, ConstantMapper('filename'))
774
836
        knit = KnitVersionedFiles(None, access)
775
837
        records = [(('rev-id-1',), (('rev-id-1',), 0, len(gz_txt)))]
776
 
        self.assertRaises(errors.KnitCorrupt, list,
 
838
        self.assertRaises(KnitCorrupt, list,
777
839
            knit._read_records_iter(records))
778
840
 
779
841
        # read_records_iter_raw won't detect that sort of mismatch/corruption
781
843
        self.assertEqual([(('rev-id-1',),  gz_txt, sha1sum)], raw_contents)
782
844
 
783
845
    def test_too_many_lines(self):
784
 
        sha1sum = osutils.sha('foo\nbar\n').hexdigest()
 
846
        sha1sum = osutils.sha_string('foo\nbar\n')
785
847
        # record says 1 lines data says 2
786
848
        gz_txt = self.create_gz_content('version rev-id-1 1 %s\n'
787
849
                                        'foo\n'
792
854
        access = _KnitKeyAccess(transport, ConstantMapper('filename'))
793
855
        knit = KnitVersionedFiles(None, access)
794
856
        records = [(('rev-id-1',), (('rev-id-1',), 0, len(gz_txt)))]
795
 
        self.assertRaises(errors.KnitCorrupt, list,
 
857
        self.assertRaises(KnitCorrupt, list,
796
858
            knit._read_records_iter(records))
797
859
 
798
860
        # read_records_iter_raw won't detect that sort of mismatch/corruption
800
862
        self.assertEqual([(('rev-id-1',), gz_txt, sha1sum)], raw_contents)
801
863
 
802
864
    def test_mismatched_version_id(self):
803
 
        sha1sum = osutils.sha('foo\nbar\n').hexdigest()
 
865
        sha1sum = osutils.sha_string('foo\nbar\n')
804
866
        gz_txt = self.create_gz_content('version rev-id-1 2 %s\n'
805
867
                                        'foo\n'
806
868
                                        'bar\n'
811
873
        knit = KnitVersionedFiles(None, access)
812
874
        # We are asking for rev-id-2, but the data is rev-id-1
813
875
        records = [(('rev-id-2',), (('rev-id-2',), 0, len(gz_txt)))]
814
 
        self.assertRaises(errors.KnitCorrupt, list,
 
876
        self.assertRaises(KnitCorrupt, list,
815
877
            knit._read_records_iter(records))
816
878
 
817
879
        # read_records_iter_raw detects mismatches in the header
818
 
        self.assertRaises(errors.KnitCorrupt, list,
 
880
        self.assertRaises(KnitCorrupt, list,
819
881
            knit._read_records_iter_raw(records))
820
882
 
821
883
    def test_uncompressed_data(self):
822
 
        sha1sum = osutils.sha('foo\nbar\n').hexdigest()
 
884
        sha1sum = osutils.sha_string('foo\nbar\n')
823
885
        txt = ('version rev-id-1 2 %s\n'
824
886
               'foo\n'
825
887
               'bar\n'
831
893
        records = [(('rev-id-1',), (('rev-id-1',), 0, len(txt)))]
832
894
 
833
895
        # We don't have valid gzip data ==> corrupt
834
 
        self.assertRaises(errors.KnitCorrupt, list,
 
896
        self.assertRaises(KnitCorrupt, list,
835
897
            knit._read_records_iter(records))
836
898
 
837
899
        # read_records_iter_raw will notice the bad data
838
 
        self.assertRaises(errors.KnitCorrupt, list,
 
900
        self.assertRaises(KnitCorrupt, list,
839
901
            knit._read_records_iter_raw(records))
840
902
 
841
903
    def test_corrupted_data(self):
842
 
        sha1sum = osutils.sha('foo\nbar\n').hexdigest()
 
904
        sha1sum = osutils.sha_string('foo\nbar\n')
843
905
        gz_txt = self.create_gz_content('version rev-id-1 2 %s\n'
844
906
                                        'foo\n'
845
907
                                        'bar\n'
851
913
        access = _KnitKeyAccess(transport, ConstantMapper('filename'))
852
914
        knit = KnitVersionedFiles(None, access)
853
915
        records = [(('rev-id-1',), (('rev-id-1',), 0, len(gz_txt)))]
854
 
        self.assertRaises(errors.KnitCorrupt, list,
 
916
        self.assertRaises(KnitCorrupt, list,
855
917
            knit._read_records_iter(records))
856
918
        # read_records_iter_raw will barf on bad gz data
857
 
        self.assertRaises(errors.KnitCorrupt, list,
 
919
        self.assertRaises(KnitCorrupt, list,
858
920
            knit._read_records_iter_raw(records))
859
921
 
860
922
 
862
924
 
863
925
    def get_knit_index(self, transport, name, mode):
864
926
        mapper = ConstantMapper(name)
865
 
        from bzrlib._knit_load_data_py import _load_data_py
 
927
        from ..bzr._knit_load_data_py import _load_data_py
866
928
        self.overrideAttr(knit, '_load_data', _load_data_py)
867
929
        allow_writes = lambda: 'w' in mode
868
930
        return _KndxIndex(transport, mapper, lambda:None, allow_writes, lambda:True)
872
934
        index = self.get_knit_index(transport, "filename", "w")
873
935
        index.keys()
874
936
        call = transport.calls.pop(0)
875
 
        # call[1][1] is a StringIO - we can't test it by simple equality.
 
937
        # call[1][1] is a BytesIO - we can't test it by simple equality.
876
938
        self.assertEqual('put_file_non_atomic', call[0])
877
939
        self.assertEqual('filename.kndx', call[1][0])
878
940
        # With no history, _KndxIndex writes a new index:
914
976
            ])
915
977
        index = self.get_knit_index(transport, "filename", "r")
916
978
        self.assertEqual(1, len(index.keys()))
917
 
        self.assertEqual(set([("version",)]), index.keys())
 
979
        self.assertEqual({("version",)}, index.keys())
918
980
 
919
981
    def test_read_corrupted_header(self):
920
982
        transport = MockTransport(['not a bzr knit index header\n'])
960
1022
        index.add_records([
961
1023
            ((utf8_revision_id,), ["option"], ((utf8_revision_id,), 0, 1), [])])
962
1024
        call = transport.calls.pop(0)
963
 
        # call[1][1] is a StringIO - we can't test it by simple equality.
 
1025
        # call[1][1] is a BytesIO - we can't test it by simple equality.
964
1026
        self.assertEqual('put_file_non_atomic', call[0])
965
1027
        self.assertEqual('filename.kndx', call[1][0])
966
1028
        # With no history, _KndxIndex writes a new index:
979
1041
        index.add_records([
980
1042
            (("version",), ["option"], (("version",), 0, 1), [(utf8_revision_id,)])])
981
1043
        call = transport.calls.pop(0)
982
 
        # call[1][1] is a StringIO - we can't test it by simple equality.
 
1044
        # call[1][1] is a BytesIO - we can't test it by simple equality.
983
1045
        self.assertEqual('put_file_non_atomic', call[0])
984
1046
        self.assertEqual('filename.kndx', call[1][0])
985
1047
        # With no history, _KndxIndex writes a new index:
997
1059
        self.assertEqual(set(), index.keys())
998
1060
 
999
1061
        index.add_records([(("a",), ["option"], (("a",), 0, 1), [])])
1000
 
        self.assertEqual(set([("a",)]), index.keys())
 
1062
        self.assertEqual({("a",)}, index.keys())
1001
1063
 
1002
1064
        index.add_records([(("a",), ["option"], (("a",), 0, 1), [])])
1003
 
        self.assertEqual(set([("a",)]), index.keys())
 
1065
        self.assertEqual({("a",)}, index.keys())
1004
1066
 
1005
1067
        index.add_records([(("b",), ["option"], (("b",), 0, 1), [])])
1006
 
        self.assertEqual(set([("a",), ("b",)]), index.keys())
 
1068
        self.assertEqual({("a",), ("b",)}, index.keys())
1007
1069
 
1008
1070
    def add_a_b(self, index, random_id=None):
1009
1071
        kwargs = {}
1033
1095
 
1034
1096
        self.add_a_b(index)
1035
1097
        call = transport.calls.pop(0)
1036
 
        # call[1][1] is a StringIO - we can't test it by simple equality.
 
1098
        # call[1][1] is a BytesIO - we can't test it by simple equality.
1037
1099
        self.assertEqual('put_file_non_atomic', call[0])
1038
1100
        self.assertEqual('filename.kndx', call[1][0])
1039
1101
        # With no history, _KndxIndex writes a new index:
1073
1135
        self.assertEqual(_KndxIndex.HEADER, call[1][1].getvalue())
1074
1136
        self.assertEqual({'create_parent_dir': True}, call[2])
1075
1137
        call = transport.calls.pop(0)
1076
 
        # call[1][1] is a StringIO - we can't test it by simple equality.
 
1138
        # call[1][1] is a BytesIO - we can't test it by simple equality.
1077
1139
        self.assertEqual('put_file_non_atomic', call[0])
1078
1140
        self.assertEqual('filename.kndx', call[1][0])
1079
1141
        # With no history, _KndxIndex writes a new index:
1127
1189
 
1128
1190
        self.assertEqual("fulltext", index.get_method("a"))
1129
1191
        self.assertEqual("line-delta", index.get_method("b"))
1130
 
        self.assertRaises(errors.KnitIndexUnknownMethod, index.get_method, "c")
 
1192
        self.assertRaises(knit.KnitIndexUnknownMethod, index.get_method, "c")
1131
1193
 
1132
1194
    def test_get_options(self):
1133
1195
        transport = MockTransport([
1150
1212
        index = self.get_knit_index(transport, "filename", "r")
1151
1213
 
1152
1214
        self.assertEqual({
1153
 
            ("a",):(),
1154
 
            ("b",):(("a",), ("c",)),
1155
 
            ("c",):(("b",), ("a",), ("e",)),
 
1215
            ("a",): (),
 
1216
            ("b",): (("a",), ("c",)),
 
1217
            ("c",): (("b",), ("a",), ("e",)),
1156
1218
            }, index.get_parent_map(index.keys()))
1157
1219
 
1158
1220
    def test_impossible_parent(self):
1163
1225
            "b option 0 1 4 :"  # We don't have a 4th record
1164
1226
            ])
1165
1227
        index = self.get_knit_index(transport, 'filename', 'r')
1166
 
        try:
1167
 
            self.assertRaises(errors.KnitCorrupt, index.keys)
1168
 
        except TypeError, e:
1169
 
            if (str(e) == ('exceptions must be strings, classes, or instances,'
1170
 
                           ' not exceptions.IndexError')
1171
 
                and sys.version_info[0:2] >= (2,5)):
1172
 
                self.knownFailure('Pyrex <0.9.5 fails with TypeError when'
1173
 
                                  ' raising new style exceptions with python'
1174
 
                                  ' >=2.5')
1175
 
            else:
1176
 
                raise
 
1228
        self.assertRaises(KnitCorrupt, index.keys)
1177
1229
 
1178
1230
    def test_corrupted_parent(self):
1179
1231
        transport = MockTransport([
1183
1235
            "c option 0 1 1v :", # Can't have a parent of '1v'
1184
1236
            ])
1185
1237
        index = self.get_knit_index(transport, 'filename', 'r')
1186
 
        try:
1187
 
            self.assertRaises(errors.KnitCorrupt, index.keys)
1188
 
        except TypeError, e:
1189
 
            if (str(e) == ('exceptions must be strings, classes, or instances,'
1190
 
                           ' not exceptions.ValueError')
1191
 
                and sys.version_info[0:2] >= (2,5)):
1192
 
                self.knownFailure('Pyrex <0.9.5 fails with TypeError when'
1193
 
                                  ' raising new style exceptions with python'
1194
 
                                  ' >=2.5')
1195
 
            else:
1196
 
                raise
 
1238
        self.assertRaises(KnitCorrupt, index.keys)
1197
1239
 
1198
1240
    def test_corrupted_parent_in_list(self):
1199
1241
        transport = MockTransport([
1203
1245
            "c option 0 1 1 v :", # Can't have a parent of 'v'
1204
1246
            ])
1205
1247
        index = self.get_knit_index(transport, 'filename', 'r')
1206
 
        try:
1207
 
            self.assertRaises(errors.KnitCorrupt, index.keys)
1208
 
        except TypeError, e:
1209
 
            if (str(e) == ('exceptions must be strings, classes, or instances,'
1210
 
                           ' not exceptions.ValueError')
1211
 
                and sys.version_info[0:2] >= (2,5)):
1212
 
                self.knownFailure('Pyrex <0.9.5 fails with TypeError when'
1213
 
                                  ' raising new style exceptions with python'
1214
 
                                  ' >=2.5')
1215
 
            else:
1216
 
                raise
 
1248
        self.assertRaises(KnitCorrupt, index.keys)
1217
1249
 
1218
1250
    def test_invalid_position(self):
1219
1251
        transport = MockTransport([
1221
1253
            "a option 1v 1 :",
1222
1254
            ])
1223
1255
        index = self.get_knit_index(transport, 'filename', 'r')
1224
 
        try:
1225
 
            self.assertRaises(errors.KnitCorrupt, index.keys)
1226
 
        except TypeError, e:
1227
 
            if (str(e) == ('exceptions must be strings, classes, or instances,'
1228
 
                           ' not exceptions.ValueError')
1229
 
                and sys.version_info[0:2] >= (2,5)):
1230
 
                self.knownFailure('Pyrex <0.9.5 fails with TypeError when'
1231
 
                                  ' raising new style exceptions with python'
1232
 
                                  ' >=2.5')
1233
 
            else:
1234
 
                raise
 
1256
        self.assertRaises(KnitCorrupt, index.keys)
1235
1257
 
1236
1258
    def test_invalid_size(self):
1237
1259
        transport = MockTransport([
1239
1261
            "a option 1 1v :",
1240
1262
            ])
1241
1263
        index = self.get_knit_index(transport, 'filename', 'r')
1242
 
        try:
1243
 
            self.assertRaises(errors.KnitCorrupt, index.keys)
1244
 
        except TypeError, e:
1245
 
            if (str(e) == ('exceptions must be strings, classes, or instances,'
1246
 
                           ' not exceptions.ValueError')
1247
 
                and sys.version_info[0:2] >= (2,5)):
1248
 
                self.knownFailure('Pyrex <0.9.5 fails with TypeError when'
1249
 
                                  ' raising new style exceptions with python'
1250
 
                                  ' >=2.5')
1251
 
            else:
1252
 
                raise
 
1264
        self.assertRaises(KnitCorrupt, index.keys)
1253
1265
 
1254
1266
    def test_scan_unvalidated_index_not_implemented(self):
1255
1267
        transport = MockTransport()
1267
1279
            "b option 10 10 0", # This line isn't terminated, ignored
1268
1280
            ])
1269
1281
        index = self.get_knit_index(transport, "filename", "r")
1270
 
        self.assertEqual(set([('a',)]), index.keys())
 
1282
        self.assertEqual({('a',)}, index.keys())
1271
1283
 
1272
1284
    def test_skip_incomplete_record(self):
1273
1285
        # A line with bogus data should just be skipped
1278
1290
            "c option 20 10 0 :", # Properly terminated, and starts with '\n'
1279
1291
            ])
1280
1292
        index = self.get_knit_index(transport, "filename", "r")
1281
 
        self.assertEqual(set([('a',), ('c',)]), index.keys())
 
1293
        self.assertEqual({('a',), ('c',)}, index.keys())
1282
1294
 
1283
1295
    def test_trailing_characters(self):
1284
1296
        # A line with bogus data should just be skipped
1289
1301
            "c option 20 10 0 :", # Properly terminated, and starts with '\n'
1290
1302
            ])
1291
1303
        index = self.get_knit_index(transport, "filename", "r")
1292
 
        self.assertEqual(set([('a',), ('c',)]), index.keys())
 
1304
        self.assertEqual({('a',), ('c',)}, index.keys())
1293
1305
 
1294
1306
 
1295
1307
class LowLevelKnitIndexTests_c(LowLevelKnitIndexTests):
1298
1310
 
1299
1311
    def get_knit_index(self, transport, name, mode):
1300
1312
        mapper = ConstantMapper(name)
1301
 
        from bzrlib._knit_load_data_pyx import _load_data_c
 
1313
        from ..bzr._knit_load_data_pyx import _load_data_c
1302
1314
        self.overrideAttr(knit, '_load_data', _load_data_c)
1303
1315
        allow_writes = lambda: mode == 'w'
1304
1316
        return _KndxIndex(transport, mapper, lambda:None,
1409
1421
        details = ('line-delta', False)
1410
1422
        p1_record = ['line1\n', 'line2\n']
1411
1423
        ann._num_compression_children[p1_key] = 1
1412
 
        res = ann._expand_record(rev_key, (p1_key,p2_key), p1_key,
 
1424
        res = ann._expand_record(rev_key, (p1_key, p2_key), p1_key,
1413
1425
                                 record, details)
1414
1426
        self.assertEqual(None, res)
1415
1427
        # self.assertTrue(p1_key in ann._pending_deltas)
1494
1506
        target.add_lines(basis, (), ['gam\n'])
1495
1507
        target.insert_record_stream(
1496
1508
            source.get_record_stream([broken], 'unordered', False))
1497
 
        err = self.assertRaises(errors.KnitCorrupt,
 
1509
        err = self.assertRaises(KnitCorrupt,
1498
1510
            target.get_record_stream([broken], 'unordered', True
1499
1511
            ).next().get_bytes_as, 'chunked')
1500
1512
        self.assertEqual(['gam\n', 'bar\n'], err.content)
1525
1537
            'a-2 fulltext 0 0 0 :\n'
1526
1538
            'a-3 fulltext 0 0 1 :'
1527
1539
            )
1528
 
        self.assertEqual(set([('a-3',), ('a-1',), ('a-2',)]), idx.keys())
 
1540
        self.assertEqual({('a-3',), ('a-1',), ('a-2',)}, idx.keys())
1529
1541
        self.assertEqual({
1530
1542
            ('a-1',): ((('a-1',), 0, 0), None, (), ('fulltext', False)),
1531
1543
            ('a-2',): ((('a-2',), 0, 0), None, (('a-1',),), ('fulltext', False)),
1532
1544
            ('a-3',): ((('a-3',), 0, 0), None, (('a-2',),), ('fulltext', False)),
1533
1545
            }, idx.get_build_details(idx.keys()))
1534
 
        self.assertEqual({('a-1',):(),
1535
 
            ('a-2',):(('a-1',),),
1536
 
            ('a-3',):(('a-2',),),},
 
1546
        self.assertEqual({('a-1',): (),
 
1547
            ('a-2',): (('a-1',),),
 
1548
            ('a-3',): (('a-2',),),},
1537
1549
            idx.get_parent_map(idx.keys()))
1538
1550
 
1539
1551
    def test_add_versions_fails_clean(self):
1563
1575
 
1564
1576
        # Assert the pre-condition
1565
1577
        def assertA1Only():
1566
 
            self.assertEqual(set([('a-1',)]), set(idx.keys()))
 
1578
            self.assertEqual({('a-1',)}, set(idx.keys()))
1567
1579
            self.assertEqual(
1568
1580
                {('a-1',): ((('a-1',), 0, 0), None, (), ('fulltext', False))},
1569
1581
                idx.get_build_details([('a-1',)]))
1579
1591
        # could leave an empty .kndx file, which bzr would later claim was a
1580
1592
        # corrupted file since the header was not present. In reality, the file
1581
1593
        # just wasn't created, so it should be ignored.
1582
 
        t = get_transport('.')
 
1594
        t = transport.get_transport_from_path('.')
1583
1595
        t.put_bytes('test.kndx', '')
1584
1596
 
1585
1597
        knit = self.make_test_knit()
1586
1598
 
1587
1599
    def test_knit_index_checks_header(self):
1588
 
        t = get_transport('.')
 
1600
        t = transport.get_transport_from_path('.')
1589
1601
        t.put_bytes('test.kndx', '# not really a knit header\n\n')
1590
1602
        k = self.make_test_knit()
1591
1603
        self.assertRaises(KnitHeaderError, k.keys)
1638
1650
 
1639
1651
    def test_keys(self):
1640
1652
        index = self.two_graph_index()
1641
 
        self.assertEqual(set([('tail',), ('tip',), ('parent',), ('separate',)]),
 
1653
        self.assertEqual({('tail',), ('tip',), ('parent',), ('separate',)},
1642
1654
            set(index.keys()))
1643
1655
 
1644
1656
    def test_get_position(self):
1690
1702
 
1691
1703
    def test_add_version_delta_not_delta_index(self):
1692
1704
        index = self.two_graph_index(catch_adds=True)
1693
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
1705
        self.assertRaises(KnitCorrupt, index.add_records,
1694
1706
            [(('new',), 'no-eol,line-delta', (None, 0, 100), [('parent',)])])
1695
1707
        self.assertEqual([], self.caught_entries)
1696
1708
 
1711
1723
    def test_add_version_different_dup(self):
1712
1724
        index = self.two_graph_index(deltas=True, catch_adds=True)
1713
1725
        # change options
1714
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
1726
        self.assertRaises(KnitCorrupt, index.add_records,
1715
1727
            [(('tip',), 'line-delta', (None, 0, 100), [('parent',)])])
1716
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
1728
        self.assertRaises(KnitCorrupt, index.add_records,
1717
1729
            [(('tip',), 'fulltext', (None, 0, 100), [('parent',)])])
1718
1730
        # parents
1719
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
1731
        self.assertRaises(KnitCorrupt, index.add_records,
1720
1732
            [(('tip',), 'fulltext,no-eol', (None, 0, 100), [])])
1721
1733
        self.assertEqual([], self.caught_entries)
1722
1734
 
1744
1756
 
1745
1757
    def test_add_versions_delta_not_delta_index(self):
1746
1758
        index = self.two_graph_index(catch_adds=True)
1747
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
1759
        self.assertRaises(KnitCorrupt, index.add_records,
1748
1760
            [(('new',), 'no-eol,line-delta', (None, 0, 100), [('parent',)])])
1749
1761
        self.assertEqual([], self.caught_entries)
1750
1762
 
1771
1783
    def test_add_versions_different_dup(self):
1772
1784
        index = self.two_graph_index(deltas=True, catch_adds=True)
1773
1785
        # change options
1774
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
1786
        self.assertRaises(KnitCorrupt, index.add_records,
1775
1787
            [(('tip',), 'line-delta', (None, 0, 100), [('parent',)])])
1776
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
1788
        self.assertRaises(KnitCorrupt, index.add_records,
1777
1789
            [(('tip',), 'fulltext', (None, 0, 100), [('parent',)])])
1778
1790
        # parents
1779
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
1791
        self.assertRaises(KnitCorrupt, index.add_records,
1780
1792
            [(('tip',), 'fulltext,no-eol', (None, 0, 100), [])])
1781
1793
        # change options in the second record
1782
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
1794
        self.assertRaises(KnitCorrupt, index.add_records,
1783
1795
            [(('tip',), 'fulltext,no-eol', (None, 0, 100), [('parent',)]),
1784
1796
             (('tip',), 'line-delta', (None, 0, 100), [('parent',)])])
1785
1797
        self.assertEqual([], self.caught_entries)
1912
1924
 
1913
1925
    def test_parents_deltas_incompatible(self):
1914
1926
        index = CombinedGraphIndex([])
1915
 
        self.assertRaises(errors.KnitError, _KnitGraphIndex, lambda:True,
 
1927
        self.assertRaises(knit.KnitError, _KnitGraphIndex, lambda:True,
1916
1928
            index, deltas=True, parents=False)
1917
1929
 
1918
1930
    def two_graph_index(self, catch_adds=False):
1940
1952
 
1941
1953
    def test_keys(self):
1942
1954
        index = self.two_graph_index()
1943
 
        self.assertEqual(set([('tail',), ('tip',), ('parent',), ('separate',)]),
 
1955
        self.assertEqual({('tail',), ('tip',), ('parent',), ('separate',)},
1944
1956
            set(index.keys()))
1945
1957
 
1946
1958
    def test_get_position(self):
1981
1993
 
1982
1994
    def test_add_version_delta_not_delta_index(self):
1983
1995
        index = self.two_graph_index(catch_adds=True)
1984
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
1996
        self.assertRaises(KnitCorrupt, index.add_records,
1985
1997
            [(('new',), 'no-eol,line-delta', (None, 0, 100), [])])
1986
1998
        self.assertEqual([], self.caught_entries)
1987
1999
 
2000
2012
    def test_add_version_different_dup(self):
2001
2013
        index = self.two_graph_index(catch_adds=True)
2002
2014
        # change options
2003
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
2015
        self.assertRaises(KnitCorrupt, index.add_records,
2004
2016
            [(('tip',), 'no-eol,line-delta', (None, 0, 100), [])])
2005
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
2017
        self.assertRaises(KnitCorrupt, index.add_records,
2006
2018
            [(('tip',), 'line-delta,no-eol', (None, 0, 100), [])])
2007
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
2019
        self.assertRaises(KnitCorrupt, index.add_records,
2008
2020
            [(('tip',), 'fulltext', (None, 0, 100), [])])
2009
2021
        # parents
2010
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
2022
        self.assertRaises(KnitCorrupt, index.add_records,
2011
2023
            [(('tip',), 'fulltext,no-eol', (None, 0, 100), [('parent',)])])
2012
2024
        self.assertEqual([], self.caught_entries)
2013
2025
 
2023
2035
 
2024
2036
    def test_add_versions_delta_not_delta_index(self):
2025
2037
        index = self.two_graph_index(catch_adds=True)
2026
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
2038
        self.assertRaises(KnitCorrupt, index.add_records,
2027
2039
            [(('new',), 'no-eol,line-delta', (None, 0, 100), [('parent',)])])
2028
2040
        self.assertEqual([], self.caught_entries)
2029
2041
 
2030
2042
    def test_add_versions_parents_not_parents_index(self):
2031
2043
        index = self.two_graph_index(catch_adds=True)
2032
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
2044
        self.assertRaises(KnitCorrupt, index.add_records,
2033
2045
            [(('new',), 'no-eol,fulltext', (None, 0, 100), [('parent',)])])
2034
2046
        self.assertEqual([], self.caught_entries)
2035
2047
 
2052
2064
    def test_add_versions_different_dup(self):
2053
2065
        index = self.two_graph_index(catch_adds=True)
2054
2066
        # change options
2055
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
2067
        self.assertRaises(KnitCorrupt, index.add_records,
2056
2068
            [(('tip',), 'no-eol,line-delta', (None, 0, 100), [])])
2057
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
2069
        self.assertRaises(KnitCorrupt, index.add_records,
2058
2070
            [(('tip',), 'line-delta,no-eol', (None, 0, 100), [])])
2059
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
2071
        self.assertRaises(KnitCorrupt, index.add_records,
2060
2072
            [(('tip',), 'fulltext', (None, 0, 100), [])])
2061
2073
        # parents
2062
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
2074
        self.assertRaises(KnitCorrupt, index.add_records,
2063
2075
            [(('tip',), 'fulltext,no-eol', (None, 0, 100), [('parent',)])])
2064
2076
        # change options in the second record
2065
 
        self.assertRaises(errors.KnitCorrupt, index.add_records,
 
2077
        self.assertRaises(KnitCorrupt, index.add_records,
2066
2078
            [(('tip',), 'fulltext,no-eol', (None, 0, 100), []),
2067
2079
             (('tip',), 'no-eol,line-delta', (None, 0, 100), [])])
2068
2080
        self.assertEqual([], self.caught_entries)
2104
2116
            }
2105
2117
        self.assertGroupKeysForIo([([f_a], set())],
2106
2118
                                  [f_a], [], positions)
2107
 
        self.assertGroupKeysForIo([([f_a], set([f_a]))],
 
2119
        self.assertGroupKeysForIo([([f_a], {f_a})],
2108
2120
                                  [f_a], [f_a], positions)
2109
2121
        self.assertGroupKeysForIo([([f_a, f_b], set([]))],
2110
2122
                                  [f_a, f_b], [], positions)
2111
 
        self.assertGroupKeysForIo([([f_a, f_b], set([f_b]))],
 
2123
        self.assertGroupKeysForIo([([f_a, f_b], {f_b})],
2112
2124
                                  [f_a, f_b], [f_b], positions)
2113
2125
        self.assertGroupKeysForIo([([f_a, f_b, g_a, g_b], set())],
2114
2126
                                  [f_a, g_a, f_b, g_b], [], positions)
2211
2223
        self.assertEqual([(key_basis, 'foo\n'), (key_basis, 'bar\n')], details)
2212
2224
        # Not optimised to date:
2213
2225
        # self.assertEqual([("annotate", key_basis)], basis.calls)
2214
 
        self.assertEqual([('get_parent_map', set([key_basis])),
2215
 
            ('get_parent_map', set([key_basis])),
 
2226
        self.assertEqual([('get_parent_map', {key_basis}),
 
2227
            ('get_parent_map', {key_basis}),
2216
2228
            ('get_record_stream', [key_basis], 'topological', True)],
2217
2229
            basis.calls)
2218
2230
 
2238
2250
        parent_map = test.get_parent_map([key, key_basis, key_missing])
2239
2251
        self.assertEqual({key: (),
2240
2252
            key_basis: ()}, parent_map)
2241
 
        self.assertEqual([("get_parent_map", set([key_basis, key_missing]))],
 
2253
        self.assertEqual([("get_parent_map", {key_basis, key_missing})],
2242
2254
            basis.calls)
2243
2255
 
2244
2256
    def test_get_record_stream_unordered_fulltexts(self):
2275
2287
        # It's not strictly minimal, but it seems reasonable for now for it to
2276
2288
        # ask which fallbacks have which parents.
2277
2289
        self.assertEqual([
2278
 
            ("get_parent_map", set([key_basis, key_missing])),
 
2290
            ("get_parent_map", {key_basis, key_missing}),
2279
2291
            ("get_record_stream", [key_basis], 'unordered', True)],
2280
2292
            calls)
2281
2293
 
2312
2324
                source = test
2313
2325
            else:
2314
2326
                source = basis
2315
 
            record = source.get_record_stream([result[0]], 'unordered',
2316
 
                True).next()
 
2327
            record = next(source.get_record_stream([result[0]], 'unordered',
 
2328
                True))
2317
2329
            self.assertEqual(record.key, result[0])
2318
2330
            self.assertEqual(record.sha1, result[1])
2319
2331
            # We used to check that the storage kind matched, but actually it
2324
2336
        # It's not strictly minimal, but it seems reasonable for now for it to
2325
2337
        # ask which fallbacks have which parents.
2326
2338
        self.assertEqual([
2327
 
            ("get_parent_map", set([key_basis, key_basis_2, key_missing])),
 
2339
            ("get_parent_map", {key_basis, key_basis_2, key_missing}),
2328
2340
            # topological is requested from the fallback, because that is what
2329
2341
            # was requested at the top level.
2330
2342
            ("get_record_stream", [key_basis_2, key_basis], 'topological', True)],
2362
2374
        # It's not strictly minimal, but it seems reasonable for now for it to
2363
2375
        # ask which fallbacks have which parents.
2364
2376
        self.assertEqual([
2365
 
            ("get_parent_map", set([key_basis, key_missing])),
 
2377
            ("get_parent_map", {key_basis, key_missing}),
2366
2378
            ("get_record_stream", [key_basis], 'unordered', False)],
2367
2379
            calls)
2368
2380
 
2399
2411
                source = test
2400
2412
            else:
2401
2413
                source = basis
2402
 
            record = source.get_record_stream([result[0]], 'unordered',
2403
 
                False).next()
 
2414
            record = next(source.get_record_stream([result[0]], 'unordered',
 
2415
                False))
2404
2416
            self.assertEqual(record.key, result[0])
2405
2417
            self.assertEqual(record.sha1, result[1])
2406
2418
            self.assertEqual(record.storage_kind, result[2])
2408
2420
        # It's not strictly minimal, but it seems reasonable for now for it to
2409
2421
        # ask which fallbacks have which parents.
2410
2422
        self.assertEqual([
2411
 
            ("get_parent_map", set([key_basis, key_basis_2, key_missing])),
 
2423
            ("get_parent_map", {key_basis, key_basis_2, key_missing}),
2412
2424
            ("get_record_stream", [key_basis_2, key_basis], 'topological', False)],
2413
2425
            calls)
2414
2426
 
2419
2431
        key_basis = ('bar',)
2420
2432
        key_missing = ('missing',)
2421
2433
        test.add_lines(key, (), ['foo\n'])
2422
 
        key_sha1sum = osutils.sha('foo\n').hexdigest()
 
2434
        key_sha1sum = osutils.sha_string('foo\n')
2423
2435
        sha1s = test.get_sha1s([key])
2424
2436
        self.assertEqual({key: key_sha1sum}, sha1s)
2425
2437
        self.assertEqual([], basis.calls)
2427
2439
        # directly (rather than via text reconstruction) so that remote servers
2428
2440
        # etc don't have to answer with full content.
2429
2441
        basis.add_lines(key_basis, (), ['foo\n', 'bar\n'])
2430
 
        basis_sha1sum = osutils.sha('foo\nbar\n').hexdigest()
 
2442
        basis_sha1sum = osutils.sha_string('foo\nbar\n')
2431
2443
        basis.calls = []
2432
2444
        sha1s = test.get_sha1s([key, key_missing, key_basis])
2433
2445
        self.assertEqual({key: key_sha1sum,
2434
2446
            key_basis: basis_sha1sum}, sha1s)
2435
 
        self.assertEqual([("get_sha1s", set([key_basis, key_missing]))],
 
2447
        self.assertEqual([("get_sha1s", {key_basis, key_missing})],
2436
2448
            basis.calls)
2437
2449
 
2438
2450
    def test_insert_record_stream(self):
2451
2463
        test.insert_record_stream(stream)
2452
2464
        # XXX: this does somewhat too many calls in making sure of whether it
2453
2465
        # has to recreate the full text.
2454
 
        self.assertEqual([("get_parent_map", set([key_basis])),
2455
 
             ('get_parent_map', set([key_basis])),
 
2466
        self.assertEqual([("get_parent_map", {key_basis}),
 
2467
             ('get_parent_map', {key_basis}),
2456
2468
             ('get_record_stream', [key_basis], 'unordered', True)],
2457
2469
            basis.calls)
2458
2470
        self.assertEqual({key_delta:(key_basis,)},
2471
2483
        basis.calls = []
2472
2484
        lines = list(test.iter_lines_added_or_present_in_keys([key1]))
2473
2485
        self.assertEqual([("foo\n", key1)], lines)
2474
 
        self.assertEqual([("iter_lines_added_or_present_in_keys", set([key1]))],
 
2486
        self.assertEqual([("iter_lines_added_or_present_in_keys", {key1})],
2475
2487
            basis.calls)
2476
2488
        # keys in both are not duplicated:
2477
2489
        test.add_lines(key2, (), ["bar\n"])
2493
2505
        basis.add_lines(key1, (), [])
2494
2506
        basis.calls = []
2495
2507
        keys = test.keys()
2496
 
        self.assertEqual(set([key1]), set(keys))
 
2508
        self.assertEqual({key1}, set(keys))
2497
2509
        self.assertEqual([("keys",)], basis.calls)
2498
2510
        # keys in both are not duplicated:
2499
2511
        test.add_lines(key2, (), [])
2501
2513
        basis.calls = []
2502
2514
        keys = test.keys()
2503
2515
        self.assertEqual(2, len(keys))
2504
 
        self.assertEqual(set([key1, key2]), set(keys))
 
2516
        self.assertEqual({key1, key2}, set(keys))
2505
2517
        self.assertEqual([("keys",)], basis.calls)
2506
2518
 
2507
2519
    def test_add_mpdiffs(self):
2519
2531
        diffs = source.make_mpdiffs([key_delta])
2520
2532
        test.add_mpdiffs([(key_delta, (key_basis,),
2521
2533
            source.get_sha1s([key_delta])[key_delta], diffs[0])])
2522
 
        self.assertEqual([("get_parent_map", set([key_basis])),
 
2534
        self.assertEqual([("get_parent_map", {key_basis}),
2523
2535
            ('get_record_stream', [key_basis], 'unordered', True),],
2524
2536
            basis.calls)
2525
2537
        self.assertEqual({key_delta:(key_basis,)},
2547
2559
            diffs)
2548
2560
        self.assertEqual(3, len(basis.calls))
2549
2561
        self.assertEqual([
2550
 
            ("get_parent_map", set([key_left, key_right])),
2551
 
            ("get_parent_map", set([key_left, key_right])),
 
2562
            ("get_parent_map", {key_left, key_right}),
 
2563
            ("get_parent_map", {key_left, key_right}),
2552
2564
            ],
2553
2565
            basis.calls[:-1])
2554
2566
        last_call = basis.calls[-1]
2555
2567
        self.assertEqual('get_record_stream', last_call[0])
2556
 
        self.assertEqual(set([key_left, key_right]), set(last_call[1]))
 
2568
        self.assertEqual({key_left, key_right}, set(last_call[1]))
2557
2569
        self.assertEqual('topological', last_call[2])
2558
2570
        self.assertEqual(True, last_call[3])
2559
2571