Add `ConstructorTests.swift`
This commit is contained in:
parent
4677810740
commit
adc4e6b7ef
|
@ -92,10 +92,10 @@ public final class Constructor {
|
|||
|
||||
public func bool(from node: Node) -> Any {
|
||||
guard let string = node.string else { fatalError("Never happen this") }
|
||||
switch string {
|
||||
case "true", "True", "TRUE":
|
||||
switch string.lowercased() {
|
||||
case "true", "yes", "on":
|
||||
return true
|
||||
case "false", "False", "FALSE":
|
||||
case "false", "no", "off":
|
||||
return false
|
||||
default:
|
||||
return string
|
||||
|
@ -103,7 +103,7 @@ public final class Constructor {
|
|||
}
|
||||
|
||||
public func float(from node: Node) -> Any {
|
||||
guard let string = node.string else { fatalError("Never happen this") }
|
||||
guard var string = node.string else { fatalError("Never happen this") }
|
||||
switch string {
|
||||
case ".inf", ".Inf", ".INF", "+.inf", "+.Inf", "+.INF":
|
||||
return Double.infinity
|
||||
|
@ -112,6 +112,24 @@ public final class Constructor {
|
|||
case ".nan", ".NaN", ".NAN":
|
||||
return Double.nan
|
||||
default:
|
||||
string = string.replacingOccurrences(of: "_", with: "")
|
||||
if string.contains(":") {
|
||||
var sign: Double = 1
|
||||
if string.hasPrefix("-") {
|
||||
sign = -1
|
||||
string = string.substring(from: string.index(after: string.startIndex))
|
||||
} else if string.hasPrefix("+") {
|
||||
string = string.substring(from: string.index(after: string.startIndex))
|
||||
}
|
||||
let digits = string.components(separatedBy: ":").flatMap(Double.init).reversed()
|
||||
var base = 1.0
|
||||
var value = 0.0
|
||||
digits.forEach {
|
||||
value += $0 * base
|
||||
base *= 60
|
||||
}
|
||||
return sign * value
|
||||
}
|
||||
return Double(string) ?? string
|
||||
}
|
||||
}
|
||||
|
@ -119,7 +137,7 @@ public final class Constructor {
|
|||
public func null(from node: Node) -> Any {
|
||||
guard let string = node.string else { fatalError("Never happen this") }
|
||||
switch string {
|
||||
case "~", "null", "Null", "NULL":
|
||||
case "", "~", "null", "Null", "NULL":
|
||||
return NSNull()
|
||||
default:
|
||||
return string
|
||||
|
@ -127,18 +145,43 @@ public final class Constructor {
|
|||
}
|
||||
|
||||
public func int(from node: Node) -> Any {
|
||||
guard let string = node.string else { fatalError("Never happen this") }
|
||||
guard var string = node.string else { fatalError("Never happen this") }
|
||||
string = string.replacingOccurrences(of: "_", with: "")
|
||||
if string == "0" {
|
||||
return 0
|
||||
}
|
||||
if string.hasPrefix("0x") {
|
||||
let hexadecimal = string.substring(from: string.index(string.startIndex, offsetBy: 2))
|
||||
return Int(hexadecimal, radix: 16) ?? string
|
||||
}
|
||||
if string.hasPrefix("0b") {
|
||||
let octal = string.substring(from: string.index(string.startIndex, offsetBy: 2))
|
||||
return Int(octal, radix: 2) ?? string
|
||||
}
|
||||
if string.hasPrefix("0o") {
|
||||
let octal = string.substring(from: string.index(string.startIndex, offsetBy: 2))
|
||||
return Int(octal, radix: 8) ?? string
|
||||
}
|
||||
if string.hasPrefix("0b") {
|
||||
let octal = string.substring(from: string.index(string.startIndex, offsetBy: 2))
|
||||
return Int(octal, radix: 2) ?? string
|
||||
if string.hasPrefix("0") {
|
||||
let octal = string.substring(from: string.index(after: string.startIndex))
|
||||
return Int(octal, radix: 8) ?? string
|
||||
}
|
||||
if string.contains(":") {
|
||||
var sign = 1
|
||||
if string.hasPrefix("-") {
|
||||
sign = -1
|
||||
string = string.substring(from: string.index(after: string.startIndex))
|
||||
} else if string.hasPrefix("+") {
|
||||
string = string.substring(from: string.index(after: string.startIndex))
|
||||
}
|
||||
let digits = string.components(separatedBy: ":").flatMap({ Int($0) }).reversed()
|
||||
var base = 1
|
||||
var value = 0
|
||||
digits.forEach {
|
||||
value += $0 * base
|
||||
base *= 60
|
||||
}
|
||||
return sign * value
|
||||
}
|
||||
return Int(string) ?? string
|
||||
}
|
||||
|
@ -151,10 +194,66 @@ public final class Constructor {
|
|||
|
||||
public func timestamp(from node: Node) -> Any {
|
||||
guard let string = node.string else { fatalError("Never happen this") }
|
||||
return ISO8601Formatter.date(from: string) ?? string
|
||||
|
||||
let range = NSRange(location: 0, length: string.utf16.count)
|
||||
guard let result = timestampPattern.firstMatch(in: string, options: [], range: range),
|
||||
result.range.location != NSNotFound else {
|
||||
return string
|
||||
}
|
||||
#if os(Linux)
|
||||
let components = (1..<result.numberOfRanges).map(result.range(at:)).map(string.substring)
|
||||
#else
|
||||
let components = (1..<result.numberOfRanges).map(result.rangeAt).map(string.substring)
|
||||
#endif
|
||||
|
||||
var datecomponents = DateComponents()
|
||||
datecomponents.calendar = Calendar(identifier: .gregorian)
|
||||
datecomponents.year = components[0].flatMap { Int($0) }
|
||||
datecomponents.month = components[1].flatMap { Int($0) }
|
||||
datecomponents.day = components[2].flatMap { Int($0) }
|
||||
datecomponents.hour = components[3].flatMap { Int($0) }
|
||||
datecomponents.minute = components[4].flatMap { Int($0) }
|
||||
datecomponents.second = components[5].flatMap { Int($0) }
|
||||
datecomponents.nanosecond = components[6].flatMap {
|
||||
let length = $0.characters.count
|
||||
let nanosecond: Int?
|
||||
if length < 9 {
|
||||
nanosecond = Int($0 + String(repeating: "0", count: 9 - length))
|
||||
} else {
|
||||
nanosecond = Int($0.substring(to: $0.index($0.startIndex, offsetBy: 9)))
|
||||
}
|
||||
return nanosecond
|
||||
}
|
||||
datecomponents.timeZone = {
|
||||
// guard components[7] != nil else { return TimeZone(secondsFromGMT: 0) }
|
||||
|
||||
var seconds = 0
|
||||
seconds += components[9].flatMap({ Int($0) }).map({ $0 * 60 * 60 }) ?? 0 // hour
|
||||
seconds += components[10].flatMap({ Int($0) }).map({ $0 * 60 }) ?? 0 // minute
|
||||
if components[8] == "-" { // sign
|
||||
seconds *= -1
|
||||
}
|
||||
return TimeZone(secondsFromGMT: seconds)
|
||||
}()
|
||||
// Using `DateComponents.date` causes crash on Linux
|
||||
return NSCalendar(identifier: .gregorian)?.date(from: datecomponents) ?? string
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate let timestampPattern: NSRegularExpression = pattern([
|
||||
"^([0-9][0-9][0-9][0-9])", // year
|
||||
"-([0-9][0-9]?)", // month
|
||||
"-([0-9][0-9]?)", // day
|
||||
"(?:(?:[Tt]|[ \\t]+)",
|
||||
"([0-9][0-9]?)", // hour
|
||||
":([0-9][0-9])", // minute
|
||||
":([0-9][0-9])", // second
|
||||
"(?:\\.([0-9]*))?", // fraction
|
||||
"(?:[ \\t]*(Z|([-+])([0-9][0-9]?)", // tz_sign, tz_hour
|
||||
"(?::([0-9][0-9]))?))?)?$" // tz_minute
|
||||
].joined()
|
||||
)
|
||||
|
||||
extension Constructor {
|
||||
public static let `default` = Constructor([
|
||||
// Failsafe Schema
|
||||
|
@ -181,6 +280,19 @@ fileprivate let ISO8601Formatter: DateFormatter = {
|
|||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
|
||||
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
|
||||
dateFormatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"
|
||||
dateFormatter.dateFormat = "yyyy-MM-ddTHH:mm:ssZ"
|
||||
return dateFormatter
|
||||
}()
|
||||
|
||||
fileprivate extension String {
|
||||
func substring(with range: NSRange) -> String? {
|
||||
guard range.location != NSNotFound else { return nil }
|
||||
let utf16lowerBound = utf16.index(utf16.startIndex, offsetBy: range.location)
|
||||
let utf16upperBound = utf16.index(utf16lowerBound, offsetBy: range.length)
|
||||
guard let lowerBound = utf16lowerBound.samePosition(in: self),
|
||||
let upperBound = utf16upperBound.samePosition(in: self) else {
|
||||
fatalError("Never happen this")
|
||||
}
|
||||
return substring(with: lowerBound..<upperBound)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,21 +49,23 @@ extension Resolver {
|
|||
"|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$"
|
||||
].joined()),
|
||||
(.float, [
|
||||
"^(?:[-+]?(\\.[0-9]+|[0-9]+(\\.[0-9]*)?)([eE][-+]?[0-9]+)?",
|
||||
"^(?:[-+]?(?:[0-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?",
|
||||
"|\\.[0-9_]+(?:[eE][-+][0-9]+)?",
|
||||
"|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*",
|
||||
"|[-+]?\\.(?:inf|Inf|INF)",
|
||||
"|\\.(?:nan|NaN|NAN))$"
|
||||
].joined()),
|
||||
(.merge, "^(?:<<)$"),
|
||||
(.null, [
|
||||
"^(?: ~",
|
||||
"^(?:~",
|
||||
"|null|Null|NULL",
|
||||
"| )$"
|
||||
"|)$"
|
||||
].joined()),
|
||||
(.timestamp, [
|
||||
"^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]",
|
||||
"|[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?",
|
||||
"|[0-9][0-9][0-9][0-9]-[0-9][0-9]?-[0-9][0-9]?",
|
||||
"(?:[Tt]|[ \\t]+)[0-9][0-9]?",
|
||||
":[0-9][0-9] :[0-9][0-9] (?:\\.[0-9]*)?",
|
||||
":[0-9][0-9]:[0-9][0-9](?:\\.[0-9]*)?",
|
||||
"(?:[ \\t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$"
|
||||
].joined()),
|
||||
(.value, "^(?:=)$")
|
||||
|
@ -76,7 +78,7 @@ extension Resolver {
|
|||
|
||||
func pattern(_ string: String) -> NSRegularExpression {
|
||||
do {
|
||||
return try .init(pattern: string, options: .allowCommentsAndWhitespace)
|
||||
return try .init(pattern: string, options: [])
|
||||
} catch {
|
||||
fatalError("Never happen this!")
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import XCTest
|
|||
@testable import YamsTests
|
||||
|
||||
XCTMain([
|
||||
testCase(ConstructorTests.allTests),
|
||||
testCase(ParserTests.allTests),
|
||||
testCase(ResolverTests.allTests),
|
||||
testCase(StringTests.allTests),
|
||||
|
|
|
@ -0,0 +1,332 @@
|
|||
//
|
||||
// ConstructorTests.swift
|
||||
// Yams
|
||||
//
|
||||
// Created by Norio Nomura on 12/23/16.
|
||||
// Copyright (c) 2016 Yams. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import XCTest
|
||||
import Yams
|
||||
|
||||
class ConstructorTests: XCTestCase { // swiftlint:disable:this type_body_length
|
||||
// Samples come from PyYAML.
|
||||
|
||||
func testBinary() throws {
|
||||
let example = [
|
||||
"canonical: !!binary \"\\",
|
||||
" R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5\\",
|
||||
" OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+\\",
|
||||
" +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC\\",
|
||||
" AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=\"",
|
||||
"generic: !!binary |",
|
||||
" R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5",
|
||||
" OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+",
|
||||
" +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC",
|
||||
" AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=",
|
||||
"description:",
|
||||
" The binary value above is a tiny arrow encoded as a gif image.",
|
||||
""
|
||||
].joined(separator: "\n")
|
||||
let objects = try Yams.load(yaml: example)
|
||||
let data = Data(base64Encoded: [
|
||||
" R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5",
|
||||
" OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+",
|
||||
" +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC",
|
||||
" AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs="
|
||||
].joined(), options: .ignoreUnknownCharacters)!
|
||||
let expected: [String:Any] = [
|
||||
"canonical": data,
|
||||
"generic": data,
|
||||
"description": "The binary value above is a tiny arrow encoded as a gif image."
|
||||
]
|
||||
YamsAssertEqual(objects, expected)
|
||||
}
|
||||
|
||||
func testBool() throws {
|
||||
let example = [
|
||||
"canonical: yes",
|
||||
"answer: NO",
|
||||
"logical: True",
|
||||
"option: on",
|
||||
"",
|
||||
"",
|
||||
"but:",
|
||||
" y: is a string",
|
||||
" n: is a string",
|
||||
""
|
||||
].joined(separator: "\n")
|
||||
let objects = try Yams.load(yaml: example)
|
||||
let expected: [String:Any] = [
|
||||
"canonical": true,
|
||||
"answer": false,
|
||||
"logical": true,
|
||||
"option": true,
|
||||
"but": [
|
||||
"y": "is a string",
|
||||
"n": "is a string"
|
||||
]
|
||||
]
|
||||
YamsAssertEqual(objects, expected)
|
||||
}
|
||||
|
||||
func testFloat() throws {
|
||||
let example = [
|
||||
"canonical: 6.8523015e+5",
|
||||
"exponential: 685.230_15e+03",
|
||||
"fixed: 685_230.15",
|
||||
"sexagesimal: 190:20:30.15",
|
||||
"negative infinity: -.inf",
|
||||
"not a number: .NaN",
|
||||
""
|
||||
].joined(separator: "\n")
|
||||
let objects = try Yams.load(yaml: example)
|
||||
let expected: [String:Any] = [
|
||||
"canonical": 685230.15,
|
||||
"exponential": 685230.15,
|
||||
"fixed": 685230.15,
|
||||
"sexagesimal": 685230.15,
|
||||
"negative infinity": -Double.infinity,
|
||||
"not a number": Double.nan
|
||||
]
|
||||
YamsAssertEqual(objects, expected)
|
||||
}
|
||||
|
||||
func testInt() throws {
|
||||
let example = [
|
||||
"canonical: 685230",
|
||||
"decimal: +685_230",
|
||||
"octal: 02472256",
|
||||
"hexadecimal: 0x_0A_74_AE",
|
||||
"binary: 0b1010_0111_0100_1010_1110",
|
||||
"sexagesimal: 190:20:30",
|
||||
""
|
||||
].joined(separator: "\n")
|
||||
let objects = try Yams.load(yaml: example)
|
||||
let expected: [String:Any] = [
|
||||
"canonical": 685230,
|
||||
"decimal": 685230,
|
||||
"octal": 685230,
|
||||
"hexadecimal": 685230,
|
||||
"binary": 685230,
|
||||
"sexagesimal": 685230
|
||||
]
|
||||
YamsAssertEqual(objects, expected)
|
||||
}
|
||||
|
||||
func testMap() throws {
|
||||
let example = [
|
||||
"# Unordered set of key: value pairs.",
|
||||
"Block style: !!map",
|
||||
" Clark : Evans",
|
||||
" Brian : Ingerson",
|
||||
" Oren : Ben-Kiki",
|
||||
"Flow style: !!map { Clark: Evans, Brian: Ingerson, Oren: Ben-Kiki }",
|
||||
""
|
||||
].joined(separator: "\n")
|
||||
let objects = try Yams.load(yaml: example)
|
||||
let expected: [String:Any] = [
|
||||
"Block style": [
|
||||
"Clark" : "Evans",
|
||||
"Brian" : "Ingerson",
|
||||
"Oren" : "Ben-Kiki"
|
||||
],
|
||||
"Flow style": ["Clark": "Evans", "Brian": "Ingerson", "Oren": "Ben-Kiki"]
|
||||
]
|
||||
YamsAssertEqual(objects, expected)
|
||||
}
|
||||
|
||||
func testMerge() throws { // swiftlint:disable:this function_body_length
|
||||
let example = [
|
||||
"---",
|
||||
"- &CENTER { x: 1, 'y': 2 }",
|
||||
"- &LEFT { x: 0, 'y': 2 }",
|
||||
"- &BIG { r: 10 }",
|
||||
"- &SMALL { r: 1 }",
|
||||
"",
|
||||
"# All the following maps are equal:",
|
||||
"",
|
||||
"- # Explicit keys",
|
||||
" x: 1",
|
||||
" 'y': 2",
|
||||
" r: 10",
|
||||
" label: center/big",
|
||||
"",
|
||||
"- # Merge one map",
|
||||
" << : *CENTER",
|
||||
" r: 10",
|
||||
" label: center/big",
|
||||
"",
|
||||
"- # Merge multiple maps",
|
||||
" << : [ *CENTER, *BIG ]",
|
||||
" label: center/big",
|
||||
"",
|
||||
"- # Override",
|
||||
" << : [ *BIG, *LEFT, *SMALL ]",
|
||||
" x: 1",
|
||||
" label: center/big",
|
||||
""
|
||||
].joined(separator: "\n")
|
||||
let objects = try Yams.load(yaml: example)
|
||||
let expected: [[String:Any]] = [
|
||||
[ "x": 1, "y": 2 ],
|
||||
[ "x": 0, "y": 2 ],
|
||||
[ "r": 10 ],
|
||||
[ "r": 1 ],
|
||||
[ "x": 1, "y": 2, "r": 10, "label": "center/big" ],
|
||||
[ "x": 1, "y": 2, "r": 10, "label": "center/big" ],
|
||||
[ "x": 1, "y": 2, "r": 10, "label": "center/big" ],
|
||||
[ "x": 1, "y": 2, "r": 10, "label": "center/big" ]
|
||||
]
|
||||
YamsAssertEqual(objects, expected)
|
||||
}
|
||||
|
||||
func testNull() throws {
|
||||
let example = [
|
||||
"# A document may be null.",
|
||||
"---",
|
||||
"---",
|
||||
"# This mapping has four keys,",
|
||||
"# one has a value.",
|
||||
"empty:",
|
||||
"canonical: ~",
|
||||
"english: null",
|
||||
"~: null key",
|
||||
"---",
|
||||
"# This sequence has five",
|
||||
"# entries, two have values.",
|
||||
"sparse:",
|
||||
" - ~",
|
||||
" - 2nd entry",
|
||||
" -",
|
||||
" - 4th entry",
|
||||
" - Null",
|
||||
""
|
||||
].joined(separator: "\n")
|
||||
let objects = Array(try Yams.load_all(yaml: example))
|
||||
let expected: [Any] = [
|
||||
NSNull(),
|
||||
[
|
||||
"empty": NSNull(),
|
||||
"canonical": NSNull(),
|
||||
"english": NSNull(),
|
||||
"~": "null key" // null key is not supported yet.
|
||||
], [
|
||||
"sparse": [
|
||||
NSNull(),
|
||||
"2nd entry",
|
||||
NSNull(),
|
||||
"4th entry",
|
||||
NSNull()
|
||||
]
|
||||
]
|
||||
]
|
||||
YamsAssertEqual(objects, expected)
|
||||
}
|
||||
|
||||
func testSeq() throws {
|
||||
let example = [
|
||||
"# Ordered sequence of nodes",
|
||||
"Block style: !!seq",
|
||||
"- Mercury # Rotates - no light/dark sides.",
|
||||
"- Venus # Deadliest. Aptly named.",
|
||||
"- Earth # Mostly dirt.",
|
||||
"- Mars # Seems empty.",
|
||||
"- Jupiter # The king.",
|
||||
"- Saturn # Pretty.",
|
||||
"- Uranus # Where the sun hardly shines.",
|
||||
"- Neptune # Boring. No rings.",
|
||||
"- Pluto # You call this a planet?",
|
||||
"Flow style: !!seq [ Mercury, Venus, Earth, Mars, # Rocks",
|
||||
" Jupiter, Saturn, Uranus, Neptune, # Gas",
|
||||
" Pluto ] # Overrated",
|
||||
"",
|
||||
""
|
||||
].joined(separator: "\n")
|
||||
let objects = try Yams.load(yaml: example)
|
||||
let expected: [String:Any] = [
|
||||
"Block style": [
|
||||
"Mercury",
|
||||
"Venus",
|
||||
"Earth",
|
||||
"Mars",
|
||||
"Jupiter",
|
||||
"Saturn",
|
||||
"Uranus",
|
||||
"Neptune",
|
||||
"Pluto"
|
||||
],
|
||||
"Flow style": [ "Mercury", "Venus", "Earth", "Mars",
|
||||
"Jupiter", "Saturn", "Uranus", "Neptune",
|
||||
"Pluto" ]
|
||||
]
|
||||
YamsAssertEqual(objects, expected)
|
||||
}
|
||||
|
||||
func testTimestamp() throws {
|
||||
let example = [
|
||||
"canonical: 2001-12-15T02:59:43.1Z",
|
||||
"valid iso8601: 2001-12-14t21:59:43.10-05:00",
|
||||
"space separated: 2001-12-14 21:59:43.10 -5",
|
||||
"no time zone (Z): 2001-12-15 2:59:43.10",
|
||||
"date (00:00:00Z): 2002-12-14",
|
||||
""
|
||||
].joined(separator: "\n")
|
||||
let objects = try Yams.load(yaml: example)
|
||||
let expected: [String:Any] = [
|
||||
"canonical": timestamp( 0, 2001, 12, 15, 02, 59, 43, 0.1),
|
||||
"valid iso8601": timestamp(-5, 2001, 12, 14, 21, 59, 43, 0.1),
|
||||
"space separated": timestamp(-5, 2001, 12, 14, 21, 59, 43, 0.1),
|
||||
"no time zone (Z)": timestamp( 0, 2001, 12, 15, 02, 59, 43, 0.1),
|
||||
"date (00:00:00Z)": timestamp( 0, 2002, 12, 14)
|
||||
]
|
||||
YamsAssertEqual(objects, expected)
|
||||
}
|
||||
|
||||
func testValue() throws {
|
||||
let example = [
|
||||
"--- # Old schema",
|
||||
"link with:",
|
||||
" - library1.dll",
|
||||
" - library2.dll",
|
||||
"--- # New schema",
|
||||
"link with:",
|
||||
" - = : library1.dll",
|
||||
" version: 1.2",
|
||||
" - = : library2.dll",
|
||||
" version: 2.3",
|
||||
""
|
||||
].joined(separator: "\n")
|
||||
let objects = Array(try Yams.load_all(yaml: example))
|
||||
let expected: [Any] = [
|
||||
[
|
||||
"link with": [ "library1.dll", "library2.dll" ]
|
||||
], [
|
||||
"link with": [
|
||||
[ "=": "library1.dll", "version": 1.2 ],
|
||||
[ "=": "library2.dll", "version": 2.3 ]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
YamsAssertEqual(objects, expected)
|
||||
}
|
||||
}
|
||||
|
||||
extension ConstructorTests {
|
||||
static var allTests: [(String, (ConstructorTests) -> () throws -> Void)] {
|
||||
return [
|
||||
("testBinary", testBinary),
|
||||
("testBool", testBool),
|
||||
("testFloat", testFloat),
|
||||
("testInt", testInt),
|
||||
("testMap", testMap),
|
||||
("testMerge", testMerge),
|
||||
("testNull", testNull),
|
||||
("testSeq", testSeq),
|
||||
("testTimestamp", testTimestamp),
|
||||
("testValue", testValue)
|
||||
]
|
||||
}
|
||||
}
|
|
@ -166,12 +166,18 @@ class ParserTests: XCTestCase { // swiftlint:disable:this type_body_length
|
|||
"action: grand slam",
|
||||
"..."
|
||||
].joined(separator: "\n")
|
||||
let objects = try Yams.load(yaml: example)
|
||||
let expected: [String:Any] = [
|
||||
"time": "20:03:20",
|
||||
"player": "Sammy Sosa",
|
||||
"action": "strike (miss)"
|
||||
let objects = Array(try Yams.load_all(yaml: example))
|
||||
let expected: [[String:Any]] = [
|
||||
[
|
||||
"time": 72200,
|
||||
"player": "Sammy Sosa",
|
||||
"action": "strike (miss)"
|
||||
], [
|
||||
"time": 72227,
|
||||
"player": "Sammy Sosa",
|
||||
"action": "grand slam"
|
||||
]
|
||||
]
|
||||
YamsAssertEqual(objects, expected)
|
||||
}
|
||||
|
||||
|
@ -502,7 +508,7 @@ class ParserTests: XCTestCase { // swiftlint:disable:this type_body_length
|
|||
]
|
||||
let expected: [String:Any] = [
|
||||
"invoice" : 34843,
|
||||
"date" : "2001-01-23",
|
||||
"date" : timestamp(0, 2001, 1, 23),
|
||||
"bill-to" : billTo,
|
||||
"ship-to" : billTo,
|
||||
"product" : [
|
||||
|
@ -559,17 +565,17 @@ class ParserTests: XCTestCase { // swiftlint:disable:this type_body_length
|
|||
let objects = Array(try Yams.load_all(yaml: example))
|
||||
let expected: [Any] = [
|
||||
[
|
||||
"Time": "2001-11-23 15:01:42 -5",
|
||||
"Time": timestamp(-5, 2001, 11, 23, 15, 1, 42),
|
||||
"User": "ed",
|
||||
"Warning": "This is an error message for the log file"
|
||||
],
|
||||
[
|
||||
"Time": "2001-11-23 15:02:31 -5",
|
||||
"Time": timestamp(-5, 2001, 11, 23, 15, 2, 31),
|
||||
"User": "ed",
|
||||
"Warning": "A slightly different error message."
|
||||
],
|
||||
[
|
||||
"Date": "2001-11-23 15:03:17 -5",
|
||||
"Date": timestamp(-5, 2001, 11, 23, 15, 3, 17),
|
||||
"User": "ed",
|
||||
"Fatal": "Unknown variable \"bar\"",
|
||||
"Stack": [
|
||||
|
|
|
@ -6,8 +6,33 @@
|
|||
// Copyright (c) 2016 Yams. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
func timestamp(_ timeZoneHour: Int = 0,
|
||||
_ year: Int? = nil,
|
||||
_ month: Int? = nil,
|
||||
_ day: Int? = nil,
|
||||
_ hour: Int? = nil,
|
||||
_ minute: Int? = nil,
|
||||
_ second: Int? = nil,
|
||||
_ fraction: Double? = nil ) -> Date {
|
||||
let calendar = Calendar(identifier: .gregorian)
|
||||
let timeZone = TimeZone(secondsFromGMT: timeZoneHour * 60 * 60)
|
||||
#if os(Linux)
|
||||
let NSEC_PER_SEC = 1000000000
|
||||
#endif
|
||||
let nanosecond = fraction.map { Int($0 * Double(NSEC_PER_SEC)) }
|
||||
let datecomponents = DateComponents(calendar: calendar, timeZone: timeZone,
|
||||
year: year, month: month, day: day,
|
||||
hour: hour, minute: minute, second: second, nanosecond: nanosecond)
|
||||
// Using `DateComponents.date` causes crash on Linux
|
||||
guard let date = NSCalendar(identifier: .gregorian)?.date(from: datecomponents) else {
|
||||
fatalError("Never happen this")
|
||||
}
|
||||
return date
|
||||
}
|
||||
|
||||
/// AssertEqual for Any
|
||||
///
|
||||
/// - Parameters:
|
||||
|
@ -17,10 +42,12 @@ import XCTest
|
|||
/// - file: file path string
|
||||
/// - line: line number
|
||||
/// - Returns: true if lhs is equal to rhs
|
||||
@discardableResult func YamsAssertEqual(_ lhs: Any?, _ rhs: Any?,
|
||||
|
||||
@discardableResult func YamsAssertEqual(_ lhs: Any?, _ rhs: Any?, // swiftlint:disable:this function_body_length
|
||||
_ context: @autoclosure @escaping () -> String = "",
|
||||
file: StaticString = #file, line: UInt = #line) -> Bool {
|
||||
// use inner function for capturing `file` and `line`
|
||||
// swiftlint:disable:next cyclomatic_complexity
|
||||
@discardableResult func equal(_ lhs: Any?, _ rhs: Any?,
|
||||
_ context: @autoclosure @escaping () -> String = "") -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
/* Begin PBXBuildFile section */
|
||||
6C0488EC1E0BE113006F9F80 /* TestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C0488EB1E0BE113006F9F80 /* TestHelper.swift */; };
|
||||
6C0488EE1E0CBD56006F9F80 /* ConstructorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C0488ED1E0CBD56006F9F80 /* ConstructorTests.swift */; };
|
||||
6C0D2A361E0A934B00C45545 /* Constructor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C0D2A351E0A934B00C45545 /* Constructor.swift */; };
|
||||
6C4A22071DF8553C002A0206 /* String+Yams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C4A22061DF8553C002A0206 /* String+Yams.swift */; };
|
||||
6C4A22091DF855BB002A0206 /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C4A22081DF855BB002A0206 /* StringTests.swift */; };
|
||||
|
@ -43,6 +44,7 @@
|
|||
|
||||
/* Begin PBXFileReference section */
|
||||
6C0488EB1E0BE113006F9F80 /* TestHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestHelper.swift; sourceTree = "<group>"; };
|
||||
6C0488ED1E0CBD56006F9F80 /* ConstructorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConstructorTests.swift; sourceTree = "<group>"; };
|
||||
6C0D2A351E0A934B00C45545 /* Constructor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constructor.swift; sourceTree = "<group>"; };
|
||||
6C4A22061DF8553C002A0206 /* String+Yams.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Yams.swift"; sourceTree = "<group>"; };
|
||||
6C4A22081DF855BB002A0206 /* StringTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringTests.swift; sourceTree = "<group>"; };
|
||||
|
@ -123,6 +125,7 @@
|
|||
OBJ_24 /* YamsTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6C0488ED1E0CBD56006F9F80 /* ConstructorTests.swift */,
|
||||
6C6834D01E0297390047B4D1 /* ParserTests.swift */,
|
||||
6C6834D41E02BC1F0047B4D1 /* ResolverTests.swift */,
|
||||
6C4A22081DF855BB002A0206 /* StringTests.swift */,
|
||||
|
@ -307,6 +310,7 @@
|
|||
files = (
|
||||
6C4A22091DF855BB002A0206 /* StringTests.swift in Sources */,
|
||||
6C0488EC1E0BE113006F9F80 /* TestHelper.swift in Sources */,
|
||||
6C0488EE1E0CBD56006F9F80 /* ConstructorTests.swift in Sources */,
|
||||
OBJ_59 /* YamlErrorTests.swift in Sources */,
|
||||
6C6834D11E0297390047B4D1 /* ParserTests.swift in Sources */,
|
||||
6C6834D51E02BC1F0047B4D1 /* ResolverTests.swift in Sources */,
|
||||
|
|
Loading…
Reference in New Issue