~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_knit.py

  • Committer: Aaron Bentley
  • Date: 2007-07-17 13:27:14 UTC
  • mfrom: (2624 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2631.
  • Revision ID: abentley@panoramicfeedback.com-20070717132714-tmzx9khmg9501k51
Merge from bzr.dev

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