1# Some tests that verify that object identity is correctly retained
2# accross the bridge
3#
4# TODO:
5# - Add unittests here for every class that is treated specially by
6#   the bridge.
7# - Add unittests that test for "real-world" scenarios (writing stuff
8#   to plists, ...)
9# - Implement the required functionality
10from __future__ import unicode_literals
11
12import sys, os
13import objc
14from PyObjCTest.identity import *
15from PyObjCTools.TestSupport import *
16
17if sys.version_info[0] == 3:
18    unicode = str
19
20class TestPythonRoundTrip (TestCase):
21    # TODO: verify
22
23    def testBasicPython(self):
24
25        container = OC_TestIdentity.alloc().init()
26
27        for v in (self, object(), list, sum):
28            container.setStoredObject_(v)
29            self.assertTrue(v is container.storedObject(), repr(v))
30
31
32    def testPythonContainer(self):
33
34        container = OC_TestIdentity.alloc().init()
35
36        for v in ( [1, 2,3], (1,2,3), {1:2, 3:4} ):
37            container.setStoredObject_(v)
38            self.assertTrue(v is container.storedObject(), repr(v))
39
40    def dont_testPythonStrings(self):
41        # XXX: this test would always fail, this is by design.
42
43        container = OC_TestIdentity.alloc().init()
44
45        for v in ( "Hello world", b"Hello world" ):
46            container.setStoredObject_(v)
47            self.assertTrue(v is container.storedObject(), repr(v))
48
49    def dont_testPythonNumber(self):
50        # XXX: this test would always fail, need to move some code to C
51        # to fix (but not now)
52        container = OC_TestIdentity.alloc().init()
53
54        for v in (99999, sys.maxsize * 3, 10.0):
55            container.setStoredObject_(v)
56            self.assertTrue(v is container.storedObject, repr(v))
57
58
59class ObjCRoundTrip (TestCase):
60    # TODO: NSProxy
61
62    def testNSObject(self):
63        container = OC_TestIdentity.alloc().init()
64
65        cls = objc.lookUpClass("NSObject")
66        container.setStoredObjectToResultOf_on_("new", cls)
67
68        v = container.storedObject()
69        self.assertTrue(container.isSameObjectAsStored_(v), repr(v))
70
71        container.setStoredObjectToResultOf_on_("class", cls)
72        v = container.storedObject()
73        self.assertTrue(container.isSameObjectAsStored_(v), repr(v))
74
75    def testNSString(self):
76
77        container = OC_TestIdentity.alloc().init()
78
79        cls = objc.lookUpClass("NSObject")
80        container.setStoredObjectToResultOf_on_("description", cls)
81        v = container.storedObject()
82        self.assertTrue(container.isSameObjectAsStored_(v), repr(v))
83        self.assertTrue(isinstance(v, unicode))
84
85        cls = objc.lookUpClass("NSMutableString")
86        container.setStoredObjectToResultOf_on_("new", cls)
87        v = container.storedObject()
88        self.assertTrue(container.isSameObjectAsStored_(v), repr(v))
89        self.assertTrue(isinstance(v, unicode))
90
91    def testProtocol(self):
92        container = OC_TestIdentity.alloc().init()
93
94        container.setStoredObjectToAProtocol()
95        v = container.storedObject()
96        self.assertTrue(container.isSameObjectAsStored_(v), repr(v))
97        self.assertTrue(isinstance(v, objc.formal_protocol))
98
99    if sys.maxsize < 2 ** 32 and os_release() < (10, 7):
100        def testObject(self):
101            container = OC_TestIdentity.alloc().init()
102            cls = objc.lookUpClass("Object")
103            container.setStoredObjectAnInstanceOfClassic_(cls)
104            v = container.storedObject()
105            self.assertTrue(container.isSameObjectAsStored_(v), repr(v))
106            self.assertTrue(isinstance(v, cls))
107
108    def testNSNumber(self):
109        container = OC_TestIdentity.alloc().init()
110
111        container.setStoredObjectToInteger_(10)
112        v = container.storedObject()
113        self.assertTrue(container.isSameObjectAsStored_(v), repr(v))
114
115        container.setStoredObjectToInteger_(-40)
116        v = container.storedObject()
117        self.assertTrue(container.isSameObjectAsStored_(v), repr(v))
118
119        container.setStoredObjectToUnsignedInteger_(40)
120        v = container.storedObject()
121        self.assertTrue(container.isSameObjectAsStored_(v), repr(v))
122
123        container.setStoredObjectToUnsignedInteger_(2 ** 32 - 4)
124        v = container.storedObject()
125        self.assertTrue(container.isSameObjectAsStored_(v), repr(v))
126
127        if sys.maxsize < 2 ** 32:
128            container.setStoredObjectToLongLong_(sys.maxsize * 2)
129            v = container.storedObject()
130            self.assertTrue(container.isSameObjectAsStored_(v), repr(v))
131
132        container.setStoredObjectToLongLong_(-sys.maxsize)
133        v = container.storedObject()
134        self.assertTrue(container.isSameObjectAsStored_(v), repr(v))
135
136        container.setStoredObjectToUnsignedLongLong_(sys.maxsize * 2)
137        v = container.storedObject()
138        self.assertTrue(container.isSameObjectAsStored_(v), repr(v))
139
140        container.setStoredObjectToFloat_(10.0)
141        v = container.storedObject()
142        self.assertTrue(container.isSameObjectAsStored_(v), repr(v))
143
144        container.setStoredObjectToDouble_(9999.0)
145        v = container.storedObject()
146        self.assertTrue(container.isSameObjectAsStored_(v), repr(v))
147
148    def testNSDecimalNumber(self):
149        container = OC_TestIdentity.alloc().init()
150        cls = objc.lookUpClass("NSDecimalNumber")
151        container.setStoredObjectToResultOf_on_("zero", cls)
152        v = container.storedObject()
153        self.assertTrue(container.isSameObjectAsStored_(v), repr(v))
154
155
156class ObjCtoPython (TestCase):
157    # TODO: NSProxy
158
159    def assertFetchingTwice(self, container, message = None):
160        v1 = container.storedObject()
161        v2 = container.storedObject()
162
163        self.assertTrue(v1 is v2, message)
164
165    def testNSObject(self):
166        container = OC_TestIdentity.alloc().init()
167
168        cls = objc.lookUpClass("NSObject")
169        container.setStoredObjectToResultOf_on_("new", cls)
170
171        self.assertFetchingTwice(container, repr(cls))
172
173        container.setStoredObjectToResultOf_on_("new", cls)
174        v1 = container.storedObject()
175        container.setStoredObjectToResultOf_on_("new", cls)
176        v2 = container.storedObject()
177        self.assertTrue(v1 is not v2, "different objects")
178
179    def dont_testNSString(self):
180        # This would always fail, NSStrings get a new proxy everytime
181        # they cross the bridge, otherwise it would be unnecessarily hard
182        # to get at the current value of NSMutableStrings.
183
184        container = OC_TestIdentity.alloc().init()
185
186        cls = objc.lookUpClass("NSObject")
187        container.setStoredObjectToResultOf_on_("description", cls)
188        self.assertFetchingTwice(container, "string")
189
190        cls = objc.lookUpClass("NSMutableString")
191        container.setStoredObjectToResultOf_on_("new", cls)
192        self.assertFetchingTwice(container, "mutable string")
193
194    def testProtocol(self):
195        container = OC_TestIdentity.alloc().init()
196
197        container.setStoredObjectToAProtocol()
198        v = container.storedObject()
199        self.assertFetchingTwice(container, "protocol")
200
201    if sys.maxsize < 2 ** 32 and os_release() < (10, 7):
202        def testObject(self):
203            container = OC_TestIdentity.alloc().init()
204
205            cls = objc.lookUpClass("Object")
206            container.setStoredObjectAnInstanceOfClassic_(cls)
207            self.assertFetchingTwice(container, "object")
208
209    def dont_testNSNumber(self):
210        # No unique proxies yet, due to the way these proxies are
211        # implemented. This needs to be fixed, but that does not have
212        # a high priority.
213        container = OC_TestIdentity.alloc().init()
214
215        container.setStoredObjectToInteger_(10)
216        self.assertFetchingTwice(container, "int 10")
217
218        container.setStoredObjectToInteger_(-40)
219        self.assertFetchingTwice(container, "int -40")
220
221        container.setStoredObjectToUnsignedInteger_(40)
222        self.assertFetchingTwice(container, "unsigned int 40")
223
224        container.setStoredObjectToUnsignedInteger_(sys.maxsize * 2)
225        self.assertFetchingTwice(container, "unsigned int sys.maxsize*2")
226
227        container.setStoredObjectToLongLong_(sys.maxsize * 2)
228        self.assertFetchingTwice(container, "long long sys.maxsize*2")
229
230        container.setStoredObjectToLongLong_(-sys.maxsize)
231        self.assertFetchingTwice(container, "long long -sys.maxsize")
232
233        container.setStoredObjectToUnsignedLongLong_(sys.maxsize * 2)
234        self.assertFetchingTwice(container, "unsigned long long sys.maxsize*2")
235
236        container.setStoredObjectToFloat_(10.0)
237        self.assertFetchingTwice(container, "float")
238
239        container.setStoredObjectToDouble_(9999.0)
240        self.assertFetchingTwice(container, "double")
241
242    def testNSDecimalNumber(self):
243        container = OC_TestIdentity.alloc().init()
244
245        cls = objc.lookUpClass("NSDecimalNumber")
246        container.setStoredObjectToResultOf_on_("zero", cls)
247        self.assertFetchingTwice(container, "decimal")
248
249class PythonToObjC (TestCase):
250    # TODO: verify
251
252    def testPlainObjects(self):
253        container = OC_TestIdentity.alloc().init()
254
255        for v in (self, object(), list, sum):
256            container.setStoredObject_(v)
257
258            self.assertTrue(container.isSameObjectAsStored_(v), repr(v))
259
260
261    def testContainers(self):
262        container = OC_TestIdentity.alloc().init()
263
264        for v in ([1,2,3], (1,2,3), {1:2, 3:4}):
265            container.setStoredObject_(v)
266
267            self.assertTrue(container.isSameObjectAsStored_(v), repr(v))
268
269    def dont_testStrings(self):
270        # These get converted, not proxied
271        container = OC_TestIdentity.alloc().init()
272
273        for v in (b"hello world", "a unicode string"):
274            container.setStoredObject_(v)
275
276            self.assertTrue(container.isSameObjectAsStored_(v), repr(v))
277
278    def dont_testNumbers(self):
279        # These get converted, not proxied
280        container = OC_TestIdentity.alloc().init()
281
282        for v in (1, 666666, sys.maxsize*3, 1.0,):
283            container.setStoredObject_(v)
284
285            self.assertTrue(container.isSameObjectAsStored_(v), repr(v))
286
287class TestSerializingDataStructures (TestCase):
288    # OC_Python{Array,Dictionary} used to contain specialized
289    # identity-preservation code. It is unclear why this was added, it might
290    # have to do with writing data to plist files.
291    # This TestCase tries to trigger the problem that caused the addition of
292    # said code, although unsuccesfully...
293
294    def tearDown(self):
295        if os.path.exists("/tmp/pyPyObjCTest.identity"):
296            os.unlink("/tmp/pyPyObjCTest.identity")
297
298    def testMakePlist(self):
299        container = OC_TestIdentity.alloc().init()
300
301        value = [ 1, 2, 3, [ "hello", ["world", ("in", 9 ) ], True, {"aap":3}]]
302        value.append(value[3])
303
304        container.setStoredObject_(value)
305        container.writeStoredObjectToFile_("/tmp/pyPyObjCTest.identity")
306
307        value = {
308            "hello": [ 1, 2, 3],
309            "world": {
310                "nl": "wereld",
311                "de": "Welt",
312            }
313        }
314        container.setStoredObject_(value)
315        container.writeStoredObjectToFile_("/tmp/pyPyObjCTest.identity")
316
317
318
319if __name__ == "__main__":
320    main()
321