1from PyObjCTools.TestSupport import *
2import objc
3import array
4import sys
5
6from Foundation import *
7from PyObjCTest.testhelper import PyObjC_TestClass3
8
9
10if sys.version_info[0] == 3:
11    buffer = memoryview
12    def array_frombytes(a, b):
13        return a.frombytes(b)
14
15    def array_tobytes(a):
16        return a.tobytes()
17
18else:
19    def array_frombytes(a, b):
20        return a.fromstring(b)
21
22    def array_tobytes(a):
23        return a.tostring()
24
25try:
26    memoryview
27except NameError:
28    memoryview = None
29
30
31rawBytes = b"a\x13b\x00cd\xFFef\xEFgh"
32otherBytes = array.array('B')
33array_frombytes(otherBytes, b'12345678901234567890' * 5)
34
35class TestNSData(TestCase):
36    def testMethods(self):
37        self.assertResultIsBOOL(NSData.isEqualToData_)
38        self.assertResultIsBOOL(NSData.writeToFile_atomically_)
39        self.assertArgIsBOOL(NSData.writeToFile_atomically_, 1)
40        self.assertResultIsBOOL(NSData.writeToURL_atomically_)
41        self.assertArgIsBOOL(NSData.writeToURL_atomically_, 1)
42        self.assertResultIsBOOL(NSData.writeToFile_options_error_)
43        self.assertArgIsOut(NSData.writeToFile_options_error_, 2)
44        self.assertResultIsBOOL(NSData.writeToURL_options_error_)
45        self.assertArgIsOut(NSData.writeToURL_options_error_, 2)
46        self.assertArgIsOut(NSData.dataWithContentsOfFile_options_error_, 2)
47        self.assertArgIsOut(NSData.dataWithContentsOfURL_options_error_, 2)
48        self.assertArgIsOut(NSData.initWithContentsOfFile_options_error_, 2)
49        self.assertArgIsOut(NSData.initWithContentsOfURL_options_error_, 2)
50
51    def testConstants(self):
52        self.assertEqual(NSMappedRead, 1)
53        self.assertEqual(NSUncachedRead, 2)
54
55        self.assertEqual(NSAtomicWrite, 1)
56
57    @min_os_level('10.6')
58    def testConstants10_6(self):
59        self.assertEqual(NSDataReadingMapped, 1<<0)
60        self.assertEqual(NSDataReadingUncached, 1<<1)
61        self.assertEqual(NSDataWritingAtomic, 1<<0)
62        self.assertEqual(NSDataSearchBackwards, 1<<0)
63        self.assertEqual(NSDataSearchAnchored, 1<<1)
64
65    @min_os_level('10.7')
66    def testConstants10_7(self):
67        self.assertEqual(NSDataReadingMappedAlways, 1<<3)
68
69    @min_os_level('10.8')
70    def testConstants10_8(self):
71        self.assertEqual(NSDataWritingWithoutOverwriting, 1<<1)
72
73    @min_os_level('10.6')
74    def testMethods10_6(self):
75        self.assertResultHasType(NSData.rangeOfData_options_range_, NSRange.__typestr__)
76        self.assertArgHasType(NSData.rangeOfData_options_range_, 2, NSRange.__typestr__)
77
78    def assertDataContents(self, d1, d2, rawData):
79        self.assertEqual(len(d1), d1.length(), "d1: len() and -length didn't match.")
80        self.assertEqual(len(d1), len(rawData), "d1: len(<data>) and len(<input>) didn't match. %d vs %d"%(len(d1), len(rawData)))
81        self.assertEqual(len(d2), d2.length(), "d2: len() and -length didn't match.")
82        self.assertEqual(len(d2), len(rawData), "d2: len(<data>) and len(<input>) didn't match. %d vs %d"%(len(d2), len(rawData)))
83
84    def testDataWithBytes_length_(self):
85        # Test +dataWithBytes:length
86        data = NSData.dataWithBytes_length_(rawBytes, len(rawBytes))
87        mutableData = NSMutableData.dataWithBytes_length_(rawBytes, len(rawBytes))
88        self.assertDataContents(data, mutableData, rawBytes)
89
90    def testAppendBytes_length_(self):
91        self.assertArgIsIn(NSMutableData.appendBytes_length_, 0)
92        self.assertArgSizeInArg(NSMutableData.appendBytes_length_, 0, 1)
93
94    def testreplaceBytesInRange_withBytes_(self):
95        self.assertArgIsIn(NSMutableData.replaceBytesInRange_withBytes_, 1)
96        self.assertArgSizeInArg(NSMutableData.replaceBytesInRange_withBytes_, 1, 0)
97
98    def testreplaceBytesInRange_withBytes_length_(self):
99        self.assertArgIsIn(NSMutableData.replaceBytesInRange_withBytes_length_, 1)
100        self.assertArgSizeInArg(NSMutableData.replaceBytesInRange_withBytes_length_, 1, 2)
101
102    def testDataWithBytesNoCopy_length_freeWhenDone_(self):
103        data = NSData.dataWithBytesNoCopy_length_freeWhenDone_(rawBytes, len(rawBytes), False)
104        mutableData = NSMutableData.dataWithBytesNoCopy_length_freeWhenDone_(rawBytes, len(rawBytes), False)
105        self.assertDataContents(data, mutableData, rawBytes)
106
107    def testInitWithBytes_length_(self):
108        # Test -initWithBytes:length:
109        data = NSData.alloc().initWithBytes_length_(rawBytes, len(rawBytes))
110        mutableData = NSMutableData.alloc().initWithBytes_length_(rawBytes, len(rawBytes))
111        self.assertDataContents(data, mutableData, rawBytes)
112
113    def testInitWithBytesNoCopy_length_freeWhenDone_(self):
114        # Test -initWithBytesNoCopy:length:
115        data = NSData.alloc().initWithBytesNoCopy_length_freeWhenDone_(rawBytes, len(rawBytes), False)
116        mutableData = NSMutableData.alloc().initWithBytesNoCopy_length_freeWhenDone_(rawBytes, len(rawBytes), False)
117        self.assertDataContents(data, mutableData, rawBytes)
118
119    def testBytes(self):
120        # Test -bytes
121        data = NSData.alloc().initWithBytes_length_(rawBytes, len(rawBytes))
122        bytesValue = data.bytes()
123        self.assertEqual(len(bytesValue), len(rawBytes), "bytes() and rawBytes not equal length.")
124
125        if sys.version_info[:2] <= (2,6):
126            self.assertEqual(buffer(rawBytes), bytesValue)
127
128        else:
129            self.assertEqual(rawBytes, bytesValue)
130
131        try:
132            bytesValue[3] = b'\xAE'
133        except TypeError as r:
134            if str(r).find('buffer is read-only') == 0:
135                pass
136            elif str(r).find('cannot modify read-only memory') == 0:
137                pass
138            else:
139                raise
140
141    def testMutableBytes(self):
142        # Test -mutableBytes
143        mutableData = NSMutableData.dataWithBytes_length_(rawBytes, len(rawBytes))
144        mutableBytes = mutableData.mutableBytes()
145        for i in range(0, len(mutableBytes)):
146            if sys.version_info[:2] >= (3,3):
147                mutableBytes[i] = array_tobytes(otherBytes[i:i+1])[0]
148            else:
149                mutableBytes[i] = array_tobytes(otherBytes[i:i+1])
150        mutableBytes[1:8] = array_tobytes(otherBytes[1:8])
151
152        try:
153            mutableBytes[2:10] = array_tobytes(otherBytes[1:5])
154        except (TypeError, ValueError) as r:
155            if str(r).find('right operand length must match slice length') == 0:
156                pass
157            elif 'cannot modify size of memoryview object' in str(r):
158                pass
159            elif 'ndarray assignment: lvalue and rvalue have different structures' in str(r):
160                pass
161            else:
162                raise
163
164    def testVariousDataLengths(self):
165        # Test data of different lengths.
166        #
167        # Data of different lengths may be stored in different subclasses within the class cluster.
168        testFactor = list(range(1, 64)) + [ 1000, 10000, 1000000]
169        for aFactor in testFactor:
170            bigRawBytes = b"1234567890" * aFactor
171
172            mutableData = NSMutableData.dataWithBytes_length_(bigRawBytes, len(bigRawBytes))
173            data = NSData.dataWithBytes_length_(bigRawBytes, len(bigRawBytes))
174
175            self.assertDataContents(data, mutableData, bigRawBytes)
176
177            mutableBytes = mutableData.mutableBytes()
178            bytes = data.bytes()
179
180            self.assertEqual(len(bytes), data.length())
181            self.assertEqual(len(mutableBytes), mutableData.length())
182            self.assertEqual(bytes, mutableBytes)
183
184            mutableBytes[0:len(mutableBytes)] = bytes[0:len(bytes)]
185
186    def testInitWithContents(self):
187        b, err = NSData.alloc().initWithContentsOfFile_options_error_(
188                "/etc/hosts", 0, None)
189        self.assertIsInstance(b, NSData)
190        self.assertIs(err, None)
191        b2, err = NSData.alloc().initWithContentsOfFile_options_error_(
192                "/etc/hosts.nosuchfile", 0, None)
193        self.assertIs(b2, None)
194        self.assertIsInstance(err, NSError)
195        url = NSURL.fileURLWithPath_isDirectory_('/etc/hosts', False)
196        b, err = NSData.alloc().initWithContentsOfURL_options_error_(
197                url, 0, None)
198        self.assertIsInstance(b, NSData)
199        self.assertIs(err, None)
200        url = NSURL.fileURLWithPath_isDirectory_('/etc/hosts.nosuchfile', False)
201        b2, err = NSData.alloc().initWithContentsOfURL_options_error_(
202                url, 0, None)
203        self.assertIs(b2, None)
204        self.assertIsInstance(err, NSError)
205
206class MyData (NSData):
207    def dataWithBytes_length_(self, bytes, length):
208        return ("data", bytes, length)
209
210BYTES="dummy bytes"
211class MyData2 (NSData):
212    def initWithBytes_length_(self, bytes, length):
213        return ("init", bytes, length)
214
215    def length(self):
216        return 42
217
218    def bytes(self):
219        return BYTES
220
221
222class MyData3 (NSData):
223    def initWithBytes_length_(self, bytes, length):
224        self._bytes = bytes
225        self._length = length
226        return self
227
228    def bytes(self):
229        return self._bytes
230
231    def length(self):
232        if hasattr(self, '_length'):
233            return self._length
234        return -1
235
236class MyData4 (NSData):
237    def initWithBytes_length_(self, bytes, length):
238        return self
239
240    def bytes(self):
241        return None
242
243    def length(self):
244        return -1
245
246class MyData5(NSData):
247    def initWithBytes_length_(self, bytes, length):
248        return self
249
250    def bytes(self):
251        raise ValueError("No bytes available")
252
253    def length(self):
254        return -1
255
256
257
258class TestMyData (TestCase):
259    # 'initWithBytes:length:' and 'dataWithBytes:length:' have custom IMP's
260    def testData(self):
261        r = PyObjC_TestClass3.makeDataWithBytes_method_(MyData, 0)
262        self.assertEqual(r, ('data', b'hello world', 11))
263
264    def testInit(self):
265        r = PyObjC_TestClass3.makeDataWithBytes_method_(MyData2, 1)
266        self.assertEqual(r, ('init', b'hello world', 11))
267
268    def testBytes(self):
269        r = PyObjC_TestClass3.makeDataWithBytes_method_(MyData3, 1)
270        b = PyObjC_TestClass3.getBytes_(r)
271
272        # Check for memoryview
273        if isinstance(b.bytes(), memoryview):
274            self.assertEqual(b.bytes().tobytes(), b'hello world')
275        else:
276            self.assertEqual(bytes(b.bytes()), b'hello world')
277
278        self.assertEqual(b.getBytes_length_(None, 4), b'hell')
279        self.assertEqual(b.getBytes_range_(None, NSRange(2, 4)), b'llo ')
280
281
282    def testBytesNone(self):
283        b = PyObjC_TestClass3.makeDataWithBytes_method_(MyData4, 1)
284        self.assertEqual(b.bytes(), None)
285
286    def testBytesRaises(self):
287        b = PyObjC_TestClass3.makeDataWithBytes_method_(MyData5, 1)
288        self.assertRaises(ValueError, b.bytes)
289
290
291
292import array
293class TestBuffer(TestCase):
294    def testArray(self):
295        a = array.array('b', b'foo')
296        m = NSMutableData.dataWithData_(a)
297        self.assertEqual(array_tobytes(a), m[:])
298        self.assertTrue(objc.repythonify(a) is a)
299        array_frombytes(a, m)
300        self.assertEqual(array_tobytes(a), b'foofoo')
301        m.appendData_(a)
302        self.assertEqual(m[:], b'foofoofoo')
303        m[3:6] = b'bar'
304        self.assertEqual(m[:], b'foobarfoo')
305
306    def testBuffer(self):
307        if sys.version_info[0] == 3:
308            b = b'foo'
309        else:
310            b = buffer('foo')
311        m = NSMutableData.dataWithData_(b)
312        self.assertEqual(b[:], m[:])
313        self.assertTrue(objc.repythonify(b) is b)
314        self.assertEqual(buffer(m)[:], m[:])
315
316
317class TestRegressions (TestCase):
318    def testDataStr(self):
319        if sys.version_info[0] == 2:
320            input = buffer("hello")
321            input_str = "hello"
322        else:
323            input = b"hello"
324            input_str = str(input)
325
326        buf = NSData.dataWithData_(input)
327        self.assertEqual(str(buf), input_str)
328
329
330if __name__ == '__main__':
331    main( )
332