mirror of
https://github.com/nicklockwood/SwiftFormat.git
synced 2026-05-17 10:30:35 +00:00
eee75a9eba
Co-authored-by: Cal Stephens <cal@calstephens.tech>
579 lines
16 KiB
Swift
579 lines
16 KiB
Swift
//
|
|
// HoistTryTests.swift
|
|
// SwiftFormatTests
|
|
//
|
|
// Created by Facundo Menzella on 2/25/23.
|
|
// Copyright © 2024 Nick Lockwood. All rights reserved.
|
|
//
|
|
|
|
import XCTest
|
|
@testable import SwiftFormat
|
|
|
|
final class HoistTryTests: XCTestCase {
|
|
func testHoistTry() {
|
|
let input = """
|
|
greet(try name(), try surname())
|
|
"""
|
|
let output = """
|
|
try greet(name(), surname())
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryWithOptionalTry() {
|
|
let input = """
|
|
greet(try name(), try? surname())
|
|
"""
|
|
let output = """
|
|
try greet(name(), try? surname())
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryInsideStringInterpolation() {
|
|
let input = """
|
|
\"\\(replace(regex: try something()))\"
|
|
"""
|
|
let output = """
|
|
try \"\\(replace(regex: something()))\"
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryInsideStringInterpolation2() {
|
|
let input = """
|
|
"Hello \\(try await someValue())"
|
|
"""
|
|
let output = """
|
|
try "Hello \\(await someValue())"
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry,
|
|
options: FormatOptions(swiftVersion: "5.5"),
|
|
exclude: [.hoistAwait])
|
|
}
|
|
|
|
func testHoistTryInsideStringInterpolation3() {
|
|
let input = """
|
|
let text = "\""
|
|
abc
|
|
\\(try bar())
|
|
xyz
|
|
"\""
|
|
"""
|
|
let output = """
|
|
let text = try "\""
|
|
abc
|
|
\\(bar())
|
|
xyz
|
|
"\""
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryInsideStringInterpolation4() {
|
|
let input = """
|
|
let str = "&enrolments[\\(index)][userid]=\\(try Foo.tryMe())"
|
|
"""
|
|
let output = """
|
|
let str = try "&enrolments[\\(index)][userid]=\\(Foo.tryMe())"
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryInsideStringInterpolation5() {
|
|
let input = """
|
|
return str +
|
|
"&enrolments[\\(index)][roleid]=\\(MoodleRoles.studentRole.rawValue)" +
|
|
"&enrolments[\\(index)][userid]=\\(try user.requireMoodleID())"
|
|
"""
|
|
let output = """
|
|
return try str +
|
|
"&enrolments[\\(index)][roleid]=\\(MoodleRoles.studentRole.rawValue)" +
|
|
"&enrolments[\\(index)][userid]=\\(user.requireMoodleID())"
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryInsideStringInterpolation6() {
|
|
let input = #"""
|
|
"""
|
|
let \(object.varName) =
|
|
\(tripleQuote)
|
|
\(try encode(object.object))
|
|
\(tripleQuote)
|
|
"""
|
|
"""#
|
|
let output = #"""
|
|
try """
|
|
let \(object.varName) =
|
|
\(tripleQuote)
|
|
\(encode(object.object))
|
|
\(tripleQuote)
|
|
"""
|
|
"""#
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryInsideArgument() {
|
|
let input = """
|
|
array.append(contentsOf: try await asyncFunction(param1: param1))
|
|
"""
|
|
let output = """
|
|
try array.append(contentsOf: await asyncFunction(param1: param1))
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry, exclude: [.hoistAwait])
|
|
}
|
|
|
|
func testNoHoistTryInsideXCTAssert() {
|
|
let input = """
|
|
XCTAssertFalse(try foo())
|
|
"""
|
|
testFormatting(for: input, rule: .hoistTry)
|
|
}
|
|
|
|
func testNoHoistTryInsideXCTUnwrap() {
|
|
let input = """
|
|
let foo = try XCTUnwrap(try expression() as? Bar, message, file: file, line: line)
|
|
"""
|
|
testFormatting(for: input, rule: .hoistTry)
|
|
}
|
|
|
|
func testNoMergeTrysInsideXCTAssert() {
|
|
let input = """
|
|
XCTAssertEqual(try foo(), try bar())
|
|
"""
|
|
testFormatting(for: input, rule: .hoistTry)
|
|
}
|
|
|
|
func testNoHoistTryInsideDo() {
|
|
let input = """
|
|
do { rg.box.seal(.fulfilled(try body(error))) }
|
|
"""
|
|
let output = """
|
|
do { try rg.box.seal(.fulfilled(body(error))) }
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testNoHoistTryInsideDoThrows() {
|
|
let input = """
|
|
do throws(Foo) { rg.box.seal(.fulfilled(try body(error))) }
|
|
"""
|
|
let output = """
|
|
do throws(Foo) { try rg.box.seal(.fulfilled(body(error))) }
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testNoHoistTryInsideMultilineDo() {
|
|
let input = """
|
|
do {
|
|
rg.box.seal(.fulfilled(try body(error)))
|
|
}
|
|
"""
|
|
let output = """
|
|
do {
|
|
try rg.box.seal(.fulfilled(body(error)))
|
|
}
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistedTryPlacedBeforeAwait() {
|
|
let input = """
|
|
let foo = await bar(contentsOf: try baz())
|
|
"""
|
|
let output = """
|
|
let foo = try await bar(contentsOf: baz())
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryInExpressionWithNoSpaces() {
|
|
let input = """
|
|
let foo=bar(contentsOf:try baz())
|
|
"""
|
|
let output = """
|
|
let foo=try bar(contentsOf:baz())
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry,
|
|
exclude: [.spaceAroundOperators])
|
|
}
|
|
|
|
func testHoistTryInExpressionWithExcessSpaces() {
|
|
let input = """
|
|
let foo = bar ( contentsOf: try baz() )
|
|
"""
|
|
let output = """
|
|
let foo = try bar ( contentsOf: baz() )
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry,
|
|
exclude: [.spaceAroundParens, .spaceInsideParens])
|
|
}
|
|
|
|
func testHoistTryWithReturn() {
|
|
let input = """
|
|
return .enumCase(try await service.greet())
|
|
"""
|
|
let output = """
|
|
return try .enumCase(await service.greet())
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry,
|
|
exclude: [.hoistAwait])
|
|
}
|
|
|
|
func testHoistDeeplyNestedTrys() {
|
|
let input = """
|
|
let foo = (bar: (5, (try quux(), 6)), baz: (7, quux: try quux()))
|
|
"""
|
|
let output = """
|
|
let foo = try (bar: (5, (quux(), 6)), baz: (7, quux: quux()))
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testTryNotHoistedOutOfClosure() {
|
|
let input = """
|
|
let foo = { (try bar(), 5) }
|
|
"""
|
|
let output = """
|
|
let foo = { try (bar(), 5) }
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testTryNotHoistedOutOfClosureWithArguments() {
|
|
let input = """
|
|
let foo = { bar in (try baz(bar), 5) }
|
|
"""
|
|
let output = """
|
|
let foo = { bar in try (baz(bar), 5) }
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testTryNotHoistedOutOfForCondition() {
|
|
let input = """
|
|
for foo in bar(try baz()) {}
|
|
"""
|
|
let output = """
|
|
for _ in try bar(baz()) {}
|
|
"""
|
|
testFormatting(for: input, [output], rules: [.hoistTry, .unusedArguments])
|
|
}
|
|
|
|
func testHoistTryWithInitAssignment() {
|
|
let input = """
|
|
let variable = String(try await asyncFunction())
|
|
"""
|
|
let output = """
|
|
let variable = try String(await asyncFunction())
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry,
|
|
exclude: [.hoistAwait])
|
|
}
|
|
|
|
func testHoistTryWithAssignment() {
|
|
let input = """
|
|
let variable = (try await asyncFunction())
|
|
"""
|
|
let output = """
|
|
let variable = try (await asyncFunction())
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry,
|
|
exclude: [.hoistAwait])
|
|
}
|
|
|
|
func testHoistTryOnlyOne() {
|
|
let input = """
|
|
greet(name, try surname())
|
|
"""
|
|
let output = """
|
|
try greet(name, surname())
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryRedundantTry() {
|
|
let input = """
|
|
try greet(try name(), try surname())
|
|
"""
|
|
let output = """
|
|
try greet(name(), surname())
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryWithAwaitOnDifferentStatement() {
|
|
let input = """
|
|
let asyncVariable = try await performSomething()
|
|
return Foo(param1: try param1())
|
|
"""
|
|
let output = """
|
|
let asyncVariable = try await performSomething()
|
|
return try Foo(param1: param1())
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryDoubleParens() {
|
|
let input = """
|
|
array.append((value: try compute()))
|
|
"""
|
|
let output = """
|
|
try array.append((value: compute()))
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryDoesNothing() {
|
|
let input = """
|
|
try greet(name, surname)
|
|
"""
|
|
testFormatting(for: input, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistOptionalTryDoesNothing() {
|
|
let input = """
|
|
try? greet(name, surname)
|
|
"""
|
|
testFormatting(for: input, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistedTryOnLineBeginningWithInfixDot() {
|
|
let input = """
|
|
let foo = bar()
|
|
.baz(try quux())
|
|
"""
|
|
let output = """
|
|
let foo = try bar()
|
|
.baz(quux())
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistedTryOnLineBeginningWithInfixPlus() {
|
|
let input = """
|
|
let foo = bar()
|
|
+ baz(try quux())
|
|
"""
|
|
let output = """
|
|
let foo = try bar()
|
|
+ baz(quux())
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistedTryOnLineBeginningWithPrefixOperator() {
|
|
let input = """
|
|
foo()
|
|
!bar(try quux())
|
|
"""
|
|
let output = """
|
|
foo()
|
|
try !bar(quux())
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testNoHoistTryIntoPreviousLineEndingWithPostfixOperator() {
|
|
let input = """
|
|
let foo = bar!
|
|
(try baz(), quux()).foo()
|
|
"""
|
|
let output = """
|
|
let foo = bar!
|
|
try (baz(), quux()).foo()
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testNoHoistTryInCapturingFunction() {
|
|
let input = """
|
|
foo(try bar)
|
|
"""
|
|
testFormatting(for: input, rule: .hoistTry,
|
|
options: FormatOptions(throwCapturing: ["foo"]))
|
|
}
|
|
|
|
func testNoHoistSecondArgumentTryInCapturingFunction() {
|
|
let input = """
|
|
foo(bar, try baz)
|
|
"""
|
|
testFormatting(for: input, rule: .hoistTry,
|
|
options: FormatOptions(throwCapturing: ["foo"]))
|
|
}
|
|
|
|
func testNoHoistFailToTerminate() {
|
|
let input = """
|
|
return ManyInitExample(
|
|
a: try Example(string: try throwingExample()),
|
|
b: try throwingExample(),
|
|
c: try throwingExample(),
|
|
d: try throwingExample(),
|
|
e: try throwingExample(),
|
|
f: try throwingExample(),
|
|
g: try throwingExample(),
|
|
h: try throwingExample(),
|
|
i: try throwingExample()
|
|
)
|
|
"""
|
|
let output = """
|
|
return try ManyInitExample(
|
|
a: Example(string: throwingExample()),
|
|
b: throwingExample(),
|
|
c: throwingExample(),
|
|
d: throwingExample(),
|
|
e: throwingExample(),
|
|
f: throwingExample(),
|
|
g: throwingExample(),
|
|
h: throwingExample(),
|
|
i: throwingExample()
|
|
)
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryInsideOptionalFunction() {
|
|
let input = """
|
|
foo?(try bar())
|
|
"""
|
|
let output = """
|
|
try foo?(bar())
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testNoHoistTryAfterOptionalTry() {
|
|
let input = """
|
|
let foo = try? bar(try baz())
|
|
"""
|
|
testFormatting(for: input, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryInsideOptionalSubscript() {
|
|
let input = """
|
|
foo?[try bar()]
|
|
"""
|
|
let output = """
|
|
try foo?[bar()]
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryAfterGenericType() {
|
|
let input = """
|
|
let foo = Tree<T>.Foo(bar: try baz())
|
|
"""
|
|
let output = """
|
|
let foo = try Tree<T>.Foo(bar: baz())
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryAfterArrayLiteral() {
|
|
let input = """
|
|
if [.first, .second].contains(try foo()) {}
|
|
"""
|
|
let output = """
|
|
if try [.first, .second].contains(foo()) {}
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryAfterSubscript() {
|
|
let input = """
|
|
if foo[5].bar(try baz()) {}
|
|
"""
|
|
let output = """
|
|
if try foo[5].bar(baz()) {}
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryInsideGenericInit() {
|
|
let input = """
|
|
return Target<T>(
|
|
file: try parseFile(path: $0)
|
|
)
|
|
"""
|
|
let output = """
|
|
return try Target<T>(
|
|
file: parseFile(path: $0)
|
|
)
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryInsideArrayClosure() {
|
|
let input = """
|
|
foo[bar](try parseFile(path: $0))
|
|
"""
|
|
let output = """
|
|
try foo[bar](parseFile(path: $0))
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryAfterString() {
|
|
let input = """
|
|
let json = "{}"
|
|
|
|
someFunction(try parse(json), "someKey")
|
|
"""
|
|
let output = """
|
|
let json = "{}"
|
|
|
|
try someFunction(parse(json), "someKey")
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testHoistTryAfterMultilineString() {
|
|
let input = #"""
|
|
let json = """
|
|
{
|
|
"foo": "bar"
|
|
}
|
|
"""
|
|
|
|
someFunction(try parse(json), "someKey")
|
|
"""#
|
|
let output = #"""
|
|
let json = """
|
|
{
|
|
"foo": "bar"
|
|
}
|
|
"""
|
|
|
|
try someFunction(parse(json), "someKey")
|
|
"""#
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testNoHoistTryInTestAttribute() {
|
|
let input = """
|
|
@Test(arguments: [try Identifier(101), nil])
|
|
func testFunction() {}
|
|
"""
|
|
|
|
let output = """
|
|
@Test(arguments: try [Identifier(101), nil])
|
|
func testFunction() {}
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
|
|
func testCorrectTryPlacementForWrappedAssert() {
|
|
let input = """
|
|
XCTAssertEqual(Consumer<String>
|
|
.character(in: try foo()))
|
|
"""
|
|
let output = """
|
|
XCTAssertEqual(try Consumer<String>
|
|
.character(in: foo()))
|
|
"""
|
|
testFormatting(for: input, output, rule: .hoistTry)
|
|
}
|
|
}
|