diff --git a/.gitignore b/.gitignore index 8699e46..ddd4ec5 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,6 @@ playground.xcworkspace # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. # Packages/ .build/ + +# Carthage +Carthage/ diff --git a/Cartfile b/Cartfile new file mode 100644 index 0000000..792b8e0 --- /dev/null +++ b/Cartfile @@ -0,0 +1 @@ +github "cherrywoods/swift-meta-serialization" ~> 1.0 diff --git a/Cartfile.resolved b/Cartfile.resolved new file mode 100644 index 0000000..af670da --- /dev/null +++ b/Cartfile.resolved @@ -0,0 +1 @@ +github "cherrywoods/swift-meta-serialization" "975b074891cf5db25402dbcab2c406fbc686e7e0" diff --git a/Codable Support/MessagePackValue+DirectlyCodable.swift b/Codable Support/MessagePackValue+DirectlyCodable.swift new file mode 100644 index 0000000..7a36b9c --- /dev/null +++ b/Codable Support/MessagePackValue+DirectlyCodable.swift @@ -0,0 +1,33 @@ +// +// MessagePackValue+DirectlyCodable.swift +// MessagePack +// +// Created by cherrywoods on 09.02.18. +// Licensed under Unlicense, https://unlicense.org +// + +import Foundation +import MetaSerialization + +// extend MessagePackValue +// so one can encode such values +// alongside with other instances, e.g: + +/* + func encode(to encoder: Encoder) { + ... + let extensionValue = MessagePackValue.extension(100, data) + let otherValue = Date() + ... + var container = encoder.unkeyedContainer() + container.encode(extensionValue) + container.encode(otherValue) + } + */ + +// with this both encoding/decoding methods, +// can be mixed arbitrarily. + +// the MessagePackValues just get passed on + +extension MessagePackValue: DirectlyCodable { } diff --git a/Codable Support/MessagePackValueSerialization.swift b/Codable Support/MessagePackValueSerialization.swift new file mode 100644 index 0000000..1482764 --- /dev/null +++ b/Codable Support/MessagePackValueSerialization.swift @@ -0,0 +1,37 @@ +// +// MessagePackValueSerialization.swift +// MessagePack +// +// Created by cherrywoods on 09.02.18. +// Licensed under Unlicense, https://unlicense.org +// + +import Foundation +import MetaSerialization + +public typealias CodableConverter = MessagePackValueSerialization + +/** + MessagePackValueSerialization (or just CodableConverted) encodes or decodes + Codable types from MessagePackValue instances. + + With it's help you may easily encode and decode more complex types implementing + Codable, including many Foundation types, as Array, Dictionary or Date. + + You may mix both ways of serialization. You could for example have a MessagePackValue property, + or encode a MessagePackValue to a container in your implementation of Encodable's encode(to:) method. + Both will be kept in the serialized MessagePackValue. + */ +public class MessagePackValueSerialization: Serialization { + + public typealias Raw = MessagePackValue + + public func provideNewEncoder() -> MetaEncoder { + return MetaEncoder(translator: MessagePackValueTranslator()) + } + + public func provideNewDecoder(raw: MessagePackValue) throws -> MetaDecoder { + return try MetaDecoder(translator: MessagePackValueTranslator(), raw: raw) + } + +} diff --git a/Codable Support/MessagePackValueTranslator.swift b/Codable Support/MessagePackValueTranslator.swift new file mode 100644 index 0000000..6b9aa0a --- /dev/null +++ b/Codable Support/MessagePackValueTranslator.swift @@ -0,0 +1,262 @@ +// +// MessagePackValueTranslator.swift +// MessagePack +// +// Created by cherrywoods on 09.02.18. +// Licensed under Unlicense, https://unlicense.org +// + +import Foundation +import MetaSerialization + +/** + Implements the Translator protocol from MetaSerialization + to convert from arbitrary codable types to MessagePackValue. + */ +internal struct MessagePackValueTranslator: Translator { + + // MARK: - meta tree stage + + // use default implementations for container methods + + internal func wrappingMeta(for value: T) -> Meta? { + + switch value { + + // support nil values + case is GenericNil: + return NilMeta.nil + + // these types need no conversion + // use SimpleGenericMeta for all these + case is String: fallthrough + case is Bool: fallthrough + case is Float: fallthrough + case is Double: fallthrough + case is Int64, is Int, is Int8, is Int16, is Int32 : fallthrough + case is UInt64, is UInt, is UInt8, is UInt16, is UInt32 : fallthrough + case is Data: fallthrough + // also MessagePackValues can be encoded + // they just get passed on + case is MessagePackValue: + return SimpleGenericMeta() + + // return nil for all other values + default: + return nil + } + + } + + internal func unwrap(meta: Meta, toType type: T.Type) throws -> T? { + + if let message = (meta as? SimpleGenericMeta)?.value { + + // nil values do not reach to this method + + switch type { + // directly convertible types + case is String.Type: + // need to throw an error, if type is string, but message not convertible + guard let value = message.stringValue else { throw TranslatorError.typeMismatch } + return (value as! T) + case is Bool.Type: + guard let value = message.boolValue else { throw TranslatorError.typeMismatch } + return (value as! T) + case is Float.Type: + guard let value = message.floatValue else { throw TranslatorError.typeMismatch } + return (value as! T) + case is Double.Type: + guard let value = message.doubleValue else { throw TranslatorError.typeMismatch } + return (value as! T) + case is Int64.Type: + guard let value = message.integerValue else { throw TranslatorError.typeMismatch } + return (value as! T) + case is UInt64.Type: + guard let value = message.unsignedIntegerValue else { throw TranslatorError.typeMismatch } + return (value as! T) + case is Data.Type: + guard let value = message.dataValue else { throw TranslatorError.typeMismatch } + return (value as! T) + case is MessagePackValue.Type: + return (message as! T) + // all further int types need conversion + case is Int.Type: + guard let int64 = message.integerValue else { throw TranslatorError.typeMismatch } + guard let value = Int(exactly: int64) else { throw TranslatorError.typeMismatch } + return (value as! T) + case is Int8.Type: + guard let int64 = message.integerValue else { throw TranslatorError.typeMismatch } + guard let value = Int8(exactly: int64) else { throw TranslatorError.typeMismatch } + return (value as! T) + case is Int16.Type: + guard let int64 = message.integerValue else { throw TranslatorError.typeMismatch } + guard let value = Int16(exactly: int64) else { throw TranslatorError.typeMismatch } + return (value as! T) + case is Int32.Type: + guard let int64 = message.integerValue else { throw TranslatorError.typeMismatch } + guard let value = Int32(exactly: int64) else { throw TranslatorError.typeMismatch } + return (value as! T) + case is UInt.Type: + guard let uint64 = message.unsignedIntegerValue else { throw TranslatorError.typeMismatch } + guard let value = UInt(exactly: uint64) else { throw TranslatorError.typeMismatch } + return (value as! T) + case is UInt8.Type: + guard let uint64 = message.unsignedIntegerValue else { throw TranslatorError.typeMismatch } + guard let value = UInt8(exactly: uint64) else { throw TranslatorError.typeMismatch } + return (value as! T) + case is UInt16.Type: + guard let uint64 = message.unsignedIntegerValue else { throw TranslatorError.typeMismatch } + guard let value = UInt16(exactly: uint64) else { throw TranslatorError.typeMismatch } + return (value as! T) + case is UInt32.Type: + guard let uint64 = message.unsignedIntegerValue else { throw TranslatorError.typeMismatch } + guard let value = UInt32(exactly: uint64) else { throw TranslatorError.typeMismatch } + return (value as! T) + + // return nil for all other types, they may still use e.g. a singleValueContainer + default: + return nil + } + + } else { + + // not a primitive meta + return nil + + } + + } + + // MARK: - conversion stage + + internal func encode(_ meta: Meta) throws -> Raw { + return encodeToMessagePackValue(meta) as! Raw + } + + private func encodeToMessagePackValue(_ meta: Meta) -> MessagePackValue { + + // nil + if meta is NilMeta { + return MessagePackValue.nil + + // other types + } else if let value = (meta as? SimpleGenericMeta)?.value { + return MessagePackValue.string(value) + } else if let value = (meta as? SimpleGenericMeta)?.value { + return MessagePackValue.bool(value) + } else if let value = (meta as? SimpleGenericMeta)?.value { + return MessagePackValue.float(value) + } else if let value = (meta as? SimpleGenericMeta)?.value { + return MessagePackValue.double(value) + } else if let value = (meta as? SimpleGenericMeta)?.value { + return MessagePackValue.int(value) + } else if let value = (meta as? SimpleGenericMeta)?.value { + return MessagePackValue.uint(value) + } else if let value = (meta as? SimpleGenericMeta)?.value { + return MessagePackValue.binary(value) + } else if let value = (meta as? SimpleGenericMeta)?.value { + // directly pass on value + return value + + // other ints + } else if let value = (meta as? SimpleGenericMeta)?.value { + return MessagePackValue(value) + } else if let value = (meta as? SimpleGenericMeta)?.value { + return MessagePackValue(value) + } else if let value = (meta as? SimpleGenericMeta)?.value { + return MessagePackValue(value) + } else if let value = (meta as? SimpleGenericMeta)?.value { + return MessagePackValue(value) + } else if let value = (meta as? SimpleGenericMeta)?.value { + return MessagePackValue(value) + } else if let value = (meta as? SimpleGenericMeta)?.value { + return MessagePackValue(value) + } else if let value = (meta as? SimpleGenericMeta)?.value { + return MessagePackValue(value) + } else if let value = (meta as? SimpleGenericMeta)?.value { + return MessagePackValue(value) + + // convert keyed and unkeyed containers + } else if let dictionary = (meta as? DictionaryKeyedContainerMeta)?.value { + + // convert keys to .string and encode values + let converted = dictionary.map { (MessagePackValue.string($0), encodeToMessagePackValue($1)) } + return MessagePackValue.map( Dictionary(uniqueKeysWithValues: converted) ) + + } else if let array = (meta as? ArrayUnkeyedContainerMeta)?.value { + + let converted = array.map( encodeToMessagePackValue ) + return MessagePackValue.array(converted) + + } else { + // we did not create other metas, + // so the call of this shows a bug + assertionFailure() + return MessagePackValue.nil + } + + } + + internal func decode(_ raw: Raw) throws -> Meta { + + let message = raw as! MessagePackValue + + // decode arrays and dictionarys + switch message { + + // if is .nil, need to return a NilMeta + case .nil: + return NilMeta.nil + + // convert arrays to ArrayUnkeyedContainerMetas + case .array(let value): + let unkeyed = ArrayUnkeyedContainerMeta() + // decode and append each element of value + try value.forEach { unkeyed.append(element: try decode($0)) } + return unkeyed + + // convert maps to DictionaryKeyedContainerMetas + case .map(let value): + let keyed = DictionaryKeyedContainerMeta() + // convert keys to string values and decode values + try value.forEach { (key, value) in keyed[try codingKeyStringValue(of: key)] = try decode(value) } + return keyed + + default: + + // if none of the above, + // do not decode at all. + // All the work here is done in unwrap + return SimpleGenericMeta(value: message) + + } + + } + + // converts strings, binarys and ints to string values + private func codingKeyStringValue(of message: MessagePackValue) throws -> String { + + // handle string and binary + if let stringValue = message.stringValue { + + return stringValue + + } else if let intValue = message.integerValue { + + return "\(intValue)" + + } else if let uintValue = message.unsignedIntegerValue { + + return "\(uintValue)" + + } else { + + let context = DecodingError.Context(codingPath: [], debugDescription: "Unsupported key type of map. Keys need to be .string, .binary, .int or .uint") + throw DecodingError.dataCorrupted(context) + + } + + } + +} diff --git a/MessagePack.xcodeproj/project.pbxproj b/MessagePack.xcodeproj/project.pbxproj index c8279a5..05cf3f4 100644 --- a/MessagePack.xcodeproj/project.pbxproj +++ b/MessagePack.xcodeproj/project.pbxproj @@ -7,6 +7,31 @@ objects = { /* Begin PBXBuildFile section */ + 63047BC4202E5418007F1576 /* MessagePackValueSerialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63047BC3202E5418007F1576 /* MessagePackValueSerialization.swift */; }; + 63047BC5202E5418007F1576 /* MessagePackValueSerialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63047BC3202E5418007F1576 /* MessagePackValueSerialization.swift */; }; + 63047BC6202E5418007F1576 /* MessagePackValueSerialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63047BC3202E5418007F1576 /* MessagePackValueSerialization.swift */; }; + 63047BC7202E5418007F1576 /* MessagePackValueSerialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63047BC3202E5418007F1576 /* MessagePackValueSerialization.swift */; }; + 63047BCD202E5768007F1576 /* CodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63047BC8202E5683007F1576 /* CodableTests.swift */; }; + 63047BCE202E5768007F1576 /* CodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63047BC8202E5683007F1576 /* CodableTests.swift */; }; + 63047BCF202E5768007F1576 /* CodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63047BC8202E5683007F1576 /* CodableTests.swift */; }; + 63047BD0202E5BFA007F1576 /* MetaSerialization.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 634F10FC202E284F00A17B97 /* MetaSerialization.framework */; }; + 63047BD1202E5BFF007F1576 /* MetaSerialization.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 634F10FE202E286400A17B97 /* MetaSerialization.framework */; }; + 63047BD3202E5C09007F1576 /* MetaSerialization.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 634F1102202E286F00A17B97 /* MetaSerialization.framework */; }; + 63047BDF202E60B2007F1576 /* MetaSerialization.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 634F10FE202E286400A17B97 /* MetaSerialization.framework */; }; + 634F10F6202E27DF00A17B97 /* MessagePackValueTranslator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 634F10F5202E27DF00A17B97 /* MessagePackValueTranslator.swift */; }; + 634F10F7202E27DF00A17B97 /* MessagePackValueTranslator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 634F10F5202E27DF00A17B97 /* MessagePackValueTranslator.swift */; }; + 634F10F8202E27DF00A17B97 /* MessagePackValueTranslator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 634F10F5202E27DF00A17B97 /* MessagePackValueTranslator.swift */; }; + 634F10F9202E27DF00A17B97 /* MessagePackValueTranslator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 634F10F5202E27DF00A17B97 /* MessagePackValueTranslator.swift */; }; + 634F1117202E2E7500A17B97 /* MessagePackValue+DirectlyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 634F1116202E2E7500A17B97 /* MessagePackValue+DirectlyCodable.swift */; }; + 634F1118202E2E7500A17B97 /* MessagePackValue+DirectlyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 634F1116202E2E7500A17B97 /* MessagePackValue+DirectlyCodable.swift */; }; + 634F1119202E2E7500A17B97 /* MessagePackValue+DirectlyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 634F1116202E2E7500A17B97 /* MessagePackValue+DirectlyCodable.swift */; }; + 634F111A202E2E7500A17B97 /* MessagePackValue+DirectlyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 634F1116202E2E7500A17B97 /* MessagePackValue+DirectlyCodable.swift */; }; + 63F07FC1202F018500EEE4B3 /* MetaSerialization.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 63F07FC0202F018500EEE4B3 /* MetaSerialization.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 63F07FC2202F01A300EEE4B3 /* MetaSerialization.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 634F10FC202E284F00A17B97 /* MetaSerialization.framework */; }; + 63F07FC5202F01BC00EEE4B3 /* MetaSerialization.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 63F07FC4202F01BC00EEE4B3 /* MetaSerialization.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 63F07FC8202F01E800EEE4B3 /* MetaSerialization.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 63F07FC7202F01E700EEE4B3 /* MetaSerialization.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 63F07FC9202F031700EEE4B3 /* MetaSerialization.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63F07FC7202F01E700EEE4B3 /* MetaSerialization.framework */; }; + 63F07FCB202F037F00EEE4B3 /* MetaSerialization.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63F07FC7202F01E700EEE4B3 /* MetaSerialization.framework */; }; 825321871EFFC9C500914B55 /* MessagePack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8253217D1EFFC9C400914B55 /* MessagePack.framework */; }; 8253219E1EFFCA0D00914B55 /* ConvenienceInitializers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825321971EFFCA0D00914B55 /* ConvenienceInitializers.swift */; }; 8253219F1EFFCA0D00914B55 /* ConvenienceProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825321981EFFCA0D00914B55 /* ConvenienceProperties.swift */; }; @@ -119,7 +144,60 @@ }; /* End PBXContainerItemProxy section */ +/* Begin PBXCopyFilesBuildPhase section */ + 63047BD7202E6030007F1576 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 63F07FC1202F018500EEE4B3 /* MetaSerialization.framework in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 634F1105202E28BB00A17B97 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 63F07FC3202F01B300EEE4B3 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 63F07FC5202F01BC00EEE4B3 /* MetaSerialization.framework in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 63F07FC6202F01D700EEE4B3 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 63F07FC8202F01E800EEE4B3 /* MetaSerialization.framework in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ + 63047BC3202E5418007F1576 /* MessagePackValueSerialization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagePackValueSerialization.swift; sourceTree = ""; }; + 63047BC8202E5683007F1576 /* CodableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableTests.swift; sourceTree = ""; }; + 634F10F5202E27DF00A17B97 /* MessagePackValueTranslator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagePackValueTranslator.swift; sourceTree = ""; }; + 634F10FC202E284F00A17B97 /* MetaSerialization.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetaSerialization.framework; path = Carthage/Build/iOS/MetaSerialization.framework; sourceTree = ""; }; + 634F10FE202E286400A17B97 /* MetaSerialization.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetaSerialization.framework; path = Carthage/Build/Mac/MetaSerialization.framework; sourceTree = ""; }; + 634F1100202E286A00A17B97 /* MetaSerialization.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetaSerialization.framework; path = Carthage/Build/tvOS/MetaSerialization.framework; sourceTree = ""; }; + 634F1102202E286F00A17B97 /* MetaSerialization.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetaSerialization.framework; path = Carthage/Build/watchOS/MetaSerialization.framework; sourceTree = ""; }; + 634F1116202E2E7500A17B97 /* MessagePackValue+DirectlyCodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessagePackValue+DirectlyCodable.swift"; sourceTree = ""; }; + 63F07FC0202F018500EEE4B3 /* MetaSerialization.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetaSerialization.framework; path = Carthage/Build/Mac/MetaSerialization.framework; sourceTree = ""; }; + 63F07FC4202F01BC00EEE4B3 /* MetaSerialization.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetaSerialization.framework; path = Carthage/Build/iOS/MetaSerialization.framework; sourceTree = ""; }; + 63F07FC7202F01E700EEE4B3 /* MetaSerialization.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetaSerialization.framework; path = Carthage/Build/tvOS/MetaSerialization.framework; sourceTree = ""; }; 8253217D1EFFC9C400914B55 /* MessagePack.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MessagePack.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 825321861EFFC9C500914B55 /* MessagePackTests-iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "MessagePackTests-iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 825321971EFFCA0D00914B55 /* ConvenienceInitializers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ConvenienceInitializers.swift; path = Sources/MessagePack/ConvenienceInitializers.swift; sourceTree = SOURCE_ROOT; }; @@ -162,6 +240,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 63047BD0202E5BFA007F1576 /* MetaSerialization.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -170,6 +249,7 @@ buildActionMask = 2147483647; files = ( 825321871EFFC9C500914B55 /* MessagePack.framework in Frameworks */, + 63F07FC2202F01A300EEE4B3 /* MetaSerialization.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -177,6 +257,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 63047BD3202E5C09007F1576 /* MetaSerialization.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -184,6 +265,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 63F07FCB202F037F00EEE4B3 /* MetaSerialization.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -192,6 +274,7 @@ buildActionMask = 2147483647; files = ( 825321E91EFFCAFA00914B55 /* MessagePack.framework in Frameworks */, + 63F07FC9202F031700EEE4B3 /* MetaSerialization.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -199,6 +282,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 63047BD1202E5BFF007F1576 /* MetaSerialization.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -207,19 +291,46 @@ buildActionMask = 2147483647; files = ( 825322051EFFCB2B00914B55 /* MessagePack.framework in Frameworks */, + 63047BDF202E60B2007F1576 /* MetaSerialization.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 634F10F4202E278900A17B97 /* Codable Support */ = { + isa = PBXGroup; + children = ( + 634F10F5202E27DF00A17B97 /* MessagePackValueTranslator.swift */, + 63047BC3202E5418007F1576 /* MessagePackValueSerialization.swift */, + 634F1116202E2E7500A17B97 /* MessagePackValue+DirectlyCodable.swift */, + ); + path = "Codable Support"; + sourceTree = ""; + }; + 634F10FB202E284F00A17B97 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 634F1102202E286F00A17B97 /* MetaSerialization.framework */, + 634F1100202E286A00A17B97 /* MetaSerialization.framework */, + 634F10FE202E286400A17B97 /* MetaSerialization.framework */, + 634F10FC202E284F00A17B97 /* MetaSerialization.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; 825321731EFFC9C400914B55 = { isa = PBXGroup; children = ( + 63F07FC0202F018500EEE4B3 /* MetaSerialization.framework */, + 63F07FC4202F01BC00EEE4B3 /* MetaSerialization.framework */, + 63F07FC7202F01E700EEE4B3 /* MetaSerialization.framework */, + 634F10F4202E278900A17B97 /* Codable Support */, 8253217F1EFFC9C400914B55 /* MessagePack */, 8253218A1EFFC9C500914B55 /* MessagePackTests */, 825321C91EFFCA2800914B55 /* Resources */, 8253217E1EFFC9C400914B55 /* Products */, + 634F10FB202E284F00A17B97 /* Frameworks */, ); sourceTree = ""; }; @@ -273,6 +384,7 @@ 825321B41EFFCA1C00914B55 /* StringTests.swift */, 825321B51EFFCA1C00914B55 /* SubdataTests.swift */, 825321B61EFFCA1C00914B55 /* TrueTests.swift */, + 63047BC8202E5683007F1576 /* CodableTests.swift */, ); name = MessagePackTests; path = Tests/MessagePackTests; @@ -331,6 +443,7 @@ 825321791EFFC9C400914B55 /* Frameworks */, 8253217A1EFFC9C400914B55 /* Headers */, 8253217B1EFFC9C400914B55 /* Resources */, + 634F1108202E28EB00A17B97 /* ShellScript */, ); buildRules = ( ); @@ -348,6 +461,7 @@ 825321821EFFC9C500914B55 /* Sources */, 825321831EFFC9C500914B55 /* Frameworks */, 825321841EFFC9C500914B55 /* Resources */, + 63F07FC3202F01B300EEE4B3 /* CopyFiles */, ); buildRules = ( ); @@ -367,6 +481,7 @@ 825321CF1EFFCAED00914B55 /* Frameworks */, 825321D01EFFCAED00914B55 /* Headers */, 825321D11EFFCAED00914B55 /* Resources */, + 634F110A202E295000A17B97 /* ShellScript */, ); buildRules = ( ); @@ -385,6 +500,7 @@ 825321DC1EFFCAF900914B55 /* Frameworks */, 825321DD1EFFCAF900914B55 /* Headers */, 825321DE1EFFCAF900914B55 /* Resources */, + 634F1109202E294200A17B97 /* ShellScript */, ); buildRules = ( ); @@ -402,6 +518,7 @@ 825321E41EFFCAFA00914B55 /* Sources */, 825321E51EFFCAFA00914B55 /* Frameworks */, 825321E61EFFCAFA00914B55 /* Resources */, + 63F07FC6202F01D700EEE4B3 /* CopyFiles */, ); buildRules = ( ); @@ -421,6 +538,7 @@ 825321F81EFFCB2A00914B55 /* Frameworks */, 825321F91EFFCB2A00914B55 /* Headers */, 825321FA1EFFCB2A00914B55 /* Resources */, + 634F1105202E28BB00A17B97 /* CopyFiles */, ); buildRules = ( ); @@ -438,6 +556,7 @@ 825322001EFFCB2B00914B55 /* Sources */, 825322011EFFCB2B00914B55 /* Frameworks */, 825322021EFFCB2B00914B55 /* Resources */, + 63047BD7202E6030007F1576 /* CopyFiles */, ); buildRules = ( ); @@ -566,18 +685,69 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 634F1108202E28EB00A17B97 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/Carthage/Build/iOS/MetaSerialization.framework", + ); + outputPaths = ( + "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/MetaSerialization.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/usr/local/bin/carthage copy-frameworks"; + }; + 634F1109202E294200A17B97 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/Carthage/Build/tvOS/MetaSerialization.framework", + ); + outputPaths = ( + "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/MetaSerialization.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/usr/local/bin/carthage copy-frameworks"; + }; + 634F110A202E295000A17B97 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/Carthage/Build/watchOS/MetaSerialization.framework", + ); + outputPaths = ( + "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/MetaSerialization.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/usr/local/bin/carthage copy-frameworks"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 825321781EFFC9C400914B55 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 825321A41EFFCA0D00914B55 /* Unpack.swift in Sources */, + 634F1117202E2E7500A17B97 /* MessagePackValue+DirectlyCodable.swift in Sources */, 825321A31EFFCA0D00914B55 /* Subdata.swift in Sources */, 825321A11EFFCA0D00914B55 /* MessagePack.swift in Sources */, 825321A01EFFCA0D00914B55 /* LiteralConvertibles.swift in Sources */, + 634F10F6202E27DF00A17B97 /* MessagePackValueTranslator.swift in Sources */, 8253219F1EFFCA0D00914B55 /* ConvenienceProperties.swift in Sources */, 8253219E1EFFCA0D00914B55 /* ConvenienceInitializers.swift in Sources */, 825321A21EFFCA0D00914B55 /* Pack.swift in Sources */, + 63047BC4202E5418007F1576 /* MessagePackValueSerialization.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -591,6 +761,7 @@ 825321BB1EFFCA1C00914B55 /* DescriptionTests.swift in Sources */, 825321B91EFFCA1C00914B55 /* ConvenienceInitializersTests.swift in Sources */, 825321BF1EFFCA1C00914B55 /* ExtendedTests.swift in Sources */, + 63047BCD202E5768007F1576 /* CodableTests.swift in Sources */, 825321C61EFFCA1C00914B55 /* StringTests.swift in Sources */, 825321BC1EFFCA1C00914B55 /* DoubleTests.swift in Sources */, 825321C81EFFCA1C00914B55 /* TrueTests.swift in Sources */, @@ -611,12 +782,15 @@ buildActionMask = 2147483647; files = ( 8253224B1EFFCBC700914B55 /* Unpack.swift in Sources */, + 634F111A202E2E7500A17B97 /* MessagePackValue+DirectlyCodable.swift in Sources */, 8253224A1EFFCBC700914B55 /* Subdata.swift in Sources */, 825322481EFFCBC700914B55 /* MessagePack.swift in Sources */, 825322471EFFCBC700914B55 /* LiteralConvertibles.swift in Sources */, + 634F10F9202E27DF00A17B97 /* MessagePackValueTranslator.swift in Sources */, 825322461EFFCBC700914B55 /* ConvenienceProperties.swift in Sources */, 825322451EFFCBC700914B55 /* ConvenienceInitializers.swift in Sources */, 825322491EFFCBC700914B55 /* Pack.swift in Sources */, + 63047BC7202E5418007F1576 /* MessagePackValueSerialization.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -625,12 +799,15 @@ buildActionMask = 2147483647; files = ( 825322441EFFCBC700914B55 /* Unpack.swift in Sources */, + 634F1119202E2E7500A17B97 /* MessagePackValue+DirectlyCodable.swift in Sources */, 825322431EFFCBC700914B55 /* Subdata.swift in Sources */, 825322411EFFCBC700914B55 /* MessagePack.swift in Sources */, 825322401EFFCBC700914B55 /* LiteralConvertibles.swift in Sources */, + 634F10F8202E27DF00A17B97 /* MessagePackValueTranslator.swift in Sources */, 8253223F1EFFCBC700914B55 /* ConvenienceProperties.swift in Sources */, 8253223E1EFFCBC700914B55 /* ConvenienceInitializers.swift in Sources */, 825322421EFFCBC700914B55 /* Pack.swift in Sources */, + 63047BC6202E5418007F1576 /* MessagePackValueSerialization.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -644,6 +821,7 @@ 825322361EFFCBC400914B55 /* TrueTests.swift in Sources */, 8253222D1EFFCBC400914B55 /* ExtendedTests.swift in Sources */, 825322321EFFCBC400914B55 /* MapTests.swift in Sources */, + 63047BCF202E5768007F1576 /* CodableTests.swift in Sources */, 8253222B1EFFCBC400914B55 /* EqualityTests.swift in Sources */, 825322341EFFCBC400914B55 /* StringTests.swift in Sources */, 825322311EFFCBC400914B55 /* IntegerTests.swift in Sources */, @@ -664,12 +842,15 @@ buildActionMask = 2147483647; files = ( 8253223D1EFFCBC700914B55 /* Unpack.swift in Sources */, + 634F1118202E2E7500A17B97 /* MessagePackValue+DirectlyCodable.swift in Sources */, 8253223C1EFFCBC700914B55 /* Subdata.swift in Sources */, 8253223A1EFFCBC700914B55 /* MessagePack.swift in Sources */, 825322391EFFCBC700914B55 /* LiteralConvertibles.swift in Sources */, + 634F10F7202E27DF00A17B97 /* MessagePackValueTranslator.swift in Sources */, 825322381EFFCBC700914B55 /* ConvenienceProperties.swift in Sources */, 825322371EFFCBC700914B55 /* ConvenienceInitializers.swift in Sources */, 8253223B1EFFCBC700914B55 /* Pack.swift in Sources */, + 63047BC5202E5418007F1576 /* MessagePackValueSerialization.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -683,6 +864,7 @@ 825322241EFFCBC400914B55 /* TrueTests.swift in Sources */, 8253221B1EFFCBC400914B55 /* ExtendedTests.swift in Sources */, 825322201EFFCBC400914B55 /* MapTests.swift in Sources */, + 63047BCE202E5768007F1576 /* CodableTests.swift in Sources */, 825322191EFFCBC400914B55 /* EqualityTests.swift in Sources */, 825322221EFFCBC400914B55 /* StringTests.swift in Sources */, 8253221F1EFFCBC400914B55 /* IntegerTests.swift in Sources */, @@ -847,6 +1029,10 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); INFOPLIST_FILE = "$(SRCROOT)/Resources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -867,6 +1053,10 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); INFOPLIST_FILE = "$(SRCROOT)/Resources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -881,6 +1071,10 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); INFOPLIST_FILE = "Resources/Tests-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = us.pandamonia.MessagePackTests; @@ -893,6 +1087,10 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); INFOPLIST_FILE = "Resources/Tests-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = us.pandamonia.MessagePackTests; @@ -910,6 +1108,10 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/watchOS", + ); INFOPLIST_FILE = "$(SRCROOT)/Resources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -931,6 +1133,10 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/watchOS", + ); INFOPLIST_FILE = "$(SRCROOT)/Resources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -951,6 +1157,10 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/tvOS", + ); INFOPLIST_FILE = "$(SRCROOT)/Resources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -971,6 +1181,10 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/tvOS", + ); INFOPLIST_FILE = "$(SRCROOT)/Resources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -987,6 +1201,10 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/tvOS", + ); INFOPLIST_FILE = "Resources/Tests-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = us.pandamonia.MessagePackTests; @@ -1001,6 +1219,10 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/tvOS", + ); INFOPLIST_FILE = "Resources/Tests-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = us.pandamonia.MessagePackTests; @@ -1020,6 +1242,10 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/Mac", + ); FRAMEWORK_VERSION = A; INFOPLIST_FILE = "$(SRCROOT)/Resources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1042,6 +1268,10 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/Mac", + ); FRAMEWORK_VERSION = A; INFOPLIST_FILE = "$(SRCROOT)/Resources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1061,6 +1291,10 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/Mac", + ); INFOPLIST_FILE = "Resources/Tests-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.12; @@ -1077,6 +1311,10 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/Mac", + ); INFOPLIST_FILE = "Resources/Tests-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.12; diff --git a/Tests/MessagePackTests/CodableTests.swift b/Tests/MessagePackTests/CodableTests.swift new file mode 100644 index 0000000..62c5cac --- /dev/null +++ b/Tests/MessagePackTests/CodableTests.swift @@ -0,0 +1,139 @@ +import Foundation +import XCTest +@testable import MessagePack + +class CodableTests: XCTestCase { + static var allTests = { + return [ + ("testDirectlyConverting", testDirectlyConverting), + ("testComplex", testComplex) + ] + }() + + func testDirectlyConverting() { + + let mars = Planet.mars + let expected = MessagePackValue.string("mars") + + roundWayConvert(value: mars, expected: expected) + + } + + func testNonstrictNumberConversion() { + + // this test shows, that a loosy converion of Double values + // is done implicitly. + // A small change in ConvenienceProperties changes this. + + /* + // this float value is not convertible to Float + let floatValue = Float(exactly: 3.565761343565446) + */ + + let testValue = MessagePackValue.map([.string("brightness"): .double(3.565761343565446), + .string("diameter"): .float(31.5), + .string("mass"): .float(3.846e26), + .string("name"): .string("fictional sun")]) + + let sun = try? CodableConverter().decode(toType: Sun.self, from: testValue) + XCTAssert(sun != nil, "Number conversion didn't succeed") + + } + + func testComplex() { + + let sunsystem = Sunsystem(name: "the sun system", + sun: Sun(brightness: 1.0, diameter: 31.5, mass: 3.846e26, name: "the sun"), + planets: .mercur, .venus, .earth, .mars, .jupiter, .saturn, .uranus, .neptun) + + let expected = MessagePackValue.map([.string("name"): .string("the sun system"), + .string("sun"): .map([.string("brightness"): .float(1.0), + .string("diameter"): .float(31.5), + .string("mass"): .float(3.846e26), + .string("name"): .string("the sun")]), + .string("planets"): .array([.string("mercur"), .string("venus"), + .string("earth"), .string("mars"), + .string("jupiter"), .string("saturn"), + .string("uranus"), .string("neptun")]) + ]) + + roundWayConvert(value: sunsystem, expected: expected) + + } + + fileprivate func roundWayConvert(value: T, expected: MessagePackValue) where T: Codable, T: Equatable { + + let converted = try? CodableConverter().encode(value) + + guard converted != nil else { + XCTFail("Converting value (\(value)) failed") + return + } + + XCTAssert(expected == converted!, "Converted value (\(converted!)) and expected value (\(expected)) didn't match.") + + let unconverted = try? CodableConverter().decode(toType: T.self, from: converted!) + + guard converted != nil else { + XCTFail("Unconverting value (\(value)) failed") + return + } + + XCTAssert(value == unconverted!, "Unconverted value (\(unconverted!)) and expected value (\(value)) didn't match.") + + } + + // MARK: - tests structs and enums + + enum Planet: String, Codable { + case mercur + case venus + case earth + case mars + case jupiter + case saturn + case uranus + case neptun + } + + struct Sun: Codable, Equatable { + + let brightness: Float + let diameter: Float + let mass: Float + + let name: String + + init(brightness: Float, diameter: Float, mass: Float, name: String) { + self.brightness = brightness + self.diameter = diameter + self.mass = mass + self.name = name + } + + static func ==(lhs: CodableTests.Sun, rhs: CodableTests.Sun) -> Bool { + return lhs.brightness == rhs.brightness && lhs.diameter == rhs.diameter && lhs.mass == rhs.mass && lhs.name == rhs.name + } + + } + + struct Sunsystem: Codable, Equatable { + + let name: String + let sun: Sun + let planets: [Planet] + + init(name: String, sun: Sun, planets: Planet...) { + self.name = name + self.sun = sun + self.planets = planets + } + + static func ==(lhs: CodableTests.Sunsystem, rhs: CodableTests.Sunsystem) -> Bool { + return lhs.name == rhs.name && lhs.sun == rhs.sun && lhs.planets == rhs.planets + } + + } + +} +