Validations/Tests/ValidationsTests/ValidatorTests.swift

140 lines
3.8 KiB
Swift

import Decoded
import Validations
import XCTest
final class ValidatorTests: ValidationsTestCase {
func test_basic_validator_success() throws {
let decoded: Decoded<Int> = try decode("0")
let validator = Validator<Int> { (value: KeyedSuccess) in
nil
}
XCTAssertNoThrow(try decoded.validated(by: validator))
}
func test_presentable_decoded_errors() throws {
struct NonOptionalName: Decodable {
let name: Decoded<String>
}
let decoded: Decoded<NonOptionalName> = try decode(#"{"name":null}"#)
do {
_ = try decoded.validated()
} catch let failures as KeyedFailures {
let descriptions = failures.mapFailures(String.init(describing:))
#if os(Linux)
XCTAssertEqual(descriptions.value, [["name"]: ["Type mismatch."]])
#else
XCTAssertEqual(descriptions.value, [["name"]: ["Value not found."]])
#endif
}
}
func test_validatorResultBuilder() throws {
let decoder = JSONDecoder()
let data = """
{
"name": "a@b.com",
"email": "ab.com",
"address": {
"street": "a",
"city": "b",
"region": "c",
"postcode": "1234"
}
}
""".data(using: .utf8)!
struct TestFailure: CustomStringConvertible, ValidationFailure {
var description: String {
"test"
}
}
let decoded = try decoder.decode(Decoded<User>.self, from: data)
let validator = Validator<User> {
\.name == "asd"
\.address.street == \.name
ValidEmail(\.email)
Validator {
\.name != \.email
}.or(Validator {
\.name == "ab@b.com"
})
Validator(withValueAt: \.name) { name in
\.email != name
}
Validator(nestedAt: \.address) {
\.street == "a"
\.line2 == nil
IsNil(\.line2)
\.city == "b"
\.region == "c"
\.postcode == "1234"
}.mapFailures { _ in TestFailure() }
}
do {
let validated = try decoded.validated(by: validator)
let name: String = validated.name
print(name)
} catch let failures as KeyedFailures {
let descriptions = failures.mapFailures(String.init(describing:))
XCTAssertEqual(descriptions.value, [
["name"]: ["'a@b.com' does not equal 'asd'."],
["address", "street"]: ["'a' does not equal 'a@b.com'."],
["email"]: ["Is not a valid email address."],
["address", "line2"]: ["test"]
])
}
}
}
struct Address: Decodable {
var street: Decoded<String>
var line2: Decoded<String?>
var city: Decoded<String>
var region: Decoded<String>
var postcode: Decoded<String>
}
struct User: Decodable {
var email: Decoded<String>
var name: Decoded<String>
var address: Decoded<Address>
}
extension DecodingFailure: CustomStringConvertible {
public var description: String {
switch self.errorType {
case .dataCorrupted:
return "Data corrupted."
case .keyNotFound:
return "Key not found."
case .typeMismatch:
return "Type mismatch."
case .valueNotFound:
return "Value not found."
}
}
}
extension IsEqual.Failure: CustomStringConvertible {
public var description: String {
"'\(lhs)' does not equal '\(rhs)'."
}
}
extension ValidEmail.Failure: CustomStringConvertible {
public var description: String {
"Is not a valid email address."
}
}