124
126
"""Assert that the derived matching blocks match real output"""
125
127
source_lines = source.splitlines(True)
126
128
target_lines = target.splitlines(True)
128
131
if noeol and not line.endswith('\n'):
129
132
return line + '\n'
132
source_content = self._make_content([(None, nl(l)) for l in source_lines])
133
target_content = self._make_content([(None, nl(l)) for l in target_lines])
135
source_content = self._make_content(
136
[(None, nl(l)) for l in source_lines])
137
target_content = self._make_content(
138
[(None, nl(l)) for l in target_lines])
134
139
line_delta = source_content.line_delta(target_content)
135
140
delta_blocks = list(KnitContent.get_line_delta_blocks(line_delta,
136
source_lines, target_lines))
141
source_lines, target_lines))
137
142
matcher = PatienceSequenceMatcher(None, source_lines, target_lines)
138
143
matcher_blocks = list(matcher.get_matching_blocks())
139
144
self.assertEqual(matcher_blocks, delta_blocks)
220
225
content = self._make_content([])
221
226
self.assertEqual(content.annotate(), [])
223
content = self._make_content([("origin1", "text1"), ("origin2", "text2")])
228
content = self._make_content(
229
[("origin1", "text1"), ("origin2", "text2")])
224
230
self.assertEqual(content.annotate(),
225
[("bogus", "text1"), ("bogus", "text2")])
231
[("bogus", "text1"), ("bogus", "text2")])
227
233
def test_line_delta(self):
228
234
content1 = self._make_content([("", "a"), ("", "b")])
229
235
content2 = self._make_content([("", "a"), ("", "a"), ("", "c")])
230
236
self.assertEqual(content1.line_delta(content2),
231
[(1, 2, 2, ["a", "c"])])
237
[(1, 2, 2, ["a", "c"])])
233
239
def test_line_delta_iter(self):
234
240
content1 = self._make_content([("", "a"), ("", "b")])
247
253
content = self._make_content([])
248
254
self.assertEqual(content.annotate(), [])
250
content = self._make_content([(b"origin1", b"text1"), (b"origin2", b"text2")])
256
content = self._make_content(
257
[(b"origin1", b"text1"), (b"origin2", b"text2")])
251
258
self.assertEqual(content.annotate(),
252
[(b"origin1", b"text1"), (b"origin2", b"text2")])
259
[(b"origin1", b"text1"), (b"origin2", b"text2")])
254
261
def test_line_delta(self):
255
262
content1 = self._make_content([("", "a"), ("", "b")])
256
263
content2 = self._make_content([("", "a"), ("", "a"), ("", "c")])
257
264
self.assertEqual(content1.line_delta(content2),
258
[(1, 2, 2, [("", "a"), ("", "c")])])
265
[(1, 2, 2, [("", "a"), ("", "c")])])
260
267
def test_line_delta_iter(self):
261
268
content1 = self._make_content([("", "a"), ("", "b")])
322
329
"""add_raw_records with many records and read some back."""
323
330
access = self.get_access()
324
331
memos = access.add_raw_records([(b'key', 10), (b'key2', 2), (b'key3', 5)],
325
b'12345678901234567')
332
b'12345678901234567')
326
333
self.assertEqual([b'1234567890', b'12', b'34567'],
327
list(access.get_raw_records(memos)))
334
list(access.get_raw_records(memos)))
328
335
self.assertEqual([b'1234567890'],
329
list(access.get_raw_records(memos[0:1])))
336
list(access.get_raw_records(memos[0:1])))
330
337
self.assertEqual([b'12'],
331
list(access.get_raw_records(memos[1:2])))
338
list(access.get_raw_records(memos[1:2])))
332
339
self.assertEqual([b'34567'],
333
list(access.get_raw_records(memos[2:3])))
340
list(access.get_raw_records(memos[2:3])))
334
341
self.assertEqual([b'1234567890', b'34567'],
335
list(access.get_raw_records(memos[0:1] + memos[2:3])))
342
list(access.get_raw_records(memos[0:1] + memos[2:3])))
338
345
class TestKnitKnitAccess(TestCaseWithMemoryTransport, KnitRecordAccessTestsMixin):
493
503
memos.extend(access.add_raw_records([(b'key', 5)], b'alpha'))
495
505
transport = self.get_transport()
496
access = pack_repo._DirectPackAccess({"FOO":(transport, 'packfile'),
497
"FOOBAR":(transport, 'pack2'),
498
"BAZ":(transport, 'pack3')})
506
access = pack_repo._DirectPackAccess({"FOO": (transport, 'packfile'),
507
"FOOBAR": (transport, 'pack2'),
508
"BAZ": (transport, 'pack3')})
499
509
self.assertEqual([b'1234567890', b'12345', b'alpha'],
500
list(access.get_raw_records(memos)))
510
list(access.get_raw_records(memos)))
501
511
self.assertEqual([b'1234567890'],
502
list(access.get_raw_records(memos[0:1])))
512
list(access.get_raw_records(memos[0:1])))
503
513
self.assertEqual([b'12345'],
504
list(access.get_raw_records(memos[1:2])))
514
list(access.get_raw_records(memos[1:2])))
505
515
self.assertEqual([b'alpha'],
506
list(access.get_raw_records(memos[2:3])))
516
list(access.get_raw_records(memos[2:3])))
507
517
self.assertEqual([b'1234567890', b'alpha'],
508
list(access.get_raw_records(memos[0:1] + memos[2:3])))
518
list(access.get_raw_records(memos[0:1] + memos[2:3])))
510
520
def test_set_writer(self):
511
521
"""The writer should be settable post construction."""
599
610
memos = self.make_pack_file()
600
611
transport = self.get_transport()
601
612
failing_transport = MockReadvFailingTransport(
602
[transport.get_bytes('packname')])
613
[transport.get_bytes('packname')])
603
614
reload_called, reload_func = self.make_reload_func()
604
615
access = pack_repo._DirectPackAccess(
605
{'foo':(failing_transport, 'packname')})
616
{'foo': (failing_transport, 'packname')})
606
617
# Asking for a single record will not trigger the Mock failure
607
618
self.assertEqual([b'1234567890'],
608
list(access.get_raw_records(memos[:1])))
619
list(access.get_raw_records(memos[:1])))
609
620
self.assertEqual([b'12345'],
610
list(access.get_raw_records(memos[1:2])))
621
list(access.get_raw_records(memos[1:2])))
611
622
# A multiple offset readv() will fail mid-way through
612
623
e = self.assertListRaises(errors.NoSuchFile,
613
624
access.get_raw_records, memos)
707
718
self.assertEqual([1, 1, 0], reload_counter)
708
719
# Now do it again, to make sure the result is equivalent
709
720
plain_lines = sorted(vf.iter_lines_added_or_present_in_keys(keys))
710
self.assertEqual([1, 1, 0], reload_counter) # No extra reloading
721
self.assertEqual([1, 1, 0], reload_counter) # No extra reloading
711
722
self.assertEqual(plain_lines, reload_lines)
712
723
self.assertEqual(21, len(plain_lines))
713
724
# Now delete all pack files, and see that we raise the right error
714
725
for trans, name in vf._access._indices.values():
715
726
trans.delete(name)
716
727
self.assertListRaises(errors.NoSuchFile,
717
vf.iter_lines_added_or_present_in_keys, keys)
728
vf.iter_lines_added_or_present_in_keys, keys)
718
729
self.assertEqual([2, 1, 1], reload_counter)
720
731
def test_get_record_stream_yields_disk_sorted_order(self):
997
1010
# check that the index used is the first one written. (Specific
998
1011
# to KnitIndex style indices.
999
1012
self.assertEqual(b"1", index._dictionary_compress([(b"version",)]))
1000
self.assertEqual(((b"version",), 3, 4), index.get_position((b"version",)))
1013
self.assertEqual(((b"version",), 3, 4),
1014
index.get_position((b"version",)))
1001
1015
self.assertEqual([b"options3"], index.get_options((b"version",)))
1002
1016
self.assertEqual({(b"version",): ((b"parent",), (b"other",))},
1003
index.get_parent_map([(b"version",)]))
1017
index.get_parent_map([(b"version",)]))
1005
1019
def test_read_compressed_parents(self):
1006
1020
transport = MockTransport([
1398
1413
ann = self.make_annotator()
1399
1414
rev_key = (b'rev-id',)
1400
1415
parent_key = (b'parent-id',)
1401
parent_ann = [(parent_key,)]*3
1416
parent_ann = [(parent_key,)] * 3
1402
1417
block_key = (rev_key, parent_key)
1403
1418
ann._annotations_cache[parent_key] = parent_ann
1404
1419
ann._matching_blocks[block_key] = [(0, 1, 1), (3, 3, 0)]
1405
1420
# We should not try to access any parent_lines content, because we know
1406
1421
# we already have the matching blocks
1407
1422
par_ann, blocks = ann._get_parent_annotations_and_matches(rev_key,
1408
[b'1\n', b'2\n', b'3\n'], parent_key)
1423
[b'1\n', b'2\n', b'3\n'], parent_key)
1409
1424
self.assertEqual(parent_ann, par_ann)
1410
1425
self.assertEqual([(0, 1, 1), (3, 3, 0)], blocks)
1411
1426
self.assertEqual({}, ann._matching_blocks)
1520
1535
idx = knit._index
1521
1536
idx.add_records([((b'a-1',), [b'fulltext'], ((b'a-1',), 0, 0), [])])
1522
1537
self.check_file_contents('test.kndx',
1523
b'# bzr knit index 8\n'
1525
b'a-1 fulltext 0 0 :'
1538
b'# bzr knit index 8\n'
1540
b'a-1 fulltext 0 0 :'
1527
1542
idx.add_records([
1528
1543
((b'a-2',), [b'fulltext'], ((b'a-2',), 0, 0), [(b'a-1',)]),
1529
1544
((b'a-3',), [b'fulltext'], ((b'a-3',), 0, 0), [(b'a-2',)]),
1531
1546
self.check_file_contents('test.kndx',
1532
b'# bzr knit index 8\n'
1534
b'a-1 fulltext 0 0 :\n'
1535
b'a-2 fulltext 0 0 0 :\n'
1536
b'a-3 fulltext 0 0 1 :'
1547
b'# bzr knit index 8\n'
1549
b'a-1 fulltext 0 0 :\n'
1550
b'a-2 fulltext 0 0 0 :\n'
1551
b'a-3 fulltext 0 0 1 :'
1538
1553
self.assertEqual({(b'a-3',), (b'a-1',), (b'a-2',)}, idx.keys())
1539
1554
self.assertEqual({
1540
1555
(b'a-1',): (((b'a-1',), 0, 0), None, (), ('fulltext', False)),
1626
1641
((b'tip', ), b'N0 100', ([(b'parent', )], [], )),
1627
1642
((b'tail', ), b'', ([], []))])
1628
1643
index2 = self.make_g_index('2', 2, [
1629
((b'parent', ), b' 100 78', ([(b'tail', ), (b'ghost', )], [(b'tail', )])),
1644
((b'parent', ), b' 100 78',
1645
([(b'tail', ), (b'ghost', )], [(b'tail', )])),
1630
1646
((b'separate', ), b'', ([], []))])
1632
1648
# just blob location and graph in the index.
1643
1659
add_callback = self.catch_add
1645
1661
add_callback = None
1646
return _KnitGraphIndex(combined_index, lambda:True, deltas=deltas,
1647
add_callback=add_callback)
1662
return _KnitGraphIndex(combined_index, lambda: True, deltas=deltas,
1663
add_callback=add_callback)
1649
1665
def test_keys(self):
1650
1666
index = self.two_graph_index()
1651
1667
self.assertEqual({(b'tail',), (b'tip',), (b'parent',), (b'separate',)},
1654
1670
def test_get_position(self):
1655
1671
index = self.two_graph_index()
1656
self.assertEqual((index._graph_index._indices[0], 0, 100), index.get_position((b'tip',)))
1657
self.assertEqual((index._graph_index._indices[1], 100, 78), index.get_position((b'parent',)))
1673
(index._graph_index._indices[0], 0, 100), index.get_position((b'tip',)))
1675
(index._graph_index._indices[1], 100, 78), index.get_position((b'parent',)))
1659
1677
def test_get_method_deltas(self):
1660
1678
index = self.two_graph_index(deltas=True)
1670
1688
def test_get_options_deltas(self):
1671
1689
index = self.two_graph_index(deltas=True)
1672
self.assertEqual([b'fulltext', b'no-eol'], index.get_options((b'tip',)))
1690
self.assertEqual([b'fulltext', b'no-eol'],
1691
index.get_options((b'tip',)))
1673
1692
self.assertEqual([b'line-delta'], index.get_options((b'parent',)))
1675
1694
def test_get_options_no_deltas(self):
1676
1695
# check that the parent-history lookup is ignored with deltas=False.
1677
1696
index = self.two_graph_index(deltas=False)
1678
self.assertEqual([b'fulltext', b'no-eol'], index.get_options((b'tip',)))
1697
self.assertEqual([b'fulltext', b'no-eol'],
1698
index.get_options((b'tip',)))
1679
1699
self.assertEqual([b'fulltext'], index.get_options((b'parent',)))
1681
1701
def test_get_parent_map(self):
1682
1702
index = self.two_graph_index()
1683
self.assertEqual({(b'parent',):((b'tail',), (b'ghost',))},
1684
index.get_parent_map([(b'parent',), (b'ghost',)]))
1703
self.assertEqual({(b'parent',): ((b'tail',), (b'ghost',))},
1704
index.get_parent_map([(b'parent',), (b'ghost',)]))
1686
1706
def catch_add(self, entries):
1687
1707
self.caught_entries.append(entries)
1689
1709
def test_add_no_callback_errors(self):
1690
1710
index = self.two_graph_index()
1691
1711
self.assertRaises(errors.ReadOnlyError, index.add_records,
1692
[((b'new',), b'fulltext,no-eol', (None, 50, 60), [b'separate'])])
1712
[((b'new',), b'fulltext,no-eol', (None, 50, 60), [b'separate'])])
1694
1714
def test_add_version_smoke(self):
1695
1715
index = self.two_graph_index(catch_adds=True)
1696
1716
index.add_records([((b'new',), b'fulltext,no-eol', (None, 50, 60),
1698
1718
self.assertEqual([[((b'new', ), b'N50 60', (((b'separate',),),))]],
1699
self.caught_entries)
1719
self.caught_entries)
1701
1721
def test_add_version_delta_not_delta_index(self):
1702
1722
index = self.two_graph_index(catch_adds=True)
1703
1723
self.assertRaises(KnitCorrupt, index.add_records,
1704
[((b'new',), b'no-eol,line-delta', (None, 0, 100), [(b'parent',)])])
1724
[((b'new',), b'no-eol,line-delta', (None, 0, 100), [(b'parent',)])])
1705
1725
self.assertEqual([], self.caught_entries)
1707
1727
def test_add_version_same_dup(self):
1708
1728
index = self.two_graph_index(catch_adds=True)
1709
1729
# options can be spelt two different ways
1710
index.add_records([((b'tip',), b'fulltext,no-eol', (None, 0, 100), [(b'parent',)])])
1711
index.add_records([((b'tip',), b'no-eol,fulltext', (None, 0, 100), [(b'parent',)])])
1731
[((b'tip',), b'fulltext,no-eol', (None, 0, 100), [(b'parent',)])])
1733
[((b'tip',), b'no-eol,fulltext', (None, 0, 100), [(b'parent',)])])
1712
1734
# position/length are ignored (because each pack could have fulltext or
1713
1735
# delta, and be at a different position.
1714
1736
index.add_records([((b'tip',), b'fulltext,no-eol', (None, 50, 100),
1716
1738
index.add_records([((b'tip',), b'fulltext,no-eol', (None, 0, 1000),
1718
1740
# but neither should have added data:
1719
1741
self.assertEqual([[], [], [], []], self.caught_entries)
1722
1744
index = self.two_graph_index(deltas=True, catch_adds=True)
1723
1745
# change options
1724
1746
self.assertRaises(KnitCorrupt, index.add_records,
1725
[((b'tip',), b'line-delta', (None, 0, 100), [(b'parent',)])])
1747
[((b'tip',), b'line-delta', (None, 0, 100), [(b'parent',)])])
1726
1748
self.assertRaises(KnitCorrupt, index.add_records,
1727
[((b'tip',), b'fulltext', (None, 0, 100), [(b'parent',)])])
1749
[((b'tip',), b'fulltext', (None, 0, 100), [(b'parent',)])])
1729
1751
self.assertRaises(KnitCorrupt, index.add_records,
1730
[((b'tip',), b'fulltext,no-eol', (None, 0, 100), [])])
1752
[((b'tip',), b'fulltext,no-eol', (None, 0, 100), [])])
1731
1753
self.assertEqual([], self.caught_entries)
1733
1755
def test_add_versions_nodeltas(self):
1734
1756
index = self.two_graph_index(catch_adds=True)
1735
1757
index.add_records([
1736
((b'new',), b'fulltext,no-eol', (None, 50, 60), [(b'separate',)]),
1737
((b'new2',), b'fulltext', (None, 0, 6), [(b'new',)]),
1758
((b'new',), b'fulltext,no-eol', (None, 50, 60), [(b'separate',)]),
1759
((b'new2',), b'fulltext', (None, 0, 6), [(b'new',)]),
1739
1761
self.assertEqual([((b'new', ), b'N50 60', (((b'separate',),),)),
1740
((b'new2', ), b' 0 6', (((b'new',),),))],
1741
sorted(self.caught_entries[0]))
1762
((b'new2', ), b' 0 6', (((b'new',),),))],
1763
sorted(self.caught_entries[0]))
1742
1764
self.assertEqual(1, len(self.caught_entries))
1744
1766
def test_add_versions_deltas(self):
1745
1767
index = self.two_graph_index(deltas=True, catch_adds=True)
1746
1768
index.add_records([
1747
((b'new',), b'fulltext,no-eol', (None, 50, 60), [(b'separate',)]),
1748
((b'new2',), b'line-delta', (None, 0, 6), [(b'new',)]),
1769
((b'new',), b'fulltext,no-eol', (None, 50, 60), [(b'separate',)]),
1770
((b'new2',), b'line-delta', (None, 0, 6), [(b'new',)]),
1750
1772
self.assertEqual([((b'new', ), b'N50 60', (((b'separate',),), ())),
1751
((b'new2', ), b' 0 6', (((b'new',),), ((b'new',),), ))],
1752
sorted(self.caught_entries[0]))
1773
((b'new2', ), b' 0 6', (((b'new',),), ((b'new',),), ))],
1774
sorted(self.caught_entries[0]))
1753
1775
self.assertEqual(1, len(self.caught_entries))
1755
1777
def test_add_versions_delta_not_delta_index(self):
1756
1778
index = self.two_graph_index(catch_adds=True)
1757
1779
self.assertRaises(KnitCorrupt, index.add_records,
1758
[((b'new',), b'no-eol,line-delta', (None, 0, 100), [(b'parent',)])])
1780
[((b'new',), b'no-eol,line-delta', (None, 0, 100), [(b'parent',)])])
1759
1781
self.assertEqual([], self.caught_entries)
1761
1783
def test_add_versions_random_id_accepted(self):
1766
1788
index = self.two_graph_index(catch_adds=True)
1767
1789
# options can be spelt two different ways
1768
1790
index.add_records([((b'tip',), b'fulltext,no-eol', (None, 0, 100),
1770
1792
index.add_records([((b'tip',), b'no-eol,fulltext', (None, 0, 100),
1772
1794
# position/length are ignored (because each pack could have fulltext or
1773
1795
# delta, and be at a different position.
1774
1796
index.add_records([((b'tip',), b'fulltext,no-eol', (None, 50, 100),
1776
1798
index.add_records([((b'tip',), b'fulltext,no-eol', (None, 0, 1000),
1778
1800
# but neither should have added data.
1779
1801
self.assertEqual([[], [], [], []], self.caught_entries)
1782
1804
index = self.two_graph_index(deltas=True, catch_adds=True)
1783
1805
# change options
1784
1806
self.assertRaises(KnitCorrupt, index.add_records,
1785
[((b'tip',), b'line-delta', (None, 0, 100), [(b'parent',)])])
1807
[((b'tip',), b'line-delta', (None, 0, 100), [(b'parent',)])])
1786
1808
self.assertRaises(KnitCorrupt, index.add_records,
1787
[((b'tip',), b'fulltext', (None, 0, 100), [(b'parent',)])])
1809
[((b'tip',), b'fulltext', (None, 0, 100), [(b'parent',)])])
1789
1811
self.assertRaises(KnitCorrupt, index.add_records,
1790
[((b'tip',), b'fulltext,no-eol', (None, 0, 100), [])])
1812
[((b'tip',), b'fulltext,no-eol', (None, 0, 100), [])])
1791
1813
# change options in the second record
1792
1814
self.assertRaises(KnitCorrupt, index.add_records,
1793
[((b'tip',), b'fulltext,no-eol', (None, 0, 100), [(b'parent',)]),
1794
((b'tip',), b'line-delta', (None, 0, 100), [(b'parent',)])])
1815
[((b'tip',), b'fulltext,no-eol', (None, 0, 100), [(b'parent',)]),
1816
((b'tip',), b'line-delta', (None, 0, 100), [(b'parent',)])])
1795
1817
self.assertEqual([], self.caught_entries)
1797
1819
def make_g_index_missing_compression_parent(self):
1798
1820
graph_index = self.make_g_index('missing_comp', 2,
1799
[((b'tip', ), b' 100 78',
1800
([(b'missing-parent', ), (b'ghost', )], [(b'missing-parent', )]))])
1821
[((b'tip', ), b' 100 78',
1822
([(b'missing-parent', ), (b'ghost', )], [(b'missing-parent', )]))])
1801
1823
return graph_index
1803
1825
def make_g_index_missing_parent(self):
1804
1826
graph_index = self.make_g_index('missing_parent', 2,
1805
[((b'parent', ), b' 100 78', ([], [])),
1806
((b'tip', ), b' 100 78',
1807
([(b'parent', ), (b'missing-parent', )], [(b'parent', )])),
1827
[((b'parent', ), b' 100 78', ([], [])),
1828
((b'tip', ), b' 100 78',
1829
([(b'parent', ), (b'missing-parent', )], [(b'parent', )])),
1809
1831
return graph_index
1811
1833
def make_g_index_no_external_refs(self):
1812
1834
graph_index = self.make_g_index('no_external_refs', 2,
1813
[((b'rev', ), b' 100 78',
1814
([(b'parent', ), (b'ghost', )], []))])
1835
[((b'rev', ), b' 100 78',
1836
([(b'parent', ), (b'ghost', )], []))])
1815
1837
return graph_index
1817
1839
def test_add_good_unvalidated_index(self):
1886
1908
def test_add_mulitiple_unvalidated_indices_with_mutual_dependencies(self):
1887
1909
graph_index_a = self.make_g_index('one', 2,
1888
[((b'parent-one', ), b' 100 78', ([(b'non-compression-parent',)], [])),
1889
((b'child-of-two', ), b' 100 78',
1890
([(b'parent-two',)], [(b'parent-two',)]))])
1910
[((b'parent-one', ), b' 100 78', ([(b'non-compression-parent',)], [])),
1911
((b'child-of-two', ), b' 100 78',
1912
([(b'parent-two',)], [(b'parent-two',)]))])
1891
1913
graph_index_b = self.make_g_index('two', 2,
1892
[((b'parent-two', ), b' 100 78', ([(b'non-compression-parent',)], [])),
1893
((b'child-of-one', ), b' 100 78',
1894
([(b'parent-one',)], [(b'parent-one',)]))])
1914
[((b'parent-two', ), b' 100 78', ([(b'non-compression-parent',)], [])),
1915
((b'child-of-one', ), b' 100 78',
1916
([(b'parent-one',)], [(b'parent-one',)]))])
1895
1917
combined = CombinedGraphIndex([graph_index_a, graph_index_b])
1896
1918
index = _KnitGraphIndex(combined, lambda: True, deltas=True)
1897
1919
index.scan_unvalidated_index(graph_index_a)
1945
1967
add_callback = self.catch_add
1947
1969
add_callback = None
1948
return _KnitGraphIndex(combined_index, lambda:True, parents=False,
1949
add_callback=add_callback)
1970
return _KnitGraphIndex(combined_index, lambda: True, parents=False,
1971
add_callback=add_callback)
1951
1973
def test_keys(self):
1952
1974
index = self.two_graph_index()
1953
1975
self.assertEqual({(b'tail',), (b'tip',), (b'parent',), (b'separate',)},
1956
1978
def test_get_position(self):
1957
1979
index = self.two_graph_index()
1958
1980
self.assertEqual((index._graph_index._indices[0], 0, 100),
1959
index.get_position((b'tip',)))
1981
index.get_position((b'tip',)))
1960
1982
self.assertEqual((index._graph_index._indices[1], 100, 78),
1961
index.get_position((b'parent',)))
1983
index.get_position((b'parent',)))
1963
1985
def test_get_method(self):
1964
1986
index = self.two_graph_index()
1968
1990
def test_get_options(self):
1969
1991
index = self.two_graph_index()
1970
self.assertEqual([b'fulltext', b'no-eol'], index.get_options((b'tip',)))
1992
self.assertEqual([b'fulltext', b'no-eol'],
1993
index.get_options((b'tip',)))
1971
1994
self.assertEqual([b'fulltext'], index.get_options((b'parent',)))
1973
1996
def test_get_parent_map(self):
1974
1997
index = self.two_graph_index()
1975
self.assertEqual({(b'parent',):None},
1976
index.get_parent_map([(b'parent',), (b'ghost',)]))
1998
self.assertEqual({(b'parent',): None},
1999
index.get_parent_map([(b'parent',), (b'ghost',)]))
1978
2001
def catch_add(self, entries):
1979
2002
self.caught_entries.append(entries)
1981
2004
def test_add_no_callback_errors(self):
1982
2005
index = self.two_graph_index()
1983
2006
self.assertRaises(errors.ReadOnlyError, index.add_records,
1984
[((b'new',), b'fulltext,no-eol', (None, 50, 60), [(b'separate',)])])
2007
[((b'new',), b'fulltext,no-eol', (None, 50, 60), [(b'separate',)])])
1986
2009
def test_add_version_smoke(self):
1987
2010
index = self.two_graph_index(catch_adds=True)
1988
index.add_records([((b'new',), b'fulltext,no-eol', (None, 50, 60), [])])
2012
[((b'new',), b'fulltext,no-eol', (None, 50, 60), [])])
1989
2013
self.assertEqual([[((b'new', ), b'N50 60')]],
1990
self.caught_entries)
2014
self.caught_entries)
1992
2016
def test_add_version_delta_not_delta_index(self):
1993
2017
index = self.two_graph_index(catch_adds=True)
1994
2018
self.assertRaises(KnitCorrupt, index.add_records,
1995
[((b'new',), b'no-eol,line-delta', (None, 0, 100), [])])
2019
[((b'new',), b'no-eol,line-delta', (None, 0, 100), [])])
1996
2020
self.assertEqual([], self.caught_entries)
1998
2022
def test_add_version_same_dup(self):
1999
2023
index = self.two_graph_index(catch_adds=True)
2000
2024
# options can be spelt two different ways
2001
index.add_records([((b'tip',), b'fulltext,no-eol', (None, 0, 100), [])])
2002
index.add_records([((b'tip',), b'no-eol,fulltext', (None, 0, 100), [])])
2026
[((b'tip',), b'fulltext,no-eol', (None, 0, 100), [])])
2028
[((b'tip',), b'no-eol,fulltext', (None, 0, 100), [])])
2003
2029
# position/length are ignored (because each pack could have fulltext or
2004
2030
# delta, and be at a different position.
2005
index.add_records([((b'tip',), b'fulltext,no-eol', (None, 50, 100), [])])
2006
index.add_records([((b'tip',), b'fulltext,no-eol', (None, 0, 1000), [])])
2032
[((b'tip',), b'fulltext,no-eol', (None, 50, 100), [])])
2034
[((b'tip',), b'fulltext,no-eol', (None, 0, 1000), [])])
2007
2035
# but neither should have added data.
2008
2036
self.assertEqual([[], [], [], []], self.caught_entries)
2011
2039
index = self.two_graph_index(catch_adds=True)
2012
2040
# change options
2013
2041
self.assertRaises(KnitCorrupt, index.add_records,
2014
[((b'tip',), b'no-eol,line-delta', (None, 0, 100), [])])
2015
self.assertRaises(KnitCorrupt, index.add_records,
2016
[((b'tip',), b'line-delta,no-eol', (None, 0, 100), [])])
2017
self.assertRaises(KnitCorrupt, index.add_records,
2018
[((b'tip',), b'fulltext', (None, 0, 100), [])])
2042
[((b'tip',), b'no-eol,line-delta', (None, 0, 100), [])])
2043
self.assertRaises(KnitCorrupt, index.add_records,
2044
[((b'tip',), b'line-delta,no-eol', (None, 0, 100), [])])
2045
self.assertRaises(KnitCorrupt, index.add_records,
2046
[((b'tip',), b'fulltext', (None, 0, 100), [])])
2020
2048
self.assertRaises(KnitCorrupt, index.add_records,
2021
[((b'tip',), b'fulltext,no-eol', (None, 0, 100), [(b'parent',)])])
2049
[((b'tip',), b'fulltext,no-eol', (None, 0, 100), [(b'parent',)])])
2022
2050
self.assertEqual([], self.caught_entries)
2024
2052
def test_add_versions(self):
2025
2053
index = self.two_graph_index(catch_adds=True)
2026
2054
index.add_records([
2027
((b'new',), b'fulltext,no-eol', (None, 50, 60), []),
2028
((b'new2',), b'fulltext', (None, 0, 6), []),
2055
((b'new',), b'fulltext,no-eol', (None, 50, 60), []),
2056
((b'new2',), b'fulltext', (None, 0, 6), []),
2030
2058
self.assertEqual([((b'new', ), b'N50 60'), ((b'new2', ), b' 0 6')],
2031
sorted(self.caught_entries[0]))
2059
sorted(self.caught_entries[0]))
2032
2060
self.assertEqual(1, len(self.caught_entries))
2034
2062
def test_add_versions_delta_not_delta_index(self):
2035
2063
index = self.two_graph_index(catch_adds=True)
2036
2064
self.assertRaises(KnitCorrupt, index.add_records,
2037
[((b'new',), b'no-eol,line-delta', (None, 0, 100), [(b'parent',)])])
2065
[((b'new',), b'no-eol,line-delta', (None, 0, 100), [(b'parent',)])])
2038
2066
self.assertEqual([], self.caught_entries)
2040
2068
def test_add_versions_parents_not_parents_index(self):
2041
2069
index = self.two_graph_index(catch_adds=True)
2042
2070
self.assertRaises(KnitCorrupt, index.add_records,
2043
[((b'new',), b'no-eol,fulltext', (None, 0, 100), [(b'parent',)])])
2071
[((b'new',), b'no-eol,fulltext', (None, 0, 100), [(b'parent',)])])
2044
2072
self.assertEqual([], self.caught_entries)
2046
2074
def test_add_versions_random_id_accepted(self):
2050
2078
def test_add_versions_same_dup(self):
2051
2079
index = self.two_graph_index(catch_adds=True)
2052
2080
# options can be spelt two different ways
2053
index.add_records([((b'tip',), b'fulltext,no-eol', (None, 0, 100), [])])
2054
index.add_records([((b'tip',), b'no-eol,fulltext', (None, 0, 100), [])])
2082
[((b'tip',), b'fulltext,no-eol', (None, 0, 100), [])])
2084
[((b'tip',), b'no-eol,fulltext', (None, 0, 100), [])])
2055
2085
# position/length are ignored (because each pack could have fulltext or
2056
2086
# delta, and be at a different position.
2057
index.add_records([((b'tip',), b'fulltext,no-eol', (None, 50, 100), [])])
2058
index.add_records([((b'tip',), b'fulltext,no-eol', (None, 0, 1000), [])])
2088
[((b'tip',), b'fulltext,no-eol', (None, 50, 100), [])])
2090
[((b'tip',), b'fulltext,no-eol', (None, 0, 1000), [])])
2059
2091
# but neither should have added data.
2060
2092
self.assertEqual([[], [], [], []], self.caught_entries)
2063
2095
index = self.two_graph_index(catch_adds=True)
2064
2096
# change options
2065
2097
self.assertRaises(KnitCorrupt, index.add_records,
2066
[((b'tip',), b'no-eol,line-delta', (None, 0, 100), [])])
2067
self.assertRaises(KnitCorrupt, index.add_records,
2068
[((b'tip',), b'line-delta,no-eol', (None, 0, 100), [])])
2069
self.assertRaises(KnitCorrupt, index.add_records,
2070
[((b'tip',), b'fulltext', (None, 0, 100), [])])
2098
[((b'tip',), b'no-eol,line-delta', (None, 0, 100), [])])
2099
self.assertRaises(KnitCorrupt, index.add_records,
2100
[((b'tip',), b'line-delta,no-eol', (None, 0, 100), [])])
2101
self.assertRaises(KnitCorrupt, index.add_records,
2102
[((b'tip',), b'fulltext', (None, 0, 100), [])])
2072
2104
self.assertRaises(KnitCorrupt, index.add_records,
2073
[((b'tip',), b'fulltext,no-eol', (None, 0, 100), [(b'parent',)])])
2105
[((b'tip',), b'fulltext,no-eol', (None, 0, 100), [(b'parent',)])])
2074
2106
# change options in the second record
2075
2107
self.assertRaises(KnitCorrupt, index.add_records,
2076
[((b'tip',), b'fulltext,no-eol', (None, 0, 100), []),
2077
((b'tip',), b'no-eol,line-delta', (None, 0, 100), [])])
2108
[((b'tip',), b'fulltext,no-eol', (None, 0, 100), []),
2109
((b'tip',), b'no-eol,line-delta', (None, 0, 100), [])])
2078
2110
self.assertEqual([], self.caught_entries)
2138
2170
def test__split_by_prefix(self):
2139
2171
self.assertSplitByPrefix({b'f': [(b'f', b'a'), (b'f', b'b')],
2140
2172
b'g': [(b'g', b'b'), (b'g', b'a')],
2142
2174
[(b'f', b'a'), (b'g', b'b'),
2143
2175
(b'g', b'a'), (b'f', b'b')])
2145
2177
self.assertSplitByPrefix({b'f': [(b'f', b'a'), (b'f', b'b')],
2146
2178
b'g': [(b'g', b'b'), (b'g', b'a')],
2148
2180
[(b'f', b'a'), (b'f', b'b'),
2149
2181
(b'g', b'b'), (b'g', b'a')])
2151
2183
self.assertSplitByPrefix({b'f': [(b'f', b'a'), (b'f', b'b')],
2152
2184
b'g': [(b'g', b'b'), (b'g', b'a')],
2154
2186
[(b'f', b'a'), (b'f', b'b'),
2155
2187
(b'g', b'b'), (b'g', b'a')])
2157
2189
self.assertSplitByPrefix({b'f': [(b'f', b'a'), (b'f', b'b')],
2158
2190
b'g': [(b'g', b'b'), (b'g', b'a')],
2159
2191
b'': [(b'a',), (b'b',)]
2160
}, [b'f', b'g', b''],
2192
}, [b'f', b'g', b''],
2161
2193
[(b'f', b'a'), (b'g', b'b'),
2162
2194
(b'a',), (b'b',),
2163
2195
(b'g', b'a'), (b'f', b'b')])
2218
2249
basis.add_lines(key_basis, (), [b'foo\n', b'bar\n'])
2219
2250
basis.calls = []
2220
2251
details = test.annotate(key_basis)
2221
self.assertEqual([(key_basis, b'foo\n'), (key_basis, b'bar\n')], details)
2253
[(key_basis, b'foo\n'), (key_basis, b'bar\n')], details)
2222
2254
# Not optimised to date:
2223
2255
# self.assertEqual([("annotate", key_basis)], basis.calls)
2224
2256
self.assertEqual([('get_parent_map', {key_basis}),
2225
('get_parent_map', {key_basis}),
2226
('get_record_stream', [key_basis], 'topological', True)],
2257
('get_parent_map', {key_basis}),
2258
('get_record_stream', [key_basis], 'topological', True)],
2229
2261
def test_check(self):
2230
2262
# At the moment checking a stacked knit does implicitly check the
2335
2367
# ask which fallbacks have which parents.
2336
2368
self.assertEqual(2, len(calls))
2337
2369
self.assertEqual(
2338
("get_parent_map", {key_basis, key_basis_2, key_missing}),
2370
("get_parent_map", {key_basis, key_basis_2, key_missing}),
2340
2372
# topological is requested from the fallback, because that is what
2341
2373
# was requested at the top level.
2344
("get_record_stream", [key_basis_2, key_basis], 'topological', True),
2376
("get_record_stream", [key_basis_2,
2377
key_basis], 'topological', True),
2345
2378
("get_record_stream", [key_basis, key_basis_2], 'topological', True)])
2347
2380
def test_get_record_stream_unordered_deltas(self):
2466
2499
# XXX: this does somewhat too many calls in making sure of whether it
2467
2500
# has to recreate the full text.
2468
2501
self.assertEqual([("get_parent_map", {key_basis}),
2469
('get_parent_map', {key_basis}),
2470
('get_record_stream', [key_basis], 'unordered', True)],
2472
self.assertEqual({key_delta:(key_basis,)},
2473
test.get_parent_map([key_delta]))
2502
('get_parent_map', {key_basis}),
2503
('get_record_stream', [key_basis], 'unordered', True)],
2505
self.assertEqual({key_delta: (key_basis,)},
2506
test.get_parent_map([key_delta]))
2474
2507
self.assertEqual(b'bar\n', next(test.get_record_stream([key_delta],
2475
'unordered', True)).get_bytes_as('fulltext'))
2508
'unordered', True)).get_bytes_as('fulltext'))
2477
2510
def test_iter_lines_added_or_present_in_keys(self):
2478
2511
# Lines from the basis are returned, and lines for a given key are only
2532
2564
source.add_lines(key_delta, (key_basis,), [b'bar\n'])
2533
2565
diffs = source.make_mpdiffs([key_delta])
2534
2566
test.add_mpdiffs([(key_delta, (key_basis,),
2535
source.get_sha1s([key_delta])[key_delta], diffs[0])])
2567
source.get_sha1s([key_delta])[key_delta], diffs[0])])
2536
2568
self.assertEqual([("get_parent_map", {key_basis}),
2537
('get_record_stream', [key_basis], 'unordered', True),],
2539
self.assertEqual({key_delta:(key_basis,)},
2540
test.get_parent_map([key_delta]))
2569
('get_record_stream', [key_basis], 'unordered', True), ],
2571
self.assertEqual({key_delta: (key_basis,)},
2572
test.get_parent_map([key_delta]))
2541
2573
self.assertEqual(b'bar\n', next(test.get_record_stream([key_delta],
2542
'unordered', True)).get_bytes_as('fulltext'))
2574
'unordered', True)).get_bytes_as('fulltext'))
2544
2576
def test_make_mpdiffs(self):
2545
2577
# Generating an mpdiff across a stacking boundary should detect parent
2552
2584
basis.add_lines(key_right, (), [b'zaphod\n'])
2553
2585
basis.calls = []
2554
2586
test.add_lines(key, (key_left, key_right),
2555
[b'bar\n', b'foo\n', b'zaphod\n'])
2587
[b'bar\n', b'foo\n', b'zaphod\n'])
2556
2588
diffs = test.make_mpdiffs([key])
2557
2589
self.assertEqual([
2558
2590
multiparent.MultiParent([multiparent.ParentText(0, 0, 0, 1),
2559
multiparent.NewText([b'foo\n']),
2560
multiparent.ParentText(1, 0, 2, 1)])],
2591
multiparent.NewText([b'foo\n']),
2592
multiparent.ParentText(1, 0, 2, 1)])],
2562
2594
self.assertEqual(3, len(basis.calls))
2563
2595
self.assertEqual([
2564
2596
("get_parent_map", {key_left, key_right}),
2583
2615
vf.add_lines((b'd2',), ((b'd1',),), [b'd2\n'])
2584
2616
# But heuristics could interfere, so check what happened:
2585
2617
self.assertEqual(['knit-ft-gz', 'knit-delta-gz', 'knit-delta-gz'],
2586
[record.storage_kind for record in
2587
vf.get_record_stream([(b'base',), (b'd1',), (b'd2',)],
2588
'topological', False)])
2618
[record.storage_kind for record in
2619
vf.get_record_stream([(b'base',), (b'd1',), (b'd2',)],
2620
'topological', False)])
2589
2621
# generate a stream of just the deltas include_delta_closure=True,
2590
2622
# serialise to the network, and check that we get a delta closure on the wire.
2591
stream = vf.get_record_stream([(b'd1',), (b'd2',)], 'topological', True)
2623
stream = vf.get_record_stream(
2624
[(b'd1',), (b'd2',)], 'topological', True)
2592
2625
netb = [record.get_bytes_as(record.storage_kind) for record in stream]
2593
2626
# The first bytes should be a memo from _ContentMapGenerator, and the
2594
2627
# second bytes should be empty (because its a API proxy not something
2625
2658
vf.add_lines((b'd2',), ((b'd1',),), [b'd2\n'])
2626
2659
keys = [(b'base',), (b'd1',), (b'd2',)]
2627
2660
generator = _VFContentMapGenerator(vf, keys,
2628
global_map=vf.get_parent_map(keys))
2661
global_map=vf.get_parent_map(keys))
2629
2662
kinds = {(b'base',): 'knit-delta-closure',
2630
(b'd1',): 'knit-delta-closure-ref',
2631
(b'd2',): 'knit-delta-closure-ref',
2663
(b'd1',): 'knit-delta-closure-ref',
2664
(b'd2',): 'knit-delta-closure-ref',
2633
2666
for record in generator.get_record_stream():
2634
2667
self.assertEqual(kinds[record.key], record.storage_kind)