| 1 | """ |
|---|
| 2 | Tests for allmydata.util.dictutil. |
|---|
| 3 | """ |
|---|
| 4 | from __future__ import annotations |
|---|
| 5 | |
|---|
| 6 | from twisted.trial import unittest |
|---|
| 7 | |
|---|
| 8 | from allmydata.util import dictutil |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | class DictUtil(unittest.TestCase): |
|---|
| 12 | def test_dict_of_sets(self): |
|---|
| 13 | ds = dictutil.DictOfSets() |
|---|
| 14 | ds.add(1, "a") |
|---|
| 15 | ds.add(2, "b") |
|---|
| 16 | ds.add(2, "b") |
|---|
| 17 | ds.add(2, "c") |
|---|
| 18 | self.failUnlessEqual(ds[1], set(["a"])) |
|---|
| 19 | self.failUnlessEqual(ds[2], set(["b", "c"])) |
|---|
| 20 | ds.discard(3, "d") # should not raise an exception |
|---|
| 21 | ds.discard(2, "b") |
|---|
| 22 | self.failUnlessEqual(ds[2], set(["c"])) |
|---|
| 23 | ds.discard(2, "c") |
|---|
| 24 | self.failIf(2 in ds) |
|---|
| 25 | |
|---|
| 26 | ds.add(3, "f") |
|---|
| 27 | ds2 = dictutil.DictOfSets() |
|---|
| 28 | ds2.add(3, "f") |
|---|
| 29 | ds2.add(3, "g") |
|---|
| 30 | ds2.add(4, "h") |
|---|
| 31 | ds.update(ds2) |
|---|
| 32 | self.failUnlessEqual(ds[1], set(["a"])) |
|---|
| 33 | self.failUnlessEqual(ds[3], set(["f", "g"])) |
|---|
| 34 | self.failUnlessEqual(ds[4], set(["h"])) |
|---|
| 35 | |
|---|
| 36 | def test_auxdict(self): |
|---|
| 37 | d = dictutil.AuxValueDict() |
|---|
| 38 | # we put the serialized form in the auxdata |
|---|
| 39 | d.set_with_aux("key", ("filecap", "metadata"), "serialized") |
|---|
| 40 | |
|---|
| 41 | self.failUnlessEqual(list(d.keys()), ["key"]) |
|---|
| 42 | self.failUnlessEqual(d["key"], ("filecap", "metadata")) |
|---|
| 43 | self.failUnlessEqual(d.get_aux("key"), "serialized") |
|---|
| 44 | def _get_missing(key): |
|---|
| 45 | return d[key] |
|---|
| 46 | self.failUnlessRaises(KeyError, _get_missing, "nonkey") |
|---|
| 47 | self.failUnlessEqual(d.get("nonkey"), None) |
|---|
| 48 | self.failUnlessEqual(d.get("nonkey", "nonvalue"), "nonvalue") |
|---|
| 49 | self.failUnlessEqual(d.get_aux("nonkey"), None) |
|---|
| 50 | self.failUnlessEqual(d.get_aux("nonkey", "nonvalue"), "nonvalue") |
|---|
| 51 | |
|---|
| 52 | d["key"] = ("filecap2", "metadata2") |
|---|
| 53 | self.failUnlessEqual(d["key"], ("filecap2", "metadata2")) |
|---|
| 54 | self.failUnlessEqual(d.get_aux("key"), None) |
|---|
| 55 | |
|---|
| 56 | d.set_with_aux("key2", "value2", "aux2") |
|---|
| 57 | self.failUnlessEqual(sorted(d.keys()), ["key", "key2"]) |
|---|
| 58 | del d["key2"] |
|---|
| 59 | self.failUnlessEqual(list(d.keys()), ["key"]) |
|---|
| 60 | self.failIf("key2" in d) |
|---|
| 61 | self.failUnlessRaises(KeyError, _get_missing, "key2") |
|---|
| 62 | self.failUnlessEqual(d.get("key2"), None) |
|---|
| 63 | self.failUnlessEqual(d.get_aux("key2"), None) |
|---|
| 64 | d["key2"] = "newvalue2" |
|---|
| 65 | self.failUnlessEqual(d.get("key2"), "newvalue2") |
|---|
| 66 | self.failUnlessEqual(d.get_aux("key2"), None) |
|---|
| 67 | |
|---|
| 68 | d = dictutil.AuxValueDict({1:2,3:4}) |
|---|
| 69 | self.failUnlessEqual(sorted(d.keys()), [1,3]) |
|---|
| 70 | self.failUnlessEqual(d[1], 2) |
|---|
| 71 | self.failUnlessEqual(d.get_aux(1), None) |
|---|
| 72 | |
|---|
| 73 | d = dictutil.AuxValueDict([ (1,2), (3,4) ]) |
|---|
| 74 | self.failUnlessEqual(sorted(d.keys()), [1,3]) |
|---|
| 75 | self.failUnlessEqual(d[1], 2) |
|---|
| 76 | self.failUnlessEqual(d.get_aux(1), None) |
|---|
| 77 | |
|---|
| 78 | d = dictutil.AuxValueDict(one=1, two=2) |
|---|
| 79 | self.failUnlessEqual(sorted(d.keys()), ["one","two"]) |
|---|
| 80 | self.failUnlessEqual(d["one"], 1) |
|---|
| 81 | self.failUnlessEqual(d.get_aux("one"), None) |
|---|
| 82 | |
|---|
| 83 | |
|---|
| 84 | class TypedKeyDict(unittest.TestCase): |
|---|
| 85 | """Tests for dictionaries that limit keys.""" |
|---|
| 86 | |
|---|
| 87 | def setUp(self): |
|---|
| 88 | pass |
|---|
| 89 | |
|---|
| 90 | def test_bytes(self): |
|---|
| 91 | """BytesKeyDict is limited to just byte keys.""" |
|---|
| 92 | self.assertRaises(TypeError, dictutil.BytesKeyDict, {u"hello": 123}) |
|---|
| 93 | d = dictutil.BytesKeyDict({b"123": 200}) |
|---|
| 94 | with self.assertRaises(TypeError): |
|---|
| 95 | d[u"hello"] = "blah" |
|---|
| 96 | with self.assertRaises(TypeError): |
|---|
| 97 | d[u"hello"] |
|---|
| 98 | with self.assertRaises(TypeError): |
|---|
| 99 | del d[u"hello"] |
|---|
| 100 | with self.assertRaises(TypeError): |
|---|
| 101 | d.setdefault(u"hello", "123") |
|---|
| 102 | with self.assertRaises(TypeError): |
|---|
| 103 | d.get(u"xcd") |
|---|
| 104 | |
|---|
| 105 | # Byte keys are fine: |
|---|
| 106 | self.assertEqual(d, {b"123": 200}) |
|---|
| 107 | d[b"456"] = 400 |
|---|
| 108 | self.assertEqual(d[b"456"], 400) |
|---|
| 109 | del d[b"456"] |
|---|
| 110 | self.assertEqual(d.get(b"456", 50), 50) |
|---|
| 111 | self.assertEqual(d.setdefault(b"456", 300), 300) |
|---|
| 112 | self.assertEqual(d[b"456"], 300) |
|---|
| 113 | |
|---|
| 114 | def test_unicode(self): |
|---|
| 115 | """UnicodeKeyDict is limited to just unicode keys.""" |
|---|
| 116 | self.assertRaises(TypeError, dictutil.UnicodeKeyDict, {b"hello": 123}) |
|---|
| 117 | d = dictutil.UnicodeKeyDict({u"123": 200}) |
|---|
| 118 | with self.assertRaises(TypeError): |
|---|
| 119 | d[b"hello"] = "blah" |
|---|
| 120 | with self.assertRaises(TypeError): |
|---|
| 121 | d[b"hello"] |
|---|
| 122 | with self.assertRaises(TypeError): |
|---|
| 123 | del d[b"hello"] |
|---|
| 124 | with self.assertRaises(TypeError): |
|---|
| 125 | d.setdefault(b"hello", "123") |
|---|
| 126 | with self.assertRaises(TypeError): |
|---|
| 127 | d.get(b"xcd") |
|---|
| 128 | |
|---|
| 129 | # Byte keys are fine: |
|---|
| 130 | self.assertEqual(d, {u"123": 200}) |
|---|
| 131 | d[u"456"] = 400 |
|---|
| 132 | self.assertEqual(d[u"456"], 400) |
|---|
| 133 | del d[u"456"] |
|---|
| 134 | self.assertEqual(d.get(u"456", 50), 50) |
|---|
| 135 | self.assertEqual(d.setdefault(u"456", 300), 300) |
|---|
| 136 | self.assertEqual(d[u"456"], 300) |
|---|
| 137 | |
|---|
| 138 | |
|---|
| 139 | class FilterTests(unittest.TestCase): |
|---|
| 140 | """ |
|---|
| 141 | Tests for ``dictutil.filter``. |
|---|
| 142 | """ |
|---|
| 143 | def test_filter(self) -> None: |
|---|
| 144 | """ |
|---|
| 145 | ``dictutil.filter`` returns a ``dict`` that contains the key/value |
|---|
| 146 | pairs for which the value is matched by the given predicate. |
|---|
| 147 | """ |
|---|
| 148 | self.assertEqual( |
|---|
| 149 | {1: 2}, |
|---|
| 150 | dictutil.filter(lambda v: v == 2, {1: 2, 2: 3}), |
|---|
| 151 | ) |
|---|