1import collections.abc
2import copy
3import pickle
4import sys
5import unittest
6
7class DictSetTest(unittest.TestCase):
8
9    def test_constructors_not_callable(self):
10        kt = type({}.keys())
11        self.assertRaises(TypeError, kt, {})
12        self.assertRaises(TypeError, kt)
13        it = type({}.items())
14        self.assertRaises(TypeError, it, {})
15        self.assertRaises(TypeError, it)
16        vt = type({}.values())
17        self.assertRaises(TypeError, vt, {})
18        self.assertRaises(TypeError, vt)
19
20    def test_dict_keys(self):
21        d = {1: 10, "a": "ABC"}
22        keys = d.keys()
23        self.assertEqual(len(keys), 2)
24        self.assertEqual(set(keys), {1, "a"})
25        self.assertEqual(keys, {1, "a"})
26        self.assertNotEqual(keys, {1, "a", "b"})
27        self.assertNotEqual(keys, {1, "b"})
28        self.assertNotEqual(keys, {1})
29        self.assertNotEqual(keys, 42)
30        self.assertIn(1, keys)
31        self.assertIn("a", keys)
32        self.assertNotIn(10, keys)
33        self.assertNotIn("Z", keys)
34        self.assertEqual(d.keys(), d.keys())
35        e = {1: 11, "a": "def"}
36        self.assertEqual(d.keys(), e.keys())
37        del e["a"]
38        self.assertNotEqual(d.keys(), e.keys())
39
40    def test_dict_items(self):
41        d = {1: 10, "a": "ABC"}
42        items = d.items()
43        self.assertEqual(len(items), 2)
44        self.assertEqual(set(items), {(1, 10), ("a", "ABC")})
45        self.assertEqual(items, {(1, 10), ("a", "ABC")})
46        self.assertNotEqual(items, {(1, 10), ("a", "ABC"), "junk"})
47        self.assertNotEqual(items, {(1, 10), ("a", "def")})
48        self.assertNotEqual(items, {(1, 10)})
49        self.assertNotEqual(items, 42)
50        self.assertIn((1, 10), items)
51        self.assertIn(("a", "ABC"), items)
52        self.assertNotIn((1, 11), items)
53        self.assertNotIn(1, items)
54        self.assertNotIn((), items)
55        self.assertNotIn((1,), items)
56        self.assertNotIn((1, 2, 3), items)
57        self.assertEqual(d.items(), d.items())
58        e = d.copy()
59        self.assertEqual(d.items(), e.items())
60        e["a"] = "def"
61        self.assertNotEqual(d.items(), e.items())
62
63    def test_dict_mixed_keys_items(self):
64        d = {(1, 1): 11, (2, 2): 22}
65        e = {1: 1, 2: 2}
66        self.assertEqual(d.keys(), e.items())
67        self.assertNotEqual(d.items(), e.keys())
68
69    def test_dict_values(self):
70        d = {1: 10, "a": "ABC"}
71        values = d.values()
72        self.assertEqual(set(values), {10, "ABC"})
73        self.assertEqual(len(values), 2)
74
75    def test_dict_repr(self):
76        d = {1: 10, "a": "ABC"}
77        self.assertIsInstance(repr(d), str)
78        r = repr(d.items())
79        self.assertIsInstance(r, str)
80        self.assertTrue(r == "dict_items([('a', 'ABC'), (1, 10)])" or
81                        r == "dict_items([(1, 10), ('a', 'ABC')])")
82        r = repr(d.keys())
83        self.assertIsInstance(r, str)
84        self.assertTrue(r == "dict_keys(['a', 1])" or
85                        r == "dict_keys([1, 'a'])")
86        r = repr(d.values())
87        self.assertIsInstance(r, str)
88        self.assertTrue(r == "dict_values(['ABC', 10])" or
89                        r == "dict_values([10, 'ABC'])")
90
91    def test_keys_set_operations(self):
92        d1 = {'a': 1, 'b': 2}
93        d2 = {'b': 3, 'c': 2}
94        d3 = {'d': 4, 'e': 5}
95        d4 = {'d': 4}
96
97        class CustomSet(set):
98            def intersection(self, other):
99                return CustomSet(super().intersection(other))
100
101        self.assertEqual(d1.keys() & d1.keys(), {'a', 'b'})
102        self.assertEqual(d1.keys() & d2.keys(), {'b'})
103        self.assertEqual(d1.keys() & d3.keys(), set())
104        self.assertEqual(d1.keys() & set(d1.keys()), {'a', 'b'})
105        self.assertEqual(d1.keys() & set(d2.keys()), {'b'})
106        self.assertEqual(d1.keys() & set(d3.keys()), set())
107        self.assertEqual(d1.keys() & tuple(d1.keys()), {'a', 'b'})
108        self.assertEqual(d3.keys() & d4.keys(), {'d'})
109        self.assertEqual(d4.keys() & d3.keys(), {'d'})
110        self.assertEqual(d4.keys() & set(d3.keys()), {'d'})
111        self.assertIsInstance(d4.keys() & frozenset(d3.keys()), set)
112        self.assertIsInstance(frozenset(d3.keys()) & d4.keys(), set)
113        self.assertIs(type(d4.keys() & CustomSet(d3.keys())), set)
114        self.assertIs(type(d1.keys() & []), set)
115        self.assertIs(type([] & d1.keys()), set)
116
117        self.assertEqual(d1.keys() | d1.keys(), {'a', 'b'})
118        self.assertEqual(d1.keys() | d2.keys(), {'a', 'b', 'c'})
119        self.assertEqual(d1.keys() | d3.keys(), {'a', 'b', 'd', 'e'})
120        self.assertEqual(d1.keys() | set(d1.keys()), {'a', 'b'})
121        self.assertEqual(d1.keys() | set(d2.keys()), {'a', 'b', 'c'})
122        self.assertEqual(d1.keys() | set(d3.keys()),
123                         {'a', 'b', 'd', 'e'})
124        self.assertEqual(d1.keys() | (1, 2), {'a', 'b', 1, 2})
125
126        self.assertEqual(d1.keys() ^ d1.keys(), set())
127        self.assertEqual(d1.keys() ^ d2.keys(), {'a', 'c'})
128        self.assertEqual(d1.keys() ^ d3.keys(), {'a', 'b', 'd', 'e'})
129        self.assertEqual(d1.keys() ^ set(d1.keys()), set())
130        self.assertEqual(d1.keys() ^ set(d2.keys()), {'a', 'c'})
131        self.assertEqual(d1.keys() ^ set(d3.keys()),
132                         {'a', 'b', 'd', 'e'})
133        self.assertEqual(d1.keys() ^ tuple(d2.keys()), {'a', 'c'})
134
135        self.assertEqual(d1.keys() - d1.keys(), set())
136        self.assertEqual(d1.keys() - d2.keys(), {'a'})
137        self.assertEqual(d1.keys() - d3.keys(), {'a', 'b'})
138        self.assertEqual(d1.keys() - set(d1.keys()), set())
139        self.assertEqual(d1.keys() - set(d2.keys()), {'a'})
140        self.assertEqual(d1.keys() - set(d3.keys()), {'a', 'b'})
141        self.assertEqual(d1.keys() - (0, 1), {'a', 'b'})
142
143        self.assertFalse(d1.keys().isdisjoint(d1.keys()))
144        self.assertFalse(d1.keys().isdisjoint(d2.keys()))
145        self.assertFalse(d1.keys().isdisjoint(list(d2.keys())))
146        self.assertFalse(d1.keys().isdisjoint(set(d2.keys())))
147        self.assertTrue(d1.keys().isdisjoint({'x', 'y', 'z'}))
148        self.assertTrue(d1.keys().isdisjoint(['x', 'y', 'z']))
149        self.assertTrue(d1.keys().isdisjoint(set(['x', 'y', 'z'])))
150        self.assertTrue(d1.keys().isdisjoint(set(['x', 'y'])))
151        self.assertTrue(d1.keys().isdisjoint(['x', 'y']))
152        self.assertTrue(d1.keys().isdisjoint({}))
153        self.assertTrue(d1.keys().isdisjoint(d3.keys()))
154
155        de = {}
156        self.assertTrue(de.keys().isdisjoint(set()))
157        self.assertTrue(de.keys().isdisjoint([]))
158        self.assertTrue(de.keys().isdisjoint(de.keys()))
159        self.assertTrue(de.keys().isdisjoint([1]))
160
161    def test_items_set_operations(self):
162        d1 = {'a': 1, 'b': 2}
163        d2 = {'a': 2, 'b': 2}
164        d3 = {'d': 4, 'e': 5}
165        self.assertEqual(
166            d1.items() & d1.items(), {('a', 1), ('b', 2)})
167        self.assertEqual(d1.items() & d2.items(), {('b', 2)})
168        self.assertEqual(d1.items() & d3.items(), set())
169        self.assertEqual(d1.items() & set(d1.items()),
170                         {('a', 1), ('b', 2)})
171        self.assertEqual(d1.items() & set(d2.items()), {('b', 2)})
172        self.assertEqual(d1.items() & set(d3.items()), set())
173
174        self.assertEqual(d1.items() | d1.items(),
175                         {('a', 1), ('b', 2)})
176        self.assertEqual(d1.items() | d2.items(),
177                         {('a', 1), ('a', 2), ('b', 2)})
178        self.assertEqual(d1.items() | d3.items(),
179                         {('a', 1), ('b', 2), ('d', 4), ('e', 5)})
180        self.assertEqual(d1.items() | set(d1.items()),
181                         {('a', 1), ('b', 2)})
182        self.assertEqual(d1.items() | set(d2.items()),
183                         {('a', 1), ('a', 2), ('b', 2)})
184        self.assertEqual(d1.items() | set(d3.items()),
185                         {('a', 1), ('b', 2), ('d', 4), ('e', 5)})
186
187        self.assertEqual(d1.items() ^ d1.items(), set())
188        self.assertEqual(d1.items() ^ d2.items(),
189                         {('a', 1), ('a', 2)})
190        self.assertEqual(d1.items() ^ d3.items(),
191                         {('a', 1), ('b', 2), ('d', 4), ('e', 5)})
192
193        self.assertEqual(d1.items() - d1.items(), set())
194        self.assertEqual(d1.items() - d2.items(), {('a', 1)})
195        self.assertEqual(d1.items() - d3.items(), {('a', 1), ('b', 2)})
196        self.assertEqual(d1.items() - set(d1.items()), set())
197        self.assertEqual(d1.items() - set(d2.items()), {('a', 1)})
198        self.assertEqual(d1.items() - set(d3.items()), {('a', 1), ('b', 2)})
199
200        self.assertFalse(d1.items().isdisjoint(d1.items()))
201        self.assertFalse(d1.items().isdisjoint(d2.items()))
202        self.assertFalse(d1.items().isdisjoint(list(d2.items())))
203        self.assertFalse(d1.items().isdisjoint(set(d2.items())))
204        self.assertTrue(d1.items().isdisjoint({'x', 'y', 'z'}))
205        self.assertTrue(d1.items().isdisjoint(['x', 'y', 'z']))
206        self.assertTrue(d1.items().isdisjoint(set(['x', 'y', 'z'])))
207        self.assertTrue(d1.items().isdisjoint(set(['x', 'y'])))
208        self.assertTrue(d1.items().isdisjoint({}))
209        self.assertTrue(d1.items().isdisjoint(d3.items()))
210
211        de = {}
212        self.assertTrue(de.items().isdisjoint(set()))
213        self.assertTrue(de.items().isdisjoint([]))
214        self.assertTrue(de.items().isdisjoint(de.items()))
215        self.assertTrue(de.items().isdisjoint([1]))
216
217    def test_set_operations_with_iterator(self):
218        origin = {1: 2, 3: 4}
219        self.assertEqual(origin.keys() & iter([1, 2]), {1})
220        self.assertEqual(origin.keys() | iter([1, 2]), {1, 2, 3})
221        self.assertEqual(origin.keys() ^ iter([1, 2]), {2, 3})
222        self.assertEqual(origin.keys() - iter([1, 2]), {3})
223
224        items = origin.items()
225        self.assertEqual(items & iter([(1, 2)]), {(1, 2)})
226        self.assertEqual(items ^ iter([(1, 2)]), {(3, 4)})
227        self.assertEqual(items | iter([(1, 2)]), {(1, 2), (3, 4)})
228        self.assertEqual(items - iter([(1, 2)]), {(3, 4)})
229
230    def test_set_operations_with_noniterable(self):
231        with self.assertRaises(TypeError):
232            {}.keys() & 1
233        with self.assertRaises(TypeError):
234            {}.keys() | 1
235        with self.assertRaises(TypeError):
236            {}.keys() ^ 1
237        with self.assertRaises(TypeError):
238            {}.keys() - 1
239
240        with self.assertRaises(TypeError):
241            {}.items() & 1
242        with self.assertRaises(TypeError):
243            {}.items() | 1
244        with self.assertRaises(TypeError):
245            {}.items() ^ 1
246        with self.assertRaises(TypeError):
247            {}.items() - 1
248
249    def test_recursive_repr(self):
250        d = {}
251        d[42] = d.values()
252        r = repr(d)
253        # Cannot perform a stronger test, as the contents of the repr
254        # are implementation-dependent.  All we can say is that we
255        # want a str result, not an exception of any sort.
256        self.assertIsInstance(r, str)
257        d[42] = d.items()
258        r = repr(d)
259        # Again.
260        self.assertIsInstance(r, str)
261
262    def test_deeply_nested_repr(self):
263        d = {}
264        for i in range(sys.getrecursionlimit() + 100):
265            d = {42: d.values()}
266        self.assertRaises(RecursionError, repr, d)
267
268    def test_copy(self):
269        d = {1: 10, "a": "ABC"}
270        self.assertRaises(TypeError, copy.copy, d.keys())
271        self.assertRaises(TypeError, copy.copy, d.values())
272        self.assertRaises(TypeError, copy.copy, d.items())
273
274    def test_compare_error(self):
275        class Exc(Exception):
276            pass
277
278        class BadEq:
279            def __hash__(self):
280                return 7
281            def __eq__(self, other):
282                raise Exc
283
284        k1, k2 = BadEq(), BadEq()
285        v1, v2 = BadEq(), BadEq()
286        d = {k1: v1}
287
288        self.assertIn(k1, d)
289        self.assertIn(k1, d.keys())
290        self.assertIn(v1, d.values())
291        self.assertIn((k1, v1), d.items())
292
293        self.assertRaises(Exc, d.__contains__, k2)
294        self.assertRaises(Exc, d.keys().__contains__, k2)
295        self.assertRaises(Exc, d.items().__contains__, (k2, v1))
296        self.assertRaises(Exc, d.items().__contains__, (k1, v2))
297        with self.assertRaises(Exc):
298            v2 in d.values()
299
300    def test_pickle(self):
301        d = {1: 10, "a": "ABC"}
302        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
303            self.assertRaises((TypeError, pickle.PicklingError),
304                pickle.dumps, d.keys(), proto)
305            self.assertRaises((TypeError, pickle.PicklingError),
306                pickle.dumps, d.values(), proto)
307            self.assertRaises((TypeError, pickle.PicklingError),
308                pickle.dumps, d.items(), proto)
309
310    def test_abc_registry(self):
311        d = dict(a=1)
312
313        self.assertIsInstance(d.keys(), collections.abc.KeysView)
314        self.assertIsInstance(d.keys(), collections.abc.MappingView)
315        self.assertIsInstance(d.keys(), collections.abc.Set)
316        self.assertIsInstance(d.keys(), collections.abc.Sized)
317        self.assertIsInstance(d.keys(), collections.abc.Iterable)
318        self.assertIsInstance(d.keys(), collections.abc.Container)
319
320        self.assertIsInstance(d.values(), collections.abc.ValuesView)
321        self.assertIsInstance(d.values(), collections.abc.MappingView)
322        self.assertIsInstance(d.values(), collections.abc.Sized)
323
324        self.assertIsInstance(d.items(), collections.abc.ItemsView)
325        self.assertIsInstance(d.items(), collections.abc.MappingView)
326        self.assertIsInstance(d.items(), collections.abc.Set)
327        self.assertIsInstance(d.items(), collections.abc.Sized)
328        self.assertIsInstance(d.items(), collections.abc.Iterable)
329        self.assertIsInstance(d.items(), collections.abc.Container)
330
331
332if __name__ == "__main__":
333    unittest.main()
334