~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_knit.py

  • Committer: Vincent Ladeuil
  • Date: 2007-07-15 11:24:18 UTC
  • mfrom: (2617 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2646.
  • Revision ID: v.ladeuil+lp@free.fr-20070715112418-9nn4n6esxv60ny4b
merge bzr.dev@1617

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007 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
20
20
import difflib
21
21
import gzip
22
22
import sha
 
23
import sys
23
24
 
24
25
from bzrlib import (
25
26
    errors,
 
27
    generate_ids,
 
28
    knit,
26
29
    )
27
30
from bzrlib.errors import (
28
31
    RevisionAlreadyPresent,
40
43
    WeaveToKnit,
41
44
    )
42
45
from bzrlib.osutils import split_lines
43
 
from bzrlib.tests import TestCase, TestCaseWithTransport
 
46
from bzrlib.tests import TestCase, TestCaseWithTransport, Feature
44
47
from bzrlib.transport import TransportLogger, get_transport
45
48
from bzrlib.transport.memory import MemoryTransport
46
49
from bzrlib.weave import Weave
47
50
 
48
51
 
 
52
class _CompiledKnitFeature(Feature):
 
53
 
 
54
    def _probe(self):
 
55
        try:
 
56
            import bzrlib._knit_load_data_c
 
57
        except ImportError:
 
58
            return False
 
59
        return True
 
60
 
 
61
    def feature_name(self):
 
62
        return 'bzrlib._knit_load_data_c'
 
63
 
 
64
CompiledKnitFeature = _CompiledKnitFeature()
 
65
 
 
66
 
49
67
class KnitContentTests(TestCase):
50
68
 
51
69
    def test_constructor(self):
240
258
 
241
259
class LowLevelKnitIndexTests(TestCase):
242
260
 
 
261
    def get_knit_index(self, *args, **kwargs):
 
262
        orig = knit._load_data
 
263
        def reset():
 
264
            knit._load_data = orig
 
265
        self.addCleanup(reset)
 
266
        from bzrlib._knit_load_data_py import _load_data_py
 
267
        knit._load_data = _load_data_py
 
268
        return _KnitIndex(*args, **kwargs)
 
269
 
243
270
    def test_no_such_file(self):
244
271
        transport = MockTransport()
245
272
 
246
 
        self.assertRaises(NoSuchFile, _KnitIndex, transport, "filename", "r")
247
 
        self.assertRaises(NoSuchFile, _KnitIndex, transport,
248
 
            "filename", "w", create=False)
 
273
        self.assertRaises(NoSuchFile, self.get_knit_index,
 
274
                          transport, "filename", "r")
 
275
        self.assertRaises(NoSuchFile, self.get_knit_index,
 
276
                          transport, "filename", "w", create=False)
249
277
 
250
278
    def test_create_file(self):
251
279
        transport = MockTransport()
252
280
 
253
 
        index = _KnitIndex(transport, "filename", "w",
 
281
        index = self.get_knit_index(transport, "filename", "w",
254
282
            file_mode="wb", create=True)
255
283
        self.assertEqual(
256
284
                ("put_bytes_non_atomic",
260
288
    def test_delay_create_file(self):
261
289
        transport = MockTransport()
262
290
 
263
 
        index = _KnitIndex(transport, "filename", "w",
 
291
        index = self.get_knit_index(transport, "filename", "w",
264
292
            create=True, file_mode="wb", create_parent_dir=True,
265
293
            delay_create=True, dir_mode=0777)
266
294
        self.assertEqual([], transport.calls)
285
313
            _KnitIndex.HEADER,
286
314
            '%s option 0 1 :' % (utf8_revision_id,)
287
315
            ])
288
 
        index = _KnitIndex(transport, "filename", "r")
 
316
        index = self.get_knit_index(transport, "filename", "r")
289
317
        # _KnitIndex is a private class, and deals in utf8 revision_ids, not
290
318
        # Unicode revision_ids.
291
319
        self.assertTrue(index.has_version(utf8_revision_id))
298
326
            _KnitIndex.HEADER,
299
327
            "version option 0 1 .%s :" % (utf8_revision_id,)
300
328
            ])
301
 
        index = _KnitIndex(transport, "filename", "r")
 
329
        index = self.get_knit_index(transport, "filename", "r")
302
330
        self.assertEqual([utf8_revision_id],
303
331
            index.get_parents_with_ghosts("version"))
304
332
 
309
337
            "corrupted options 0 1 .b .c ",
310
338
            "version options 0 1 :"
311
339
            ])
