Skip to content

Commit fbbccf9

Browse files
authored
Allow configuring xct_specific_matcher with matchers (realm#4905)
So that either `one-argument-asserts` or `two-argument-asserts` or both can be enabled. The following configuration effectively reverts back to the rule behavior prior to realm#3858: ```yaml xct_specific_matcher: matchers: - two-argument-asserts ```
1 parent 8b72eb0 commit fbbccf9

File tree

4 files changed

+63
-5
lines changed

4 files changed

+63
-5
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@
1919
[kimdv](https://github.com/kimdv)
2020

2121
* Extend `xct_specific_matcher` rule to check for boolean asserts on (un)equal
22-
comparisons.
22+
comparisons. The rule can be configured with the matchers that should trigger
23+
rule violations. By default, all matchers trigger, but that can be limited to
24+
just `one-argument-asserts` or `two-argument-asserts`.
2325
[SimplyDanny](https://github.com/SimplyDanny)
26+
[JP Simard](https://github.com/jpsim)
2427
[#3726](https://github.com/realm/SwiftLint/issues/3726)
2528

2629
* Trigger `prefer_self_in_static_references` rule on more type references.

Source/SwiftLintFramework/Rules/Idiomatic/XCTSpecificMatcherRule.swift

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import SwiftOperators
22
import SwiftSyntax
33

44
struct XCTSpecificMatcherRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
5-
var configuration = SeverityConfiguration(.warning)
5+
var configuration = XCTSpecificMatcherRuleConfiguration()
66

77
init() {}
88

@@ -16,14 +16,28 @@ struct XCTSpecificMatcherRule: SwiftSyntaxRule, OptInRule, ConfigurationProvider
1616
)
1717

1818
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
19-
Visitor(viewMode: .sourceAccurate)
19+
Visitor(configuration: configuration)
2020
}
2121
}
2222

2323
private extension XCTSpecificMatcherRule {
2424
final class Visitor: ViolationsSyntaxVisitor {
25+
let configuration: XCTSpecificMatcherRuleConfiguration
26+
27+
init(configuration: XCTSpecificMatcherRuleConfiguration) {
28+
self.configuration = configuration
29+
super.init(viewMode: .sourceAccurate)
30+
}
31+
2532
override func visitPost(_ node: FunctionCallExprSyntax) {
26-
if let suggestion = TwoArgsXCTAssert.violations(in: node) ?? OneArgXCTAssert.violations(in: node) {
33+
if configuration.matchers.contains(.twoArgumentAsserts),
34+
let suggestion = TwoArgsXCTAssert.violations(in: node) {
35+
violations.append(ReasonedRuleViolation(
36+
position: node.positionAfterSkippingLeadingTrivia,
37+
reason: "Prefer the specific matcher '\(suggestion)' instead"
38+
))
39+
} else if configuration.matchers.contains(.oneArgumentAsserts),
40+
let suggestion = OneArgXCTAssert.violations(in: node) {
2741
violations.append(ReasonedRuleViolation(
2842
position: node.positionAfterSkippingLeadingTrivia,
2943
reason: "Prefer the specific matcher '\(suggestion)' instead"

Source/SwiftLintFramework/Rules/Idiomatic/XCTSpecificMatcherRuleExamples.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,13 @@ internal struct XCTSpecificMatcherRuleExamples {
5050
Example("XCTAssertEqual(foo?.bar, toto())"),
5151
Example("XCTAssertEqual(foo?.bar, .toto(.zoo))"),
5252
Example("XCTAssertEqual(toto(), foo?.bar)"),
53-
Example("XCTAssertEqual(.toto(.zoo), foo?.bar)")
53+
Example("XCTAssertEqual(.toto(.zoo), foo?.bar)"),
54+
55+
// Configurations Disabled
56+
Example("XCTAssertEqual(foo, true)",
57+
configuration: ["matchers": ["one-argument-asserts"]]),
58+
Example("XCTAssert(foo == bar)",
59+
configuration: ["matchers": ["two-argument-asserts"]])
5460
]
5561

5662
static let triggeringExamples = [
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
struct XCTSpecificMatcherRuleConfiguration: SeverityBasedRuleConfiguration, Equatable {
2+
private(set) var severityConfiguration = SeverityConfiguration(.warning)
3+
private(set) var matchers = Set(Matcher.allCases)
4+
5+
enum Matcher: String, Hashable, CaseIterable {
6+
case oneArgumentAsserts = "one-argument-asserts"
7+
case twoArgumentAsserts = "two-argument-asserts"
8+
}
9+
10+
private enum ConfigurationKey: String {
11+
case severity
12+
case matchers
13+
}
14+
15+
var consoleDescription: String {
16+
return [
17+
"severity: \(severityConfiguration.consoleDescription)",
18+
"\(ConfigurationKey.matchers): \(matchers.map(\.rawValue).sorted().joined(separator: ", "))"
19+
].joined(separator: ", ")
20+
}
21+
22+
mutating func apply(configuration: Any) throws {
23+
guard let configuration = configuration as? [String: Any] else {
24+
throw ConfigurationError.unknownConfiguration
25+
}
26+
27+
if let severityString = configuration[ConfigurationKey.severity.rawValue] as? String {
28+
try severityConfiguration.apply(configuration: severityString)
29+
}
30+
31+
if let matchers = configuration[ConfigurationKey.matchers.rawValue] as? [String] {
32+
self.matchers = Set(matchers.compactMap(Matcher.init(rawValue:)))
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)