1010//
1111//===----------------------------------------------------------------------===//
1212
13- #if canImport(TestSupport)
14- import TestSupport
15- #endif
16-
17- #if canImport(Glibc)
18- @preconcurrency import Glibc
19- #endif
13+ import Testing
2014
2115#if FOUNDATION_FRAMEWORK
2216@testable import Foundation
2317#else
2418@testable import FoundationEssentials
2519#endif // FOUNDATION_FRAMEWORK
2620
27- class DataIOTests : XCTestCase {
21+ private func generateTestData( count: Int = 16_777_216 ) -> Data {
22+ // Set a few bytes so we're sure to not be all zeros
23+ let buf = UnsafeMutableBufferPointer< UInt8> . allocate( capacity: count)
24+ for i in 0 ..< 15 {
25+ for j in 0 ..< 128 {
26+ buf [ j * 1024 + i] = UInt8 . random ( in: 1 ..< 42 )
27+ }
28+ }
29+
30+ return Data ( bytesNoCopy: buf. baseAddress!, count: count, deallocator: . custom( { ptr, _ in
31+ ptr. deallocate ( )
32+ } ) )
33+ }
34+
35+ @Suite ( " Data I/O " )
36+ private final class DataIOTests {
2837
2938 // MARK: - Helpers
3039
31- func testURL( ) -> URL {
32- // Generate a random file name
33- URL ( fileURLWithPath: NSTemporaryDirectory ( ) , isDirectory: true ) . appendingPathComponent ( " testfile- \( UUID ( ) . uuidString) " )
34- }
40+ let url : URL
3541
36- func generateTestData( count: Int = 16_777_216 ) -> Data {
37- let memory = malloc ( count) !
38- let ptr = memory. bindMemory ( to: UInt8 . self, capacity: count)
39-
40- // Set a few bytes so we're sure to not be all zeros
41- let buf = UnsafeMutableBufferPointer ( start: ptr, count: count)
42- for i in 0 ..< 15 {
43- for j in 0 ..< 128 {
44- buf [ j * 1024 + i] = UInt8 . random ( in: 1 ..< 42 )
45- }
46- }
47-
48- return Data ( bytesNoCopy: ptr, count: count, deallocator: . free)
42+ init ( ) {
43+ // Generate a random file name
44+ url = URL . temporaryDirectory. appendingPathComponent ( " testfile- \( UUID ( ) . uuidString) " )
4945 }
5046
51- func writeAndVerifyTestData( to url: URL , writeOptions: Data . WritingOptions = [ ] , readOptions: Data . ReadingOptions = [ ] ) throws {
47+ func writeAndVerifyTestData( to url: URL , writeOptions: Data . WritingOptions = [ ] , readOptions: Data . ReadingOptions = [ ] , sourceLocation : SourceLocation = #_sourceLocation ) throws {
5248 let data = generateTestData ( )
5349 try data. write ( to: url, options: writeOptions)
5450 let readData = try Data ( contentsOf: url, options: readOptions)
55- XCTAssertEqual ( data, readData)
51+ #expect ( data == readData, sourceLocation : sourceLocation )
5652 }
5753
58- func cleanup ( at url : URL ) {
54+ deinit {
5955 do {
6056 try FileManager . default. removeItem ( at: url)
6157 } catch {
6258 // Ignore
6359 }
6460 }
6561
66-
6762 // MARK: - Tests
6863
69- func test_basicReadWrite( ) throws {
70- let url = testURL ( )
64+ @Test func basicReadWrite( ) throws {
7165 try writeAndVerifyTestData ( to: url)
72- cleanup ( at: url)
7366 }
7467
75- func test_slicedReadWrite ( ) throws {
68+ @ Test func slicedReadWrite ( ) throws {
7669 // Be sure to use progress reporting so we get tests of the chunking
77- let url = testURL ( )
7870 let data = generateTestData ( )
7971 let slice = data [ data. startIndex. advanced ( by: 1 * 1024 * 1024 ) ..< data. startIndex. advanced ( by: 8 * 1024 * 1024 ) ]
8072
@@ -87,76 +79,57 @@ class DataIOTests : XCTestCase {
8779 p. resignCurrent ( )
8880#endif
8981 let readData = try Data ( contentsOf: url, options: [ ] )
90- XCTAssertEqual ( readData, slice)
91- cleanup ( at: url)
82+ #expect( readData == slice)
9283 }
9384
85+ #if !os(WASI)
9486 // Atomic writing is a very different code path
95- func test_readWriteAtomic( ) throws {
96- #if os(WASI)
97- try XCTSkip ( " atomic writing is not supported on WASI " )
98- #else
99- let url = testURL ( )
87+ @Test func readWriteAtomic( ) throws {
10088 // Perform an atomic write to a file that does not exist
10189 try writeAndVerifyTestData ( to: url, writeOptions: [ . atomic] )
10290
10391 // Perform an atomic write to a file that already exists
10492 try writeAndVerifyTestData ( to: url, writeOptions: [ . atomic] )
105-
106- cleanup ( at: url)
107- #endif
10893 }
94+ #endif
10995
110- func test_readWriteMapped( ) throws {
111- let url = testURL ( )
96+ @Test func readWriteMapped( ) throws {
11297 try writeAndVerifyTestData ( to: url, readOptions: [ . mappedIfSafe] )
113-
114- cleanup ( at: url)
11598 }
11699
117- func test_writeFailure( ) throws {
118- let url = testURL ( )
119-
100+ @Test func writeFailure( ) throws {
120101 let data = Data ( )
121102 try data. write ( to: url)
122-
123- #if FOUNDATION_FRAMEWORK
124- XCTAssertThrowsError ( try data. write ( to: url, options: [ . withoutOverwriting] ) ) { e in
125- XCTAssertEqual ( ( e as NSError ) . code, NSFileWriteFileExistsError)
103+
104+ #expect {
105+ try data. write ( to: url, options: [ . withoutOverwriting] )
106+ } throws: {
107+ ( $0 as? CocoaError ) ? . code == . fileWriteFileExists
126108 }
127- #else
128- XCTAssertThrowsError ( try data. write ( to: url, options: [ . withoutOverwriting] ) )
129- #endif
130109
131- cleanup ( at: url)
110+ try FileManager . default . removeItem ( at: url)
132111
133112 // Make sure clearing the error condition allows the write to succeed
134113 try data. write ( to: url, options: [ . withoutOverwriting] )
135-
136- cleanup ( at: url)
137114 }
138115
139116#if FOUNDATION_FRAMEWORK
140117 // Progress is currently stubbed out for FoundationPreview
141- func test_writeWithProgress( ) throws {
142- let url = testURL ( )
143-
118+ @Test func writeWithProgress( ) throws {
144119 let p = Progress ( totalUnitCount: 1 )
145120 p. becomeCurrent ( withPendingUnitCount: 1 )
146121 try writeAndVerifyTestData ( to: url)
147122 p. resignCurrent ( )
148123
149- XCTAssertEqual ( p. completedUnitCount, 1 )
150- XCTAssertEqual ( p. fractionCompleted, 1.0 , accuracy: 0.1 )
151- cleanup ( at: url)
124+ #expect( p. completedUnitCount == 1 )
125+ #expect( abs ( p. fractionCompleted - 1.0 ) <= 0.1 )
152126 }
153127#endif
154128
155129#if FOUNDATION_FRAMEWORK
156- func test_writeWithAttributes ( ) throws {
130+ @ Test func writeWithAttributes ( ) throws {
157131 let writeData = generateTestData ( )
158132
159- let url = testURL ( )
160133 // Data doesn't have a direct API to write with attributes, but our I/O code has it. Use it via @testable interface here.
161134
162135 let writeAttrs : [ String : Data ] = [ FileAttributeKey . hfsCreatorCode. rawValue : " abcd " . data ( using: . ascii) !]
@@ -166,146 +139,85 @@ class DataIOTests : XCTestCase {
166139 var readAttrs : [ String : Data ] = [ : ]
167140 let readData = try readDataFromFile ( path: . url( url) , reportProgress: false , options: [ ] , attributesToRead: [ FileAttributeKey . hfsCreatorCode. rawValue] , attributes: & readAttrs)
168141
169- XCTAssertEqual ( writeData, readData)
170- XCTAssertEqual ( writeAttrs, readAttrs)
171-
172- cleanup ( at: url)
142+ #expect( writeData == readData)
143+ #expect( writeAttrs == readAttrs)
173144 }
174145#endif
175146
176- func test_emptyFile ( ) throws {
147+ @ Test func emptyFile ( ) throws {
177148 let data = Data ( )
178- let url = testURL ( )
179149 try data. write ( to: url)
180150 let read = try Data ( contentsOf: url, options: [ ] )
181- XCTAssertEqual ( data, read)
182-
183- cleanup ( at: url)
151+ #expect( data == read)
184152 }
185153
186154#if FOUNDATION_FRAMEWORK
187155 // String(contentsOf:) is not available outside the framework yet
188156 @available ( * , deprecated)
189- func test_emptyFileString ( ) {
157+ @ Test func emptyFileString ( ) throws {
190158 let data = Data ( )
191- let url = testURL ( )
192-
193- do {
194- try data. write ( to: url)
195- let readString = try String ( contentsOf: url)
196- XCTAssertEqual ( readString, " " )
197-
198- let readStringWithEncoding = try String ( contentsOf: url, encoding: String . _Encoding. utf8)
199- XCTAssertEqual ( readStringWithEncoding, " " )
200-
201- cleanup ( at: url)
202- } catch {
203- XCTFail ( " Could not read file: \( error) " )
204- }
205- }
206- #endif
207-
208- func test_largeFile( ) throws {
209- #if !os(watchOS)
210- // More than 2 GB
211- let size = 0x80010000
212- let url = testURL ( )
213-
214- let data = generateTestData ( count: size)
215159
216160 try data. write ( to: url)
217- let read = try ! Data ( contentsOf: url, options: . mappedIfSafe)
218-
219- // No need to compare the contents, but do compare the size
220- XCTAssertEqual ( data. count, read. count)
161+ let readString = try String ( contentsOf: url)
162+ #expect( readString == " " )
221163
222- #if FOUNDATION_FRAMEWORK
223- // Try the NSData path
224- let readNS = try ! NSData ( contentsOf: url, options: . mappedIfSafe) as Data
225- XCTAssertEqual ( data. count, readNS. count)
226- #endif
227-
228- cleanup ( at: url)
229- #endif // !os(watchOS)
164+ let readStringWithEncoding = try String ( contentsOf: url, encoding: . utf8)
165+ #expect( readStringWithEncoding == " " )
230166 }
167+ #endif
231168
232- func test_writeToSpecialFile( ) throws {
233- #if !os(Linux) && !os(Windows)
234- throw XCTSkip ( " This test is only supported on Linux and Windows " )
235- #else
169+ #if os(Linux) || os(Windows)
170+ @Test
171+ #else
172+ @Test ( . disabled( " This test is not applicable on this platform " ) )
173+ #endif
174+ func writeToSpecialFile( ) throws {
236175 #if os(Windows)
237176 let path = URL ( filePath: " CON " , directoryHint: . notDirectory)
238177 #else
239178 let path = URL ( filePath: " /dev/stdout " , directoryHint: . notDirectory)
240179 #endif
241- XCTAssertNoThrow ( try Data ( " Output to STDOUT \n " . utf8) . write ( to: path) )
242- #endif
180+ #expect( throws: Never . self) {
181+ try Data ( " Output to STDOUT \n " . utf8) . write ( to: path)
182+ }
243183 }
244184
245- func test_zeroSizeFile( ) throws {
246- #if !os(Linux) && !os(Android)
247- throw XCTSkip ( " This test is only applicable on Linux " )
248- #else
185+ #if os(Linux) || os(Android)
186+ @Test
187+ #else
188+ @Test ( . disabled( " This test is not applicable on this platform " ) )
189+ #endif
190+ func zeroSizeFile( ) throws {
249191 // Some files in /proc report a file size of 0 bytes via a stat call
250192 // Ensure that these files can still be read despite appearing to be empty
251- let maps = try String ( contentsOfFile: " /proc/self/maps " , encoding: String . _Encoding. utf8)
252- XCTAssertFalse ( maps. isEmpty)
253- #endif
193+ let maps = try String ( contentsOfFile: " /proc/self/maps " , encoding: . utf8)
194+ #expect( !maps. isEmpty)
254195 }
196+ }
255197
256- // MARK: - String Path Tests
257- func testStringDeletingLastPathComponent( ) {
258- XCTAssertEqual ( " /a/b/c " . deletingLastPathComponent ( ) , " /a/b " )
259- XCTAssertEqual ( " " . deletingLastPathComponent ( ) , " " )
260- XCTAssertEqual ( " / " . deletingLastPathComponent ( ) , " / " )
261- XCTAssertEqual ( " q " . deletingLastPathComponent ( ) , " " )
262- XCTAssertEqual ( " /aaa " . deletingLastPathComponent ( ) , " / " )
263- XCTAssertEqual ( " /aaa/ " . deletingLastPathComponent ( ) , " / " )
264- XCTAssertEqual ( " /a/b/c/ " . deletingLastPathComponent ( ) , " /a/b " )
265- XCTAssertEqual ( " hello " . deletingLastPathComponent ( ) , " " )
266- XCTAssertEqual ( " hello/ " . deletingLastPathComponent ( ) , " " )
267- XCTAssertEqual ( " /hello/ " . deletingLastPathComponent ( ) , " / " )
268- XCTAssertEqual ( " hello/// " . deletingLastPathComponent ( ) , " " )
269- XCTAssertEqual ( " a/ " . deletingLastPathComponent ( ) , " " )
270- XCTAssertEqual ( " a/b " . deletingLastPathComponent ( ) , " a " )
271- XCTAssertEqual ( " a/b/ " . deletingLastPathComponent ( ) , " a " )
272- XCTAssertEqual ( " a//b// " . deletingLastPathComponent ( ) , " a " )
273- }
274-
275- func testAppendingPathComponent( ) {
276- let comp = " test "
277- XCTAssertEqual ( " /a/b/c " . appendingPathComponent ( comp) , " /a/b/c/test " )
278- XCTAssertEqual ( " " . appendingPathComponent ( comp) , " test " )
279- XCTAssertEqual ( " / " . appendingPathComponent ( comp) , " /test " )
280- XCTAssertEqual ( " q " . appendingPathComponent ( comp) , " q/test " )
281- XCTAssertEqual ( " /aaa " . appendingPathComponent ( comp) , " /aaa/test " )
282- XCTAssertEqual ( " /a/b/c/ " . appendingPathComponent ( comp) , " /a/b/c/test " )
283- XCTAssertEqual ( " hello " . appendingPathComponent ( comp) , " hello/test " )
284- XCTAssertEqual ( " hello/ " . appendingPathComponent ( comp) , " hello/test " )
198+ extension LargeDataTests {
199+ // This test is placed in the LargeDataTests suite since it allocates an extremely large amount of memory for some devices
200+ #if !os(watchOS)
201+ @Test func readLargeFile( ) throws {
202+ let url = URL . temporaryDirectory. appendingPathComponent ( " testfile- \( UUID ( ) . uuidString) " )
203+ defer { try ? FileManager . default. removeItem ( at: url) }
204+ // More than 2 GB
205+ let size = 0x80010000
285206
286- XCTAssertEqual ( " hello/ " . appendingPathComponent ( " /test " ) , " hello/test " )
287- XCTAssertEqual ( " hello " . appendingPathComponent ( " /test " ) , " hello/test " )
288- XCTAssertEqual ( " hello/// " . appendingPathComponent ( " ///test " ) , " hello/test " )
289- XCTAssertEqual ( " hello " . appendingPathComponent ( " test/ " ) , " hello/test " )
290- XCTAssertEqual ( " hello " . appendingPathComponent ( " test/test2 " ) , " hello/test/test2 " )
291- XCTAssertEqual ( " hello " . appendingPathComponent ( " test/test2/ " ) , " hello/test/test2 " )
292- XCTAssertEqual ( " hello " . appendingPathComponent ( " test///test2/ " ) , " hello/test/test2 " )
293- XCTAssertEqual ( " hello " . appendingPathComponent ( " / " ) , " hello " )
294- XCTAssertEqual ( " // " . appendingPathComponent ( " / " ) , " / " )
295- XCTAssertEqual ( " " . appendingPathComponent ( " " ) , " " )
296- }
297-
298- func testStringLastPathComponent( ) {
299- XCTAssertEqual ( " /a/b/c " . lastPathComponent, " c " )
300- XCTAssertEqual ( " " . lastPathComponent, " " )
301- XCTAssertEqual ( " / " . lastPathComponent, " / " )
302- XCTAssertEqual ( " q " . lastPathComponent, " q " )
303- XCTAssertEqual ( " /aaa " . lastPathComponent, " aaa " )
304- XCTAssertEqual ( " /a/b/c/ " . lastPathComponent, " c " )
305- XCTAssertEqual ( " hello " . lastPathComponent, " hello " )
306- XCTAssertEqual ( " hello/ " . lastPathComponent, " hello " )
307- XCTAssertEqual ( " hello/// " . lastPathComponent, " hello " )
308- XCTAssertEqual ( " //a// " . lastPathComponent, " a " )
207+ let data = generateTestData ( count: size)
208+
209+ try data. write ( to: url)
210+ let read = try Data ( contentsOf: url, options: . mappedIfSafe)
211+
212+ // No need to compare the contents, but do compare the size
213+ #expect( data. count == read. count)
214+
215+ #if FOUNDATION_FRAMEWORK
216+ // Try the NSData path
217+ let readNS = try NSData ( contentsOf: url, options: . mappedIfSafe) as Data
218+ #expect( data. count == readNS. count)
219+ #endif
309220 }
221+ #endif
310222}
311223
0 commit comments