Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dedicated benchmarking test suite #34

Merged
merged 7 commits into from Jan 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 3 additions & 4 deletions Sources/XMLCoder/Box/KeyedBox.swift
Expand Up @@ -56,10 +56,9 @@ extension KeyedStorage: ExpressibleByDictionaryLiteral {
}
}

extension KeyedStorage: CustomStringConvertible
where Key: Comparable {
extension KeyedStorage: CustomStringConvertible {
var description: String {
return "[\(buffer)]"
return "\(buffer)"
}
}

Expand Down Expand Up @@ -110,6 +109,6 @@ extension KeyedBox: Box {

extension KeyedBox: CustomStringConvertible {
var description: String {
return "\(elements)"
return "{attributes: \(attributes), elements: \(elements)}"
}
}
13 changes: 9 additions & 4 deletions Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift
Expand Up @@ -222,10 +222,15 @@ struct _XMLKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainerProtocol

let value: T? = try decoder.unbox(entry)

if value == nil,
let type = type as? AnyArray.Type,
type.elementType is AnyOptional.Type {
return [nil] as! T
if value == nil {
if let type = type as? AnyArray.Type,
type.elementType is AnyOptional.Type,
let result = [nil] as? T {
return result
} else if let type = type as? AnyOptional.Type,
let result = type.init() as? T {
return result
}
}

guard let unwrapped = value else {
Expand Down
15 changes: 14 additions & 1 deletion Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift
Expand Up @@ -160,7 +160,20 @@ struct _XMLUnkeyedDecodingContainer: UnkeyedDecodingContainer {
decoder.codingPath.append(_XMLKey(index: currentIndex))
defer { self.decoder.codingPath.removeLast() }

let box = container[self.currentIndex]
let box: Box

// work around unkeyed box wrapped as single element of keyed box
if let type = type as? AnyArray.Type,
let keyedBox = container[self.currentIndex] as? KeyedBox,
keyedBox.attributes.count == 0,
keyedBox.elements.count == 1,
let firstKey = keyedBox.elements.keys.first,
let unkeyedBox = keyedBox.elements[firstKey] {
box = unkeyedBox
} else {
box = container[self.currentIndex]
}

let value = try decode(decoder, box)

defer { currentIndex += 1 }
Expand Down
243 changes: 243 additions & 0 deletions Tests/XMLCoderTests/BenchmarkTests.swift
@@ -0,0 +1,243 @@
import XCTest
@testable import XMLCoder

class BenchmarkTests: XCTestCase {
struct Container<T: Codable>: Codable {
let unkeyed: [T]
let keyed: [String: T]
}

func container<T: Codable>(with value: T) -> Container<T> {
// unkeyed.count + keyed.count = self.count:
let count = self.count / 2

let unkeyed = [T](repeating: value, count: count)
let keyed = Dictionary(uniqueKeysWithValues: unkeyed.enumerated().map { index, value in
("key_\(index)", value)
})

return Container(unkeyed: unkeyed, keyed: keyed)
}

func encodedContainer<T: Codable>(of _: T.Type, with value: T) throws -> Data {
let container = self.container(with: value)

let encoder = XMLEncoder()
encoder.outputFormatting = .prettyPrinted

return try encoder.encode(container, withRootKey: "container")
}

func testEncoding<T: Codable>(with value: T, _ closure: (() -> ()) -> ()) throws {
try testEncoding(of: T.self, with: value, closure)
}

func testEncoding<T: Codable>(of _: T.Type, with value: T, _ closure: (() -> ()) -> ()) throws {
let container: Container<T> = self.container(with: value)

let encoder = XMLEncoder()

var caughtError: Error?

closure {
do {
_ = try encoder.encode(container, withRootKey: "container")
} catch {
caughtError = error
}
}

if let error = caughtError {
throw error
}
}

func testDecoding<T: Codable>(with value: T, _ closure: (() -> ()) -> ()) throws {
try testDecoding(of: T.self, with: value, closure)
}

func testDecoding<T: Codable>(of _: T.Type, with value: T, _ closure: (() -> ()) -> ()) throws {
let data: Data = try encodedContainer(of: T.self, with: value)

let decoder = XMLDecoder()

var caughtError: Error?

closure {
do {
_ = try decoder.decode(Container<T>.self, from: data)
} catch {
caughtError = error
}
}

if let error = caughtError {
throw error
}
}

let count: Int = 1000

let null: Bool? = nil
let bool: Bool = true
let int: Int = -42
let uint: UInt = 42
let float: Float = 42.0
let decimal: Decimal = 42.0
let date: Date = Date()
let data: Data = Data(base64Encoded: "bG9yZW0gaXBzdW0=")!
let url: URL = URL(string: "http://example.com")!
let array: [Int] = [1, 2, 3, 4, 5]
let dictionary: [String: Int] = ["key_1": 1, "key_2": 2, "key_3": 3, "key_4": 4, "key_5": 5]

func testEncodeNulls() throws {
try testEncoding(with: null) { closure in
self.measure { closure() }
}
}

func testDecodeNulls() throws {
try testDecoding(with: null) { closure in
self.measure { closure() }
}
}

func testEncodeBools() throws {
try testEncoding(with: bool) { closure in
self.measure { closure() }
}
}

func testDecodeBools() throws {
try testDecoding(with: bool) { closure in
self.measure { closure() }
}
}

func testEncodeInts() throws {
try testEncoding(with: int) { closure in
self.measure { closure() }
}
}

func testDecodeInts() throws {
try testDecoding(with: int) { closure in
self.measure { closure() }
}
}

func testEncodeUInts() throws {
try testEncoding(with: uint) { closure in
self.measure { closure() }
}
}

func testDecodeUInts() throws {
try testDecoding(with: uint) { closure in
self.measure { closure() }
}
}

func testEncodeFloats() throws {
try testEncoding(with: float) { closure in
self.measure { closure() }
}
}

func testDecodeFloats() throws {
try testDecoding(with: float) { closure in
self.measure { closure() }
}
}

func testEncodeDecimals() throws {
try testEncoding(with: decimal) { closure in
self.measure { closure() }
}
}

func testDecodeDecimals() throws {
try testDecoding(with: decimal) { closure in
self.measure { closure() }
}
}

func testEncodeDates() throws {
try testEncoding(with: date) { closure in
self.measure { closure() }
}
}

func testDecodeDates() throws {
try testDecoding(with: date) { closure in
self.measure { closure() }
}
}

func testEncodeDatas() throws {
try testEncoding(with: data) { closure in
self.measure { closure() }
}
}

func testDecodeDatas() throws {
try testDecoding(with: data) { closure in
self.measure { closure() }
}
}

func testEncodeURLs() throws {
try testEncoding(with: url) { closure in
self.measure { closure() }
}
}

func testDecodeURLs() throws {
try testDecoding(with: url) { closure in
self.measure { closure() }
}
}

func testEncodeArrays() throws {
try testEncoding(with: array) { closure in
self.measure { closure() }
}
}

func testDecodeArrays() throws {
try testDecoding(with: array) { closure in
self.measure { closure() }
}
}

func testEncodeDictionaries() throws {
try testEncoding(with: dictionary) { closure in
self.measure { closure() }
}
}

func testDecodeDictionaries() throws {
try testDecoding(with: dictionary) { closure in
self.measure { closure() }
}
}

static var allTests = [
("testEncodeNulls", testEncodeNulls),
("testDecodeNulls", testDecodeNulls),
("testEncodeBools", testEncodeBools),
("testDecodeBools", testDecodeBools),
("testEncodeInts", testEncodeInts),
("testDecodeInts", testDecodeInts),
("testEncodeUInts", testEncodeUInts),
("testDecodeUInts", testDecodeUInts),
("testEncodeFloats", testEncodeFloats),
("testDecodeFloats", testDecodeFloats),
("testEncodeDecimals", testEncodeDecimals),
("testDecodeDecimals", testDecodeDecimals),
("testEncodeArrays", testEncodeArrays),
("testDecodeArrays", testDecodeArrays),
("testEncodeDictionaries", testEncodeDictionaries),
("testDecodeDictionaries", testDecodeDictionaries),
]
}
4 changes: 4 additions & 0 deletions XMLCoder.xcodeproj/project.pbxproj
Expand Up @@ -29,6 +29,7 @@
BF63EF0821CD7AF8001D38C5 /* URLBoxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF63EF0721CD7AF8001D38C5 /* URLBoxTests.swift */; };
BF63EF0A21CD7C1A001D38C5 /* URLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF63EF0921CD7C1A001D38C5 /* URLTests.swift */; };
BF63EF0C21CD7F28001D38C5 /* EmptyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF63EF0B21CD7F28001D38C5 /* EmptyTests.swift */; };
BF63EF1E21CEC99B001D38C5 /* BenchmarkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF63EF1D21CEC99A001D38C5 /* BenchmarkTests.swift */; };
BF63EF6721D0F874001D38C5 /* XMLKeyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF63EF6621D0F874001D38C5 /* XMLKeyTests.swift */; };
BF63EF6921D0FDB5001D38C5 /* XMLHeaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF63EF6821D0FDB5001D38C5 /* XMLHeaderTests.swift */; };
BF63EF6B21D10284001D38C5 /* XMLElementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF63EF6A21D10284001D38C5 /* XMLElementTests.swift */; };
Expand Down Expand Up @@ -126,6 +127,7 @@
BF63EF0721CD7AF8001D38C5 /* URLBoxTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLBoxTests.swift; sourceTree = "<group>"; };
BF63EF0921CD7C1A001D38C5 /* URLTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLTests.swift; sourceTree = "<group>"; };
BF63EF0B21CD7F28001D38C5 /* EmptyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyTests.swift; sourceTree = "<group>"; };
BF63EF1D21CEC99A001D38C5 /* BenchmarkTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BenchmarkTests.swift; sourceTree = "<group>"; };
BF63EF6621D0F874001D38C5 /* XMLKeyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XMLKeyTests.swift; sourceTree = "<group>"; };
BF63EF6821D0FDB5001D38C5 /* XMLHeaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XMLHeaderTests.swift; sourceTree = "<group>"; };
BF63EF6A21D10284001D38C5 /* XMLElementTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XMLElementTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -342,6 +344,7 @@
OBJ_36 /* PlantTest.swift */,
OBJ_37 /* RJITest.swift */,
OBJ_38 /* RelationshipsTest.swift */,
BF63EF1D21CEC99A001D38C5 /* BenchmarkTests.swift */,
D1FC040421C7EF8200065B43 /* RJISample.swift */,
A61DCCD621DF8DB300C0A19D /* ClassTests.swift */,
);
Expand Down Expand Up @@ -551,6 +554,7 @@
OBJ_82 /* CDCatalog.swift in Sources */,
BF63EF0021CCDED2001D38C5 /* XMLStackParserTests.swift in Sources */,
BF9457CC21CBB516005ACFDE /* NullBoxTests.swift in Sources */,
BF63EF1E21CEC99B001D38C5 /* BenchmarkTests.swift in Sources */,
BF9457CF21CBB516005ACFDE /* IntBoxTests.swift in Sources */,
BF9457E021CBB68A005ACFDE /* DataBoxTests.swift in Sources */,
BF9457F521CBB6BC005ACFDE /* DecimalTests.swift in Sources */,
Expand Down