312
 
        index = _KnitIndex(transport, "filename", "r")
 
340
        index = self.get_knit_index(transport, "filename", "r")
313
341
        self.assertEqual(1, index.num_versions())
314
342
        self.assertTrue(index.has_version("version"))
315
343
 
316
344
    def test_read_corrupted_header(self):
317
345
        transport = MockTransport(['not a bzr knit index header\n'])
318
346
        self.assertRaises(KnitHeaderError,
319
 
            _KnitIndex, transport, "filename", "r")
 
347
            self.get_knit_index, transport, "filename", "r")
320
348
 
321
349
    def test_read_duplicate_entries(self):
322
350
        transport = MockTransport([
326
354
            "version options2 1 2 .other :",
327
355
            "version options3 3 4 0 .other :"
328
356
            ])
329
 
        index = _KnitIndex(transport, "filename", "r")
 
357
        index = self.get_knit_index(transport, "filename", "r")
330
358
        self.assertEqual(2, index.num_versions())
331
359
        self.assertEqual(1, index.lookup("version"))
332
360
        self.assertEqual((3, 4), index.get_position("version"))
341
369
            "b option 0 1 0 :",
342
370
            "c option 0 1 1 0 :",
343
371
            ])
344
 
        index = _KnitIndex(transport, "filename", "r")
 
372
        index = self.get_knit_index(transport, "filename", "r")
345
373
        self.assertEqual(["a"], index.get_parents("b"))
346
374
        self.assertEqual(["b", "a"], index.get_parents("c"))
347
375
 
351
379
        transport = MockTransport([
352
380
            _KnitIndex.HEADER
353
381
            ])
354
 
        index = _KnitIndex(transport, "filename", "r")
 
382
        index = self.get_knit_index(transport, "filename", "r")
355
383
        index.add_version(utf8_revision_id, ["option"], 0, 1, [])
356
384
        self.assertEqual(("append_bytes", ("filename",
357
385
            "\n%s option 0 1  :" % (utf8_revision_id,)),
364
392
        transport = MockTransport([
365
393
            _KnitIndex.HEADER
366
394
            ])
367
 
        index = _KnitIndex(transport, "filename", "r")
 
395
        index = self.get_knit_index(transport, "filename", "r")
368
396
        index.add_version("version", ["option"], 0, 1, [utf8_revision_id])
369
397
        self.assertEqual(("append_bytes", ("filename",
370
398
            "\nversion option 0 1 .%s :" % (utf8_revision_id,)),
373
401
 
374
402
    def test_get_graph(self):
375
403
        transport = MockTransport()
376
 
        index = _KnitIndex(transport, "filename", "w", create=True)
 
404
        index = self.get_knit_index(transport, "filename", "w", create=True)
377
405
        self.assertEqual([], index.get_graph())
378
406
 
379
407
        index.add_version("a", ["option"], 0, 1, ["b"])
391
419
            "c option 0 1 1 0 :",
392
420
            "d option 0 1 2 .f :"
393
421
            ])
394
 
        index = _KnitIndex(transport, "filename", "r")
 
422
        index = self.get_knit_index(transport, "filename", "r")
395
423
 
396
424
        self.assertEqual([], index.get_ancestry([]))
397
425
        self.assertEqual(["a"], index.get_ancestry(["a"]))
411
439
            "c option 0 1 0 .f .g :",
412
440
            "d option 0 1 2 .h .j .k :"
413
441
            ])
414
 
        index = _KnitIndex(transport, "filename", "r")
 
442
        index = self.get_knit_index(transport, "filename", "r")
415
443
 
416
444
        self.assertEqual([], index.get_ancestry_with_ghosts([]))
417
445
        self.assertEqual(["a"], index.get_ancestry_with_ghosts(["a"]))
436
464
        transport = MockTransport([
437
465
            _KnitIndex.HEADER
438
466
            ])
439
 
        index = _KnitIndex(transport, "filename", "r")
 
