mirror of
https://github.com/realm/SwiftLint.git
synced 2026-06-06 20:18:40 +00:00
This allows custom rules to define an `excluded_match_kinds` array instead of listing out all but one or a few of the `SyntaxKind`s in `match_kinds`. Rules that include both `match_kinds` and `excluded_match_kinds` will be invalid, since there's not an obvious way to resolve the two without an arbitrary priority between them.
220 lines
8.5 KiB
Swift
220 lines
8.5 KiB
Swift
import SourceKittenFramework
|
|
@testable import SwiftLintFramework
|
|
import XCTest
|
|
|
|
class CustomRulesTests: XCTestCase {
|
|
func testCustomRuleConfigurationSetsCorrectlyWithMatchKinds() {
|
|
let configDict = [
|
|
"my_custom_rule": [
|
|
"name": "MyCustomRule",
|
|
"message": "Message",
|
|
"regex": "regex",
|
|
"match_kinds": "comment",
|
|
"severity": "error"
|
|
]
|
|
]
|
|
var comp = RegexConfiguration(identifier: "my_custom_rule")
|
|
comp.name = "MyCustomRule"
|
|
comp.message = "Message"
|
|
comp.regex = regex("regex")
|
|
comp.severityConfiguration = SeverityConfiguration(.error)
|
|
comp.excludedMatchKinds = SyntaxKind.allKinds.subtracting([.comment])
|
|
var compRules = CustomRulesConfiguration()
|
|
compRules.customRuleConfigurations = [comp]
|
|
do {
|
|
var configuration = CustomRulesConfiguration()
|
|
try configuration.apply(configuration: configDict)
|
|
XCTAssertEqual(configuration, compRules)
|
|
} catch {
|
|
XCTFail("Did not configure correctly")
|
|
}
|
|
}
|
|
|
|
func testCustomRuleConfigurationSetsCorrectlyWithExcludedMatchKinds() {
|
|
let configDict = [
|
|
"my_custom_rule": [
|
|
"name": "MyCustomRule",
|
|
"message": "Message",
|
|
"regex": "regex",
|
|
"excluded_match_kinds": "comment",
|
|
"severity": "error"
|
|
]
|
|
]
|
|
var comp = RegexConfiguration(identifier: "my_custom_rule")
|
|
comp.name = "MyCustomRule"
|
|
comp.message = "Message"
|
|
comp.regex = regex("regex")
|
|
comp.severityConfiguration = SeverityConfiguration(.error)
|
|
comp.excludedMatchKinds = Set<SyntaxKind>([.comment])
|
|
var compRules = CustomRulesConfiguration()
|
|
compRules.customRuleConfigurations = [comp]
|
|
do {
|
|
var configuration = CustomRulesConfiguration()
|
|
try configuration.apply(configuration: configDict)
|
|
XCTAssertEqual(configuration, compRules)
|
|
} catch {
|
|
XCTFail("Did not configure correctly")
|
|
}
|
|
}
|
|
|
|
func testCustomRuleConfigurationThrows() {
|
|
let config = 17
|
|
var customRulesConfig = CustomRulesConfiguration()
|
|
checkError(ConfigurationError.unknownConfiguration) {
|
|
try customRulesConfig.apply(configuration: config)
|
|
}
|
|
}
|
|
|
|
func testCustomRuleConfigurationMatchKindAmbiguity() {
|
|
let configDict = [
|
|
"name": "MyCustomRule",
|
|
"message": "Message",
|
|
"regex": "regex",
|
|
"match_kinds": "comment",
|
|
"excluded_match_kinds": "argument",
|
|
"severity": "error"
|
|
]
|
|
|
|
var configuration = RegexConfiguration(identifier: "my_custom_rule")
|
|
checkError(ConfigurationError.ambiguousMatchKindParameters) {
|
|
try configuration.apply(configuration: configDict)
|
|
}
|
|
}
|
|
|
|
func testCustomRuleConfigurationIgnoreInvalidRules() throws {
|
|
let configDict = [
|
|
"my_custom_rule": ["name": "MyCustomRule",
|
|
"message": "Message",
|
|
"regex": "regex",
|
|
"match_kinds": "comment",
|
|
"severity": "error"],
|
|
"invalid_rule": ["name": "InvalidRule"] // missing `regex`
|
|
]
|
|
var customRulesConfig = CustomRulesConfiguration()
|
|
try customRulesConfig.apply(configuration: configDict)
|
|
|
|
XCTAssertEqual(customRulesConfig.customRuleConfigurations.count, 1)
|
|
|
|
let identifier = customRulesConfig.customRuleConfigurations.first?.description.identifier
|
|
XCTAssertEqual(identifier, "my_custom_rule")
|
|
}
|
|
|
|
func testCustomRules() {
|
|
let (regexConfig, customRules) = getCustomRules()
|
|
|
|
let file = SwiftLintFile(contents: "// My file with\n// a pattern")
|
|
XCTAssertEqual(customRules.validate(file: file),
|
|
[StyleViolation(ruleDescription: regexConfig.description,
|
|
severity: .warning,
|
|
location: Location(file: nil, line: 2, character: 6),
|
|
reason: regexConfig.message)])
|
|
}
|
|
|
|
func testLocalDisableCustomRule() {
|
|
let (_, customRules) = getCustomRules()
|
|
let file = SwiftLintFile(contents: "//swiftlint:disable custom \n// file with a pattern")
|
|
XCTAssertEqual(customRules.validate(file: file), [])
|
|
}
|
|
|
|
func testLocalDisableCustomRuleWithMultipleRules() {
|
|
let (configs, customRules) = getCustomRulesWithTwoRules()
|
|
let file = SwiftLintFile(contents: "//swiftlint:disable \(configs.1.identifier) \n// file with a pattern")
|
|
XCTAssertEqual(customRules.validate(file: file),
|
|
[StyleViolation(ruleDescription: configs.0.description,
|
|
severity: .warning,
|
|
location: Location(file: nil, line: 2, character: 16),
|
|
reason: configs.0.message)])
|
|
}
|
|
|
|
func testCustomRulesIncludedDefault() {
|
|
// Violation detected when included is omitted.
|
|
let (_, customRules) = getCustomRules()
|
|
let violations = customRules.validate(file: getTestTextFile())
|
|
XCTAssertEqual(violations.count, 1)
|
|
}
|
|
|
|
func testCustomRulesIncludedExcludesFile() {
|
|
var (regexConfig, customRules) = getCustomRules(["included": "\\.yml$"])
|
|
|
|
var customRuleConfiguration = CustomRulesConfiguration()
|
|
customRuleConfiguration.customRuleConfigurations = [regexConfig]
|
|
customRules.configuration = customRuleConfiguration
|
|
|
|
let violations = customRules.validate(file: getTestTextFile())
|
|
XCTAssertEqual(violations.count, 0)
|
|
}
|
|
|
|
func testCustomRulesExcludedExcludesFile() {
|
|
var (regexConfig, customRules) = getCustomRules(["excluded": "\\.txt$"])
|
|
|
|
var customRuleConfiguration = CustomRulesConfiguration()
|
|
customRuleConfiguration.customRuleConfigurations = [regexConfig]
|
|
customRules.configuration = customRuleConfiguration
|
|
|
|
let violations = customRules.validate(file: getTestTextFile())
|
|
XCTAssertEqual(violations.count, 0)
|
|
}
|
|
|
|
func testCustomRulesCaptureGroup() {
|
|
let (_, customRules) = getCustomRules(["regex": #"\ba\s+(\w+)"#,
|
|
"capture_group": 1])
|
|
let violations = customRules.validate(file: getTestTextFile())
|
|
XCTAssertEqual(violations.count, 1)
|
|
XCTAssertEqual(violations[0].location.line, 2)
|
|
XCTAssertEqual(violations[0].location.character, 6)
|
|
}
|
|
|
|
private func getCustomRules(_ extraConfig: [String: Any] = [:]) -> (RegexConfiguration, CustomRules) {
|
|
var config: [String: Any] = ["regex": "pattern",
|
|
"match_kinds": "comment"]
|
|
extraConfig.forEach { config[$0] = $1 }
|
|
|
|
var regexConfig = RegexConfiguration(identifier: "custom")
|
|
do {
|
|
try regexConfig.apply(configuration: config)
|
|
} catch {
|
|
XCTFail("Failed regex config")
|
|
}
|
|
|
|
var customRuleConfiguration = CustomRulesConfiguration()
|
|
customRuleConfiguration.customRuleConfigurations = [regexConfig]
|
|
|
|
var customRules = CustomRules()
|
|
customRules.configuration = customRuleConfiguration
|
|
return (regexConfig, customRules)
|
|
}
|
|
|
|
private func getCustomRulesWithTwoRules() -> ((RegexConfiguration, RegexConfiguration), CustomRules) {
|
|
let config1 = ["regex": "pattern",
|
|
"match_kinds": "comment"]
|
|
|
|
var regexConfig1 = RegexConfiguration(identifier: "custom1")
|
|
do {
|
|
try regexConfig1.apply(configuration: config1)
|
|
} catch {
|
|
XCTFail("Failed regex config")
|
|
}
|
|
|
|
let config2 = ["regex": "something",
|
|
"match_kinds": "comment"]
|
|
|
|
var regexConfig2 = RegexConfiguration(identifier: "custom2")
|
|
do {
|
|
try regexConfig2.apply(configuration: config2)
|
|
} catch {
|
|
XCTFail("Failed regex config")
|
|
}
|
|
|
|
var customRuleConfiguration = CustomRulesConfiguration()
|
|
customRuleConfiguration.customRuleConfigurations = [regexConfig1, regexConfig2]
|
|
|
|
var customRules = CustomRules()
|
|
customRules.configuration = customRuleConfiguration
|
|
return ((regexConfig1, regexConfig2), customRules)
|
|
}
|
|
|
|
private func getTestTextFile() -> SwiftLintFile {
|
|
return SwiftLintFile(path: "\(testResourcesPath)/test.txt")!
|
|
}
|
|
}
|