Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TestCaseAccessibilityRule #3376

Merged
merged 7 commits into from
Oct 12, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 5 additions & 15 deletions Source/SwiftLintFramework/Helpers/XCTestHelpers.swift
Original file line number Diff line number Diff line change
@@ -1,24 +1,14 @@
import SourceKittenFramework

private let testFunctionNames: Set = [
"setUp()",
"setUpWithError()",
"tearDown()",
"tearDownWithError()"
]

private let testVariableNames: Set = [
"allTests"
]

enum XCTestHelpers {
static func isXCTestMember(kind: SwiftDeclarationKind, name: String) -> Bool {
if SwiftDeclarationKind.functionKinds.contains(kind) {
return name.hasPrefix("test") || testFunctionNames.contains(name)
} else if SwiftDeclarationKind.variableKinds.contains(kind) {
return testVariableNames.contains(name)
}

return false
static func isXCTestMember(kind: SwiftDeclarationKind, name: String,
attributes: [SwiftDeclarationAttributeKind]) -> Bool {
return attributes.contains(.override)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice.

|| (kind == .functionMethodInstance && name.hasPrefix("test"))
|| ([.varStatic, .varClass].contains(kind) && testVariableNames.contains(name))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ public struct EmptyXCTestMethodRule: Rule, OptInRule, ConfigurationProviderRule,
guard
let kind = subDictionary.declarationKind,
let name = subDictionary.name,
XCTestHelpers.isXCTestMember(kind: kind, name: name),
XCTestHelpers.isXCTestMember(kind: kind, name: name,
attributes: subDictionary.enclosedSwiftAttributes),
let offset = subDictionary.offset,
subDictionary.enclosedVarParameters.isEmpty,
subDictionary.substructure.isEmpty else { return nil }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ public struct TestCaseAccessibilityRule: Rule, OptInRule, ConfigurationProviderR
private func testClasses(in file: SwiftLintFile) -> [SourceKittenDictionary] {
let dict = file.structureDictionary
return dict.substructure.filter { dictionary in
dictionary.declarationKind == .class &&
dictionary.inheritedTypes.contains("XCTestCase")
dictionary.declarationKind == .class && dictionary.inheritedTypes.contains("XCTestCase")
}
}

Expand All @@ -35,7 +34,7 @@ public struct TestCaseAccessibilityRule: Rule, OptInRule, ConfigurationProviderR
let kind = subDictionary.declarationKind,
kind != .varLocal,
let name = subDictionary.name,
!isXCTestMember(kind: kind, name: name),
!isXCTestMember(kind: kind, name: name, attributes: subDictionary.enclosedSwiftAttributes),
let offset = subDictionary.offset,
subDictionary.accessibility?.isPrivate != true else { return nil }

Expand All @@ -45,8 +44,9 @@ public struct TestCaseAccessibilityRule: Rule, OptInRule, ConfigurationProviderR
}
}

private func isXCTestMember(kind: SwiftDeclarationKind, name: String) -> Bool {
return XCTestHelpers.isXCTestMember(kind: kind, name: name)
|| configuration.methodPrefixes.contains(where: name.hasPrefix)
private func isXCTestMember(kind: SwiftDeclarationKind, name: String,
attributes: [SwiftDeclarationAttributeKind]) -> Bool {
return XCTestHelpers.isXCTestMember(kind: kind, name: name, attributes: attributes)
|| configuration.allowedPrefixes.contains(where: name.hasPrefix)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ internal struct TestCaseAccessibilityRuleExamples {
let foo: String?

class FooTests: XCTestCase {
static let allTests: [String] = []

private let foo: String {
let nestedMember = "hi"
return nestedMember
Expand Down Expand Up @@ -35,6 +37,10 @@ internal struct TestCaseAccessibilityRuleExamples {
try super.tearDownWithError()
}

override func someFutureXCTestFunction() {
super.someFutureXCTestFunction()
}

func testFoo() {
XCTAssertTrue(true)
}
Expand Down Expand Up @@ -69,6 +75,10 @@ internal struct TestCaseAccessibilityRuleExamples {
↓func not_testBar() {}

↓enum Nested {}

↓static func testFoo() {}

↓static func allTests() {}
}

final class BarTests: XCTestCase {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
public struct TestCaseAccessibilityConfiguration: RuleConfiguration, Equatable {
public private(set) var severityConfiguration = SeverityConfiguration(.warning)
public private(set) var methodPrefixes: Set<String> = []
public private(set) var allowedPrefixes: Set<String> = []

public var consoleDescription: String {
return severityConfiguration.consoleDescription +
", method_prefixes: [\(methodPrefixes)]"
", allowed_prefixes: [\(allowedPrefixes)]"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Examples can now specify configurations, so it'd be nice to test something like disabled_test as an allowed prefix.

/// The untyped configuration to apply to the rule, if deviating from the default configuration.
/// The structure should match what is expected as a configuration value for the rule being tested.
///
/// For example, if the following YAML would be used to configure the rule:
///
/// ```
/// severity: warning
/// ```
///
/// Then the equivalent configuration value would be `["severity": "warning"]`.
public private(set) var configuration: Any?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an example of that working? I tried that and I don't believe it's passed all the way through the tests

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICT it only is for analyze tests

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I think you're right. Let's hold off for now, but it should be easy to make normal lint tests apply this configuration value.

}

public mutating func apply(configuration: Any) throws {
Expand All @@ -16,8 +16,8 @@ public struct TestCaseAccessibilityConfiguration: RuleConfiguration, Equatable {
try severityConfiguration.apply(configuration: severityString)
}

if let methodPrefixes = configuration["method_prefixes"] as? [String] {
self.methodPrefixes = Set(methodPrefixes)
if let allowedPrefixes = configuration["allowed_prefixes"] as? [String] {
self.allowedPrefixes = Set(allowedPrefixes)
}
}

Expand Down