1"""
2Tests for the Key-Value Coding for hybrid python objects.
3
4NOTE: Testcases here should be synchronized with the Key-Value Coding tests
5in PyObjCTools.test.test_keyvalue and objc.test.test_keyvalue.
6
7TODO:
8    - This test uses C code, that code should be added to this package!
9    - Tests that access properties in the parent Objective-C class!
10    - More key-error tests, the tests don't cover all relevant code yet.
11"""
12import objc
13from PyObjCTools.TestSupport import *
14import sys
15from PyObjCTest.testhelper import PyObjC_TestClass3 as STUB
16from Foundation import *
17
18class KeyValueClass1 (NSObject):
19    def init(self):
20        self = super(KeyValueClass1, self).init()
21        self.key3 = 3
22        self._key4 = b"4".decode('ascii')
23        self.__private = b"private".decode('ascii')
24        return self
25
26    def addMultiple(self):
27        self.multiple = KeyValueClass1.alloc().init()
28        self.multiple.level2 = KeyValueClass1.alloc().init()
29        self.multiple.level2.level3 = KeyValueClass1.alloc().init()
30        self.multiple.level2.level3.keyA = b"hello".decode('ascii')
31        self.multiple.level2.level3.keyB = b"world".decode('ascii')
32
33    def getKey1(self):
34        return 1
35
36    def key2(self):
37        return 2
38
39    def setKey4_(self, value):
40        self._key4 = value * 4
41
42    def setKey5_(self, value):
43        self.key5 = value * 5
44
45    def keyRaisingValueError(self):
46        raise ValueError("42")
47
48    def keyRaisingNSUnknownKeyException(self):
49        return self.valueForKey_("thisKeyDoesNotExist")
50
51    def keyReturningSameSlector(self):
52        return self.keyReturningSameSelector
53
54    def keyReturningOtherSelector(self):
55        return self.getKey1
56
57class KeyValueClass1Explicit (NSObject):
58    def init(self):
59        self = super(KeyValueClass1Explicit, self).init()
60        self._values = {}
61        self._values[b'key3'.decode('ascii')] = 3
62        self._values[b'key4'.decode('ascii')] = b"4".decode('ascii')
63        self._values['_private'] = b"private".decode('ascii')
64        return self
65
66    def addMultiple(self):
67        self._values["multiple"] = KeyValueClass1Explicit.alloc().init()
68        self._values["multiple"]._values["level2"] = KeyValueClass1Explicit.alloc().init()
69        self._values["multiple"]._values["level2"]._values["level3"] = KeyValueClass1Explicit.alloc().init()
70        self._values["multiple"]._values["level2"]._values["level3"]._values["keyA"] = b"hello".decode('ascii')
71        self._values["multiple"]._values["level2"]._values["level3"]._values["keyB"] = b"world".decode('ascii')
72
73    def valueForKey_(self, key):
74        if key == "key1":
75            return 1
76
77        elif key == "key2":
78            return 2
79
80        return self._values[key]
81
82    def storedValueForKey_(self, key):
83        return self.valueForKey_(key)
84
85    def setValue_forKey_(self, value, key):
86        if key == "key4":
87            value = value * 4
88        elif key == "key5":
89            value = value * 5
90
91        self._values[key] = value
92
93    def takeStoredValue_forKey_(self, value, key):
94        self.setValue_forKey_(value, key)
95
96    def takeValue_forKey_(self, value, key):
97        self.setValue_forKey_(value, key)
98
99class KeyValueClass4 (NSObject):
100    __slots__ = ('foo', )
101
102    def init(self):
103        self = super(KeyValueClass4, self).init()
104        self.foo = b"foobar".decode('ascii')
105        return self
106
107    # Definition for property 'bar'. Use odd names for the methods
108    # because the KeyValue support recognizes the usual names.
109    def read_bar(self):
110        return self.foo + self.foo
111
112    def write_bar (self, value):
113        self.foo = value + value
114
115    bar = property(read_bar, write_bar)
116
117    roprop = property(lambda self: b"read-only".decode('ascii'))
118
119class KVOClass(NSObject):
120    def automaticallyNotifiesObserversForKey_(self, aKey):
121        return objc.NO
122
123    def test(self): return b"test".decode('ascii')
124
125
126class KeyValueObserver (NSObject):
127    def init(self):
128        self.observed = []
129        return self
130
131    def observeValueForKeyPath_ofObject_change_context_(
132            self, keyPath, object, change, context):
133        self.observed.append( (keyPath, object, change) )
134
135
136class PyKeyValueCoding (TestCase):
137    def testNoPrivateVars(self):
138        # Private instance variables ('anObject.__value') are not accessible using
139        # key-value coding.
140        o = KeyValueClass1.alloc().init()
141        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 0, o, b"private".decode('ascii'))
142
143    def testValueForKey(self):
144        o = KeyValueClass1.alloc().init()
145        o.addMultiple()
146
147        self.assertEqual(STUB.keyValue_forObject_key_(0, o, b"key1".decode('ascii')), 1)
148
149        self.assertEqual(STUB.keyValue_forObject_key_(0, o, b"key2".decode('ascii')), 2)
150        self.assertEqual(STUB.keyValue_forObject_key_(0, o, b"key3".decode('ascii')), 3)
151        self.assertEqual(STUB.keyValue_forObject_key_(0, o, b"key4".decode('ascii')), "4")
152        self.assertEqual(STUB.keyValue_forObject_key_(0, o, b"multiple".decode('ascii')), o.multiple)
153
154        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 0, o, b"nokey".decode('ascii'))
155
156        self.assertRaises(ValueError, STUB.keyValue_forObject_key_, 0, o,
157                b"keyRaisingValueError".decode('ascii'))
158        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 0, o,
159                b"keyRaisingNSUnknownKeyException".decode('ascii'))
160        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 0, o,
161                b"keyReturningSameSelector".decode('ascii'))
162
163        obj = STUB.keyValue_forObject_key_( 0, o, b"keyReturningOtherSelector".decode('ascii'))
164        self.assertIsInstance(obj, objc.selector)
165        self.assertEqual(obj.selector, b"getKey1")
166        self.assertIs(obj.self, o )
167    def testValueForKey2(self):
168        o = KeyValueClass4.alloc().init()
169
170        self.assertEqual(STUB.keyValue_forObject_key_(0, o, b"foo".decode('ascii')), b"foobar".decode('ascii'))
171        self.assertEqual(STUB.keyValue_forObject_key_(0, o, b"bar".decode('ascii')), b"foobarfoobar".decode('ascii'))
172        self.assertEqual(STUB.keyValue_forObject_key_(0, o, b"roprop".decode('ascii')), b"read-only".decode('ascii'))
173
174
175    def testStoredValueForKey(self):
176        o = KeyValueClass1.alloc().init()
177        o.addMultiple()
178
179        self.assertEqual(STUB.keyValue_forObject_key_(2, o, b"key1".decode('ascii')), 1)
180        self.assertEqual(STUB.keyValue_forObject_key_(2, o, b"key2".decode('ascii')), 2)
181        self.assertEqual(STUB.keyValue_forObject_key_(2, o, b"key3".decode('ascii')), 3)
182        self.assertEqual(STUB.keyValue_forObject_key_(2, o, b"key4".decode('ascii')), "4")
183        self.assertEqual(STUB.keyValue_forObject_key_(2, o, b"multiple".decode('ascii')), o.multiple)
184
185        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 2, o, b"nokey".decode('ascii'))
186
187    def testStoredValueForKey2(self):
188        o = KeyValueClass4.alloc().init()
189
190        self.assertEqual(STUB.keyValue_forObject_key_(2, o, b"foo".decode('ascii')), b"foobar".decode('ascii'))
191        self.assertEqual(STUB.keyValue_forObject_key_(2, o, b"bar".decode('ascii')), b"foobarfoobar".decode('ascii'))
192        self.assertEqual(STUB.keyValue_forObject_key_(2, o, b"roprop".decode('ascii')), b"read-only".decode('ascii'))
193
194    def testValueForKeyPath(self):
195        o = KeyValueClass1.alloc().init()
196        o.addMultiple()
197
198        self.assertEqual(STUB.keyValue_forObject_key_(1, o, b"multiple".decode('ascii')), o.multiple)
199        self.assertEqual(STUB.keyValue_forObject_key_(1, o, b"multiple.level2".decode('ascii')), o.multiple.level2)
200        self.assertEqual(STUB.keyValue_forObject_key_(1, o, b"multiple.level2.level3.keyA".decode('ascii')),
201            o.multiple.level2.level3.keyA)
202        self.assertEqual(STUB.keyValue_forObject_key_(1, o, b"multiple.level2.level3.keyB".decode('ascii')),
203            o.multiple.level2.level3.keyB)
204
205        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 1, o, b"multiple.level2.nokey".decode('ascii'))
206
207    @max_os_level('10.5')
208    def testValuesForKeys(self):
209        o = KeyValueClass1.alloc().init()
210
211        self.assertEqual(STUB.keyValue_forObject_key_(3, o, [b"key1".decode('ascii'), b"key2".decode('ascii'), b"key3".decode('ascii'), b"key4".decode('ascii')]), { b"key1".decode('ascii'):1, b"key2".decode('ascii'):2, b"key3".decode('ascii'): 3, b"key4".decode('ascii'): b"4".decode('ascii')} )
212
213        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 3, o, [b"key1".decode('ascii'), b"key3".decode('ascii'), b"nosuchkey".decode('ascii')])
214
215    @max_os_level('10.5')
216    def testTakeValueForKey(self):
217        o = KeyValueClass1.alloc().init()
218
219        self.assertEqual(o.key3, 3)
220        STUB.setKeyValue_forObject_key_value_(0, o, b'key3'.decode('ascii'), b'drie'.decode('ascii'))
221        self.assertEqual(o.key3, b"drie".decode('ascii'))
222
223        self.assertEqual(o._key4, b"4".decode('ascii'))
224        STUB.setKeyValue_forObject_key_value_(0, o, b'key4'.decode('ascii'), b'vier'.decode('ascii'))
225        self.assert_(not hasattr(o, b"key4".decode('ascii')))
226        self.assertEqual(o._key4, b"viervierviervier".decode('ascii'))
227
228        o.key5 = 1
229        STUB.setKeyValue_forObject_key_value_(0, o, b'key5'.decode('ascii'), b'V'.decode('ascii'))
230        self.assertEqual(o.key5, b"VVVVV".decode('ascii'))
231
232        self.assert_(not hasattr(o, b'key9'.decode('ascii')))
233        STUB.setKeyValue_forObject_key_value_(0, o, b'key9'.decode('ascii'), b'IX'.decode('ascii'))
234        self.assert_(hasattr(o, b'key9'.decode('ascii')))
235        self.assertEqual(o.key9, b'IX'.decode('ascii'))
236
237    @max_os_level('10.5')
238    def testTakeValueForKey2(self):
239        o = KeyValueClass4.alloc().init()
240
241        self.assertEqual(o.foo, b"foobar".decode('ascii'))
242        STUB.setKeyValue_forObject_key_value_(0, o, b'foo'.decode('ascii'), b'FOO'.decode('ascii'))
243        self.assertEqual(o.foo, b"FOO".decode('ascii'))
244
245        self.assertRaises(KeyError, STUB.setKeyValue_forObject_key_value_, 0, o, b'key9'.decode('ascii'), b'IX'.decode('ascii'))
246
247
248    def testTakeStoredValueForKey(self):
249        o = KeyValueClass1.alloc().init()
250
251        self.assertEqual(o.key3, 3)
252        STUB.setKeyValue_forObject_key_value_(2, o, b'key3'.decode('ascii'), b'drie'.decode('ascii'))
253        self.assertEqual(o.key3, b"drie".decode('ascii'))
254
255        self.assertEqual(o._key4, b"4".decode('ascii'))
256        STUB.setKeyValue_forObject_key_value_(2, o, b'key4'.decode('ascii'), b'vier'.decode('ascii'))
257        self.assertEqual(o._key4, b"viervierviervier".decode('ascii'))
258
259        o.key5 = 1
260        STUB.setKeyValue_forObject_key_value_(2, o, b'key5'.decode('ascii'), b'V'.decode('ascii'))
261        self.assertEqual(o.key5, b"VVVVV".decode('ascii'))
262
263        self.assert_(not hasattr(o, b'key9'.decode('ascii')))
264        STUB.setKeyValue_forObject_key_value_(2, o, b'key9'.decode('ascii'), b'IX'.decode('ascii'))
265        self.assert_(hasattr(o, b'key9'.decode('ascii')))
266        self.assertEqual(o.key9, b'IX'.decode('ascii'))
267
268    def testStoredTakeValueForKey2(self):
269        o = KeyValueClass4.alloc().init()
270
271        self.assertEqual(o.foo, b"foobar".decode('ascii'))
272        STUB.setKeyValue_forObject_key_value_(2, o, b'foo'.decode('ascii'), b'FOO'.decode('ascii'))
273        self.assertEqual(o.foo, b"FOO".decode('ascii'))
274
275        self.assertRaises(KeyError, STUB.setKeyValue_forObject_key_value_, 2, o, b'key9'.decode('ascii'), b'IX'.decode('ascii'))
276        self.assertRaises(KeyError, STUB.setKeyValue_forObject_key_value_, 2, o, b'roprop'.decode('ascii'), b'IX'.decode('ascii'))
277
278    @max_os_level('10.5')
279    def testTakeValuesFromDictionary(self):
280        o = KeyValueClass1.alloc().init()
281
282        self.assertEqual(o.key3, 3)
283        self.assertEqual(o._key4, b"4".decode('ascii'))
284        o.key5 = 1
285        self.assert_(not hasattr(o, b'key9'.decode('ascii')))
286
287        STUB.setKeyValue_forObject_key_value_(3, o, None,
288            {
289                b'key3'.decode('ascii'): b'drie'.decode('ascii'),
290                b'key4'.decode('ascii'): b'vier'.decode('ascii'),
291                b'key5'.decode('ascii'): b'V'.decode('ascii'),
292                b'key9'.decode('ascii'): b'IX'.decode('ascii'),
293            })
294
295        self.assertEqual(o.key3, b"drie".decode('ascii'))
296        self.assertEqual(o._key4, b"viervierviervier".decode('ascii'))
297        self.assertEqual(o.key5, b"VVVVV".decode('ascii'))
298        self.assert_(hasattr(o, b'key9'.decode('ascii')))
299        self.assertEqual(o.key9, b'IX'.decode('ascii'))
300
301    @max_os_level('10.5')
302    def testTakeValuesFromDictionary2(self):
303        o = KeyValueClass4.alloc().init()
304
305        self.assertEqual(o.foo, b"foobar".decode('ascii'))
306        STUB.setKeyValue_forObject_key_value_(3, o, None, { b'foo'.decode('ascii'): b'FOO'.decode('ascii') })
307        self.assertEqual(o.foo, b"FOO".decode('ascii'))
308
309        self.assertRaises(KeyError, STUB.setKeyValue_forObject_key_value_, 3, o, None, { b'key9'.decode('ascii'):  b'IX'.decode('ascii') })
310        self.assertRaises(KeyError, STUB.setKeyValue_forObject_key_value_, 3, o, None, { b'roprop'.decode('ascii'):  b'IX'.decode('ascii') })
311
312    @max_os_level('10.5')
313    def testTakeValueForKeyPath(self):
314        o = KeyValueClass1.alloc().init()
315        o.addMultiple()
316
317        self.assertEqual(o.multiple.level2.level3.keyA, b"hello".decode('ascii'))
318        self.assertEqual(o.multiple.level2.level3.keyB, b"world".decode('ascii'))
319
320        STUB.setKeyValue_forObject_key_value_(1, o, b"multiple.level2.level3.keyA".decode('ascii'), b"KeyAValue".decode('ascii'))
321        self.assertEqual(o.multiple.level2.level3.keyA, b"KeyAValue".decode('ascii'))
322
323        STUB.setKeyValue_forObject_key_value_(1, o, b"multiple.level2.level3.keyB".decode('ascii'), 9.999)
324        self.assertEqual(o.multiple.level2.level3.keyB, 9.999)
325
326    if hasattr(NSObject, b"willChangeValueForKey_".decode('ascii')):
327        # NSKeyValueObserving is only available on Panther and beyond
328        def testKVO1(self):
329            o = KVOClass.alloc().init()
330            o.addObserver_forKeyPath_options_context_(self, b"test".decode('ascii'), 0, None)
331            o.removeObserver_forKeyPath_(self, b"test".decode('ascii'))
332
333        def testKVO2(self):
334            """
335            Check if observations work for python-based keys on ObjC classes
336            """
337            observer = KeyValueObserver.alloc().init()
338            self.assertEqual(observer.observed, [])
339
340            o = KeyValueClass1.alloc().init()
341
342            o.addObserver_forKeyPath_options_context_(observer, b"key3".decode('ascii'), 0, 0)
343            try:
344                STUB.setKeyValue_forObject_key_value_(2, o, b'key3'.decode('ascii'), b'drie'.decode('ascii'))
345                self.assertEqual(o.key3, b"drie".decode('ascii'))
346
347                self.assertEqual(len(observer.observed), 1)
348
349                keyPath, object, change = observer.observed[0]
350                self.assertEqual(keyPath, b"key3".decode('ascii'))
351                self.assert_(object is o)
352                self.assertEqual(change, {NSKeyValueChangeKindKey: 1 })
353
354            finally:
355                o.removeObserver_forKeyPath_(observer, b'key3'.decode('ascii'))
356
357        def testKVO3(self):
358            """
359            Check if observations work for python-based keys on ObjC classes
360            """
361            observer = KeyValueObserver.alloc().init()
362            self.assertEqual(observer.observed, [])
363
364            o = KeyValueClass1.alloc().init()
365            STUB.setKeyValue_forObject_key_value_(2, o, b'key3'.decode('ascii'), b'three'.decode('ascii'))
366
367            o.addObserver_forKeyPath_options_context_(observer, b"key3".decode('ascii'),
368                    NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld,
369                    0)
370            try:
371                STUB.setKeyValue_forObject_key_value_(2, o, b'key3'.decode('ascii'), b'drie'.decode('ascii'))
372                self.assertEqual(o.key3, b"drie".decode('ascii'))
373
374                self.assertEqual(len(observer.observed), 1)
375
376                keyPath, object, change = observer.observed[0]
377                self.assertEqual(keyPath, b"key3".decode('ascii'))
378                self.assert_(object is o)
379                self.assertEqual(change,
380                    {
381                        NSKeyValueChangeKindKey:1,
382                        NSKeyValueChangeNewKey:b'drie'.decode('ascii'),
383                        NSKeyValueChangeOldKey:b'three'.decode('ascii')
384                    })
385
386            finally:
387                o.removeObserver_forKeyPath_(observer, b'key3'.decode('ascii'))
388
389class PyKeyValueCodingExplicit (TestCase):
390
391    def testValueForKey(self):
392        o = KeyValueClass1Explicit.alloc().init()
393        o.addMultiple()
394
395        self.assertEqual(STUB.keyValue_forObject_key_(0, o, b"key1".decode('ascii')), 1)
396
397        self.assertEqual(STUB.keyValue_forObject_key_(0, o, b"key2".decode('ascii')), 2)
398        self.assertEqual(STUB.keyValue_forObject_key_(0, o, b"key3".decode('ascii')), 3)
399        self.assertEqual(STUB.keyValue_forObject_key_(0, o, b"key4".decode('ascii')), "4")
400        self.assertEqual(STUB.keyValue_forObject_key_(0, o, b"multiple".decode('ascii')), o._values['multiple'])
401
402        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 0, o, b"nokey".decode('ascii'))
403
404    def testStoredValueForKey(self):
405        o = KeyValueClass1Explicit.alloc().init()
406        o.addMultiple()
407
408        self.assertEqual(STUB.keyValue_forObject_key_(2, o, b"key1".decode('ascii')), 1)
409        self.assertEqual(STUB.keyValue_forObject_key_(2, o, b"key2".decode('ascii')), 2)
410        self.assertEqual(STUB.keyValue_forObject_key_(2, o, b"key3".decode('ascii')), 3)
411        self.assertEqual(STUB.keyValue_forObject_key_(2, o, b"key4".decode('ascii')), "4")
412        self.assertEqual(STUB.keyValue_forObject_key_(2, o, b"multiple".decode('ascii')), o._values['multiple'])
413
414        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 2, o, b"nokey".decode('ascii'))
415
416    def testValueForKeyPath(self):
417        o = KeyValueClass1Explicit.alloc().init()
418        o.addMultiple()
419
420        self.assertEqual(STUB.keyValue_forObject_key_(1, o, b"multiple".decode('ascii')), o._values['multiple'])
421        self.assertEqual(STUB.keyValue_forObject_key_(1, o, b"multiple.level2".decode('ascii')), o._values['multiple']._values['level2'])
422        self.assertEqual(STUB.keyValue_forObject_key_(1, o, b"multiple.level2.level3.keyA".decode('ascii')),
423            o._values['multiple']._values['level2']._values['level3']._values['keyA'])
424        self.assertEqual(STUB.keyValue_forObject_key_(1, o, b"multiple.level2.level3.keyB".decode('ascii')),
425            o._values['multiple']._values['level2']._values['level3']._values['keyB'])
426
427        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 1, o, b"multiple.level2.nokey".decode('ascii'))
428
429    @max_os_level('10.5')
430    def testValuesForKeys(self):
431        o = KeyValueClass1Explicit.alloc().init()
432
433        self.assertEqual(STUB.keyValue_forObject_key_(3, o, [b"key1".decode('ascii'), b"key2".decode('ascii'), b"key3".decode('ascii'), b"key4".decode('ascii')]), { b"key1".decode('ascii'):1, b"key2".decode('ascii'):2, b"key3".decode('ascii'): 3, b"key4".decode('ascii'): b"4".decode('ascii')} )
434
435        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 3, o, [b"key1".decode('ascii'), b"key3".decode('ascii'), b"nosuchkey".decode('ascii')])
436
437    def testTakeValueForKey(self):
438        o = KeyValueClass1Explicit.alloc().init()
439
440        self.assertEqual(o._values['key3'], 3)
441        STUB.setKeyValue_forObject_key_value_(0, o, b'key3'.decode('ascii'), b'drie'.decode('ascii'))
442        self.assertEqual(o._values['key3'], b"drie".decode('ascii'))
443
444        self.assertEqual(o._values['key4'], b"4".decode('ascii'))
445        STUB.setKeyValue_forObject_key_value_(0, o, b'key4'.decode('ascii'), b'vier'.decode('ascii'))
446        self.assert_(not hasattr(o, b"key4".decode('ascii')))
447        self.assertEqual(o._values['key4'], b"viervierviervier".decode('ascii'))
448
449        o._values['key5'] = 1
450        STUB.setKeyValue_forObject_key_value_(0, o, b'key5'.decode('ascii'), b'V'.decode('ascii'))
451        self.assertEqual(o._values['key5'], b"VVVVV".decode('ascii'))
452
453        self.assert_(not hasattr(o, b'key9'.decode('ascii')))
454        self.assert_('key9' not in o._values)
455        STUB.setKeyValue_forObject_key_value_(0, o, b'key9'.decode('ascii'), b'IX'.decode('ascii'))
456        self.assert_(not hasattr(o, b'key9'.decode('ascii')))
457        self.assert_('key9' in o._values)
458        self.assertEqual(o._values['key9'], b'IX'.decode('ascii'))
459
460    def testTakeStoredValueForKey(self):
461        o = KeyValueClass1Explicit.alloc().init()
462
463        self.assertEqual(o._values['key3'], 3)
464        STUB.setKeyValue_forObject_key_value_(2, o, b'key3'.decode('ascii'), b'drie'.decode('ascii'))
465        self.assertEqual(o._values['key3'], b"drie".decode('ascii'))
466
467        self.assertEqual(o._values['key4'], b"4".decode('ascii'))
468        STUB.setKeyValue_forObject_key_value_(2, o, b'key4'.decode('ascii'), b'vier'.decode('ascii'))
469        self.assertEqual(o._values['key4'], b"viervierviervier".decode('ascii'))
470
471        o.key5 = 1
472        STUB.setKeyValue_forObject_key_value_(2, o, b'key5'.decode('ascii'), b'V'.decode('ascii'))
473        self.assertEqual(o._values['key5'], b"VVVVV".decode('ascii'))
474
475        self.assert_('key9' not in o._values)
476        STUB.setKeyValue_forObject_key_value_(2, o, b'key9'.decode('ascii'), b'IX'.decode('ascii'))
477        self.assert_('key9' in o._values)
478        self.assertEqual(o._values['key9'], b'IX'.decode('ascii'))
479
480    @max_os_level('10.5')
481    def testTakeValuesFromDictionary(self):
482        o = KeyValueClass1Explicit.alloc().init()
483
484        self.assertEqual(o._values['key3'], 3)
485        self.assertEqual(o._values['key4'], b"4".decode('ascii'))
486        o._values['key5'] = 1
487        self.assert_('key9' not in o._values)
488
489        STUB.setKeyValue_forObject_key_value_(3, o, None,
490            {
491                b'key3'.decode('ascii'): b'drie'.decode('ascii'),
492                b'key4'.decode('ascii'): b'vier'.decode('ascii'),
493                b'key5'.decode('ascii'): b'V'.decode('ascii'),
494                b'key9'.decode('ascii'): b'IX'.decode('ascii'),
495            })
496
497        self.assertEqual(o._values['key3'], b"drie".decode('ascii'))
498        self.assertEqual(o._values['key4'], b"viervierviervier".decode('ascii'))
499        self.assertEqual(o._values['key5'], b"VVVVV".decode('ascii'))
500        self.assertEqual(o._values['key9'], b'IX'.decode('ascii'))
501
502    @max_os_level('10.5')
503    def testTakeValueForKeyPath(self):
504        o = KeyValueClass1Explicit.alloc().init()
505        o.addMultiple()
506
507        self.assertEqual(o._values['multiple']._values['level2']._values['level3']._values['keyA'], b"hello".decode('ascii'))
508        self.assertEqual(o._values['multiple']._values['level2']._values['level3']._values['keyB'], b"world".decode('ascii'))
509
510        STUB.setKeyValue_forObject_key_value_(1, o, b"multiple.level2.level3.keyA".decode('ascii'), b"KeyAValue".decode('ascii'))
511        self.assertEqual(o._values['multiple']._values['level2']._values['level3']._values['keyA'], b"KeyAValue".decode('ascii'))
512
513        STUB.setKeyValue_forObject_key_value_(1, o, b"multiple.level2.level3.keyB".decode('ascii'), 9.999)
514        self.assertEqual(o._values['multiple']._values['level2']._values['level3']._values['keyB'], 9.999)
515
516
517class TestBaseExceptions (TestCase):
518    """
519    Check that NSObject implementation of Key-Value coding raises the
520    exception that we expect it to raise.
521    """
522    def testValueForKey(self):
523        o = NSObject.alloc().init()
524
525        self.assertRaises(KeyError, o.valueForKey_, b"unknownKey".decode('ascii'))
526
527    def testStoredValueForKey(self):
528        o = NSObject.alloc().init()
529
530        self.assertRaises(KeyError, o.storedValueForKey_, b"unknownKey".decode('ascii'))
531
532    def testTakeStoredValue(self):
533        o = NSObject.alloc().init()
534
535        self.assertRaises(KeyError,
536            o.takeStoredValue_forKey_, b"value".decode('ascii'), b"unknownKey".decode('ascii'))
537
538
539
540if __name__ == "__main__":
541    main()
542