Files
SwiftFormat/Tests/XCTestCase+testFormatting.swift

134 lines
6.2 KiB
Swift

//
// XCTestCase+testFormatting.swift
// SwiftFormat
//
// Created by Nick Lockwood on 12/08/2016.
// Copyright 2016 Nick Lockwood
//
// Distributed under the permissive MIT license
// Get the latest version from here:
//
// https://github.com/nicklockwood/SwiftFormat
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import XCTest
@testable import SwiftFormat
extension XCTestCase {
func testFormatting(for input: String, _ output: String? = nil, rule: FormatRule,
options: FormatOptions = .default, exclude: [FormatRule] = [],
file: StaticString = #file, line: UInt = #line)
{
testFormatting(for: input, output.map { [$0] } ?? [], rules: [rule],
options: options, exclude: exclude, file: file, line: line)
}
func testFormatting(for input: String, _ outputs: [String] = [], rules: [FormatRule],
options: FormatOptions = .default, exclude: [FormatRule] = [],
file: StaticString = #file, line: UInt = #line)
{
// Always make sure the rule registry is up-to-date before running the tests
do {
try FormatRules.generateRuleRegistryIfNecessary()
} catch {
XCTFail("Encountered error generating rule registry: \(error.localizedDescription)", file: file, line: line)
}
var options = options
if options.timeout == FormatOptions.default.timeout {
// Make breakpoint debugging easier by increasing timeout
options.timeout = 120
}
// The `name` property on individual rules is not populated until the first call into `rulesByName`,
// so we have to make sure to trigger this before checking the names of the given rules.
if rules.contains(where: \.name.isEmpty) {
_ = FormatRules.all
}
// Check swift versions updated
if options.swiftVersion != .undefined {
let maxVersion = Version(rawValue: swiftVersions.last!)!
XCTAssert(options.swiftVersion <= maxVersion,
"Swift version '\(options.swiftVersion)' not found in swiftVersions array",
file: file, line: line)
}
precondition(input != outputs.first || input != outputs.last, "Redundant output parameter")
precondition((0 ... 2).contains(outputs.count), "Only 0, 1 or 2 output parameters permitted")
precondition(Set(exclude).intersection(rules).isEmpty, "Cannot exclude rule under test")
let output = outputs.first ?? input, output2 = outputs.last ?? input
let defaultExclusions = FormatRules.deprecated + [
.linebreakAtEndOfFile,
.organizeDeclarations,
.extensionAccessControl,
.markTypes,
.blockComments,
.unusedPrivateDeclarations,
.preferFinalClasses,
.preferExplicitFalse,
.wrapCaseBodies,
]
let exclude = exclude + defaultExclusions.filter { !rules.contains($0) }
let formatResult: (output: String, changes: [SwiftFormat.Formatter.Change])
do {
formatResult = try format(input, rules: rules, options: options)
} catch {
XCTFail("Failed to format input, threw error \(error)", file: file, line: line)
return
}
XCTAssertEqual(formatResult.output, output, file: file, line: line)
if input != output, formatResult.output == output {
XCTAssert(!formatResult.changes.isEmpty, """
Rules applied changes but unexpectedly produced no `Formatter.Change`s. \
This would result in no messages being printed when running with --lint. \
This can happen in cases where a rule only moves lines, but doesn't modify their contents. \
You can fix this by using `formatter.moveTokens`.
""", file: file, line: line)
}
XCTAssertEqual(try format(input, rules: FormatRules.all(except: exclude), options: options).output,
output2, file: file, line: line)
if input != output {
XCTAssertEqual(try format(output, rules: rules, options: options).output,
output, file: file, line: line)
if !input.hasPrefix("#!") {
for rule in rules {
let disabled = "// swiftformat:disable \(rule)\n\(input)"
XCTAssertEqual(try format(disabled, rules: [rule], options: options).output,
disabled, "Failed to disable \(rule) rule", file: file, line: line)
}
}
}
if input != output2, output != output2 {
XCTAssertEqual(try format(output2, rules: FormatRules.all(except: exclude), options: options).output,
output2, file: file, line: line)
}
#if os(macOS)
// These tests are flakey on Linux, and it's hard to debug
XCTAssertEqual(try lint(output, rules: rules, options: options), [], file: file, line: line)
XCTAssertEqual(try lint(output2, rules: FormatRules.all(except: exclude), options: options),
[], file: file, line: line)
#endif
}
}