Files
SwiftLint/Tests/BuiltInRulesTests/FileHeaderRuleTests.swift
2025-12-28 08:46:16 +01:00

271 lines
11 KiB
Swift

@testable import SwiftLintBuiltInRules
import TestHelpers
import XCTest
private let fixturesDirectory = TestResources.path().appending(component: "FileHeaderRuleFixtures")
final class FileHeaderRuleTests: SwiftLintTestCase {
private func validate(fileName: String, using configuration: Any) throws -> [StyleViolation] {
let file = SwiftLintFile(path: fixturesDirectory.appending(component: fileName))!
let rule = try FileHeaderRule(configuration: configuration)
return rule.validate(file: file)
}
func testFileHeaderWithDefaultConfiguration() {
verifyRule(FileHeaderRule.description, skipCommentTests: true)
}
func testFileHeaderWithRequiredString() {
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)
}
func testFileHeaderWithRequiredPattern() {
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)
}
func testFileHeaderWithRequiredStringAndURLComment() {
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)
}
func testFileHeaderWithForbiddenString() {
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)
}
func testFileHeaderWithForbiddenPattern() {
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)
}
func testFileHeaderWithForbiddenPatternAndDocComment() {
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)
}
func testFileHeaderWithRequiredStringUsingFilenamePlaceholder() {
let configuration = ["required_string": "// SWIFTLINT_CURRENT_FILENAME"]
// Non triggering tests
XCTAssert(try validate(fileName: "FileNameMatchingSimple.swift", using: configuration).isEmpty)
// Triggering tests
XCTAssertEqual(try validate(fileName: "FileNameCaseMismatch.swift", using: configuration).count, 1)
XCTAssertEqual(try validate(fileName: "FileNameMismatch.swift", using: configuration).count, 1)
XCTAssertEqual(try validate(fileName: "FileNameMissing.swift", using: configuration).count, 1)
}
func testFileHeaderWithForbiddenStringUsingFilenamePlaceholder() {
let configuration = ["forbidden_string": "// SWIFTLINT_CURRENT_FILENAME"]
// Non triggering tests
XCTAssert(try validate(fileName: "FileNameCaseMismatch.swift", using: configuration).isEmpty)
XCTAssert(try validate(fileName: "FileNameMismatch.swift", using: configuration).isEmpty)
XCTAssert(try validate(fileName: "FileNameMissing.swift", using: configuration).isEmpty)
// Triggering tests
XCTAssertEqual(try validate(fileName: "FileNameMatchingSimple.swift", using: configuration).count, 1)
}
func testFileHeaderWithRequiredPatternUsingFilenamePlaceholder() {
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
XCTAssert(try validate(fileName: "FileNameMatchingSimple.swift", using: configuration1).isEmpty)
XCTAssert(try validate(fileName: "FileNameMatchingComplex.swift", using: configuration2).isEmpty)
// Triggering tests
XCTAssertEqual(try validate(fileName: "FileNameCaseMismatch.swift", using: configuration1).count, 1)
XCTAssertEqual(try validate(fileName: "FileNameMismatch.swift", using: configuration1).count, 1)
XCTAssertEqual(try validate(fileName: "FileNameMissing.swift", using: configuration1).count, 1)
}
func testFileHeaderWithForbiddenPatternUsingFilenamePlaceholder() {
let configuration1 = ["forbidden_pattern": "// SWIFTLINT_CURRENT_FILENAME\n.*\\d{4}"]
let configuration2 = ["forbidden_pattern": "//.*(\\s|\")SWIFTLINT_CURRENT_FILENAME(\\s|\").*"]
// Non triggering tests
XCTAssert(try validate(fileName: "FileNameCaseMismatch.swift", using: configuration1).isEmpty)
XCTAssert(try validate(fileName: "FileNameMismatch.swift", using: configuration1).isEmpty)
XCTAssert(try validate(fileName: "FileNameMissing.swift", using: configuration1).isEmpty)
XCTAssert(try validate(fileName: "FileNameCaseMismatch.swift", using: configuration2).isEmpty)
XCTAssert(try validate(fileName: "FileNameMismatch.swift", using: configuration2).isEmpty)
XCTAssert(try validate(fileName: "FileNameMissing.swift", using: configuration2).isEmpty)
// Triggering tests
XCTAssertEqual(try validate(fileName: "FileNameMatchingSimple.swift", using: configuration1).count, 1)
XCTAssertEqual(try validate(fileName: "FileNameMatchingComplex.swift", using: configuration2).count, 1)
}
func testFileHeaderShouldBeEmpty() {
let configuration = ["forbidden_pattern": "."]
// Non triggering tests
XCTAssert(try validate(fileName: "FileHeaderEmpty.swift", using: configuration).isEmpty)
XCTAssert(try validate(fileName: "DocumentedType.swift", using: configuration).isEmpty)
// Triggering tests
XCTAssertEqual(try validate(fileName: "FileNameCaseMismatch.swift", using: configuration).count, 1)
XCTAssertEqual(try validate(fileName: "FileNameMismatch.swift", using: configuration).count, 1)
XCTAssertEqual(try validate(fileName: "FileNameMissing.swift", using: configuration).count, 1)
}
func testSimplePattern() {
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
)
}
func testPattern() {
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
)
}
}