Skip to content

Commit ff1296c

Browse files
committed
[test] add RawSpan tests
1 parent a9bda07 commit ff1296c

File tree

1 file changed

+331
-0
lines changed

1 file changed

+331
-0
lines changed

test/stdlib/Span/RawSpanTests.swift

Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,331 @@
1+
//===--- RawSpanTests.swift -----------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 - 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
// RUN: %target-run-stdlib-swift
14+
15+
// REQUIRES: executable_test
16+
17+
import StdlibUnittest
18+
19+
var suite = TestSuite("Span Tests")
20+
defer { runAllTests() }
21+
22+
suite.test("Initialize with Span<Int>")
23+
.skip(.custom(
24+
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
25+
reason: "Requires Swift 6.2's standard library"
26+
))
27+
.code {
28+
guard #available(SwiftStdlib 6.2, *) else { return }
29+
30+
let capacity = 4
31+
Array(0..<capacity).withUnsafeBufferPointer {
32+
let intSpan = Span(_unsafeElements: $0)
33+
let span = RawSpan(_elements: intSpan)
34+
expectEqual(span.byteCount, capacity*MemoryLayout<Int>.stride)
35+
expectFalse(span.isEmpty)
36+
}
37+
38+
let a: [Int] = []
39+
a.withUnsafeBufferPointer {
40+
let intSpan = Span(_unsafeElements: $0)
41+
let span = RawSpan(_elements: intSpan)
42+
expectTrue(span.isEmpty)
43+
}
44+
}
45+
46+
suite.test("Initialize with UnsafeRawBufferPointer")
47+
.skip(.custom(
48+
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
49+
reason: "Requires Swift 6.2's standard library"
50+
))
51+
.code {
52+
guard #available(SwiftStdlib 6.2, *) else { return }
53+
54+
let capacity = 4
55+
var a = Array(0..<capacity)
56+
a.withUnsafeBytes {
57+
let span = RawSpan(_unsafeBytes: $0)
58+
expectEqual(span.byteCount, capacity*MemoryLayout<Int>.stride)
59+
}
60+
61+
a.withUnsafeMutableBytes {
62+
let span = RawSpan(_unsafeBytes: $0)
63+
expectEqual(span.byteCount, capacity*MemoryLayout<Int>.stride)
64+
}
65+
}
66+
67+
suite.test("Initialize with UnsafeRawPointer")
68+
.skip(.custom(
69+
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
70+
reason: "Requires Swift 6.2's standard library"
71+
))
72+
.code {
73+
guard #available(SwiftStdlib 6.2, *) else { return }
74+
75+
let capacity = 4
76+
var a = Array(0..<capacity)
77+
a.withUnsafeBytes {
78+
let pointer = $0.baseAddress!
79+
let span = RawSpan(
80+
_unsafeStart: pointer,
81+
byteCount: capacity*MemoryLayout<Int>.stride
82+
)
83+
expectEqual(span.byteCount, $0.count)
84+
}
85+
86+
a.withUnsafeMutableBytes {
87+
let pointer = $0.baseAddress!
88+
let span = RawSpan(
89+
_unsafeStart: pointer,
90+
byteCount: capacity*MemoryLayout<Int>.stride
91+
)
92+
expectEqual(span.byteCount, $0.count)
93+
}
94+
}
95+
96+
suite.test("unsafeLoad(as:)")
97+
.skip(.custom(
98+
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
99+
reason: "Requires Swift 6.2's standard library"
100+
))
101+
.code {
102+
guard #available(SwiftStdlib 6.2, *) else { return }
103+
104+
let capacity = 4
105+
let s = (0..<capacity).map({ "\(#file)+\(#function) #\($0)" })
106+
s.withUnsafeBytes {
107+
let span = RawSpan(_unsafeBytes: $0)
108+
let stride = MemoryLayout<String>.stride
109+
110+
let s0 = span.unsafeLoad(as: String.self)
111+
expectEqual(s0.contains("0"), true)
112+
let s1 = span.unsafeLoad(fromByteOffset: stride, as: String.self)
113+
expectEqual(s1.contains("1"), true)
114+
let s2 = span.unsafeLoad(fromUncheckedByteOffset: 2*stride, as: String.self)
115+
expectEqual(s2.contains("2"), true)
116+
}
117+
}
118+
119+
suite.test("unsafeLoadUnaligned(as:)")
120+
.skip(.custom(
121+
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
122+
reason: "Requires Swift 6.2's standard library"
123+
))
124+
.code {
125+
guard #available(SwiftStdlib 6.2, *) else { return }
126+
127+
let capacity = 64
128+
let a = Array(0..<UInt8(capacity))
129+
a.withUnsafeBytes {
130+
let span = RawSpan(_unsafeBytes: $0)
131+
132+
let suffix = span._extracting(droppingFirst: 2)
133+
let u0 = suffix.unsafeLoadUnaligned(as: UInt64.self)
134+
expectEqual(u0 & 0xff, 2)
135+
expectEqual(u0.byteSwapped & 0xff, 9)
136+
let u1 = span.unsafeLoadUnaligned(fromByteOffset: 6, as: UInt64.self)
137+
expectEqual(u1 & 0xff, 6)
138+
let u3 = span.unsafeLoadUnaligned(fromUncheckedByteOffset: 7, as: UInt32.self)
139+
expectEqual(u3 & 0xff, 7)
140+
}
141+
}
142+
143+
suite.test("_extracting() functions")
144+
.skip(.custom(
145+
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
146+
reason: "Requires Swift 6.2's standard library"
147+
))
148+
.code {
149+
guard #available(SwiftStdlib 6.2, *) else { return }
150+
151+
let capacity = 4
152+
let b = (0..<capacity).map(Int8.init)
153+
b.withUnsafeBytes {
154+
let span = RawSpan(_unsafeBytes: $0)
155+
let sub1 = span._extracting(0..<2)
156+
let sub2 = span._extracting(..<2)
157+
let sub3 = span._extracting(...)
158+
let sub4 = span._extracting(unchecked: 2...)
159+
160+
sub1.withUnsafeBytes { p1 in
161+
sub2.withUnsafeBytes { p2 in
162+
expectTrue(p1.elementsEqual(p2))
163+
}
164+
}
165+
sub3.withUnsafeBytes { p3 in
166+
span.withUnsafeBytes { p0 in
167+
expectTrue(p3.elementsEqual(p0))
168+
}
169+
}
170+
sub4.withUnsafeBytes { p4 in
171+
sub3.withUnsafeBytes { p3 in
172+
expectFalse(p4.elementsEqual(p3))
173+
}
174+
}
175+
}
176+
}
177+
178+
suite.test("_extracting(unchecked:) functions")
179+
.skip(.custom(
180+
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
181+
reason: "Requires Swift 6.2's standard library"
182+
))
183+
.code {
184+
guard #available(SwiftStdlib 6.2, *) else { return }
185+
186+
let capacity = 32
187+
let b = (0..<capacity).map(UInt8.init)
188+
b.withUnsafeBytes {
189+
let span = RawSpan(_unsafeBytes: $0)
190+
let prefix = span._extracting(0..<8)
191+
let beyond = prefix._extracting(unchecked: 16...23)
192+
expectEqual(beyond.byteCount, 8)
193+
expectEqual(beyond.unsafeLoad(as: UInt8.self), 16)
194+
}
195+
}
196+
197+
suite.test("prefix _extracting() functions")
198+
.skip(.custom(
199+
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
200+
reason: "Requires Swift 6.2's standard library"
201+
))
202+
.code {
203+
guard #available(SwiftStdlib 6.2, *) else { return }
204+
205+
let capacity = 4
206+
let a = Array(0..<UInt8(capacity))
207+
a.withUnsafeBytes {
208+
let span = RawSpan(_unsafeBytes: $0)
209+
expectEqual(span.byteCount, capacity)
210+
expectEqual(span._extracting(first: 1).unsafeLoad(as: UInt8.self), 0)
211+
expectEqual(
212+
span._extracting(first: capacity).unsafeLoad(
213+
fromByteOffset: capacity-1, as: UInt8.self
214+
),
215+
UInt8(capacity-1)
216+
)
217+
expectTrue(span._extracting(droppingLast: capacity).isEmpty)
218+
expectEqual(
219+
span._extracting(droppingLast: 1).unsafeLoad(
220+
fromByteOffset: capacity-2, as: UInt8.self
221+
),
222+
UInt8(capacity-2)
223+
)
224+
let emptySpan = span._extracting(first: 0)
225+
let emptierSpan = emptySpan._extracting(0..<0)
226+
expectTrue(emptySpan.isIdentical(to: emptierSpan))
227+
}
228+
229+
do {
230+
let b = UnsafeRawBufferPointer(start: nil, count: 0)
231+
let span = RawSpan(_unsafeBytes: b)
232+
expectEqual(span.byteCount, b.count)
233+
expectEqual(span._extracting(first: 1).byteCount, b.count)
234+
expectEqual(span._extracting(droppingLast: 1).byteCount, b.count)
235+
}
236+
}
237+
238+
suite.test("suffix _extracting() functions")
239+
.skip(.custom(
240+
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
241+
reason: "Requires Swift 6.2's standard library"
242+
))
243+
.code {
244+
guard #available(SwiftStdlib 6.2, *) else { return }
245+
246+
let capacity = 4
247+
let a = Array(0..<UInt8(capacity))
248+
a.withUnsafeBytes {
249+
let span = RawSpan(_unsafeBytes: $0)
250+
expectEqual(span.byteCount, capacity)
251+
expectEqual(span._extracting(last: capacity).unsafeLoad(as: UInt8.self), 0)
252+
expectEqual(span._extracting(last: capacity-1).unsafeLoad(as: UInt8.self), 1)
253+
expectEqual(span._extracting(last: 1).unsafeLoad(as: UInt8.self), UInt8(capacity-1))
254+
expectTrue(span._extracting(droppingFirst: capacity).isEmpty)
255+
expectEqual(span._extracting(droppingFirst: 1).unsafeLoad(as: UInt8.self), 1)
256+
}
257+
258+
do {
259+
let b = UnsafeRawBufferPointer(start: nil, count: 0)
260+
let span = RawSpan(_unsafeBytes: b)
261+
expectEqual(span.byteCount, b.count)
262+
expectEqual(span._extracting(last: 1).byteCount, b.count)
263+
expectEqual(span._extracting(droppingFirst: 1).byteCount, b.count)
264+
}
265+
}
266+
267+
suite.test("withUnsafeBytes()")
268+
.skip(.custom(
269+
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
270+
reason: "Requires Swift 6.2's standard library"
271+
))
272+
.code {
273+
guard #available(SwiftStdlib 6.2, *) else { return }
274+
275+
let capacity = 4
276+
let array = Array(0..<capacity)
277+
array.withUnsafeBufferPointer {
278+
let intSpan = Span(_unsafeElements: $0)
279+
let span = RawSpan(_elements: intSpan)
280+
array.withUnsafeBytes { b1 in
281+
span.withUnsafeBytes { b2 in
282+
expectTrue(b1.elementsEqual(b2))
283+
}
284+
}
285+
286+
let emptyBuffer = UnsafeBufferPointer(rebasing: $0[0..<0])
287+
expectEqual(emptyBuffer.baseAddress, $0.baseAddress)
288+
289+
let emptySpan = RawSpan(_unsafeElements: emptyBuffer)
290+
emptySpan.withUnsafeBytes {
291+
expectNil($0.baseAddress)
292+
}
293+
}
294+
}
295+
296+
suite.test("byteOffsets(of:)")
297+
.skip(.custom(
298+
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
299+
reason: "Requires Swift 6.2's standard library"
300+
))
301+
.code {
302+
guard #available(SwiftStdlib 6.2, *) else { return }
303+
304+
let b = UnsafeMutableRawBufferPointer.allocate(byteCount: 8, alignment: 8)
305+
defer { b.deallocate() }
306+
307+
let span = RawSpan(_unsafeBytes: b)
308+
let subSpan1 = span._extracting(first: 6)
309+
let subSpan2 = span._extracting(last: 6)
310+
let emptySpan = span._extracting(first: 0)
311+
let nilBuffer = UnsafeRawBufferPointer(start: nil, count: 0)
312+
let nilSpan = RawSpan(_unsafeBytes: nilBuffer)
313+
314+
var bounds: Range<Int>?
315+
bounds = span.byteOffsets(of: subSpan1)
316+
expectEqual(bounds, span.byteOffsets.prefix(6))
317+
bounds = span.byteOffsets(of: subSpan2)
318+
expectEqual(bounds, span.byteOffsets.suffix(6))
319+
bounds = subSpan2.byteOffsets(of: subSpan1)
320+
expectNil(bounds)
321+
bounds = subSpan1.byteOffsets(of: subSpan2)
322+
expectNil(bounds)
323+
bounds = subSpan2.byteOffsets(of: span)
324+
expectNil(bounds)
325+
bounds = nilSpan.byteOffsets(of: emptySpan)
326+
expectNil(bounds)
327+
bounds = span.byteOffsets(of: nilSpan)
328+
expectNil(bounds)
329+
bounds = nilSpan.byteOffsets(of: nilSpan)
330+
expectEqual(bounds, 0..<0)
331+
}

0 commit comments

Comments
 (0)