mirror of
https://github.com/encounter/JSONAPI.git
synced 2026-03-30 11:18:38 -07:00
compare(to:) bug fixes and test additions
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// File.swift
|
||||
// AttributesCompare.swift
|
||||
//
|
||||
//
|
||||
// Created by Mathew Polzin on 11/3/19.
|
||||
@@ -24,12 +24,16 @@ extension Attributes {
|
||||
continue
|
||||
}
|
||||
|
||||
if (attributesEqual(child.value, otherChild.value)) {
|
||||
comparisons[childLabel] = .same
|
||||
} else {
|
||||
let otherChildDescription = attributeDescription(of: otherChild.value)
|
||||
do {
|
||||
if (try attributesEqual(child.value, otherChild.value)) {
|
||||
comparisons[childLabel] = .same
|
||||
} else {
|
||||
let otherChildDescription = attributeDescription(of: otherChild.value)
|
||||
|
||||
comparisons[childLabel] = .different(childDescription, otherChildDescription)
|
||||
comparisons[childLabel] = .different(childDescription, otherChildDescription)
|
||||
}
|
||||
} catch let error {
|
||||
comparisons[childLabel] = .prebuilt(String(describing: error))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,9 +41,20 @@ extension Attributes {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func attributesEqual(_ one: Any, _ two: Any) -> Bool {
|
||||
enum AttributeCompareError: Swift.Error, CustomStringConvertible {
|
||||
case nonAttributeTypeProperty(String)
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .nonAttributeTypeProperty(let type):
|
||||
return "comparison on non-JSON:API Attribute type (\(type)) not supported."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func attributesEqual(_ one: Any, _ two: Any) throws -> Bool {
|
||||
guard let attr = one as? AbstractAttribute else {
|
||||
return false
|
||||
throw AttributeCompareError.nonAttributeTypeProperty(String(describing: type(of: one)))
|
||||
}
|
||||
|
||||
return attr.equals(two)
|
||||
@@ -55,6 +70,29 @@ protocol AbstractAttribute {
|
||||
func equals(_ other: Any) -> Bool
|
||||
}
|
||||
|
||||
extension Optional: AbstractAttribute where Wrapped: AbstractAttribute {
|
||||
var abstractDescription: String {
|
||||
switch self {
|
||||
case .none:
|
||||
return "nil"
|
||||
case .some(let rel):
|
||||
return rel.abstractDescription
|
||||
}
|
||||
}
|
||||
|
||||
func equals(_ other: Any) -> Bool {
|
||||
switch self {
|
||||
case .none:
|
||||
return (other as? _AbstractWrapper).map { $0.abstractSelf == nil } ?? false
|
||||
case .some(let rel):
|
||||
guard case let .some(otherVal) = (other as? _AbstractWrapper)?.abstractSelf else {
|
||||
return rel.equals(other)
|
||||
}
|
||||
return rel.equals(otherVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Attribute: AbstractAttribute {
|
||||
var abstractDescription: String { String(describing: value) }
|
||||
|
||||
|
||||
@@ -24,12 +24,16 @@ extension Relationships {
|
||||
continue
|
||||
}
|
||||
|
||||
if (relationshipsEqual(child.value, otherChild.value)) {
|
||||
comparisons[childLabel] = .same
|
||||
} else {
|
||||
let otherChildDescription = relationshipDescription(of: otherChild.value)
|
||||
do {
|
||||
if (try relationshipsEqual(child.value, otherChild.value)) {
|
||||
comparisons[childLabel] = .same
|
||||
} else {
|
||||
let otherChildDescription = relationshipDescription(of: otherChild.value)
|
||||
|
||||
comparisons[childLabel] = .different(childDescription, otherChildDescription)
|
||||
comparisons[childLabel] = .different(childDescription, otherChildDescription)
|
||||
}
|
||||
} catch let error {
|
||||
comparisons[childLabel] = .prebuilt(String(describing: error))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,9 +41,20 @@ extension Relationships {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func relationshipsEqual(_ one: Any, _ two: Any) -> Bool {
|
||||
enum RelationshipCompareError: Swift.Error, CustomStringConvertible {
|
||||
case nonRelationshipTypeProperty(String)
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .nonRelationshipTypeProperty(let type):
|
||||
return "comparison on non-JSON:API Relationship type (\(type)) not supported."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func relationshipsEqual(_ one: Any, _ two: Any) throws -> Bool {
|
||||
guard let attr = one as? AbstractRelationship else {
|
||||
return false
|
||||
throw RelationshipCompareError.nonRelationshipTypeProperty(String(describing: type(of: one)))
|
||||
}
|
||||
|
||||
return attr.equals(two)
|
||||
@@ -55,6 +70,29 @@ protocol AbstractRelationship {
|
||||
func equals(_ other: Any) -> Bool
|
||||
}
|
||||
|
||||
extension Optional: AbstractRelationship where Wrapped: AbstractRelationship {
|
||||
var abstractDescription: String {
|
||||
switch self {
|
||||
case .none:
|
||||
return "nil"
|
||||
case .some(let rel):
|
||||
return rel.abstractDescription
|
||||
}
|
||||
}
|
||||
|
||||
func equals(_ other: Any) -> Bool {
|
||||
switch self {
|
||||
case .none:
|
||||
return (other as? _AbstractWrapper).map { $0.abstractSelf == nil } ?? false
|
||||
case .some(let rel):
|
||||
guard case let .some(otherVal) = (other as? _AbstractWrapper)?.abstractSelf else {
|
||||
return rel.equals(other)
|
||||
}
|
||||
return rel.equals(otherVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ToOneRelationship: AbstractRelationship {
|
||||
var abstractDescription: String {
|
||||
if meta is NoMetadata && links is NoLinks {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// File.swift
|
||||
// AttributesCompareTests.swift
|
||||
//
|
||||
//
|
||||
// Created by Mathew Polzin on 11/3/19.
|
||||
@@ -17,7 +17,9 @@ final class AttributesCompareTests: XCTestCase {
|
||||
bool: true,
|
||||
double: 105.4,
|
||||
struct: .init(value: .init()),
|
||||
transformed: try .init(rawValue: 10)
|
||||
transformed: try .init(rawValue: 10),
|
||||
optional: .init(value: 20),
|
||||
optionalTransformed: try .init(rawValue: 10)
|
||||
)
|
||||
let attr2 = attr1
|
||||
|
||||
@@ -27,7 +29,9 @@ final class AttributesCompareTests: XCTestCase {
|
||||
"bool": .same,
|
||||
"double": .same,
|
||||
"struct": .same,
|
||||
"transformed": .same
|
||||
"transformed": .same,
|
||||
"optional": .same,
|
||||
"optionalTransformed": .same
|
||||
])
|
||||
}
|
||||
|
||||
@@ -38,7 +42,9 @@ final class AttributesCompareTests: XCTestCase {
|
||||
bool: true,
|
||||
double: 105.4,
|
||||
struct: .init(value: .init()),
|
||||
transformed: try .init(rawValue: 10)
|
||||
transformed: try .init(rawValue: 10),
|
||||
optional: nil,
|
||||
optionalTransformed: nil
|
||||
)
|
||||
let attr2 = TestAttributes(
|
||||
string: "hello",
|
||||
@@ -46,7 +52,9 @@ final class AttributesCompareTests: XCTestCase {
|
||||
bool: false,
|
||||
double: 1.4,
|
||||
struct: .init(value: .init(val: "there")),
|
||||
transformed: try .init(rawValue: 11)
|
||||
transformed: try .init(rawValue: 11),
|
||||
optional: .init(value: 20.5),
|
||||
optionalTransformed: try .init(rawValue: 10)
|
||||
)
|
||||
|
||||
XCTAssertEqual(attr1.compare(to: attr2), [
|
||||
@@ -55,7 +63,29 @@ final class AttributesCompareTests: XCTestCase {
|
||||
"bool": .different("true", "false"),
|
||||
"double": .different("105.4", "1.4"),
|
||||
"struct": .different("string: hello", "string: there"),
|
||||
"transformed": .different("10", "11")
|
||||
"transformed": .different("10", "11"),
|
||||
"optional": .different("nil", "20.5"),
|
||||
"optionalTransformed": .different("nil", "10")
|
||||
])
|
||||
}
|
||||
|
||||
func test_nonAttributeTypes() {
|
||||
let attr1 = NonAttributeTest(
|
||||
string: "hello",
|
||||
int: 10,
|
||||
double: 11.2,
|
||||
bool: true,
|
||||
struct: .init(),
|
||||
optional: nil
|
||||
)
|
||||
|
||||
XCTAssertEqual(attr1.compare(to: attr1), [
|
||||
"string": .prebuilt("comparison on non-JSON:API Attribute type (String) not supported."),
|
||||
"int": .prebuilt("comparison on non-JSON:API Attribute type (Int) not supported."),
|
||||
"double": .prebuilt("comparison on non-JSON:API Attribute type (Double) not supported."),
|
||||
"bool": .prebuilt("comparison on non-JSON:API Attribute type (Bool) not supported."),
|
||||
"struct": .prebuilt("comparison on non-JSON:API Attribute type (Struct) not supported."),
|
||||
"optional": .prebuilt("comparison on non-JSON:API Attribute type (Optional<Int>) not supported.")
|
||||
])
|
||||
}
|
||||
}
|
||||
@@ -67,16 +97,18 @@ private struct TestAttributes: JSONAPI.Attributes {
|
||||
let double: Attribute<Double>
|
||||
let `struct`: Attribute<Struct>
|
||||
let transformed: TransformedAttribute<Int, TestTransformer>
|
||||
let optional: Attribute<Double>?
|
||||
let optionalTransformed: TransformedAttribute<Int, TestTransformer>?
|
||||
}
|
||||
|
||||
struct Struct: Equatable, Codable, CustomStringConvertible {
|
||||
let string: String
|
||||
private struct Struct: Equatable, Codable, CustomStringConvertible {
|
||||
let string: String
|
||||
|
||||
init(val: String = "hello") {
|
||||
self.string = val
|
||||
}
|
||||
|
||||
var description: String { return "string: \(string)" }
|
||||
init(val: String = "hello") {
|
||||
self.string = val
|
||||
}
|
||||
|
||||
var description: String { return "string: \(string)" }
|
||||
}
|
||||
|
||||
private enum TestTransformer: Transformer {
|
||||
@@ -84,3 +116,12 @@ private enum TestTransformer: Transformer {
|
||||
return "\(value)"
|
||||
}
|
||||
}
|
||||
|
||||
private struct NonAttributeTest: JSONAPI.Attributes {
|
||||
let string: String
|
||||
let int: Int
|
||||
let double: Double
|
||||
let bool: Bool
|
||||
let `struct`: Struct
|
||||
let optional: Int?
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ final class DocumentCompareTests: XCTestCase {
|
||||
XCTAssertTrue(d8.compare(to: d8).differences.isEmpty)
|
||||
XCTAssertTrue(d9.compare(to: d9).differences.isEmpty)
|
||||
XCTAssertTrue(d10.compare(to: d10).differences.isEmpty)
|
||||
|
||||
XCTAssertEqual(String(describing: d1.compare(to: d1).body), "same")
|
||||
}
|
||||
|
||||
func test_errorAndData() {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Optional+AbstractWrapper.swift
|
||||
// JSONAPITesting
|
||||
//
|
||||
// Created by Mathew Polzin on 11/15/19.
|
||||
//
|
||||
|
||||
protocol _AbstractWrapper {
|
||||
var abstractSelf: Any? { get }
|
||||
}
|
||||
|
||||
extension Optional: _AbstractWrapper {
|
||||
var abstractSelf: Any? {
|
||||
return self
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// File.swift
|
||||
// RelationshipCompareTests.swift
|
||||
//
|
||||
//
|
||||
// Created by Mathew Polzin on 11/5/19.
|
||||
@@ -11,22 +11,175 @@ import JSONAPITesting
|
||||
|
||||
final class RelationshipsCompareTests: XCTestCase {
|
||||
func test_same() {
|
||||
// TODO: write test
|
||||
let r1 = TestRelationships(
|
||||
a: t1,
|
||||
b: t2,
|
||||
c: t3,
|
||||
d: t4
|
||||
)
|
||||
let r2 = r1
|
||||
|
||||
XCTAssertTrue(r1.compare(to: r2).allSatisfy { $0.value == .same })
|
||||
|
||||
let r3 = TestRelationships(
|
||||
a: t1_differentId,
|
||||
b: t2_differentLinks,
|
||||
c: t3_differentId,
|
||||
d: t4_differentLinks
|
||||
)
|
||||
let r4 = r3
|
||||
|
||||
XCTAssertTrue(r3.compare(to: r4).allSatisfy { $0.value == .same })
|
||||
|
||||
let r5 = TestRelationships(
|
||||
a: nil,
|
||||
b: nil,
|
||||
c: nil,
|
||||
d: nil
|
||||
)
|
||||
let r6 = r5
|
||||
|
||||
XCTAssertTrue(r5.compare(to: r6).allSatisfy { $0.value == .same })
|
||||
}
|
||||
|
||||
func test_differentIds() {
|
||||
// TODO: write test
|
||||
}
|
||||
let r1 = TestRelationships(
|
||||
a: t1,
|
||||
b: nil,
|
||||
c: t3,
|
||||
d: nil
|
||||
)
|
||||
|
||||
func test_differentTypes() {
|
||||
// TODO: write test
|
||||
let r2 = TestRelationships(
|
||||
a: t1_differentId,
|
||||
b: nil,
|
||||
c: t3_differentId,
|
||||
d: nil
|
||||
)
|
||||
|
||||
XCTAssertEqual(r1.compare(to: r2), [
|
||||
"a": .different("Id(123)", "Id(999)"),
|
||||
"b": .same,
|
||||
"c": .different("123, 456", "999, 1010"),
|
||||
"d": .same
|
||||
])
|
||||
}
|
||||
|
||||
func test_differentMetadata() {
|
||||
// TODO: write test
|
||||
let r1 = TestRelationships(
|
||||
a: nil,
|
||||
b: t2,
|
||||
c: nil,
|
||||
d: t4
|
||||
)
|
||||
|
||||
let r2 = TestRelationships(
|
||||
a: nil,
|
||||
b: t2_differentMeta,
|
||||
c: nil,
|
||||
d: t4_differentMeta
|
||||
)
|
||||
|
||||
XCTAssertEqual(r1.compare(to: r2), [
|
||||
"a": .same,
|
||||
"b": .different(#"("Id(456)", "hello: world", "link: http://google.com")"#, #"("Id(456)", "hello: there", "link: http://google.com")"#),
|
||||
"c": .same,
|
||||
"d": .different(#"("123, 456", "hello: world", "link: http://google.com")"#, #"("123, 456", "hello: there", "link: http://google.com")"#)
|
||||
])
|
||||
}
|
||||
|
||||
func test_differentLinks() {
|
||||
// TODO: write tests
|
||||
let r1 = TestRelationships(
|
||||
a: nil,
|
||||
b: t2,
|
||||
c: nil,
|
||||
d: t4
|
||||
)
|
||||
|
||||
let r2 = TestRelationships(
|
||||
a: nil,
|
||||
b: t2_differentLinks,
|
||||
c: nil,
|
||||
d: t4_differentLinks
|
||||
)
|
||||
|
||||
XCTAssertEqual(r1.compare(to: r2), [
|
||||
"a": .same,
|
||||
"b": .different(#"("Id(456)", "hello: world", "link: http://google.com")"#, #"("Id(456)", "hello: world", "link: http://yahoo.com")"#),
|
||||
"c": .same,
|
||||
"d": .different(#"("123, 456", "hello: world", "link: http://google.com")"#, #"("123, 456", "hello: world", "link: http://yahoo.com")"#)
|
||||
])
|
||||
}
|
||||
|
||||
func test_nonRelationshipTypes() {
|
||||
let r1 = TestNonRelationships(
|
||||
a: .init(attributes: .none, relationships: .none, meta: .none, links: .none),
|
||||
b: false,
|
||||
c: 10,
|
||||
d: "1234"
|
||||
)
|
||||
|
||||
XCTAssertEqual(r1.compare(to: r1), [
|
||||
"a": .prebuilt("comparison on non-JSON:API Relationship type (ResourceObject<TestTypeDescription, NoMetadata, NoLinks, String>) not supported."),
|
||||
"b": .prebuilt("comparison on non-JSON:API Relationship type (Bool) not supported."),
|
||||
"c": .prebuilt("comparison on non-JSON:API Relationship type (Int) not supported."),
|
||||
"d": .prebuilt("comparison on non-JSON:API Relationship type (Id<String, ResourceObject<TestTypeDescription, NoMetadata, NoLinks, String>>) not supported.")
|
||||
])
|
||||
}
|
||||
|
||||
let t1 = ToOneRelationship<TestType, NoMetadata, NoLinks>(id: "123")
|
||||
let t2 = ToOneRelationship<TestType, TestMeta, TestLinks>(id: "456", meta: .init(hello: "world"), links: .init(link: .init(url: "http://google.com")))
|
||||
let t3 = ToManyRelationship<TestType, NoMetadata, NoLinks>(ids: ["123", "456"])
|
||||
let t4 = ToManyRelationship<TestType, TestMeta, TestLinks>(ids: ["123", "456"], meta: .init(hello: "world"), links: .init(link: .init(url: "http://google.com")))
|
||||
|
||||
let t1_differentId = ToOneRelationship<TestType, NoMetadata, NoLinks>(id: "999")
|
||||
let t3_differentId = ToManyRelationship<TestType, NoMetadata, NoLinks>(ids: ["999", "1010"])
|
||||
|
||||
let t2_differentLinks = ToOneRelationship<TestType, TestMeta, TestLinks>(id: "456", meta: .init(hello: "world"), links: .init(link: .init(url: "http://yahoo.com")))
|
||||
let t4_differentLinks = ToManyRelationship<TestType, TestMeta, TestLinks>(ids: ["123", "456"], meta: .init(hello: "world"), links: .init(link: .init(url: "http://yahoo.com")))
|
||||
|
||||
let t2_differentMeta = ToOneRelationship<TestType, TestMeta, TestLinks>(id: "456", meta: .init(hello: "there"), links: .init(link: .init(url: "http://google.com")))
|
||||
let t4_differentMeta = ToManyRelationship<TestType, TestMeta, TestLinks>(ids: ["123", "456"], meta: .init(hello: "there"), links: .init(link: .init(url: "http://google.com")))
|
||||
}
|
||||
|
||||
// MARK: - Test Types
|
||||
extension RelationshipsCompareTests {
|
||||
enum TestTypeDescription: ResourceObjectDescription {
|
||||
static let jsonType: String = "test"
|
||||
|
||||
typealias Attributes = NoAttributes
|
||||
typealias Relationships = NoRelationships
|
||||
}
|
||||
|
||||
typealias TestType = ResourceObject<TestTypeDescription, NoMetadata, NoLinks, String>
|
||||
|
||||
struct TestMeta: JSONAPI.Meta, CustomDebugStringConvertible {
|
||||
let hello: String
|
||||
|
||||
var debugDescription: String {
|
||||
"hello: \(hello)"
|
||||
}
|
||||
}
|
||||
|
||||
struct TestLinks: JSONAPI.Links, CustomDebugStringConvertible {
|
||||
let link: Link<String, NoMetadata>
|
||||
|
||||
var debugDescription: String {
|
||||
"link: \(link.url)"
|
||||
}
|
||||
}
|
||||
|
||||
struct TestRelationships: JSONAPI.Relationships {
|
||||
let a: ToOneRelationship<TestType, NoMetadata, NoLinks>?
|
||||
let b: ToOneRelationship<TestType, TestMeta, TestLinks>?
|
||||
let c: ToManyRelationship<TestType, NoMetadata, NoLinks>?
|
||||
let d: ToManyRelationship<TestType, TestMeta, TestLinks>?
|
||||
}
|
||||
|
||||
struct TestNonRelationships: JSONAPI.Relationships {
|
||||
let a: TestType
|
||||
let b: Bool
|
||||
let c: Int
|
||||
let d: JSONAPI.Id<String, TestType>
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user