1from PyObjCTools.TestSupport import *
2import objc
3import re
4import sys
5import operator
6import os
7
8try:
9    long
10except NameError:
11    long = int
12
13
14from Foundation import *
15
16PLIST=b"""\
17<?xml version="1.0" encoding="UTF-8"?>
18<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
19<plist version="1.0">
20<dict>
21\t<key>bool</key>
22\t<true/>
23\t<key>plain</key>
24\t<integer>1</integer>
25</dict>
26</plist>
27""".decode('latin1')
28
29def stripDocType(val):
30    """
31    Strip non-significant information. This is needed because the proplists
32    on MacOS X 10.1 are slightly different from the ones on MacOS X 10.2 (
33    different DOCTYPE and version).
34    """
35    r =  re.sub(b'<!DOCTYPE [^>]*>'.decode('ascii'), b'<!DOCTYPE>'.decode('ascii'), val)
36    return r.replace(b'version="0.9"'.decode('ascii'), b'version="1.0"'.decode('ascii'))
37
38
39class TestNSNumber( TestCase ):
40    def testSimple(self):
41        self.assertEqual(NSNumber.numberWithFloat_(1.0), 1,0)
42        self.assertEqual(NSNumber.numberWithInt_(1), 1)
43        self.assertEqual(NSNumber.numberWithFloat_(-0.5), -0.5)
44        self.assertEqual(NSNumber.numberWithInt_(-4), -4)
45        self.assertEqual(NSNumber.numberWithInt_(0), 0)
46        self.assertEqual(NSNumber.numberWithFloat_(0.0), 0.0)
47
48    def testReadOnly(self):
49        n = NSNumber.numberWithFloat_(1.2)
50        self.assertRaises(AttributeError, setattr, n, 'foo', 2)
51
52        n = NSNumber.numberWithInt_(1)
53        self.assertRaises(AttributeError, setattr, n, 'foo', 2)
54
55        n = NSNumber.numberWithLongLong_(2**32 + 2)
56        self.assertRaises(AttributeError, setattr, n, 'foo', 2)
57
58    def testUseAsBasicType(self):
59        lstValue = list(range(0, 20, 2))
60        for idx, v in enumerate(lstValue):
61            self.assertEqual(v, lstValue[NSNumber.numberWithInt_(idx)])
62            self.assertEqual(v, lstValue[NSNumber.numberWithLong_(idx)])
63            self.assertEqual(v, lstValue[NSNumber.numberWithLongLong_(idx)])
64
65        self.assertRaises(TypeError, operator.getitem, lstValue,
66                NSNumber.numberWithFloat_(2.0))
67
68    def testUnsignedIssues(self):
69        # NSNumber stores unsigned numbers as signed numbers
70        # This is a bug in Cocoa... (RADAR #4007594), fixed in 10.5
71        if sdkForPython() is not None and sdkForPython() < (10, 5):
72            self.assertEqual(NSNumber.numberWithUnsignedInt_(2**31),
73                -(2**31))
74        else:
75            self.assertEqual(NSNumber.numberWithUnsignedInt_(2**31),
76                (2**31))
77
78    def testMethods(self):
79        v = NSNumber.numberWithUnsignedInt_(2**31)
80
81        self.assertEqual(v.unsignedIntValue(), 2**31)
82        self.assertEqual(v.intValue(), -(2**31))
83
84        v = NSNumber.numberWithInt_(10)
85        self.assertEqual(v.doubleValue(), float(10))
86
87    def testMath(self):
88        Xs = list(range(10, 40, 3))
89        Ys = list(range(-12, 44, 5))
90
91        self.assertTrue(0 not in Ys)
92        self.assertTrue(0 not in Xs)
93
94        for x in Xs:
95            for y in Ys:
96                Nx = NSNumber.numberWithInt_(x)
97                Ny = NSNumber.numberWithInt_(y)
98
99                self.assertEqual(x + y, Nx + Ny)
100                self.assertEqual(x - y, Nx - Ny)
101                self.assertEqual(x * y, Nx * Ny)
102                self.assertEqual(x / y, Nx / Ny)
103                self.assertEqual(x % y, Nx % Ny)
104                self.assertEqual(x ** y, Nx ** Ny)
105
106                Nx = NSNumber.numberWithFloat_(x+0.5)
107                Ny = NSNumber.numberWithFloat_(y+0.5)
108
109                self.assertEqual((x+0.5) + (y+0.5), Nx + Ny)
110                self.assertEqual((x+0.5) - (y+0.5), Nx - Ny)
111                self.assertEqual((x+0.5) * (y+0.5), Nx * Ny)
112                self.assertEqual((x+0.5) / (y+0.5), Nx / Ny)
113                self.assertEqual((x+0.5) % (y+0.5), Nx % Ny)
114                self.assertEqual((x+0.5) ** (y+0.5), Nx ** Ny)
115
116                Nx = NSNumber.numberWithLongLong_(x)
117                Ny = NSNumber.numberWithLongLong_(y)
118
119                self.assertEqual(long(x) + long(y), Nx + Ny)
120                self.assertEqual(long(x) - long(y), Nx - Ny)
121                self.assertEqual(long(x) * long(y), Nx * Ny)
122                self.assertEqual(long(x) / long(y), Nx / Ny)
123                self.assertEqual(long(x) % long(y), Nx % Ny)
124                self.assertEqual(long(x) ** long(y), Nx ** Ny)
125
126
127    def testTyping(self):
128        # Thanks to some tricks and a cooperating Python runtime,
129        # NSNumber "instances" seem to be subclasses of both NSNumber and
130        # the corresponding Python number type.
131        #
132
133        n = NSNumber.numberWithInt_(10)
134        self.assertIsInstance(n, (int, long))
135        self.assertIsInstance(n, NSNumber)
136
137        n = NSNumber.numberWithUnsignedInt_(10)
138        self.assertIsInstance(n, (int, long))
139        self.assertIsInstance(n, NSNumber)
140
141        n = NSNumber.numberWithLong_(10)
142        self.assertIsInstance(n, (int, long))
143        self.assertIsInstance(n, NSNumber)
144
145        n = NSNumber.numberWithUnsignedLong_(10)
146        self.assertIsInstance(n, (int, long))
147        self.assertIsInstance(n, NSNumber)
148
149        n = NSNumber.numberWithLongLong_(2**32 * 1024)
150        self.assertEqual(n, 2**32 * 1024)
151        self.assertIsInstance(n, (int, long))
152        self.assertIsInstance(n, NSNumber)
153
154        n = NSNumber.numberWithUnsignedLongLong_(2**32 + 100)
155        self.assertEqual(n, 2**32 + 100)
156        self.assertIsInstance(n, (int, long))
157        self.assertIsInstance(n, NSNumber)
158
159        n = NSNumber.numberWithFloat_(10)
160        self.assertIsInstance(n, float)
161        self.assertIsInstance(n, NSNumber)
162
163        n = NSNumber.numberWithDouble_(10)
164        self.assertIsInstance(n, float)
165        self.assertIsInstance(n, NSNumber)
166
167
168if objc.platform == 'MACOSX':
169    class TestPropList (TestCase):
170        #Test if numbers are stored properly in property-list. The most
171        #important part of the testcase are boolean values.
172        #
173        # NOTE: GNUstep uses the old NeXT property lists, and these tests
174        # will fail.
175
176        def testPropertyList1(self):
177            d = NSMutableDictionary.dictionary()
178
179            # Python 2.3 only...
180            d[b'plain'.decode('ascii')] = 1
181            d[b'bool'.decode('ascii')] = objc.YES
182
183            self.assertEqual(d.writeToFile_atomically_(
184                b"/tmp/pyobjctest.plist".decode('ascii'), 0), 1)
185
186            fd = open(b'/tmp/pyobjctest.plist'.decode('ascii'), 'rb')
187            data = fd.read().decode('utf8')
188            fd.close()
189
190            self.assertEqual(stripDocType(data), stripDocType(PLIST))
191
192        def testPropertyList2(self):
193            d = NSMutableDictionary.dictionary()
194
195            d[b'plain'.decode('ascii')] = NSNumber.numberWithLong_(1)
196            d[b'bool'.decode('ascii')] = NSNumber.numberWithBool_(1)
197
198            self.assertEqual(d.writeToFile_atomically_(
199                b"/tmp/pyobjctest.plist".decode('ascii'), 0), 1)
200
201            fd = open(b'/tmp/pyobjctest.plist'.decode('ascii'), 'rb')
202            data = fd.read().decode('utf8')
203            fd.close()
204
205            self.assertEqual(stripDocType(data), stripDocType(PLIST))
206
207class TestDecimalNumber (TestCase):
208    def testProxy (self):
209        one = NSDecimalNumber.decimalNumberWithString_(b"1.00".decode('ascii'))
210        self.assertIsInstance(one, NSDecimalNumber)
211
212        two = NSDecimalNumber.decimalNumberWithString_(b"2.00".decode('ascii'))
213        self.assertIsInstance(two, NSDecimalNumber)
214
215        three = NSDecimalNumber.decimalNumberWithString_(b"3.00".decode('ascii'))
216        self.assertIsInstance(three, NSDecimalNumber)
217
218        six = NSDecimalNumber.decimalNumberWithString_(b"6.00".decode('ascii'))
219        self.assertIsInstance(six, NSDecimalNumber)
220
221        one_half = NSDecimalNumber.decimalNumberWithString_(b"0.50".decode('ascii'))
222        self.assertIsInstance(one_half, NSDecimalNumber)
223
224
225        self.assertEqual(one + two, three)
226        self.assertEqual(three - one, two)
227        self.assertEqual(three * two, six)
228        self.assertEqual(one / two, one_half)
229        self.assertEqual(three // two, one)
230
231        if sys.version_info[0] > 2:
232            self.assertEqual(round(three / two), one)
233            self.assertEqual(round(one / two, 1), one_half)
234
235
236
237if __name__ == '__main__':
238    main( )
239