Skip to content

Commit f50ae1b

Browse files
committed
[test] OutputSpan tests
1 parent 4ed4f2e commit f50ae1b

File tree

1 file changed

+327
-0
lines changed

1 file changed

+327
-0
lines changed
Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
//===--- OutputSpanTests.swift --------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 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("OutputSpan Tests")
20+
defer { runAllTests() }
21+
22+
@available(SwiftStdlib 6.2, *)
23+
struct Allocation<T>: ~Copyable {
24+
let allocation: UnsafeMutableBufferPointer<T>
25+
var count: Int? = nil
26+
27+
init(of count: Int = 1, _ t: T.Type) {
28+
precondition(count >= 0)
29+
allocation = .allocate(capacity: count)
30+
}
31+
32+
var isEmpty: Bool { (count ?? 0) == 0 }
33+
34+
mutating func initialize<E>(
35+
_ body: (inout OutputSpan<T>) throws(E) -> Void
36+
) throws(E) {
37+
if count != nil { fatalError() }
38+
var outputBuffer = OutputSpan<T>(buffer: allocation, initializedCount: 0)
39+
do {
40+
try body(&outputBuffer)
41+
let initialized = outputBuffer.finalize(for: allocation)
42+
count = initialized
43+
}
44+
catch {
45+
outputBuffer.removeAll()
46+
let initialized = outputBuffer.finalize(for: allocation)
47+
assert(initialized == 0)
48+
throw error
49+
}
50+
}
51+
52+
borrowing func withSpan<E, R: ~Copyable>(
53+
_ body: (borrowing Span<T>) throws(E) -> R
54+
) throws(E) -> R {
55+
try body(Span(_unsafeElements: allocation[0..<count!]))
56+
}
57+
58+
deinit {
59+
if let count {
60+
allocation.prefix(count).deinitialize()
61+
}
62+
allocation.deallocate()
63+
}
64+
}
65+
66+
enum MyTestError: Error { case error }
67+
68+
suite.test("Create OutputSpan")
69+
.require(.stdlib_6_2).code {
70+
guard #available(SwiftStdlib 6.2, *) else { return }
71+
72+
let c = 48
73+
let allocation = UnsafeMutableBufferPointer<UInt8>.allocate(capacity: c)
74+
defer { allocation.deallocate() }
75+
76+
let ob = unsafe OutputSpan(buffer: allocation, initializedCount: 0)
77+
let initialized = ob.finalize(for: allocation)
78+
expectEqual(initialized, 0)
79+
}
80+
81+
suite.test("deinit without relinquishing memory")
82+
.require(.stdlib_6_2).code {
83+
guard #available(SwiftStdlib 6.2, *) else { return }
84+
85+
let c = 48
86+
let allocation = UnsafeMutableBufferPointer<UInt8>.allocate(capacity: c)
87+
defer { allocation.deallocate() }
88+
89+
var ob = unsafe OutputSpan(buffer: allocation, initializedCount: 0)
90+
// OutputSpan(buffer: Slice(base: allocation, bounds: 0..<c))
91+
ob.append(repeating: 65, count: 12)
92+
expectEqual(ob.count, 12)
93+
_ = ob
94+
}
95+
96+
suite.test("append single elements")
97+
.require(.stdlib_6_2).code {
98+
guard #available(SwiftStdlib 6.2, *) else { return }
99+
100+
var a = Allocation(of: 48, Int.self)
101+
let c = 10
102+
a.initialize {
103+
for i in 0...c {
104+
$0.append(i)
105+
}
106+
let oops = $0.removeLast()
107+
expectEqual(oops, c)
108+
}
109+
expectNotNil(a.count)
110+
expectEqual(a.count, c)
111+
a.withSpan {
112+
expectEqual($0.count, c)
113+
for i in $0.indices {
114+
expectEqual($0[i], i)
115+
}
116+
}
117+
}
118+
119+
suite.test("initialize buffer with repeated elements")
120+
.require(.stdlib_6_2).code {
121+
guard #available(SwiftStdlib 6.2, *) else { return }
122+
123+
var a = Allocation(of: 48, Int.self)
124+
let c = 10
125+
a.initialize {
126+
$0.append(repeating: c, count: c)
127+
let oops = $0.removeLast()
128+
expectEqual(oops, c)
129+
expectEqual($0.count, c-1)
130+
}
131+
a.withSpan {
132+
expectEqual($0.count, c-1)
133+
for i in $0.indices {
134+
expectEqual($0[i], c)
135+
}
136+
}
137+
}
138+
139+
suite.test("initialize buffer from Sequence")
140+
.require(.stdlib_6_2).code {
141+
guard #available(SwiftStdlib 6.2, *) else { return }
142+
143+
var a = Allocation(of: 48, Int.self)
144+
a.initialize {
145+
$0.append(contentsOf: 0..<18)
146+
}
147+
a.withSpan {
148+
expectEqual($0.count, 18)
149+
for i in $0.indices {
150+
expectEqual($0[i], i)
151+
}
152+
}
153+
}
154+
155+
suite.test("initialize buffer from noncontiguous Collection")
156+
.require(.stdlib_6_2).code {
157+
guard #available(SwiftStdlib 6.2, *) else { return }
158+
159+
var a = Allocation(of: 48, Int.self)
160+
let c = 24
161+
a.initialize {
162+
$0.append(contentsOf: 0..<c)
163+
164+
let prefix = $0.span
165+
expectEqual(prefix.count, c)
166+
for i in prefix.indices {
167+
expectEqual(prefix[i], i)
168+
}
169+
}
170+
}
171+
172+
suite.test("initialize buffer from contiguous Collection")
173+
.require(.stdlib_6_2).code {
174+
guard #available(SwiftStdlib 6.2, *) else { return }
175+
176+
var a = Allocation(of: 48, Int.self)
177+
let c = 24
178+
a.initialize {
179+
$0.append(contentsOf: Array(0..<c))
180+
181+
let prefix = $0.span
182+
expectEqual(prefix.count, c)
183+
for i in prefix.indices {
184+
expectEqual(prefix[i], i)
185+
}
186+
}
187+
}
188+
189+
suite.test("indices property")
190+
.require(.stdlib_6_2).code {
191+
guard #available(SwiftStdlib 6.2, *) else { return }
192+
193+
let capacity = 4
194+
let b = UnsafeMutableBufferPointer<Int>.allocate(capacity: capacity)
195+
defer { b.deallocate() }
196+
_ = b.initialize(fromContentsOf: 0..<capacity)
197+
defer { b.deinitialize() }
198+
199+
let span = unsafe OutputSpan(buffer: b, initializedCount: capacity)
200+
expectEqual(span.indices.count, capacity)
201+
let equal = span.indices.elementsEqual(0..<capacity)
202+
expectTrue(equal)
203+
}
204+
205+
suite.test("IndexingSubscript")
206+
.require(.stdlib_6_2).code {
207+
guard #available(SwiftStdlib 6.2, *) else { return }
208+
209+
let capacity = 4
210+
let b = UnsafeMutableBufferPointer<Int>.allocate(capacity: capacity)
211+
defer { b.deallocate() }
212+
_ = b.initialize(fromContentsOf: 0..<capacity)
213+
defer { b.deinitialize() }
214+
215+
var span = unsafe OutputSpan(buffer: b, initializedCount: capacity)
216+
expectEqual(span[0], b.first)
217+
218+
span[0] += 1
219+
expectEqual(span[0], b.first)
220+
}
221+
222+
suite.test("initialize from Span")
223+
.require(.stdlib_6_2).code {
224+
guard #available(SwiftStdlib 6.2, *) else { return }
225+
226+
var a = Allocation(of: 48, Int.self)
227+
let c = 24
228+
229+
let array = Array(0..<c)
230+
let span = array.span
231+
a.initialize {
232+
$0.append(copying: span)
233+
}
234+
a.withSpan {
235+
expectEqual($0.count, c)
236+
for i in $0.indices {
237+
expectEqual($0[i], i)
238+
}
239+
}
240+
}
241+
242+
suite.test("initialize buffer from empty contiguous Collection")
243+
.require(.stdlib_6_2).code {
244+
guard #available(SwiftStdlib 6.2, *) else { return }
245+
246+
var a = Allocation(of: 48, Int.self)
247+
a.initialize {
248+
$0.append(contentsOf: [])
249+
}
250+
a.withSpan { span in
251+
expectEqual(span.count, 0)
252+
}
253+
expectTrue(a.isEmpty)
254+
}
255+
256+
suite.test("moveAppend()")
257+
.require(.stdlib_6_2).code {
258+
guard #available(SwiftStdlib 6.2, *) else { return }
259+
260+
class I {
261+
let i: Int
262+
init(_ i: Int) {
263+
self.i = i
264+
}
265+
}
266+
let c = 20
267+
let b = UnsafeMutableBufferPointer<I>.allocate(capacity: c)
268+
for i in 0..<c {
269+
b.initializeElement(at: i, to: I(i))
270+
}
271+
var a = Allocation(of: 48, I.self)
272+
a.initialize {
273+
$0.append(consuming: b)
274+
$0.append(consuming: b[c..<c])
275+
}
276+
expectFalse(a.isEmpty)
277+
a.withSpan {
278+
expectEqual($0.count, c)
279+
}
280+
}
281+
282+
suite.test("deinitialize buffer")
283+
.require(.stdlib_6_2).code {
284+
guard #available(SwiftStdlib 6.2, *) else { return }
285+
286+
var a = Allocation(of: 48, Int.self)
287+
do {
288+
try a.initialize {
289+
$0.append(0)
290+
$0.append(1)
291+
expectTrue($0.count > 0)
292+
throw MyTestError.error
293+
}
294+
}
295+
catch MyTestError.error {
296+
expectEqual(a.isEmpty, true)
297+
}
298+
catch {
299+
expectTrue(false)
300+
}
301+
}
302+
303+
suite.test("mutate with MutableSpan prefix")
304+
.require(.stdlib_6_2).code {
305+
guard #available(SwiftStdlib 6.2, *) else { return }
306+
307+
let b = UnsafeMutableBufferPointer<Int>.allocate(capacity: 10)
308+
defer { b.deallocate() }
309+
310+
var span = unsafe OutputSpan(buffer: b, initializedCount: 0)
311+
expectEqual(span.count, 0)
312+
span.append(contentsOf: 1...9)
313+
expectEqual(span.count, 9)
314+
315+
var mutable = span.mutableSpan
316+
// span.append(20) // exclusivity violation
317+
for i in 0..<mutable.count {
318+
mutable[i] *= 2
319+
}
320+
321+
span.append(20)
322+
323+
let initialized = span.finalize(for: b)
324+
expectEqual(initialized, 10)
325+
expectTrue(b.elementsEqual((0..<10).map({2*(1+$0)})))
326+
b.deinitialize()
327+
}

0 commit comments

Comments
 (0)