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