mirror of
https://github.com/realm/SwiftLint.git
synced 2026-06-06 20:18:40 +00:00
295 lines
12 KiB
Swift
295 lines
12 KiB
Swift
import Foundation
|
|
import TestHelpers
|
|
import Testing
|
|
|
|
@testable import SwiftLintBuiltInRules
|
|
|
|
private let fixturesDirectory = "\(TestResources.path())/FileHeaderRuleFixtures"
|
|
|
|
@Suite(.rulesRegistered)
|
|
struct FileHeaderRuleTests {
|
|
private func validate(fileName: String, using configuration: Any) throws -> [StyleViolation] {
|
|
let file = TestResources.path()
|
|
.appending(path: "FileHeaderRuleFixtures", directoryHint: .isDirectory)
|
|
.appending(path: fileName, directoryHint: .notDirectory)
|
|
let rule = try FileHeaderRule(configuration: configuration)
|
|
return rule.validate(file: SwiftLintFile(path: file)!)
|
|
}
|
|
|
|
@Test
|
|
func fileHeaderWithDefaultConfiguration() {
|
|
verifyRule(FileHeaderRule.description, skipCommentTests: true)
|
|
}
|
|
|
|
@Test
|
|
func fileHeaderWithRequiredString() {
|
|
let nonTriggeringExamples = [
|
|
Example("// **Header"),
|
|
Example("//\n// **Header"),
|
|
]
|
|
let triggeringExamples = [
|
|
Example("↓// Copyright\n"),
|
|
Example("let foo = \"**Header\""),
|
|
Example("let foo = 2 // **Header"),
|
|
Example("let foo = 2\n// **Header"),
|
|
Example("let foo = 2 // **Header"),
|
|
]
|
|
let description = FileHeaderRule.description
|
|
.with(nonTriggeringExamples: nonTriggeringExamples)
|
|
.with(triggeringExamples: triggeringExamples)
|
|
|
|
verifyRule(
|
|
description,
|
|
ruleConfiguration: ["required_string": "**Header"],
|
|
stringDoesntViolate: false,
|
|
skipCommentTests: true,
|
|
skipDisableCommandTests: true,
|
|
testMultiByteOffsets: false,
|
|
testShebang: false
|
|
)
|
|
}
|
|
|
|
@Test
|
|
func fileHeaderWithRequiredPattern() {
|
|
let nonTriggeringExamples = [
|
|
Example("// Copyright © 2016 Realm"),
|
|
Example("//\n// Copyright © 2016 Realm)"),
|
|
]
|
|
let triggeringExamples = [
|
|
Example("↓// Copyright\n"),
|
|
Example("↓// Copyright © foo Realm"),
|
|
Example("↓// Copyright © 2016 MyCompany"),
|
|
]
|
|
let description = FileHeaderRule.description
|
|
.with(nonTriggeringExamples: nonTriggeringExamples)
|
|
.with(triggeringExamples: triggeringExamples)
|
|
|
|
verifyRule(description, ruleConfiguration: ["required_pattern": "\\d{4} Realm"],
|
|
stringDoesntViolate: false, skipCommentTests: true,
|
|
testMultiByteOffsets: false)
|
|
}
|
|
|
|
@Test
|
|
func fileHeaderWithRequiredStringAndURLComment() {
|
|
let nonTriggeringExamples = [
|
|
Example("/* Check this url: https://github.com/realm/SwiftLint */")
|
|
]
|
|
let triggeringExamples = [
|
|
Example("/* Check this url: https://github.com/apple/swift */")
|
|
]
|
|
let description = FileHeaderRule.description
|
|
.with(nonTriggeringExamples: nonTriggeringExamples)
|
|
.with(triggeringExamples: triggeringExamples)
|
|
|
|
let config = ["required_string": "/* Check this url: https://github.com/realm/SwiftLint */"]
|
|
verifyRule(description, ruleConfiguration: config,
|
|
stringDoesntViolate: false, skipCommentTests: true,
|
|
testMultiByteOffsets: false)
|
|
}
|
|
|
|
@Test
|
|
func fileHeaderWithForbiddenString() {
|
|
let nonTriggeringExamples = [
|
|
Example("// Copyright\n"),
|
|
Example("let foo = \"**All rights reserved.\""),
|
|
Example("let foo = 2 // **All rights reserved."),
|
|
Example("let foo = 2\n// **All rights reserved."),
|
|
Example("let foo = 2 // **All rights reserved."),
|
|
]
|
|
let triggeringExamples = [
|
|
Example("// ↓**All rights reserved."),
|
|
Example("//\n// ↓**All rights reserved."),
|
|
]
|
|
let description = FileHeaderRule.description
|
|
.with(nonTriggeringExamples: nonTriggeringExamples)
|
|
.with(triggeringExamples: triggeringExamples)
|
|
|
|
verifyRule(description, ruleConfiguration: ["forbidden_string": "**All rights reserved."],
|
|
skipCommentTests: true)
|
|
}
|
|
|
|
@Test
|
|
func fileHeaderWithForbiddenPattern() {
|
|
let nonTriggeringExamples = [
|
|
Example("// Copyright\n"),
|
|
Example("// FileHeaderRuleTests.m\n"),
|
|
Example("let foo = \"FileHeaderRuleTests.swift\""),
|
|
Example("let foo = 2 // FileHeaderRuleTests.swift."),
|
|
Example("let foo = 2\n // FileHeaderRuleTests.swift."),
|
|
]
|
|
let triggeringExamples = [
|
|
Example("//↓ FileHeaderRuleTests.swift"),
|
|
Example("//\n//↓ FileHeaderRuleTests.swift"),
|
|
]
|
|
let description = FileHeaderRule.description
|
|
.with(nonTriggeringExamples: nonTriggeringExamples)
|
|
.with(triggeringExamples: triggeringExamples)
|
|
|
|
verifyRule(description, ruleConfiguration: ["forbidden_pattern": "\\s\\w+\\.swift"],
|
|
skipCommentTests: true)
|
|
}
|
|
|
|
@Test
|
|
func fileHeaderWithForbiddenPatternAndDocComment() {
|
|
let nonTriggeringExamples = [
|
|
Example("/// This is great tool with tests.\nclass GreatTool {}"),
|
|
Example("class GreatTool {}"),
|
|
]
|
|
let triggeringExamples = [
|
|
Example("// FileHeaderRule↓Tests.swift"),
|
|
Example("//\n// FileHeaderRule↓Tests.swift"),
|
|
]
|
|
let description = FileHeaderRule.description
|
|
.with(nonTriggeringExamples: nonTriggeringExamples)
|
|
.with(triggeringExamples: triggeringExamples)
|
|
|
|
verifyRule(description, ruleConfiguration: ["forbidden_pattern": "[tT]ests"],
|
|
skipCommentTests: true, testMultiByteOffsets: false)
|
|
}
|
|
|
|
@Test
|
|
func fileHeaderWithRequiredStringUsingFilenamePlaceholder() throws {
|
|
let configuration = ["required_string": "// SWIFTLINT_CURRENT_FILENAME"]
|
|
|
|
// Non triggering tests
|
|
try #expect(validate(fileName: "FileNameMatchingSimple.swift", using: configuration).isEmpty)
|
|
|
|
// Triggering tests
|
|
try #expect(validate(fileName: "FileNameCaseMismatch.swift", using: configuration).count == 1)
|
|
try #expect(validate(fileName: "FileNameMismatch.swift", using: configuration).count == 1)
|
|
try #expect(validate(fileName: "FileNameMissing.swift", using: configuration).count == 1)
|
|
}
|
|
|
|
@Test
|
|
func fileHeaderWithForbiddenStringUsingFilenamePlaceholder() throws {
|
|
let configuration = ["forbidden_string": "// SWIFTLINT_CURRENT_FILENAME"]
|
|
|
|
// Non triggering tests
|
|
try #expect(validate(fileName: "FileNameCaseMismatch.swift", using: configuration).isEmpty)
|
|
try #expect(validate(fileName: "FileNameMismatch.swift", using: configuration).isEmpty)
|
|
try #expect(validate(fileName: "FileNameMissing.swift", using: configuration).isEmpty)
|
|
|
|
// Triggering tests
|
|
#expect(try validate(fileName: "FileNameMatchingSimple.swift", using: configuration).count == 1)
|
|
}
|
|
|
|
@Test
|
|
func fileHeaderWithRequiredPatternUsingFilenamePlaceholder() throws {
|
|
let configuration1 = ["required_pattern": "// SWIFTLINT_CURRENT_FILENAME\n.*\\d{4}"]
|
|
let configuration2 = [
|
|
"required_pattern": "// Copyright © \\d{4}\n// File: \"SWIFTLINT_CURRENT_FILENAME\""
|
|
]
|
|
|
|
// Non triggering tests
|
|
try #expect(validate(fileName: "FileNameMatchingSimple.swift", using: configuration1).isEmpty)
|
|
try #expect(validate(fileName: "FileNameMatchingComplex.swift", using: configuration2).isEmpty)
|
|
|
|
// Triggering tests
|
|
try #expect(validate(fileName: "FileNameCaseMismatch.swift", using: configuration1).count == 1)
|
|
try #expect(validate(fileName: "FileNameMismatch.swift", using: configuration1).count == 1)
|
|
try #expect(validate(fileName: "FileNameMissing.swift", using: configuration1).count == 1)
|
|
}
|
|
|
|
@Test
|
|
func fileHeaderWithForbiddenPatternUsingFilenamePlaceholder() throws {
|
|
let configuration1 = ["forbidden_pattern": "// SWIFTLINT_CURRENT_FILENAME\n.*\\d{4}"]
|
|
let configuration2 = ["forbidden_pattern": "//.*(\\s|\")SWIFTLINT_CURRENT_FILENAME(\\s|\").*"]
|
|
|
|
// Non triggering tests
|
|
try #expect(validate(fileName: "FileNameCaseMismatch.swift", using: configuration1).isEmpty)
|
|
try #expect(validate(fileName: "FileNameMismatch.swift", using: configuration1).isEmpty)
|
|
try #expect(validate(fileName: "FileNameMissing.swift", using: configuration1).isEmpty)
|
|
|
|
try #expect(validate(fileName: "FileNameCaseMismatch.swift", using: configuration2).isEmpty)
|
|
try #expect(validate(fileName: "FileNameMismatch.swift", using: configuration2).isEmpty)
|
|
try #expect(validate(fileName: "FileNameMissing.swift", using: configuration2).isEmpty)
|
|
|
|
// Triggering tests
|
|
try #expect(validate(fileName: "FileNameMatchingSimple.swift", using: configuration1).count == 1)
|
|
try #expect(validate(fileName: "FileNameMatchingComplex.swift", using: configuration2).count == 1)
|
|
}
|
|
|
|
@Test
|
|
func fileHeaderShouldBeEmpty() throws {
|
|
let configuration = ["forbidden_pattern": "."]
|
|
|
|
// Non triggering tests
|
|
try #expect(validate(fileName: "FileHeaderEmpty.swift", using: configuration).isEmpty)
|
|
try #expect(validate(fileName: "DocumentedType.swift", using: configuration).isEmpty)
|
|
|
|
// Triggering tests
|
|
try #expect(validate(fileName: "FileNameCaseMismatch.swift", using: configuration).count == 1)
|
|
try #expect(validate(fileName: "FileNameMismatch.swift", using: configuration).count == 1)
|
|
try #expect(validate(fileName: "FileNameMissing.swift", using: configuration).count == 1)
|
|
}
|
|
|
|
@Test
|
|
func simplePattern() {
|
|
let description = FileHeaderRule.description
|
|
.with(nonTriggeringExamples: [
|
|
Example("""
|
|
// Test
|
|
|
|
enum Test {}
|
|
"""),
|
|
Example("""
|
|
// Test
|
|
"""),
|
|
Example("""
|
|
// Test
|
|
|
|
"""),
|
|
])
|
|
.with(triggeringExamples: [])
|
|
|
|
verifyRule(
|
|
description,
|
|
ruleConfiguration: [
|
|
"required_pattern": #"""
|
|
\/\/ Test
|
|
|
|
"""#, // The empty line at the end is important since YAML adds it as well in `|` blocks.
|
|
],
|
|
skipCommentTests: true,
|
|
testMultiByteOffsets: false
|
|
)
|
|
}
|
|
|
|
@Test
|
|
func pattern() {
|
|
let description = FileHeaderRule.description
|
|
.with(nonTriggeringExamples: [
|
|
Example("""
|
|
//
|
|
// Test.swift
|
|
// Dummy App
|
|
//
|
|
// Created by Alice Bob on 3.9.2025.
|
|
// Copyright © 2025 Dummy Corporation. All rights reserved.
|
|
//
|
|
|
|
enum Test {}
|
|
"""),
|
|
])
|
|
.with(triggeringExamples: [])
|
|
|
|
verifyRule(
|
|
description,
|
|
ruleConfiguration: [
|
|
"required_pattern": #"""
|
|
\/\/
|
|
\/\/ Test\.swift
|
|
\/\/ .*?
|
|
\/\/
|
|
\/\/ Created by .*? on \d{1,2}[\.\/]\d{1,2}[\.\/]\d{2,4}\.
|
|
\/\/ Copyright © \d{4} Dummy Corporation\. All rights reserved\.
|
|
\/\/
|
|
|
|
"""#, // The empty line at the end is important since YAML adds it as well in `|` blocks.
|
|
],
|
|
skipCommentTests: true,
|
|
testMultiByteOffsets: false
|
|
)
|
|
}
|
|
}
|