@testable import SwiftLintBuiltInRules import TestHelpers final class LineLengthRuleTests: SwiftLintTestCase { private static let longString = String(repeating: "a", count: 121) private let longFunctionDeclarations = [ Example(""" public func superDuperLongFunctionDeclaration(a: String, b: String, \ c: String, d: String, e: String, f: String, g: String, h: String, i: String, \ j: String, k: String, l: String, m: String, n: String, o: String, p: String, \ q: String, r: String, s: String, t: String, u: String, v: String, w: String, \ x: String, y: String, z: String) {} """), Example(""" func superDuperLongFunctionDeclaration(a: String, b: String, \ c: String, d: String, e: String, f: String, g: String, h: String, i: String, \ j: String, k: String, l: String, m: String, n: String, o: String, p: String, \ q: String, r: String, s: String, t: String, u: String, v: String, w: String, \ x: String, y: String, z: String) {} """), Example(""" struct S { public init(a: String, b: String, c: String, d: String, e: String, f: String, \ g: String, h: String, i: String, j: String, k: String, l: String, \ m: String, n: String, o: String, p: String, q: String, r: String, \ s: String, t: String, u: String, v: String, w: String, x: String, \ y: String, z: String) throws { // ... } } """), Example(""" struct S { subscript(a: String, b: String, c: String, d: String, e: String, f: String, \ g: String, h: String, i: String, j: String, k: String, l: String, \ m: String, n: String, o: String, p: String, q: String, r: String, \ s: String, t: String, u: String, v: String, w: String, x: String, \ y: String, z: String) -> Int { // ... return 0 } } """), ] private let longFunctionCalls = [ Example(""" superDuperLongFunctionCall(a: "A", b: "B", c: "C", d: "D", e: "E", f: "F", \ g: "G", h: "H", i: "I", j: "J", k: "K", l: "L", m: "M", n: "N", o: "O", p: "P", \ q: "Q", r: "R", s: "S", t: "T", u: "U", v: "V", w: "W", x: "X", y: "Y", z: "Z") """), Example(""" func test() { let _ = superDuperLongFunctionCall(a: "A", b: "B", c: "C", d: "D", e: "E", f: "F", \ g: "G", h: "H", i: "I", j: "J", k: "K", l: "L", m: "M", n: "N", o: "O", p: "P", \ q: "Q", r: "R", s: "S", t: "T", u: "U", v: "V", w: "W", x: "X", y: "Y", z: "Z") } """), ] private let longComment = Example(String(repeating: "/", count: 121) + "\n") private let longBlockComment = Example("/*" + String(repeating: " ", count: 121) + "*/\n") private let longRealBlockComment = Example(""" /* \(LineLengthRuleTests.longString) */ """) private let declarationWithTrailingLongComment = Example("let foo = 1 " + String(repeating: "/", count: 121) + "\n") private let interpolatedString = Example("print(\"\\(value)" + String(repeating: "A", count: 113) + "\" )\n") private let plainString = Example("print(\"" + LineLengthRuleTests.longString + ")\"\n") private let multilineString = Example(""" let multilineString = \"\"\" \(LineLengthRuleTests.longString) \"\"\" """) private let tripleStringSingleLine = Example( "let tripleString = \"\"\"\(LineLengthRuleTests.longString)\"\"\"\n" ) private let poundStringSingleLine = Example("let poundString = #\"\(LineLengthRuleTests.longString)\"#\n") private let multilineStringWithExpression = Example(""" let multilineString = \"\"\" \(LineLengthRuleTests.longString) \"\"\"; let a = 1 """) private let multilineStringWithNewlineExpression = Example(""" let multilineString = \"\"\" \(LineLengthRuleTests.longString) \"\"\" ; let a = 1 """) private let multilineStringFail = Example(""" let multilineString = "A" + "\(LineLengthRuleTests.longString)" """) private let multilineStringWithFunction = Example(""" let multilineString = \"\"\" \(LineLengthRuleTests.longString) \"\"\".functionCall() """) // Regex literal examples // swiftlint:disable line_length private let regexLiteral = Example(""" let emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$|^\(LineLengthRuleTests.longString)$/ """) private let regexLiteralWithCapture = Example(""" let urlRegex = /^(https?:\\/\\/)?(www\\.)?([a-zA-Z0-9.-]+\\.[a-zA-Z]{2,})(\\/\(LineLengthRuleTests.longString))?$/ """) private let regexLiteralMultiline = Example(""" let complexRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$|^very\\.long\\.regex\\.pattern\\.here\\.with\\.many\\.dots\\.and\\.extra\\.text$/ """) // swiftlint:enable line_length private let regexLiteralFail = Example(""" let longRegexString = "\(LineLengthRuleTests.longString)" """) func testLineLength() { verifyRule(LineLengthRule.description, commentDoesntViolate: false, stringDoesntViolate: false) } func testLineLengthWithIgnoreFunctionDeclarationsEnabled() { let baseDescription = LineLengthRule.description let description = baseDescription.with( nonTriggeringExamples: baseDescription.nonTriggeringExamples + longFunctionDeclarations, triggeringExamples: longFunctionCalls ) verifyRule( description, ruleConfiguration: ["ignores_function_declarations": true], commentDoesntViolate: false, stringDoesntViolate: false ) } func testLineLengthWithIgnoreCommentsEnabled() { let baseDescription = LineLengthRule.description let triggeringExamples = longFunctionDeclarations + [declarationWithTrailingLongComment] let nonTriggeringExamples = [longComment, longBlockComment, longRealBlockComment] let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples) .with(triggeringExamples: triggeringExamples) verifyRule(description, ruleConfiguration: ["ignores_comments": true], commentDoesntViolate: false, stringDoesntViolate: false, skipCommentTests: true) } func testLineLengthWithIgnoreURLsEnabled() { let url = "https://github.com/realm/SwiftLint" let triggeringLines = [Example(String(repeating: "/", count: 121) + "\(url)\n")] let nonTriggeringLines = [ Example("\(url) " + String(repeating: "/", count: 118) + " \(url)\n"), Example("\(url)/" + String(repeating: "a", count: 120)), ] let baseDescription = LineLengthRule.description let nonTriggeringExamples = baseDescription.nonTriggeringExamples + nonTriggeringLines let triggeringExamples = baseDescription.triggeringExamples + triggeringLines let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples) .with(triggeringExamples: triggeringExamples) verifyRule(description, ruleConfiguration: ["ignores_urls": true], commentDoesntViolate: false, stringDoesntViolate: false) } func testLineLengthWithIgnoreInterpolatedStringsTrue() { let triggeringLines = [plainString] let nonTriggeringLines = [interpolatedString] let baseDescription = LineLengthRule.description let nonTriggeringExamples = baseDescription.nonTriggeringExamples + nonTriggeringLines let triggeringExamples = baseDescription.triggeringExamples + triggeringLines let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples) .with(triggeringExamples: triggeringExamples) verifyRule(description, ruleConfiguration: ["ignores_interpolated_strings": true], commentDoesntViolate: false, stringDoesntViolate: false) } func testLineLengthWithIgnoreMultilineStringsTrue() { let triggeringLines = [ multilineStringFail, tripleStringSingleLine, poundStringSingleLine, ] let nonTriggeringLines = [ multilineString, multilineStringWithExpression, multilineStringWithNewlineExpression, multilineStringWithFunction, ] let baseDescription = LineLengthRule.description let nonTriggeringExamples = baseDescription.nonTriggeringExamples + nonTriggeringLines let triggeringExamples = baseDescription.triggeringExamples + triggeringLines let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples) .with(triggeringExamples: triggeringExamples) verifyRule(description, ruleConfiguration: ["ignores_multiline_strings": true], commentDoesntViolate: false, stringDoesntViolate: false) } func testLineLengthWithIgnoreInterpolatedStringsFalse() { let triggeringLines = [plainString, interpolatedString] let baseDescription = LineLengthRule.description let nonTriggeringExamples = baseDescription.nonTriggeringExamples let triggeringExamples = baseDescription.triggeringExamples + triggeringLines let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples) .with(triggeringExamples: triggeringExamples) verifyRule(description, ruleConfiguration: ["ignores_interpolated_strings": false], commentDoesntViolate: false, stringDoesntViolate: false) } func testLineLengthWithExcludedLinesPatterns() { let nonTriggeringLines = [plainString, interpolatedString] let baseDescription = LineLengthRule.description let nonTriggeringExamples = baseDescription.nonTriggeringExamples + nonTriggeringLines let triggeringExamples = baseDescription.triggeringExamples let description = baseDescription .with(nonTriggeringExamples: nonTriggeringExamples) .with(triggeringExamples: triggeringExamples) verifyRule( description, ruleConfiguration: ["excluded_lines_patterns": ["^print"]], commentDoesntViolate: false, stringDoesntViolate: false ) } func testLineLengthWithEmptyExcludedLinesPatterns() { let triggeringLines = [plainString, interpolatedString] let baseDescription = LineLengthRule.description let nonTriggeringExamples = baseDescription.nonTriggeringExamples let triggeringExamples = baseDescription.triggeringExamples + triggeringLines let description = baseDescription .with(nonTriggeringExamples: nonTriggeringExamples) .with(triggeringExamples: triggeringExamples) verifyRule( description, ruleConfiguration: ["excluded_lines_patterns": []], commentDoesntViolate: false, stringDoesntViolate: false ) } func testLineLengthWithIgnoreRegexLiteralsTrue() { let triggeringLines = [ regexLiteralFail, plainString, ] let nonTriggeringLines = [ regexLiteral, regexLiteralWithCapture, regexLiteralMultiline, ] let baseDescription = LineLengthRule.description let nonTriggeringExamples = baseDescription.nonTriggeringExamples + nonTriggeringLines let triggeringExamples = baseDescription.triggeringExamples + triggeringLines let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples) .with(triggeringExamples: triggeringExamples) verifyRule(description, ruleConfiguration: ["ignores_regex_literals": true], commentDoesntViolate: false, stringDoesntViolate: false) } }