Skip to content

Commit 33bb68c

Browse files
committed
[test] stdlib/StringTraps: Add some coverage for foreign traps in UTF-8/16 views
These trigger Objective-C exceptions in Foundation, but the fact these operations reliably trap when applied to foreign strings is part of the String contract in the stdlib, and we should have regression tests for them.
1 parent 58826ed commit 33bb68c

File tree

1 file changed

+94
-1
lines changed

1 file changed

+94
-1
lines changed

test/stdlib/StringTraps.swift

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
// UNSUPPORTED: OS=wasi
1111

1212
import StdlibUnittest
13+
#if _runtime(_ObjC)
14+
import Foundation // For NSString
15+
#endif
1316

1417
let testSuiteSuffix = _isDebugAssertConfiguration() ? "_debug" : "_release"
1518

@@ -131,7 +134,7 @@ StringTraps.test("UTF16ViewSubscript/endIndex")
131134
{ _isFastAssertConfiguration() },
132135
reason: "this trap is not guaranteed to happen in -Ounchecked"))
133136
.code {
134-
var s = "abc"
137+
let s = "abc"
135138
var i = s.utf16.startIndex
136139
i = s.utf16.index(after: i)
137140
i = s.utf16.index(after: i)
@@ -260,5 +263,95 @@ StringTraps.test("UnicodeScalarView index(after:) trap on i > endIndex")
260263
i = s.unicodeScalars.index(after: i)
261264
}
262265

266+
StringTraps.test("UnicodeScalarView index(before:) trap on i > endIndex")
267+
.skip(
268+
.custom({ _isFastAssertConfiguration() },
269+
reason: "trap is not guaranteed to happen in -Ounchecked"))
270+
.code {
271+
guard #available(SwiftStdlib 5.7, *) else { return }
272+
273+
let long = "abcd"
274+
var i = long.unicodeScalars.endIndex
275+
276+
let s = "abc"
277+
expectCrashLater()
278+
i = s.unicodeScalars.index(before: i)
279+
}
280+
281+
#if _runtime(_ObjC)
282+
StringTraps.test("UTF8View foreign index(after:) trap on i > endIndex")
283+
.skip(
284+
.custom({ _isFastAssertConfiguration() },
285+
reason: "trap is not guaranteed to happen in -Ounchecked"))
286+
.code {
287+
guard #available(SwiftStdlib 5.7, *) else { return }
288+
289+
let long = "🐘 This is a quite large string, with lots of data"
290+
let short = ("🐭 I'm much smaller" as NSString) as String
291+
292+
var i = long.utf8.endIndex
293+
expectCrashLater()
294+
// Note: we expect that `short` will be UTF-16 encoded here -- this trap only
295+
// happens on the foreign path. For native/shared strings, the UTF-8 view's
296+
// `index(after:)` is essentially doing a simple `i + 1`, like Array does.
297+
i = short.utf8.index(after: i)
298+
}
299+
#endif
300+
301+
#if _runtime(_ObjC)
302+
StringTraps.test("UTF8View foreign index(before:) trap on i > endIndex")
303+
.skip(
304+
.custom({ _isFastAssertConfiguration() },
305+
reason: "trap is not guaranteed to happen in -Ounchecked"))
306+
.code {
307+
guard #available(SwiftStdlib 5.7, *) else { return }
308+
309+
let long = "🐘 This is a quite large string, with lots of data"
310+
let short = ("🐭 I'm much smaller" as NSString) as String
311+
312+
var i = long.utf8.endIndex
313+
expectCrashLater()
314+
// Note: we expect that `short` will be UTF-16 encoded here -- this trap only
315+
// happens on the foreign path. For native/shared strings, the UTF-8 view's
316+
// `index(before:)` is essentially doing a simple `i - 1`, like Array does.
317+
// (Following the unconditional i != startIndex check.)
318+
i = short.utf8.index(before: i)
319+
}
320+
#endif
321+
322+
#if _runtime(_ObjC)
323+
StringTraps.test("UTF8View foreign index(after:) trap on i == endIndex")
324+
.skip(
325+
.custom({ _isFastAssertConfiguration() },
326+
reason: "trap is not guaranteed to happen in -Ounchecked"))
327+
.code {
328+
guard #available(SwiftStdlib 5.7, *) else { return }
329+
330+
let s = ("🦧 The Librarian" as NSString) as String
331+
332+
var i = s.utf8.endIndex
333+
expectCrashLater()
334+
// Note: we expect that `short` will be UTF-16 encoded here -- this trap only
335+
// happens on the foreign path. For native/shared strings, the UTF-8 view's
336+
// `index(after:)` is essentially doing a simple `i + 1`, like Array does.
337+
i = s.utf8.index(after: i)
338+
}
339+
#endif
340+
341+
#if _runtime(_ObjC)
342+
StringTraps.test("UTF8View foreign index(before:) trap on i == startIndex")
343+
.skip(
344+
.custom({ _isFastAssertConfiguration() },
345+
reason: "trap is not guaranteed to happen in -Ounchecked"))
346+
.code {
347+
guard #available(SwiftStdlib 5.7, *) else { return }
348+
349+
let s = ("🦧 The Librarian" as NSString) as String
350+
var i = s.utf8.startIndex
351+
expectCrashLater()
352+
i = s.utf8.index(before: i)
353+
}
354+
#endif
355+
263356
runAllTests()
264357

0 commit comments

Comments
 (0)