467
        index = self.get_knit_index(transport, "filename", "r")
440
468
 
441
469
        self.assertEqual(0, index.num_versions())
442
470
        self.assertEqual(0, len(index))
457
485
        transport = MockTransport([
458
486
            _KnitIndex.HEADER
459
487
            ])
460
 
        index = _KnitIndex(transport, "filename", "r")
 
488
        index = self.get_knit_index(transport, "filename", "r")
461
489
 
462
490
        self.assertEqual([], index.get_versions())
463
491
 
476
504
            "a option 0 1 :",
477
505
            "b option 0 1 :"
478
506
            ])
479
 
        index = _KnitIndex(transport, "filename", "r")
 
507
        index = self.get_knit_index(transport, "filename", "r")
480
508
 
481
509
        self.assertEqual("a", index.idx_to_name(0))
482
510
        self.assertEqual("b", index.idx_to_name(1))
489
517
            "a option 0 1 :",
490
518
            "b option 0 1 :"
491
519
            ])
492
 
        index = _KnitIndex(transport, "filename", "r")
 
520
        index = self.get_knit_index(transport, "filename", "r")
493
521
 
494
522
        self.assertEqual(0, index.lookup("a"))
495
523
        self.assertEqual(1, index.lookup("b"))
498
526
        transport = MockTransport([
499
527
            _KnitIndex.HEADER
500
528
            ])
501
 
        index = _KnitIndex(transport, "filename", "r")
 
529
        index = self.get_knit_index(transport, "filename", "r")
502
530
 
503
531
        index.add_version("a", ["option"], 0, 1, ["b"])
504
532
        self.assertEqual(("append_bytes",
534
562
        transport = MockTransport([
535
563
            _KnitIndex.HEADER
536
564
            ])
537
 
        index = _KnitIndex(transport, "filename", "r")
 
565
        index = self.get_knit_index(transport, "filename", "r")
538
566
 
539
567
        index.add_versions([
540
568
            ("a", ["option"], 0, 1, ["b"]),
559
587
    def test_delay_create_and_add_versions(self):
560
588
        transport = MockTransport()
561
589
 
562
 
        index = _KnitIndex(transport, "filename", "w",
 
590
        index = self.get_knit_index(transport, "filename", "w",
563
591
            create=True, file_mode="wb", create_parent_dir=True,
564
592
            delay_create=True, dir_mode=0777)
565
593
        self.assertEqual([], transport.calls)
587
615
            _KnitIndex.HEADER,
588
616
            "a option 0 1 :"
589
617
            ])
590
 
        index = _KnitIndex(transport, "filename", "r")
 
618
        index = self.get_knit_index(transport, "filename", "r")
591
619
 
592
620
        self.assertTrue(index.has_version("a"))
593
621
        self.assertFalse(index.has_version("b"))
598
626
            "a option 0 1 :",
599
627
            "b option 1 2 :"
600
628
            ])
601
 
        index = _KnitIndex(transport, "filename", "r")
 
629
        index = self.get_knit_index(transport, "filename", "r")
602
630
 
603
631
        self.assertEqual((0, 1), index.get_position("a"))
604
632
        self.assertEqual((1, 2), index.get_position("b"))
610
638
            "b unknown,line-delta 1 2 :",
611
639
            "c bad 3 4 :"
612
640
            ])
613
 
        index = _KnitIndex(transport, "filename", "r")
 
641
        index = self.get_knit_index(transport, "filename", "r")
614
642
 
615
643
        self.assertEqual("fulltext", index.get_method("a"))
616
644
        self.assertEqual("line-delta", index.get_method("b"))
622
650
            "a opt1 0 1 :",
623
651
            "b opt2,opt3 1 2 :"
624
652
            ])
625
 
        index = _KnitIndex(transport, "filename", "r")
 
653
        index = self.get_knit_index(transport, "filename", "r")
626
654
 
627
655
        self.assertEqual(["opt1"], index.get_options("a"))
628
656
        self.assertEqual(["opt2", "opt3"], index.get_options("b"))
634
662
            "b option 1 2 0 .c :",
635
663
            "c option 1 2 1 0 .e :"
636
664
            ])
637
 
        index = _KnitIndex(transport, "filename", "r")
 
