874
878
chkmap._dump_tree())
875
879
# Save everything to the map, and start over
876
880
chkmap = CHKMap(store, chkmap._save())
877
chkmap.map(('aac',), 'v')
878
chkmap.map(('aad',), 'v')
879
chkmap.map(('aae',), 'v')
880
chkmap.map(('aaf',), 'v')
881
chkmap.map((b'aac',), b'v')
882
chkmap.map((b'aad',), b'v')
883
chkmap.map((b'aae',), b'v')
884
chkmap.map((b'aaf',), b'v')
881
885
# At this point, the previous nodes should not be paged in, but the
882
886
# newly added nodes would be
883
self.assertIsInstance(chkmap._root_node._items['aaa'], StaticTuple)
884
self.assertIsInstance(chkmap._root_node._items['aab'], StaticTuple)
885
self.assertIsInstance(chkmap._root_node._items['aac'], LeafNode)
886
self.assertIsInstance(chkmap._root_node._items['aad'], LeafNode)
887
self.assertIsInstance(chkmap._root_node._items['aae'], LeafNode)
888
self.assertIsInstance(chkmap._root_node._items['aaf'], LeafNode)
887
self.assertIsInstance(chkmap._root_node._items[b'aaa'], StaticTuple)
888
self.assertIsInstance(chkmap._root_node._items[b'aab'], StaticTuple)
889
self.assertIsInstance(chkmap._root_node._items[b'aac'], LeafNode)
890
self.assertIsInstance(chkmap._root_node._items[b'aad'], LeafNode)
891
self.assertIsInstance(chkmap._root_node._items[b'aae'], LeafNode)
892
self.assertIsInstance(chkmap._root_node._items[b'aaf'], LeafNode)
889
893
# Now unmapping one of the new nodes will use only the already-paged-in
890
894
# nodes to determine that we don't need to do more.
891
chkmap.unmap(('aaf',))
892
self.assertIsInstance(chkmap._root_node._items['aaa'], StaticTuple)
893
self.assertIsInstance(chkmap._root_node._items['aab'], StaticTuple)
894
self.assertIsInstance(chkmap._root_node._items['aac'], LeafNode)
895
self.assertIsInstance(chkmap._root_node._items['aad'], LeafNode)
896
self.assertIsInstance(chkmap._root_node._items['aae'], LeafNode)
895
chkmap.unmap((b'aaf',))
896
self.assertIsInstance(chkmap._root_node._items[b'aaa'], StaticTuple)
897
self.assertIsInstance(chkmap._root_node._items[b'aab'], StaticTuple)
898
self.assertIsInstance(chkmap._root_node._items[b'aac'], LeafNode)
899
self.assertIsInstance(chkmap._root_node._items[b'aad'], LeafNode)
900
self.assertIsInstance(chkmap._root_node._items[b'aae'], LeafNode)
898
902
def test_unmap_pages_in_if_necessary(self):
899
903
store = self.get_chk_bytes()
900
904
chkmap = CHKMap(store, None)
901
905
# Should fit 2 keys per LeafNode
902
906
chkmap._root_node.set_maximum_size(30)
903
chkmap.map(('aaa',), 'val')
904
chkmap.map(('aab',), 'val')
905
chkmap.map(('aac',), 'val')
907
chkmap.map((b'aaa',), b'val')
908
chkmap.map((b'aab',), b'val')
909
chkmap.map((b'aac',), b'val')
906
910
self.assertEqualDiff("'' InternalNode\n"
907
911
" 'aaa' LeafNode\n"
908
912
" ('aaa',) 'val'\n"
914
918
root_key = chkmap._save()
915
919
# Save everything to the map, and start over
916
920
chkmap = CHKMap(store, root_key)
917
chkmap.map(('aad',), 'v')
921
chkmap.map((b'aad',), b'v')
918
922
# At this point, the previous nodes should not be paged in, but the
919
923
# newly added node would be
920
self.assertIsInstance(chkmap._root_node._items['aaa'], StaticTuple)
921
self.assertIsInstance(chkmap._root_node._items['aab'], StaticTuple)
922
self.assertIsInstance(chkmap._root_node._items['aac'], StaticTuple)
923
self.assertIsInstance(chkmap._root_node._items['aad'], LeafNode)
924
self.assertIsInstance(chkmap._root_node._items[b'aaa'], StaticTuple)
925
self.assertIsInstance(chkmap._root_node._items[b'aab'], StaticTuple)
926
self.assertIsInstance(chkmap._root_node._items[b'aac'], StaticTuple)
927
self.assertIsInstance(chkmap._root_node._items[b'aad'], LeafNode)
924
928
# Unmapping the new node will check the existing nodes to see if they
926
930
# Clear the page cache so we ensure we have to read all the children
927
931
chk_map.clear_cache()
928
chkmap.unmap(('aad',))
929
self.assertIsInstance(chkmap._root_node._items['aaa'], LeafNode)
930
self.assertIsInstance(chkmap._root_node._items['aab'], LeafNode)
931
self.assertIsInstance(chkmap._root_node._items['aac'], LeafNode)
932
chkmap.unmap((b'aad',))
933
self.assertIsInstance(chkmap._root_node._items[b'aaa'], LeafNode)
934
self.assertIsInstance(chkmap._root_node._items[b'aab'], LeafNode)
935
self.assertIsInstance(chkmap._root_node._items[b'aac'], LeafNode)
933
937
def test_unmap_pages_in_from_page_cache(self):
934
938
store = self.get_chk_bytes()
935
939
chkmap = CHKMap(store, None)
936
940
# Should fit 2 keys per LeafNode
937
941
chkmap._root_node.set_maximum_size(30)
938
chkmap.map(('aaa',), 'val')
939
chkmap.map(('aab',), 'val')
940
chkmap.map(('aac',), 'val')
942
chkmap.map((b'aaa',), b'val')
943
chkmap.map((b'aab',), b'val')
944
chkmap.map((b'aac',), b'val')
941
945
root_key = chkmap._save()
942
946
# Save everything to the map, and start over
943
947
chkmap = CHKMap(store, root_key)
944
chkmap.map(('aad',), 'val')
948
chkmap.map((b'aad',), b'val')
945
949
self.assertEqualDiff("'' InternalNode\n"
946
950
" 'aaa' LeafNode\n"
947
951
" ('aaa',) 'val'\n"
974
978
# Unmapping the new node will check the nodes from the page cache
975
979
# first, and not have to read in 'aaa'
976
chkmap.unmap(('aad',))
977
self.assertIsInstance(chkmap._root_node._items['aaa'], StaticTuple)
978
self.assertIsInstance(chkmap._root_node._items['aab'], LeafNode)
979
self.assertIsInstance(chkmap._root_node._items['aac'], LeafNode)
980
chkmap.unmap((b'aad',))
981
self.assertIsInstance(chkmap._root_node._items[b'aaa'], StaticTuple)
982
self.assertIsInstance(chkmap._root_node._items[b'aab'], LeafNode)
983
self.assertIsInstance(chkmap._root_node._items[b'aac'], LeafNode)
981
985
def test_unmap_uses_existing_items(self):
982
986
store = self.get_chk_bytes()
983
987
chkmap = CHKMap(store, None)
984
988
# Should fit 2 keys per LeafNode
985
989
chkmap._root_node.set_maximum_size(30)
986
chkmap.map(('aaa',), 'val')
987
chkmap.map(('aab',), 'val')
988
chkmap.map(('aac',), 'val')
990
chkmap.map((b'aaa',), b'val')
991
chkmap.map((b'aab',), b'val')
992
chkmap.map((b'aac',), b'val')
989
993
root_key = chkmap._save()
990
994
# Save everything to the map, and start over
991
995
chkmap = CHKMap(store, root_key)
992
chkmap.map(('aad',), 'val')
993
chkmap.map(('aae',), 'val')
994
chkmap.map(('aaf',), 'val')
996
chkmap.map((b'aad',), b'val')
997
chkmap.map((b'aae',), b'val')
998
chkmap.map((b'aaf',), b'val')
995
999
# At this point, the previous nodes should not be paged in, but the
996
1000
# newly added node would be
997
self.assertIsInstance(chkmap._root_node._items['aaa'], StaticTuple)
998
self.assertIsInstance(chkmap._root_node._items['aab'], StaticTuple)
999
self.assertIsInstance(chkmap._root_node._items['aac'], StaticTuple)
1000
self.assertIsInstance(chkmap._root_node._items['aad'], LeafNode)
1001
self.assertIsInstance(chkmap._root_node._items['aae'], LeafNode)
1002
self.assertIsInstance(chkmap._root_node._items['aaf'], LeafNode)
1001
self.assertIsInstance(chkmap._root_node._items[b'aaa'], StaticTuple)
1002
self.assertIsInstance(chkmap._root_node._items[b'aab'], StaticTuple)
1003
self.assertIsInstance(chkmap._root_node._items[b'aac'], StaticTuple)
1004
self.assertIsInstance(chkmap._root_node._items[b'aad'], LeafNode)
1005
self.assertIsInstance(chkmap._root_node._items[b'aae'], LeafNode)
1006
self.assertIsInstance(chkmap._root_node._items[b'aaf'], LeafNode)
1004
1008
# Unmapping a new node will see the other nodes that are already in
1005
1009
# memory, and not need to page in anything else
1006
chkmap.unmap(('aad',))
1007
self.assertIsInstance(chkmap._root_node._items['aaa'], StaticTuple)
1008
self.assertIsInstance(chkmap._root_node._items['aab'], StaticTuple)
1009
self.assertIsInstance(chkmap._root_node._items['aac'], StaticTuple)
1010
self.assertIsInstance(chkmap._root_node._items['aae'], LeafNode)
1011
self.assertIsInstance(chkmap._root_node._items['aaf'], LeafNode)
1010
chkmap.unmap((b'aad',))
1011
self.assertIsInstance(chkmap._root_node._items[b'aaa'], StaticTuple)
1012
self.assertIsInstance(chkmap._root_node._items[b'aab'], StaticTuple)
1013
self.assertIsInstance(chkmap._root_node._items[b'aac'], StaticTuple)
1014
self.assertIsInstance(chkmap._root_node._items[b'aae'], LeafNode)
1015
self.assertIsInstance(chkmap._root_node._items[b'aaf'], LeafNode)
1013
1017
def test_iter_changes_empty_ab(self):
1014
1018
# Asking for changes between an empty dict to a dict with keys returns
1015
1019
# all the keys.
1016
1020
basis = self._get_map({}, maximum_size=10)
1017
1021
target = self._get_map(
1018
{('a',): 'content here', ('b',): 'more content'},
1022
{(b'a',): b'content here', (b'b',): b'more content'},
1019
1023
chk_bytes=basis._store, maximum_size=10)
1020
self.assertEqual([(('a',), None, 'content here'),
1021
(('b',), None, 'more content')],
1022
sorted(list(target.iter_changes(basis))))
1024
self.assertEqual([((b'a',), None, b'content here'),
1025
((b'b',), None, b'more content')],
1026
sorted(list(target.iter_changes(basis))))
1024
1028
def test_iter_changes_ab_empty(self):
1025
1029
# Asking for changes between a dict with keys to an empty dict returns
1026
1030
# all the keys.
1027
basis = self._get_map({('a',): 'content here', ('b',): 'more content'},
1031
basis = self._get_map({(b'a',): b'content here', (b'b',): b'more content'},
1029
1033
target = self._get_map({}, chk_bytes=basis._store, maximum_size=10)
1030
self.assertEqual([(('a',), 'content here', None),
1031
(('b',), 'more content', None)],
1032
sorted(list(target.iter_changes(basis))))
1034
self.assertEqual([((b'a',), b'content here', None),
1035
((b'b',), b'more content', None)],
1036
sorted(list(target.iter_changes(basis))))
1034
1038
def test_iter_changes_empty_empty_is_empty(self):
1035
1039
basis = self._get_map({}, maximum_size=10)
1100
1104
# aaa to be not loaded
1101
1105
# aaa not to be in result.
1102
basis_dict = {('aaa',): 'foo bar',
1103
('aab',): 'common altered a', ('b',): 'foo bar b'}
1106
basis_dict = {(b'aaa',): b'foo bar',
1107
(b'aab',): b'common altered a', (b'b',): b'foo bar b'}
1104
1108
# target splits at byte 1, at is target only
1105
target_dict = {('aaa',): 'foo bar',
1106
('aab',): 'common altered b', ('at',): 'foo bar t'}
1109
target_dict = {(b'aaa',): b'foo bar',
1110
(b'aab',): b'common altered b', (b'at',): b'foo bar t'}
1107
1111
basis = self._get_map(basis_dict, maximum_size=10)
1108
1112
target = self._get_map(target_dict, maximum_size=10,
1109
chk_bytes=basis._store)
1113
chk_bytes=basis._store)
1110
1114
basis_get = basis._store.get_record_stream
1111
1116
def get_record_stream(keys, order, fulltext):
1112
if ('sha1:1adf7c0d1b9140ab5f33bb64c6275fa78b1580b7',) in keys:
1117
if (b'sha1:1adf7c0d1b9140ab5f33bb64c6275fa78b1580b7',) in keys:
1113
1118
raise AssertionError("'aaa' pointer was followed %r" % keys)
1114
1119
return basis_get(keys, order, fulltext)
1115
1120
basis._store.get_record_stream = get_record_stream
1116
1121
result = sorted(list(target.iter_changes(basis)))
1117
1122
for change in result:
1118
if change[0] == ('aaa',):
1123
if change[0] == (b'aaa',):
1119
1124
self.fail("Found unexpected change: %s" % change)
1121
1126
def test_iter_changes_unchanged_keys_in_multi_key_leafs_ignored(self):
1122
1127
# Within a leaf there are no hash's to exclude keys, make sure multi
1123
1128
# value leaf nodes are handled well.
1124
basis_dict = {('aaa',): 'foo bar',
1125
('aab',): 'common altered a', ('b',): 'foo bar b'}
1126
target_dict = {('aaa',): 'foo bar',
1127
('aab',): 'common altered b', ('at',): 'foo bar t'}
1129
basis_dict = {(b'aaa',): b'foo bar',
1130
(b'aab',): b'common altered a', (b'b',): b'foo bar b'}
1131
target_dict = {(b'aaa',): b'foo bar',
1132
(b'aab',): b'common altered b', (b'at',): b'foo bar t'}
1129
(('aab',), 'common altered a', 'common altered b'),
1130
(('at',), None, 'foo bar t'),
1131
(('b',), 'foo bar b', None),
1134
((b'aab',), b'common altered a', b'common altered b'),
1135
((b'at',), None, b'foo bar t'),
1136
((b'b',), b'foo bar b', None),
1133
1138
basis = self._get_map(basis_dict)
1134
1139
target = self._get_map(target_dict, chk_bytes=basis._store)
1143
1148
def test_iteritems_two_items(self):
1144
1149
chk_bytes = self.get_chk_bytes()
1145
1150
root_key = CHKMap.from_dict(chk_bytes,
1146
{"a":"content here", "b":"more content"})
1151
{(b"a", ): b"content here", (b"b", ): b"more content"})
1147
1152
chkmap = CHKMap(chk_bytes, root_key)
1148
self.assertEqual([(("a",), "content here"), (("b",), "more content")],
1149
sorted(list(chkmap.iteritems())))
1153
self.assertEqual([((b"a",), b"content here"), ((b"b",), b"more content")],
1154
sorted(list(chkmap.iteritems())))
1151
1156
def test_iteritems_selected_one_of_two_items(self):
1152
chkmap = self._get_map( {("a",):"content here", ("b",):"more content"})
1153
self.assertEqual({("a",): "content here"},
1154
self.to_dict(chkmap, [("a",)]))
1157
chkmap = self._get_map(
1158
{(b"a",): b"content here", (b"b",): b"more content"})
1159
self.assertEqual({(b"a",): b"content here"},
1160
self.to_dict(chkmap, [(b"a",)]))
1156
1162
def test_iteritems_keys_prefixed_by_2_width_nodes(self):
1157
1163
chkmap = self._get_map(
1158
{("a", "a"):"content here", ("a", "b",):"more content",
1159
("b", ""): 'boring content'},
1164
{(b"a", b"a"): b"content here", (b"a", b"b",): b"more content",
1165
(b"b", b""): b'boring content'},
1160
1166
maximum_size=10, key_width=2)
1161
1167
self.assertEqual(
1162
{("a", "a"): "content here", ("a", "b"): 'more content'},
1163
self.to_dict(chkmap, [("a",)]))
1168
{(b"a", b"a"): b"content here", (b"a", b"b"): b'more content'},
1169
self.to_dict(chkmap, [(b"a",)]))
1165
1171
def test_iteritems_keys_prefixed_by_2_width_nodes_hashed(self):
1166
search_key_func = chk_map.search_key_registry.get('hash-16-way')
1167
self.assertEqual('E8B7BE43\x00E8B7BE43',
1168
search_key_func(StaticTuple('a', 'a')))
1169
self.assertEqual('E8B7BE43\x0071BEEFF9',
1170
search_key_func(StaticTuple('a', 'b')))
1171
self.assertEqual('71BEEFF9\x0000000000',
1172
search_key_func(StaticTuple('b', '')))
1172
search_key_func = chk_map.search_key_registry.get(b'hash-16-way')
1173
self.assertEqual(b'E8B7BE43\x00E8B7BE43',
1174
search_key_func(StaticTuple(b'a', b'a')))
1175
self.assertEqual(b'E8B7BE43\x0071BEEFF9',
1176
search_key_func(StaticTuple(b'a', b'b')))
1177
self.assertEqual(b'71BEEFF9\x0000000000',
1178
search_key_func(StaticTuple(b'b', b'')))
1173
1179
chkmap = self._get_map(
1174
{("a", "a"):"content here", ("a", "b",):"more content",
1175
("b", ""): 'boring content'},
1180
{(b"a", b"a"): b"content here", (b"a", b"b",): b"more content",
1181
(b"b", b""): b'boring content'},
1176
1182
maximum_size=10, key_width=2, search_key_func=search_key_func)
1177
1183
self.assertEqual(
1178
{("a", "a"): "content here", ("a", "b"): 'more content'},
1179
self.to_dict(chkmap, [("a",)]))
1184
{(b"a", b"a"): b"content here", (b"a", b"b"): b'more content'},
1185
self.to_dict(chkmap, [(b"a",)]))
1181
1187
def test_iteritems_keys_prefixed_by_2_width_one_leaf(self):
1182
1188
chkmap = self._get_map(
1183
{("a", "a"):"content here", ("a", "b",):"more content",
1184
("b", ""): 'boring content'}, key_width=2)
1189
{(b"a", b"a"): b"content here", (b"a", b"b",): b"more content",
1190
(b"b", b""): b'boring content'}, key_width=2)
1185
1191
self.assertEqual(
1186
{("a", "a"): "content here", ("a", "b"): 'more content'},
1187
self.to_dict(chkmap, [("a",)]))
1192
{(b"a", b"a"): b"content here", (b"a", b"b"): b'more content'},
1193
self.to_dict(chkmap, [(b"a",)]))
1189
1195
def test___len__empty(self):
1190
1196
chkmap = self._get_map({})
1191
1197
self.assertEqual(0, len(chkmap))
1193
1199
def test___len__2(self):
1194
chkmap = self._get_map({("foo",):"bar", ("gam",):"quux"})
1200
chkmap = self._get_map({(b"foo",): b"bar", (b"gam",): b"quux"})
1195
1201
self.assertEqual(2, len(chkmap))
1197
1203
def test_max_size_100_bytes_new(self):
1198
1204
# When there is a 100 byte upper node limit, a tree is formed.
1199
chkmap = self._get_map({("k1"*50,):"v1", ("k2"*50,):"v2"}, maximum_size=100)
1205
chkmap = self._get_map(
1206
{(b"k1" * 50,): b"v1", (b"k2" * 50,): b"v2"}, maximum_size=100)
1200
1207
# We expect three nodes:
1201
1208
# A root, with two children, and with two key prefixes - k1 to one, and
1202
1209
# k2 to the other as our node splitting is only just being developed.
1391
1402
" 'test:2' LeafNode\n"
1392
1403
" ('2',) 'bar'\n"
1393
1404
" 'test:3' LeafNode\n"
1395
, chkmap._dump_tree())
1405
" ('3',) 'baz'\n", chkmap._dump_tree())
1397
1407
def test_search_key_16(self):
1398
1408
chk_bytes = self.get_chk_bytes()
1399
1409
chkmap = chk_map.CHKMap(chk_bytes, None,
1400
1410
search_key_func=chk_map._search_key_16)
1401
1411
chkmap._root_node.set_maximum_size(10)
1402
chkmap.map(('1',), 'foo')
1403
chkmap.map(('2',), 'bar')
1404
chkmap.map(('3',), 'baz')
1412
chkmap.map((b'1',), b'foo')
1413
chkmap.map((b'2',), b'bar')
1414
chkmap.map((b'3',), b'baz')
1405
1415
self.assertEqualDiff("'' InternalNode\n"
1406
1416
" '1' LeafNode\n"
1407
1417
" ('2',) 'bar'\n"
1408
1418
" '6' LeafNode\n"
1409
1419
" ('3',) 'baz'\n"
1410
1420
" '8' LeafNode\n"
1412
, chkmap._dump_tree())
1421
" ('1',) 'foo'\n", chkmap._dump_tree())
1413
1422
root_key = chkmap._save()
1414
1423
chkmap = chk_map.CHKMap(chk_bytes, root_key,
1415
1424
search_key_func=chk_map._search_key_16)
1416
1425
# We can get the values back correctly
1417
self.assertEqual([(('1',), 'foo')],
1418
list(chkmap.iteritems([('1',)])))
1426
self.assertEqual([((b'1',), b'foo')],
1427
list(chkmap.iteritems([(b'1',)])))
1419
1428
self.assertEqualDiff("'' InternalNode\n"
1420
1429
" '1' LeafNode\n"
1421
1430
" ('2',) 'bar'\n"
1422
1431
" '6' LeafNode\n"
1423
1432
" ('3',) 'baz'\n"
1424
1433
" '8' LeafNode\n"
1426
, chkmap._dump_tree())
1434
" ('1',) 'foo'\n", chkmap._dump_tree())
1428
1436
def test_search_key_255(self):
1429
1437
chk_bytes = self.get_chk_bytes()
1430
1438
chkmap = chk_map.CHKMap(chk_bytes, None,
1431
1439
search_key_func=chk_map._search_key_255)
1432
1440
chkmap._root_node.set_maximum_size(10)
1433
chkmap.map(('1',), 'foo')
1434
chkmap.map(('2',), 'bar')
1435
chkmap.map(('3',), 'baz')
1441
chkmap.map((b'1',), b'foo')
1442
chkmap.map((b'2',), b'bar')
1443
chkmap.map((b'3',), b'baz')
1436
1444
self.assertEqualDiff("'' InternalNode\n"
1437
1445
" '\\x1a' LeafNode\n"
1438
1446
" ('2',) 'bar'\n"
1439
1447
" 'm' LeafNode\n"
1440
1448
" ('3',) 'baz'\n"
1441
1449
" '\\x83' LeafNode\n"
1443
, chkmap._dump_tree())
1450
" ('1',) 'foo'\n", chkmap._dump_tree(encoding='latin1'))
1444
1451
root_key = chkmap._save()
1445
1452
chkmap = chk_map.CHKMap(chk_bytes, root_key,
1446
1453
search_key_func=chk_map._search_key_255)
1447
1454
# We can get the values back correctly
1448
self.assertEqual([(('1',), 'foo')],
1449
list(chkmap.iteritems([('1',)])))
1455
self.assertEqual([((b'1',), b'foo')],
1456
list(chkmap.iteritems([(b'1',)])))
1450
1457
self.assertEqualDiff("'' InternalNode\n"
1451
1458
" '\\x1a' LeafNode\n"
1452
1459
" ('2',) 'bar'\n"
1453
1460
" 'm' LeafNode\n"
1454
1461
" ('3',) 'baz'\n"
1455
1462
" '\\x83' LeafNode\n"
1457
, chkmap._dump_tree())
1463
" ('1',) 'foo'\n", chkmap._dump_tree(encoding='latin1'))
1459
1465
def test_search_key_collisions(self):
1460
1466
chkmap = chk_map.CHKMap(self.get_chk_bytes(), None,
1491
1496
def test_current_size_items(self):
1492
1497
node = LeafNode()
1493
1498
base_size = node._current_size()
1494
node.map(None, ("foo bar",), "baz")
1499
node.map(None, (b"foo bar",), b"baz")
1495
1500
self.assertEqual(base_size + 14, node._current_size())
1497
1502
def test_deserialise_empty(self):
1498
node = LeafNode.deserialise("chkleaf:\n10\n1\n0\n\n", ("sha1:1234",))
1503
node = LeafNode.deserialise(b"chkleaf:\n10\n1\n0\n\n", (b"sha1:1234",))
1499
1504
self.assertEqual(0, len(node))
1500
1505
self.assertEqual(10, node.maximum_size)
1501
self.assertEqual(("sha1:1234",), node.key())
1506
self.assertEqual((b"sha1:1234",), node.key())
1502
1507
self.assertIs(None, node._search_prefix)
1503
1508
self.assertIs(None, node._common_serialised_prefix)
1505
1510
def test_deserialise_items(self):
1506
1511
node = LeafNode.deserialise(
1507
"chkleaf:\n0\n1\n2\n\nfoo bar\x001\nbaz\nquux\x001\nblarh\n",
1512
b"chkleaf:\n0\n1\n2\n\nfoo bar\x001\nbaz\nquux\x001\nblarh\n",
1509
1514
self.assertEqual(2, len(node))
1510
self.assertEqual([(("foo bar",), "baz"), (("quux",), "blarh")],
1511
sorted(node.iteritems(None)))
1515
self.assertEqual([((b"foo bar",), b"baz"), ((b"quux",), b"blarh")],
1516
sorted(node.iteritems(None)))
1513
1518
def test_deserialise_item_with_null_width_1(self):
1514
1519
node = LeafNode.deserialise(
1515
"chkleaf:\n0\n1\n2\n\nfoo\x001\nbar\x00baz\nquux\x001\nblarh\n",
1520
b"chkleaf:\n0\n1\n2\n\nfoo\x001\nbar\x00baz\nquux\x001\nblarh\n",
1517
1522
self.assertEqual(2, len(node))
1518
self.assertEqual([(("foo",), "bar\x00baz"), (("quux",), "blarh")],
1519
sorted(node.iteritems(None)))
1523
self.assertEqual([((b"foo",), b"bar\x00baz"), ((b"quux",), b"blarh")],
1524
sorted(node.iteritems(None)))
1521
1526
def test_deserialise_item_with_null_width_2(self):
1522
1527
node = LeafNode.deserialise(
1523
"chkleaf:\n0\n2\n2\n\nfoo\x001\x001\nbar\x00baz\n"
1524
"quux\x00\x001\nblarh\n",
1528
b"chkleaf:\n0\n2\n2\n\nfoo\x001\x001\nbar\x00baz\n"
1529
b"quux\x00\x001\nblarh\n",
1526
1531
self.assertEqual(2, len(node))
1527
self.assertEqual([(("foo", "1"), "bar\x00baz"), (("quux", ""), "blarh")],
1528
sorted(node.iteritems(None)))
1532
self.assertEqual([((b"foo", b"1"), b"bar\x00baz"), ((b"quux", b""), b"blarh")],
1533
sorted(node.iteritems(None)))
1530
1535
def test_iteritems_selected_one_of_two_items(self):
1531
1536
node = LeafNode.deserialise(
1532
"chkleaf:\n0\n1\n2\n\nfoo bar\x001\nbaz\nquux\x001\nblarh\n",
1537
b"chkleaf:\n0\n1\n2\n\nfoo bar\x001\nbaz\nquux\x001\nblarh\n",
1534
1539
self.assertEqual(2, len(node))
1535
self.assertEqual([(("quux",), "blarh")],
1536
sorted(node.iteritems(None, [("quux",), ("qaz",)])))
1540
self.assertEqual([((b"quux",), b"blarh")],
1541
sorted(node.iteritems(None, [(b"quux",), (b"qaz",)])))
1538
1543
def test_deserialise_item_with_common_prefix(self):
1539
1544
node = LeafNode.deserialise(
1540
"chkleaf:\n0\n2\n2\nfoo\x00\n1\x001\nbar\x00baz\n2\x001\nblarh\n",
1545
b"chkleaf:\n0\n2\n2\nfoo\x00\n1\x001\nbar\x00baz\n2\x001\nblarh\n",
1542
1547
self.assertEqual(2, len(node))
1543
self.assertEqual([(("foo", "1"), "bar\x00baz"), (("foo", "2"), "blarh")],
1544
sorted(node.iteritems(None)))
1548
self.assertEqual([((b"foo", b"1"), b"bar\x00baz"), ((b"foo", b"2"), b"blarh")],
1549
sorted(node.iteritems(None)))
1545
1550
self.assertIs(chk_map._unknown, node._search_prefix)
1546
self.assertEqual('foo\x00', node._common_serialised_prefix)
1551
self.assertEqual(b'foo\x00', node._common_serialised_prefix)
1548
1553
def test_deserialise_multi_line(self):
1549
1554
node = LeafNode.deserialise(
1550
"chkleaf:\n0\n2\n2\nfoo\x00\n1\x002\nbar\nbaz\n2\x002\nblarh\n\n",
1555
b"chkleaf:\n0\n2\n2\nfoo\x00\n1\x002\nbar\nbaz\n2\x002\nblarh\n\n",
1552
1557
self.assertEqual(2, len(node))
1553
self.assertEqual([(("foo", "1"), "bar\nbaz"),
1554
(("foo", "2"), "blarh\n"),
1555
], sorted(node.iteritems(None)))
1558
self.assertEqual([((b"foo", b"1"), b"bar\nbaz"),
1559
((b"foo", b"2"), b"blarh\n"),
1560
], sorted(node.iteritems(None)))
1556
1561
self.assertIs(chk_map._unknown, node._search_prefix)
1557
self.assertEqual('foo\x00', node._common_serialised_prefix)
1562
self.assertEqual(b'foo\x00', node._common_serialised_prefix)
1559
1564
def test_key_new(self):
1560
1565
node = LeafNode()
1561
1566
self.assertEqual(None, node.key())
1563
1568
def test_key_after_map(self):
1564
node = LeafNode.deserialise("chkleaf:\n10\n1\n0\n\n", ("sha1:1234",))
1565
node.map(None, ("foo bar",), "baz quux")
1569
node = LeafNode.deserialise(b"chkleaf:\n10\n1\n0\n\n", (b"sha1:1234",))
1570
node.map(None, (b"foo bar",), b"baz quux")
1566
1571
self.assertEqual(None, node.key())
1568
1573
def test_key_after_unmap(self):
1569
1574
node = LeafNode.deserialise(
1570
"chkleaf:\n0\n1\n2\n\nfoo bar\x001\nbaz\nquux\x001\nblarh\n",
1572
node.unmap(None, ("foo bar",))
1575
b"chkleaf:\n0\n1\n2\n\nfoo bar\x001\nbaz\nquux\x001\nblarh\n",
1577
node.unmap(None, (b"foo bar",))
1573
1578
self.assertEqual(None, node.key())
1575
1580
def test_map_exceeding_max_size_only_entry_new(self):
1576
1581
node = LeafNode()
1577
1582
node.set_maximum_size(10)
1578
result = node.map(None, ("foo bar",), "baz quux")
1579
self.assertEqual(("foo bar", [("", node)]), result)
1583
result = node.map(None, (b"foo bar",), b"baz quux")
1584
self.assertEqual((b"foo bar", [(b"", node)]), result)
1580
1585
self.assertTrue(10 < node._current_size())
1582
1587
def test_map_exceeding_max_size_second_entry_early_difference_new(self):
1583
1588
node = LeafNode()
1584
1589
node.set_maximum_size(10)
1585
node.map(None, ("foo bar",), "baz quux")
1586
prefix, result = list(node.map(None, ("blue",), "red"))
1587
self.assertEqual("", prefix)
1590
node.map(None, (b"foo bar",), b"baz quux")
1591
prefix, result = list(node.map(None, (b"blue",), b"red"))
1592
self.assertEqual(b"", prefix)
1588
1593
self.assertEqual(2, len(result))
1589
1594
split_chars = {result[0][0], result[1][0]}
1590
self.assertEqual({"f", "b"}, split_chars)
1595
self.assertEqual({b"f", b"b"}, split_chars)
1591
1596
nodes = dict(result)
1593
self.assertEqual({("foo bar",): "baz quux"}, self.to_dict(node, None))
1598
self.assertEqual({(b"foo bar",): b"baz quux"},
1599
self.to_dict(node, None))
1594
1600
self.assertEqual(10, node.maximum_size)
1595
1601
self.assertEqual(1, node._key_width)
1597
self.assertEqual({("blue",): "red"}, self.to_dict(node, None))
1603
self.assertEqual({(b"blue",): b"red"}, self.to_dict(node, None))
1598
1604
self.assertEqual(10, node.maximum_size)
1599
1605
self.assertEqual(1, node._key_width)
1601
1607
def test_map_first(self):
1602
1608
node = LeafNode()
1603
result = node.map(None, ("foo bar",), "baz quux")
1604
self.assertEqual(("foo bar", [("", node)]), result)
1605
self.assertEqual({("foo bar",):"baz quux"}, self.to_dict(node, None))
1609
result = node.map(None, (b"foo bar",), b"baz quux")
1610
self.assertEqual((b"foo bar", [(b"", node)]), result)
1611
self.assertEqual({(b"foo bar",): b"baz quux"},
1612
self.to_dict(node, None))
1606
1613
self.assertEqual(1, len(node))
1608
1615
def test_map_second(self):
1609
1616
node = LeafNode()
1610
node.map(None, ("foo bar",), "baz quux")
1611
result = node.map(None, ("bingo",), "bango")
1612
self.assertEqual(("", [("", node)]), result)
1613
self.assertEqual({("foo bar",):"baz quux", ("bingo",):"bango"},
1614
self.to_dict(node, None))
1617
node.map(None, (b"foo bar",), b"baz quux")
1618
result = node.map(None, (b"bingo",), b"bango")
1619
self.assertEqual((b"", [(b"", node)]), result)
1620
self.assertEqual({(b"foo bar",): b"baz quux", (b"bingo",): b"bango"},
1621
self.to_dict(node, None))
1615
1622
self.assertEqual(2, len(node))
1617
1624
def test_map_replacement(self):
1618
1625
node = LeafNode()
1619
node.map(None, ("foo bar",), "baz quux")
1620
result = node.map(None, ("foo bar",), "bango")
1621
self.assertEqual(("foo bar", [("", node)]), result)
1622
self.assertEqual({("foo bar",): "bango"},
1623
self.to_dict(node, None))
1626
node.map(None, (b"foo bar",), b"baz quux")
1627
result = node.map(None, (b"foo bar",), b"bango")
1628
self.assertEqual((b"foo bar", [(b"", node)]), result)
1629
self.assertEqual({(b"foo bar",): b"bango"},
1630
self.to_dict(node, None))
1624
1631
self.assertEqual(1, len(node))
1626
1633
def test_serialise_empty(self):
1627
1634
store = self.get_chk_bytes()
1628
1635
node = LeafNode()
1629
1636
node.set_maximum_size(10)
1630
expected_key = ("sha1:f34c3f0634ea3f85953dffa887620c0a5b1f4a51",)
1637
expected_key = (b"sha1:f34c3f0634ea3f85953dffa887620c0a5b1f4a51",)
1631
1638
self.assertEqual([expected_key],
1632
list(node.serialise(store)))
1633
self.assertEqual("chkleaf:\n10\n1\n0\n\n", self.read_bytes(store, expected_key))
1639
list(node.serialise(store)))
1640
self.assertEqual(b"chkleaf:\n10\n1\n0\n\n",
1641
self.read_bytes(store, expected_key))
1634
1642
self.assertEqual(expected_key, node.key())
1636
1644
def test_serialise_items(self):
1637
1645
store = self.get_chk_bytes()
1638
1646
node = LeafNode()
1639
1647
node.set_maximum_size(10)
1640
node.map(None, ("foo bar",), "baz quux")
1641
expected_key = ("sha1:f89fac7edfc6bdb1b1b54a556012ff0c646ef5e0",)
1642
self.assertEqual('foo bar', node._common_serialised_prefix)
1648
node.map(None, (b"foo bar",), b"baz quux")
1649
expected_key = (b"sha1:f89fac7edfc6bdb1b1b54a556012ff0c646ef5e0",)
1650
self.assertEqual(b'foo bar', node._common_serialised_prefix)
1643
1651
self.assertEqual([expected_key],
1644
list(node.serialise(store)))
1645
self.assertEqual("chkleaf:\n10\n1\n1\nfoo bar\n\x001\nbaz quux\n",
1646
self.read_bytes(store, expected_key))
1652
list(node.serialise(store)))
1653
self.assertEqual(b"chkleaf:\n10\n1\n1\nfoo bar\n\x001\nbaz quux\n",
1654
self.read_bytes(store, expected_key))
1647
1655
self.assertEqual(expected_key, node.key())
1649
1657
def test_unique_serialised_prefix_empty_new(self):
1670
1678
def test_map_maintains_common_prefixes(self):
1671
1679
node = LeafNode()
1672
1680
node._key_width = 2
1673
node.map(None, ("foo bar", "baz"), "baz quux")
1674
self.assertEqual('foo bar\x00baz', node._search_prefix)
1675
self.assertEqual('foo bar\x00baz', node._common_serialised_prefix)
1676
node.map(None, ("foo bar", "bing"), "baz quux")
1677
self.assertEqual('foo bar\x00b', node._search_prefix)
1678
self.assertEqual('foo bar\x00b', node._common_serialised_prefix)
1679
node.map(None, ("fool", "baby"), "baz quux")
1680
self.assertEqual('foo', node._search_prefix)
1681
self.assertEqual('foo', node._common_serialised_prefix)
1682
node.map(None, ("foo bar", "baz"), "replaced")
1683
self.assertEqual('foo', node._search_prefix)
1684
self.assertEqual('foo', node._common_serialised_prefix)
1685
node.map(None, ("very", "different"), "value")
1686
self.assertEqual('', node._search_prefix)
1687
self.assertEqual('', node._common_serialised_prefix)
1681
node.map(None, (b"foo bar", b"baz"), b"baz quux")
1682
self.assertEqual(b'foo bar\x00baz', node._search_prefix)
1683
self.assertEqual(b'foo bar\x00baz', node._common_serialised_prefix)
1684
node.map(None, (b"foo bar", b"bing"), b"baz quux")
1685
self.assertEqual(b'foo bar\x00b', node._search_prefix)
1686
self.assertEqual(b'foo bar\x00b', node._common_serialised_prefix)
1687
node.map(None, (b"fool", b"baby"), b"baz quux")
1688
self.assertEqual(b'foo', node._search_prefix)
1689
self.assertEqual(b'foo', node._common_serialised_prefix)
1690
node.map(None, (b"foo bar", b"baz"), b"replaced")
1691
self.assertEqual(b'foo', node._search_prefix)
1692
self.assertEqual(b'foo', node._common_serialised_prefix)
1693
node.map(None, (b"very", b"different"), b"value")
1694
self.assertEqual(b'', node._search_prefix)
1695
self.assertEqual(b'', node._common_serialised_prefix)
1689
1697
def test_unmap_maintains_common_prefixes(self):
1690
1698
node = LeafNode()
1691
1699
node._key_width = 2
1692
node.map(None, ("foo bar", "baz"), "baz quux")
1693
node.map(None, ("foo bar", "bing"), "baz quux")
1694
node.map(None, ("fool", "baby"), "baz quux")
1695
node.map(None, ("very", "different"), "value")
1696
self.assertEqual('', node._search_prefix)
1697
self.assertEqual('', node._common_serialised_prefix)
1698
node.unmap(None, ("very", "different"))
1699
self.assertEqual("foo", node._search_prefix)
1700
self.assertEqual("foo", node._common_serialised_prefix)
1701
node.unmap(None, ("fool", "baby"))
1702
self.assertEqual('foo bar\x00b', node._search_prefix)
1703
self.assertEqual('foo bar\x00b', node._common_serialised_prefix)
1704
node.unmap(None, ("foo bar", "baz"))
1705
self.assertEqual('foo bar\x00bing', node._search_prefix)
1706
self.assertEqual('foo bar\x00bing', node._common_serialised_prefix)
1707
node.unmap(None, ("foo bar", "bing"))
1700
node.map(None, (b"foo bar", b"baz"), b"baz quux")
1701
node.map(None, (b"foo bar", b"bing"), b"baz quux")
1702
node.map(None, (b"fool", b"baby"), b"baz quux")
1703
node.map(None, (b"very", b"different"), b"value")
1704
self.assertEqual(b'', node._search_prefix)
1705
self.assertEqual(b'', node._common_serialised_prefix)
1706
node.unmap(None, (b"very", b"different"))
1707
self.assertEqual(b"foo", node._search_prefix)
1708
self.assertEqual(b"foo", node._common_serialised_prefix)
1709
node.unmap(None, (b"fool", b"baby"))
1710
self.assertEqual(b'foo bar\x00b', node._search_prefix)
1711
self.assertEqual(b'foo bar\x00b', node._common_serialised_prefix)
1712
node.unmap(None, (b"foo bar", b"baz"))
1713
self.assertEqual(b'foo bar\x00bing', node._search_prefix)
1714
self.assertEqual(b'foo bar\x00bing', node._common_serialised_prefix)
1715
node.unmap(None, (b"foo bar", b"bing"))
1708
1716
self.assertEqual(None, node._search_prefix)
1709
1717
self.assertEqual(None, node._common_serialised_prefix)
1813
1821
self.assertEqual(2, len(node_key_filter))
1815
1823
def make_fo_fa_node(self):
1816
node = InternalNode('f')
1818
child.set_maximum_size(100)
1819
child.map(None, ("foo",), "val")
1820
child.map(None, ("fob",), "val")
1821
node.add_node('fo', child)
1823
child.set_maximum_size(100)
1824
child.map(None, ("far",), "val")
1825
child.map(None, ("faz",), "val")
1826
node.add_node("fa", child)
1824
node = InternalNode(b'f')
1826
child.set_maximum_size(100)
1827
child.map(None, (b"foo",), b"val")
1828
child.map(None, (b"fob",), b"val")
1829
node.add_node(b'fo', child)
1831
child.set_maximum_size(100)
1832
child.map(None, (b"far",), b"val")
1833
child.map(None, (b"faz",), b"val")
1834
node.add_node(b"fa", child)
1829
1837
def test__iter_nodes_single_entry(self):
1830
1838
node = self.make_fo_fa_node()
1831
key_filter = [('foo',)]
1839
key_filter = [(b'foo',)]
1832
1840
nodes = list(node._iter_nodes(None, key_filter=key_filter))
1833
1841
self.assertEqual(1, len(nodes))
1834
1842
self.assertEqual(key_filter, nodes[0][1])
1836
1844
def test__iter_nodes_single_entry_misses(self):
1837
1845
node = self.make_fo_fa_node()
1838
key_filter = [('bar',)]
1846
key_filter = [(b'bar',)]
1839
1847
nodes = list(node._iter_nodes(None, key_filter=key_filter))
1840
1848
self.assertEqual(0, len(nodes))
1842
1850
def test__iter_nodes_mixed_key_width(self):
1843
1851
node = self.make_fo_fa_node()
1844
key_filter = [('foo', 'bar'), ('foo',), ('fo',), ('b',)]
1852
key_filter = [(b'foo', b'bar'), (b'foo',), (b'fo',), (b'b',)]
1845
1853
nodes = list(node._iter_nodes(None, key_filter=key_filter))
1846
1854
self.assertEqual(1, len(nodes))
1847
1855
matches = key_filter[:]
1848
matches.remove(('b',))
1856
matches.remove((b'b',))
1849
1857
self.assertEqual(sorted(matches), sorted(nodes[0][1]))
1851
1859
def test__iter_nodes_match_all(self):
1852
1860
node = self.make_fo_fa_node()
1853
key_filter = [('foo', 'bar'), ('foo',), ('fo',), ('f',)]
1861
key_filter = [(b'foo', b'bar'), (b'foo',), (b'fo',), (b'f',)]
1854
1862
nodes = list(node._iter_nodes(None, key_filter=key_filter))
1855
1863
self.assertEqual(2, len(nodes))
1857
1865
def test__iter_nodes_fixed_widths_and_misses(self):
1858
1866
node = self.make_fo_fa_node()
1859
1867
# foo and faa should both match one child, baz should miss
1860
key_filter = [('foo',), ('faa',), ('baz',)]
1868
key_filter = [(b'foo',), (b'faa',), (b'baz',)]
1861
1869
nodes = list(node._iter_nodes(None, key_filter=key_filter))
1862
1870
self.assertEqual(2, len(nodes))
1863
1871
for node, matches in nodes:
1870
1878
def test_iteritems_two_children(self):
1871
1879
node = InternalNode()
1872
1880
leaf1 = LeafNode()
1873
leaf1.map(None, ('foo bar',), 'quux')
1881
leaf1.map(None, (b'foo bar',), b'quux')
1874
1882
leaf2 = LeafNode()
1875
leaf2.map(None, ('strange',), 'beast')
1876
node.add_node("f", leaf1)
1877
node.add_node("s", leaf2)
1878
self.assertEqual([(('foo bar',), 'quux'), (('strange',), 'beast')],
1879
sorted(node.iteritems(None)))
1883
leaf2.map(None, (b'strange',), b'beast')
1884
node.add_node(b"f", leaf1)
1885
node.add_node(b"s", leaf2)
1886
self.assertEqual([((b'foo bar',), b'quux'), ((b'strange',), b'beast')],
1887
sorted(node.iteritems(None)))
1881
1889
def test_iteritems_two_children_partial(self):
1882
1890
node = InternalNode()
1883
1891
leaf1 = LeafNode()
1884
leaf1.map(None, ('foo bar',), 'quux')
1892
leaf1.map(None, (b'foo bar',), b'quux')
1885
1893
leaf2 = LeafNode()
1886
leaf2.map(None, ('strange',), 'beast')
1887
node.add_node("f", leaf1)
1894
leaf2.map(None, (b'strange',), b'beast')
1895
node.add_node(b"f", leaf1)
1888
1896
# This sets up a path that should not be followed - it will error if
1889
1897
# the code tries to.
1890
node._items['f'] = None
1891
node.add_node("s", leaf2)
1892
self.assertEqual([(('strange',), 'beast')],
1893
sorted(node.iteritems(None, [('strange',), ('weird',)])))
1898
node._items[b'f'] = None
1899
node.add_node(b"s", leaf2)
1900
self.assertEqual([((b'strange',), b'beast')],
1901
sorted(node.iteritems(None, [(b'strange',), (b'weird',)])))
1895
1903
def test_iteritems_two_children_with_hash(self):
1896
search_key_func = chk_map.search_key_registry.get('hash-255-way')
1904
search_key_func = chk_map.search_key_registry.get(b'hash-255-way')
1897
1905
node = InternalNode(search_key_func=search_key_func)
1898
1906
leaf1 = LeafNode(search_key_func=search_key_func)
1899
leaf1.map(None, StaticTuple('foo bar',), 'quux')
1907
leaf1.map(None, StaticTuple(b'foo bar',), b'quux')
1900
1908
leaf2 = LeafNode(search_key_func=search_key_func)
1901
leaf2.map(None, StaticTuple('strange',), 'beast')
1902
self.assertEqual('\xbeF\x014', search_key_func(StaticTuple('foo bar',)))
1903
self.assertEqual('\x85\xfa\xf7K', search_key_func(StaticTuple('strange',)))
1904
node.add_node("\xbe", leaf1)
1909
leaf2.map(None, StaticTuple(b'strange',), b'beast')
1910
self.assertEqual(b'\xbeF\x014', search_key_func(
1911
StaticTuple(b'foo bar',)))
1912
self.assertEqual(b'\x85\xfa\xf7K', search_key_func(
1913
StaticTuple(b'strange',)))
1914
node.add_node(b"\xbe", leaf1)
1905
1915
# This sets up a path that should not be followed - it will error if
1906
1916
# the code tries to.
1907
node._items['\xbe'] = None
1908
node.add_node("\x85", leaf2)
1909
self.assertEqual([(('strange',), 'beast')],
1910
sorted(node.iteritems(None, [StaticTuple('strange',),
1911
StaticTuple('weird',)])))
1917
node._items[b'\xbe'] = None
1918
node.add_node(b"\x85", leaf2)
1919
self.assertEqual([((b'strange',), b'beast')],
1920
sorted(node.iteritems(None, [StaticTuple(b'strange',),
1921
StaticTuple(b'weird',)])))
1913
1923
def test_iteritems_partial_empty(self):
1914
1924
node = InternalNode()
1915
self.assertEqual([], sorted(node.iteritems([('missing',)])))
1925
self.assertEqual([], sorted(node.iteritems([(b'missing',)])))
1917
1927
def test_map_to_new_child_new(self):
1918
chkmap = self._get_map({('k1',):'foo', ('k2',):'bar'}, maximum_size=10)
1928
chkmap = self._get_map(
1929
{(b'k1',): b'foo', (b'k2',): b'bar'}, maximum_size=10)
1919
1930
chkmap._ensure_root()
1920
1931
node = chkmap._root_node
1921
1932
# Ensure test validity: nothing paged in below the root.
1922
1933
self.assertEqual(2,
1923
len([value for value in node._items.values()
1924
if isinstance(value, StaticTuple)]))
1934
len([value for value in node._items.values()
1935
if isinstance(value, StaticTuple)]))
1925
1936
# now, mapping to k3 should add a k3 leaf
1926
prefix, nodes = node.map(None, ('k3',), 'quux')
1927
self.assertEqual("k", prefix)
1928
self.assertEqual([("", node)], nodes)
1937
prefix, nodes = node.map(None, (b'k3',), b'quux')
1938
self.assertEqual(b"k", prefix)
1939
self.assertEqual([(b"", node)], nodes)
1929
1940
# check new child details
1930
child = node._items['k3']
1941
child = node._items[b'k3']
1931
1942
self.assertIsInstance(child, LeafNode)
1932
1943
self.assertEqual(1, len(child))
1933
self.assertEqual({('k3',): 'quux'}, self.to_dict(child, None))
1944
self.assertEqual({(b'k3',): b'quux'}, self.to_dict(child, None))
1934
1945
self.assertEqual(None, child._key)
1935
1946
self.assertEqual(10, child.maximum_size)
1936
1947
self.assertEqual(1, child._key_width)
1937
1948
# Check overall structure:
1938
1949
self.assertEqual(3, len(chkmap))
1939
self.assertEqual({('k1',): 'foo', ('k2',): 'bar', ('k3',): 'quux'},
1940
self.to_dict(chkmap))
1950
self.assertEqual({(b'k1',): b'foo', (b'k2',): b'bar', (b'k3',): b'quux'},
1951
self.to_dict(chkmap))
1941
1952
# serialising should only serialise the new data - k3 and the internal
1943
1954
keys = list(node.serialise(chkmap._store))
1945
1956
self.assertEqual([child_key, keys[1]], keys)
1947
1958
def test_map_to_child_child_splits_new(self):
1948
chkmap = self._get_map({('k1',):'foo', ('k22',):'bar'}, maximum_size=10)
1959
chkmap = self._get_map(
1960
{(b'k1',): b'foo', (b'k22',): b'bar'}, maximum_size=10)
1949
1961
# Check for the canonical root value for this tree:
1950
1962
self.assertEqualDiff("'' InternalNode\n"
1951
1963
" 'k1' LeafNode\n"
1952
1964
" ('k1',) 'foo'\n"
1953
1965
" 'k2' LeafNode\n"
1955
, chkmap._dump_tree())
1966
" ('k22',) 'bar'\n", chkmap._dump_tree())
1956
1967
# _dump_tree pages everything in, so reload using just the root
1957
1968
chkmap = CHKMap(chkmap._store, chkmap._root_node)
1958
1969
chkmap._ensure_root()
1959
1970
node = chkmap._root_node
1960
1971
# Ensure test validity: nothing paged in below the root.
1961
1972
self.assertEqual(2,
1962
len([value for value in node._items.values()
1963
if isinstance(value, StaticTuple)]))
1973
len([value for value in node._items.values()
1974
if isinstance(value, StaticTuple)]))
1964
1975
# now, mapping to k23 causes k22 ('k2' in node) to split into k22 and
1965
1976
# k23, which for simplicity in the current implementation generates
1966
1977
# a new internal node between node, and k22/k23.
1967
prefix, nodes = node.map(chkmap._store, ('k23',), 'quux')
1968
self.assertEqual("k", prefix)
1969
self.assertEqual([("", node)], nodes)
1978
prefix, nodes = node.map(chkmap._store, (b'k23',), b'quux')
1979
self.assertEqual(b"k", prefix)
1980
self.assertEqual([(b"", node)], nodes)
1970
1981
# check new child details
1971
child = node._items['k2']
1982
child = node._items[b'k2']
1972
1983
self.assertIsInstance(child, InternalNode)
1973
1984
self.assertEqual(2, len(child))
1974
self.assertEqual({('k22',): 'bar', ('k23',): 'quux'},
1975
self.to_dict(child, None))
1985
self.assertEqual({(b'k22',): b'bar', (b'k23',): b'quux'},
1986
self.to_dict(child, None))
1976
1987
self.assertEqual(None, child._key)
1977
1988
self.assertEqual(10, child.maximum_size)
1978
1989
self.assertEqual(1, child._key_width)
1979
1990
self.assertEqual(3, child._node_width)
1980
1991
# Check overall structure:
1981
1992
self.assertEqual(3, len(chkmap))
1982
self.assertEqual({('k1',): 'foo', ('k22',): 'bar', ('k23',): 'quux'},
1983
self.to_dict(chkmap))
1993
self.assertEqual({(b'k1',): b'foo', (b'k22',): b'bar', (b'k23',): b'quux'},
1994
self.to_dict(chkmap))
1984
1995
# serialising should only serialise the new data - although k22 hasn't
1985
1996
# changed because its a special corner case (splitting on with only one
1986
1997
# key leaves one node unaltered), in general k22 is serialised, so we
1987
1998
# expect k22, k23, the new internal node, and node, to be serialised.
1988
1999
keys = list(node.serialise(chkmap._store))
1989
2000
child_key = child._key
1990
k22_key = child._items['k22']._key
1991
k23_key = child._items['k23']._key
1992
self.assertEqual([k22_key, k23_key, child_key, node.key()], keys)
2001
k22_key = child._items[b'k22']._key
2002
k23_key = child._items[b'k23']._key
2003
self.assertEqual({k22_key, k23_key, child_key, node.key()}, set(keys))
1993
2004
self.assertEqualDiff("'' InternalNode\n"
1994
2005
" 'k1' LeafNode\n"
1995
2006
" ('k1',) 'foo'\n"
2201
2207
def test__read_all_roots_multi_new_prepares_queues(self):
2202
2208
c_map = self.make_one_deep_map(chk_map._search_key_plain)
2203
2209
key1 = c_map.key()
2204
c_map._dump_tree() # load everything
2205
key1_a = c_map._root_node._items['a'].key()
2206
key1_c = c_map._root_node._items['c'].key()
2207
c_map.map(('abb',), 'new abb content')
2210
c_map._dump_tree() # load everything
2211
key1_a = c_map._root_node._items[b'a'].key()
2212
key1_c = c_map._root_node._items[b'c'].key()
2213
c_map.map((b'abb',), b'new abb content')
2208
2214
key2 = c_map._save()
2209
key2_a = c_map._root_node._items['a'].key()
2210
key2_c = c_map._root_node._items['c'].key()
2215
key2_a = c_map._root_node._items[b'a'].key()
2216
key2_c = c_map._root_node._items[b'c'].key()
2211
2217
c_map = chk_map.CHKMap(self.get_chk_bytes(), key1,
2212
2218
chk_map._search_key_plain)
2213
c_map.map(('ccc',), 'new ccc content')
2219
c_map.map((b'ccc',), b'new ccc content')
2214
2220
key3 = c_map._save()
2215
key3_a = c_map._root_node._items['a'].key()
2216
key3_c = c_map._root_node._items['c'].key()
2221
key3_a = c_map._root_node._items[b'a'].key()
2222
key3_c = c_map._root_node._items[b'c'].key()
2217
2223
diff = self.get_difference([key2, key3], [key1],
2218
2224
chk_map._search_key_plain)
2219
2225
root_results = [record.key for record in diff._read_all_roots()]
2220
2226
self.assertEqual(sorted([key2, key3]), sorted(root_results))
2221
2227
# We should have queued up key2_a, and key3_c, but not key2_c or key3_c
2222
self.assertEqual([key2_a, key3_c], diff._new_queue)
2228
self.assertEqual({key2_a, key3_c}, set(diff._new_queue))
2223
2229
self.assertEqual([], diff._new_item_queue)
2224
2230
# And we should have queued up both a and c for the old set
2225
self.assertEqual([key1_a, key1_c], diff._old_queue)
2231
self.assertEqual({key1_a, key1_c}, set(diff._old_queue))
2227
2233
def test__read_all_roots_different_depths(self):
2228
2234
c_map = self.make_two_deep_map(chk_map._search_key_plain)
2229
c_map._dump_tree() # load everything
2235
c_map._dump_tree() # load everything
2230
2236
key1 = c_map.key()
2231
key1_a = c_map._root_node._items['a'].key()
2232
key1_c = c_map._root_node._items['c'].key()
2233
key1_d = c_map._root_node._items['d'].key()
2237
key1_a = c_map._root_node._items[b'a'].key()
2238
key1_c = c_map._root_node._items[b'c'].key()
2239
key1_d = c_map._root_node._items[b'd'].key()
2235
2241
c_map2 = self.make_one_deep_two_prefix_map(chk_map._search_key_plain)
2236
2242
c_map2._dump_tree()
2237
2243
key2 = c_map2.key()
2238
key2_aa = c_map2._root_node._items['aa'].key()
2239
key2_ad = c_map2._root_node._items['ad'].key()
2244
key2_aa = c_map2._root_node._items[b'aa'].key()
2245
key2_ad = c_map2._root_node._items[b'ad'].key()
2241
2247
diff = self.get_difference([key2], [key1], chk_map._search_key_plain)
2242
2248
root_results = [record.key for record in diff._read_all_roots()]