Add `test_parent_class` option to more test rules (#4262)
This commit is contained in:
parent
92304cdd98
commit
7a8b2d1dab
|
@ -100,6 +100,10 @@
|
|||
SwiftLintFramework. This only impacts the programmatic API for the
|
||||
SwiftLintFramework module.
|
||||
[JP Simard](https://github.com/jpsim)
|
||||
* The `balanced_xctest_lifecycle`, `single_test_class`, `empty_xctest_method` and
|
||||
`test_case_accessibility` rules will now be applied to subclasses of `QuickSpec`,
|
||||
as well as `XCTestCase`, by default.
|
||||
[Martin Redington](https://github.com/mildm8nnered)
|
||||
|
||||
#### Experimental
|
||||
|
||||
|
@ -341,6 +345,11 @@
|
|||
* Print violations in realtime if `--progress` and `--output` are both set.
|
||||
[JP Simard](https://github.com/jpsim)
|
||||
|
||||
* Add `test_parent_classes` option to `balanced_xctest_lifecycle`, `single_test_class`
|
||||
and `empty_xctest_method` rules.
|
||||
[Martin Redington](https://github.com/mildm8nnered)
|
||||
[#4200](https://github.com/realm/SwiftLint/issues/4200)
|
||||
|
||||
* Trigger `prefer_self_in_static_references` rule on more type references like:
|
||||
* Key paths (e.g. `\MyType.myVar` -> `\Self.myVar`)
|
||||
* Computed properties (e.g. `var i: Int { MyType.myVar )` -> `var i: Int { Self.myVar }`)
|
||||
|
|
|
@ -75,6 +75,16 @@ extension ByteSourceRange {
|
|||
}
|
||||
}
|
||||
|
||||
extension ClassDeclSyntax {
|
||||
func isXCTestCase(_ testParentClasses: Set<String>) -> Bool {
|
||||
guard let inheritanceList = inheritanceClause?.inheritedTypeCollection else {
|
||||
return false
|
||||
}
|
||||
let inheritedTypes = inheritanceList.compactMap { $0.typeName.as(SimpleTypeIdentifierSyntax.self)?.name.text }
|
||||
return testParentClasses.intersection(inheritedTypes).isNotEmpty
|
||||
}
|
||||
}
|
||||
|
||||
extension ExprSyntax {
|
||||
var asFunctionCall: FunctionCallExprSyntax? {
|
||||
if let functionCall = self.as(FunctionCallExprSyntax.self) {
|
||||
|
|
|
@ -3,7 +3,7 @@ import SwiftSyntax
|
|||
struct BalancedXCTestLifecycleRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
|
||||
// MARK: - Properties
|
||||
|
||||
var configuration = SeverityConfiguration(.warning)
|
||||
var configuration = BalancedXCTestLifecycleConfiguration()
|
||||
|
||||
static let description = RuleDescription(
|
||||
identifier: "balanced_xctest_lifecycle",
|
||||
|
@ -113,16 +113,22 @@ struct BalancedXCTestLifecycleRule: SwiftSyntaxRule, OptInRule, ConfigurationPro
|
|||
// MARK: - Public
|
||||
|
||||
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
|
||||
Visitor(viewMode: .sourceAccurate)
|
||||
Visitor(viewMode: .sourceAccurate, testClasses: configuration.testParentClasses)
|
||||
}
|
||||
}
|
||||
|
||||
private extension BalancedXCTestLifecycleRule {
|
||||
final class Visitor: ViolationsSyntaxVisitor {
|
||||
private let testClasses: Set<String>
|
||||
override var skippableDeclarations: [DeclSyntaxProtocol.Type] { .all }
|
||||
|
||||
init(viewMode: SyntaxTreeViewMode, testClasses: Set<String>) {
|
||||
self.testClasses = testClasses
|
||||
super.init(viewMode: viewMode)
|
||||
}
|
||||
|
||||
override func visitPost(_ node: ClassDeclSyntax) {
|
||||
guard node.isXCTestCase else {
|
||||
guard node.isXCTestCase(testClasses) else {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -149,17 +155,6 @@ private extension BalancedXCTestLifecycleRule {
|
|||
}
|
||||
}
|
||||
|
||||
private extension ClassDeclSyntax {
|
||||
var isXCTestCase: Bool {
|
||||
guard let inheritanceList = inheritanceClause?.inheritedTypeCollection else {
|
||||
return false
|
||||
}
|
||||
return inheritanceList.contains { type in
|
||||
type.typeName.as(SimpleTypeIdentifierSyntax.self)?.name.text == "XCTestCase"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private enum XCTMethod {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import SwiftSyntax
|
||||
|
||||
struct EmptyXCTestMethodRule: OptInRule, ConfigurationProviderRule, SwiftSyntaxRule {
|
||||
var configuration = SeverityConfiguration(.warning)
|
||||
var configuration = EmptyXCTestMethodConfiguration()
|
||||
|
||||
init() {}
|
||||
|
||||
|
@ -15,15 +15,21 @@ struct EmptyXCTestMethodRule: OptInRule, ConfigurationProviderRule, SwiftSyntaxR
|
|||
)
|
||||
|
||||
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
|
||||
EmptyXCTestMethodRuleVisitor(viewMode: .sourceAccurate)
|
||||
EmptyXCTestMethodRuleVisitor(testParentClasses: configuration.testParentClasses)
|
||||
}
|
||||
}
|
||||
|
||||
private final class EmptyXCTestMethodRuleVisitor: ViolationsSyntaxVisitor {
|
||||
override var skippableDeclarations: [DeclSyntaxProtocol.Type] { .all }
|
||||
private let testParentClasses: Set<String>
|
||||
|
||||
init(testParentClasses: Set<String>) {
|
||||
self.testParentClasses = testParentClasses
|
||||
super.init(viewMode: .sourceAccurate)
|
||||
}
|
||||
|
||||
override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind {
|
||||
node.isXCTestCase ? .visitChildren : .skipChildren
|
||||
node.isXCTestCase(testParentClasses) ? .visitChildren : .skipChildren
|
||||
}
|
||||
|
||||
override func visitPost(_ node: FunctionDeclSyntax) {
|
||||
|
@ -33,17 +39,6 @@ private final class EmptyXCTestMethodRuleVisitor: ViolationsSyntaxVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
private extension ClassDeclSyntax {
|
||||
var isXCTestCase: Bool {
|
||||
guard let inheritanceList = inheritanceClause?.inheritedTypeCollection else {
|
||||
return false
|
||||
}
|
||||
return inheritanceList.contains { type in
|
||||
type.typeName.as(SimpleTypeIdentifierSyntax.self)?.name.text == "XCTestCase"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension FunctionDeclSyntax {
|
||||
var hasEmptyBody: Bool {
|
||||
if let body = body {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
struct TestCaseAccessibilityConfiguration: SeverityBasedRuleConfiguration, Equatable {
|
||||
private(set) var severityConfiguration = SeverityConfiguration(.warning)
|
||||
private(set) var allowedPrefixes: Set<String> = []
|
||||
private(set) var testParentClasses: Set<String> = ["XCTestCase"]
|
||||
private(set) var testParentClasses: Set<String> = ["QuickSpec", "XCTestCase"]
|
||||
|
||||
var consoleDescription: String {
|
||||
return severityConfiguration.consoleDescription +
|
||||
", allowed_prefixes: [\(allowedPrefixes)]" +
|
||||
", test_parent_classes: [\(testParentClasses)]"
|
||||
", allowed_prefixes: \(allowedPrefixes.sorted())" +
|
||||
", test_parent_classes: \(testParentClasses.sorted())"
|
||||
}
|
||||
|
||||
mutating func apply(configuration: Any) throws {
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
public typealias BalancedXCTestLifecycleConfiguration = UnitTestRuleConfiguration
|
||||
public typealias EmptyXCTestMethodConfiguration = UnitTestRuleConfiguration
|
||||
public typealias SingleTestClassConfiguration = UnitTestRuleConfiguration
|
||||
|
||||
public struct UnitTestRuleConfiguration: SeverityBasedRuleConfiguration, Equatable {
|
||||
public private(set) var severityConfiguration = SeverityConfiguration(.warning)
|
||||
public private(set) var testParentClasses: Set<String> = ["QuickSpec", "XCTestCase"]
|
||||
|
||||
public var consoleDescription: String {
|
||||
return severityConfiguration.consoleDescription +
|
||||
", test_parent_classes: \(testParentClasses.sorted())"
|
||||
}
|
||||
|
||||
public mutating func apply(configuration: Any) throws {
|
||||
guard let configuration = configuration as? [String: Any] else {
|
||||
throw ConfigurationError.unknownConfiguration
|
||||
}
|
||||
|
||||
if let severityString = configuration["severity"] as? String {
|
||||
try severityConfiguration.apply(configuration: severityString)
|
||||
}
|
||||
|
||||
if let extraTestParentClasses = configuration["test_parent_classes"] as? [String] {
|
||||
self.testParentClasses.formUnion(extraTestParentClasses)
|
||||
}
|
||||
}
|
||||
|
||||
public var severity: ViolationSeverity {
|
||||
return severityConfiguration.severity
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import SwiftSyntax
|
||||
|
||||
struct SingleTestClassRule: SourceKitFreeRule, OptInRule, ConfigurationProviderRule {
|
||||
var configuration = SeverityConfiguration(.warning)
|
||||
var configuration = SingleTestClassConfiguration()
|
||||
|
||||
static let description = RuleDescription(
|
||||
identifier: "single_test_class",
|
||||
|
@ -52,7 +52,7 @@ struct SingleTestClassRule: SourceKitFreeRule, OptInRule, ConfigurationProviderR
|
|||
init() {}
|
||||
|
||||
func validate(file: SwiftLintFile) -> [StyleViolation] {
|
||||
let classes = TestClassVisitor(viewMode: .sourceAccurate)
|
||||
let classes = TestClassVisitor(viewMode: .sourceAccurate, testClasses: configuration.testParentClasses)
|
||||
.walk(tree: file.syntaxTree, handler: \.violations)
|
||||
|
||||
guard classes.count > 1 else { return [] }
|
||||
|
@ -67,9 +67,14 @@ struct SingleTestClassRule: SourceKitFreeRule, OptInRule, ConfigurationProviderR
|
|||
}
|
||||
|
||||
private class TestClassVisitor: ViolationsSyntaxVisitor {
|
||||
private let testClasses: Set = ["QuickSpec", "XCTestCase"]
|
||||
private let testClasses: Set<String>
|
||||
override var skippableDeclarations: [DeclSyntaxProtocol.Type] { .all }
|
||||
|
||||
init(viewMode: SyntaxTreeViewMode, testClasses: Set<String>) {
|
||||
self.testClasses = testClasses
|
||||
super.init(viewMode: viewMode)
|
||||
}
|
||||
|
||||
override func visitPost(_ node: ClassDeclSyntax) {
|
||||
guard node.inheritanceClause.containsInheritedType(inheritedTypes: testClasses) else {
|
||||
return
|
||||
|
|
Loading…
Reference in New Issue