665
        index = self.get_knit_index(transport, "filename", "r")
638
666
 
639
667
        self.assertEqual([], index.get_parents("a"))
640
668
        self.assertEqual(["a", "c"], index.get_parents("b"))
647
675
            "b option 1 2 0 .c :",
648
676
            "c option 1 2 1 0 .e :"
649
677
            ])
650
 
        index = _KnitIndex(transport, "filename", "r")
 
678
        index = self.get_knit_index(transport, "filename", "r")
651
679
 
652
680
        self.assertEqual([], index.get_parents_with_ghosts("a"))
653
681
        self.assertEqual(["a", "c"], index.get_parents_with_ghosts("b"))
660
688
            "a option 0 1 :",
661
689
            "b option 0 1 :"
662
690
            ])
663
 
        index = _KnitIndex(transport, "filename", "r")
 
691
        index = self.get_knit_index(transport, "filename", "r")
664
692
 
665
693
        check = index.check_versions_present
666
694
 
671
699
        self.assertRaises(RevisionNotPresent, check, ["c"])
672
700
        self.assertRaises(RevisionNotPresent, check, ["a", "b", "c"])
673
701
 
 
702
    def test_impossible_parent(self):
 
703
        """Test we get KnitCorrupt if the parent couldn't possibly exist."""
 
704
        transport = MockTransport([
 
705
            _KnitIndex.HEADER,
 
706
            "a option 0 1 :",
 
707
            "b option 0 1 4 :"  # We don't have a 4th record
 
708
            ])
 
709
        try:
 
710
            self.assertRaises(errors.KnitCorrupt,
 
711
                              self.get_knit_index, transport, 'filename', 'r')
 
712
        except TypeError, e:
 
713
            if (str(e) == ('exceptions must be strings, classes, or instances,'
 
714
                           ' not exceptions.IndexError')
 
715
                and sys.version_info[0:2] >= (2,5)):
 
716
                self.knownFailure('Pyrex <0.9.5 fails with TypeError when'
 
717
                                  ' raising new style exceptions with python'
 
718
                                  ' >=2.5')
 
719
            else:
 
720
                raise
 
721
 
 
722
    def test_corrupted_parent(self):
 
723
        transport = MockTransport([
 
724
            _KnitIndex.HEADER,
 
725
            "a option 0 1 :",
 
726
            "b option 0 1 :",
 
727
            "c option 0 1 1v :", # Can't have a parent of '1v'
 
728
            ])
 
729
        try:
 
730
            self.assertRaises(errors.KnitCorrupt,
 
731
                              self.get_knit_index, transport, 'filename', 'r')
 
732
        except TypeError, e:
 
733
            if (str(e) == ('exceptions must be strings, classes, or instances,'
 
734
                           ' not exceptions.ValueError')
 
735
                and sys.version_info[0:2] >= (2,5)):
 
736
                self.knownFailure('Pyrex <0.9.5 fails with TypeError when'
 
737
                                  ' raising new style exceptions with python'
 
738
                                  ' >=2.5')
 
739
            else:
 
740
                raise
 
741
 
 
742
    def test_corrupted_parent_in_list(self):
 
743
        transport = MockTransport([
 
744
            _KnitIndex.HEADER,
 
745
            "a option 0 1 :",
 
746
            "b option 0 1 :",
 
747
            "c option 0 1 1 v :", # Can't have a parent of 'v'
 
748
            ])
 
749
        try:
 
750
            self.assertRaises(errors.KnitCorrupt,
 
751
                              self.get_knit_index, transport, 'filename', 'r')
 
752
        except TypeError, e:
 
753
            if (str(e) == ('exceptions must be strings, classes, or instances,'
 
754
                           ' not exceptions.ValueError')
 
755
                and sys.version_info[0:2] >= (2,5)):
 
756
                self.knownFailure('Pyrex <0.9.5 fails with TypeError when'
 
757
                                  ' raising new style exceptions with python'
 
758
                                  ' >=2.5')
 
759
            else:
 
760
                raise
 
761
 
 
762
    def test_invalid_position(self):
 
763
        transport = MockTransport([
 
764
            _KnitIndex.HEADER,
 
765
            "a option 1v 1 :",
 
766
            ])
 
767
        try:
 
