Skip to content

Commit a4268dd

Browse files
Test traits (#157)
* Expose test traits dynamically * wip * test * wip * wip * wip * wip * wip * wip * disable android ci --------- Co-authored-by: Brandon Williams <[email protected]>
1 parent e876472 commit a4268dd

File tree

10 files changed

+139
-30
lines changed

10 files changed

+139
-30
lines changed

.github/workflows/ci.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,10 @@ jobs:
135135
# - name: Run tests (debug only)
136136
# run: swift test
137137

138-
android:
139-
name: Android
140-
runs-on: ubuntu-latest
141-
steps:
142-
- uses: actions/checkout@v4
143-
- name: "Test Swift Package on Android"
144-
uses: skiptools/swift-android-action@v2
138+
# android:
139+
# name: Android
140+
# runs-on: ubuntu-latest
141+
# steps:
142+
# - uses: actions/checkout@v4
143+
# - name: "Test Swift Package on Android"
144+
# uses: skiptools/swift-android-action@v2

Examples/Examples.xcodeproj/project.pbxproj

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
CA1972D72DB1836900351823 /* TraitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA1972D62DB1836900351823 /* TraitTests.swift */; };
11+
CA1972D92DB1847200351823 /* ExampleTrait.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA1972D82DB1847200351823 /* ExampleTrait.swift */; };
1012
CADE79AE2C4A9D2C005A85F7 /* ExamplesApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = CADE79AD2C4A9D2C005A85F7 /* ExamplesApp.swift */; };
1113
CADE79B22C4A9D2D005A85F7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CADE79B12C4A9D2D005A85F7 /* Assets.xcassets */; };
1214
CADE79DA2C4A9D3A005A85F7 /* IssueReporting in Frameworks */ = {isa = PBXBuildFile; productRef = CADE79D92C4A9D3A005A85F7 /* IssueReporting */; };
1315
CADE79DD2C4A9E59005A85F7 /* SwiftTestingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CADE79DB2C4A9E59005A85F7 /* SwiftTestingTests.swift */; };
1416
CADE79DE2C4A9E59005A85F7 /* XCTestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CADE79DC2C4A9E59005A85F7 /* XCTestTests.swift */; };
1517
CADE79E02C4ABD94005A85F7 /* Examples.xctestplan in Resources */ = {isa = PBXBuildFile; fileRef = CADE79DF2C4ABD94005A85F7 /* Examples.xctestplan */; };
16-
CADE79E22C4ABE90005A85F7 /* IssueReporting in Frameworks */ = {isa = PBXBuildFile; productRef = CADE79E12C4ABE90005A85F7 /* IssueReporting */; };
1718
/* End PBXBuildFile section */
1819

1920
/* Begin PBXContainerItemProxy section */
@@ -26,7 +27,32 @@
2627
};
2728
/* End PBXContainerItemProxy section */
2829

