1from PyObjCTools.TestSupport import *
2import objc
3
4from Foundation import *
5from PyObjCTest.testhelper import PyObjC_TestClass4
6
7class TestNSCoderUsage(TestCase):
8    if not hasattr(TestCase, 'assertAlmostEquals'):
9        # XXX Move to a PyObjC unittest module?
10        def assertAlmostEquals(self, val1, val2):
11            self.assert_ (abs(val1 - val2) <  0.000001)
12
13    def testUsage(self):
14        class CoderClass1 (NSObject):
15            def encodeWithCoder_(self, coder):
16                # NSObject does not implement NSCoding, no need to
17                # call superclass implementation:
18                #    super(CoderClass1, self).encodeWithCoder_(coder)
19                coder.encodeValueOfObjCType_at_(objc._C_INT, 2)
20                coder.encodeValueOfObjCType_at_(objc._C_DBL, 2.0)
21                coder.encodeArrayOfObjCType_count_at_(objc._C_DBL, 4, (1.0, 2.0, 3.0, 4.0))
22                coder.encodeBytes_length_("hello world!", 5)
23
24            def initWithCoder_(self, coder):
25                # NSObject does not implement NSCoding, no need to
26                # call superclass implementation:
27                #    self = super(CodeClass1, self).initWithCoder_(coder)
28                self = self.init()
29                self.intVal = coder.decodeValueOfObjCType_at_(objc._C_INT)
30                self.dblVal = coder.decodeValueOfObjCType_at_(objc._C_DBL)
31                self.dblArray = coder.decodeArrayOfObjCType_count_at_(objc._C_DBL, 4)
32                self.decodedBytes = coder.decodeBytesWithReturnedLength_()
33                return self
34
35        origObj = CoderClass1.alloc().init()
36        data = NSMutableData.data()
37        archiver = NSArchiver.alloc().initForWritingWithMutableData_(data)
38        archiver.encodeObject_(origObj)
39
40        archiver = NSUnarchiver.alloc().initForReadingWithData_(data)
41        newObj = archiver.decodeObject()
42
43        self.assertEquals(newObj.intVal, 2)
44        self.assertAlmostEquals(newObj.dblVal, 2.0)
45        self.assertEquals(len(newObj.dblArray), 4)
46        self.assertAlmostEquals(newObj.dblArray[0], 1.0)
47        self.assertAlmostEquals(newObj.dblArray[1], 2.0)
48        self.assertAlmostEquals(newObj.dblArray[2], 3.0)
49        self.assertAlmostEquals(newObj.dblArray[3], 4.0)
50        self.assertEquals(newObj.decodedBytes[0], "hello")
51        self.assertEquals(newObj.decodedBytes[1], 5)
52
53
54class MyCoder (NSCoder):
55    def init(self):
56        self = super(MyCoder, self).init()
57        if self is None: return None
58        self.coded = []
59        return self
60
61    def encodeValueOfObjCType_at_(self, tp, value):
62        self.coded.append( ("value", tp, value) )
63
64    def encodeArrayOfObjCType_count_at_(self, tp, cnt, value):
65        self.coded.append( ("array", tp, cnt, value) )
66
67    def encodeBytes_length_(self, bytes, length):
68        self.coded.append( ("bytes", bytes, length) )
69
70    def decodeValueOfObjCType_at_(self, tp):
71        if tp == 'i':
72            return 42
73        elif tp == 'd':
74            return 1.5
75
76    def decodeArrayOfObjCType_count_at_(self, tp, cnt):
77        return range(cnt)
78
79    def decodeBytesWithReturnedLength_(self):
80        return ("ABCDEabcde", 10)
81
82class TestPythonCoder(TestCase):
83    #
84    # This test accesses a NSCoder implemented in Python from Objective-C
85    #
86    # The tests only use those methods that require a custom IMP-stub.
87    #
88    def testEncoding(self):
89        coder = MyCoder.alloc().init()
90        o = PyObjC_TestClass4.alloc().init()
91        o.encodeWithCoder_(coder)
92        self.assertEquals(coder.coded,
93                [
94                    ("value", "d", 1.5),
95                    ("array", "i", 4, (3,4,5,6)),
96                    ("bytes", "hello world", 11),
97                ])
98
99    def testDecoding(self):
100        coder = MyCoder.alloc().init()
101        o = PyObjC_TestClass4
102
103        self.assertEquals(o.fetchInt_(coder), 42)
104        self.assertEquals(o.fetchDouble_(coder), 1.5)
105
106        d = o.fetchData_(coder)
107        self.assertEquals(d.length(), 10)
108        self.assertEquals(str(d.bytes()), "ABCDEabcde")
109
110        d = o.fetchArray_(coder)
111        self.assertEquals(tuple(range(10)), tuple(d))
112
113    def testMethods(self):
114        self.failUnlessResultIsBOOL(NSCoder.allowsKeyedCoding)
115        self.failUnlessArgIsBOOL(NSCoder.encodeBool_forKey_, 0)
116        self.failUnlessResultIsBOOL(NSCoder.containsValueForKey_)
117        self.failUnlessResultIsBOOL(NSCoder.decodeBoolForKey_)
118
119        self.failUnlessResultHasType(NSCoder.decodeBytesForKey_returnedLength_, '^v')
120        self.failUnlessResultSizeInArg(NSCoder.decodeBytesForKey_returnedLength_, 1)
121        self.failUnlessArgIsOut(NSCoder.decodeBytesForKey_returnedLength_, 1)
122
123
124if __name__ == '__main__':
125    main( )
126