Skip to content

Commit d099735

Browse files
authored
Migrate to Swift Testing (#70)
Migrating `swift-service-context` from XCTest to Swift Testing ### Motivation Swift Testing is a modern alternative to XCTest. Swift Server Ecosystem packages should serve as reference implementations for modern Swift features and best practices. ### Modifications - 1-to-1 migration of test suites, tests, and assertions to Swift Testing syntax with XCTest import removed ### Result Successfully executes 10 tests with `swift test --disable-xctest`.
1 parent e75f55b commit d099735

File tree

2 files changed

+82
-39
lines changed

2 files changed

+82
-39
lines changed

CONTRIBUTING.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,38 @@ A good patch is:
5050

5151
### Run CI checks locally
5252

53-
You can run the Github Actions workflows locally using [act](https://github.com/nektos/act). For detailed steps on how to do this please see [https://github.com/swiftlang/github-workflows?tab=readme-ov-file#running-workflows-locally](https://github.com/swiftlang/github-workflows?tab=readme-ov-file#running-workflows-locally).
53+
You can run the Github Actions workflows locally using
54+
[act](https://github.com/nektos/act). To run all the jobs that run on a pull
55+
request, use the following command:
56+
57+
```
58+
% act pull_request
59+
```
60+
61+
To run just a single job, use `workflow_call -j <job>`, and specify the inputs
62+
the job expects. For example, to run just shellcheck:
63+
64+
```
65+
% act workflow_call -j soundness --input shell_check_enabled=true
66+
```
67+
68+
To bind-mount the working directory to the container, rather than a copy, use
69+
`--bind`. For example, to run just the formatting, and have the results
70+
reflected in your working directory:
71+
72+
```
73+
% act --bind workflow_call -j soundness --input format_check_enabled=true
74+
```
75+
76+
If you'd like `act` to always run with certain flags, these can be be placed in
77+
an `.actrc` file either in the current working directory or your home
78+
directory, for example:
79+
80+
```
81+
--container-architecture=linux/amd64
82+
--remote-name upstream
83+
--action-offline-mode
84+
```
5485

5586
## How to contribute your work
5687

Tests/ServiceContextTests/ServiceContextTests.swift

Lines changed: 50 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,37 @@
1212
//
1313
//===----------------------------------------------------------------------===//
1414

15-
import XCTest
15+
import Testing
1616

1717
@testable import ServiceContextModule
1818

19-
final class ServiceContextTests: XCTestCase {
20-
func test_topLevelServiceContextIsEmpty() {
19+
@Suite("ServiceContext Tests")
20+
struct ServiceContextTests {
21+
@Test("Top-level ServiceContext is empty")
22+
func topLevelServiceContextIsEmpty() {
2123
let context = ServiceContext.topLevel
2224

23-
XCTAssertTrue(context.isEmpty)
24-
XCTAssertEqual(context.count, 0)
25+
#expect(context.isEmpty)
26+
#expect(context.count == 0)
2527
}
2628

27-
func test_readAndWriteThroughSubscript() throws {
29+
@Test("Read and write values through subscript")
30+
func readAndWriteThroughSubscript() throws {
2831
var context = ServiceContext.topLevel
29-
XCTAssertNil(context[FirstTestKey.self])
30-
XCTAssertNil(context[SecondTestKey.self])
32+
#expect(context[FirstTestKey.self] == nil)
33+
#expect(context[SecondTestKey.self] == nil)
3134

3235
context[FirstTestKey.self] = 42
3336
context[SecondTestKey.self] = 42.0
3437

35-
XCTAssertFalse(context.isEmpty)
36-
XCTAssertEqual(context.count, 2)
37-
XCTAssertEqual(context[FirstTestKey.self], 42)
38-
XCTAssertEqual(context[SecondTestKey.self], 42.0)
38+
#expect(!context.isEmpty)
39+
#expect(context.count == 2)
40+
#expect(context[FirstTestKey.self] == 42)
41+
#expect(context[SecondTestKey.self] == 42.0)
3942
}
4043

41-
func test_forEachIteratesOverAllServiceContextItems() {
44+
@Test("Context forEach iterates over all context items")
45+
func forEachIteratesOverAllServiceContextItems() {
4246
var context = ServiceContext.topLevel
4347

4448
context[FirstTestKey.self] = 42
@@ -50,51 +54,59 @@ final class ServiceContextTests: XCTestCase {
5054
context.forEach { key, value in
5155
contextItems[key] = value
5256
}
53-
XCTAssertEqual(contextItems.count, 3)
54-
XCTAssertTrue(contextItems.contains(where: { $0.key.name == "FirstTestKey" }))
55-
XCTAssertTrue(contextItems.contains(where: { $0.value as? Int == 42 }))
56-
XCTAssertTrue(contextItems.contains(where: { $0.key.name == "SecondTestKey" }))
57-
XCTAssertTrue(contextItems.contains(where: { $0.value as? Double == 42.0 }))
58-
XCTAssertTrue(contextItems.contains(where: { $0.key.name == "explicit" }))
59-
XCTAssertTrue(contextItems.contains(where: { $0.value as? String == "test" }))
57+
#expect(contextItems.count == 3)
58+
#expect(contextItems.contains(where: { $0.key.name == "FirstTestKey" }))
59+
#expect(contextItems.contains(where: { $0.value as? Int == 42 }))
60+
#expect(contextItems.contains(where: { $0.key.name == "SecondTestKey" }))
61+
#expect(contextItems.contains(where: { $0.value as? Double == 42.0 }))
62+
#expect(contextItems.contains(where: { $0.key.name == "explicit" }))
63+
#expect(contextItems.contains(where: { $0.value as? String == "test" }))
6064
}
6165

62-
func test_TODO_doesNotCrashWithoutExplicitCompilerFlag() {
66+
@Test("TODO Context does not crash without explicit compiler flag")
67+
func TODO_doesNotCrashWithoutExplicitCompilerFlag() {
6368
_ = ServiceContext.TODO(#function)
6469
}
6570

66-
func test_serviceContextKeyName_withoutOverride() {
71+
@Test("ServiceContextKey name defaults to type name without override")
72+
func serviceContextKeyName_withoutOverride() {
6773
let name = FirstTestKey.name
68-
XCTAssertEqual(name, "FirstTestKey")
74+
#expect(name == "FirstTestKey")
6975
}
7076

71-
func test_serviceContextKeyName_withOverride() {
77+
@Test("ServiceContextKey name uses explicit override when provided")
78+
func serviceContextKeyName_withOverride() {
7279
let name = ThirdTestKey.name
73-
XCTAssertEqual(name, "explicit")
80+
#expect(name == "explicit")
7481
}
7582

76-
func test_anyServiceContextKeyName_withoutOverride() {
83+
@Test("AnyServiceContextKey name defaults to type name without override")
84+
func anyServiceContextKeyName_withoutOverride() {
7785
let anyKey = AnyServiceContextKey(FirstTestKey.self)
78-
XCTAssertEqual(anyKey.name, "FirstTestKey")
86+
#expect(anyKey.name == "FirstTestKey")
7987
}
8088

81-
func test_anyServiceContextKeyName_withOverride() {
89+
@Test("AnyServiceContextKey name uses explicit override when provided")
90+
func anyServiceContextKeyName_withOverride() {
8291
let anyKey = AnyServiceContextKey(ThirdTestKey.self)
83-
XCTAssertEqual(anyKey.name, "explicit")
92+
#expect(anyKey.name == "explicit")
8493
}
8594

86-
func test_serviceContextKeyName_matchesAnyServiceContextKeyName() {
87-
XCTAssertEqual(FirstTestKey.name, AnyServiceContextKey(FirstTestKey.self).name)
88-
XCTAssertEqual(SecondTestKey.name, AnyServiceContextKey(SecondTestKey.self).name)
89-
XCTAssertEqual(ThirdTestKey.name, AnyServiceContextKey(ThirdTestKey.self).name)
95+
@Test("ServiceContextKey name matches AnyServiceContextKey name")
96+
func serviceContextKeyName_matchesAnyServiceContextKeyName() {
97+
#expect(FirstTestKey.name == AnyServiceContextKey(FirstTestKey.self).name)
98+
#expect(SecondTestKey.name == AnyServiceContextKey(SecondTestKey.self).name)
99+
#expect(ThirdTestKey.name == AnyServiceContextKey(ThirdTestKey.self).name)
90100
}
91101

92-
func test_automaticPropagationThroughTaskLocal() throws {
102+
@Test("Automatic propagation through task-local storage")
103+
func automaticPropagationThroughTaskLocal() throws {
93104
guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else {
94-
throw XCTSkip("Task locals are not supported on this platform.")
105+
#expect(Bool(true), "Task locals are not supported on this platform.")
106+
return
95107
}
96108

97-
XCTAssertNil(ServiceContext.current)
109+
#expect(ServiceContext.current == nil)
98110

99111
var context = ServiceContext.topLevel
100112
context[FirstTestKey.self] = 42
@@ -107,8 +119,8 @@ final class ServiceContextTests: XCTestCase {
107119
let c = ServiceContext.$current
108120
c.withValue(context, operation: exampleFunction)
109121

110-
XCTAssertEqual(propagatedServiceContext?.count, 1)
111-
XCTAssertEqual(propagatedServiceContext?[FirstTestKey.self], 42)
122+
#expect(propagatedServiceContext?.count == 1)
123+
#expect(propagatedServiceContext?[FirstTestKey.self] == 42)
112124
}
113125

114126
actor SomeActor {

0 commit comments

Comments
 (0)