30+
/* Begin PBXCopyFilesBuildPhase section */
31+
CA1972DD2DB1854600351823 /* Embed Frameworks */ = {
32+
isa = PBXCopyFilesBuildPhase;
33+
buildActionMask = 2147483647;
34+
dstPath = "";
35+
dstSubfolderSpec = 10;
36+
files = (
37+
);
38+
name = "Embed Frameworks";
39+
runOnlyForDeploymentPostprocessing = 0;
40+
};
41+
CA1972E12DB186BC00351823 /* Embed Frameworks */ = {
42+
isa = PBXCopyFilesBuildPhase;
43+
buildActionMask = 2147483647;
44+
dstPath = "";
45+
dstSubfolderSpec = 10;
46+
files = (
47+
);
48+
name = "Embed Frameworks";
49+
runOnlyForDeploymentPostprocessing = 0;
50+
};
51+
/* End PBXCopyFilesBuildPhase section */
52+
2953
/* Begin PBXFileReference section */
54+
CA1972D62DB1836900351823 /* TraitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TraitTests.swift; sourceTree = "<group>"; };
55+
CA1972D82DB1847200351823 /* ExampleTrait.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleTrait.swift; sourceTree = "<group>"; };
3056
CADE79AA2C4A9D2C005A85F7 /* Examples.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Examples.app; sourceTree = BUILT_PRODUCTS_DIR; };
3157
CADE79AD2C4A9D2C005A85F7 /* ExamplesApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExamplesApp.swift; sourceTree = "<group>"; };
3258
CADE79B12C4A9D2D005A85F7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@@ -50,7 +76,6 @@
5076
isa = PBXFrameworksBuildPhase;
5177
buildActionMask = 2147483647;
5278
files = (
53-
CADE79E22C4ABE90005A85F7 /* IssueReporting in Frameworks */,
5479
);
5580
runOnlyForDeploymentPostprocessing = 0;
5681
};
@@ -80,6 +105,7 @@
80105
isa = PBXGroup;
81106
children = (
82107
CADE79AD2C4A9D2C005A85F7 /* ExamplesApp.swift */,
108+
CA1972D82DB1847200351823 /* ExampleTrait.swift */,
83109
CADE79B12C4A9D2D005A85F7 /* Assets.xcassets */,
84110
CADE79B32C4A9D2D005A85F7 /* Examples.entitlements */,
85111
);
@@ -92,6 +118,7 @@
92118
CADE79DF2C4ABD94005A85F7 /* Examples.xctestplan */,
93119
CADE79DB2C4A9E59005A85F7 /* SwiftTestingTests.swift */,
94120
CADE79DC2C4A9E59005A85F7 /* XCTestTests.swift */,
121+
CA1972D62DB1836900351823 /* TraitTests.swift */,
95122
);
96123
path = ExamplesTests;
97124
sourceTree = "<group>";
@@ -113,6 +140,7 @@
113140
CADE79A62C4A9D2C005A85F7 /* Sources */,
114141
CADE79A72C4A9D2C005A85F7 /* Frameworks */,
115142
CADE79A82C4A9D2C005A85F7 /* Resources */,
143+
CA1972E12DB186BC00351823 /* Embed Frameworks */,
116144
);
117145
buildRules = (
118146
);
@@ -133,6 +161,7 @@
133161
CADE79B72C4A9D2D005A85F7 /* Sources */,
134162
CADE79B82C4A9D2D005A85F7 /* Frameworks */,
135163
CADE79B92C4A9D2D005A85F7 /* Resources */,
164+
CA1972DD2DB1854600351823 /* Embed Frameworks */,
136165
);
137166
buildRules = (
138167
);
@@ -141,7 +170,6 @@
141170
);
142171
name = ExamplesTests;
143172
packageProductDependencies = (
144-
CADE79E12C4ABE90005A85F7 /* IssueReporting */,
145173
);
146174
productName = ExamplesTests;
147175
productReference = CADE79BB2C4A9D2D005A85F7 /* ExamplesTests.xctest */;
@@ -210,6 +238,7 @@
210238
buildActionMask = 2147483647;
211239
files = (
212240
CADE79AE2C4A9D2C005A85F7 /* ExamplesApp.swift in Sources */,
241+
CA1972D92DB1847200351823 /* ExampleTrait.swift in Sources */,
213242
);
214243
runOnlyForDeploymentPostprocessing = 0;
215244
};
@@ -219,6 +248,7 @@
219248
files = (
220249
CADE79DD2C4A9E59005A85F7 /* SwiftTestingTests.swift in Sources */,
221250
CADE79DE2C4A9E59005A85F7 /* XCTestTests.swift in Sources */,
251+
CA1972D72DB1836900351823 /* TraitTests.swift in Sources */,
222252
);
223253
runOnlyForDeploymentPostprocessing = 0;
224254
};
@@ -504,10 +534,6 @@
504534
isa = XCSwiftPackageProductDependency;
505535
productName = IssueReporting;
506536
};
507-
CADE79E12C4ABE90005A85F7 /* IssueReporting */ = {
508-
isa = XCSwiftPackageProductDependency;
509-
productName = IssueReporting;
510-
};
511537
/* End XCSwiftPackageProductDependency section */
512538
};
513539
rootObject = CADE79A22C4A9D2C005A85F7 /* Project object */;

