Compare commits

...

2 Commits

Author SHA1 Message Date
Norio Nomura 9cb3b45cd1 Refactoring `nonTriggeringExample` of `NestingRule`
Extract nesting function trigger from map of `["class", "struct", "enum"]`.
2016-01-26 12:05:10 +09:00
Norio Nomura 8d46e22729 Generate assertion on every (non)triggering examples in `verifyRule()`
It makes failed triggering/non-triggering example locatable on Xcode's Issue Navigator.
2016-01-26 12:05:10 +09:00
30 changed files with 339 additions and 295 deletions

View File

@ -10,14 +10,14 @@ public struct RuleDescription: Equatable {
public let identifier: String
public let name: String
public let description: String
public let nonTriggeringExamples: [String]
public let triggeringExamples: [String]
public let nonTriggeringExamples: [Trigger]
public let triggeringExamples: [Trigger]
public let corrections: [String: String]
public var consoleDescription: String { return "\(name) (\(identifier)): \(description)" }
public init(identifier: String, name: String, description: String,
nonTriggeringExamples: [String] = [], triggeringExamples: [String] = [],
nonTriggeringExamples: [Trigger] = [], triggeringExamples: [Trigger] = [],
corrections: [String: String] = [:]) {
self.identifier = identifier
self.name = name
@ -33,3 +33,14 @@ public struct RuleDescription: Equatable {
public func == (lhs: RuleDescription, rhs: RuleDescription) -> Bool {
return lhs.identifier == rhs.identifier
}
public struct Trigger {
public let string: String
public let file: String
public let line: UInt
public init(_ string: String, file: String = __FILE__, line: Int = __LINE__) {
self.string = string
self.file = file
self.line = UInt(line)
}
}

View File

@ -32,10 +32,10 @@ public struct ClosingBraceRule: CorrectableRule, ConfigProviderRule {
description: "Closing brace with closing parenthesis " +
"should not have any whitespaces in the middle.",
nonTriggeringExamples: [
"[].map({ })"
Trigger("[].map({ })")
],
triggeringExamples: [
"[].map({ ↓} )"
Trigger("[].map({ ↓} )")
],
corrections: [
"[].map({ } )\n": "[].map({ })\n"

View File

@ -20,41 +20,41 @@ public struct ColonRule: CorrectableRule, ConfigProviderRule {
name: "Colon",
description: "Colons should be next to the identifier when specifying a type.",
nonTriggeringExamples: [
"let abc: Void\n",
"let abc: [Void: Void]\n",
"let abc: (Void, Void)\n",
"let abc: ([Void], String, Int)\n",
"let abc: [([Void], String, Int)]\n",
"let abc: String=\"def\"\n",
"let abc: Int=0\n",
"let abc: Enum=Enum.Value\n",
"func abc(def: Void) {}\n",
"func abc(def: Void, ghi: Void) {}\n",
"// 周斌佳年周斌佳\nlet abc: String = \"abc:\""
Trigger("let abc: Void\n"),
Trigger("let abc: [Void: Void]\n"),
Trigger("let abc: (Void, Void)\n"),
Trigger("let abc: ([Void], String, Int)\n"),
Trigger("let abc: [([Void], String, Int)]\n"),
Trigger("let abc: String=\"def\"\n"),
Trigger("let abc: Int=0\n"),
Trigger("let abc: Enum=Enum.Value\n"),
Trigger("func abc(def: Void) {}\n"),
Trigger("func abc(def: Void, ghi: Void) {}\n"),
Trigger("// 周斌佳年周斌佳\nlet abc: String = \"abc:\"")
],
triggeringExamples: [
"let ↓abc:Void\n",
"let ↓abc: Void\n",
"let ↓abc :Void\n",
"let ↓abc : Void\n",
"let ↓abc : [Void: Void]\n",
"let ↓abc : (Void, String, Int)\n",
"let ↓abc : ([Void], String, Int)\n",
"let ↓abc : [([Void], String, Int)]\n",
"let ↓abc: (Void, String, Int)\n",
"let ↓abc: ([Void], String, Int)\n",
"let ↓abc: [([Void], String, Int)]\n",
"let ↓abc :String=\"def\"\n",
"let ↓abc :Int=0\n",
"let ↓abc :Int = 0\n",
"let ↓abc:Int=0\n",
"let ↓abc:Int = 0\n",
"let ↓abc:Enum=Enum.Value\n",
"func abc(↓def:Void) {}\n",
"func abc(↓def: Void) {}\n",
"func abc(↓def :Void) {}\n",
"func abc(↓def : Void) {}\n",
"func abc(def: Void, ↓ghi :Void) {}\n"
Trigger("let ↓abc:Void\n"),
Trigger("let ↓abc: Void\n"),
Trigger("let ↓abc :Void\n"),
Trigger("let ↓abc : Void\n"),
Trigger("let ↓abc : [Void: Void]\n"),
Trigger("let ↓abc : (Void, String, Int)\n"),
Trigger("let ↓abc : ([Void], String, Int)\n"),
Trigger("let ↓abc : [([Void], String, Int)]\n"),
Trigger("let ↓abc: (Void, String, Int)\n"),
Trigger("let ↓abc: ([Void], String, Int)\n"),
Trigger("let ↓abc: [([Void], String, Int)]\n"),
Trigger("let ↓abc :String=\"def\"\n"),
Trigger("let ↓abc :Int=0\n"),
Trigger("let ↓abc :Int = 0\n"),
Trigger("let ↓abc:Int=0\n"),
Trigger("let ↓abc:Int = 0\n"),
Trigger("let ↓abc:Enum=Enum.Value\n"),
Trigger("func abc(↓def:Void) {}\n"),
Trigger("func abc(↓def: Void) {}\n"),
Trigger("func abc(↓def :Void) {}\n"),
Trigger("func abc(↓def : Void) {}\n"),
Trigger("func abc(def: Void, ↓ghi :Void) {}\n")
],
corrections: [
"let abc:Void\n": "let abc: Void\n",

View File

@ -20,14 +20,14 @@ public struct CommaRule: CorrectableRule, ConfigProviderRule {
name: "Comma Spacing",
description: "There should be no space before and one after any comma.",
nonTriggeringExamples: [
"func abc(a: String, b: String) { }",
"abc(a: \"string\", b: \"string\"",
"enum a { case a, b, c }"
Trigger("func abc(a: String, b: String) { }"),
Trigger("abc(a: \"string\", b: \"string\""),
Trigger("enum a { case a, b, c }")
],
triggeringExamples: [
"func abc(a: String↓ ,b: String) { }",
"abc(a: \"string\"↓,b: \"string\"",
"enum a { case a↓ ,b }"
Trigger("func abc(a: String↓ ,b: String) { }"),
Trigger("abc(a: \"string\"↓,b: \"string\""),
Trigger("enum a { case a↓ ,b }")
],
corrections: [
"func abc(a: String,b: String) {}\n": "func abc(a: String, b: String) {}\n",

View File

@ -20,22 +20,22 @@ public struct ConditionalBindingCascadeRule: ConfigProviderRule {
name: "Conditional Binding Cascade",
description: "Repeated `let` statements in conditional binding cascade should be avoided.",
nonTriggeringExamples: [
"if let a = b, c = d {",
"if let a = b, \n c = d {",
"if let a = b, \n c = d \n {",
"if let a = b { if let c = d {",
"if let a = b { let c = d({ foo in ... })",
"guard let a = b, c = d else {",
"guard let a = b where a, let c = d else {"
Trigger("if let a = b, c = d {"),
Trigger("if let a = b, \n c = d {"),
Trigger("if let a = b, \n c = d \n {"),
Trigger("if let a = b { if let c = d {"),
Trigger("if let a = b { let c = d({ foo in ... })"),
Trigger("guard let a = b, c = d else {"),
Trigger("guard let a = b where a, let c = d else {")
],
triggeringExamples: [
"if let a = b, let c = d {",
"if let a = b, \n let c = d {",
"if let a = b, c = d, let e = f {",
"if let a = b, let c = d \n {",
"if \n let a = b, let c = d {",
"if let a = b, c = d.indexOf({$0 == e}), let f = g {",
"guard let a = b, let c = d else {"
Trigger("if let a = b, let c = d {"),
Trigger("if let a = b, \n let c = d {"),
Trigger("if let a = b, c = d, let e = f {"),
Trigger("if let a = b, let c = d \n {"),
Trigger("if \n let a = b, let c = d {"),
Trigger("if let a = b, c = d.indexOf({$0 == e}), let f = g {"),
Trigger("guard let a = b, let c = d else {")
]
)

View File

@ -19,39 +19,39 @@ public struct ControlStatementRule: ConfigProviderRule {
name: "Control Statement",
description: "if,for,while,do statements shouldn't wrap their conditionals in parentheses.",
nonTriggeringExamples: [
"if condition {\n",
"if (a, b) == (0, 1) {\n",
"if (a || b) && (c || d) {\n",
"if (min...max).contains(value) {\n",
"if renderGif(data) {\n",
"renderGif(data)\n",
"for item in collection {\n",
"for (key, value) in dictionary {\n",
"for (index, value) in enumerate(array) {\n",
"for var index = 0; index < 42; index++ {\n",
"guard condition else {\n",
"while condition {\n",
"} while condition {\n",
"do { ; } while condition {\n",
"switch foo {\n"
Trigger("if condition {\n"),
Trigger("if (a, b) == (0, 1) {\n"),
Trigger("if (a || b) && (c || d) {\n"),
Trigger("if (min...max).contains(value) {\n"),
Trigger("if renderGif(data) {\n"),
Trigger("renderGif(data)\n"),
Trigger("for item in collection {\n"),
Trigger("for (key, value) in dictionary {\n"),
Trigger("for (index, value) in enumerate(array) {\n"),
Trigger("for var index = 0; index < 42; index++ {\n"),
Trigger("guard condition else {\n"),
Trigger("while condition {\n"),
Trigger("} while condition {\n"),
Trigger("do { ; } while condition {\n"),
Trigger("switch foo {\n")
],
triggeringExamples: [
"↓if (condition) {\n",
"↓if(condition) {\n",
"↓if ((a || b) && (c || d)) {\n",
"↓if ((min...max).contains(value)) {\n",
"↓for (item in collection) {\n",
"↓for (var index = 0; index < 42; index++) {\n",
"↓for(item in collection) {\n",
"↓for(var index = 0; index < 42; index++) {\n",
"↓guard (condition) else {\n",
"↓while (condition) {\n",
"↓while(condition) {\n",
"} ↓while (condition) {\n",
"} ↓while(condition) {\n",
"do { ; } ↓while(condition) {\n",
"do { ; } ↓while (condition) {\n",
"↓switch (foo) {\n"
Trigger("↓if (condition) {\n"),
Trigger("↓if(condition) {\n"),
Trigger("↓if ((a || b) && (c || d)) {\n"),
Trigger("↓if ((min...max).contains(value)) {\n"),
Trigger("↓for (item in collection) {\n"),
Trigger("↓for (var index = 0; index < 42; index++) {\n"),
Trigger("↓for(item in collection) {\n"),
Trigger("↓for(var index = 0; index < 42; index++) {\n"),
Trigger("↓guard (condition) else {\n"),
Trigger("↓while (condition) {\n"),
Trigger("↓while(condition) {\n"),
Trigger("} ↓while (condition) {\n"),
Trigger("} ↓while(condition) {\n"),
Trigger("do { ; } ↓while(condition) {\n"),
Trigger("do { ; } ↓while (condition) {\n"),
Trigger("↓switch (foo) {\n")
]
)

View File

@ -19,14 +19,14 @@ public struct CyclomaticComplexityRule: ASTRule, ConfigProviderRule {
name: "Cyclomatic Complexity",
description: "Complexity of function bodies should be limited.",
nonTriggeringExamples: [
"func f1() {\nif true {\nfor _ in 1..5 { } }\nif false { }\n}",
"func f3() {while true {}}",
Trigger("func f1() {\nif true {\nfor _ in 1..5 { } }\nif false { }\n}"),
Trigger("func f3() {while true {}}"),
],
triggeringExamples: [
"func f1() {\n if true {\n if true {\n if false {}\n }\n" +
Trigger("func f1() {\n if true {\n if true {\n if false {}\n }\n" +
" }\n if false {}\n let i = 0\n\n switch i {\n case 1: break\n" +
" case 2: break\n case 3: break\n default: break\n }\n\n" +
" for _ in 1...5 {\n guard true else {\n return\n }\n }\n}\n"
" for _ in 1...5 {\n guard true else {\n return\n }\n }\n}\n")
]
)

View File

@ -18,15 +18,15 @@ public struct EmptyCountRule: ConfigProviderRule, OptInRule {
name: "Empty Count",
description: "Prefer checking `isEmpty` over comparing `count` to zero.",
nonTriggeringExamples: [
"var count = 0\n",
"[Int]().isEmpty\n",
"[Int]().count > 1\n",
"[Int]().count == 1\n"
Trigger("var count = 0\n"),
Trigger("[Int]().isEmpty\n"),
Trigger("[Int]().count > 1\n"),
Trigger("[Int]().count == 1\n")
],
triggeringExamples: [
"[Int]().count == 0\n",
"[Int]().count > 0\n",
"[Int]().count != 0\n"
Trigger("[Int]().count == 0\n"),
Trigger("[Int]().count > 0\n"),
Trigger("[Int]().count != 0\n")
]
)

View File

@ -18,10 +18,10 @@ public struct FileLengthRule: ConfigProviderRule {
name: "File Line Length",
description: "Files should not span too many lines.",
nonTriggeringExamples: [
Repeat(count: 400, repeatedValue: "//\n").joinWithSeparator("")
Trigger(Repeat(count: 400, repeatedValue: "//\n").joinWithSeparator(""))
],
triggeringExamples: [
Repeat(count: 401, repeatedValue: "//\n").joinWithSeparator("")
Trigger(Repeat(count: 401, repeatedValue: "//\n").joinWithSeparator(""))
]
)

View File

@ -19,9 +19,11 @@ public struct ForceCastRule: ConfigProviderRule {
name: "Force Cast",
description: "Force casts should be avoided.",
nonTriggeringExamples: [
"NSNumber() as? Int\n"
Trigger("NSNumber() as? Int\n")
],
triggeringExamples: [ "NSNumber() ↓as! Int\n" ]
triggeringExamples: [
Trigger("NSNumber() ↓as! Int\n")
]
)
public func validateFile(file: File) -> [StyleViolation] {

View File

@ -19,10 +19,10 @@ public struct ForceTryRule: ConfigProviderRule {
name: "Force Try",
description: "Force tries should be avoided.",
nonTriggeringExamples: [
"func a() throws {}; do { try a() } catch {}"
Trigger("func a() throws {}; do { try a() } catch {}")
],
triggeringExamples: [
"func a() throws {}; ↓try! a()"
Trigger("func a() throws {}; ↓try! a()")
]
)

View File

@ -19,8 +19,13 @@ public struct LeadingWhitespaceRule: ConfigProviderRule {
identifier: "leading_whitespace",
name: "Leading Whitespace",
description: "Files should not contain leading whitespace.",
nonTriggeringExamples: [ "//\n" ],
triggeringExamples: [ "\n", " //\n" ]
nonTriggeringExamples: [
Trigger("//\n")
],
triggeringExamples: [
Trigger("\n"),
Trigger(" //\n")
]
)
public func validateFile(file: File) -> [StyleViolation] {

View File

@ -19,18 +19,18 @@ public struct LegacyConstantRule: CorrectableRule, ConfigProviderRule {
name: "Legacy Constant",
description: "Struct-scoped constants are preferred over legacy global constants.",
nonTriggeringExamples: [
"CGRect.infinite",
"CGPoint.zero",
"CGRect.zero",
"CGSize.zero",
"CGRect.null"
Trigger("CGRect.infinite"),
Trigger("CGPoint.zero"),
Trigger("CGRect.zero"),
Trigger("CGSize.zero"),
Trigger("CGRect.null")
],
triggeringExamples: [
"↓CGRectInfinite",
"↓CGPointZero",
"↓CGRectZero",
"↓CGSizeZero",
"↓CGRectNull"
Trigger("↓CGRectInfinite"),
Trigger("↓CGPointZero"),
Trigger("↓CGRectZero"),
Trigger("↓CGSizeZero"),
Trigger("↓CGRectNull")
],
corrections: [
"CGRectInfinite\n": "CGRect.infinite\n",

View File

@ -19,18 +19,18 @@ public struct LegacyConstructorRule: CorrectableRule, ConfigProviderRule {
name: "Legacy Constructor",
description: "Swift constructors are preferred over legacy convenience functions.",
nonTriggeringExamples: [
"CGPoint(x: 10, y: 10)",
"CGSize(width: 10, height: 10)",
"CGRect(x: 0, y: 0, width: 10, height: 10)",
"CGVector(dx: 10, dy: 10)",
"NSRange(location: 10, length: 1)",
Trigger("CGPoint(x: 10, y: 10)"),
Trigger("CGSize(width: 10, height: 10)"),
Trigger("CGRect(x: 0, y: 0, width: 10, height: 10)"),
Trigger("CGVector(dx: 10, dy: 10)"),
Trigger("NSRange(location: 10, length: 1)"),
],
triggeringExamples: [
"↓CGPointMake(10, 10)",
"↓CGSizeMake(10, 10)",
"↓CGRectMake(0, 0, 10, 10)",
"↓CGVectorMake(10, 10)",
"↓NSMakeRange(10, 1)",
Trigger("↓CGPointMake(10, 10)"),
Trigger("↓CGSizeMake(10, 10)"),
Trigger("↓CGRectMake(0, 0, 10, 10)"),
Trigger("↓CGVectorMake(10, 10)"),
Trigger("↓NSMakeRange(10, 1)"),
],
corrections: [
"CGPointMake(10, 10 )\n": "CGPoint(x: 10, y: 10)\n",

View File

@ -18,10 +18,10 @@ public struct LineLengthRule: ConfigProviderRule {
name: "Line Length",
description: "Lines should not span too many characters.",
nonTriggeringExamples: [
Repeat(count: 100, repeatedValue: "/").joinWithSeparator("") + "\n"
Trigger(String(count: 100, repeatedValue: Character("/")) + "\n")
],
triggeringExamples: [
Repeat(count: 101, repeatedValue: "/").joinWithSeparator("") + "\n"
Trigger(String(count: 101, repeatedValue: Character("/")) + "\n")
]
)

View File

@ -88,39 +88,39 @@ public struct MissingDocsRule: ConfigurableRule, OptInRule {
description: "Public declarations should be documented.",
nonTriggeringExamples: [
// public, documented using /// docs
"/// docs\npublic func a() {}\n",
Trigger("/// docs\npublic func a() {}\n"),
// public, documented using /** docs */
"/** docs */\npublic func a() {}\n",
Trigger("/** docs */\npublic func a() {}\n"),
// internal (implicit), undocumented
"func a() {}\n",
Trigger("func a() {}\n"),
// internal (explicit), undocumented
"internal func a() {}\n",
Trigger("internal func a() {}\n"),
// private, undocumented
"private func a() {}\n",
Trigger("private func a() {}\n"),
// internal (implicit), undocumented
"// regular comment\nfunc a() {}\n",
Trigger("// regular comment\nfunc a() {}\n"),
// internal (implicit), undocumented
"/* regular comment */\nfunc a() {}\n",
Trigger("/* regular comment */\nfunc a() {}\n"),
// protocol member is documented, but inherited member is not
"/// docs\npublic protocol A {\n/// docs\nvar b: Int { get } }\n" +
"/// docs\npublic struct C: A {\npublic let b: Int\n}",
Trigger("/// docs\npublic protocol A {\n/// docs\nvar b: Int { get } }\n" +
"/// docs\npublic struct C: A {\npublic let b: Int\n}"),
// locally-defined superclass member is documented, but subclass member is not
"/// docs\npublic class A {\n/// docs\npublic func b() {}\n}\n" +
"/// docs\npublic class B: A { override public func b() {} }\n",
Trigger("/// docs\npublic class A {\n/// docs\npublic func b() {}\n}\n" +
"/// docs\npublic class B: A { override public func b() {} }\n"),
// externally-defined superclass member is documented, but subclass member is not
"import Foundation\n/// docs\npublic class B: NSObject {\n" +
"// no docs\noverride public var description: String { fatalError() } }\n"
Trigger("import Foundation\n/// docs\npublic class B: NSObject {\n" +
"// no docs\noverride public var description: String { fatalError() } }\n")
],
triggeringExamples: [
// public, undocumented
"public func a() {}\n",
Trigger("public func a() {}\n"),
// public, undocumented
"// regular comment\npublic func a() {}\n",
Trigger("// regular comment\npublic func a() {}\n"),
// public, undocumented
"/* regular comment */\npublic func a() {}\n",
Trigger("/* regular comment */\npublic func a() {}\n"),
// protocol member and inherited member are both undocumented
"/// docs\npublic protocol A {\n// no docs\nvar b: Int { get } }\n" +
"/// docs\npublic struct C: A {\n\npublic let b: Int\n}"
Trigger("/// docs\npublic protocol A {\n// no docs\nvar b: Int { get } }\n" +
"/// docs\npublic struct C: A {\n\npublic let b: Int\n}")
]
)

View File

@ -19,16 +19,18 @@ public struct NestingRule: ASTRule, ConfigProviderRule {
name: "Nesting",
description: "Types should be nested at most 1 level deep, " +
"and statements should be nested at most 5 levels deep.",
nonTriggeringExamples: ["class", "struct", "enum"].flatMap { kind in
["\(kind) Class0 { \(kind) Class1 {} }\n",
"func func0() {\nfunc func1() {\nfunc func2() {\nfunc func3() {\nfunc func4() { " +
"func func5() {\n}\n}\n}\n}\n}\n}\n"]
} + ["enum Enum0 { enum Enum1 { case Case } }"],
nonTriggeringExamples: ["class", "struct", "enum"].map { kind in
Trigger("\(kind) Class0 { \(kind) Class1 {} }\n")
} + [
Trigger("func func0() {\nfunc func1() {\nfunc func2() {\nfunc func3() {\n" +
"func func4() { func func5() {\n}\n}\n}\n}\n}\n}\n"),
Trigger("enum Enum0 { enum Enum1 { case Case } }")
],
triggeringExamples: ["class", "struct", "enum"].map { kind in
"\(kind) A { \(kind) B { ↓\(kind) C {} } }\n"
} + [
"func func0() {\nfunc func1() {\nfunc func2() {\nfunc func3() {\nfunc func4() { " +
"func func5() {\n↓func func6() {\n}\n}\n}\n}\n}\n}\n}\n"
Trigger("\(kind) A { \(kind) B { ↓\(kind) C {} } }\n")
} + [
Trigger("func func0() {\nfunc func1() {\nfunc func2() {\nfunc func3() {\n" +
"func func4() { func func5() {\n↓func func6() {\n}\n}\n}\n}\n}\n}\n}\n")
]
)

View File

@ -32,15 +32,15 @@ public struct OpeningBraceRule: CorrectableRule, ConfigProviderRule {
description: "Opening braces should be preceded by a single space and on the same line " +
"as the declaration.",
nonTriggeringExamples: [
"func abc() {\n}",
"[].map() { $0 }",
"[].map({ })"
Trigger("func abc() {\n}"),
Trigger("[].map() { $0 }"),
Trigger("[].map({ })")
],
triggeringExamples: [
"func abc(↓){\n}",
"func abc()↓\n\t{ }",
"[].map(↓){ $0 }",
"[].map↓( { } )"
Trigger("func abc(↓){\n}"),
Trigger("func abc()↓\n\t{ }"),
Trigger("[].map(↓){ $0 }"),
Trigger("[].map↓( { } )")
],
corrections: [
"struct Rule{}\n": "struct Rule {}\n",

View File

@ -19,17 +19,17 @@ public struct OperatorFunctionWhitespaceRule: ConfigProviderRule {
name: "Operator Function Whitespace",
description: "Operators should be surrounded by a single whitespace when defining them.",
nonTriggeringExamples: [
"func <| (lhs: Int, rhs: Int) -> Int {}\n",
"func <|< <A>(lhs: A, rhs: A) -> A {}\n",
"func abc(lhs: Int, rhs: Int) -> Int {}\n"
Trigger("func <| (lhs: Int, rhs: Int) -> Int {}\n"),
Trigger("func <|< <A>(lhs: A, rhs: A) -> A {}\n"),
Trigger("func abc(lhs: Int, rhs: Int) -> Int {}\n")
],
triggeringExamples: [
"↓func <|(lhs: Int, rhs: Int) -> Int {}\n", // no spaces after
"↓func <|<<A>(lhs: A, rhs: A) -> A {}\n", // no spaces after
"↓func <| (lhs: Int, rhs: Int) -> Int {}\n", // 2 spaces after
"↓func <|< <A>(lhs: A, rhs: A) -> A {}\n", // 2 spaces after
"↓func <| (lhs: Int, rhs: Int) -> Int {}\n", // 2 spaces before
"↓func <|< <A>(lhs: A, rhs: A) -> A {}\n" // 2 spaces before
Trigger("↓func <|(lhs: Int, rhs: Int) -> Int {}\n"), // no spaces after
Trigger("↓func <|<<A>(lhs: A, rhs: A) -> A {}\n"), // no spaces after
Trigger("↓func <| (lhs: Int, rhs: Int) -> Int {}\n"), // 2 spaces after
Trigger("↓func <|< <A>(lhs: A, rhs: A) -> A {}\n"), // 2 spaces after
Trigger("↓func <| (lhs: Int, rhs: Int) -> Int {}\n"), // 2 spaces before
Trigger("↓func <|< <A>(lhs: A, rhs: A) -> A {}\n") // 2 spaces before
]
)

View File

@ -21,22 +21,22 @@ public struct ReturnArrowWhitespaceRule: ConfigProviderRule {
description: "Return arrow and return type should be separated by a single space or on a " +
"separate line.",
nonTriggeringExamples: [
"func abc() -> Int {}\n",
"func abc() -> [Int] {}\n",
"func abc() -> (Int, Int) {}\n",
"var abc = {(param: Int) -> Void in }\n",
"func abc() ->\n Int {}\n",
"func abc()\n -> Int {}\n"
Trigger("func abc() -> Int {}\n"),
Trigger("func abc() -> [Int] {}\n"),
Trigger("func abc() -> (Int, Int) {}\n"),
Trigger("var abc = {(param: Int) -> Void in }\n"),
Trigger("func abc() ->\n Int {}\n"),
Trigger("func abc()\n -> Int {}\n")
],
triggeringExamples: [
"func abc(↓)->Int {}\n",
"func abc(↓)->[Int] {}\n",
"func abc(↓)->(Int, Int) {}\n",
"func abc(↓)-> Int {}\n",
"func abc(↓) ->Int {}\n",
"func abc(↓) -> Int {}\n",
"var abc = {(param: Int↓) ->Bool in }\n",
"var abc = {(param: Int↓)->Bool in }\n"
Trigger("func abc(↓)->Int {}\n"),
Trigger("func abc(↓)->[Int] {}\n"),
Trigger("func abc(↓)->(Int, Int) {}\n"),
Trigger("func abc(↓)-> Int {}\n"),
Trigger("func abc(↓) ->Int {}\n"),
Trigger("func abc(↓) -> Int {}\n"),
Trigger("var abc = {(param: Int↓) ->Bool in }\n"),
Trigger("var abc = {(param: Int↓)->Bool in }\n")
]
)

View File

@ -21,18 +21,18 @@ public struct StatementPositionRule: CorrectableRule, ConfigProviderRule {
description: "Else and catch should be on the same line, one space after the previous " +
"declaration.",
nonTriggeringExamples: [
"} else if {",
"} else {",
"} catch {",
"\"}else{\"",
"struct A { let catchphrase: Int }\nlet a = A(\n catchphrase: 0\n)",
"struct A { let `catch`: Int }\nlet a = A(\n `catch`: 0\n)"
Trigger("} else if {"),
Trigger("} else {"),
Trigger("} catch {"),
Trigger("\"}else{\""),
Trigger("struct A { let catchphrase: Int }\nlet a = A(\n catchphrase: 0\n)"),
Trigger("struct A { let `catch`: Int }\nlet a = A(\n `catch`: 0\n)")
],
triggeringExamples: [
"↓}else if {",
"}↓ else {",
"}↓\ncatch {",
"}\n\t↓ catch {"
Trigger("↓}else if {"),
Trigger("}↓ else {"),
Trigger("}↓\ncatch {"),
Trigger("}\n\t↓ catch {")
],
corrections: [
"}\n else {\n": "} else {\n",

View File

@ -26,18 +26,18 @@ public struct TodoRule: ConfigProviderRule {
name: "Todo",
description: "TODOs and FIXMEs should be avoided.",
nonTriggeringExamples: [
"// notaTODO:\n",
"// notaFIXME:\n"
Trigger("// notaTODO:\n"),
Trigger("// notaFIXME:\n")
],
triggeringExamples: [
"// ↓TODO:\n",
"// ↓FIXME:\n",
"// ↓TODO(note)\n",
"// ↓FIXME(note)\n",
"/* ↓FIXME: */\n",
"/* ↓TODO: */\n",
"/** ↓FIXME: */\n",
"/** ↓TODO: */\n"
Trigger("// ↓TODO:\n"),
Trigger("// ↓FIXME:\n"),
Trigger("// ↓TODO(note)\n"),
Trigger("// ↓FIXME(note)\n"),
Trigger("/* ↓FIXME: */\n"),
Trigger("/* ↓TODO: */\n"),
Trigger("/** ↓FIXME: */\n"),
Trigger("/** ↓TODO: */\n")
]
)

View File

@ -37,11 +37,11 @@ public struct TrailingNewlineRule: CorrectableRule, ConfigProviderRule {
name: "Trailing Newline",
description: "Files should have a single trailing newline.",
nonTriggeringExamples: [
"let a = 0\n"
Trigger("let a = 0\n")
],
triggeringExamples: [
"let a = 0",
"let a = 0\n\n"
Trigger("let a = 0"),
Trigger("let a = 0\n\n")
],
corrections: [
"let a = 0": "let a = 0\n",

View File

@ -25,10 +25,12 @@ public struct TrailingSemicolonRule: CorrectableRule, ConfigProviderRule {
identifier: "trailing_semicolon",
name: "Trailing Semicolon",
description: "Lines should not have trailing semicolons.",
nonTriggeringExamples: [ "let a = 0\n" ],
nonTriggeringExamples: [
Trigger("let a = 0\n")
],
triggeringExamples: [
"let a = 0↓;\n",
"let a = 0↓;\nlet b = 1\n"
Trigger("let a = 0↓;\n"),
Trigger("let a = 0↓;\nlet b = 1\n")
],
corrections: [
"let a = 0;\n": "let a = 0\n",

View File

@ -19,8 +19,12 @@ public struct TrailingWhitespaceRule: CorrectableRule, ConfigProviderRule {
identifier: "trailing_whitespace",
name: "Trailing Whitespace",
description: "Lines should not have trailing whitespace.",
nonTriggeringExamples: [ "//\n" ],
triggeringExamples: [ "// \n" ],
nonTriggeringExamples: [
Trigger("//\n")
],
triggeringExamples: [
Trigger("// \n")
],
corrections: [ "// \n": "//\n" ]
)

View File

@ -24,14 +24,15 @@ public struct TypeBodyLengthRule: ASTRule, ConfigProviderRule {
description: "Type bodies should not span too many lines.",
nonTriggeringExamples: ["class", "struct", "enum"].flatMap({ type in
[
example(type, "let abc = 0\n", 199),
example(type, "\n", 201),
example(type, "// this is a comment\n", 201),
example(type, "let abc = 0\n", 199, "\n/* this is\na multiline comment\n*/\n")
Trigger(example(type, "let abc = 0\n", 199)),
Trigger(example(type, "\n", 201)),
Trigger(example(type, "// this is a comment\n", 201)),
Trigger(example(type, "let abc = 0\n", 199, "\n" +
"/* this is\na multiline comment\n*/\n"))
]
}),
triggeringExamples: ["class", "struct", "enum"].map({ type in
example(type, "let abc = 0\n", 201)
Trigger(example(type, "let abc = 0\n", 201))
})
)

View File

@ -25,18 +25,18 @@ public struct TypeNameRule: ASTRule, ConfigProviderRule {
"uppercase character and span between 3 and 40 characters in length.",
nonTriggeringExamples: ["class", "struct", "enum"].flatMap({ type in
[
"\(type) MyType {}",
"private \(type) _MyType {}",
"\(type) " + Repeat(count: 40, repeatedValue: "A").joinWithSeparator("") + " {}"
Trigger("\(type) MyType {}"),
Trigger("private \(type) _MyType {}"),
Trigger("\(type) " + String(count: 40, repeatedValue: Character("A")) + " {}")
]
}),
triggeringExamples: ["class", "struct", "enum"].flatMap({ type in
[
"\(type) myType {}",
"\(type) _MyType {}",
"private ↓\(type) MyType_ {}",
"\(type) My {}",
"\(type) " + Repeat(count: 41, repeatedValue: "A").joinWithSeparator("") + " {}"
Trigger("\(type) myType {}"),
Trigger("\(type) _MyType {}"),
Trigger("private ↓\(type) MyType_ {}"),
Trigger("\(type) My {}"),
Trigger("\(type) " + String(count: 41, repeatedValue: Character("A")) + " {}")
]
})
)

View File

@ -121,48 +121,56 @@ public struct ValidDocsRule: ConfigProviderRule {
name: "Valid Docs",
description: "Documented declarations should be valid.",
nonTriggeringExamples: [
"/// docs\npublic func a() {}\n",
"/// docs\n/// - parameter param: this is void\npublic func a(param: Void) {}\n",
"/// docs\n/// - parameter label: this is void\npublic func a(label param: Void) {}",
"/// docs\n/// - parameter param: this is void\npublic func a(label param: Void) {}",
"/// docs\n/// - returns: false\npublic func no() -> Bool { return false }",
"/// Returns false\npublic func no() -> Bool { return false }",
"/// Returns false\nvar no: Bool { return false }",
"/// docs\nvar no: Bool { return false }",
"/// docs\n/// - throws: NSError\nfunc a() throws {}",
"/// docs\n/// - parameter param: this is void\n/// - returns: false" +
"\npublic func no(param: (Void -> Void)?) -> Bool { return false }",
"/// docs\n/// - parameter param: this is void" +
"\n///- parameter param2: this is void too\n/// - returns: false",
"\npublic func no(param: (Void -> Void)?, param2: String->Void) -> Bool {return false}",
"/// docs\n/// - parameter param: this is void" +
"\npublic func no(param: (Void -> Void)?) {}",
"/// docs\n/// - parameter param: this is void" +
"\n///- parameter param2: this is void too" +
"\npublic func no(param: (Void -> Void)?, param2: String->Void) {}",
"/// docs👨👩👧👧\n/// - returns: false\npublic func no() -> Bool { return false }",
"/// docs\n/// - returns: tuple\npublic func no() -> (Int, Int) {return (1, 2)}",
Trigger("/// docs\npublic func a() {}\n"),
Trigger("/// docs\n/// - parameter param: this is void\n" +
"public func a(param: Void) {}\n"),
Trigger("/// docs\n/// - parameter label: this is void\n" +
"public func a(label param: Void) {}"),
Trigger("/// docs\n/// - parameter param: this is void\n" +
"public func a(label param: Void) {}"),
Trigger("/// docs\n/// - returns: false\npublic func no() -> Bool { return false }"),
Trigger("/// Returns false\npublic func no() -> Bool { return false }"),
Trigger("/// Returns false\nvar no: Bool { return false }"),
Trigger("/// docs\nvar no: Bool { return false }"),
Trigger("/// docs\n/// - throws: NSError\nfunc a() throws {}"),
Trigger("/// docs\n/// - parameter param: this is void\n/// - returns: false" +
"\npublic func no(param: (Void -> Void)?) -> Bool { return false }"),
Trigger("/// docs\n/// - parameter param: this is void" +
"\n///- parameter param2: this is void too\n/// - returns: false"),
Trigger("\npublic func no(param: (Void -> Void)?, param2: String->Void) -> Bool" +
" {return false}"),
Trigger("/// docs\n/// - parameter param: this is void" +
"\npublic func no(param: (Void -> Void)?) {}"),
Trigger("/// docs\n/// - parameter param: this is void" +
"\n///- parameter param2: this is void too" +
"\npublic func no(param: (Void -> Void)?, param2: String->Void) {}"),
Trigger("/// docs👨👩👧👧\n/// - returns: false\n" +
"public func no() -> Bool { return false }"),
Trigger("/// docs\n" +
"/// - returns: tuple\npublic func no() -> (Int, Int) {return (1, 2)}"),
],
triggeringExamples: [
"/// docs\npublic ↓func a(param: Void) {}\n",
"/// docs\n/// - parameter invalid: this is void\npublic ↓func a(param: Void) {}",
"/// docs\n/// - parameter invalid: this is void\npublic ↓func a(label param: Void) {}",
"/// docs\n/// - parameter invalid: this is void\npublic ↓func a() {}",
"/// docs\npublic ↓func no() -> Bool { return false }",
"/// Returns false\npublic ↓func a() {}",
"/// docs\n/// - throws: NSError\n↓func a() {}",
"/// docs\n↓func a() throws {}",
"/// docs\n/// - parameter param: this is void" +
"\npublic ↓func no(param: (Void -> Void)?) -> Bool { return false }",
"/// docs\n/// - parameter param: this is void" +
"\n///- parameter param2: this is void too" +
"\npublic ↓func no(param: (Void -> Void)?, param2: String->Void) -> " +
"Bool {return false}",
"/// docs\n/// - parameter param: this is void\n/// - returns: false" +
"\npublic ↓func no(param: (Void -> Void)?) {}",
"/// docs\n/// - parameter param: this is void" +
"\n///- parameter param2: this is void too\n/// - returns: false" +
"\npublic ↓func no(param: (Void -> Void)?, param2: String->Void) {}",
Trigger("/// docs\npublic ↓func a(param: Void) {}\n"),
Trigger("/// docs\n/// - parameter invalid: this is void\n" +
"public ↓func a(param: Void) {}"),
Trigger("/// docs\n/// - parameter invalid: this is void\n" +
"public ↓func a(label param: Void) {}"),
Trigger("/// docs\n/// - parameter invalid: this is void\npublic ↓func a() {}"),
Trigger("/// docs\npublic ↓func no() -> Bool { return false }"),
Trigger("/// Returns false\npublic ↓func a() {}"),
Trigger("/// docs\n/// - throws: NSError\n↓func a() {}"),
Trigger("/// docs\n↓func a() throws {}"),
Trigger("/// docs\n/// - parameter param: this is void" +
"\npublic ↓func no(param: (Void -> Void)?) -> Bool { return false }"),
Trigger("/// docs\n/// - parameter param: this is void" +
"\n///- parameter param2: this is void too" +
"\npublic ↓func no(param: (Void -> Void)?, param2: String->Void) -> " +
"Bool {return false}"),
Trigger("/// docs\n/// - parameter param: this is void\n/// - returns: false" +
"\npublic ↓func no(param: (Void -> Void)?) {}"),
Trigger("/// docs\n/// - parameter param: this is void" +
"\n///- parameter param2: this is void too\n/// - returns: false" +
"\npublic ↓func no(param: (Void -> Void)?, param2: String->Void) {}"),
]
)

View File

@ -27,22 +27,22 @@ public struct VariableNameRule: ASTRule, ConfigProviderRule {
"when they are declared static and immutable. Variable names should not be too " +
"long or too short.",
nonTriggeringExamples: [
"let myLet = 0",
"var myVar = 0",
"private let _myLet = 0",
"class Abc { static let MyLet = 0 }",
"let URL: NSURL? = nil"
Trigger("let myLet = 0"),
Trigger("var myVar = 0"),
Trigger("private let _myLet = 0"),
Trigger("class Abc { static let MyLet = 0 }"),
Trigger("let URL: NSURL? = nil")
],
triggeringExamples: [
"↓let MyLet = 0",
"↓let _myLet = 0",
"private ↓let myLet_ = 0",
"↓let myExtremelyVeryVeryVeryVeryVeryVeryLongLet = 0",
"↓var myExtremelyVeryVeryVeryVeryVeryVeryLongVar = 0",
"private ↓let _myExtremelyVeryVeryVeryVeryVeryVeryLongLet = 0",
"↓let i = 0",
"↓var id = 0",
"private ↓let _i = 0"
Trigger("↓let MyLet = 0"),
Trigger("↓let _myLet = 0"),
Trigger("private ↓let myLet_ = 0"),
Trigger("↓let myExtremelyVeryVeryVeryVeryVeryVeryLongLet = 0"),
Trigger("↓var myExtremelyVeryVeryVeryVeryVeryVeryLongVar = 0"),
Trigger("private ↓let _myExtremelyVeryVeryVeryVeryVeryVeryLongLet = 0"),
Trigger("↓let i = 0"),
Trigger("↓var id = 0"),
Trigger("private ↓let _i = 0")
]
)

View File

@ -67,38 +67,47 @@ extension XCTestCase {
let nonTriggers = ruleDescription.nonTriggeringExamples
// Non-triggering examples don't violate
XCTAssert(nonTriggers.flatMap({ violations($0, ruleDescription) }).isEmpty)
for nonTrigger in nonTriggers {
XCTAssertTrue(violations(nonTrigger.string, ruleDescription).isEmpty,
"Non triggering example violated.",
file: nonTrigger.file, line: nonTrigger.line)
}
var violationsCount = 0
// Triggering examples violate
for trigger in triggers {
let triggerViolations = violations(trigger, ruleDescription)
violationsCount += triggerViolations.count
let string = trigger.string
let triggerViolations = violations(string, ruleDescription)
XCTAssertFalse(triggerViolations.isEmpty,
"Triggering example did not violate.",
file: trigger.file, line: trigger.line)
// Triggering examples with violation markers violate at the marker's location
let markerLocation = (trigger as NSString).rangeOfString(violationMarker).location
if markerLocation == NSNotFound { continue }
let cleanTrigger = trigger.stringByReplacingOccurrencesOfString(violationMarker,
let markerLocation = (string as NSString).rangeOfString(violationMarker).location
if markerLocation == NSNotFound {
continue
}
let cleanTrigger = string.stringByReplacingOccurrencesOfString(violationMarker,
withString: "")
XCTAssertEqual(triggerViolations.first!.location,
Location(file: File(contents: cleanTrigger), characterOffset: markerLocation))
Location(file: File(contents: cleanTrigger), characterOffset: markerLocation),
"Location of violation was incorrect.",
file: trigger.file, line: trigger.line)
}
// Triggering examples violate
XCTAssertEqual(violationsCount, triggers.count)
// Comment doesn't violate
XCTAssertEqual(
triggers.flatMap({ violations("/*\n " + $0 + "\n */", ruleDescription) }).count,
triggers.flatMap({ violations("/*\n " + $0.string + "\n */", ruleDescription) }).count,
commentDoesntViolate ? 0 : triggers.count
)
// String doesn't violate
XCTAssertEqual(
triggers.flatMap({ violations($0.toStringLiteral(), ruleDescription) }).count,
triggers.flatMap({ violations($0.string.toStringLiteral(), ruleDescription) }).count,
stringDoesntViolate ? 0 : triggers.count
)
// "disable" command doesn't violate
let command = "// swiftlint:disable \(ruleDescription.identifier)\n"
XCTAssert(triggers.flatMap({ violations(command + $0, ruleDescription) }).isEmpty)
XCTAssert(triggers.flatMap({ violations(command + $0.string, ruleDescription) }).isEmpty)
// corrections
ruleDescription.corrections.forEach(assertCorrection)