768
            self.assertRaises(errors.KnitCorrupt,
 
769
                              self.get_knit_index, transport, 'filename', 'r')
 
770
        except TypeError, e:
 
771
            if (str(e) == ('exceptions must be strings, classes, or instances,'
 
772
                           ' not exceptions.ValueError')
 
773
                and sys.version_info[0:2] >= (2,5)):
 
774
                self.knownFailure('Pyrex <0.9.5 fails with TypeError when'
 
775
                                  ' raising new style exceptions with python'
 
776
                                  ' >=2.5')
 
777
            else:
 
778
                raise
 
779
 
 
780
    def test_invalid_size(self):
 
781
        transport = MockTransport([
 
782
            _KnitIndex.HEADER,
 
783
            "a option 1 1v :",
 
784
            ])
 
785
        try:
 
786
            self.assertRaises(errors.KnitCorrupt,
 
787
                              self.get_knit_index, transport, 'filename', 'r')
 
788
        except TypeError, e:
 
789
            if (str(e) == ('exceptions must be strings, classes, or instances,'
 
790
                           ' not exceptions.ValueError')
 
791
                and sys.version_info[0:2] >= (2,5)):
 
792
                self.knownFailure('Pyrex <0.9.5 fails with TypeError when'
 
793
                                  ' raising new style exceptions with python'
 
794
                                  ' >=2.5')
 
795
            else:
 
796
                raise
 
797
 
 
798
    def test_short_line(self):
 
799
        transport = MockTransport([
 
800
            _KnitIndex.HEADER,
 
801
            "a option 0 10  :",
 
802
            "b option 10 10 0", # This line isn't terminated, ignored
 
803
            ])
 
804
        index = self.get_knit_index(transport, "filename", "r")
 
805
        self.assertEqual(['a'], index.get_versions())
 
806
 
 
807
    def test_skip_incomplete_record(self):
 
808
        # A line with bogus data should just be skipped
 
809
        transport = MockTransport([
 
810
            _KnitIndex.HEADER,
 
811
            "a option 0 10  :",
 
812
            "b option 10 10 0", # This line isn't terminated, ignored
 
813
            "c option 20 10 0 :", # Properly terminated, and starts with '\n'
 
814
            ])
 
815
        index = self.get_knit_index(transport, "filename", "r")
 
816
        self.assertEqual(['a', 'c'], index.get_versions())
 
817
 
 
818
    def test_trailing_characters(self):
 
819
        # A line with bogus data should just be skipped
 
820
        transport = MockTransport([
 
821
            _KnitIndex.HEADER,
 
822
            "a option 0 10  :",
 
823
            "b option 10 10 0 :a", # This line has extra trailing characters
 
824
            "c option 20 10 0 :", # Properly terminated, and starts with '\n'
 
825
            ])
 
826
        index = self.get_knit_index(transport, "filename", "r")
 
827
        self.assertEqual(['a', 'c'], index.get_versions())
 
828
 
 
829
 
 
830
class LowLevelKnitIndexTests_c(LowLevelKnitIndexTests):
 
831
 
 
832
    _test_needs_features = [CompiledKnitFeature]
 
833
 
 
834
    def get_knit_index(self, *args, **kwargs):
 
835
        orig = knit._load_data
 
836
        def reset():
 
837
            knit._load_data = orig
 
838
        self.addCleanup(reset)
 
839
        from bzrlib._knit_load_data_c import _load_data_c
 
840
        knit._load_data = _load_data_c
 
841
        return _KnitIndex(*args, **kwargs)
 
842
 
 
843
 
674
844
 
675
845
class KnitTests(TestCaseWithTransport):
676
846
    """Class containing knit test helper routines."""
971
1141
        knit = KnitVersionedFile('test', get_transport('.'), access_mode='r')
972
1142
        self.assertEqual(['revid', 'revid2'], knit.versions())
973
1143
        # write a short write to the file and ensure that its ignored
974
 
        indexfile = file('test.kndx', 'at')
 
1144
        indexfile = file('test.kndx', 'ab')
975
1145
        indexfile.write('\nrevid3 line-delta 166 82 1 2 3 4 5 .phwoar:demo ')
976
1146
        indexfile.close()
977
1147
        # we should be able to load this file again