Compare commits

...

1 Commits

Author SHA1 Message Date
JP Simard b07ffed3d7
Proof-of-concept: Async Rules
Using the new SourceKitten async send support introduced in
https://github.com/jpsim/SourceKitten/pull/762.
2023-02-20 16:17:07 -05:00
125 changed files with 1682 additions and 1383 deletions

View File

@ -8,8 +8,8 @@ import XCTest
{% for rule in types.structs %}
{% if rule.name|hasSuffix:"Rule" %}
class {{ rule.name }}GeneratedTests: XCTestCase {
func testWithDefaultConfiguration() {
verifyRule({{ rule.name }}.description)
func testWithDefaultConfiguration() async throws {
try await verifyRule({{ rule.name }}.description)
}
}
{% if not forloop.last %}

1
BUILD
View File

@ -21,6 +21,7 @@ swift_library(
module_name = "SwiftLintFramework",
visibility = ["//visibility:public"],
deps = [
"@com_github_johnsundell_collectionconcurrencykit//:CollectionConcurrencyKit",
"@com_github_jpsim_sourcekitten//:SourceKittenFramework",
"@com_github_apple_swift_syntax//:optlibs",
"@sourcekitten_com_github_jpsim_yams//:Yams",

View File

@ -11,6 +11,13 @@ extension Request {
return try send()
}
func sendAsyncIfNotDisabled() async throws -> [String: SourceKitRepresentable] {
guard !Self.disableSourceKit else {
throw Self.Error.connectionInterrupted("SourceKit is disabled by `SWIFTLINT_DISABLE_SOURCEKIT`.")
}
return try await asyncSend()
}
static func cursorInfo(file: String, offset: ByteCount, arguments: [String]) -> Request {
.customRequest(request: [
"key.request": UID("source.request.cursorinfo"),

View File

@ -10,6 +10,16 @@ import SwiftParserDiagnostics
import SwiftSyntax
private typealias FileCacheKey = UUID
private let responseActorCache = ActorCache { file -> [String: SourceKitRepresentable]? in
do {
return try Request.editorOpen(file: file.file).sendIfNotDisabled()
} catch let error as Request.Error {
queuedPrintError(error.description)
return nil
} catch {
return nil
}
}
private let responseCache = Cache { file -> [String: SourceKitRepresentable]? in
do {
return try Request.editorOpen(file: file.file).sendIfNotDisabled()
@ -20,6 +30,9 @@ private let responseCache = Cache { file -> [String: SourceKitRepresentable]? in
return nil
}
}
private let structureDictionaryActorCache = ActorCache { file in
await responseActorCache.get(file).map(Structure.init).map { SourceKittenDictionary($0.dictionary) }
}
private let structureDictionaryCache = Cache { file in
return responseCache.get(file).map(Structure.init).map { SourceKittenDictionary($0.dictionary) }
}
@ -58,6 +71,41 @@ public var parserDiagnosticsDisabledForTests = false
private let assertHandlers = [FileCacheKey: AssertHandler]()
private let assertHandlerCache = Cache { file in assertHandlers[file.cacheKey] }
private actor ActorCache<T> {
private var values = [FileCacheKey: T]()
private let factory: (SwiftLintFile) async -> T
init(_ factory: @escaping (SwiftLintFile) async -> T) {
self.factory = factory
}
func get(_ file: SwiftLintFile) async -> T {
let key = file.cacheKey
if let cachedValue = values[key] {
return cachedValue
}
let value = await factory(file)
values[key] = value
return value
}
func invalidate(_ file: SwiftLintFile) {
values.removeValue(forKey: file.cacheKey)
}
func clear() {
values.removeAll(keepingCapacity: false)
}
func set(key: FileCacheKey, value: T) {
values[key] = value
}
func unset(key: FileCacheKey) {
values.removeValue(forKey: key)
}
}
private class Cache<T> {
private var values = [FileCacheKey: T]()
private let factory: (SwiftLintFile) -> T
@ -146,6 +194,17 @@ extension SwiftLintFile {
return structureDictionary
}
internal func getStructureDictionary() async throws -> SourceKittenDictionary {
guard let structureDictionary = await structureDictionaryActorCache.get(self) else {
if let handler = assertHandler {
handler()
return SourceKittenDictionary([:])
}
queuedFatalError("Never call this for file that sourcekitd fails.")
}
return structureDictionary
}
internal var syntaxClassifications: SyntaxClassifications { syntaxClassificationsCache.get(self) }
internal var syntaxMap: SwiftLintSyntaxMap {

View File

@ -1,3 +1,4 @@
import CollectionConcurrencyKit
import Foundation
import SourceKittenFramework
@ -61,7 +62,7 @@ private extension Rule {
storage: RuleStorage,
configuration: Configuration,
superfluousDisableCommandRule: SuperfluousDisableCommandRule?,
compilerArguments: [String]) -> LintResult? {
compilerArguments: [String]) async throws -> LintResult? {
// Empty files shouldn't trigger violations
guard !file.isEmpty, SwiftVersion.current >= Self.description.minSwiftVersion else {
return nil
@ -78,10 +79,10 @@ private extension Rule {
let ruleTime: (String, Double)?
if benchmark {
let start = Date()
violations = validate(file: file, using: storage, compilerArguments: compilerArguments)
violations = try await validate(file: file, using: storage, compilerArguments: compilerArguments)
ruleTime = (ruleID, -start.timeIntervalSinceNow)
} else {
violations = validate(file: file, using: storage, compilerArguments: compilerArguments)
violations = try await validate(file: file, using: storage, compilerArguments: compilerArguments)
ruleTime = nil
}
@ -193,8 +194,8 @@ public struct CollectedLinter {
/// - parameter storage: The storage object containing all collected info.
///
/// - returns: All style violations found by this linter.
public func styleViolations(using storage: RuleStorage) -> [StyleViolation] {
return getStyleViolations(using: storage).0
public func styleViolations(using storage: RuleStorage) async throws -> [StyleViolation] {
return try await getStyleViolations(using: storage).0
}
/// Computes or retrieves style violations and the time spent executing each rule.
@ -203,12 +204,13 @@ public struct CollectedLinter {
///
/// - returns: All style violations found by this linter, and the time spent executing each rule.
public func styleViolationsAndRuleTimes(using storage: RuleStorage)
-> ([StyleViolation], [(id: String, time: Double)]) {
return getStyleViolations(using: storage, benchmark: true)
async throws -> ([StyleViolation], [(id: String, time: Double)]) {
return try await getStyleViolations(using: storage, benchmark: true)
}
private func getStyleViolations(using storage: RuleStorage,
benchmark: Bool = false) -> ([StyleViolation], [(id: String, time: Double)]) {
benchmark: Bool = false) async throws
-> ([StyleViolation], [(id: String, time: Double)]) {
guard !file.isEmpty else {
// Empty files shouldn't trigger violations
return ([], [])
@ -222,12 +224,12 @@ public struct CollectedLinter {
let superfluousDisableCommandRule = rules.first(where: {
$0 is SuperfluousDisableCommandRule
}) as? SuperfluousDisableCommandRule
let validationResults = rules.parallelCompactMap {
$0.lint(file: self.file, regions: regions, benchmark: benchmark,
storage: storage,
configuration: self.configuration,
superfluousDisableCommandRule: superfluousDisableCommandRule,
compilerArguments: self.compilerArguments)
let validationResults = try await rules.concurrentCompactMap {
try await $0.lint(file: self.file, regions: regions, benchmark: benchmark,
storage: storage,
configuration: self.configuration,
superfluousDisableCommandRule: superfluousDisableCommandRule,
compilerArguments: self.compilerArguments)
}
let undefinedSuperfluousCommandViolations = self.undefinedSuperfluousCommandViolations(
regions: regions, configuration: configuration,

View File

@ -26,8 +26,8 @@ public protocol ASTRule: Rule {
}
public extension ASTRule {
func validate(file: SwiftLintFile) -> [StyleViolation] {
return validate(file: file, dictionary: file.structureDictionary)
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
return validate(file: file, dictionary: try await file.getStructureDictionary())
}
/// Executes the rule on a file and a subset of its AST structure, returning any violations to the rule's

View File

@ -60,10 +60,10 @@ public extension CollectingRule {
compilerArguments: [String]) -> [StyleViolation] {
return validate(file: file, collectedInfo: collectedInfo)
}
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
queuedFatalError("Must call `validate(file:collectedInfo:)` for CollectingRule")
}
func validate(file: SwiftLintFile, compilerArguments: [String]) -> [StyleViolation] {
func validate(file: SwiftLintFile, compilerArguments: [String]) async throws -> [StyleViolation] {
queuedFatalError("Must call `validate(file:collectedInfo:compilerArguments:)` for CollectingRule")
}
}
@ -74,7 +74,7 @@ public extension CollectingRule where Self: AnalyzerRule {
"Must call `collect(infoFor:compilerArguments:)` for AnalyzerRule & CollectingRule"
)
}
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
queuedFatalError(
"Must call `validate(file:collectedInfo:compilerArguments:)` for AnalyzerRule & CollectingRule"
)

View File

@ -25,14 +25,14 @@ public protocol Rule {
/// - parameter compilerArguments: The compiler arguments needed to compile this file.
///
/// - returns: All style violations to the rule's expectations.
func validate(file: SwiftLintFile, compilerArguments: [String]) -> [StyleViolation]
func validate(file: SwiftLintFile, compilerArguments: [String]) async throws -> [StyleViolation]
/// Executes the rule on a file and returns any violations to the rule's expectations.
///
/// - parameter file: The file for which to execute the rule.
///
/// - returns: All style violations to the rule's expectations.
func validate(file: SwiftLintFile) -> [StyleViolation]
func validate(file: SwiftLintFile) async throws -> [StyleViolation]
/// Whether or not the specified rule is equivalent to the current rule.
///
@ -60,17 +60,18 @@ public protocol Rule {
/// - parameter compilerArguments: The compiler arguments needed to compile this file.
///
/// - returns: All style violations to the rule's expectations.
func validate(file: SwiftLintFile, using storage: RuleStorage, compilerArguments: [String]) -> [StyleViolation]
func validate(file: SwiftLintFile, using storage: RuleStorage, compilerArguments: [String]) async throws
-> [StyleViolation]
}
extension Rule {
public func validate(file: SwiftLintFile, using storage: RuleStorage,
compilerArguments: [String]) -> [StyleViolation] {
return validate(file: file, compilerArguments: compilerArguments)
compilerArguments: [String]) async throws -> [StyleViolation] {
return try await validate(file: file, compilerArguments: compilerArguments)
}
public func validate(file: SwiftLintFile, compilerArguments: [String]) -> [StyleViolation] {
return validate(file: file)
public func validate(file: SwiftLintFile, compilerArguments: [String]) async throws -> [StyleViolation] {
return try await validate(file: file)
}
public func isEqualTo(_ rule: Rule) -> Bool {
@ -200,9 +201,10 @@ public protocol SubstitutionCorrectableASTRule: SubstitutionCorrectableRule, AST
public extension SubstitutionCorrectableASTRule {
func violationRanges(in file: SwiftLintFile) -> [NSRange] {
return file.structureDictionary.traverseDepthFirst { subDict in
guard let kind = self.kind(from: subDict) else { return nil }
return violationRanges(in: file, kind: kind, dictionary: subDict)
file.structureDictionary.traverseDepthFirst { subDict in
kind(from: subDict).flatMap { kind in
violationRanges(in: file, kind: kind, dictionary: subDict)
}
}
}
}
@ -215,7 +217,7 @@ public protocol SourceKitFreeRule: Rule {}
public protocol AnalyzerRule: OptInRule {}
public extension AnalyzerRule {
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
queuedFatalError("Must call `validate(file:compilerArguments:)` for AnalyzerRule")
}
}

View File

@ -53,7 +53,7 @@ public extension SwiftSyntaxRule {
.compactMap { $0.toSourceRange(locationConverter: locationConverter) }
}
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
guard let syntaxTree = preprocess(file: file) else {
return []
}

View File

@ -132,7 +132,7 @@ struct DuplicateImportsRule: ConfigurationProviderRule, CorrectableRule {
})
}
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
return duplicateImports(file: file).map { duplicateImport in
StyleViolation(
ruleDescription: Self.description,

View File

@ -122,8 +122,10 @@ struct ExplicitACLRule: OptInRule, ConfigurationProviderRule {
}
}
func validate(file: SwiftLintFile) -> [StyleViolation] {
let implicitAndExplicitInternalElements = internalTypeElements(in: file.structureDictionary)
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
let implicitAndExplicitInternalElements = internalTypeElements(
in: try await file.getStructureDictionary()
)
guard implicitAndExplicitInternalElements.isNotEmpty else {
return []

View File

@ -16,7 +16,7 @@ struct FileNameNoSpaceRule: ConfigurationProviderRule, OptInRule, SourceKitFreeR
kind: .idiomatic
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
guard let filePath = file.path,
case let fileName = filePath.bridge().lastPathComponent,
!configuration.excluded.contains(fileName),

View File

@ -18,7 +18,7 @@ struct FileNameRule: ConfigurationProviderRule, OptInRule, SourceKitFreeRule {
kind: .idiomatic
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
guard let filePath = file.path,
case let fileName = filePath.bridge().lastPathComponent,
!configuration.excluded.contains(fileName) else {

View File

@ -98,7 +98,7 @@ struct NimbleOperatorRule: ConfigurationProviderRule, OptInRule, CorrectableRule
"beNil": (to: "==", toNot: "!=", .nullary(analogueValue: "nil"))
]
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
let matches = violationMatchesRanges(in: file)
return matches.map {
StyleViolation(ruleDescription: Self.description,

View File

@ -23,8 +23,10 @@ struct NoGroupingExtensionRule: OptInRule, ConfigurationProviderRule {
]
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
let collector = NamespaceCollector(dictionary: file.structureDictionary)
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
let collector = NamespaceCollector(
dictionary: try await file.getStructureDictionary()
)
let elements = collector.findAllElements(of: [.class, .enum, .struct, .extension])
let susceptibleNames = Set(elements.compactMap { $0.kind != .extension ? $0.name : nil })

View File

@ -76,7 +76,7 @@ struct RedundantTypeAnnotationRule: OptInRule, SubstitutionCorrectableRule, Conf
]
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
return violationRanges(in: file).map { range in
StyleViolation(
ruleDescription: Self.description,

View File

@ -17,7 +17,7 @@ struct SyntacticSugarRule: CorrectableRule, ConfigurationProviderRule, SourceKit
corrections: SyntacticSugarRuleExamples.corrections
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
let visitor = SyntacticSugarRuleVisitor(viewMode: .sourceAccurate)
return visitor.walk(file: file) { visitor in
flattenViolations(visitor.violations)

View File

@ -150,7 +150,7 @@ struct CommentSpacingRule: SourceKitFreeRule, ConfigurationProviderRule, Substit
.flatMap { $0 }
}
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
return violationRanges(in: file).map { range in
StyleViolation(
ruleDescription: Self.description,

View File

@ -48,7 +48,7 @@ struct ExpiringTodoRule: ConfigurationProviderRule, OptInRule {
init() {}
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
let regex = #"""
\b(?:TODO|FIXME)(?::|\b)(?:(?!\b(?:TODO|FIXME)(?::|\b)).)*?\#
\\#(configuration.dateDelimiters.opening)\#

View File

@ -102,7 +102,7 @@ struct MarkRule: CorrectableRule, ConfigurationProviderRule {
].joined(separator: "|")
}
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
return violationRanges(in: file, matching: pattern).map {
StyleViolation(ruleDescription: Self.description,
severity: configuration.severity,

View File

@ -119,9 +119,9 @@ struct MissingDocsRule: OptInRule, ConfigurationProviderRule {
]
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
let acls = configuration.parameters.map { $0.value }
let dict = file.structureDictionary
let dict = try await file.getStructureDictionary()
return file.missingDocOffsets(
in: dict,
acls: acls,

View File

@ -46,7 +46,7 @@ struct OrphanedDocCommentRule: SourceKitFreeRule, ConfigurationProviderRule {
]
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
file.syntaxClassifications
.filter { $0.kind != .none }
.pairs()

View File

@ -78,7 +78,7 @@ struct PeriodSpacingRule: SourceKitFreeRule, ConfigurationProviderRule, OptInRul
.flatMap { $0 }
}
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
return violationRanges(in: file).map { range in
StyleViolation(
ruleDescription: Self.description,

View File

@ -14,8 +14,8 @@ struct QuickDiscouragedCallRule: OptInRule, ConfigurationProviderRule {
triggeringExamples: QuickDiscouragedCallRuleExamples.triggeringExamples
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
let dict = file.structureDictionary
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
let dict = try await file.getStructureDictionary()
let testClasses = dict.substructure.filter {
return $0.inheritedTypes.isNotEmpty &&
$0.declarationKind == .class

View File

@ -14,7 +14,7 @@ public struct SuperfluousDisableCommandRule: ConfigurationProviderRule, SourceKi
kind: .lint
)
public func validate(file: SwiftLintFile) -> [StyleViolation] {
public func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
// This rule is implemented in Linter.swift
return []
}

View File

@ -71,7 +71,7 @@ struct TodoRule: ConfigurationProviderRule {
return reason
}
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
return file.match(pattern: "\\b(?:TODO|FIXME)(?::|\\b)").compactMap { range, syntaxKinds in
if syntaxKinds.contains(where: { !$0.isCommentLike }) {
return nil

View File

@ -58,7 +58,7 @@ struct TypesafeArrayInitRule: AnalyzerRule, ConfigurationProviderRule {
\\Q(Self) -> ((Self.Element) throws -> T) throws -> [T]\\E
""")
func validate(file: SwiftLintFile, compilerArguments: [String]) -> [StyleViolation] {
func validate(file: SwiftLintFile, compilerArguments: [String]) async throws -> [StyleViolation] {
guard let filePath = file.path else {
return []
}
@ -69,7 +69,7 @@ struct TypesafeArrayInitRule: AnalyzerRule, ConfigurationProviderRule {
""")
return []
}
return Self.parentRule.validate(file: file)
return try await Self.parentRule.validate(file: file)
.filter { violation in
guard let offset = getOffset(in: file, at: violation.location) else {
return false

View File

@ -20,7 +20,7 @@ struct UnusedImportRule: CorrectableRule, ConfigurationProviderRule, AnalyzerRul
requiresFileOnDisk: true
)
func validate(file: SwiftLintFile, compilerArguments: [String]) -> [StyleViolation] {
func validate(file: SwiftLintFile, compilerArguments: [String]) async throws -> [StyleViolation] {
return importUsage(in: file, compilerArguments: compilerArguments).map { importUsage in
StyleViolation(ruleDescription: Self.description,
severity: configuration.severity.severity,

View File

@ -20,7 +20,7 @@ struct FileLengthRule: ConfigurationProviderRule {
].skipWrappingInCommentTests()
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
func lineCountWithoutComments() -> Int {
let commentKinds = SyntaxKind.commentKinds
let lineCount = file.syntaxKindsByLines.filter { kinds in

View File

@ -14,7 +14,7 @@ struct LargeTupleRule: SourceKitFreeRule, ConfigurationProviderRule {
triggeringExamples: LargeTupleRuleExamples.triggeringExamples
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
LargeTupleRuleVisitor(viewMode: .sourceAccurate)
.walk(file: file, handler: \.violationPositions)
.sorted(by: { $0.position < $1.position })

View File

@ -27,7 +27,7 @@ struct LineLengthRule: ConfigurationProviderRule {
].skipWrappingInCommentTests().skipWrappingInStringTests()
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
let minValue = configuration.params.map({ $0.value }).min() ?? .max
let swiftDeclarationKindsByLine = Lazy(file.swiftDeclarationKindsByLine() ?? [])
let syntaxKindsByLine = Lazy(file.syntaxKindsByLine() ?? [])

View File

@ -35,8 +35,9 @@ struct NestingRule: ConfigurationProviderRule {
}
}
func validate(file: SwiftLintFile) -> [StyleViolation] {
return validate(file: file, substructure: file.structureDictionary.substructure, args: ValidationArgs())
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
let substructure = try await file.getStructureDictionary().substructure
return validate(file: file, substructure: substructure, args: ValidationArgs())
}
private func validate(file: SwiftLintFile, substructure: [SourceKittenDictionary],

View File

@ -18,7 +18,7 @@ struct ClosureEndIndentationRule: Rule, OptInRule, ConfigurationProviderRule {
fileprivate static let notWhitespace = regex("[^\\s]")
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
return violations(in: file).map { violation in
return styleViolation(for: violation, in: file)
}

View File

@ -19,7 +19,7 @@ struct ColonRule: SubstitutionCorrectableRule, ConfigurationProviderRule, Source
corrections: ColonRuleExamples.corrections
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
violationRanges(in: file).map { range in
StyleViolation(ruleDescription: Self.description,
severity: configuration.severityConfiguration.severity,

View File

@ -62,7 +62,7 @@ struct CommaInheritanceRule: OptInRule, SubstitutionCorrectableRule, Configurati
// MARK: - Rule
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
return violationRanges(in: file).map {
StyleViolation(ruleDescription: Self.description,
severity: configuration.severity,

View File

@ -90,7 +90,7 @@ struct CommaRule: CorrectableRule, ConfigurationProviderRule, SourceKitFreeRule
]
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
return violationRanges(in: file).map {
StyleViolation(ruleDescription: Self.description,
severity: configuration.severity,

View File

@ -80,7 +80,7 @@ struct ControlStatementRule: ConfigurationProviderRule, SubstitutionCorrectableR
]
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
return violationRanges(in: file).map { match -> StyleViolation in
return StyleViolation(ruleDescription: Self.description,
severity: configuration.severity,

View File

@ -80,7 +80,7 @@ struct CustomRules: Rule, ConfigurationProviderRule, CacheDescriptionProvider {
var configuration = CustomRulesConfiguration()
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
var configurations = configuration.customRuleConfigurations
guard configurations.isNotEmpty else {

View File

@ -17,7 +17,7 @@ struct ExplicitSelfRule: CorrectableRule, ConfigurationProviderRule, AnalyzerRul
requiresFileOnDisk: true
)
func validate(file: SwiftLintFile, compilerArguments: [String]) -> [StyleViolation] {
func validate(file: SwiftLintFile, compilerArguments: [String]) async throws -> [StyleViolation] {
return violationRanges(in: file, compilerArguments: compilerArguments).map {
StyleViolation(ruleDescription: Self.description,
severity: configuration.severity,

View File

@ -33,7 +33,7 @@ struct FileHeaderRule: ConfigurationProviderRule, OptInRule {
].skipWrappingInCommentTests()
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
var firstToken: SwiftLintSyntaxToken?
var lastToken: SwiftLintSyntaxToken?
var firstNonCommentToken: SwiftLintSyntaxToken?

View File

@ -17,26 +17,26 @@ struct FileTypesOrderRule: ConfigurationProviderRule, OptInRule {
triggeringExamples: FileTypesOrderRuleExamples.triggeringExamples
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
guard let mainTypeSubstructure = mainTypeSubstructure(in: file),
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
guard let mainTypeSubstructure = try await mainTypeSubstructure(in: file),
let mainTypeSubstuctureOffset = mainTypeSubstructure.offset else { return [] }
let extensionsSubstructures = self.extensionsSubstructures(
let extensionsSubstructures = try await self.extensionsSubstructures(
in: file,
mainTypeSubstructure: mainTypeSubstructure
)
let supportingTypesSubstructures = self.supportingTypesSubstructures(
let supportingTypesSubstructures = try await self.supportingTypesSubstructures(
in: file,
mainTypeSubstructure: mainTypeSubstructure
)
let previewProviderSubstructures = self.substructures(
let previewProviderSubstructures = try await self.substructures(
in: file,
withInheritedType: "PreviewProvider"
)
let libraryContentSubstructures = self.substructures(
let libraryContentSubstructures = try await self.substructures(
in: file,
withInheritedType: "LibraryContentProvider"
)
@ -95,8 +95,8 @@ struct FileTypesOrderRule: ConfigurationProviderRule, OptInRule {
private func extensionsSubstructures(
in file: SwiftLintFile,
mainTypeSubstructure: SourceKittenDictionary
) -> [SourceKittenDictionary] {
let dict = file.structureDictionary
) async throws -> [SourceKittenDictionary] {
let dict = try await file.getStructureDictionary()
return dict.substructure.filter { substructure in
guard let kind = substructure.kind else { return false }
return substructure.offset != mainTypeSubstructure.offset
@ -107,11 +107,11 @@ struct FileTypesOrderRule: ConfigurationProviderRule, OptInRule {
private func supportingTypesSubstructures(
in file: SwiftLintFile,
mainTypeSubstructure: SourceKittenDictionary
) -> [SourceKittenDictionary] {
) async throws -> [SourceKittenDictionary] {
var supportingTypeKinds = SwiftDeclarationKind.typeKinds
supportingTypeKinds.insert(SwiftDeclarationKind.protocol)
let dict = file.structureDictionary
let dict = try await file.getStructureDictionary()
return dict.substructure.filter { substructure in
guard let declarationKind = substructure.declarationKind else { return false }
guard !substructure.hasExcludedInheritedType else { return false }
@ -124,14 +124,14 @@ struct FileTypesOrderRule: ConfigurationProviderRule, OptInRule {
private func substructures(
in file: SwiftLintFile,
withInheritedType inheritedType: String
) -> [SourceKittenDictionary] {
file.structureDictionary.substructure.filter { substructure in
) async throws -> [SourceKittenDictionary] {
try await file.getStructureDictionary().substructure.filter { substructure in
substructure.inheritedTypes.contains(inheritedType)
}
}
private func mainTypeSubstructure(in file: SwiftLintFile) -> SourceKittenDictionary? {
let dict = file.structureDictionary
private func mainTypeSubstructure(in file: SwiftLintFile) async throws -> SourceKittenDictionary? {
let dict = try await file.getStructureDictionary()
guard let filePath = file.path else {
return self.mainTypeSubstructure(in: dict)
@ -140,7 +140,7 @@ struct FileTypesOrderRule: ConfigurationProviderRule, OptInRule {
let fileName = URL(fileURLWithPath: filePath, isDirectory: false)
.lastPathComponent.replacingOccurrences(of: ".swift", with: "")
guard let mainTypeSubstructure = dict.substructure.first(where: { $0.name == fileName }) else {
return self.mainTypeSubstructure(in: file.structureDictionary)
return self.mainTypeSubstructure(in: try await file.getStructureDictionary())
}
// specify type with name matching the files name as main type

View File

@ -16,7 +16,7 @@ struct ImplicitReturnRule: ConfigurationProviderRule, SubstitutionCorrectableRul
corrections: ImplicitReturnRuleExamples.corrections
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
return violationRanges(in: file).compactMap {
StyleViolation(ruleDescription: Self.description,
severity: configuration.severityConfiguration.severity,

View File

@ -47,7 +47,7 @@ struct IndentationWidthRule: ConfigurationProviderRule, OptInRule {
init() {}
// MARK: - Methods: Validation
func validate(file: SwiftLintFile) -> [StyleViolation] { // swiftlint:disable:this function_body_length
func validate(file: SwiftLintFile) async throws -> [StyleViolation] { // swiftlint:disable:this function_body_length
var violations: [StyleViolation] = []
var previousLineIndentations: [Indentation] = []

View File

@ -23,7 +23,7 @@ struct LeadingWhitespaceRule: CorrectableRule, ConfigurationProviderRule, Source
]
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
let countOfLeadingWhitespace = file.contents.countOfLeadingCharacters(in: .whitespacesAndNewlines)
if countOfLeadingWhitespace == 0 {
return []

View File

@ -62,8 +62,8 @@ struct LetVarWhitespaceRule: ConfigurationProviderRule, OptInRule {
]
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
let dict = file.structureDictionary
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
let dict = try await file.getStructureDictionary()
var attributeLines = attributeLineNumbers(file: file)
var varLines = Set<Int>()

View File

@ -123,7 +123,7 @@ struct LiteralExpressionEndIdentationRule: Rule, ConfigurationProviderRule, OptI
]
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
return violations(in: file).map { violation in
return styleViolation(for: violation, in: file)
}

View File

@ -92,8 +92,8 @@ struct MultilineParametersBracketsRule: OptInRule, ConfigurationProviderRule {
]
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
return violations(in: file.structureDictionary, file: file)
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
return violations(in: try await file.getStructureDictionary(), file: file)
}
private func violations(in substructure: SourceKittenDictionary, file: SwiftLintFile) -> [StyleViolation] {

View File

@ -175,7 +175,7 @@ struct OpeningBraceRule: CorrectableRule, ConfigurationProviderRule {
]
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
return file.violatingOpeningBraceRanges(allowMultilineFunc: configuration.allowMultilineFunc).map {
StyleViolation(ruleDescription: Self.description,
severity: configuration.severityConfiguration.severity,

View File

@ -17,7 +17,7 @@ struct OperatorUsageWhitespaceRule: OptInRule, CorrectableRule, ConfigurationPro
corrections: OperatorUsageWhitespaceRuleExamples.corrections
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
return violationRanges(file: file).map { range, _ in
StyleViolation(ruleDescription: Self.description,
severity: configuration.severityConfiguration.severity,

View File

@ -51,7 +51,7 @@ struct SingleTestClassRule: SourceKitFreeRule, OptInRule, ConfigurationProviderR
init() {}
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
let classes = TestClassVisitor(viewMode: .sourceAccurate, testClasses: configuration.testParentClasses)
.walk(tree: file.syntaxTree, handler: \.violations)

View File

@ -133,7 +133,7 @@ struct SortedImportsRule: CorrectableRule, ConfigurationProviderRule, OptInRule
]
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
let groups = importGroups(in: file, filterEnabled: false)
return violatingOffsets(inGroups: groups).map { index -> StyleViolation in
let location = Location(file: file, characterOffset: index)

View File

@ -63,7 +63,7 @@ struct StatementPositionRule: CorrectableRule, ConfigurationProviderRule {
]
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
switch configuration.statementMode {
case .default:
return defaultValidate(file: file)

View File

@ -30,8 +30,8 @@ struct TrailingClosureRule: OptInRule, ConfigurationProviderRule {
]
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
let dict = file.structureDictionary
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
let dict = try await file.getStructureDictionary()
return violationOffsets(for: dict, file: file).map {
StyleViolation(ruleDescription: Self.description,
severity: configuration.severityConfiguration.severity,

View File

@ -42,7 +42,7 @@ struct TrailingNewlineRule: CorrectableRule, ConfigurationProviderRule, SourceKi
]
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
if file.contents.trailingNewlineCount() == 1 {
return []
}

View File

@ -25,7 +25,7 @@ struct TrailingWhitespaceRule: CorrectableRule, ConfigurationProviderRule {
]
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
let filteredLines = file.lines.filter {
guard $0.content.hasTrailingWhitespace() else { return false }

View File

@ -16,8 +16,8 @@ struct TypeContentsOrderRule: ConfigurationProviderRule, OptInRule {
triggeringExamples: TypeContentsOrderRuleExamples.triggeringExamples
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
let dict = file.structureDictionary
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
let dict = try await file.getStructureDictionary()
let substructures = dict.substructure
return substructures.reduce(into: [StyleViolation]()) { violations, substructure in
violations.append(contentsOf: validateTypeSubstructure(substructure, in: file))

View File

@ -148,7 +148,7 @@ extension VerticalWhitespaceBetweenCasesRule: OptInRule {
corrections: violatingToValidExamples.removingViolationMarkers()
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
let patternRegex = regex(pattern)
return violationRanges(in: file).compactMap { violationRange in
let substring = file.contents.substring(from: violationRange.location, length: violationRange.length)

View File

@ -69,7 +69,7 @@ extension VerticalWhitespaceClosingBracesRule: OptInRule {
corrections: examples.violatingToValidExamples.removingViolationMarkers()
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
let pattern = configuration.onlyEnforceBeforeTrivialLines ? self.trivialLinePattern : self.pattern
let patternRegex: NSRegularExpression = regex(pattern)

View File

@ -155,7 +155,7 @@ extension VerticalWhitespaceOpeningBracesRule: OptInRule {
corrections: violatingToValidExamples.removingViolationMarkers()
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
let patternRegex: NSRegularExpression = regex(pattern)
return file.violatingRanges(for: pattern).map { violationRange in

View File

@ -38,7 +38,7 @@ struct VerticalWhitespaceRule: CorrectableRule, ConfigurationProviderRule {
return defaultDescriptionReason
}
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
let linesSections = violatingLineSections(in: file)
guard linesSections.isNotEmpty else {
return []

View File

@ -49,7 +49,7 @@ struct VoidReturnRule: ConfigurationProviderRule, SubstitutionCorrectableRule {
]
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
return violationRanges(in: file).map {
StyleViolation(ruleDescription: Self.description,
severity: configuration.severity,

View File

@ -66,9 +66,9 @@ extension Configuration {
duplicateFileNames: duplicateFileNames)
}
}
let result = await Signposts.record(name: "Configuration.VisitLintableFiles.Visit") {
await collected.asyncMap { linters, duplicateFileNames in
await visit(linters: linters, visitor: visitor, duplicateFileNames: duplicateFileNames)
let result = try await Signposts.record(name: "Configuration.VisitLintableFiles.Visit") {
try await collected.asyncMap { linters, duplicateFileNames in
try await visit(linters: linters, visitor: visitor, duplicateFileNames: duplicateFileNames)
}
}
return result.flatMap { $0 }
@ -181,7 +181,7 @@ extension Configuration {
private func visit(linters: [CollectedLinter],
visitor: LintableFilesVisitor,
duplicateFileNames: Set<String>) async -> [SwiftLintFile] {
duplicateFileNames: Set<String>) async throws -> [SwiftLintFile] {
let counter = CounterActor()
let progress = ProgressBar(count: linters.count)
if visitor.showProgressBar {
@ -198,12 +198,12 @@ extension Configuration {
}
}
await Signposts.record(name: "Configuration.Visit", span: .file(linter.file.path ?? "")) {
await visitor.block(linter)
try await Signposts.record(name: "Configuration.Visit", span: .file(linter.file.path ?? "")) {
try await visitor.block(linter)
}
return linter.file
}
return await visitor.parallel ?
return try await visitor.parallel ?
linters.concurrentMap(visit) :
linters.asyncMap(visit)
}
@ -244,7 +244,8 @@ extension Configuration {
}
func visitLintableFiles(options: LintOrAnalyzeOptions, cache: LinterCache? = nil, storage: RuleStorage,
visitorBlock: @escaping (CollectedLinter) async -> Void) async throws -> [SwiftLintFile] {
visitorBlock: @escaping (CollectedLinter) async throws -> Void) async throws
-> [SwiftLintFile] {
let visitor = try LintableFilesVisitor.create(options, cache: cache,
allowZeroLintableFiles: allowZeroLintableFiles,
block: visitorBlock)

View File

@ -58,7 +58,7 @@ struct LintOrAnalyzeCommand {
if options.benchmark {
CustomRuleTimer.shared.activate()
let start = Date()
let (violationsBeforeLeniency, currentRuleTimes) = linter
let (violationsBeforeLeniency, currentRuleTimes) = try await linter
.styleViolationsAndRuleTimes(using: builder.storage)
currentViolations = applyLeniency(options: options, violations: violationsBeforeLeniency)
visitorMutationQueue.sync {
@ -68,7 +68,7 @@ struct LintOrAnalyzeCommand {
}
} else {
currentViolations = applyLeniency(options: options,
violations: linter.styleViolations(using: builder.storage))
violations: try await linter.styleViolations(using: builder.storage))
visitorMutationQueue.sync {
builder.violations += currentViolations
}

View File

@ -81,12 +81,12 @@ struct LintableFilesVisitor {
let parallel: Bool
let allowZeroLintableFiles: Bool
let mode: LintOrAnalyzeModeWithCompilerArguments
let block: (CollectedLinter) async -> Void
let block: (CollectedLinter) async throws -> Void
private init(paths: [String], action: String, useSTDIN: Bool, quiet: Bool, showProgressBar: Bool,
useScriptInputFiles: Bool, forceExclude: Bool, useExcludingByPrefix: Bool,
cache: LinterCache?, compilerInvocations: CompilerInvocations?,
allowZeroLintableFiles: Bool, block: @escaping (CollectedLinter) async -> Void) {
allowZeroLintableFiles: Bool, block: @escaping (CollectedLinter) async throws -> Void) {
self.paths = resolveParamsFiles(args: paths)
self.action = action
self.useSTDIN = useSTDIN
@ -113,7 +113,7 @@ struct LintableFilesVisitor {
static func create(_ options: LintOrAnalyzeOptions,
cache: LinterCache?,
allowZeroLintableFiles: Bool,
block: @escaping (CollectedLinter) async -> Void)
block: @escaping (CollectedLinter) async throws -> Void)
throws -> LintableFilesVisitor {
try Signposts.record(name: "LintableFilesVisitor.Create") {
let compilerInvocations: CompilerInvocations?

View File

@ -139,7 +139,7 @@ private struct RuleMock1: Rule {
init() {}
init(configuration: Any) throws { self.init() }
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
return []
}
}
@ -152,7 +152,7 @@ private struct RuleMock2: Rule {
init() {}
init(configuration: Any) throws { self.init() }
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
return []
}
}
@ -165,7 +165,7 @@ private struct CorrectableRuleMock: CorrectableRule {
init() {}
init(configuration: Any) throws { self.init() }
func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) async throws -> [StyleViolation] {
return []
}

View File

@ -3,15 +3,15 @@ import SwiftLintTestHelpers
import XCTest
final class ExtraRulesTests: XCTestCase {
func testWithDefaultConfiguration() {
func testWithDefaultConfiguration() async throws {
for ruleType in extraRules() {
verifyRule(ruleType.description)
try await verifyRule(ruleType.description)
}
}
}
extension ExtraRulesTests {
static var allTests: [(String, (ExtraRulesTests) -> () throws -> Void)] {
static var allTests: [(String, (ExtraRulesTests) -> () async throws -> Void)] {
[("testWithDefaultConfiguration", testWithDefaultConfiguration)]
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,4 @@
import CollectionConcurrencyKit
import Foundation
import SourceKittenFramework
@_spi(TestHelper)
@ -15,7 +16,7 @@ private let config: Configuration = {
}()
class IntegrationTests: XCTestCase {
func testSwiftLintLints() {
func testSwiftLintLints() async throws {
// This is as close as we're ever going to get to a self-hosting linter.
let swiftFiles = config.lintableFiles(inPath: "", forceExclude: false)
XCTAssert(
@ -24,8 +25,8 @@ class IntegrationTests: XCTestCase {
)
let storage = RuleStorage()
let violations = swiftFiles.parallelFlatMap {
Linter(file: $0, configuration: config).collect(into: storage).styleViolations(using: storage)
let violations = try await swiftFiles.concurrentFlatMap {
try await Linter(file: $0, configuration: config).collect(into: storage).styleViolations(using: storage)
}
violations.forEach { violation in
violation.location.file!.withStaticString {

View File

@ -2,7 +2,7 @@
import XCTest
class AttributesRuleTests: XCTestCase {
func testAttributesWithAlwaysOnSameLine() {
func testAttributesWithAlwaysOnSameLine() async throws {
// Test with custom `always_on_same_line`
let nonTriggeringExamples = [
Example("@objc var x: String"),
@ -28,11 +28,11 @@ class AttributesRuleTests: XCTestCase {
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExamples)
verifyRule(alwaysOnSameLineDescription,
ruleConfiguration: ["always_on_same_line": ["@objc"]])
try await verifyRule(alwaysOnSameLineDescription,
ruleConfiguration: ["always_on_same_line": ["@objc"]])
}
func testAttributesWithAlwaysOnLineAbove() {
func testAttributesWithAlwaysOnLineAbove() async throws {
// Test with custom `always_on_line_above`
let nonTriggeringExamples = [
Example("@objc\n var x: String"),
@ -49,11 +49,11 @@ class AttributesRuleTests: XCTestCase {
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExamples)
verifyRule(alwaysOnNewLineDescription,
ruleConfiguration: ["always_on_line_above": ["@objc"]])
try await verifyRule(alwaysOnNewLineDescription,
ruleConfiguration: ["always_on_line_above": ["@objc"]])
}
func testAttributesWithAttributesOnLineAboveButOnOtherDeclaration() {
func testAttributesWithAttributesOnLineAboveButOnOtherDeclaration() async throws {
let nonTriggeringExamples = [
Example("""
@IBDesignable open class TagListView: UIView {
@ -92,8 +92,11 @@ class AttributesRuleTests: XCTestCase {
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExamples)
verifyRule(alwaysOnNewLineDescription,
ruleConfiguration: ["always_on_same_line": ["@discardableResult", "@objc",
"@IBAction", "@IBDesignable"]])
try await verifyRule(
alwaysOnNewLineDescription,
ruleConfiguration: [
"always_on_same_line": ["@discardableResult", "@objc", "@IBAction", "@IBDesignable"]
]
)
}
}

View File

@ -5,7 +5,7 @@ import SwiftLintTestHelpers
import XCTest
class CollectingRuleTests: XCTestCase {
func testCollectsIntoStorage() {
func testCollectsIntoStorage() async throws {
struct Spec: MockCollectingRule {
func collectInfo(for file: SwiftLintFile) -> Int {
return 42
@ -17,10 +17,11 @@ class CollectingRuleTests: XCTestCase {
}
}
XCTAssertFalse(violations(Example("_ = 0"), config: Spec.configuration!).isEmpty)
let violations = try await violations(Example("_ = 0"), config: Spec.configuration!)
XCTAssertNotEqual(violations, [])
}
func testCollectsAllFiles() {
func testCollectsAllFiles() async throws {
struct Spec: MockCollectingRule {
func collectInfo(for file: SwiftLintFile) -> String {
return file.contents
@ -36,10 +37,11 @@ class CollectingRuleTests: XCTestCase {
}
let inputs = ["foo", "bar", "baz"]
XCTAssertEqual(inputs.violations(config: Spec.configuration!).count, inputs.count)
let violations = try await inputs.violations(config: Spec.configuration!)
XCTAssertEqual(violations.count, inputs.count)
}
func testCollectsAnalyzerFiles() {
func testCollectsAnalyzerFiles() async throws {
struct Spec: MockCollectingRule, AnalyzerRule {
func collectInfo(for file: SwiftLintFile, compilerArguments: [String]) -> [String] {
return compilerArguments
@ -52,7 +54,8 @@ class CollectingRuleTests: XCTestCase {
}
}
XCTAssertFalse(violations(Example("_ = 0"), config: Spec.configuration!, requiresFileOnDisk: true).isEmpty)
let violations = try await violations(Example("_ = 0"), config: Spec.configuration!, requiresFileOnDisk: true)
XCTAssertNotEqual(violations, [])
}
func testCorrects() {

View File

@ -2,23 +2,23 @@
import XCTest
class CollectionAlignmentRuleTests: XCTestCase {
func testCollectionAlignmentWithAlignLeft() {
func testCollectionAlignmentWithAlignLeft() async throws {
let baseDescription = CollectionAlignmentRule.description
let examples = CollectionAlignmentRule.Examples(alignColons: false)
let description = baseDescription.with(nonTriggeringExamples: examples.nonTriggeringExamples,
triggeringExamples: examples.triggeringExamples)
verifyRule(description)
try await verifyRule(description)
}
func testCollectionAlignmentWithAlignColons() {
func testCollectionAlignmentWithAlignColons() async throws {
let baseDescription = CollectionAlignmentRule.description
let examples = CollectionAlignmentRule.Examples(alignColons: true)
let description = baseDescription.with(nonTriggeringExamples: examples.nonTriggeringExamples,
triggeringExamples: examples.triggeringExamples)
verifyRule(description, ruleConfiguration: ["align_colons": true])
try await verifyRule(description, ruleConfiguration: ["align_colons": true])
}
}

View File

@ -2,7 +2,7 @@
import XCTest
class ColonRuleTests: XCTestCase {
func testColonWithFlexibleRightSpace() {
func testColonWithFlexibleRightSpace() async throws {
// Verify Colon rule with test values for when flexible_right_spacing
// is true.
let nonTriggeringExamples = ColonRule.description.nonTriggeringExamples + [
@ -65,10 +65,10 @@ class ColonRuleTests: XCTestCase {
.with(nonTriggeringExamples: nonTriggeringExamples)
.with(corrections: corrections)
verifyRule(description, ruleConfiguration: ["flexible_right_spacing": true])
try await verifyRule(description, ruleConfiguration: ["flexible_right_spacing": true])
}
func testColonWithoutApplyToDictionaries() {
func testColonWithoutApplyToDictionaries() async throws {
let nonTriggeringExamples = ColonRule.description.nonTriggeringExamples + [
Example("let abc = [Void:Void]()\n"),
Example("let abc = [Void : Void]()\n"),
@ -130,6 +130,6 @@ class ColonRuleTests: XCTestCase {
.with(nonTriggeringExamples: nonTriggeringExamples)
.with(corrections: corrections)
verifyRule(description, ruleConfiguration: ["apply_to_dictionaries": false])
try await verifyRule(description, ruleConfiguration: ["apply_to_dictionaries": false])
}
}

View File

@ -4,6 +4,8 @@ import SourceKittenFramework
@testable import SwiftLintFramework
import XCTest
// swiftlint:disable file_length
private extension Command {
init?(string: String) {
let nsString = string.bridge()
@ -234,161 +236,184 @@ class CommandTests: XCTestCase {
// MARK: Superfluous Disable Command Detection
func testSuperfluousDisableCommands() {
XCTAssertEqual(
violations(Example("// swiftlint:disable nesting\nprint(123)\n"))[0].ruleIdentifier,
"superfluous_disable_command"
)
XCTAssertEqual(
violations(Example("// swiftlint:disable:next nesting\nprint(123)\n"))[0].ruleIdentifier,
"superfluous_disable_command"
)
XCTAssertEqual(
violations(Example("print(123) // swiftlint:disable:this nesting\n"))[0].ruleIdentifier,
"superfluous_disable_command"
)
XCTAssertEqual(
violations(Example("print(123)\n// swiftlint:disable:previous nesting\n"))[0].ruleIdentifier,
"superfluous_disable_command"
)
func testSuperfluousDisableCommands() async throws {
do {
let first = try await violations(Example("// swiftlint:disable nesting\nprint(123)\n"))[0]
XCTAssertEqual(first.ruleIdentifier, "superfluous_disable_command")
}
do {
let first = try await violations(Example("// swiftlint:disable:next nesting\nprint(123)\n"))[0]
XCTAssertEqual(first.ruleIdentifier, "superfluous_disable_command")
}
do {
let first = try await violations(Example("print(123) // swiftlint:disable:this nesting\n"))[0]
XCTAssertEqual(first.ruleIdentifier, "superfluous_disable_command")
}
do {
let first = try await violations(Example("print(123)\n// swiftlint:disable:previous nesting\n"))[0]
XCTAssertEqual(first.ruleIdentifier, "superfluous_disable_command")
}
}
func testDisableAllOverridesSuperfluousDisableCommand() {
XCTAssert(
violations(
func testDisableAllOverridesSuperfluousDisableCommand() async throws {
do {
let violations = try await violations(
Example("// swiftlint:disable all\n// swiftlint:disable nesting\nprint(123)\n")
).isEmpty
)
XCTAssert(
violations(
)
XCTAssertEqual(violations, [])
}
do {
let violations = try await violations(
Example("// swiftlint:disable all\n// swiftlint:disable:next nesting\nprint(123)\n")
).isEmpty
)
XCTAssert(
violations(
)
XCTAssertEqual(violations, [])
}
do {
let violations = try await violations(
Example("// swiftlint:disable all\n// swiftlint:disable:this nesting\nprint(123)\n")
).isEmpty
)
XCTAssert(
violations(
)
XCTAssertEqual(violations, [])
}
do {
let violations = try await violations(
Example("// swiftlint:disable all\n// swiftlint:disable:previous nesting\nprint(123)\n")
).isEmpty
)
)
XCTAssertEqual(violations, [])
}
}
func testSuperfluousDisableCommandsIgnoreDelimiter() {
func testSuperfluousDisableCommandsIgnoreDelimiter() async throws {
let longComment = "Comment with a large number of words that shouldn't register as superfluous"
XCTAssertEqual(
violations(Example("// swiftlint:disable nesting - \(longComment)\nprint(123)\n"))[0]
.ruleIdentifier,
"superfluous_disable_command"
)
XCTAssertEqual(
violations(Example("// swiftlint:disable:next nesting - Comment\nprint(123)\n"))[0]
.ruleIdentifier,
"superfluous_disable_command"
)
XCTAssertEqual(
violations(Example("print(123) // swiftlint:disable:this nesting - Comment\n"))[0]
.ruleIdentifier,
"superfluous_disable_command"
)
XCTAssertEqual(
violations(Example("print(123)\n// swiftlint:disable:previous nesting - Comment\n"))[0]
.ruleIdentifier,
"superfluous_disable_command"
)
do {
let first = try await violations(Example("// swiftlint:disable nesting - \(longComment)\nprint(123)\n"))[0]
XCTAssertEqual(first.ruleIdentifier, "superfluous_disable_command")
}
do {
let first = try await violations(Example("// swiftlint:disable:next nesting - Comment\nprint(123)\n"))[0]
XCTAssertEqual(first.ruleIdentifier, "superfluous_disable_command")
}
do {
let first = try await violations(Example("print(123) // swiftlint:disable:this nesting - Comment\n"))[0]
XCTAssertEqual(first.ruleIdentifier, "superfluous_disable_command")
}
do {
let first = try await violations(
Example("print(123)\n// swiftlint:disable:previous nesting - Comment\n")
)[0]
XCTAssertEqual(first.ruleIdentifier, "superfluous_disable_command")
}
}
func testInvalidDisableCommands() {
XCTAssertEqual(
violations(Example("// swiftlint:disable nesting_foo\nprint(123)\n"))[0]
.ruleIdentifier,
"superfluous_disable_command"
)
XCTAssertEqual(
violations(Example("// swiftlint:disable:next nesting_foo\nprint(123)\n"))[0]
.ruleIdentifier,
"superfluous_disable_command"
)
XCTAssertEqual(
violations(Example("print(123) // swiftlint:disable:this nesting_foo\n"))[0]
.ruleIdentifier,
"superfluous_disable_command"
)
XCTAssertEqual(
violations(Example("print(123)\n// swiftlint:disable:previous nesting_foo\n"))[0]
.ruleIdentifier,
"superfluous_disable_command"
)
func testInvalidDisableCommands() async throws {
do {
let first = try await violations(Example("// swiftlint:disable nesting_foo\nprint(123)\n"))[0]
XCTAssertEqual(first.ruleIdentifier, "superfluous_disable_command")
}
do {
let first = try await violations(Example("// swiftlint:disable:next nesting_foo\nprint(123)\n"))[0]
XCTAssertEqual(first.ruleIdentifier, "superfluous_disable_command")
}
do {
let first = try await violations(Example("print(123) // swiftlint:disable:this nesting_foo\n"))[0]
XCTAssertEqual(first.ruleIdentifier, "superfluous_disable_command")
}
do {
let first = try await violations(Example("print(123)\n// swiftlint:disable:previous nesting_foo\n"))[0]
XCTAssertEqual(first.ruleIdentifier, "superfluous_disable_command")
}
XCTAssertEqual(
violations(Example("print(123)\n// swiftlint:disable:previous nesting_foo \n")).count,
1
)
do {
let violations = try await violations(Example("print(123)\n// swiftlint:disable:previous nesting_foo \n"))
XCTAssertEqual(violations.count, 1)
}
let multipleViolations = violations(Example("// swiftlint:disable nesting this is a comment\n"))
let multipleViolations = try await violations(Example("// swiftlint:disable nesting this is a comment\n"))
XCTAssertEqual(multipleViolations.count, 5)
XCTAssertTrue(multipleViolations.allSatisfy { $0.ruleIdentifier == "superfluous_disable_command" })
let onlyNonExistentRulesViolations = violations(Example("// swiftlint:disable this is a comment\n"))
let onlyNonExistentRulesViolations = try await violations(Example("// swiftlint:disable this is a comment\n"))
XCTAssertEqual(onlyNonExistentRulesViolations.count, 4)
XCTAssertTrue(onlyNonExistentRulesViolations.allSatisfy {
$0.ruleIdentifier == "superfluous_disable_command"
})
XCTAssertEqual(
violations(Example("print(123)\n// swiftlint:disable:previous nesting_foo\n"))[0].reason,
"'nesting_foo' is not a valid SwiftLint rule; remove it from the disable command"
)
do {
let first = try await violations(Example("print(123)\n// swiftlint:disable:previous nesting_foo\n"))[0]
XCTAssertEqual(first.reason,
"'nesting_foo' is not a valid SwiftLint rule; remove it from the disable command")
}
XCTAssertEqual(violations(Example("/* swiftlint:disable nesting */\n")).count, 1)
do {
let violations = try await violations(Example("/* swiftlint:disable nesting */\n"))
XCTAssertEqual(violations.count, 1)
}
}
func testSuperfluousDisableCommandsDisabled() {
XCTAssertEqual(
violations(Example("// swiftlint:disable superfluous_disable_command nesting\nprint(123)\n")),
[]
)
XCTAssertEqual(
violations(Example("// swiftlint:disable superfluous_disable_command\n" +
"// swiftlint:disable nesting\n" +
"print(123)\n")),
[]
)
XCTAssertEqual(
violations(Example("// swiftlint:disable:next superfluous_disable_command nesting\nprint(123)\n")),
[]
)
XCTAssertEqual(
violations(Example("print(123) // swiftlint:disable:this superfluous_disable_command nesting\n")),
[]
)
XCTAssertEqual(
violations(Example("print(123)\n// swiftlint:disable:previous superfluous_disable_command nesting\n")),
[]
)
func testSuperfluousDisableCommandsDisabled() async throws {
do {
let violations = try await violations(
Example("// swiftlint:disable superfluous_disable_command nesting\nprint(123)\n")
)
XCTAssertEqual(violations, [])
}
do {
let violations = try await violations(
Example("// swiftlint:disable superfluous_disable_command\n" +
"// swiftlint:disable nesting\n" +
"print(123)\n")
)
XCTAssertEqual(
violations,
[]
)
}
do {
let violations = try await violations(
Example("// swiftlint:disable:next superfluous_disable_command nesting\nprint(123)\n")
)
XCTAssertEqual(violations, [])
}
do {
let violations = try await violations(
Example("print(123) // swiftlint:disable:this superfluous_disable_command nesting\n")
)
XCTAssertEqual(violations, [])
}
do {
let violations = try await violations(
Example("print(123)\n// swiftlint:disable:previous superfluous_disable_command nesting\n")
)
XCTAssertEqual(violations, [])
}
}
func testSuperfluousDisableCommandsDisabledOnConfiguration() {
func testSuperfluousDisableCommandsDisabledOnConfiguration() async throws {
let rulesMode = Configuration.RulesMode.default(disabled: ["superfluous_disable_command"], optIn: [])
let configuration = Configuration(rulesMode: rulesMode)
XCTAssertEqual(
violations(Example("// swiftlint:disable nesting\nprint(123)\n"), config: configuration),
[]
)
XCTAssertEqual(
violations(Example("// swiftlint:disable:next nesting\nprint(123)\n"), config: configuration),
[]
)
XCTAssertEqual(
violations(Example("print(123) // swiftlint:disable:this nesting\n"), config: configuration),
[]
)
XCTAssertEqual(
violations(Example("print(123)\n// swiftlint:disable:previous nesting\n"), config: configuration),
[]
)
do {
let violations = try await violations(
Example("// swiftlint:disable nesting\nprint(123)\n"), config: configuration
)
XCTAssertEqual(violations, [])
}
do {
let violations = try await violations(
Example("// swiftlint:disable:next nesting\nprint(123)\n"), config: configuration
)
XCTAssertEqual(violations, [])
}
do {
let violations = try await violations(
Example("print(123) // swiftlint:disable:this nesting\n"), config: configuration
)
XCTAssertEqual(violations, [])
}
do {
let violations = try await violations(
Example("print(123)\n// swiftlint:disable:previous nesting\n"), config: configuration
)
XCTAssertEqual(violations, [])
}
}
}

View File

@ -4,9 +4,9 @@ import XCTest
class CompilerProtocolInitRuleTests: XCTestCase {
private let ruleID = CompilerProtocolInitRule.description.identifier
func testViolationMessageForExpressibleByIntegerLiteral() throws {
func testViolationMessageForExpressibleByIntegerLiteral() async throws {
let config = try XCTUnwrap(makeConfig(nil, ruleID))
let allViolations = violations(Example("let a = NSNumber(integerLiteral: 1)"), config: config)
let allViolations = try await violations(Example("let a = NSNumber(integerLiteral: 1)"), config: config)
let compilerProtocolInitViolation = allViolations.first { $0.ruleIdentifier == ruleID }
let violation = try XCTUnwrap(

View File

@ -2,7 +2,7 @@
import XCTest
class ComputedAccessorsOrderRuleTests: XCTestCase {
func testSetGetConfiguration() {
func testSetGetConfiguration() async throws {
let nonTriggeringExamples = [
Example("""
class Foo {
@ -36,10 +36,10 @@ class ComputedAccessorsOrderRuleTests: XCTestCase {
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExamples)
verifyRule(description, ruleConfiguration: ["order": "set_get"])
try await verifyRule(description, ruleConfiguration: ["order": "set_get"])
}
func testGetSetPropertyReason() {
func testGetSetPropertyReason() async throws {
let example = Example("""
class Foo {
var foo: Int {
@ -53,13 +53,14 @@ class ComputedAccessorsOrderRuleTests: XCTestCase {
}
""")
let ruleViolations = try await ruleViolations(example)
XCTAssertEqual(
ruleViolations(example).first?.reason,
ruleViolations.first?.reason,
"Computed properties should first declare the getter and then the setter"
)
}
func testGetSetSubscriptReason() {
func testGetSetSubscriptReason() async throws {
let example = Example("""
class Foo {
subscript(i: Int) -> Int {
@ -73,13 +74,14 @@ class ComputedAccessorsOrderRuleTests: XCTestCase {
}
""")
let ruleViolations = try await ruleViolations(example)
XCTAssertEqual(
ruleViolations(example).first?.reason,
ruleViolations.first?.reason,
"Computed subscripts should first declare the getter and then the setter"
)
}
func testSetGetPropertyReason() {
func testSetGetPropertyReason() async throws {
let example = Example("""
class Foo {
var foo: Int {
@ -93,13 +95,14 @@ class ComputedAccessorsOrderRuleTests: XCTestCase {
}
""")
let ruleViolations = try await ruleViolations(example, ruleConfiguration: ["order": "set_get"])
XCTAssertEqual(
ruleViolations(example, ruleConfiguration: ["order": "set_get"]).first?.reason,
ruleViolations.first?.reason,
"Computed properties should first declare the setter and then the getter"
)
}
func testSetGetSubscriptReason() {
func testSetGetSubscriptReason() async throws {
let example = Example("""
class Foo {
subscript(i: Int) -> Int {
@ -113,17 +116,18 @@ class ComputedAccessorsOrderRuleTests: XCTestCase {
}
""")
let ruleViolations = try await ruleViolations(example, ruleConfiguration: ["order": "set_get"])
XCTAssertEqual(
ruleViolations(example, ruleConfiguration: ["order": "set_get"]).first?.reason,
ruleViolations.first?.reason,
"Computed subscripts should first declare the setter and then the getter"
)
}
private func ruleViolations(_ example: Example, ruleConfiguration: Any? = nil) -> [StyleViolation] {
private func ruleViolations(_ example: Example, ruleConfiguration: Any? = nil) async throws -> [StyleViolation] {
guard let config = makeConfig(ruleConfiguration, ComputedAccessorsOrderRule.description.identifier) else {
return []
}
return violations(example, config: config)
return try await violations(example, config: config)
}
}

View File

@ -2,7 +2,7 @@
import XCTest
class ConditionalReturnsOnNewlineRuleTests: XCTestCase {
func testConditionalReturnsOnNewlineWithIfOnly() {
func testConditionalReturnsOnNewlineWithIfOnly() async throws {
// Test with `if_only` set to true
let nonTriggeringExamples = [
Example("guard true else {\n return true\n}"),
@ -25,6 +25,6 @@ class ConditionalReturnsOnNewlineRuleTests: XCTestCase {
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExamples)
verifyRule(description, ruleConfiguration: ["if_only": true])
try await verifyRule(description, ruleConfiguration: ["if_only": true])
}
}

View File

@ -2,17 +2,17 @@
import XCTest
class ContainsOverFirstNotNilRuleTests: XCTestCase {
func testFirstReason() {
func testFirstReason() async throws {
let example = Example("↓myList.first { $0 % 2 == 0 } != nil")
let violations = self.violations(example)
let violations = try await self.violations(example)
XCTAssertEqual(violations.count, 1)
XCTAssertEqual(violations.first?.reason, "Prefer `contains` over `first(where:) != nil`")
}
func testFirstIndexReason() {
func testFirstIndexReason() async throws {
let example = Example("↓myList.firstIndex { $0 % 2 == 0 } != nil")
let violations = self.violations(example)
let violations = try await self.violations(example)
XCTAssertEqual(violations.count, 1)
XCTAssertEqual(violations.first?.reason, "Prefer `contains` over `firstIndex(where:) != nil`")
@ -20,11 +20,11 @@ class ContainsOverFirstNotNilRuleTests: XCTestCase {
// MARK: - Private
private func violations(_ example: Example, config: Any? = nil) -> [StyleViolation] {
private func violations(_ example: Example, config: Any? = nil) async throws -> [StyleViolation] {
guard let config = makeConfig(config, ContainsOverFirstNotNilRule.description.identifier) else {
return []
}
return SwiftLintFrameworkTests.violations(example, config: config)
return try await SwiftLintFrameworkTests.violations(example, config: config)
}
}

View File

@ -99,77 +99,80 @@ class CustomRulesTests: XCTestCase {
XCTAssertEqual(identifier, "my_custom_rule")
}
func testCustomRules() {
func testCustomRules() async throws {
let (regexConfig, customRules) = getCustomRules()
let file = SwiftLintFile(contents: "// My file with\n// a pattern")
XCTAssertEqual(customRules.validate(file: file),
let violations = try await customRules.validate(file: file)
XCTAssertEqual(violations,
[StyleViolation(ruleDescription: regexConfig.description,
severity: .warning,
location: Location(file: nil, line: 2, character: 6),
reason: regexConfig.message)])
}
func testLocalDisableCustomRule() {
func testLocalDisableCustomRule() async throws {
let (_, customRules) = getCustomRules()
let file = SwiftLintFile(contents: "//swiftlint:disable custom \n// file with a pattern")
XCTAssertEqual(customRules.validate(file: file), [])
let violations = try await customRules.validate(file: file)
XCTAssertEqual(violations, [])
}
func testLocalDisableCustomRuleWithMultipleRules() {
func testLocalDisableCustomRuleWithMultipleRules() async throws {
let (configs, customRules) = getCustomRulesWithTwoRules()
let file = SwiftLintFile(contents: "//swiftlint:disable \(configs.1.identifier) \n// file with a pattern")
XCTAssertEqual(customRules.validate(file: file),
let violations = try await customRules.validate(file: file)
XCTAssertEqual(violations,
[StyleViolation(ruleDescription: configs.0.description,
severity: .warning,
location: Location(file: nil, line: 2, character: 16),
reason: configs.0.message)])
}
func testCustomRulesIncludedDefault() {
func testCustomRulesIncludedDefault() async throws {
// Violation detected when included is omitted.
let (_, customRules) = getCustomRules()
let violations = customRules.validate(file: getTestTextFile())
let violations = try await customRules.validate(file: getTestTextFile())
XCTAssertEqual(violations.count, 1)
}
func testCustomRulesIncludedExcludesFile() {
func testCustomRulesIncludedExcludesFile() async throws {
var (regexConfig, customRules) = getCustomRules(["included": "\\.yml$"])
var customRuleConfiguration = CustomRulesConfiguration()
customRuleConfiguration.customRuleConfigurations = [regexConfig]
customRules.configuration = customRuleConfiguration
let violations = customRules.validate(file: getTestTextFile())
let violations = try await customRules.validate(file: getTestTextFile())
XCTAssertEqual(violations.count, 0)
}
func testCustomRulesExcludedExcludesFile() {
func testCustomRulesExcludedExcludesFile() async throws {
var (regexConfig, customRules) = getCustomRules(["excluded": "\\.txt$"])
var customRuleConfiguration = CustomRulesConfiguration()
customRuleConfiguration.customRuleConfigurations = [regexConfig]
customRules.configuration = customRuleConfiguration
let violations = customRules.validate(file: getTestTextFile())
let violations = try await customRules.validate(file: getTestTextFile())
XCTAssertEqual(violations.count, 0)
}
func testCustomRulesExcludedArrayExcludesFile() {
func testCustomRulesExcludedArrayExcludesFile() async throws {
var (regexConfig, customRules) = getCustomRules(["excluded": ["\\.pdf$", "\\.txt$"]])
var customRuleConfiguration = CustomRulesConfiguration()
customRuleConfiguration.customRuleConfigurations = [regexConfig]
customRules.configuration = customRuleConfiguration
let violations = customRules.validate(file: getTestTextFile())
let violations = try await customRules.validate(file: getTestTextFile())
XCTAssertEqual(violations.count, 0)
}
func testCustomRulesCaptureGroup() {
func testCustomRulesCaptureGroup() async throws {
let (_, customRules) = getCustomRules(["regex": #"\ba\s+(\w+)"#,
"capture_group": 1])
let violations = customRules.validate(file: getTestTextFile())
let violations = try await customRules.validate(file: getTestTextFile())
XCTAssertEqual(violations.count, 1)
XCTAssertEqual(violations[0].location.line, 2)
XCTAssertEqual(violations[0].location.character, 6)

View File

@ -30,11 +30,12 @@ class CyclomaticComplexityRuleTests: XCTestCase {
return Example(example)
}()
func testCyclomaticComplexity() {
verifyRule(CyclomaticComplexityRule.description, commentDoesntViolate: true, stringDoesntViolate: true)
func testCyclomaticComplexity() async throws {
try await verifyRule(CyclomaticComplexityRule.description, commentDoesntViolate: true,
stringDoesntViolate: true)
}
func testIgnoresCaseStatementsConfigurationEnabled() {
func testIgnoresCaseStatementsConfigurationEnabled() async throws {
let baseDescription = CyclomaticComplexityRule.description
let triggeringExamples = [complexIfExample]
let nonTriggeringExamples = baseDescription.nonTriggeringExamples + [complexSwitchExample]
@ -42,11 +43,11 @@ class CyclomaticComplexityRuleTests: XCTestCase {
let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples)
.with(triggeringExamples: triggeringExamples)
verifyRule(description, ruleConfiguration: ["ignores_case_statements": true],
commentDoesntViolate: true, stringDoesntViolate: true)
try await verifyRule(description, ruleConfiguration: ["ignores_case_statements": true],
commentDoesntViolate: true, stringDoesntViolate: true)
}
func testIgnoresCaseStatementsConfigurationDisabled() {
func testIgnoresCaseStatementsConfigurationDisabled() async throws {
let baseDescription = CyclomaticComplexityRule.description
let triggeringExamples = baseDescription.triggeringExamples + [complexSwitchExample]
let nonTriggeringExamples = baseDescription.nonTriggeringExamples
@ -54,7 +55,7 @@ class CyclomaticComplexityRuleTests: XCTestCase {
let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples)
.with(triggeringExamples: triggeringExamples)
verifyRule(description, ruleConfiguration: ["ignores_case_statements": false],
commentDoesntViolate: true, stringDoesntViolate: true)
try await verifyRule(description, ruleConfiguration: ["ignores_case_statements": false],
commentDoesntViolate: true, stringDoesntViolate: true)
}
}

View File

@ -2,9 +2,9 @@
import XCTest
class DeploymentTargetRuleTests: XCTestCase {
func testMacOSAttributeReason() {
func testMacOSAttributeReason() async throws {
let example = Example("@available(macOS 10.11, *)\nclass A {}")
let violations = self.violations(example, config: ["macOS_deployment_target": "10.14.0"])
let violations = try await self.violations(example, config: ["macOS_deployment_target": "10.14.0"])
let expectedMessage = "Availability attribute is using a version (10.11) that is satisfied by " +
"the deployment target (10.14) for platform macOS"
@ -12,9 +12,9 @@ class DeploymentTargetRuleTests: XCTestCase {
XCTAssertEqual(violations.first?.reason, expectedMessage)
}
func testWatchOSConditionReason() {
func testWatchOSConditionReason() async throws {
let example = Example("if #available(watchOS 4, *) {}")
let violations = self.violations(example, config: ["watchOS_deployment_target": "5.0.1"])
let violations = try await self.violations(example, config: ["watchOS_deployment_target": "5.0.1"])
let expectedMessage = "Availability condition is using a version (4) that is satisfied by " +
"the deployment target (5.0.1) for platform watchOS"
@ -22,11 +22,11 @@ class DeploymentTargetRuleTests: XCTestCase {
XCTAssertEqual(violations.first?.reason, expectedMessage)
}
func testiOSNegativeAttributeReason() throws {
func testiOSNegativeAttributeReason() async throws {
try XCTSkipUnless(SwiftVersion.current >= .fiveDotSix)
let example = Example("if #unavailable(iOS 14) { legacyImplementation() }")
let violations = self.violations(example, config: ["iOS_deployment_target": "15.0"])
let violations = try await self.violations(example, config: ["iOS_deployment_target": "15.0"])
let expectedMessage = "Availability negative condition is using a version (14) that is satisfied by " +
"the deployment target (15.0) for platform iOS"
@ -34,11 +34,11 @@ class DeploymentTargetRuleTests: XCTestCase {
XCTAssertEqual(violations.first?.reason, expectedMessage)
}
private func violations(_ example: Example, config: Any?) -> [StyleViolation] {
private func violations(_ example: Example, config: Any?) async throws -> [StyleViolation] {
guard let config = makeConfig(config, DeploymentTargetRule.description.identifier) else {
return []
}
return SwiftLintFrameworkTests.violations(example, config: config)
return try await SwiftLintFrameworkTests.violations(example, config: config)
}
}

View File

@ -11,10 +11,11 @@ class DisableAllTests: XCTestCase {
// MARK: Violating Phrase
/// Tests whether example violating phrases trigger when not applying disable rule
func testViolatingPhrase() {
func testViolatingPhrase() async throws {
for violatingPhrase in violatingPhrases {
let violations = try await violations(violatingPhrase.with(code: violatingPhrase.code + "\n"))
XCTAssertEqual(
violations(violatingPhrase.with(code: violatingPhrase.code + "\n")).count,
violations.count,
1,
#function,
file: violatingPhrase.file,
@ -24,11 +25,12 @@ class DisableAllTests: XCTestCase {
// MARK: Enable / Disable Base
/// Tests whether swiftlint:disable all protects properly
func testDisableAll() {
func testDisableAll() async throws {
for violatingPhrase in violatingPhrases {
let protectedPhrase = violatingPhrase.with(code: "// swiftlint:disable all\n" + violatingPhrase.code)
let violations = try await violations(protectedPhrase)
XCTAssertEqual(
violations(protectedPhrase).count,
violations.count,
0,
#function,
file: violatingPhrase.file,
@ -37,7 +39,7 @@ class DisableAllTests: XCTestCase {
}
/// Tests whether swiftlint:enable all unprotects properly
func testEnableAll() {
func testEnableAll() async throws {
for violatingPhrase in violatingPhrases {
let unprotectedPhrase = violatingPhrase.with(code: """
// swiftlint:disable all
@ -45,8 +47,9 @@ class DisableAllTests: XCTestCase {
// swiftlint:enable all
\(violatingPhrase.code)\n
""")
let violations = try await violations(unprotectedPhrase)
XCTAssertEqual(
violations(unprotectedPhrase).count,
violations.count,
1,
#function,
file: violatingPhrase.file,
@ -56,15 +59,16 @@ class DisableAllTests: XCTestCase {
// MARK: Enable / Disable Previous
/// Tests whether swiftlint:disable:previous all protects properly
func testDisableAllPrevious() {
func testDisableAllPrevious() async throws {
for violatingPhrase in violatingPhrases {
let protectedPhrase = violatingPhrase
.with(code: """
\(violatingPhrase.code)
// swiftlint:disable:previous all\n
""")
let violations = try await violations(protectedPhrase)
XCTAssertEqual(
violations(protectedPhrase).count,
violations.count,
0,
#function,
file: violatingPhrase.file,
@ -73,7 +77,7 @@ class DisableAllTests: XCTestCase {
}
/// Tests whether swiftlint:enable:previous all unprotects properly
func testEnableAllPrevious() {
func testEnableAllPrevious() async throws {
for violatingPhrase in violatingPhrases {
let unprotectedPhrase = violatingPhrase.with(code: """
// swiftlint:disable all
@ -81,8 +85,9 @@ class DisableAllTests: XCTestCase {
\(violatingPhrase.code)
// swiftlint:enable:previous all\n
""")
let violations = try await violations(unprotectedPhrase)
XCTAssertEqual(
violations(unprotectedPhrase).count,
violations.count,
1,
#function,
file: violatingPhrase.file,
@ -92,11 +97,12 @@ class DisableAllTests: XCTestCase {
// MARK: Enable / Disable Next
/// Tests whether swiftlint:disable:next all protects properly
func testDisableAllNext() {
func testDisableAllNext() async throws {
for violatingPhrase in violatingPhrases {
let protectedPhrase = violatingPhrase.with(code: "// swiftlint:disable:next all\n" + violatingPhrase.code)
let violations = try await violations(protectedPhrase)
XCTAssertEqual(
violations(protectedPhrase).count,
violations.count,
0,
#function,
file: violatingPhrase.file,
@ -105,7 +111,7 @@ class DisableAllTests: XCTestCase {
}
/// Tests whether swiftlint:enable:next all unprotects properly
func testEnableAllNext() {
func testEnableAllNext() async throws {
for violatingPhrase in violatingPhrases {
let unprotectedPhrase = violatingPhrase.with(code: """
// swiftlint:disable all
@ -113,8 +119,9 @@ class DisableAllTests: XCTestCase {
// swiftlint:enable:next all
\(violatingPhrase.code)\n
""")
let violations = try await violations(unprotectedPhrase)
XCTAssertEqual(
violations(unprotectedPhrase).count,
violations.count,
1,
#function,
file: violatingPhrase.file,
@ -124,12 +131,13 @@ class DisableAllTests: XCTestCase {
// MARK: Enable / Disable This
/// Tests whether swiftlint:disable:this all protects properly
func testDisableAllThis() {
func testDisableAllThis() async throws {
for violatingPhrase in violatingPhrases {
let rawViolatingPhrase = violatingPhrase.code.replacingOccurrences(of: "\n", with: "")
let protectedPhrase = violatingPhrase.with(code: rawViolatingPhrase + "// swiftlint:disable:this all\n")
let violations = try await violations(protectedPhrase)
XCTAssertEqual(
violations(protectedPhrase).count,
violations.count,
0,
#function,
file: violatingPhrase.file,
@ -138,7 +146,7 @@ class DisableAllTests: XCTestCase {
}
/// Tests whether swiftlint:enable:next all unprotects properly
func testEnableAllThis() {
func testEnableAllThis() async throws {
for violatingPhrase in violatingPhrases {
let rawViolatingPhrase = violatingPhrase.code.replacingOccurrences(of: "\n", with: "")
let unprotectedPhrase = violatingPhrase.with(code: """
@ -146,8 +154,9 @@ class DisableAllTests: XCTestCase {
\(violatingPhrase.code)
\(rawViolatingPhrase)// swiftlint:enable:this all\n"
""")
let violations = try await violations(unprotectedPhrase)
XCTAssertEqual(
violations(unprotectedPhrase).count,
violations.count,
1,
#function,
file: violatingPhrase.file,

View File

@ -4,11 +4,11 @@ import XCTest
class DiscouragedDirectInitRuleTests: XCTestCase {
private let baseDescription = DiscouragedDirectInitRule.description
func testDiscouragedDirectInitWithConfiguredSeverity() {
verifyRule(baseDescription, ruleConfiguration: ["severity": "error"])
func testDiscouragedDirectInitWithConfiguredSeverity() async throws {
try await verifyRule(baseDescription, ruleConfiguration: ["severity": "error"])
}
func testDiscouragedDirectInitWithNewIncludedTypes() {
func testDiscouragedDirectInitWithNewIncludedTypes() async throws {
let triggeringExamples = [
Example("let foo = ↓Foo()"),
Example("let bar = ↓Bar()")
@ -23,10 +23,10 @@ class DiscouragedDirectInitRuleTests: XCTestCase {
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExamples)
verifyRule(description, ruleConfiguration: ["types": ["Foo", "Bar"]])
try await verifyRule(description, ruleConfiguration: ["types": ["Foo", "Bar"]])
}
func testDiscouragedDirectInitWithReplacedTypes() {
func testDiscouragedDirectInitWithReplacedTypes() async throws {
let triggeringExamples = [
Example("let bundle = ↓Bundle()")
]
@ -39,6 +39,6 @@ class DiscouragedDirectInitRuleTests: XCTestCase {
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExamples)
verifyRule(description, ruleConfiguration: ["types": ["Bundle"]])
try await verifyRule(description, ruleConfiguration: ["types": ["Bundle"]])
}
}

View File

@ -2,7 +2,7 @@
import XCTest
class DiscouragedObjectLiteralRuleTests: XCTestCase {
func testWithImageLiteral() {
func testWithImageLiteral() async throws {
let baseDescription = DiscouragedObjectLiteralRule.description
let nonTriggeringExamples = baseDescription.nonTriggeringExamples + [
Example("let color = #colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1)")
@ -14,10 +14,10 @@ class DiscouragedObjectLiteralRuleTests: XCTestCase {
let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples,
triggeringExamples: triggeringExamples)
verifyRule(description, ruleConfiguration: ["image_literal": true, "color_literal": false])
try await verifyRule(description, ruleConfiguration: ["image_literal": true, "color_literal": false])
}
func testWithColorLiteral() {
func testWithColorLiteral() async throws {
let baseDescription = DiscouragedObjectLiteralRule.description
let nonTriggeringExamples = baseDescription.nonTriggeringExamples + [
Example("let image = #imageLiteral(resourceName: \"image.jpg\")")
@ -29,6 +29,6 @@ class DiscouragedObjectLiteralRuleTests: XCTestCase {
let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples,
triggeringExamples: triggeringExamples)
verifyRule(description, ruleConfiguration: ["image_literal": false, "color_literal": true])
try await verifyRule(description, ruleConfiguration: ["image_literal": false, "color_literal": true])
}
}

View File

@ -2,7 +2,7 @@
import XCTest
class EmptyCountRuleTests: XCTestCase {
func testEmptyCountWithOnlyAfterDot() {
func testEmptyCountWithOnlyAfterDot() async throws {
// Test with `only_after_dot` set to true
let nonTriggeringExamples = [
Example("var count = 0\n"),
@ -30,6 +30,6 @@ class EmptyCountRuleTests: XCTestCase {
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExamples)
verifyRule(description, ruleConfiguration: ["only_after_dot": true])
try await verifyRule(description, ruleConfiguration: ["only_after_dot": true])
}
}

View File

@ -10,49 +10,50 @@ class ExpiringTodoRuleTests: XCTestCase {
config = makeConfiguration()
}
func testExpiringTodo() {
verifyRule(ExpiringTodoRule.description, commentDoesntViolate: false)
func testExpiringTodo() async throws {
try await verifyRule(ExpiringTodoRule.description, commentDoesntViolate: false)
}
func testExpiredTodo() {
func testExpiredTodo() async throws {
let example = Example("fatalError() // TODO: [\(dateString(for: .expired))] Implement")
let violations = self.violations(example)
let violations = try await self.violations(example)
XCTAssertEqual(violations.count, 1)
XCTAssertEqual(violations.first!.reason, "TODO/FIXME has expired and must be resolved")
}
func testExpiredFixMe() {
func testExpiredFixMe() async throws {
let example = Example("fatalError() // FIXME: [\(dateString(for: .expired))] Implement")
let violations = self.violations(example)
let violations = try await self.violations(example)
XCTAssertEqual(violations.count, 1)
XCTAssertEqual(violations.first!.reason, "TODO/FIXME has expired and must be resolved")
}
func testApproachingExpiryTodo() {
func testApproachingExpiryTodo() async throws {
let example = Example("fatalError() // TODO: [\(dateString(for: .approachingExpiry))] Implement")
let violations = self.violations(example)
let violations = try await self.violations(example)
XCTAssertEqual(violations.count, 1)
XCTAssertEqual(violations.first!.reason, "TODO/FIXME is approaching its expiry and should be resolved soon")
}
func testNonExpiredTodo() {
func testNonExpiredTodo() async throws {
let example = Example("fatalError() // TODO: [\(dateString(for: nil))] Implement")
XCTAssertEqual(violations(example).count, 0)
let violations = try await violations(example)
XCTAssertEqual(violations, [])
}
func testExpiredCustomDelimiters() {
func testExpiredCustomDelimiters() async throws {
let ruleConfig: ExpiringTodoConfiguration = .init(
dateDelimiters: .init(opening: "<", closing: ">")
)
config = makeConfiguration(with: ruleConfig)
let example = Example("fatalError() // TODO: <\(dateString(for: .expired))> Implement")
let violations = self.violations(example)
let violations = try await self.violations(example)
XCTAssertEqual(violations.count, 1)
XCTAssertEqual(violations.first!.reason, "TODO/FIXME has expired and must be resolved")
}
func testExpiredCustomSeparator() {
func testExpiredCustomSeparator() async throws {
let ruleConfig: ExpiringTodoConfiguration = .init(
dateFormat: "MM-dd-yyyy",
dateSeparator: "-"
@ -60,31 +61,31 @@ class ExpiringTodoRuleTests: XCTestCase {
config = makeConfiguration(with: ruleConfig)
let example = Example("fatalError() // TODO: [\(dateString(for: .expired))] Implement")
let violations = self.violations(example)
let violations = try await self.violations(example)
XCTAssertEqual(violations.count, 1)
XCTAssertEqual(violations.first!.reason, "TODO/FIXME has expired and must be resolved")
}
func testExpiredCustomFormat() {
func testExpiredCustomFormat() async throws {
let ruleConfig: ExpiringTodoConfiguration = .init(
dateFormat: "yyyy/MM/dd"
)
config = makeConfiguration(with: ruleConfig)
let example = Example("fatalError() // TODO: [\(dateString(for: .expired))] Implement")
let violations = self.violations(example)
let violations = try await self.violations(example)
XCTAssertEqual(violations.count, 1)
XCTAssertEqual(violations.first!.reason, "TODO/FIXME has expired and must be resolved")
}
func testMultipleExpiredTodos() {
func testMultipleExpiredTodos() async throws {
let example = Example(
"""
fatalError() // TODO: [\(dateString(for: .expired))] Implement one
fatalError() // TODO: Implement two by [\(dateString(for: .expired))]
"""
)
let violations = self.violations(example)
let violations = try await self.violations(example)
XCTAssertEqual(violations.count, 2)
XCTAssertEqual(violations[0].reason, "TODO/FIXME has expired and must be resolved")
XCTAssertEqual(violations[0].location.line, 1)
@ -92,7 +93,7 @@ class ExpiringTodoRuleTests: XCTestCase {
XCTAssertEqual(violations[1].location.line, 2)
}
func testTodoAndExpiredTodo() {
func testTodoAndExpiredTodo() async throws {
let example = Example(
"""
// TODO: Implement one - without deadline
@ -100,13 +101,13 @@ class ExpiringTodoRuleTests: XCTestCase {
// TODO: Implement two by [\(dateString(for: .expired))]
"""
)
let violations = self.violations(example)
let violations = try await self.violations(example)
XCTAssertEqual(violations.count, 1)
XCTAssertEqual(violations[0].reason, "TODO/FIXME has expired and must be resolved")
XCTAssertEqual(violations[0].location.line, 3)
}
func testMultilineExpiredTodo() {
func testMultilineExpiredTodo() async throws {
let example = Example(
"""
// TODO: Multi-line task
@ -115,39 +116,39 @@ class ExpiringTodoRuleTests: XCTestCase {
// severity: fatal
"""
)
let violations = self.violations(example)
let violations = try await self.violations(example)
XCTAssertEqual(violations.count, 1)
XCTAssertEqual(violations[0].reason, "TODO/FIXME has expired and must be resolved")
XCTAssertEqual(violations[0].location.line, 3)
}
func testTodoFunctionAndExpiredTodo() {
func testTodoFunctionAndExpiredTodo() async throws {
let example = Example(
"""
TODO()
// TODO: Implement two by [\(dateString(for: .expired))]
"""
)
let violations = self.violations(example)
let violations = try await self.violations(example)
XCTAssertEqual(violations.count, 1)
XCTAssertEqual(violations[0].reason, "TODO/FIXME has expired and must be resolved")
XCTAssertEqual(violations[0].location.line, 2)
}
func testBadExpiryTodoFormat() throws {
func testBadExpiryTodoFormat() async throws {
let ruleConfig: ExpiringTodoConfiguration = .init(
dateFormat: "dd/yyyy/MM"
)
config = makeConfiguration(with: ruleConfig)
let example = Example("fatalError() // TODO: [31/01/2020] Implement")
let violations = self.violations(example)
let violations = try await self.violations(example)
XCTAssertEqual(violations.count, 1)
XCTAssertEqual(violations.first?.reason, "Expiring TODO/FIXME is incorrectly formatted")
}
private func violations(_ example: Example) -> [StyleViolation] {
return SwiftLintFrameworkTests.violations(example, config: config)
private func violations(_ example: Example) async throws -> [StyleViolation] {
return try await SwiftLintFrameworkTests.violations(example, config: config)
}
private func dateString(for status: ExpiringTodoRule.ExpiryViolationLevel?) -> String {

View File

@ -2,7 +2,7 @@
import XCTest
class ExplicitTypeInterfaceRuleTests: XCTestCase {
func testLocalVars() {
func testLocalVars() async throws {
let nonTriggeringExamples = [
Example("func foo() {\nlet intVal: Int = 1\n}"),
Example("""
@ -27,10 +27,10 @@ class ExplicitTypeInterfaceRuleTests: XCTestCase {
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExamples)
verifyRule(description)
try await verifyRule(description)
}
func testExcludeLocalVars() {
func testExcludeLocalVars() async throws {
let nonTriggeringExamples = ExplicitTypeInterfaceRule.description.nonTriggeringExamples + [
Example("func foo() {\nlet intVal = 1\n}")
]
@ -39,10 +39,10 @@ class ExplicitTypeInterfaceRuleTests: XCTestCase {
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExamples)
verifyRule(description, ruleConfiguration: ["excluded": ["local"]])
try await verifyRule(description, ruleConfiguration: ["excluded": ["local"]])
}
func testExcludeClassVars() {
func testExcludeClassVars() async throws {
let nonTriggeringExamples = ExplicitTypeInterfaceRule.description.nonTriggeringExamples + [
Example("class Foo {\n static var myStaticVar = 0\n}\n"),
Example("class Foo {\n static let myStaticLet = 0\n}\n")
@ -56,10 +56,10 @@ class ExplicitTypeInterfaceRuleTests: XCTestCase {
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExamples)
verifyRule(description, ruleConfiguration: ["excluded": ["static"]])
try await verifyRule(description, ruleConfiguration: ["excluded": ["static"]])
}
func testAllowRedundancy() {
func testAllowRedundancy() async throws {
let nonTriggeringExamples: [Example] = [
Example("class Foo {\n var myVar: Int? = 0\n}\n"),
Example("class Foo {\n let myVar: Int? = 0\n}\n"),
@ -87,10 +87,10 @@ class ExplicitTypeInterfaceRuleTests: XCTestCase {
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExamples)
verifyRule(description, ruleConfiguration: ["allow_redundancy": true])
try await verifyRule(description, ruleConfiguration: ["allow_redundancy": true])
}
func testEmbeddedInStatements() {
func testEmbeddedInStatements() async throws {
let nonTriggeringExamples = [
Example("""
func foo() {
@ -114,10 +114,10 @@ class ExplicitTypeInterfaceRuleTests: XCTestCase {
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExamples)
verifyRule(description)
try await verifyRule(description)
}
func testCaptureGroup() {
func testCaptureGroup() async throws {
let nonTriggeringExamples = [
Example("""
var k: Int = 0
@ -147,10 +147,10 @@ class ExplicitTypeInterfaceRuleTests: XCTestCase {
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExamples)
verifyRule(description)
try await verifyRule(description)
}
func testFastEnumerationDeclaration() {
func testFastEnumerationDeclaration() async throws {
let nonTriggeringExaples = [
Example("""
func foo() {
@ -170,10 +170,10 @@ class ExplicitTypeInterfaceRuleTests: XCTestCase {
let description = ExplicitTypeInterfaceRule.description
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExaples)
verifyRule(description)
try await verifyRule(description)
}
func testSwitchCaseDeclarations() {
func testSwitchCaseDeclarations() async throws {
let nonTriggeringExamples = [
Example("""
enum Foo {
@ -233,6 +233,6 @@ class ExplicitTypeInterfaceRuleTests: XCTestCase {
let description = ExplicitTypeInterfaceRule.description
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExamples)
verifyRule(description)
try await verifyRule(description)
}
}

View File

@ -4,17 +4,17 @@ import XCTest
private let fixturesDirectory = "\(TestResources.path)/FileHeaderRuleFixtures"
class FileHeaderRuleTests: XCTestCase {
private func validate(fileName: String, using configuration: Any) throws -> [StyleViolation] {
private func validate(fileName: String, using configuration: Any) async throws -> [StyleViolation] {
let file = SwiftLintFile(path: fixturesDirectory.stringByAppendingPathComponent(fileName))!
let rule = try FileHeaderRule(configuration: configuration)
return rule.validate(file: file)
return try await rule.validate(file: file)
}
func testFileHeaderWithDefaultConfiguration() {
verifyRule(FileHeaderRule.description, skipCommentTests: true)
func testFileHeaderWithDefaultConfiguration() async throws {
try await verifyRule(FileHeaderRule.description, skipCommentTests: true)
}
func testFileHeaderWithRequiredString() {
func testFileHeaderWithRequiredString() async throws {
let nonTriggeringExamples = [
Example("// **Header"),
Example("//\n// **Header")
@ -30,12 +30,12 @@ class FileHeaderRuleTests: XCTestCase {
.with(nonTriggeringExamples: nonTriggeringExamples)
.with(triggeringExamples: triggeringExamples)
verifyRule(description, ruleConfiguration: ["required_string": "**Header"],
stringDoesntViolate: false, skipCommentTests: true,
testMultiByteOffsets: false, testShebang: false)
try await verifyRule(description, ruleConfiguration: ["required_string": "**Header"],
stringDoesntViolate: false, skipCommentTests: true,
testMultiByteOffsets: false, testShebang: false)
}
func testFileHeaderWithRequiredPattern() {
func testFileHeaderWithRequiredPattern() async throws {
let nonTriggeringExamples = [
Example("// Copyright © 2016 Realm"),
Example("//\n// Copyright © 2016 Realm)")
@ -49,12 +49,12 @@ class FileHeaderRuleTests: XCTestCase {
.with(nonTriggeringExamples: nonTriggeringExamples)
.with(triggeringExamples: triggeringExamples)
verifyRule(description, ruleConfiguration: ["required_pattern": "\\d{4} Realm"],
stringDoesntViolate: false, skipCommentTests: true,
testMultiByteOffsets: false)
try await verifyRule(description, ruleConfiguration: ["required_pattern": "\\d{4} Realm"],
stringDoesntViolate: false, skipCommentTests: true,
testMultiByteOffsets: false)
}
func testFileHeaderWithRequiredStringAndURLComment() {
func testFileHeaderWithRequiredStringAndURLComment() async throws {
let nonTriggeringExamples = [
Example("/* Check this url: https://github.com/realm/SwiftLint */")
]
@ -66,12 +66,12 @@ class FileHeaderRuleTests: XCTestCase {
.with(triggeringExamples: triggeringExamples)
let config = ["required_string": "/* Check this url: https://github.com/realm/SwiftLint */"]
verifyRule(description, ruleConfiguration: config,
stringDoesntViolate: false, skipCommentTests: true,
testMultiByteOffsets: false)
try await verifyRule(description, ruleConfiguration: config,
stringDoesntViolate: false, skipCommentTests: true,
testMultiByteOffsets: false)
}
func testFileHeaderWithForbiddenString() {
func testFileHeaderWithForbiddenString() async throws {
let nonTriggeringExamples = [
Example("// Copyright\n"),
Example("let foo = \"**All rights reserved.\""),
@ -87,11 +87,11 @@ class FileHeaderRuleTests: XCTestCase {
.with(nonTriggeringExamples: nonTriggeringExamples)
.with(triggeringExamples: triggeringExamples)
verifyRule(description, ruleConfiguration: ["forbidden_string": "**All rights reserved."],
skipCommentTests: true)
try await verifyRule(description, ruleConfiguration: ["forbidden_string": "**All rights reserved."],
skipCommentTests: true)
}
func testFileHeaderWithForbiddenPattern() {
func testFileHeaderWithForbiddenPattern() async throws {
let nonTriggeringExamples = [
Example("// Copyright\n"),
Example("// FileHeaderRuleTests.m\n"),
@ -107,11 +107,11 @@ class FileHeaderRuleTests: XCTestCase {
.with(nonTriggeringExamples: nonTriggeringExamples)
.with(triggeringExamples: triggeringExamples)
verifyRule(description, ruleConfiguration: ["forbidden_pattern": "\\s\\w+\\.swift"],
skipCommentTests: true)
try await verifyRule(description, ruleConfiguration: ["forbidden_pattern": "\\s\\w+\\.swift"],
skipCommentTests: true)
}
func testFileHeaderWithForbiddenPatternAndDocComment() {
func testFileHeaderWithForbiddenPatternAndDocComment() async throws {
let nonTriggeringExamples = [
Example("/// This is great tool with tests.\nclass GreatTool {}"),
Example("class GreatTool {}")
@ -124,64 +124,127 @@ class FileHeaderRuleTests: XCTestCase {
.with(nonTriggeringExamples: nonTriggeringExamples)
.with(triggeringExamples: triggeringExamples)
verifyRule(description, ruleConfiguration: ["forbidden_pattern": "[tT]ests"],
skipCommentTests: true, testMultiByteOffsets: false)
try await verifyRule(description, ruleConfiguration: ["forbidden_pattern": "[tT]ests"],
skipCommentTests: true, testMultiByteOffsets: false)
}
func testFileHeaderWithRequiredStringUsingFilenamePlaceholder() {
func testFileHeaderWithRequiredStringUsingFilenamePlaceholder() async throws {
let configuration = ["required_string": "// SWIFTLINT_CURRENT_FILENAME"]
// Non triggering tests
XCTAssert(try validate(fileName: "FileNameMatchingSimple.swift", using: configuration).isEmpty)
do {
let violations = try await validate(fileName: "FileNameMatchingSimple.swift", using: configuration)
XCTAssert(violations.isEmpty)
}
// Triggering tests
XCTAssertEqual(try validate(fileName: "FileNameCaseMismatch.swift", using: configuration).count, 1)
XCTAssertEqual(try validate(fileName: "FileNameMismatch.swift", using: configuration).count, 1)
XCTAssertEqual(try validate(fileName: "FileNameMissing.swift", using: configuration).count, 1)
do {
let violations = try await validate(fileName: "FileNameCaseMismatch.swift", using: configuration)
XCTAssertEqual(violations.count, 1)
}
do {
let violations = try await validate(fileName: "FileNameMismatch.swift", using: configuration)
XCTAssertEqual(violations.count, 1)
}
do {
let violations = try await validate(fileName: "FileNameMissing.swift", using: configuration)
XCTAssertEqual(violations.count, 1)
}
}
func testFileHeaderWithForbiddenStringUsingFilenamePlaceholder() {
func testFileHeaderWithForbiddenStringUsingFilenamePlaceholder() async throws {
let configuration = ["forbidden_string": "// SWIFTLINT_CURRENT_FILENAME"]
// Non triggering tests
XCTAssert(try validate(fileName: "FileNameCaseMismatch.swift", using: configuration).isEmpty)
XCTAssert(try validate(fileName: "FileNameMismatch.swift", using: configuration).isEmpty)
XCTAssert(try validate(fileName: "FileNameMissing.swift", using: configuration).isEmpty)
do {
let violations = try await validate(fileName: "FileNameCaseMismatch.swift", using: configuration)
XCTAssert(violations.isEmpty)
}
do {
let violations = try await validate(fileName: "FileNameMismatch.swift", using: configuration)
XCTAssert(violations.isEmpty)
}
do {
let violations = try await validate(fileName: "FileNameMissing.swift", using: configuration)
XCTAssert(violations.isEmpty)
}
// Triggering tests
XCTAssertEqual(try validate(fileName: "FileNameMatchingSimple.swift", using: configuration).count, 1)
do {
let violations = try await validate(fileName: "FileNameMatchingSimple.swift", using: configuration)
XCTAssertEqual(violations.count, 1)
}
}
func testFileHeaderWithRequiredPatternUsingFilenamePlaceholder() {
func testFileHeaderWithRequiredPatternUsingFilenamePlaceholder() async throws {
let configuration1 = ["required_pattern": "// SWIFTLINT_CURRENT_FILENAME\n.*\\d{4}"]
let configuration2 = ["required_pattern":
"// Copyright © \\d{4}\n// File: \"SWIFTLINT_CURRENT_FILENAME\""]
// Non triggering tests
XCTAssert(try validate(fileName: "FileNameMatchingSimple.swift", using: configuration1).isEmpty)
XCTAssert(try validate(fileName: "FileNameMatchingComplex.swift", using: configuration2).isEmpty)
do {
let violations = try await validate(fileName: "FileNameMatchingSimple.swift", using: configuration1)
XCTAssert(violations.isEmpty)
}
do {
let violations = try await validate(fileName: "FileNameMatchingComplex.swift", using: configuration2)
XCTAssert(violations.isEmpty)
}
// Triggering tests
XCTAssertEqual(try validate(fileName: "FileNameCaseMismatch.swift", using: configuration1).count, 1)
XCTAssertEqual(try validate(fileName: "FileNameMismatch.swift", using: configuration1).count, 1)
XCTAssertEqual(try validate(fileName: "FileNameMissing.swift", using: configuration1).count, 1)
do {
let violations = try await validate(fileName: "FileNameCaseMismatch.swift", using: configuration1)
XCTAssertEqual(violations.count, 1)
}
do {
let violations = try await validate(fileName: "FileNameMismatch.swift", using: configuration1)
XCTAssertEqual(violations.count, 1)
}
do {
let violations = try await validate(fileName: "FileNameMissing.swift", using: configuration1)
XCTAssertEqual(violations.count, 1)
}
}
func testFileHeaderWithForbiddenPatternUsingFilenamePlaceholder() {
func testFileHeaderWithForbiddenPatternUsingFilenamePlaceholder() async throws {
let configuration1 = ["forbidden_pattern": "// SWIFTLINT_CURRENT_FILENAME\n.*\\d{4}"]
let configuration2 = ["forbidden_pattern": "//.*(\\s|\")SWIFTLINT_CURRENT_FILENAME(\\s|\").*"]
// Non triggering tests
XCTAssert(try validate(fileName: "FileNameCaseMismatch.swift", using: configuration1).isEmpty)
XCTAssert(try validate(fileName: "FileNameMismatch.swift", using: configuration1).isEmpty)
XCTAssert(try validate(fileName: "FileNameMissing.swift", using: configuration1).isEmpty)
do {
let violations = try await validate(fileName: "FileNameCaseMismatch.swift", using: configuration1)
XCTAssert(violations.isEmpty)
}
do {
let violations = try await validate(fileName: "FileNameMismatch.swift", using: configuration1)
XCTAssert(violations.isEmpty)
}
do {
let violations = try await validate(fileName: "FileNameMissing.swift", using: configuration1)
XCTAssert(violations.isEmpty)
}
XCTAssert(try validate(fileName: "FileNameCaseMismatch.swift", using: configuration2).isEmpty)
XCTAssert(try validate(fileName: "FileNameMismatch.swift", using: configuration2).isEmpty)
XCTAssert(try validate(fileName: "FileNameMissing.swift", using: configuration2).isEmpty)
do {
let violations = try await validate(fileName: "FileNameCaseMismatch.swift", using: configuration2)
XCTAssert(violations.isEmpty)
}
do {
let violations = try await validate(fileName: "FileNameMismatch.swift", using: configuration2)
XCTAssert(violations.isEmpty)
}
do {
let violations = try await validate(fileName: "FileNameMissing.swift", using: configuration2)
XCTAssert(violations.isEmpty)
}
// Triggering tests
XCTAssertEqual(try validate(fileName: "FileNameMatchingSimple.swift", using: configuration1).count, 1)
XCTAssertEqual(try validate(fileName: "FileNameMatchingComplex.swift", using: configuration2).count, 1)
do {
let violations = try await validate(fileName: "FileNameMatchingSimple.swift", using: configuration1)
XCTAssertEqual(violations.count, 1)
}
do {
let violations = try await validate(fileName: "FileNameMatchingComplex.swift", using: configuration2)
XCTAssertEqual(violations.count, 1)
}
}
}

View File

@ -2,12 +2,12 @@
import XCTest
class FileLengthRuleTests: XCTestCase {
func testFileLengthWithDefaultConfiguration() {
verifyRule(FileLengthRule.description, commentDoesntViolate: false,
testMultiByteOffsets: false, testShebang: false)
func testFileLengthWithDefaultConfiguration() async throws {
try await verifyRule(FileLengthRule.description, commentDoesntViolate: false,
testMultiByteOffsets: false, testShebang: false)
}
func testFileLengthIgnoringLinesWithOnlyComments() {
func testFileLengthIgnoringLinesWithOnlyComments() async throws {
let triggeringExamples = [
Example(repeatElement("print(\"swiftlint\")\n", count: 401).joined())
]
@ -21,7 +21,7 @@ class FileLengthRuleTests: XCTestCase {
.with(nonTriggeringExamples: nonTriggeringExamples)
.with(triggeringExamples: triggeringExamples)
verifyRule(description, ruleConfiguration: ["ignore_comment_only_lines": true],
testMultiByteOffsets: false, testShebang: false)
try await verifyRule(description, ruleConfiguration: ["ignore_comment_only_lines": true],
testMultiByteOffsets: false, testShebang: false)
}
}

View File

@ -6,7 +6,7 @@ private let fixturesDirectory = "\(TestResources.path)/FileNameRuleFixtures"
class FileNameRuleTests: XCTestCase {
private func validate(fileName: String, excludedOverride: [String]? = nil,
prefixPattern: String? = nil, suffixPattern: String? = nil,
nestedTypeSeparator: String? = nil) throws -> [StyleViolation] {
nestedTypeSeparator: String? = nil) async throws -> [StyleViolation] {
let file = SwiftLintFile(path: fixturesDirectory.stringByAppendingPathComponent(fileName))!
let rule: FileNameRule
if let excluded = excludedOverride {
@ -23,81 +23,124 @@ class FileNameRuleTests: XCTestCase {
rule = FileNameRule()
}
return rule.validate(file: file)
return try await rule.validate(file: file)
}
func testMainDoesntTrigger() {
XCTAssert(try validate(fileName: "main.swift").isEmpty)
func testMainDoesntTrigger() async throws {
let violations = try await validate(fileName: "main.swift")
XCTAssert(violations.isEmpty)
}
func testLinuxMainDoesntTrigger() {
XCTAssert(try validate(fileName: "LinuxMain.swift").isEmpty)
func testLinuxMainDoesntTrigger() async throws {
let violations = try await validate(fileName: "LinuxMain.swift")
XCTAssert(violations.isEmpty)
}
func testClassNameDoesntTrigger() {
XCTAssert(try validate(fileName: "MyClass.swift").isEmpty)
func testClassNameDoesntTrigger() async throws {
let violations = try await validate(fileName: "MyClass.swift")
XCTAssert(violations.isEmpty)
}
func testStructNameDoesntTrigger() {
XCTAssert(try validate(fileName: "MyStruct.swift").isEmpty)
func testStructNameDoesntTrigger() async throws {
let violations = try await validate(fileName: "MyStruct.swift")
XCTAssert(violations.isEmpty)
}
func testExtensionNameDoesntTrigger() {
XCTAssert(try validate(fileName: "NSString+Extension.swift").isEmpty)
func testExtensionNameDoesntTrigger() async throws {
let violations = try await validate(fileName: "NSString+Extension.swift")
XCTAssert(violations.isEmpty)
}
func testNestedExtensionDoesntTrigger() {
XCTAssert(try validate(fileName: "Notification.Name+Extension.swift").isEmpty)
func testNestedExtensionDoesntTrigger() async throws {
let violations = try await validate(fileName: "Notification.Name+Extension.swift")
XCTAssert(violations.isEmpty)
}
func testNestedTypeSeparatorDoesntTrigger() {
XCTAssert(try validate(fileName: "NotificationName+Extension.swift", nestedTypeSeparator: "").isEmpty)
XCTAssert(try validate(fileName: "Notification__Name+Extension.swift", nestedTypeSeparator: "__").isEmpty)
func testNestedTypeSeparatorDoesntTrigger() async throws {
do {
let violations = try await validate(fileName: "NotificationName+Extension.swift",
nestedTypeSeparator: "")
XCTAssert(violations.isEmpty)
}
do {
let violations = try await validate(fileName: "Notification__Name+Extension.swift",
nestedTypeSeparator: "__")
XCTAssert(violations.isEmpty)
}
}
func testWrongNestedTypeSeparatorDoesTrigger() {
XCTAssert(try !validate(fileName: "Notification__Name+Extension.swift", nestedTypeSeparator: ".").isEmpty)
XCTAssert(try !validate(fileName: "NotificationName+Extension.swift", nestedTypeSeparator: "__").isEmpty)
func testWrongNestedTypeSeparatorDoesTrigger() async throws {
do {
let violations = try await validate(fileName: "Notification__Name+Extension.swift",
nestedTypeSeparator: ".")
XCTAssert(!violations.isEmpty)
}
do {
let violations = try await validate(fileName: "NotificationName+Extension.swift",
nestedTypeSeparator: "__")
XCTAssert(!violations.isEmpty)
}
}
func testMisspelledNameDoesTrigger() {
XCTAssertEqual(try validate(fileName: "MyStructf.swift").count, 1)
func testMisspelledNameDoesTrigger() async throws {
let violations = try await validate(fileName: "MyStructf.swift")
XCTAssertEqual(violations.count, 1)
}
func testMisspelledNameDoesntTriggerWithOverride() {
XCTAssert(try validate(fileName: "MyStructf.swift", excludedOverride: ["MyStructf.swift"]).isEmpty)
func testMisspelledNameDoesntTriggerWithOverride() async throws {
let violations = try await validate(fileName: "MyStructf.swift", excludedOverride: ["MyStructf.swift"])
XCTAssert(violations.isEmpty)
}
func testMainDoesTriggerWithoutOverride() {
XCTAssertEqual(try validate(fileName: "main.swift", excludedOverride: []).count, 1)
func testMainDoesTriggerWithoutOverride() async throws {
let violations = try await validate(fileName: "main.swift", excludedOverride: [])
XCTAssertEqual(violations.count, 1)
}
func testCustomSuffixPattern() {
XCTAssert(try validate(fileName: "BoolExtension.swift", suffixPattern: "Extensions?").isEmpty)
XCTAssert(try validate(fileName: "BoolExtensions.swift", suffixPattern: "Extensions?").isEmpty)
XCTAssert(try validate(fileName: "BoolExtensionTests.swift", suffixPattern: "Extensions?|\\+.*").isEmpty)
func testCustomSuffixPattern() async throws {
do {
let violations = try await validate(fileName: "BoolExtension.swift", suffixPattern: "Extensions?")
XCTAssert(violations.isEmpty)
}
do {
let violations = try await validate(fileName: "BoolExtensions.swift", suffixPattern: "Extensions?")
XCTAssert(violations.isEmpty)
}
do {
let violations = try await validate(fileName: "BoolExtensionTests.swift",
suffixPattern: "Extensions?|\\+.*")
XCTAssert(violations.isEmpty)
}
}
func testCustomPrefixPattern() {
XCTAssert(try validate(fileName: "ExtensionBool.swift", prefixPattern: "Extensions?").isEmpty)
XCTAssert(try validate(fileName: "ExtensionsBool.swift", prefixPattern: "Extensions?").isEmpty)
func testCustomPrefixPattern() async throws {
do {
let violations = try await validate(fileName: "ExtensionBool.swift", prefixPattern: "Extensions?")
XCTAssert(violations.isEmpty)
}
do {
let violations = try await validate(fileName: "ExtensionsBool.swift", prefixPattern: "Extensions?")
XCTAssert(violations.isEmpty)
}
}
func testCustomPrefixAndSuffixPatterns() {
XCTAssert(
try validate(
func testCustomPrefixAndSuffixPatterns() async throws {
do {
let violations = try await validate(
fileName: "SLBoolExtension.swift",
prefixPattern: "SL",
suffixPattern: "Extensions?|\\+.*"
).isEmpty
)
)
XCTAssertEqual(violations, [])
}
XCTAssert(
try validate(
do {
let violations = try await validate(
fileName: "ExtensionBool+SwiftLint.swift",
prefixPattern: "Extensions?",
suffixPattern: "Extensions?|\\+.*"
).isEmpty
)
)
XCTAssertEqual(violations, [])
}
}
}

View File

@ -3,7 +3,7 @@ import XCTest
class FileTypesOrderRuleTests: XCTestCase {
// swiftlint:disable:next function_body_length
func testFileTypesOrderReversedOrder() {
func testFileTypesOrderReversedOrder() async throws {
// Test with reversed `order` entries
let nonTriggeringExamples = [
Example(FileTypesOrderRuleExamples.defaultOrderParts.reversed().joined(separator: "\n\n"))
@ -74,7 +74,7 @@ class FileTypesOrderRuleTests: XCTestCase {
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExamples)
verifyRule(
try await verifyRule(
reversedOrderDescription,
ruleConfiguration: [
"order": ["library_content_provider", "preview_provider", "extension", "main_type", "supporting_type"]
@ -82,7 +82,7 @@ class FileTypesOrderRuleTests: XCTestCase {
)
}
func testFileTypesOrderGroupedOrder() {
func testFileTypesOrderGroupedOrder() async throws {
// Test with grouped `order` entries
let nonTriggeringExamples = [
Example("""
@ -140,7 +140,7 @@ class FileTypesOrderRuleTests: XCTestCase {
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExamples)
verifyRule(
try await verifyRule(
groupedOrderDescription,
ruleConfiguration: [
"order": ["main_type", ["extension", "supporting_type"], "preview_provider"]

View File

@ -14,76 +14,121 @@ private func violatingFuncWithBody(_ body: String, file: StaticString = #file, l
}
class FunctionBodyLengthRuleTests: XCTestCase {
func testFunctionBodyLengths() {
let longFunctionBody = funcWithBody(repeatElement("x = 0\n", count: 49).joined())
XCTAssertEqual(self.violations(longFunctionBody), [])
func testFunctionBodyLengths() async throws {
do {
let longFunctionBody = funcWithBody(repeatElement("x = 0\n", count: 49).joined())
let violations = try await self.violations(longFunctionBody)
XCTAssertEqual(violations, [])
}
let longerFunctionBody = violatingFuncWithBody(repeatElement("x = 0\n", count: 51).joined())
XCTAssertEqual(self.violations(longerFunctionBody), [StyleViolation(
ruleDescription: FunctionBodyLengthRule.description,
location: Location(file: nil, line: 1, character: 6),
reason: "Function body should span 50 lines or less excluding comments and " +
"whitespace: currently spans 51 lines")])
do {
let longerFunctionBody = violatingFuncWithBody(repeatElement("x = 0\n", count: 51).joined())
let violations = try await self.violations(longerFunctionBody)
XCTAssertEqual(violations, [StyleViolation(
ruleDescription: FunctionBodyLengthRule.description,
location: Location(file: nil, line: 1, character: 6),
reason: "Function body should span 50 lines or less excluding comments and " +
"whitespace: currently spans 51 lines")])
}
let longerFunctionBodyWithEmptyLines = funcWithBody(
repeatElement("\n", count: 100).joined()
)
XCTAssertEqual(self.violations(longerFunctionBodyWithEmptyLines), [])
do {
let longerFunctionBodyWithEmptyLines = funcWithBody(
repeatElement("\n", count: 100).joined()
)
let violations = try await self.violations(longerFunctionBodyWithEmptyLines)
XCTAssertEqual(violations, [])
}
}
func testFunctionBodyLengthsWithComments() {
let longFunctionBodyWithComments = funcWithBody(
repeatElement("x = 0\n", count: 49).joined() +
"// comment only line should be ignored.\n"
)
XCTAssertEqual(violations(longFunctionBodyWithComments), [])
func testFunctionBodyLengthsWithComments() async throws {
do {
let longFunctionBodyWithComments = funcWithBody(
repeatElement("x = 0\n", count: 49).joined() +
"// comment only line should be ignored.\n"
)
let violations = try await violations(longFunctionBodyWithComments)
XCTAssertEqual(violations, [])
}
let longerFunctionBodyWithComments = violatingFuncWithBody(
repeatElement("x = 0\n", count: 51).joined() +
"// comment only line should be ignored.\n"
)
XCTAssertEqual(self.violations(longerFunctionBodyWithComments), [StyleViolation(
ruleDescription: FunctionBodyLengthRule.description,
location: Location(file: nil, line: 1, character: 6),
reason: "Function body should span 50 lines or less excluding comments and " +
"whitespace: currently spans 51 lines")])
do {
let longerFunctionBodyWithComments = violatingFuncWithBody(
repeatElement("x = 0\n", count: 51).joined() +
"// comment only line should be ignored.\n"
)
let violations = try await self.violations(longerFunctionBodyWithComments)
XCTAssertEqual(violations, [StyleViolation(
ruleDescription: FunctionBodyLengthRule.description,
location: Location(file: nil, line: 1, character: 6),
reason: "Function body should span 50 lines or less excluding comments and " +
"whitespace: currently spans 51 lines")])
}
}
func testFunctionBodyLengthsWithMultilineComments() {
let longFunctionBodyWithMultilineComments = funcWithBody(
repeatElement("x = 0\n", count: 49).joined() +
"/* multi line comment only line should be ignored.\n*/\n"
)
XCTAssertEqual(self.violations(longFunctionBodyWithMultilineComments), [])
func testFunctionBodyLengthsWithMultilineComments() async throws {
do {
let longFunctionBodyWithMultilineComments = funcWithBody(
repeatElement("x = 0\n", count: 49).joined() +
"/* multi line comment only line should be ignored.\n*/\n"
)
let violations = try await self.violations(longFunctionBodyWithMultilineComments)
XCTAssertEqual(violations, [])
}
let longerFunctionBodyWithMultilineComments = violatingFuncWithBody(
repeatElement("x = 0\n", count: 51).joined() +
"/* multi line comment only line should be ignored.\n*/\n"
)
XCTAssertEqual(self.violations(longerFunctionBodyWithMultilineComments), [StyleViolation(
ruleDescription: FunctionBodyLengthRule.description,
location: Location(file: nil, line: 1, character: 6),
reason: "Function body should span 50 lines or less excluding comments and " +
"whitespace: currently spans 51 lines")])
do {
let longerFunctionBodyWithMultilineComments = violatingFuncWithBody(
repeatElement("x = 0\n", count: 51).joined() +
"/* multi line comment only line should be ignored.\n*/\n"
)
let violations = try await self.violations(longerFunctionBodyWithMultilineComments)
XCTAssertEqual(violations, [StyleViolation(
ruleDescription: FunctionBodyLengthRule.description,
location: Location(file: nil, line: 1, character: 6),
reason: "Function body should span 50 lines or less excluding comments and " +
"whitespace: currently spans 51 lines")])
}
}
func testConfiguration() {
func testConfiguration() async throws {
let function = violatingFuncWithBody(repeatElement("x = 0\n", count: 10).joined())
XCTAssertEqual(self.violations(function, configuration: ["warning": 12]).count, 0)
XCTAssertEqual(self.violations(function, configuration: ["warning": 12, "error": 14]).count, 0)
XCTAssertEqual(
self.violations(function, configuration: ["warning": 8]).map(\.reason),
["Function body should span 8 lines or less excluding comments and whitespace: currently spans 10 lines"]
)
XCTAssertEqual(
self.violations(function, configuration: ["warning": 12, "error": 8]).map(\.reason),
["Function body should span 8 lines or less excluding comments and whitespace: currently spans 10 lines"]
)
do {
let violations = try await self.violations(function, configuration: ["warning": 12])
XCTAssertEqual(violations, [])
}
do {
let violations = try await self.violations(function, configuration: ["warning": 12, "error": 14])
XCTAssertEqual(violations, [])
}
do {
let violations = try await self.violations(function, configuration: ["warning": 8])
XCTAssertEqual(
violations.map(\.reason),
[
"""
Function body should span 8 lines or less excluding comments and whitespace: \
currently spans 10 lines
"""
]
)
}
do {
let violations = try await self.violations(function, configuration: ["warning": 12, "error": 8])
XCTAssertEqual(
violations.map(\.reason),
[
"""
Function body should span 8 lines or less excluding comments and whitespace: \
currently spans 10 lines
"""
]
)
}
}
private func violations(_ example: Example, configuration: Any? = nil) -> [StyleViolation] {
private func violations(_ example: Example, configuration: Any? = nil) async throws -> [StyleViolation] {
let config = makeConfig(configuration, FunctionBodyLengthRule.description.identifier)!
return SwiftLintFrameworkTests.violations(example, config: config)
return try await SwiftLintFrameworkTests.violations(example, config: config)
}
}

View File

@ -11,7 +11,7 @@ private func funcWithParameters(_ parameters: String,
}
class FunctionParameterCountRuleTests: XCTestCase {
func testFunctionParameterCount() {
func testFunctionParameterCount() async throws {
let baseDescription = FunctionParameterCountRule.description
let nonTriggeringExamples = [
funcWithParameters(repeatElement("x: Int, ", count: 3).joined() + "x: Int")
@ -24,10 +24,10 @@ class FunctionParameterCountRuleTests: XCTestCase {
let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples)
.with(triggeringExamples: triggeringExamples)
verifyRule(description)
try await verifyRule(description)
}
func testDefaultFunctionParameterCount() {
func testDefaultFunctionParameterCount() async throws {
let baseDescription = FunctionParameterCountRule.description
let nonTriggeringExamples = [
funcWithParameters(repeatElement("x: Int, ", count: 3).joined() + "x: Int")
@ -41,6 +41,6 @@ class FunctionParameterCountRuleTests: XCTestCase {
let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples)
.with(triggeringExamples: triggeringExamples)
verifyRule(description, ruleConfiguration: ["ignores_default_parameters": false])
try await verifyRule(description, ruleConfiguration: ["ignores_default_parameters": false])
}
}

View File

@ -2,7 +2,7 @@
import XCTest
class GenericTypeNameRuleTests: XCTestCase {
func testGenericTypeNameWithExcluded() {
func testGenericTypeNameWithExcluded() async throws {
let baseDescription = GenericTypeNameRule.description
let nonTriggeringExamples = baseDescription.nonTriggeringExamples + [
Example("func foo<apple> {}\n"),
@ -15,10 +15,10 @@ class GenericTypeNameRuleTests: XCTestCase {
]
let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples,
triggeringExamples: triggeringExamples)
verifyRule(description, ruleConfiguration: ["excluded": ["apple", "some.*", ".*st\\d+.*"]])
try await verifyRule(description, ruleConfiguration: ["excluded": ["apple", "some.*", ".*st\\d+.*"]])
}
func testGenericTypeNameWithAllowedSymbols() {
func testGenericTypeNameWithAllowedSymbols() async throws {
let baseDescription = GenericTypeNameRule.description
let nonTriggeringExamples = baseDescription.nonTriggeringExamples + [
Example("func foo<T$>() {}\n"),
@ -30,20 +30,20 @@ class GenericTypeNameRuleTests: XCTestCase {
]
let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples)
verifyRule(description, ruleConfiguration: ["allowed_symbols": ["$", "%"]])
try await verifyRule(description, ruleConfiguration: ["allowed_symbols": ["$", "%"]])
}
func testGenericTypeNameWithAllowedSymbolsAndViolation() {
func testGenericTypeNameWithAllowedSymbolsAndViolation() async throws {
let baseDescription = GenericTypeNameRule.description
let triggeringExamples = [
Example("func foo<↓T_$>() {}\n")
]
let description = baseDescription.with(triggeringExamples: triggeringExamples)
verifyRule(description, ruleConfiguration: ["allowed_symbols": ["$", "%"]])
try await verifyRule(description, ruleConfiguration: ["allowed_symbols": ["$", "%"]])
}
func testGenericTypeNameWithIgnoreStartWithLowercase() {
func testGenericTypeNameWithIgnoreStartWithLowercase() async throws {
let baseDescription = GenericTypeNameRule.description
let triggeringExamplesToRemove = [
Example("func foo<↓type>() {}\n"),
@ -58,6 +58,6 @@ class GenericTypeNameRuleTests: XCTestCase {
let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples)
.with(triggeringExamples: triggeringExamples)
verifyRule(description, ruleConfiguration: ["validates_start_with_lowercase": false])
try await verifyRule(description, ruleConfiguration: ["validates_start_with_lowercase": false])
}
}

View File

@ -2,7 +2,7 @@
import XCTest
class IdentifierNameRuleTests: XCTestCase {
func testIdentifierNameWithExcluded() {
func testIdentifierNameWithExcluded() async throws {
let baseDescription = IdentifierNameRule.description
let nonTriggeringExamples = baseDescription.nonTriggeringExamples + [
Example("let Apple = 0"),
@ -15,10 +15,10 @@ class IdentifierNameRuleTests: XCTestCase {
]
let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples,
triggeringExamples: triggeringExamples)
verifyRule(description, ruleConfiguration: ["excluded": ["Apple", "some.*", ".*\\d+.*"]])
try await verifyRule(description, ruleConfiguration: ["excluded": ["Apple", "some.*", ".*\\d+.*"]])
}
func testIdentifierNameWithAllowedSymbols() {
func testIdentifierNameWithAllowedSymbols() async throws {
let baseDescription = IdentifierNameRule.description
let nonTriggeringExamples = baseDescription.nonTriggeringExamples + [
Example("let myLet$ = 0"),
@ -29,20 +29,20 @@ class IdentifierNameRuleTests: XCTestCase {
let triggeringExamples = baseDescription.triggeringExamples.filter { !$0.code.contains("_") }
let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples,
triggeringExamples: triggeringExamples)
verifyRule(description, ruleConfiguration: ["allowed_symbols": ["$", "%", "_"]])
try await verifyRule(description, ruleConfiguration: ["allowed_symbols": ["$", "%", "_"]])
}
func testIdentifierNameWithAllowedSymbolsAndViolation() {
func testIdentifierNameWithAllowedSymbolsAndViolation() async throws {
let baseDescription = IdentifierNameRule.description
let triggeringExamples = [
Example("↓let my_Let$ = 0")
]
let description = baseDescription.with(triggeringExamples: triggeringExamples)
verifyRule(description, ruleConfiguration: ["allowed_symbols": ["$", "%"]])
try await verifyRule(description, ruleConfiguration: ["allowed_symbols": ["$", "%"]])
}
func testIdentifierNameWithIgnoreStartWithLowercase() {
func testIdentifierNameWithIgnoreStartWithLowercase() async throws {
let baseDescription = IdentifierNameRule.description
let triggeringExamplesToRemove = [
Example("↓let MyLet = 0"),
@ -57,16 +57,16 @@ class IdentifierNameRuleTests: XCTestCase {
let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples)
.with(triggeringExamples: triggeringExamples)
verifyRule(description, ruleConfiguration: ["validates_start_with_lowercase": false])
try await verifyRule(description, ruleConfiguration: ["validates_start_with_lowercase": false])
}
func testLinuxCrashOnEmojiNames() {
func testLinuxCrashOnEmojiNames() async throws {
let baseDescription = IdentifierNameRule.description
let triggeringExamples = [
Example("let 👦🏼 = \"👦🏼\"")
]
let description = baseDescription.with(triggeringExamples: triggeringExamples)
verifyRule(description, ruleConfiguration: ["allowed_symbols": ["$", "%"]])
try await verifyRule(description, ruleConfiguration: ["allowed_symbols": ["$", "%"]])
}
}

View File

@ -2,7 +2,7 @@
import XCTest
final class ImplicitGetterRuleTests: XCTestCase {
func testPropertyReason() throws {
func testPropertyReason() async throws {
let config = try XCTUnwrap(makeConfig(nil, ImplicitGetterRule.description.identifier))
let example = Example("""
class Foo {
@ -14,12 +14,12 @@ final class ImplicitGetterRuleTests: XCTestCase {
}
""")
let violations = violations(example, config: config)
let violations = try await violations(example, config: config)
XCTAssertEqual(violations.count, 1)
XCTAssertEqual(violations.first?.reason, "Computed read-only properties should avoid using the get keyword")
}
func testSubscriptReason() throws {
func testSubscriptReason() async throws {
let config = try XCTUnwrap(makeConfig(nil, ImplicitGetterRule.description.identifier))
let example = Example("""
class Foo {
@ -31,7 +31,7 @@ final class ImplicitGetterRuleTests: XCTestCase {
}
""")
let violations = violations(example, config: config)
let violations = try await violations(example, config: config)
XCTAssertEqual(violations.count, 1)
XCTAssertEqual(violations.first?.reason, "Computed read-only subscripts should avoid using the get keyword")
}

View File

@ -2,7 +2,7 @@
import XCTest
class ImplicitReturnRuleTests: XCTestCase {
func testOnlyClosureKindIncluded() {
func testOnlyClosureKindIncluded() async throws {
let nonTriggeringExamples = ImplicitReturnRuleExamples.GenericExamples.nonTriggeringExamples +
ImplicitReturnRuleExamples.ClosureExamples.nonTriggeringExamples +
ImplicitReturnRuleExamples.FunctionExamples.nonTriggeringExamples +
@ -17,10 +17,10 @@ class ImplicitReturnRuleTests: XCTestCase {
.with(triggeringExamples: triggeringExamples)
.with(corrections: corrections)
self.verifyRule(description, returnKind: .closure)
try await self.verifyRule(description, returnKind: .closure)
}
func testOnlyFunctionKindIncluded() {
func testOnlyFunctionKindIncluded() async throws {
let nonTriggeringExamples = ImplicitReturnRuleExamples.GenericExamples.nonTriggeringExamples +
ImplicitReturnRuleExamples.ClosureExamples.nonTriggeringExamples +
ImplicitReturnRuleExamples.ClosureExamples.triggeringExamples +
@ -35,10 +35,10 @@ class ImplicitReturnRuleTests: XCTestCase {
.with(triggeringExamples: triggeringExamples)
.with(corrections: corrections)
self.verifyRule(description, returnKind: .function)
try await self.verifyRule(description, returnKind: .function)
}
func testOnlyGetterKindIncluded() {
func testOnlyGetterKindIncluded() async throws {
let nonTriggeringExamples = ImplicitReturnRuleExamples.GenericExamples.nonTriggeringExamples +
ImplicitReturnRuleExamples.ClosureExamples.nonTriggeringExamples +
ImplicitReturnRuleExamples.ClosureExamples.triggeringExamples +
@ -53,10 +53,11 @@ class ImplicitReturnRuleTests: XCTestCase {
.with(triggeringExamples: triggeringExamples)
.with(corrections: corrections)
self.verifyRule(description, returnKind: .getter)
try await self.verifyRule(description, returnKind: .getter)
}
private func verifyRule(_ ruleDescription: RuleDescription, returnKind: ImplicitReturnConfiguration.ReturnKind) {
self.verifyRule(ruleDescription, ruleConfiguration: ["included": [returnKind.rawValue]])
private func verifyRule(_ ruleDescription: RuleDescription, returnKind: ImplicitReturnConfiguration.ReturnKind)
async throws {
try await self.verifyRule(ruleDescription, ruleConfiguration: ["included": [returnKind.rawValue]])
}
}

View File

@ -8,7 +8,7 @@ class ImplicitlyUnwrappedOptionalRuleTests: XCTestCase {
XCTAssertEqual(rule.configuration.severity, .warning)
}
func testImplicitlyUnwrappedOptionalRuleWarnsOnOutletsInAllMode() {
func testImplicitlyUnwrappedOptionalRuleWarnsOnOutletsInAllMode() async throws {
let baseDescription = ImplicitlyUnwrappedOptionalRule.description
let triggeringExamples = [
Example("@IBOutlet private var label: UILabel!"),
@ -20,7 +20,7 @@ class ImplicitlyUnwrappedOptionalRuleTests: XCTestCase {
let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples)
.with(triggeringExamples: triggeringExamples)
verifyRule(description, ruleConfiguration: ["mode": "all"],
commentDoesntViolate: true, stringDoesntViolate: true)
try await verifyRule(description, ruleConfiguration: ["mode": "all"],
commentDoesntViolate: true, stringDoesntViolate: true)
}
}

View File

@ -2,21 +2,21 @@
import XCTest
class InclusiveLanguageRuleTests: XCTestCase {
func testNonTriggeringExamplesWithNonDefaultConfig() {
InclusiveLanguageRuleExamples.nonTriggeringExamplesWithConfig.forEach { example in
func testNonTriggeringExamplesWithNonDefaultConfig() async throws {
for example in InclusiveLanguageRuleExamples.nonTriggeringExamplesWithConfig {
let description = InclusiveLanguageRule.description
.with(nonTriggeringExamples: [example])
.with(triggeringExamples: [])
verifyRule(description, ruleConfiguration: example.configuration)
try await verifyRule(description, ruleConfiguration: example.configuration)
}
}
func testTriggeringExamplesWithNonDefaultConfig() {
InclusiveLanguageRuleExamples.triggeringExamplesWithConfig.forEach { example in
func testTriggeringExamplesWithNonDefaultConfig() async throws {
for example in InclusiveLanguageRuleExamples.triggeringExamplesWithConfig {
let description = InclusiveLanguageRule.description
.with(nonTriggeringExamples: [])
.with(triggeringExamples: [example])
verifyRule(description, ruleConfiguration: example.configuration)
try await verifyRule(description, ruleConfiguration: example.configuration)
}
}
}

View File

@ -4,166 +4,168 @@ import XCTest
class IndentationWidthRuleTests: XCTestCase {
// MARK: Examples
/// It's not okay to have the first line indented.
func testFirstLineIndentation() {
assert1Violation(in: " firstLine")
assert1Violation(in: " firstLine")
assert1Violation(in: " firstLine")
assert1Violation(in: "\tfirstLine")
func testFirstLineIndentation() async throws {
try await assert1Violation(in: " firstLine")
try await assert1Violation(in: " firstLine")
try await assert1Violation(in: " firstLine")
try await assert1Violation(in: "\tfirstLine")
assertNoViolation(in: "firstLine")
try await assertNoViolation(in: "firstLine")
}
/// It's not okay to indent using both tabs and spaces in one line.
func testMixedTabSpaceIndentation() {
func testMixedTabSpaceIndentation() async throws {
// Expect 2 violations as secondLine is also indented by 8 spaces (which isn't valid)
assertViolations(in: "firstLine\n\t secondLine", equals: 2)
assertViolations(in: "firstLine\n \tsecondLine", equals: 2)
try await assertViolations(in: "firstLine\n\t secondLine", equals: 2)
try await assertViolations(in: "firstLine\n \tsecondLine", equals: 2)
}
/// It's okay to indent using either tabs or spaces in different lines.
func testMixedTabsAndSpacesIndentation() {
assertNoViolation(in: "firstLine\n\tsecondLine\n thirdLine")
assertNoViolation(in: "firstLine\n secondLine\n\t\tthirdLine")
assertNoViolation(in: "firstLine\n\tsecondLine\n thirdLine\n\t\t\tfourthLine")
func testMixedTabsAndSpacesIndentation() async throws {
try await assertNoViolation(in: "firstLine\n\tsecondLine\n thirdLine")
try await assertNoViolation(in: "firstLine\n secondLine\n\t\tthirdLine")
try await assertNoViolation(in: "firstLine\n\tsecondLine\n thirdLine\n\t\t\tfourthLine")
}
/// It's okay to keep the same indentation.
func testKeepingIndentation() {
assertNoViolation(in: "firstLine\nsecondLine")
assertNoViolation(in: "firstLine \nsecondLine\n thirdLine")
assertNoViolation(in: "firstLine\t\nsecondLine\n\tthirdLine")
func testKeepingIndentation() async throws {
try await assertNoViolation(in: "firstLine\nsecondLine")
try await assertNoViolation(in: "firstLine \nsecondLine\n thirdLine")
try await assertNoViolation(in: "firstLine\t\nsecondLine\n\tthirdLine")
}
/// It's only okay to indent using one tab or indentationWidth spaces.
func testIndentationLength() {
assert1Violation(in: "firstLine\n secondLine", indentationWidth: 1)
assert1Violation(in: "firstLine\n secondLine", indentationWidth: 2)
assert1Violation(in: "firstLine\n secondLine", indentationWidth: 3)
assert1Violation(in: "firstLine\n secondLine", indentationWidth: 4)
assert1Violation(in: "firstLine\n secondLine", indentationWidth: 5)
assert1Violation(in: "firstLine\n secondLine", indentationWidth: 6)
assert1Violation(in: "firstLine\n secondLine", indentationWidth: 7)
assert1Violation(in: "firstLine\n\t\tsecondLine")
assert1Violation(in: "firstLine\n\t\t\tsecondLine")
assert1Violation(in: "firstLine\n\t\t\t\t\t\tsecondLine")
func testIndentationLength() async throws {
try await assert1Violation(in: "firstLine\n secondLine", indentationWidth: 1)
try await assert1Violation(in: "firstLine\n secondLine", indentationWidth: 2)
try await assert1Violation(in: "firstLine\n secondLine", indentationWidth: 3)
try await assert1Violation(in: "firstLine\n secondLine", indentationWidth: 4)
try await assert1Violation(in: "firstLine\n secondLine", indentationWidth: 5)
try await assert1Violation(in: "firstLine\n secondLine", indentationWidth: 6)
try await assert1Violation(in: "firstLine\n secondLine", indentationWidth: 7)
try await assert1Violation(in: "firstLine\n\t\tsecondLine")
try await assert1Violation(in: "firstLine\n\t\t\tsecondLine")
try await assert1Violation(in: "firstLine\n\t\t\t\t\t\tsecondLine")
assertNoViolation(in: "firstLine\n\tsecondLine")
assertNoViolation(in: "firstLine\n secondLine", indentationWidth: 1)
assertNoViolation(in: "firstLine\n secondLine", indentationWidth: 2)
assertNoViolation(in: "firstLine\n secondLine", indentationWidth: 3)
assertNoViolation(in: "firstLine\n secondLine", indentationWidth: 4)
assertNoViolation(in: "firstLine\n secondLine", indentationWidth: 5)
assertNoViolation(in: "firstLine\n secondLine", indentationWidth: 6)
assertNoViolation(in: "firstLine\n secondLine", indentationWidth: 7)
assertNoViolation(in: "firstLine\n secondLine", indentationWidth: 8)
try await assertNoViolation(in: "firstLine\n\tsecondLine")
try await assertNoViolation(in: "firstLine\n secondLine", indentationWidth: 1)
try await assertNoViolation(in: "firstLine\n secondLine", indentationWidth: 2)
try await assertNoViolation(in: "firstLine\n secondLine", indentationWidth: 3)
try await assertNoViolation(in: "firstLine\n secondLine", indentationWidth: 4)
try await assertNoViolation(in: "firstLine\n secondLine", indentationWidth: 5)
try await assertNoViolation(in: "firstLine\n secondLine", indentationWidth: 6)
try await assertNoViolation(in: "firstLine\n secondLine", indentationWidth: 7)
try await assertNoViolation(in: "firstLine\n secondLine", indentationWidth: 8)
}
/// It's okay to unindent indentationWidth * (1, 2, 3, ...) - x iff x == 0.
func testUnindentation() {
assert1Violation(in: "firstLine\n secondLine\n thirdLine\n fourthLine")
assert1Violation(in: "firstLine\n secondLine\n thirdLine\n fourthLine")
assert1Violation(in: "firstLine\n secondLine\n thirdLine\n fourthLine")
assert1Violation(in: "firstLine\n secondLine\n thirdLine\n fourthLine")
func testUnindentation() async throws {
try await assert1Violation(in: "firstLine\n secondLine\n thirdLine\n fourthLine")
try await assert1Violation(in: "firstLine\n secondLine\n thirdLine\n fourthLine")
try await assert1Violation(in: "firstLine\n secondLine\n thirdLine\n fourthLine")
try await assert1Violation(in: "firstLine\n secondLine\n thirdLine\n fourthLine")
assertNoViolation(in: "firstLine\n secondLine\n thirdLine\nfourthLine")
assertNoViolation(in: "firstLine\n secondLine\n thirdLine\nfourthLine")
assertNoViolation(in: "firstLine\n\tsecondLine\n\t\tthirdLine\n\t\t\tfourthLine\nfifthLine")
try await assertNoViolation(in: "firstLine\n secondLine\n thirdLine\nfourthLine")
try await assertNoViolation(in: "firstLine\n secondLine\n thirdLine\nfourthLine")
try await assertNoViolation(in: "firstLine\n\tsecondLine\n\t\tthirdLine\n\t\t\tfourthLine\nfifthLine")
}
/// It's okay to have empty lines between iff the following indentations obey the rules.
func testEmptyLinesBetween() {
assertNoViolation(in: "firstLine\n\tsecondLine\n\n\tfourthLine")
assertNoViolation(in: "firstLine\n\tsecondLine\n \n\tfourthLine")
assertNoViolation(in: "firstLine\n\tsecondLine\n \n\tfourthLine")
assertNoViolation(in: "firstLine\n\tsecondLine\n\n fourthLine")
assertNoViolation(in: "firstLine\n\tsecondLine\n \n fourthLine")
assertNoViolation(in: "firstLine\n\tsecondLine\n \n fourthLine")
func testEmptyLinesBetween() async throws {
try await assertNoViolation(in: "firstLine\n\tsecondLine\n\n\tfourthLine")
try await assertNoViolation(in: "firstLine\n\tsecondLine\n \n\tfourthLine")
try await assertNoViolation(in: "firstLine\n\tsecondLine\n \n\tfourthLine")
try await assertNoViolation(in: "firstLine\n\tsecondLine\n\n fourthLine")
try await assertNoViolation(in: "firstLine\n\tsecondLine\n \n fourthLine")
try await assertNoViolation(in: "firstLine\n\tsecondLine\n \n fourthLine")
assert1Violation(in: "firstLine\n\tsecondLine\n\n\t\t\tfourthLine")
assert1Violation(in: "firstLine\n\tsecondLine\n \n\t\t\tfourthLine")
assert1Violation(in: "firstLine\n\tsecondLine\n \n\t\t\tfourthLine")
assert1Violation(in: "firstLine\n\tsecondLine\n\n fourthLine")
assert1Violation(in: "firstLine\n\tsecondLine\n \n fourthLine")
assert1Violation(in: "firstLine\n\tsecondLine\n \n fourthLine")
try await assert1Violation(in: "firstLine\n\tsecondLine\n\n\t\t\tfourthLine")
try await assert1Violation(in: "firstLine\n\tsecondLine\n \n\t\t\tfourthLine")
try await assert1Violation(in: "firstLine\n\tsecondLine\n \n\t\t\tfourthLine")
try await assert1Violation(in: "firstLine\n\tsecondLine\n\n fourthLine")
try await assert1Violation(in: "firstLine\n\tsecondLine\n \n fourthLine")
try await assert1Violation(in: "firstLine\n\tsecondLine\n \n fourthLine")
}
func testsBrackets() {
assertNoViolation(
func testsBrackets() async throws {
try await assertNoViolation(
in: "firstLine\n [\n .thirdLine\n ]\nfifthLine",
includeComments: true
)
assertNoViolation(
try await assertNoViolation(
in: "firstLine\n [\n .thirdLine\n ]\nfifthLine",
includeComments: false
)
assertNoViolation(
try await assertNoViolation(
in: "firstLine\n (\n .thirdLine\n )\nfifthLine",
includeComments: true
)
assertNoViolation(
try await assertNoViolation(
in: "firstLine\n (\n .thirdLine\n )\nfifthLine",
includeComments: false
)
}
/// It's okay to have comments not following the indentation pattern iff the configuration allows this.
func testCommentLines() {
assert1Violation(
func testCommentLines() async throws {
try await assert1Violation(
in: "firstLine\n\tsecondLine\n\t\tthirdLine\n//test\n\t\tfourthLine",
includeComments: true
)
assertViolations(
try await assertViolations(
in: "firstLine\n\tsecondLine\n\t\tthirdLine\n//test\n // test\n//test\n\t\tfourthLine",
equals: 2,
includeComments: true
)
assertViolations(
try await assertViolations(
in: "firstLine\n\tsecondLine\n\t\tthirdLine\n/*test\n bad indent...\n test*/\n\t\tfourthLine",
equals: 3,
includeComments: true
)
assertNoViolation(
try await assertNoViolation(
in: "firstLine\n\tsecondLine\n\t\tthirdLine\n//test\n\t\tfourthLine",
includeComments: false
)
assertNoViolation(
try await assertNoViolation(
in: "firstLine\n\tsecondLine\n\t\tthirdLine\n//test\n // test\n//test\n\t\tfourthLine",
includeComments: false
)
assertNoViolation(
try await assertNoViolation(
in: "firstLine\n\tsecondLine\n\t\tthirdLine\n/*test\n bad indent...\n test*/\n\t\tfourthLine",
includeComments: false
)
}
/// Duplicate warnings for one actual indentation issue should be avoided.
func testDuplicateWarningAvoidanceMechanism() {
func testDuplicateWarningAvoidanceMechanism() async throws {
// thirdLine is indented correctly, yet not in-line with the badly indented secondLine. This should be allowed.
assert1Violation(in: "firstLine\n secondLine\nthirdLine")
try await assert1Violation(in: "firstLine\n secondLine\nthirdLine")
// thirdLine is indented correctly, yet not in-line with the badly indented secondLine. This should be allowed.
assert1Violation(in: "firstLine\n secondLine\n thirdLine")
try await assert1Violation(in: "firstLine\n secondLine\n thirdLine")
// thirdLine is indented badly, yet in-line with the badly indented secondLine. This should be allowed.
assert1Violation(in: "firstLine\n secondLine\n thirdLine")
try await assert1Violation(in: "firstLine\n secondLine\n thirdLine")
// This pattern should go on indefinitely...
assert1Violation(in: "firstLine\n secondLine\n thirdLine\n fourthLine")
assert1Violation(in: "firstLine\n secondLine\n thirdLine\n fourthLine")
try await assert1Violation(in: "firstLine\n secondLine\n thirdLine\n fourthLine")
try await assert1Violation(in: "firstLine\n secondLine\n thirdLine\n fourthLine")
// Still, this won't disable multiple line warnings in one file if suitable...
assertViolations(in: "firstLine\n secondLine\nthirdLine\n fourthLine", equals: 2)
assertViolations(in: "firstLine\n secondLine\n thirdLine\n fourthLine", equals: 2)
assertViolations(in: "firstLine\n secondLine\n thirdLine\nfourthLine\n fifthLine", equals: 2)
assertViolations(in: "firstLine\n secondLine\n thirdLine\n fourthLine\n fifthLine", equals: 2)
try await assertViolations(in: "firstLine\n secondLine\nthirdLine\n fourthLine", equals: 2)
try await assertViolations(in: "firstLine\n secondLine\n thirdLine\n fourthLine", equals: 2)
try await assertViolations(in: "firstLine\n secondLine\n thirdLine\nfourthLine\n fifthLine",
equals: 2)
try await assertViolations(in: "firstLine\n secondLine\n thirdLine\n fourthLine\n fifthLine",
equals: 2)
}
func testIgnoredCompilerDirectives() {
assertNoViolation(in: """
func testIgnoredCompilerDirectives() async throws {
try await assertNoViolation(in: """
struct S {
#if os(iOS)
var i: Int = 0
@ -179,7 +181,7 @@ class IndentationWidthRuleTests: XCTestCase {
}
""", includeCompilerDirectives: false)
assertNoViolation(in: """
try await assertNoViolation(in: """
struct S {
#if os(iOS)
var i: Int = 0
@ -204,7 +206,7 @@ class IndentationWidthRuleTests: XCTestCase {
includeCompilerDirectives: Bool? = nil,
file: StaticString = #file,
line: UInt = #line
) -> Int {
) async throws -> Int {
var configDict: [String: Any] = [:]
if let indentationWidth {
configDict["indentation_width"] = indentationWidth
@ -221,7 +223,7 @@ class IndentationWidthRuleTests: XCTestCase {
return 0
}
return violations(example.with(code: example.code + "\n"), config: config).count
return try await violations(example.with(code: example.code + "\n"), config: config).count
}
private func assertViolations(
@ -232,20 +234,16 @@ class IndentationWidthRuleTests: XCTestCase {
includeCompilerDirectives: Bool? = nil,
file: StaticString = #file,
line: UInt = #line
) {
XCTAssertEqual(
countViolations(
in: Example(string, file: (file), line: line),
indentationWidth: indentationWidth,
includeComments: includeComments,
includeCompilerDirectives: includeCompilerDirectives,
file: file,
line: line
),
expectedCount,
file: (file),
) async throws {
let actualCount = try await countViolations(
in: Example(string, file: (file), line: line),
indentationWidth: indentationWidth,
includeComments: includeComments,
includeCompilerDirectives: includeCompilerDirectives,
file: file,
line: line
)
XCTAssertEqual(actualCount, expectedCount, file: file, line: line)
}
private func assertNoViolation(
@ -255,8 +253,8 @@ class IndentationWidthRuleTests: XCTestCase {
includeCompilerDirectives: Bool? = nil,
file: StaticString = #file,
line: UInt = #line
) {
assertViolations(
) async throws {
try await assertViolations(
in: string,
equals: 0,
indentationWidth: indentationWidth,
@ -274,8 +272,8 @@ class IndentationWidthRuleTests: XCTestCase {
includeCompilerDirectives: Bool? = nil,
file: StaticString = #file,
line: UInt = #line
) {
assertViolations(
) async throws {
try await assertViolations(
in: string,
equals: 1,
indentationWidth: indentationWidth,

View File

@ -2,11 +2,8 @@
import XCTest
class LineEndingTests: XCTestCase {
func testCarriageReturnDoesNotCauseError() {
XCTAssert(
violations(
Example("// swiftlint:disable all\r\nprint(123)\r\n")
).isEmpty
)
func testCarriageReturnDoesNotCauseError() async throws {
let violations = try await violations(Example("// swiftlint:disable all\r\nprint(123)\r\n"))
XCTAssertEqual(violations, [])
}
}

Some files were not shown because too many files have changed in this diff Show More