1from PyObjCTools.TestSupport import *
2import objc
3from PyObjCTest.test_object_property import OCObserve
4import sys
5import pickle
6
7NSObject = objc.lookUpClass('NSObject')
8
9class TestSetPropertyHelper (NSObject):
10    aSet = objc.set_property()
11    aSet2 = objc.set_property()
12    aROSet = objc.set_property(read_only=True)
13
14class TestSetProperty (TestCase):
15    def testCopying(self):
16        o = TestSetPropertyHelper.alloc().init()
17        aSet = set([1,2])
18        o.aSet = aSet
19
20        self.assertEqual(len(o.aSet), 2)
21        self.assertEqual(len(aSet), 2)
22        aSet.add(3)
23        self.assertEqual(len(o.aSet), 2)
24        self.assertEqual(len(aSet), 3)
25
26    def testRepr(self):
27        o = TestSetPropertyHelper.alloc().init()
28        aSet = set([1,2])
29        o.aSet = aSet
30
31        self.assertEqual(repr(o.aSet), '<set proxy for property aSet %r>'%(aSet,))
32
33    def testDefault(self):
34        with OCObserve.alloc().init() as observer:
35            o = TestSetPropertyHelper.alloc().init()
36
37            observer.register(o, 'aSet')
38
39            o.aSet = set()
40            self.assertEqual(observer.seen, {'aSet': set()})
41
42
43            self.assertEqual(len(o.aSet), 0)
44            o.aSet.add('a')
45            o.aSet.add('b')
46            self.assertEqual(len(o.aSet), 2)
47            self.assertEqual(observer.seen, {'aSet': {'b'}})
48
49            self.assertEqual(observer.values[-2][-1]['kind'], 2)
50            self.assertNotIn('old', observer.values[-2][-1])
51            self.assertEqual(observer.values[-2][-1]['new'], set('a'))
52
53            self.assertEqual(observer.values[-1][-1]['kind'], 2)
54            self.assertNotIn('old', observer.values[-1][-1])
55            self.assertEqual(observer.values[-1][-1]['new'], set('b'))
56
57            v = list(o.aSet)
58            v.sort()
59            self.assertEqual(v, ['a', 'b'])
60
61            self.assertEqual(o.aSet, set(['a', 'b']))
62
63            proxy = o.aSet
64
65
66            o.aSet.clear()
67            self.assertEqual(len(o.aSet), 0)
68            self.assertEqual(len(proxy), 0)
69
70            self.assertEqual(observer.values[-1][-1]['old'], set(['a', 'b']))
71            self.assertNotIn('new', observer.values[-1][-1])
72
73    def testForwarding(self):
74        o = TestSetPropertyHelper.alloc().init()
75        o.aSet = set()
76
77        self.assertTrue(o.aSet.issubset({1,2}))
78
79    def testSetting(self):
80        o = TestSetPropertyHelper.alloc().init()
81        s = {1,2}
82        o.aSet = s
83        self.assertEqual(o.aSet, s)
84        s.add(3)
85        self.assertNotEqual(o.aSet, s)
86        o.aSet2 = o.aSet
87        o.aSet.add(4)
88        self.assertNotEqual(o.aSet, o.aSet2)
89
90        v = o.aSet
91        o._aSet = None
92        self.assertEqual(v, set())
93
94
95
96
97    def testDifferenceUpdate(self):
98        with OCObserve.alloc().init() as observer:
99            o = TestSetPropertyHelper.alloc().init()
100
101            o.aSet.add(1)
102            o.aSet.add(2)
103            o.aSet.add(3)
104
105            observer.register(o, 'aSet')
106
107            o.aSet.difference_update(set([1,4]))
108            self.assertEqual(o.aSet, set([2,3]))
109
110            self.assertEqual(len(observer.values), 1)
111            self.assertEqual(observer.values[-1][-1]['kind'], 3)
112            self.assertNotIn('new', observer.values[-1][-1])
113            self.assertEqual(observer.values[-1][-1]['old'], set([1]))
114
115    def testSymmetricDifferenceUpdate(self):
116        with OCObserve.alloc().init() as observer:
117            o = TestSetPropertyHelper.alloc().init()
118
119            o.aSet = set([1,2,3])
120
121            observer.register(o, 'aSet')
122
123            self.assertEqual(len(observer.values), 0)
124            o.aSet.symmetric_difference_update(set([1,4]))
125            self.assertEqual(o.aSet, set([2, 3, 4]))
126
127            self.assertEqual(len(observer.values), 2)
128
129            haveAdd = False
130            haveRemove = False
131
132            for i in 0, 1:
133                if observer.values[i][-1]['kind'] == 3:
134                    # Remove
135                    self.assertNotIn('new', observer.values[i][-1])
136                    self.assertEqual(observer.values[i][-1]['old'], set([1]))
137                    haveRemove = True
138
139                elif observer.values[i][-1]['kind'] == 2:
140                    # Remove
141                    self.assertNotIn('old', observer.values[i][-1])
142                    self.assertEqual(observer.values[i][-1]['new'], set([4]))
143                    haveAdd = True
144
145                else:
146                    self.fail("Unexpected update kind")
147
148            if not haveAdd and haveRemove:
149                self.fail("Do not have both an add and remove notification")
150
151    def testUpdate(self):
152        with OCObserve.alloc().init() as observer:
153            o = TestSetPropertyHelper.alloc().init()
154            observer.register(o, 'aSet')
155            self.assertEqual(o.aSet, set())
156            self.assertEqual(len(observer.values), 1)
157
158            o.aSet.update([1,2,3])
159            self.assertEqual(len(observer.values), 2)
160            self.assertEqual(observer.values[-1][-1]['kind'], 2)
161            self.assertNotIn('old', observer.values[-1][-1])
162            self.assertEqual(observer.values[-1][-1]['new'], set([1, 2, 3]))
163
164            o.aSet.update(set([3,4,5]))
165            self.assertEqual(len(observer.values), 3)
166            self.assertEqual(observer.values[-1][-1]['kind'], 2)
167            self.assertNotIn('old', observer.values[-1][-1])
168            self.assertEqual(observer.values[-1][-1]['new'], set([4, 5]))
169
170
171
172    def testAddDiscard(self):
173        with OCObserve.alloc().init() as observer:
174            o = TestSetPropertyHelper.alloc().init()
175            observer.register(o, 'aSet')
176
177            o.aSet.add(1)
178            self.assertEqual(observer.seen, {'aSet': {1}})
179            self.assertNotIn('old', observer.values[-1][-1])
180            self.assertEqual(observer.values[-1][-1]['new'], set([1]))
181
182            o.aSet.discard(1)
183            self.assertNotIn('new', observer.values[-1][-1])
184            self.assertEqual(observer.values[-1][-1]['old'], set([1]))
185
186            o.aSet.discard(2)
187            self.assertNotIn('new', observer.values[-1][-1])
188            self.assertEqual(observer.values[-1][-1]['old'], set([]))
189
190
191    def testAddRemove(self):
192        with OCObserve.alloc().init() as observer:
193            o = TestSetPropertyHelper.alloc().init()
194            observer.register(o, 'aSet')
195
196            o.aSet.add(1)
197            self.assertEqual(observer.seen, {'aSet': {1}})
198            self.assertNotIn('old', observer.values[-1][-1])
199            self.assertEqual(observer.values[-1][-1]['new'], set([1]))
200
201            o.aSet.remove(1)
202            self.assertNotIn('new', observer.values[-1][-1])
203            self.assertEqual(observer.values[-1][-1]['old'], set([1]))
204
205            self.assertRaises(KeyError, o.aSet.remove, 2)
206            self.assertNotIn('new', observer.values[-1][-1])
207            self.assertEqual(observer.values[-1][-1]['old'], set([]))
208
209            o.aSet.add(1)
210            o.aSet.add(2)
211            v = o.aSet.pop()
212            self.assertTrue(v in (1, 2))
213            self.assertNotIn('new', observer.values[-1][-1])
214            self.assertEqual(observer.values[-1][-1]['old'], set([v]))
215
216            o.aSet = set()
217            self.assertRaises(KeyError, o.aSet.pop)
218
219    def testOperators(self):
220        with OCObserve.alloc().init() as observer:
221            o = TestSetPropertyHelper.alloc().init()
222            o.aSet = {1,2,3}
223
224            observer.register(o, 'aSet')
225            self.assertEquals(observer.seen, {})
226
227            self.assertEquals(o.aSet - {2}, {1,3})
228            self.assertEquals(o.aSet, {1,2,3})
229
230            self.assertEquals(o.aSet | {4}, {1,2,3,4})
231            self.assertEquals(o.aSet, {1,2,3})
232
233            self.assertEquals(o.aSet & {3,4}, {3})
234            self.assertEquals(o.aSet, {1,2,3})
235
236            self.assertEquals(o.aSet ^ {3,4}, {1,2,4})
237            self.assertEquals(o.aSet, {1,2,3})
238
239    def testInplace(self):
240        # FIXME: the disabled lines in this test indicate a problem in
241        # either the set_proxy implementation, or my understanding of
242        # unordered collection properties.
243        with OCObserve.alloc().init() as observer:
244            o = TestSetPropertyHelper.alloc().init()
245            o.aSet.add(1)
246            observer.register(o, 'aSet')
247
248
249            # The inplace operators aren't actually implemented, which means
250            # "o.aSet |= value" is actually  "o.aSet = o.aSet | value" and
251            # we get the some KVO notificatons as when a new value is set.
252
253            self.assertEqual(o.aSet, {1})
254            o.aSet |= set([2,3])
255            self.assertEqual(o.aSet, {1,2,3})
256            self.assertEqual(o.aSet, set([1,2,3]))
257            self.assertEqual(len(observer.values), 2)
258            self.assertEqual(observer.values[-1][-1]['kind'], 1)
259            #self.assertEqual(observer.values[-1][-1]['old'], set([1]))
260            self.assertEqual(observer.values[-1][-1]['new'], set([1,2,3]))
261
262            self.assertEqual(o.aSet, {1,2,3})
263            o.aSet &= set([3, 4])
264            self.assertEqual(o.aSet, {3})
265            self.assertEqual(o.aSet, set([3]))
266            self.assertEqual(len(observer.values), 4)
267            self.assertEqual(observer.values[-1][-1]['kind'], 1)
268            #self.assertEqual(observer.values[-1][-1]['old'], set([1,2,3]))
269            #self.assertEqual(observer.values[-1][-1]['new'], set([3]))
270
271            self.assertEqual(o.aSet, {3})
272            o.aSet -= {3}
273            self.assertEqual(o.aSet, set())
274            self.assertEqual(o.aSet, set([]))
275            self.assertEqual(len(observer.values), 6)
276            self.assertEqual(observer.values[-1][-1]['kind'], 1)
277            #self.assertEqual(observer.values[-1][-1]['old'], set([3]))
278            #self.assertEqual(observer.values[-1][-1]['new'], set())
279
280            o.aSet = set([1,2,3])
281            #self.assertEqual(len(observer.values), 8)
282
283            self.assertEqual(o.aSet, {1,2,3})
284            o.aSet ^= set([1, 4])
285            self.assertEqual(o.aSet, {2, 3, 4})
286            #self.assertEqual(len(observer.values), 9)
287            self.assertEqual(observer.values[-1][-1]['kind'], 1)
288            #self.assertEqual(observer.values[-1][-1]['old'], set([1,2,3]))
289            #self.assertEqual(observer.values[-1][-1]['new'], set([2,3,4]))
290
291    def testObjCAccessors(self):
292        # Check that the right ObjC array accessors are defined and work properly
293        self.assertTrue(TestSetPropertyHelper.instancesRespondToSelector_(b"setASet:"))
294        self.assertTrue(TestSetPropertyHelper.instancesRespondToSelector_(b"aSet"))
295        self.assertTrue(TestSetPropertyHelper.instancesRespondToSelector_(b"countOfASet"))
296        self.assertTrue(TestSetPropertyHelper.instancesRespondToSelector_(b"enumeratorOfASet"))
297        self.assertTrue(TestSetPropertyHelper.instancesRespondToSelector_(b"memberOfASet:"))
298        self.assertTrue(TestSetPropertyHelper.instancesRespondToSelector_(b"addASet:"))
299        self.assertTrue(TestSetPropertyHelper.instancesRespondToSelector_(b"addASetObject:"))
300        self.assertTrue(TestSetPropertyHelper.instancesRespondToSelector_(b"removeASet:"))
301        self.assertTrue(TestSetPropertyHelper.instancesRespondToSelector_(b"removeASetObject:"))
302
303        o = TestSetPropertyHelper.alloc().init()
304        self.assertEqual(0, o.pyobjc_instanceMethods.countOfASet())
305        self.assertRaises(AttributeError, getattr, o, 'countOfASet')
306        o.aSet.add(1)
307        o.aSet.add(2)
308
309        v = list(sorted(o.pyobjc_instanceMethods.enumeratorOfASet()))
310        self.assertEqual(v, [1,2])
311
312        class Testing (object):
313            def __hash__(self):
314                return 42
315
316            def __eq__(self, other):
317                return isinstance(other, Testing)
318
319        p = Testing()
320        o.aSet.add(p)
321
322        v = o.pyobjc_instanceMethods.memberOfASet_(Testing())
323        self.assertIs(p, v)
324        v = o.pyobjc_instanceMethods.memberOfASet_(9)
325        self.assertIs(v, None)
326
327        self.assertNotIn(9, o.aSet)
328        o.pyobjc_instanceMethods.addASet_(9)
329        self.assertIn(9, o.aSet)
330
331        self.assertNotIn(10, o.aSet)
332        o.pyobjc_instanceMethods.addASetObject_(10)
333        self.assertIn(10, o.aSet)
334
335        self.assertIn(9, o.aSet)
336        o.pyobjc_instanceMethods.removeASet_(9)
337        self.assertNotIn(9, o.aSet)
338
339        self.assertIn(10, o.aSet)
340        o.pyobjc_instanceMethods.removeASetObject_(10)
341        self.assertNotIn(10, o.aSet)
342
343    def test_ro_set(self):
344        o = TestSetPropertyHelper.alloc().init()
345        o._aROSet = { 1, 2, 3, 4 }
346
347        self.assertEqual(o.aROSet, { 1, 2, 3, 4 })
348        self.assertIsNot(type(o.aROSet), set)
349
350        self.assertRaises(ValueError, o.aROSet.add, 1)
351        self.assertRaises(ValueError, o.aROSet.clear)
352        self.assertRaises(ValueError, o.aROSet.pop)
353        self.assertRaises(ValueError, o.aROSet.remove, 1)
354        self.assertRaises(ValueError, o.aROSet.difference_update, { 1, 2})
355        self.assertRaises(ValueError, o.aROSet.intersection_update, { 1, 2})
356        self.assertRaises(ValueError, o.aROSet.symmetric_difference_update, { 1, 2})
357        self.assertRaises(ValueError, o.aROSet.update, { 1, 2})
358        self.assertRaises(ValueError, o.aROSet.discard, 4)
359
360        try:
361            o.aROSet |= {1,2}
362        except ValueError:
363            pass
364        else:
365            self.fail()
366
367        try:
368            o.aROSet -= {1,2}
369        except ValueError:
370            pass
371        else:
372            self.fail()
373
374        try:
375            o.aROSet ^= {1,2}
376        except ValueError:
377            pass
378        else:
379            self.fail()
380
381        try:
382            o.aROSet &= {1,2}
383        except ValueError:
384            pass
385        else:
386            self.fail()
387
388    def test_compare(self):
389        o = TestSetPropertyHelper.alloc().init()
390        o.aSet =  {1, 2, 3}
391        o.aSet2 = {1, 2, 3}
392
393        self.assertTrue(o.aSet ==  o.aSet2)
394        self.assertTrue(o.aSet ==  {1, 2, 3})
395        self.assertTrue(o.aSet <=  o.aSet2)
396        self.assertTrue(o.aSet <=  {1, 2, 3})
397        self.assertTrue(o.aSet >=  o.aSet2)
398        self.assertTrue(o.aSet >=  {1, 2, 3})
399        self.assertFalse(o.aSet != o.aSet2)
400        self.assertFalse(o.aSet != {1, 2, 3})
401
402        o.aSet2 = {2, 3}
403        self.assertTrue(o.aSet !=  o.aSet2)
404        self.assertTrue(o.aSet !=  {1, 2})
405        self.assertFalse(o.aSet == o.aSet2)
406        self.assertFalse(o.aSet == {1, 2})
407
408        o.aSet2 = { 1, 2, 3, 4}
409        self.assertTrue(o.aSet < o.aSet2)
410        self.assertTrue(o.aSet < {1, 2, 3, 4})
411        self.assertTrue(o.aSet <= o.aSet2)
412        self.assertTrue(o.aSet <= {1, 2, 3, 4})
413        self.assertFalse(o.aSet > o.aSet2)
414        self.assertFalse(o.aSet > {1, 2, 3, 4})
415        self.assertFalse(o.aSet >= o.aSet2)
416        self.assertFalse(o.aSet >= {1, 2, 3, 4})
417
418        o.aSet2 = { 1 }
419        self.assertTrue(o.aSet > o.aSet2)
420        self.assertTrue(o.aSet > {1})
421        self.assertTrue(o.aSet >= o.aSet2)
422        self.assertTrue(o.aSet >= {1})
423        self.assertFalse(o.aSet < o.aSet2)
424        self.assertFalse(o.aSet < {1})
425        self.assertFalse(o.aSet <= o.aSet2)
426        self.assertFalse(o.aSet <= {1})
427
428        if sys.version_info[0] == 2:
429            o.aSet = {1, 2, 3}
430            o.aSet2 = {1, 2 }
431
432            self.assertRaises(TypeError, cmp, o.aSet, o.aSet2)
433            #self.assertRaises(TypeError, cmp, o.aSet, {1})
434
435            self.assertRaises(TypeError, o.aSet.__cmp__, o.aSet2)
436            self.assertRaises(TypeError, o.aSet.__cmp__, {1})
437
438    def testPickling(self):
439        o = TestSetPropertyHelper.alloc().init()
440        o.aSet = {1, 2, 3}
441
442        self.assertFalse(isinstance(o.aSet, set))
443
444        p = pickle.dumps(o.aSet)
445        v = pickle.loads(p)
446        self.assertEqual(o.aSet, v)
447        self.assertTrue(isinstance(v, set))
448
449
450if __name__ == "__main__":
451    main()
452