Files
SwiftGen/Tests/SwiftGenKitTests/StringPlaceholderTypeTests.swift
David Jennes 4d1d3591c7 Bump year
2022-07-30 20:47:39 +02:00

205 lines
7.7 KiB
Swift

//
// SwiftGenKit UnitTests
// Copyright © 2022 SwiftGen
// MIT Licence
//
@testable import SwiftGenKit
import XCTest
final class StringPlaceholderTypeTests: XCTestCase {
func testParseStringPlaceholder() throws {
let placeholders = try Strings.PlaceholderType.placeholderTypes(fromFormat: "%@")
XCTAssertEqual(placeholders, [.object])
}
func testParseFloatPlaceholder() throws {
let placeholders = try Strings.PlaceholderType.placeholderTypes(fromFormat: "%f")
XCTAssertEqual(placeholders, [.float])
}
func testParseDoublePlaceholders() throws {
let placeholders = try Strings.PlaceholderType.placeholderTypes(fromFormat: "%g-%e")
XCTAssertEqual(placeholders, [.float, .float])
}
func testParseFloatWithPrecisionPlaceholders() throws {
let placeholders = try Strings.PlaceholderType.placeholderTypes(fromFormat: "%1.2f : %.3f : %+3f : %-6.2f")
XCTAssertEqual(placeholders, [.float, .float, .float, .float])
}
func testParseIntPlaceholders() throws {
let placeholders = try Strings.PlaceholderType.placeholderTypes(fromFormat: "%d-%i-%o-%u-%x")
XCTAssertEqual(placeholders, [.int, .int, .int, .int, .int])
}
func testParseCCharAndStringPlaceholders() throws {
let placeholders = try Strings.PlaceholderType.placeholderTypes(fromFormat: "%c-%s")
XCTAssertEqual(placeholders, [.char, .cString])
}
func testParsePositionalPlaceholders() throws {
let placeholders = try Strings.PlaceholderType.placeholderTypes(fromFormat: "%2$d-%4$f-%3$@-%c")
XCTAssertEqual(placeholders, [.char, .int, .object, .float])
}
func testParseComplexFormatPlaceholders() throws {
let format = "%2$1.3d - %4$-.7f - %3$@ - %% - %5$+3c - %%"
let placeholders = try Strings.PlaceholderType.placeholderTypes(fromFormat: format)
// positions 2, 4, 3, 5 set to .int, .float, .object, .char ; position 1 not matched
XCTAssertEqual(placeholders, [.int, .object, .float, .char])
}
func testParseManyPlaceholders() throws {
let format = "%@ - %d - %f - %5$d - %04$f - %6$d - %007$@ - %8$3.2f - %11$1.2f - %9$@ - %10$d"
let placeholders = try Strings.PlaceholderType.placeholderTypes(fromFormat: format)
XCTAssertEqual(
placeholders,
[.object, .int, .float, .float, .int, .int, .object, .float, .object, .int, .float]
)
}
func testParseManyPlaceholdersWithZeroPos() throws {
// %0$@ is interpreted by Foundation not as a placeholder (because invalid 0 position)
// but instead rendered as a "0@" literal.
let format = "%@ - %d - %0$@ - %f - %5$d - %04$f - %6$d - %007$@ - %8$3.2f - %11$1.2f - %9$@ - %10$d"
let placeholders = try Strings.PlaceholderType.placeholderTypes(fromFormat: format)
XCTAssertEqual(
placeholders,
[.object, .int, .float, .float, .int, .int, .object, .float, .object, .int, .float]
)
}
func testParseInterleavedPositionalAndNonPositionalPlaceholders() throws {
let format = "%@ %7$d %@ %@ %8$d %@ %@"
let placeholders = try Strings.PlaceholderType.placeholderTypes(fromFormat: format)
XCTAssertEqual(placeholders, [.object, .object, .object, .object, .object, /* ?, */ .int, .int])
}
func testParseFlags() throws {
let formats = ["%-9d", "%+9d", "% 9d", "%#9d", "%09d"]
for format in formats {
let placeholders = try Strings.PlaceholderType.placeholderTypes(fromFormat: format)
XCTAssertEqual(placeholders, [.int], "Failed to parse format \"\(format)\"")
}
let invalidFormat = "%_9d %_9f %_9@ %!9@"
let placeholders = try Strings.PlaceholderType.placeholderTypes(fromFormat: invalidFormat)
XCTAssertEqual(placeholders, [])
}
func testParseDuplicateFormatPlaceholders() throws {
let placeholders = try Strings.PlaceholderType.placeholderTypes(fromFormat: "Text: %1$@; %1$@.")
XCTAssertEqual(placeholders, [.object])
}
private func pluralVariable(
_ name: String,
type: String,
one: String,
other: String
) -> StringsDict.PluralEntry.Variable {
.init(
name: name,
rule: .init(
specTypeKey: "NSStringPluralRuleType",
valueTypeKey: type,
zero: nil,
one: one,
two: nil,
few: nil,
many: nil,
other: other
)
)
}
func testStringsDictPlaceholdersConversion() throws {
let entry = StringsDict.PluralEntry(
formatKey:
"""
%@ - %#@d2@ - %0$#@zero@ - %#@f3@ - %5$#@d5@ - %04$#@f4@ - %6$#@d6@ - %007$@
- %8$#@f8@ - %11$#@f11@ - %9$@ - %10$#@d10@
""",
variables: [
pluralVariable("zero", type: "d", one: "unused", other: "unused"),
pluralVariable("d2", type: "d", one: "%d two", other: "%d twos"),
pluralVariable("f3", type: "f", one: "%f three", other: "%f threes"),
pluralVariable("f4", type: "f", one: "%f four", other: "%f fours"),
pluralVariable("d5", type: "d", one: "%d five", other: "%d fives"),
pluralVariable("d6", type: "d", one: "%d six", other: "%d sixes"),
pluralVariable("f8", type: "f", one: "%f eight", other: "%f eights"),
pluralVariable("d10", type: "d", one: "%d ten", other: "%d tens"),
pluralVariable("f11", type: "f", one: "%f eleven", other: "%f elevens")
]
)
let converted = entry.formatKeyWithVariableValueTypes
XCTAssertEqual(
converted,
"%@ - %d - %0$d - %f - %5$d - %4$f - %6$d - %007$@\n- %8$f - %11$f - %9$@ - %10$d"
)
let placeholders = try Strings.PlaceholderType.placeholderTypes(fromFormat: converted)
XCTAssertEqual(
placeholders,
[.object, .int, .float, .float, .int, .int, .object, .float, .object, .int, .float]
)
}
// MARK: - Testing Errors
func testParseErrorOnTypeMismatch() throws {
XCTAssertThrowsError(
try Strings.PlaceholderType.placeholderTypes(fromFormat: "Text: %1$@; %1$ld."),
"Code did parse string successfully while it was expected to fail for bad syntax"
) { error in
guard
let parserError = error as? Strings.ParserError,
case .invalidPlaceholder = parserError // That's the expected exception we want to happen
else {
XCTFail("Unexpected error occured while parsing: \(error)")
return
}
}
}
func testParseErrorOnPositionalValueBeingOverwritten() throws {
let formatStrings: [String: (Strings.PlaceholderType, Strings.PlaceholderType)] = [
"%@ %1$d": (.object, .int), // `.int` would overwrite existing `.object`
"%1$d %@": (.int, .object), // `.object` would overwrite existing `.int`
"%@ %2$d %@": (.int, .object), // `.object` would overwrite existing `.int`
"%@ %2$d %@ %@ %5$d %@ %@": (.int, .object), // `.object` would overwrite existing `.int`
"%@ %@ %2$d %@ %5$d %@ %@": (.object, .int) // `.int` would overwrite existing `.object`
]
for (formatString, expectedFormats) in formatStrings {
XCTAssertThrowsError(
try Strings.PlaceholderType.placeholderTypes(fromFormat: formatString),
"Code did parse string successfully while it was expected to fail for bad syntax"
) { error in
guard
let parserError = error as? Strings.ParserError,
case .invalidPlaceholder(previous: expectedFormats.0, new: expectedFormats.1) = parserError
else {
XCTFail("Unexpected error occured while parsing: \(error)")
return
}
}
}
}
// MARK: - Testing Percent Escapes
func testParseEvenEscapePercentSign() throws {
let placeholders = try Strings.PlaceholderType.placeholderTypes(fromFormat: "%%foo")
// Must NOT map to [.float]
XCTAssertEqual(placeholders, [])
}
func testParseOddEscapePercentSign() throws {
let placeholders = try Strings.PlaceholderType.placeholderTypes(fromFormat: "%%%foo")
// Should map to [.float]
XCTAssertEqual(placeholders, [.float])
}
}