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