From 9099919569884c2b889ecb34efc4a47ea9d48b79 Mon Sep 17 00:00:00 2001 From: Paul Taykalo Date: Sat, 12 Mar 2022 19:13:26 +0200 Subject: [PATCH] Add ability to focus on a specific test example --- CHANGELOG.md | 4 ++ .../SwiftLintFramework/Models/Example.swift | 11 ++++++ .../SwiftLintFrameworkTests/TestHelpers.swift | 39 +++++++++++++++++-- 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b4bea5103a..41b708b1acd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,10 @@ environments, such as in Swift Package Manager plugins. [Juozas Valancius](https://github.com/juozasvalancius) +* Add ability to run only one (focused) example + [PaulTaykalo](https://github.com/PaulTaykalo) + [#3911](https://github.com/realm/SwiftLint/issues/3911) + #### Bug Fixes * Extend `class_delegate_protocol` to correctly identify cases with the protocol diff --git a/Source/SwiftLintFramework/Models/Example.swift b/Source/SwiftLintFramework/Models/Example.swift index f7de7959455..ae0126400dc 100644 --- a/Source/SwiftLintFramework/Models/Example.swift +++ b/Source/SwiftLintFramework/Models/Example.swift @@ -32,6 +32,9 @@ public struct Example { /// pathological use cases which are indeed important to test but not helpful for understanding can be /// hidden from the documentation with this option. let excludeFromDocumentation: Bool + + /// Specifies whether the test example should be the only example run during the current test case execution. + var isFocused: Bool } public extension Example { @@ -55,6 +58,7 @@ public extension Example { self.file = file self.line = line self.excludeFromDocumentation = excludeFromDocumentation + self.isFocused = false } /// Returns the same example, but with the `code` that is passed in @@ -69,6 +73,13 @@ public extension Example { func removingViolationMarkers() -> Example { return with(code: code.replacingOccurrences(of: "↓", with: "")) } + + /// Makes the current example focused. + func focused() -> Example { + var new = self + new.isFocused = true + return new + } } extension Example: Hashable { diff --git a/Tests/SwiftLintFrameworkTests/TestHelpers.swift b/Tests/SwiftLintFrameworkTests/TestHelpers.swift index 126018a914e..1330279e2d1 100644 --- a/Tests/SwiftLintFrameworkTests/TestHelpers.swift +++ b/Tests/SwiftLintFrameworkTests/TestHelpers.swift @@ -356,7 +356,11 @@ extension XCTestCase { requiresFileOnDisk: ruleDescription.requiresFileOnDisk, file: file, line: line) } + func makeViolations(_ example: Example) -> [StyleViolation] { + return violations(example, config: config, requiresFileOnDisk: ruleDescription.requiresFileOnDisk) + } + let ruleDescription = ruleDescription.focused() let triggers = ruleDescription.triggeringExamples let nonTriggers = ruleDescription.nonTriggeringExamples verify(triggers: triggers, nonTriggers: nonTriggers) @@ -369,10 +373,6 @@ extension XCTestCase { verify(triggers: triggers.map(addShebang), nonTriggers: nonTriggers.map(addShebang)) } - func makeViolations(_ example: Example) -> [StyleViolation] { - return violations(example, config: config, requiresFileOnDisk: ruleDescription.requiresFileOnDisk) - } - // Comment doesn't violate if !skipCommentTests { XCTAssertEqual( @@ -401,6 +401,8 @@ extension XCTestCase { func verifyCorrections(_ ruleDescription: RuleDescription, config: Configuration, disableCommands: [String], testMultiByteOffsets: Bool) { + let ruleDescription = ruleDescription.focused() + parserDiagnosticsDisabledForTests = true // corrections @@ -509,3 +511,32 @@ extension XCTestCase { } } } + +private struct FocusedRuleDescription { + let nonTriggeringExamples: [Example] + let triggeringExamples: [Example] + let corrections: [Example: Example] + + init(rule: RuleDescription) { + let nonTriggering = rule.nonTriggeringExamples.filter(\.isFocused) + let triggering = rule.triggeringExamples.filter(\.isFocused) + let corrections = rule.corrections.filter { _, value in value.isFocused } + let anyFocused = nonTriggering.isNotEmpty || triggering.isNotEmpty || corrections.isNotEmpty + + if anyFocused { + self.nonTriggeringExamples = nonTriggering + self.triggeringExamples = triggering + self.corrections = corrections + } else { + self.nonTriggeringExamples = rule.nonTriggeringExamples + self.triggeringExamples = rule.triggeringExamples + self.corrections = rule.corrections + } + } +} + +private extension RuleDescription { + func focused() -> FocusedRuleDescription { + return FocusedRuleDescription(rule: self) + } +}