1"""
2test.test_dict from python 2.7 adapted for testing NSMutableDictionary
3"""
4from PyObjCTools.TestSupport import *
5
6import objc
7import operator
8NSDictionary = objc.lookUpClass('NSDictionary')
9NSMutableDictionary = objc.lookUpClass('NSMutableDictionary')
10
11import test.test_dict
12
13
14class TestDict (test.test_dict.DictTest, TestCase):
15    def setUp(self):
16        test.test_dict.dict = NSMutableDictionary
17
18    def tearDown(self):
19        del test.test_dict.dict
20
21    def test_literal_constructor(self): pass
22
23    def test_bool(self):
24        self.assertIs(not NSMutableDictionary(), True)
25        self.assertTrue(NSMutableDictionary({1: 2}))
26        self.assertIs(bool(NSMutableDictionary()), False)
27        self.assertIs(bool(NSMutableDictionary({1: 2})), True)
28
29    def test_keys(self):
30        d = NSMutableDictionary()
31        self.assertEqual(d.keys(), [])
32        d = NSMutableDictionary({'a': 1, 'b': 2})
33        k = d.keys()
34        self.assertTrue(d.has_key('a'))
35        self.assertTrue(d.has_key('b'))
36
37        self.assertRaises(TypeError, d.keys, None)
38
39    def test_values(self):
40        d = NSMutableDictionary({})
41        self.assertEqual(d.values(), [])
42        d = NSMutableDictionary({1:2})
43        self.assertEqual(d.values(), [2])
44
45        self.assertRaises(TypeError, d.values, None)
46
47    def test_items(self):
48        d = NSMutableDictionary({})
49        self.assertEqual(d.items(), [])
50
51        d = NSMutableDictionary({1:2})
52        self.assertEqual(d.items(), [(1, 2)])
53
54        self.assertRaises(TypeError, d.items, None)
55
56    def test_has_key(self):
57        d = NSMutableDictionary({})
58        self.assertFalse(d.has_key('a'))
59        d = NSMutableDictionary({'a': 1, 'b': 2})
60        k = list(d.keys())
61        k.sort()
62        self.assertEqual(k, ['a', 'b'])
63
64        self.assertRaises(TypeError, d.has_key)
65
66    def test_contains(self):
67        d = NSMutableDictionary({})
68        self.assertNotIn('a', d)
69        self.assertFalse('a' in d)
70        self.assertTrue('a' not in d)
71        d = NSMutableDictionary({'a': 1, 'b': 2})
72        self.assertIn('a', d)
73        self.assertIn('b', d)
74        self.assertNotIn('c', d)
75
76        self.assertRaises(TypeError, d.__contains__)
77
78    def test_len(self):
79        d = NSMutableDictionary({})
80        self.assertEqual(len(d), 0)
81        d = NSMutableDictionary({'a': 1, 'b': 2})
82        self.assertEqual(len(d), 2)
83
84    def test_getitem(self):
85        d = NSMutableDictionary({'a': 1, 'b': 2})
86        self.assertEqual(d['a'], 1)
87        self.assertEqual(d['b'], 2)
88        d['c'] = 3
89        d['a'] = 4
90        self.assertEqual(d['c'], 3)
91        self.assertEqual(d['a'], 4)
92        del d['b']
93        self.assertEqual(d, {'a': 4, 'c': 3})
94
95        self.assertRaises(TypeError, d.__getitem__)
96
97        class BadEq(object):
98            def __eq__(self, other):
99                raise Exc()
100            def __hash__(self):
101                return 24
102
103        d = NSMutableDictionary({})
104        d[BadEq()] = 42
105        self.assertRaises(KeyError, d.__getitem__, 23)
106
107        class Exc(Exception): pass
108
109        class BadHash(object):
110            fail = False
111            def __hash__(self):
112                if self.fail:
113                    raise Exc()
114                else:
115                    return 42
116
117        #x = BadHash()
118        #d[x] = 42
119        #x.fail = True
120        #self.assertRaises(Exc, d.__getitem__, x)
121
122    def test_clear(self):
123        d = NSMutableDictionary({1:1, 2:2, 3:3})
124        d.clear()
125        self.assertEqual(d, {})
126
127        self.assertRaises(TypeError, d.clear, None)
128
129    def test_update(self):
130        d = NSMutableDictionary({})
131        d.update({1:100})
132        d.update({2:20})
133        d.update({1:1, 2:2, 3:3})
134        self.assertEqual(d, {1:1, 2:2, 3:3})
135
136        d.update()
137        self.assertEqual(d, {1:1, 2:2, 3:3})
138
139        self.assertRaises((TypeError, AttributeError), d.update, None)
140
141        class SimpleUserDict:
142            def __init__(self):
143                self.d = {1:1, 2:2, 3:3}
144            def keys(self):
145                return self.d.keys()
146            def __getitem__(self, i):
147                return self.d[i]
148        d.clear()
149        d.update(SimpleUserDict())
150        self.assertEqual(d, {1:1, 2:2, 3:3})
151
152        class Exc(Exception): pass
153
154        d.clear()
155        class FailingUserDict:
156            def keys(self):
157                raise Exc()
158        self.assertRaises(Exc, d.update, FailingUserDict())
159
160        class FailingUserDict:
161            def keys(self):
162                class BogonIter:
163                    def __init__(self):
164                        self.i = 1
165                    def __iter__(self):
166                        return self
167                    def next(self):
168                        if self.i:
169                            self.i = 0
170                            return 'a'
171                        raise Exc()
172                return BogonIter()
173            def __getitem__(self, key):
174                return key
175        self.assertRaises(Exc, d.update, FailingUserDict())
176
177        class FailingUserDict:
178            def keys(self):
179                class BogonIter:
180                    def __init__(self):
181                        self.i = ord('a')
182                    def __iter__(self):
183                        return self
184                    def next(self):
185                        if self.i <= ord('z'):
186                            rtn = chr(self.i)
187                            self.i += 1
188                            return rtn
189                        raise StopIteration()
190                return BogonIter()
191            def __getitem__(self, key):
192                raise Exc()
193        self.assertRaises(Exc, d.update, FailingUserDict())
194
195        class badseq(object):
196            def __iter__(self):
197                return self
198            def next(self):
199                raise Exc()
200
201        self.assertRaises(Exc, NSMutableDictionary({}).update, badseq())
202
203        self.assertRaises(ValueError, NSMutableDictionary({}).update, [(1, 2, 3)])
204
205    def test_fromkeys(self):
206        self.assertEqual(NSMutableDictionary.fromkeys('abc'), {'a':None, 'b':None, 'c':None})
207        d = NSMutableDictionary({})
208        self.assertIsNot(d.fromkeys('abc'), d)
209        self.assertEqual(d.fromkeys('abc'), {'a':None, 'b':None, 'c':None})
210        self.assertEqual(d.fromkeys((4,5),0), {4:0, 5:0})
211        self.assertEqual(d.fromkeys([]), {})
212        def g():
213            yield 1
214        self.assertEqual(d.fromkeys(g()), {1:None})
215        self.assertRaises(TypeError, NSMutableDictionary({}).fromkeys, 3)
216        #class dictlike(dict): pass
217        #self.assertEqual(dictlike.fromkeys('a'), {'a':None})
218        #self.assertEqual(dictlike().fromkeys('a'), {'a':None})
219        #self.assertIsInstance(dictlike.fromkeys('a'), dictlike)
220        #self.assertIsInstance(dictlike().fromkeys('a'), dictlike)
221        #class mydict(dict):
222        #    def __new__(cls):
223        #        return UserDict.UserDict()
224        #ud = mydict.fromkeys('ab')
225        #self.assertEqual(ud, {'a':None, 'b':None})
226        #self.assertIsInstance(ud, UserDict.UserDict)
227        #self.assertRaises(TypeError, dict.fromkeys)
228
229        class Exc(Exception): pass
230
231        #class baddict1(dict):
232        #    def __init__(self):
233        #        raise Exc()
234
235        #self.assertRaises(Exc, baddict1.fromkeys, [1])
236
237        class BadSeq(object):
238            def __iter__(self):
239                return self
240            def next(self):
241                raise Exc()
242
243        self.assertRaises(Exc, NSMutableDictionary.fromkeys, BadSeq())
244
245        #class baddict2(dict):
246        #    def __setitem__(self, key, value):
247        #        raise Exc()
248
249        #self.assertRaises(Exc, baddict2.fromkeys, [1])
250
251        # test fast path for dictionary inputs
252        d = NSMutableDictionary(zip(range(6), range(6)))
253        self.assertEqual(NSMutableDictionary.fromkeys(d, 0), NSMutableDictionary(zip(range(6), [0]*6)))
254
255    def test_copy(self):
256        d = NSMutableDictionary({1:1, 2:2, 3:3})
257        self.assertEqual(d.copy(), {1:1, 2:2, 3:3})
258        self.assertEqual(NSMutableDictionary({}).copy(), {})
259        self.assertRaises(TypeError, d.copy, None)
260
261    def test_get(self):
262        d = NSMutableDictionary({})
263        self.assertIs(d.get('c'), None)
264        self.assertEqual(d.get('c', 3), 3)
265        d = NSMutableDictionary({'a': 1, 'b': 2})
266        self.assertIs(d.get('c'), None)
267        self.assertEqual(d.get('c', 3), 3)
268        self.assertEqual(d.get('a'), 1)
269        self.assertEqual(d.get('a', 3), 1)
270        self.assertRaises(TypeError, d.get)
271        self.assertRaises(TypeError, d.get, None, None, None)
272
273    def test_setdefault(self):
274        # dict.setdefault()
275        d = NSMutableDictionary({})
276        self.assertIs(d.setdefault('key0'), None)
277        d.setdefault('key0', [])
278        self.assertIs(d.setdefault('key0'), None)
279        d.setdefault('key', []).append(3)
280        self.assertEqual(d['key'][0], 3)
281        d.setdefault('key', []).append(4)
282        self.assertEqual(len(d['key']), 2)
283        self.assertRaises(TypeError, d.setdefault)
284
285        class Exc(Exception): pass
286
287        class BadHash(object):
288            fail = False
289            def __hash__(self):
290                if self.fail:
291                    raise Exc()
292                else:
293                    return 42
294
295        #x = BadHash()
296        #d[x] = 42
297        #x.fail = True
298        #self.assertRaises(Exc, d.setdefault, x, [])
299
300    def test_popitem(self):
301        # dict.popitem()
302        for copymode in -1, +1:
303            # -1: b has same structure as a
304            # +1: b is a.copy()
305            for log2size in range(12):
306                size = 2**log2size
307                a = NSMutableDictionary({})
308                b = NSMutableDictionary({})
309                for i in range(size):
310                    a[repr(i)] = i
311                    if copymode < 0:
312                        b[repr(i)] = i
313                if copymode > 0:
314                    b = a.mutableCopy()
315                for i in range(size):
316                    ka, va = ta = a.popitem()
317                    self.assertEqual(va, int(ka))
318                    kb, vb = tb = b.popitem()
319                    self.assertEqual(vb, int(kb))
320                    self.assertFalse(copymode < 0 and ta != tb)
321                self.assertFalse(a)
322                self.assertFalse(b)
323
324        d = NSMutableDictionary({})
325        self.assertRaises(KeyError, d.popitem)
326
327    def test_pop(self):
328        # Tests for pop with specified key
329        d = NSMutableDictionary({})
330        k, v = 'abc', 'def'
331        d[k] = v
332        self.assertRaises(KeyError, d.pop, 'ghi')
333
334        self.assertEqual(d.pop(k), v)
335        self.assertEqual(len(d), 0)
336
337        self.assertRaises(KeyError, d.pop, k)
338
339        # verify longs/ints get same value when key > 32 bits
340        # (for 64-bit archs).  See SF bug #689659.
341        x = 4503599627370496L
342        y = 4503599627370496
343        h = NSMutableDictionary({x: 'anything', y: 'something else'})
344        self.assertEqual(h[x], h[y])
345
346        self.assertEqual(d.pop(k, v), v)
347        d[k] = v
348        self.assertEqual(d.pop(k, 1), v)
349
350        self.assertRaises(TypeError, d.pop)
351
352        class Exc(Exception): pass
353
354        class BadHash(object):
355            fail = False
356            def __hash__(self):
357                if self.fail:
358                    raise Exc()
359                else:
360                    return 42
361
362        #x = BadHash()
363        #d[x] = 42
364        #x.fail = True
365        #self.assertRaises(Exc, d.pop, x)
366
367    def test_mutatingiteration(self):
368        # XXX: Reimplement iteration using NSFastIteration,
369        return
370
371        # changing dict size during iteration
372        d = NSMutableDictionary({})
373        d[1] = 1
374        try:
375            for i in d:
376                d[i+1] = 1
377        except RuntimeError:
378            pass
379        else:
380            self.fail("RuntimeError not raised")
381
382    def test_repr(self): pass
383    def test_le(self): pass
384    def test_missing(self): pass
385    def test_tuple_keyerror(self):
386        # SF #1576657
387        d = NSMutableDictionary()
388        try:
389            d[(1,)]
390        except KeyError as exc:
391            pass
392        else:
393            fail("KeyError not raised")
394        self.assertEqual(exc.args, ((1,),))
395
396    def test_bad_key(self): pass
397    def test_resize1(self): pass
398    def test_resize2(self): pass
399    def test_empty_presized_dict_in_freelist(self): pass
400    def test_container_iterator(self): pass
401    def test_track_literals(self): pass
402    def test_track_dynamic(self): pass
403    def test_track_subtypes(self): pass
404
405class GeneralMappingTests (test.test_dict.GeneralMappingTests):
406    type2test = NSMutableDictionary
407
408
409if __name__ == "__main__":
410    main()
411