mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
* spelling: abcdefghijklmnopqrstuvwxyz Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: clazz Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: collection Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: compressible Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: constituent Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: contiguous Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: convertibility Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: element Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: enforce Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: exhaustive Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: exhausts Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: existential Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: facilitate Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: ignored Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: incorporated Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: intersection Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: laziness Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: misaligned Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: overhaul Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: preamble Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: precondition Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: replacement Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: trailing Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: unambiguous Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: uncompressible Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: world Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> Co-authored-by: Josh Soref <jsoref@users.noreply.github.com>
445 lines
10 KiB
Swift
445 lines
10 KiB
Swift
// RUN: %target-run-simple-swift
|
|
// REQUIRES: executable_test
|
|
|
|
//
|
|
// Tests for error handling in standard library APIs.
|
|
//
|
|
|
|
import StdlibUnittest
|
|
import StdlibCollectionUnittest
|
|
|
|
|
|
var NoisyCount = 0
|
|
|
|
class Noisy {
|
|
init() { NoisyCount += 1 }
|
|
deinit { NoisyCount -= 1 }
|
|
}
|
|
enum SillyError : Error { case JazzHands }
|
|
|
|
var ErrorHandlingTests = TestSuite("ErrorHandling")
|
|
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/withUnsafeMutableBufferPointer restores array on throw") {
|
|
var x = [1, 2, 3]
|
|
do {
|
|
// Check that the array buffer is restored when an error is thrown
|
|
// inside withUnsafeMutableBufferPointer
|
|
try x.withUnsafeMutableBufferPointer { p in
|
|
p[0] = 4
|
|
p[1] = 5
|
|
p[2] = 6
|
|
|
|
// FIXME: Seems to have recently regressed
|
|
// Buffer should be swapped out of the original array.
|
|
// expectEqual(x, [])
|
|
|
|
throw SillyError.JazzHands
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
|
|
// Mutated buffer should be restored to the array.
|
|
expectEqual(x, [4, 5, 6])
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/withUnsafeBufferPointer extends lifetime") {
|
|
let initialCount = NoisyCount
|
|
do {
|
|
let x = [Noisy(), Noisy(), Noisy()]
|
|
let countBeforeWithUBP = NoisyCount
|
|
do {
|
|
// Don't use x anywhere in this test after this point.
|
|
try x.withUnsafeBufferPointer { p in
|
|
expectEqual(NoisyCount, countBeforeWithUBP)
|
|
throw SillyError.JazzHands
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
}
|
|
expectEqual(NoisyCount, initialCount)
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/Optional.map and .flatMap") {
|
|
let x: Int? = 222
|
|
|
|
do {
|
|
let _: String? = try x.map {(n: Int) -> String in
|
|
throw SillyError.JazzHands
|
|
return "\(n)"
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
|
|
do {
|
|
let _: String? = try x.flatMap {(n: Int) -> String? in
|
|
throw SillyError.JazzHands
|
|
return .some("\(n)")
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/withCString extends lifetime") {
|
|
do {
|
|
let x = "ad astra per aspera"
|
|
do {
|
|
// Don't use x anywhere in this test after this point.
|
|
try x.withCString { p in
|
|
expectEqual(p[0], Int8(("a" as UnicodeScalar).value))
|
|
expectEqual(p[1], Int8(("d" as UnicodeScalar).value))
|
|
throw SillyError.JazzHands
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
}
|
|
// TODO: Some way to check string was deallocated?
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/firstIndex(where:)") {
|
|
do {
|
|
let _: Int? = try [1, 2, 3].firstIndex {
|
|
throw SillyError.JazzHands
|
|
return $0 == $0
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/split") {
|
|
do {
|
|
let _: [Substring] = try "foo".split { _ in
|
|
throw SillyError.JazzHands
|
|
return false
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
|
|
do {
|
|
let _: [ArraySlice<Character>]
|
|
= try AnySequence("foo").split { _ in
|
|
throw SillyError.JazzHands
|
|
return false
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/forEach") {
|
|
var loopCount = 0
|
|
do {
|
|
try [1, 2, 3].forEach {
|
|
loopCount += 1
|
|
if $0 == 2 {
|
|
throw SillyError.JazzHands
|
|
}
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
|
|
expectEqual(loopCount, 2)
|
|
}
|
|
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/Optional flatMap") {
|
|
var loopCount = 0
|
|
do {
|
|
let _: [Int] = try [1, 2, 3].flatMap {
|
|
loopCount += 1
|
|
if $0 == 2 {
|
|
throw SillyError.JazzHands
|
|
}
|
|
return .some($0)
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
|
|
expectEqual(loopCount, 2)
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/Array flatMap") {
|
|
var loopCount = 0
|
|
do {
|
|
let _: [Int] = try [1, 2, 3].flatMap {(x) -> [Int] in
|
|
loopCount += 1
|
|
if x == 2 {
|
|
throw SillyError.JazzHands
|
|
}
|
|
return Array(repeating: x, count: x)
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
|
|
expectEqual(loopCount, 2)
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/min") {
|
|
do {
|
|
let _: Int? = try [1, 2, 3].min { _, _ in
|
|
throw SillyError.JazzHands
|
|
return false
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
|
|
do {
|
|
let _: Int? = try [1, 2, 3].max { _, _ in
|
|
throw SillyError.JazzHands
|
|
return false
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/starts(with:)") {
|
|
do {
|
|
let _: Bool = try [1, 2, 3].starts(with: [1, 2]) { _, _ in
|
|
throw SillyError.JazzHands
|
|
return false
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/elementsEqual") {
|
|
do {
|
|
let _: Bool = try [1, 2, 3].elementsEqual([1, 2, 3]) { _, _ in
|
|
throw SillyError.JazzHands
|
|
return false
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/lexicographicallyPrecedes(_:)") {
|
|
do {
|
|
let _: Bool = try [1, 2, 3].lexicographicallyPrecedes([0, 2, 3]) { _, _ in
|
|
throw SillyError.JazzHands
|
|
return false
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/contains") {
|
|
do {
|
|
let _: Bool = try [1, 2, 3].contains { _ in
|
|
throw SillyError.JazzHands
|
|
return false
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/reduce") {
|
|
var loopCount = 0
|
|
do {
|
|
let _: Int = try [1, 2, 3, 4, 5].reduce(0) {
|
|
(x: Int, y: Int) -> Int
|
|
in
|
|
loopCount += 1
|
|
let total = x + y
|
|
if total > 5 {
|
|
throw SillyError.JazzHands
|
|
}
|
|
return total
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
expectEqual(loopCount, 3)
|
|
}
|
|
|
|
func explosiveBoolean() throws -> Bool {
|
|
throw SillyError.JazzHands
|
|
}
|
|
func explosiveInt() throws -> Int {
|
|
throw SillyError.JazzHands
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/operators") {
|
|
do {
|
|
if try true && explosiveBoolean() {
|
|
expectUnreachable()
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
|
|
do {
|
|
if try false || explosiveBoolean() {
|
|
expectUnreachable()
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
|
|
do {
|
|
if try nil ?? explosiveInt() == 0 {
|
|
expectUnreachable()
|
|
}
|
|
expectUnreachable()
|
|
} catch {}
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/Sequence map") {
|
|
let initialCount = NoisyCount
|
|
for throwAtCount in 0...3 {
|
|
let sequence = MinimalSequence(elements: [1, 2, 3])
|
|
var loopCount = 0
|
|
do {
|
|
let result: [Noisy] = try sequence.map { _ in
|
|
if loopCount == throwAtCount {
|
|
throw SillyError.JazzHands
|
|
}
|
|
loopCount += 1
|
|
return Noisy()
|
|
}
|
|
expectEqual(NoisyCount, initialCount + 3)
|
|
expectEqual(result.count, 3)
|
|
} catch {}
|
|
expectEqual(NoisyCount, initialCount)
|
|
}
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/Sequence filter") {
|
|
let initialCount = NoisyCount
|
|
for condition in [true, false] {
|
|
for throwAtCount in 0...3 {
|
|
let sequence = [Noisy(), Noisy(), Noisy()]
|
|
var loopCount = 0
|
|
do {
|
|
let result: [Noisy] = try sequence.filter { _ in
|
|
if loopCount == throwAtCount {
|
|
throw SillyError.JazzHands
|
|
}
|
|
loopCount += 1
|
|
return condition
|
|
}
|
|
expectEqual(NoisyCount, initialCount + sequence.count)
|
|
expectEqual(result.count, condition ? 3 : 0)
|
|
} catch {}
|
|
}
|
|
expectEqual(NoisyCount, initialCount)
|
|
}
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/Collection map") {
|
|
let initialCount = NoisyCount
|
|
let collection = [1, 2, 3]
|
|
for throwAtCount in 0...3 {
|
|
var loopCount = 0
|
|
do {
|
|
let result: [Noisy] = try collection.map { _ in
|
|
if loopCount == throwAtCount {
|
|
throw SillyError.JazzHands
|
|
}
|
|
loopCount += 1
|
|
return Noisy()
|
|
}
|
|
expectEqual(NoisyCount, initialCount + 3)
|
|
expectEqual(result.count, 3)
|
|
} catch {}
|
|
expectEqual(NoisyCount, initialCount)
|
|
}
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/sort") {
|
|
let collection = Array(1...5)
|
|
forAllPermutations(collection) { sequence in
|
|
for i in 0..<sequence.count {
|
|
var s = sequence
|
|
let throwElement = sequence[i]
|
|
do {
|
|
try s.sort { (a, b) throws -> Bool in
|
|
if b == throwElement {
|
|
throw SillyError.JazzHands
|
|
}
|
|
return a < b
|
|
}
|
|
} catch {}
|
|
//Check no element should lost and added
|
|
expectEqualsUnordered(collection, s)
|
|
}
|
|
}
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/sorted") {
|
|
let collection = Array(1...5)
|
|
forAllPermutations(collection) { sequence in
|
|
for i in 0..<sequence.count {
|
|
let s = sequence
|
|
var thrown = false
|
|
let throwElement = sequence[i]
|
|
var result: [Int] = []
|
|
do {
|
|
result = try s.sorted { (a, b) throws -> Bool in
|
|
if b == throwElement {
|
|
thrown = true
|
|
throw SillyError.JazzHands
|
|
}
|
|
return a < b
|
|
}
|
|
} catch {}
|
|
//Check actual sequence should not mutate
|
|
expectEqualSequence(sequence, s)
|
|
if thrown {
|
|
//Check result should be empty when thrown
|
|
expectEqualSequence([], result)
|
|
} else {
|
|
//Check result should be sorted when not thrown
|
|
expectEqualSequence(collection, result)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/sort") {
|
|
let collection = Array(1...5)
|
|
forAllPermutations(collection) { sequence in
|
|
for i in 0..<sequence.count {
|
|
var s = sequence
|
|
let throwElement = sequence[i]
|
|
do {
|
|
try s.sort { (a, b) throws -> Bool in
|
|
if b == throwElement {
|
|
throw SillyError.JazzHands
|
|
}
|
|
return a < b
|
|
}
|
|
} catch {}
|
|
//Check no element should lost and added
|
|
expectEqualsUnordered(collection, s)
|
|
}
|
|
}
|
|
}
|
|
|
|
ErrorHandlingTests.test("ErrorHandling/sorted") {
|
|
let collection = Array(1...5)
|
|
forAllPermutations(collection) { sequence in
|
|
for i in 0..<sequence.count {
|
|
let s = sequence
|
|
var thrown = false
|
|
let throwElement = sequence[i]
|
|
var result: [Int] = []
|
|
do {
|
|
result = try s.sorted { (a, b) throws -> Bool in
|
|
if b == throwElement {
|
|
thrown = true
|
|
throw SillyError.JazzHands
|
|
}
|
|
return a < b
|
|
}
|
|
} catch {}
|
|
//Check actual sequence should not mutate
|
|
expectEqualSequence(sequence, s)
|
|
if thrown {
|
|
//Check result should be empty when thrown
|
|
expectEqualSequence([], result)
|
|
} else {
|
|
//Check result should be sorted when not thrown
|
|
expectEqualSequence(collection, result)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
runAllTests()
|