1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
|
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors
//
@testable @_spi(Experimental) @_spi(ForToolsIntegrationOnly) import Testing
@Suite("TestScoping-conforming Trait Tests")
struct TestScopingTraitTests {
@Test("Execute code before and after a non-parameterized test.")
func executeCodeBeforeAndAfterNonParameterizedTest() async {
await confirmation("Code was run before the test") { before in
await confirmation("Code was run after the test") { after in
await Test(CustomTrait(before: before, after: after)) {
// do nothing
}.run()
}
}
}
@Test("Execute code before and after a parameterized test.")
func executeCodeBeforeAndAfterParameterizedTest() async {
// `expectedCount` is 2 because we run it for each test case
await confirmation("Code was run before the test", expectedCount: 2) { before in
await confirmation("Code was run after the test", expectedCount: 2) { after in
await Test(CustomTrait(before: before, after: after), arguments: ["Hello", "World"]) { _ in
// do nothing
}.run()
}
}
}
@Test("Custom execution trait throws an error")
func customExecutionTraitThrowsAnError() async throws {
var configuration = Configuration()
await confirmation("Error thrown", expectedCount: 1) { errorThrownConfirmation in
configuration.eventHandler = { event, _ in
guard case let .issueRecorded(issue) = event.kind,
case let .errorCaught(error) = issue.kind else {
return
}
#expect(error is CustomThrowingErrorTrait.CustomTraitError)
errorThrownConfirmation()
}
await Test(CustomThrowingErrorTrait()) {
// Make sure this does not get reached
Issue.record("Expected trait to fail the test. Should not have reached test body.")
}.run(configuration: configuration)
}
}
@Test("Teardown occurs after child tests run")
func teardownOccursAtEnd() async throws {
await runTest(for: TestsWithCustomTraitWithStrongOrdering.self, configuration: .init())
}
struct ExecutionControl {
@Test("Trait applied directly to function is executed once")
func traitAppliedToFunction() async {
let counter = Locked(rawValue: 0)
await DefaultExecutionTrait.$counter.withValue(counter) {
await Test(DefaultExecutionTrait()) {}.run()
}
#expect(counter.rawValue == 1)
}
@Test("Non-recursive suite trait with default scope provider implementation")
func nonRecursiveSuiteTrait() async {
let counter = Locked(rawValue: 0)
await DefaultExecutionTrait.$counter.withValue(counter) {
await runTest(for: SuiteWithNonRecursiveDefaultExecutionTrait.self)
}
#expect(counter.rawValue == 1)
}
@Test("Recursive suite trait with default scope provider implementation")
func recursiveSuiteTrait() async {
let counter = Locked(rawValue: 0)
await DefaultExecutionTrait.$counter.withValue(counter) {
await runTest(for: SuiteWithRecursiveDefaultExecutionTrait.self)
}
#expect(counter.rawValue == 1)
}
@Test("Recursive, all-inclusive suite trait")
func recursiveAllInclusiveSuiteTrait() async {
let counter = Locked(rawValue: 0)
await AllInclusiveExecutionTrait.$counter.withValue(counter) {
await runTest(for: SuiteWithAllInclusiveExecutionTrait.self)
}
#expect(counter.rawValue == 3)
}
}
}
// MARK: - Fixtures
private struct CustomTrait: TestTrait, TestScoping {
var before: Confirmation
var after: Confirmation
func provideScope(for test: Test, testCase: Test.Case?, performing function: @Sendable () async throws -> Void) async throws {
before()
defer {
after()
}
try await function()
}
}
private struct CustomThrowingErrorTrait: TestTrait, TestScoping {
fileprivate struct CustomTraitError: Error {}
func provideScope(for test: Test, testCase: Test.Case?, performing function: @Sendable () async throws -> Void) async throws {
throw CustomTraitError()
}
}
struct DoSomethingBeforeAndAfterTrait: SuiteTrait, TestTrait, TestScoping {
static let state = Locked(rawValue: 0)
func provideScope(for test: Test, testCase: Test.Case?, performing function: @Sendable () async throws -> Void) async throws {
#expect(Self.state.increment() == 1)
try await function()
#expect(Self.state.increment() == 3)
}
}
@Suite(.hidden, DoSomethingBeforeAndAfterTrait())
struct TestsWithCustomTraitWithStrongOrdering {
@Test(.hidden) func f() async {
#expect(DoSomethingBeforeAndAfterTrait.state.increment() == 2)
}
}
private struct DefaultExecutionTrait: SuiteTrait, TestTrait, TestScoping {
@TaskLocal static var counter: Locked<Int>?
var isRecursive: Bool = false
func provideScope(for test: Test, testCase: Test.Case?, performing function: @Sendable () async throws -> Void) async throws {
Self.counter!.increment()
try await function()
}
}
@Suite(.hidden, DefaultExecutionTrait())
private struct SuiteWithNonRecursiveDefaultExecutionTrait {
@Test func f() {}
}
@Suite(.hidden, DefaultExecutionTrait(isRecursive: true))
private struct SuiteWithRecursiveDefaultExecutionTrait {
@Test func f() {}
}
private struct AllInclusiveExecutionTrait: SuiteTrait, TestTrait, TestScoping {
@TaskLocal static var counter: Locked<Int>?
var isRecursive: Bool {
true
}
func scopeProvider(for test: Test, testCase: Test.Case?) -> AllInclusiveExecutionTrait? {
// Unconditionally returning self makes this trait "all inclusive".
self
}
func provideScope(for test: Test, testCase: Test.Case?, performing function: @Sendable () async throws -> Void) async throws {
Self.counter!.increment()
try await function()
}
}
@Suite(.hidden, AllInclusiveExecutionTrait())
private struct SuiteWithAllInclusiveExecutionTrait {
@Test func f() {}
}
|