Examples/Examples/ExampleTrait.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import IssueReporting
2+
3+
public struct ExampleTrait: Sendable {
4+
public init() {}
5+
6+
public static func hasTrait() -> Bool {
7+
switch TestContext.current {
8+
case .none, .some(.xcTest):
9+
return false
10+
case .some(.swiftTesting(let testing)):
11+
return testing?.test.traits.contains { $0 is Self } ?? false
12+
}
13+
}
14+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import IssueReporting
2+
import Testing
3+
import Examples
4+
5+
extension ExampleTrait: @retroactive SuiteTrait, @retroactive TestTrait {
6+
}
7+
8+
@Suite
9+
struct TraitTests {
10+
@Test(ExampleTrait()) func hasTrait() {
11+
#if DEBUG
12+
#expect(ExampleTrait.hasTrait())
13+
#else
14+
#expect(ExampleTrait.hasTrait() == false)
15+
#endif
16+
}
17+
18+
@Test func doesNotHaveTrait() {
19+
#expect(ExampleTrait.hasTrait() == false)
20+
}
21+
}

Package.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,13 @@ let package = Package(
2222
],
2323
targets: [
2424
.target(
25-
name: "IssueReporting"
25+
name: "IssueReportingPackageSupport"
26+
),
27+
.target(
28+
name: "IssueReporting",
29+
dependencies: [
30+
"IssueReportingPackageSupport"
31+
]
2632
),
2733
.testTarget(
2834
name: "IssueReportingTests",
@@ -32,7 +38,10 @@ let package = Package(
3238
]
3339
),
3440
.target(
35-
name: "IssueReportingTestSupport"
41+
name: "IssueReportingTestSupport",
42+
dependencies: [
43+
"IssueReportingPackageSupport"
44+
]
3645
),
3746
.target(
3847
name: "XCTestDynamicOverlay",

[email protected]

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,13 @@ let package = Package(
2121
],
2222
targets: [
2323
.target(
24-
name: "IssueReporting"
24+
name: "IssueReportingPackageSupport"
25+
),
26+
.target(
27+
name: "IssueReporting",
28+
dependencies: [
29+
"IssueReportingPackageSupport",
30+
]
2531
),
2632
.testTarget(
2733
name: "IssueReportingTests",
@@ -31,7 +37,10 @@ let package = Package(
3137
]
3238
),
3339
.target(
34-
name: "IssueReportingTestSupport"
40+
name: "IssueReportingTestSupport",
41+
dependencies: [
42+
"IssueReportingPackageSupport",
43+
]
3544
),
3645
.target(
3746
name: "XCTestDynamicOverlay",

Sources/IssueReporting/Internal/SwiftTesting.swift

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Foundation
2+
import IssueReportingPackageSupport
23

34
#if canImport(WinSDK)
45
import WinSDK
@@ -313,17 +314,21 @@ func _withKnownIssue(
313314
#endif
314315

315316
@usableFromInline
316-
func _currentTestID() -> AnyHashable? {
317-
guard let function = function(for: "$s25IssueReportingTestSupport08_currentC2IDypyF")
317+
func _currentTest() -> _Test? {
318+
guard let function = function(for: "$s25IssueReportingTestSupport08_currentC0ypyF")
318319
else {
319320
#if DEBUG
320-
return Test.current?.id
321+
return Test.current.map { _Test(id: $0.id, traits: $0.traits) }
321322
#else
322323
return nil
323324
#endif
324325
}
325326

326-
return (function as! @Sendable () -> AnyHashable?)()
327+
return withUnsafePointer(to: function) {
328+
$0.withMemoryRebound(to: (@Sendable () -> _Test?).self, capacity: 1) {
329+
$0.pointee()
330+
}
331+
}
327332
}
328333

329334
#if DEBUG
@@ -446,7 +451,7 @@ func _currentTestID() -> AnyHashable? {
446451
struct Case {}
447452
private var name: String
448453
private var displayName: String?
449-
private var traits: [any Trait]
454+
fileprivate var traits: [any Trait]
450455
private var sourceLocation: SourceLocation
451456
private var containingTypeInfo: TypeInfo?
452457
private var xcTestCompatibleSelector: __XCTestCompatibleSelector?

Sources/IssueReporting/TestContext.swift

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ public enum TestContext: Equatable, Sendable {
2323
/// If executed outside of a test process, this will return `nil`.
2424
public static var current: Self? {
2525
guard isTesting else { return nil }
26-
if let currentTestID = _currentTestID() {
27-
return .swiftTesting(Testing(id: currentTestID))
26+
if let currentTest = _currentTest() {
27+
return .swiftTesting(Testing(id: currentTest.id, traits: currentTest.traits))
2828
} else {
2929
return .xcTest
3030
}
@@ -42,10 +42,19 @@ public enum TestContext: Equatable, Sendable {
4242

4343
public struct Test: Equatable, Hashable, Identifiable, Sendable {
4444
public let id: ID
45+
public let traits: [any Sendable]
4546

4647
public struct ID: Equatable, Hashable, @unchecked Sendable {
4748
public let rawValue: AnyHashable
4849
}
50+
51+
public static func == (lhs: Self, rhs: Self) -> Bool {
52+
lhs.id == rhs.id
53+
}
54+
55+
public func hash(into hasher: inout Hasher) {
56+
hasher.combine(id)
57+
}
4958
}
5059
}
5160

@@ -73,7 +82,7 @@ public enum TestContext: Equatable, Sendable {
7382
}
7483

7584
extension TestContext.Testing {
76-
fileprivate init(id: AnyHashable) {
77-
self.init(test: Test(id: Test.ID(rawValue: id)))
85+
fileprivate init(id: AnyHashable, traits: [any Sendable]) {
86+
self.init(test: Test(id: Test.ID(rawValue: id), traits: traits))
7887
}
7988
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
@usableFromInline
2+
package struct _Test {
3+
@usableFromInline
4+
package let id: AnyHashable
5+
6+
@usableFromInline
7+
package let traits: [any Sendable]
8+
9+
@usableFromInline
10+
package init(id: AnyHashable, traits: [any Sendable]) {
11+
self.id = id
12+
self.traits = traits
13+
}
14+
}

Sources/IssueReportingTestSupport/SwiftTesting.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import IssueReportingPackageSupport
2+
13
#if canImport(Testing)
24
import Testing
35
#endif
@@ -134,11 +136,11 @@ private func __withKnownIssueAsync(
134136
}
135137
#endif
136138

137-
public func _currentTestID() -> Any { __currentTestID }
139+
public func _currentTest() -> Any { __currentTest }
138140
@Sendable
139-
private func __currentTestID() -> AnyHashable? {
141+
private func __currentTest() -> _Test? {
140142
#if canImport(Testing)
141-
return Test.current?.id
143+
return Test.current.map { _Test(id: $0.id, traits: $0.traits) }
142144
#else
143145
return nil
144146
#endif

0 commit comments

Comments
 (0)