10
10
//
11
11
//===----------------------------------------------------------------------===//
12
12
13
- #if canImport(TestSupport)
14
- import TestSupport
15
- #endif
16
-
17
- #if canImport(Glibc)
18
- @preconcurrency import Glibc
19
- #endif
13
+ import Testing
20
14
21
15
#if FOUNDATION_FRAMEWORK
22
16
@testable import Foundation
23
17
#else
24
18
@testable import FoundationEssentials
25
19
#endif // FOUNDATION_FRAMEWORK
26
20
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 {
28
37
29
38
// MARK: - Helpers
30
39
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
35
41
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) " )
49
45
}
50
46
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 {
52
48
let data = generateTestData ( )
53
49
try data. write ( to: url, options: writeOptions)
54
50
let readData = try Data ( contentsOf: url, options: readOptions)
55
- XCTAssertEqual ( data, readData)
51
+ #expect ( data == readData, sourceLocation : sourceLocation )
56
52
}
57
53
58
- func cleanup ( at url : URL ) {
54
+ deinit {
59
55
do {
60
56
try FileManager . default. removeItem ( at: url)
61
57
} catch {
62
58
// Ignore
63
59
}
64
60
}
65
61
66
-
67
62
// MARK: - Tests
68
63
69
- func test_basicReadWrite( ) throws {
70
- let url = testURL ( )
64
+ @Test func basicReadWrite( ) throws {
71
65
try writeAndVerifyTestData ( to: url)
72
- cleanup ( at: url)
73
66
}
74
67
75
- func test_slicedReadWrite ( ) throws {
68
+ @ Test func slicedReadWrite ( ) throws {
76
69
// Be sure to use progress reporting so we get tests of the chunking
77
- let url = testURL ( )
78
70
let data = generateTestData ( )
79
71
let slice = data [ data. startIndex. advanced ( by: 1 * 1024 * 1024 ) ..< data. startIndex. advanced ( by: 8 * 1024 * 1024 ) ]
80
72
@@ -87,76 +79,57 @@ class DataIOTests : XCTestCase {
87
79
p. resignCurrent ( )
88
80
#endif
89
81
let readData = try Data ( contentsOf: url, options: [ ] )
90
- XCTAssertEqual ( readData, slice)
91
- cleanup ( at: url)
82
+ #expect( readData == slice)
92
83
}
93
84
85
+ #if !os(WASI)
94
86
// 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 {
100
88
// Perform an atomic write to a file that does not exist
101
89
try writeAndVerifyTestData ( to: url, writeOptions: [ . atomic] )
102
90
103
91
// Perform an atomic write to a file that already exists
104
92
try writeAndVerifyTestData ( to: url, writeOptions: [ . atomic] )
105
-
106
- cleanup ( at: url)
107
- #endif
108
93
}
94
+ #endif
109
95
110
- func test_readWriteMapped( ) throws {
111
- let url = testURL ( )
96
+ @Test func readWriteMapped( ) throws {
112
97
try writeAndVerifyTestData ( to: url, readOptions: [ . mappedIfSafe] )
113
-
114
- cleanup ( at: url)
115
98
}
116
99
117
- func test_writeFailure( ) throws {
118
- let url = testURL ( )
119
-
100
+ @Test func writeFailure( ) throws {
120
101
let data = Data ( )
121
102
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
126
108
}
127
- #else
128
- XCTAssertThrowsError ( try data. write ( to: url, options: [ . withoutOverwriting] ) )
129
- #endif
130
109
131
- cleanup ( at: url)
110
+ try FileManager . default . removeItem ( at: url)
132
111
133
112
// Make sure clearing the error condition allows the write to succeed
134
113
try data. write ( to: url, options: [ . withoutOverwriting] )
135
-
136
- cleanup ( at: url)
137
114
}
138
115
139
116
#if FOUNDATION_FRAMEWORK
140
117
// Progress is currently stubbed out for FoundationPreview
141
- func test_writeWithProgress( ) throws {
142
- let url = testURL ( )
143
-
118
+ @Test func writeWithProgress( ) throws {
144
119
let p = Progress ( totalUnitCount: 1 )
145
120
p. becomeCurrent ( withPendingUnitCount: 1 )
146
121
try writeAndVerifyTestData ( to: url)
147
122
p. resignCurrent ( )
148
123
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 )
152
126
}
153
127
#endif
154
128
155
129
#if FOUNDATION_FRAMEWORK
156
- func test_writeWithAttributes ( ) throws {
130
+ @ Test func writeWithAttributes ( ) throws {
157
131
let writeData = generateTestData ( )
158
132
159
- let url = testURL ( )
160
133
// Data doesn't have a direct API to write with attributes, but our I/O code has it. Use it via @testable interface here.
161
134
162
135
let writeAttrs : [ String : Data ] = [ FileAttributeKey . hfsCreatorCode. rawValue : " abcd " . data ( using: . ascii) !]
@@ -166,146 +139,85 @@ class DataIOTests : XCTestCase {
166
139
var readAttrs : [ String : Data ] = [ : ]
167
140
let readData = try readDataFromFile ( path: . url( url) , reportProgress: false , options: [ ] , attributesToRead: [ FileAttributeKey . hfsCreatorCode. rawValue] , attributes: & readAttrs)
168
141
169
- XCTAssertEqual ( writeData, readData)
170
- XCTAssertEqual ( writeAttrs, readAttrs)
171
-
172
- cleanup ( at: url)
142
+ #expect( writeData == readData)
143
+ #expect( writeAttrs == readAttrs)
173
144
}
174
145
#endif
175
146
176
- func test_emptyFile ( ) throws {
147
+ @ Test func emptyFile ( ) throws {
177
148
let data = Data ( )
178
- let url = testURL ( )
179
149
try data. write ( to: url)
180
150
let read = try Data ( contentsOf: url, options: [ ] )
181
- XCTAssertEqual ( data, read)
182
-
183
- cleanup ( at: url)
151
+ #expect( data == read)
184
152
}
185
153
186
154
#if FOUNDATION_FRAMEWORK
187
155
// String(contentsOf:) is not available outside the framework yet
188
156
@available ( * , deprecated)
189
- func test_emptyFileString ( ) {
157
+ @ Test func emptyFileString ( ) throws {
190
158
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)
215
159
216
160
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 == " " )
221
163
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 == " " )
230
166
}
167
+ #endif
231
168
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 {
236
175
#if os(Windows)
237
176
let path = URL ( filePath: " CON " , directoryHint: . notDirectory)
238
177
#else
239
178
let path = URL ( filePath: " /dev/stdout " , directoryHint: . notDirectory)
240
179
#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
+ }
243
183
}
244
184
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 {
249
191
// Some files in /proc report a file size of 0 bytes via a stat call
250
192
// 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)
254
195
}
196
+ }
255
197
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
285
206
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
309
220
}
221
+ #endif
310
222
}
311
223
0 commit comments