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