Skip to content

Commit

Permalink
Add ability to focus on a specific test example
Browse files Browse the repository at this point in the history
  • Loading branch information
PaulTaykalo committed Mar 20, 2022
1 parent 702b36a commit d52f802
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 5 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 13 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ $ xcodebuild -scheme swiftlint test
$ swift test
$ make docker_test
```

## Rules

New rules should be added in the `Source/SwiftLintFramework/Rules` directory.
Expand All @@ -72,6 +71,19 @@ over time. This way adding a unit test for your new Rule is just a matter of
adding a test case in `RulesTests.swift` which simply calls
`verifyRule(YourNewRule.description)`.

For debugging purposes examples can be marked as `focused`. If there are any
focused examples found, then only those will be run when running tests.
```
nonTriggeringExamples: [
Example("let x: [Int]"),
Example("let x: [Int: String]").focused() // only this one will be run in tests
],
triggeringExamples: [
Example("let x: ↓Array<String>"),
Example("let x: ↓Dictionary<Int, String>")
]
```

### `ConfigurationProviderRule`

If your rule supports user-configurable options via `.swiftlint.yml`, you can
Expand Down
11 changes: 11 additions & 0 deletions Source/SwiftLintFramework/Models/Example.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
Expand All @@ -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 {
Expand Down
39 changes: 35 additions & 4 deletions Tests/SwiftLintFrameworkTests/TestHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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(
Expand Down Expand Up @@ -401,6 +401,8 @@ extension XCTestCase {

func verifyCorrections(_ ruleDescription: RuleDescription, config: Configuration,
disableCommands: [String], testMultiByteOffsets: Bool) {
let ruleDescription = ruleDescription.focused()

parserDiagnosticsDisabledForTests = true

// corrections
Expand Down Expand Up @@ -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)
}
}

0 comments on commit d52f802

Please sign in to comment.