diff --git a/Tests/XMLCoderTests/ClassTests.swift b/Tests/XMLCoderTests/ClassTests.swift new file mode 100644 index 00000000..b6ed39fa --- /dev/null +++ b/Tests/XMLCoderTests/ClassTests.swift @@ -0,0 +1,115 @@ +// +// ClassTest.swift +// XMLCoder +// +// Created by Matvii Hodovaniuk on 1/4/19. +// + +import Foundation +import XCTest +@testable import XMLCoder + +class A: Codable { + let x: String +} + +class B: A { + let y: Double + + private enum CodingKeys: CodingKey { + case y + } + + required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + y = try container.decode(Double.self, forKey: .y) + let superDecoder = try container.superDecoder() + try super.init(from: superDecoder) + } + + override func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(y, forKey: .y) + let superEncoder = container.superEncoder() + try super.encode(to: superEncoder) + } +} + +class C: B { + let z: Int + + private enum CodingKeys: CodingKey { + case z + } + + required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + z = try container.decode(Int.self, forKey: .z) + let superDecoder = try container.superDecoder() + try super.init(from: superDecoder) + } + + override func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(z, forKey: .z) + let superEncoder = container.superEncoder() + try super.encode(to: superEncoder) + } +} + +struct S: Codable { + let a: A + let b: B + let c: C +} + +let str = "test_string" +let int = 42 +let double = 4.2 + +let xmlData = """ + + + \(str) + + + + \(str) + + \(double) + + + + + \(str) + + \(double) + + \(int) + + +""".data(using: .utf8)! + +class ClassTests: XCTestCase { + func testEmpty() throws { + let decoder = XMLDecoder() + let encoder = XMLEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys] + + let decoded = try decoder.decode(S.self, from: xmlData) + XCTAssertEqual(decoded.a.x, str) + XCTAssertEqual(decoded.b.x, str) + XCTAssertEqual(decoded.b.y, double) + XCTAssertEqual(decoded.c.z, int) + XCTAssertEqual(decoded.c.x, str) + XCTAssertEqual(decoded.c.y, double) + + let encoded = try encoder.encode(decoded, withRootKey: "s") + + XCTAssertEqual(encoded, xmlData) + } + + static var allTests = [ + ("testEmpty", testEmpty), + ] +} diff --git a/Tests/XMLCoderTests/Minimal/IntTests.swift b/Tests/XMLCoderTests/Minimal/IntTests.swift index ff778736..ae99c471 100644 --- a/Tests/XMLCoderTests/Minimal/IntTests.swift +++ b/Tests/XMLCoderTests/Minimal/IntTests.swift @@ -8,29 +8,38 @@ import XCTest @testable import XMLCoder +protocol IntegerContainer { + associatedtype Integer: BinaryInteger + + var value: Integer { get } +} + +extension IntegerContainer { + var intValue: Int { + return Int(value) + } +} + class IntTests: XCTestCase { typealias Value = Int - struct Container: Codable, Equatable { - let value: Value + struct Container: Codable, Equatable, IntegerContainer where T: Codable & Equatable & BinaryInteger { + let value: T } let values: [(Value, String)] = [ - (-42, "-42"), (0, "0"), (42, "42"), ] - func testMissing() { + func testMissing(_ type: T.Type) throws { let decoder = XMLDecoder() - let xmlString = "" let xmlData = xmlString.data(using: .utf8)! - - XCTAssertThrowsError(try decoder.decode(Container.self, from: xmlData)) + XCTAssertThrowsError(try decoder.decode(type, from: xmlData)) } - func testAttribute() throws { + func testAttribute(_ type: T.Type) throws { let decoder = XMLDecoder() let encoder = XMLEncoder() @@ -45,15 +54,15 @@ class IntTests: XCTestCase { """ let xmlData = xmlString.data(using: .utf8)! - let decoded = try decoder.decode(Container.self, from: xmlData) - XCTAssertEqual(decoded.value, value) + let decoded = try decoder.decode(type, from: xmlData) + XCTAssertEqual(decoded.intValue, value) let encoded = try encoder.encode(decoded, withRootKey: "container") XCTAssertEqual(String(data: encoded, encoding: .utf8)!, xmlString) } } - func testElement() throws { + func testElement(_ type: T.Type) throws { let decoder = XMLDecoder() let encoder = XMLEncoder() @@ -68,16 +77,56 @@ class IntTests: XCTestCase { """ let xmlData = xmlString.data(using: .utf8)! - let decoded = try decoder.decode(Container.self, from: xmlData) - XCTAssertEqual(decoded.value, value) + let decoded = try decoder.decode(type, from: xmlData) + XCTAssertEqual(decoded.intValue, value) let encoded = try encoder.encode(decoded, withRootKey: "container") XCTAssertEqual(String(data: encoded, encoding: .utf8)!, xmlString) } } + func testIntegerTypeMissing() throws { + try testMissing(Container.self) + try testMissing(Container.self) + try testMissing(Container.self) + try testMissing(Container.self) + try testMissing(Container.self) + try testMissing(Container.self) + try testMissing(Container.self) + try testMissing(Container.self) + try testMissing(Container.self) + try testMissing(Container.self) + } + + func testIntegerTypeAttribute() throws { + try testAttribute(Container.self) + try testAttribute(Container.self) + try testAttribute(Container.self) + try testAttribute(Container.self) + try testAttribute(Container.self) + try testAttribute(Container.self) + try testAttribute(Container.self) + try testAttribute(Container.self) + try testAttribute(Container.self) + try testAttribute(Container.self) + } + + func testIntegerTypeElement() throws { + try testElement(Container.self) + try testElement(Container.self) + try testElement(Container.self) + try testElement(Container.self) + try testElement(Container.self) + try testElement(Container.self) + try testElement(Container.self) + try testElement(Container.self) + try testElement(Container.self) + try testElement(Container.self) + } + static var allTests = [ - ("testAttribute", testAttribute), - ("testElement", testElement), + ("testIntegerTypeMissing", testIntegerTypeMissing), + ("testIntegerTypeAttribute", testIntegerTypeAttribute), + ("testIntegerTypeElement", testIntegerTypeElement), ] } diff --git a/Tests/XMLCoderTests/Minimal/KeyedTests.swift b/Tests/XMLCoderTests/Minimal/KeyedTests.swift index 9052f30d..654832ad 100644 --- a/Tests/XMLCoderTests/Minimal/KeyedTests.swift +++ b/Tests/XMLCoderTests/Minimal/KeyedTests.swift @@ -13,6 +13,26 @@ class KeyedTests: XCTestCase { let value: [String: Int] } + struct ContainerCamelCase: Codable, Equatable { + let valUe: [String: Int] + let testAttribute: String + } + + struct AnyKey: CodingKey { + var stringValue: String + var intValue: Int? + + init?(stringValue: String) { + self.stringValue = stringValue + intValue = nil + } + + init?(intValue: Int) { + stringValue = String(intValue) + self.intValue = intValue + } + } + func testEmpty() throws { let decoder = XMLDecoder() @@ -72,10 +92,69 @@ class KeyedTests: XCTestCase { ) } + func testConvertFromSnakeCase() throws { + let decoder = XMLDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + + let xmlString = + """ + + + 12 + + + """ + let xmlData = xmlString.data(using: .utf8)! + + let decoded = try decoder.decode(ContainerCamelCase.self, from: xmlData) + + XCTAssertEqual(decoded.valUe, ["foO": 12]) + } + + func testErrorDescriptionConvertFromSnakeCase() throws { + let decoder = XMLDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + + let xmlString = + """ + + + 12 + + + """ + let xmlData = xmlString.data(using: .utf8)! + + XCTAssertThrowsError(try decoder.decode(ContainerCamelCase.self, from: xmlData)) + } + + func testCustomDecoderConvert() throws { + let decoder = XMLDecoder() + decoder.keyDecodingStrategy = .custom { keys in + let lastComponent = keys.last!.stringValue.split(separator: "_").last! + return AnyKey(stringValue: String(lastComponent))! + } + + let xmlString = + """ + + + 12 + + + """ + let xmlData = xmlString.data(using: .utf8)! + + let decoded = try decoder.decode(ContainerCamelCase.self, from: xmlData) + + XCTAssertEqual(decoded.valUe, ["foo": 12]) + } + static var allTests = [ ("testEmpty", testEmpty), ("testSingleElement", testSingleElement), ("testMultiElement", testMultiElement), ("testAttribute", testAttribute), + ("testConvertFromSnakeCase", testConvertFromSnakeCase), ] } diff --git a/XMLCoder.xcodeproj/project.pbxproj b/XMLCoder.xcodeproj/project.pbxproj index 5c8bb7f2..fcd21e54 100644 --- a/XMLCoder.xcodeproj/project.pbxproj +++ b/XMLCoder.xcodeproj/project.pbxproj @@ -21,6 +21,7 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + A61DCCD821DF9CA200C0A19D /* ClassTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A61DCCD621DF8DB300C0A19D /* ClassTests.swift */; }; BF63EF0021CCDED2001D38C5 /* XMLStackParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF63EEFF21CCDED2001D38C5 /* XMLStackParserTests.swift */; }; BF63EF0621CD7A74001D38C5 /* URLBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF63EF0521CD7A74001D38C5 /* URLBox.swift */; }; BF63EF0821CD7AF8001D38C5 /* URLBoxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF63EF0721CD7AF8001D38C5 /* URLBoxTests.swift */; }; @@ -115,6 +116,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + A61DCCD621DF8DB300C0A19D /* ClassTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClassTests.swift; sourceTree = ""; }; BF63EEFF21CCDED2001D38C5 /* XMLStackParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XMLStackParserTests.swift; sourceTree = ""; }; BF63EF0521CD7A74001D38C5 /* URLBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLBox.swift; sourceTree = ""; }; BF63EF0721CD7AF8001D38C5 /* URLBoxTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLBoxTests.swift; sourceTree = ""; }; @@ -335,6 +337,7 @@ OBJ_37 /* RJITest.swift */, OBJ_38 /* RelationshipsTest.swift */, D1FC040421C7EF8200065B43 /* RJISample.swift */, + A61DCCD621DF8DB300C0A19D /* ClassTests.swift */, ); name = XMLCoderTests; path = Tests/XMLCoderTests; @@ -555,6 +558,7 @@ OBJ_88 /* PlantTest.swift in Sources */, BF63EF0821CD7AF8001D38C5 /* URLBoxTests.swift in Sources */, BF9457DD21CBB62C005ACFDE /* DateBoxTests.swift in Sources */, + A61DCCD821DF9CA200C0A19D /* ClassTests.swift in Sources */, BF9457CD21CBB516005ACFDE /* FloatBoxTests.swift in Sources */, BF9457F621CBB6BC005ACFDE /* KeyedTests.swift in Sources */, BF9457C821CBB516005ACFDE /* BoolBoxTests.swift in Sources */,