Skip to content

Commit df8a6d2

Browse files
authored
Correctly block @Suite and @Test on XCTest.XCTest and XCTestSuite. (#1456)
This PR ensures that we diagnose if `@Suite` or `@Test` is applied to a class (or method on such class) that subclasses [`XCTest.XCTest`](https://developer.apple.com/documentation/xctest/xctest) or [`XCTestSuite`](https://developer.apple.com/documentation/xctest/xctestsuite), not just [`XCTestCase`](https://developer.apple.com/documentation/xctest/xctestcase). This change also suppresses the emitted call to the helper function `__invokeXCTest[Case]Method()` if the suite type is _known_ not to subclass `XCTest.XCTest` (e.g. because it's a `struct`.) This slightly improves the performance of non-class suite types (although probably not measurably so). Finally, this change improves the emitted diagnostic when `@Test` is used on a method in an `XCTest.XCTest` subclass such that it explicitly states the reason why the attribute can't be used: > 🛑 Attribute 'Test' cannot be applied to a function within class 'C' because it is a subclass of 'XCTest', 'XCTestCase', or 'XCTestSuite' ### Checklist: - [x] Code and documentation should follow the style of the [Style Guide](https://github.com/apple/swift-testing/blob/main/Documentation/StyleGuide.md). - [x] If public symbols are renamed or modified, DocC references should be updated.
1 parent 60d80e7 commit df8a6d2

10 files changed

Lines changed: 117 additions & 53 deletions

Sources/Testing/ExitTests/ExitTest.swift

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,7 @@ extension ExitTest {
812812
?? parentArguments.dropFirst().last
813813
// If the running executable appears to be the XCTest runner executable in
814814
// Xcode, figure out the path to the running XCTest bundle. If we can find
815-
// it, then we can re-run the host XCTestCase instance.
815+
// it, then we can spawn a child process of it.
816816
var isHostedByXCTest = false
817817
if let executablePath = try? childProcessExecutablePath.get() {
818818
executablePath.withCString { childProcessExecutablePath in
@@ -825,12 +825,9 @@ extension ExitTest {
825825
}
826826

827827
if isHostedByXCTest, let xctestTargetPath {
828-
// HACK: if the current test is being run from within Xcode, we don't
829-
// always know we're being hosted by an XCTestCase instance. In cases
830-
// where we don't, but the XCTest environment variable specifying the
831-
// test bundle is set, assume we _are_ being hosted and specify a
832-
// blank test identifier ("/") to force the xctest command-line tool
833-
// to run.
828+
// HACK: specify a blank test identifier ("/") to force the xctest
829+
// command-line tool to run. Xcode will then (eventually) invoke the
830+
// testing library which will then start the exit test.
834831
result += ["-XCTest", "/", xctestTargetPath]
835832
}
836833

Sources/Testing/Test+Macro.swift

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -568,54 +568,51 @@ public var __defaultSynchronousIsolationContext: (any Actor)? {
568568
Configuration.current?.defaultSynchronousIsolationContext ?? #isolation
569569
}
570570

571-
/// Run a test function as an `XCTestCase`-compatible method.
571+
/// Run a test function as an XCTest-compatible method.
572572
///
573573
/// This overload is used for types that are not classes. It always returns
574574
/// `false`.
575575
///
576576
/// - Warning: This function is used to implement the `@Test` macro. Do not call
577577
/// it directly.
578-
@inlinable public func __invokeXCTestCaseMethod<T>(
578+
@inlinable public func __invokeXCTestMethod<T>(
579579
_ selector: __XCTestCompatibleSelector?,
580580
onInstanceOf type: T.Type,
581581
sourceLocation: SourceLocation
582582
) async throws -> Bool where T: ~Copyable {
583583
false
584584
}
585585

586-
// TODO: implement a hook in XCTest that __invokeXCTestCaseMethod() can call to
587-
// run an XCTestCase nested in the current @Test function.
588-
589-
/// The `XCTestCase` Objective-C class.
590-
let xcTestCaseClass: AnyClass? = {
586+
/// The `XCTest.XCTest` Objective-C class.
587+
let xcTestClass: AnyClass? = {
591588
#if _runtime(_ObjC)
592-
objc_getClass("XCTestCase") as? AnyClass
589+
objc_getClass("XCTest") as? AnyClass
593590
#else
594-
_typeByName("6XCTest0A4CaseC") as? AnyClass // _mangledTypeName(XCTest.XCTestCase.self)
591+
_typeByName("6XCTestAAC") as? AnyClass // _mangledTypeName(XCTest.XCTest.self)
595592
#endif
596593
}()
597594

598-
/// Run a test function as an `XCTestCase`-compatible method.
595+
/// Run a test function as an XCTest-compatible method.
599596
///
600597
/// This overload is used for types that are classes. If the type is not a
601-
/// subclass of `XCTestCase`, or if XCTest is not loaded in the current process,
602-
/// this function returns immediately.
598+
/// subclass of `XCTest.XCTest`, or if XCTest is not loaded in the current
599+
/// process, this function returns immediately.
603600
///
604601
/// - Warning: This function is used to implement the `@Test` macro. Do not call
605602
/// it directly.
606-
public func __invokeXCTestCaseMethod<T>(
603+
public func __invokeXCTestMethod<T>(
607604
_ selector: __XCTestCompatibleSelector?,
608-
onInstanceOf xcTestCaseSubclass: T.Type,
605+
onInstanceOf xcTestSubclass: T.Type,
609606
sourceLocation: SourceLocation
610607
) async throws -> Bool where T: AnyObject {
611608
// All classes will end up on this code path, so only record an issue if it is
612-
// really an XCTestCase subclass.
613-
guard let xcTestCaseClass, isClass(xcTestCaseSubclass, subclassOf: xcTestCaseClass) else {
609+
// really an XCTest.XCTest subclass.
610+
guard let xcTestClass, isClass(xcTestSubclass, subclassOf: xcTestClass) else {
614611
return false
615612
}
616613
let issue = Issue(
617614
kind: .apiMisused,
618-
comments: ["The @Test attribute cannot be applied to methods on a subclass of XCTestCase."],
615+
comments: ["The 'Test' attribute cannot be applied to a method on a subclass of 'XCTest', 'XCTestCase', or 'XCTestSuite'."],
619616
sourceContext: .init(backtrace: nil, sourceLocation: sourceLocation)
620617
)
621618
issue.record()

Sources/TestingMacros/SuiteDeclarationMacro.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,14 @@ public struct SuiteDeclarationMacro: MemberMacro, PeerMacro, Sendable {
7474
diagnostics += diagnoseIssuesWithLexicalContext(context.lexicalContext, containing: declaration, attribute: suiteAttribute)
7575
diagnostics += diagnoseIssuesWithLexicalContext(declaration, containing: declaration, attribute: suiteAttribute)
7676

77-
// Suites inheriting from XCTestCase are not supported. This check is
77+
// Suites inheriting from XCTest.XCTest are not supported. This check is
7878
// duplicated in TestDeclarationMacro but is not part of
7979
// diagnoseIssuesWithLexicalContext() because it doesn't need to recurse
8080
// across the entire lexical context list, just the innermost type
8181
// declaration.
82-
if let declaration = declaration.asProtocol((any DeclGroupSyntax).self),
83-
declaration.inherits(fromTypeNamed: "XCTestCase", inModuleNamed: "XCTest") {
84-
diagnostics.append(.xcTestCaseNotSupported(declaration, whenUsing: suiteAttribute))
82+
let inheritsFromXCTestClass = declarationInheritsFromXCTestClass(declaration)
83+
if inheritsFromXCTestClass == true {
84+
diagnostics.append(.xcTestSubclassNotSupported(declaration, whenUsing: suiteAttribute))
8585
}
8686

8787
// @Suite cannot be applied to a type extension (although a type extension

Sources/TestingMacros/Support/DiagnosticMessage+Diagnosing.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,3 +281,39 @@ func makeGenericGuardDecl(
281281
private static let \(genericGuardName): Void = ()
282282
"""
283283
}
284+
285+
// MARK: -
286+
287+
/// Check whether or not the given declaration inherits from `XCTest.XCTest` or
288+
/// its known subclasses `XCTestCase` and `XCTestSuite`.
289+
///
290+
/// - Parameters:
291+
/// - decl: The declaration to examine.
292+
///
293+
/// - Returns: Whether or not `decl` inherits from `XCTest.XCTest`. If the
294+
/// result could not be determined from the available syntax, returns `nil`.
295+
func declarationInheritsFromXCTestClass(_ decl: some DeclSyntaxProtocol) -> Bool? {
296+
switch decl.kind {
297+
case .structDecl, .enumDecl:
298+
// Value types can never inherit from XCTest.XCTest because it's a class, so
299+
// we can confidently return `false` here.
300+
return false
301+
302+
default:
303+
if let decl = decl.asProtocol((any DeclGroupSyntax).self) {
304+
let xctestClassNames = ["XCTest", "XCTestCase", "XCTestSuite"]
305+
let inheritsFromXCTestClass = xctestClassNames.contains { className in
306+
decl.inherits(fromTypeNamed: className, inModuleNamed: "XCTest")
307+
}
308+
if inheritsFromXCTestClass {
309+
// We can plainly see the inheritance, so return `true`. Note we don't
310+
// return `false` along this branch because we can't be sure it doesn't
311+
// inherit via an intermediate class, typealias, etc.
312+
return true
313+
}
314+
}
315+
}
316+
317+
// We couldn't tell either way.
318+
return nil
319+
}

Sources/TestingMacros/Support/DiagnosticMessage.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,8 @@ struct DiagnosticMessage: SwiftDiagnostics.DiagnosticMessage {
375375
}
376376
if escapableNonConformance != nil {
377377
message += " because its conformance to 'Escapable' has been suppressed"
378+
} else if let decl = node.as(DeclSyntax.self), declarationInheritsFromXCTestClass(decl) == true {
379+
message += " because it is a subclass of 'XCTest', 'XCTestCase', or 'XCTestSuite'"
378380
}
379381

380382
return Self(syntax: syntax, message: message, severity: .error)
@@ -529,18 +531,18 @@ struct DiagnosticMessage: SwiftDiagnostics.DiagnosticMessage {
529531
}
530532

531533
/// Create a diagnostic message stating that `@Test` or `@Suite` is
532-
/// incompatible with `XCTestCase` and its subclasses.
534+
/// incompatible with `XCTest.XCTest` and its subclasses.
533535
///
534536
/// - Parameters:
535537
/// - decl: The expression or declaration referring to the unsupported
536538
/// XCTest symbol.
537539
/// - attribute: The `@Test` or `@Suite` attribute.
538540
///
539541
/// - Returns: A diagnostic message.
540-
static func xcTestCaseNotSupported(_ decl: some SyntaxProtocol, whenUsing attribute: AttributeSyntax) -> Self {
542+
static func xcTestSubclassNotSupported(_ decl: some SyntaxProtocol, whenUsing attribute: AttributeSyntax) -> Self {
541543
Self(
542544
syntax: Syntax(decl),
543-
message: "Attribute \(_macroName(attribute)) cannot be applied to a subclass of 'XCTestCase'",
545+
message: "Attribute \(_macroName(attribute)) cannot be applied to a subclass of 'XCTest', 'XCTestCase', or 'XCTestSuite'",
544546
severity: .error
545547
)
546548
}

Sources/TestingMacros/TestDeclarationMacro.swift

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,15 @@ public struct TestDeclarationMacro: PeerMacro, Sendable {
2727
providingPeersOf declaration: some DeclSyntaxProtocol,
2828
in context: some MacroExpansionContext
2929
) throws -> [DeclSyntax] {
30-
guard _diagnoseIssues(with: declaration, testAttribute: node, in: context) else {
30+
var inheritsFromXCTestClass: Bool?
31+
guard _diagnoseIssues(with: declaration, testAttribute: node, inheritsFromXCTestClass: &inheritsFromXCTestClass, in: context) else {
3132
return []
3233
}
3334

3435
let functionDecl = declaration.cast(FunctionDeclSyntax.self)
3536
let typeName = context.typeOfLexicalContext
3637

37-
return _createTestDecls(for: functionDecl, on: typeName, testAttribute: node, in: context)
38+
return _createTestDecls(for: functionDecl, on: typeName, testAttribute: node, inheritsFromXCTestClass: inheritsFromXCTestClass, in: context)
3839
}
3940

4041
public static var formatMode: FormatMode {
@@ -46,20 +47,26 @@ public struct TestDeclarationMacro: PeerMacro, Sendable {
4647
/// - Parameters:
4748
/// - declaration: The function declaration to diagnose.
4849
/// - testAttribute: The `@Test` attribute applied to `declaration`.
50+
/// - inheritsFromXCTestClass: On return, whether or not the type containing
51+
/// `declaration` (if any) is known to inherit from `XCTest.XCTest`.
4952
/// - context: The macro context in which the expression is being parsed.
5053
///
5154
/// - Returns: Whether or not macro expansion should continue (i.e. stopping
5255
/// if a fatal error was diagnosed.)
5356
private static func _diagnoseIssues(
5457
with declaration: some DeclSyntaxProtocol,
5558
testAttribute: AttributeSyntax,
59+
inheritsFromXCTestClass: inout Bool?,
5660
in context: some MacroExpansionContext
5761
) -> Bool {
5862
var diagnostics = [DiagnosticMessage]()
5963
defer {
6064
context.diagnose(diagnostics)
6165
}
6266

67+
// Default to "we don't know".
68+
inheritsFromXCTestClass = nil
69+
6370
// The @Test attribute is only supported on function declarations.
6471
guard let function = declaration.as(FunctionDeclSyntax.self), !function.isOperator else {
6572
diagnostics.append(.attributeNotSupported(testAttribute, on: declaration))
@@ -70,14 +77,16 @@ public struct TestDeclarationMacro: PeerMacro, Sendable {
7077
let lexicalContext = context.lexicalContext
7178
diagnostics += diagnoseIssuesWithLexicalContext(lexicalContext, containing: declaration, attribute: testAttribute)
7279

73-
// Suites inheriting from XCTestCase are not supported. We are a bit
80+
// Suites inheriting from XCTest.XCTest are not supported. We are a bit
7481
// conservative here in this check and only check the immediate context.
7582
// Presumably, if there's an intermediate lexical context that is *not* a
7683
// type declaration, then it must be a function or closure (disallowed
7784
// elsewhere) and thus the test function is not a member of any type.
78-
if let containingTypeDecl = lexicalContext.first?.asProtocol((any DeclGroupSyntax).self),
79-
containingTypeDecl.inherits(fromTypeNamed: "XCTestCase", inModuleNamed: "XCTest") {
80-
diagnostics.append(.containingNodeUnsupported(containingTypeDecl, whenUsing: testAttribute, on: declaration))
85+
if let containingTypeDecl = lexicalContext.first?.asProtocol((any DeclGroupSyntax).self) {
86+
inheritsFromXCTestClass = declarationInheritsFromXCTestClass(containingTypeDecl)
87+
if inheritsFromXCTestClass == true {
88+
diagnostics.append(.containingNodeUnsupported(containingTypeDecl, whenUsing: testAttribute, on: declaration))
89+
}
8190
}
8291

8392
// Only one @Test attribute is supported.
@@ -291,7 +300,7 @@ public struct TestDeclarationMacro: PeerMacro, Sendable {
291300
let sourceLocationExpr = createSourceLocationExpr(of: functionDecl.name, context: context)
292301

293302
thunkBody = """
294-
if try await Testing.__invokeXCTestCaseMethod(\(selectorExpr), onInstanceOf: \(typeName).self, sourceLocation: \(sourceLocationExpr)) {
303+
if try await Testing.__invokeXCTestMethod(\(selectorExpr), onInstanceOf: \(typeName).self, sourceLocation: \(sourceLocationExpr)) {
295304
return
296305
}
297306
\(thunkBody)
@@ -368,6 +377,8 @@ public struct TestDeclarationMacro: PeerMacro, Sendable {
368377
/// - typeName: The name of the type of which `functionDecl` is a member, if
369378
/// any.
370379
/// - testAttribute: The `@Test` attribute applied to `declaration`.
380+
/// - inheritsFromXCTestClass: Whether or not the type containing
381+
/// `functionDecl` (if any) is known to inherit from `XCTest.XCTest`.
371382
/// - context: The macro context in which the expression is being parsed.
372383
///
373384
/// - Returns: An array of declarations providing runtime information about
@@ -376,6 +387,7 @@ public struct TestDeclarationMacro: PeerMacro, Sendable {
376387
for functionDecl: FunctionDeclSyntax,
377388
on typeName: TypeSyntax?,
378389
testAttribute: AttributeSyntax,
390+
inheritsFromXCTestClass: Bool?,
379391
in context: some MacroExpansionContext
380392
) -> [DeclSyntax] {
381393
var result = [DeclSyntax]()
@@ -401,7 +413,8 @@ public struct TestDeclarationMacro: PeerMacro, Sendable {
401413

402414
// Generate a selector expression compatible with XCTest.
403415
var selectorExpr: ExprSyntax?
404-
if let selector = functionDecl.xcTestCompatibleSelector {
416+
if inheritsFromXCTestClass != false, // definitely does or maybe does
417+
let selector = functionDecl.xcTestCompatibleSelector {
405418
let selectorLiteral = String(selector.tokens(viewMode: .fixedUp).lazy.flatMap(\.textWithoutBackticks))
406419
selectorExpr = "Testing.__xcTestCompatibleSelector(\(literal: selectorLiteral))"
407420
}

Tests/TestingMacrosTests/TestDeclarationMacroTests.swift

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,31 @@ struct TestDeclarationMacroTests {
8080
"@_unavailableFromAsync @Suite actor A {}":
8181
"Attribute 'Suite' cannot be applied to this actor because it has been marked '@_unavailableFromAsync'",
8282
83-
// XCTestCase
83+
// XCTest/XCTestCase/XCTestSuite
84+
"@Suite final class C: XCTest {}":
85+
"Attribute 'Suite' cannot be applied to a subclass of 'XCTest', 'XCTestCase', or 'XCTestSuite'",
8486
"@Suite final class C: XCTestCase {}":
85-
"Attribute 'Suite' cannot be applied to a subclass of 'XCTestCase'",
87+
"Attribute 'Suite' cannot be applied to a subclass of 'XCTest', 'XCTestCase', or 'XCTestSuite'",
88+
"@Suite final class C: XCTestSuite {}":
89+
"Attribute 'Suite' cannot be applied to a subclass of 'XCTest', 'XCTestCase', or 'XCTestSuite'",
90+
"@Suite final class C: XCTest.XCTest {}":
91+
"Attribute 'Suite' cannot be applied to a subclass of 'XCTest', 'XCTestCase', or 'XCTestSuite'",
8692
"@Suite final class C: XCTest.XCTestCase {}":
87-
"Attribute 'Suite' cannot be applied to a subclass of 'XCTestCase'",
93+
"Attribute 'Suite' cannot be applied to a subclass of 'XCTest', 'XCTestCase', or 'XCTestSuite'",
94+
"@Suite final class C: XCTest.XCTestSuite {}":
95+
"Attribute 'Suite' cannot be applied to a subclass of 'XCTest', 'XCTestCase', or 'XCTestSuite'",
96+
"final class C: XCTest { @Test func f() {} }":
97+
"Attribute 'Test' cannot be applied to a function within class 'C' because it is a subclass of 'XCTest', 'XCTestCase', or 'XCTestSuite'",
8898
"final class C: XCTestCase { @Test func f() {} }":
89-
"Attribute 'Test' cannot be applied to a function within class 'C'",
99+
"Attribute 'Test' cannot be applied to a function within class 'C' because it is a subclass of 'XCTest', 'XCTestCase', or 'XCTestSuite'",
100+
"final class C: XCTestSuite { @Test func f() {} }":
101+
"Attribute 'Test' cannot be applied to a function within class 'C' because it is a subclass of 'XCTest', 'XCTestCase', or 'XCTestSuite'",
102+
"final class C: XCTest.XCTest { @Test func f() {} }":
103+
"Attribute 'Test' cannot be applied to a function within class 'C' because it is a subclass of 'XCTest', 'XCTestCase', or 'XCTestSuite'",
90104
"final class C: XCTest.XCTestCase { @Test func f() {} }":
91-
"Attribute 'Test' cannot be applied to a function within class 'C'",
105+
"Attribute 'Test' cannot be applied to a function within class 'C' because it is a subclass of 'XCTest', 'XCTestCase', or 'XCTestSuite'",
106+
"final class C: XCTest.XCTestSuite { @Test func f() {} }":
107+
"Attribute 'Test' cannot be applied to a function within class 'C' because it is a subclass of 'XCTest', 'XCTestCase', or 'XCTestSuite'",
92108
93109
// Unsupported inheritance
94110
"@Suite protocol P {}":
@@ -440,10 +456,10 @@ struct TestDeclarationMacroTests {
440456
("@Test @available(*, noasync) func f() {}", nil, "__requiringTry"),
441457
("@Test @_unavailableFromAsync func f() {}", nil, "__requiringTry"),
442458
("@Test(arguments: []) func f(f: () -> String) {}", "(() -> String).self", nil),
443-
("struct S {\n\t@Test func testF() {} }", nil, "__invokeXCTestCaseMethod"),
444-
("struct S {\n\t@Test func testF() throws {} }", nil, "__invokeXCTestCaseMethod"),
445-
("struct S {\n\t@Test func testF() async {} }", nil, "__invokeXCTestCaseMethod"),
446-
("struct S {\n\t@Test func testF() async throws {} }", nil, "__invokeXCTestCaseMethod"),
459+
("class S {\n\t@Test func testF() {} }", nil, "__invokeXCTestMethod"),
460+
("class S {\n\t@Test func testF() throws {} }", nil, "__invokeXCTestMethod"),
461+
("class S {\n\t@Test func testF() async {} }", nil, "__invokeXCTestMethod"),
462+
("class S {\n\t@Test func testF() async throws {} }", nil, "__invokeXCTestMethod"),
447463
(
448464
"""
449465
struct S {

Tests/TestingTests/NonCopyableSuiteTests.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ struct NonCopyableTests: ~Copyable {
1616
@Test borrowing func borrowMe() {}
1717
@Test consuming func consumeMe() {}
1818
@Test mutating func mutateMe() {}
19-
@Test borrowing func testNotAnXCTestCaseMethod() {}
2019

2120
@Test borrowing func typeComparison() {
2221
let lhs = TypeInfo(describing: Self.self)
@@ -31,3 +30,7 @@ struct NonCopyableTests: ~Copyable {
3130
#expect(TypeInfo(describing: Self.self).mangledName != nil)
3231
}
3332
}
33+
34+
extension NonCopyableTests {
35+
@Test borrowing func testNotAnXCTestCaseMethod() {}
36+
}

Tests/TestingTests/ObjCInteropTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ struct ObjCAndXCTestInteropTests {
9999
if case let .issueRecorded(issue) = event.kind,
100100
case .apiMisused = issue.kind,
101101
let comment = issue.comments.first,
102-
comment == "The @Test attribute cannot be applied to methods on a subclass of XCTestCase." {
102+
comment == "The 'Test' attribute cannot be applied to a method on a subclass of 'XCTest', 'XCTestCase', or 'XCTestSuite'." {
103103
issueRecorded()
104104
}
105105
}

Tests/TestingTests/TypeNameConflictTests.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ fileprivate func __forwardNoAsync<R>(_ value: @autoclosure () throws -> R) throw
3737
Issue.record("Called wrong __forwardNoAsync()")
3838
}
3939

40-
fileprivate func __invokeXCTestCaseMethod<T>(
40+
fileprivate func __invokeXCTestMethod<T>(
4141
_ selector: __XCTestCompatibleSelector?,
42-
onInstanceOf xcTestCaseSubclass: T.Type,
42+
onInstanceOf xcTestSubclass: T.Type,
4343
sourceLocation: SourceLocation
4444
) {
45-
Issue.record("Called wrong __invokeXCTestCaseMethod()")
45+
Issue.record("Called wrong __invokeXCTestMethod()")
4646
}
4747

4848
fileprivate func __xcTestCompatibleSelector(_ selector: String) -> __XCTestCompatibleSelector? {

0 commit comments

Comments
 (0)