Add SwiftLint

This commit is contained in:
woxtu 2018-07-07 16:01:08 +09:00
parent 7e8d9c64e7
commit 637b91471d
17 changed files with 106 additions and 55 deletions

12
.swiftlint.yml Normal file
View File

@ -0,0 +1,12 @@
disabled_rules:
- force_try
- identifier_name
- trailing_whitespace
line_length: 300
nesting:
type_level: 3
trailing_comma:
mandatory_comma: true

View File

@ -8,22 +8,22 @@ Type-safe URL routing for Swift.
```swift ```swift
// Define routes // Define routes
struct UserIndex : Route { struct UserIndex: Route {
let path = "/users" let path = "/users"
func map(to url: URL, parameters: [String : String], queries: [String : String]) -> UIViewController { func map(to url: URL, parameters: [String: String], queries: [String: String]) -> UIViewController {
return UserIndexViewController() return UserIndexViewController()
} }
} }
struct UserDetail : Route { struct UserDetail: Route {
let path = "/users/{id}" let path = "/users/{id}"
struct Parameters : Decodable { struct Parameters: Decodable {
let id: Int let id: Int
} }
func map(to url: URL, parameters: Parameters, queries: [String : String]) -> UIViewController { func map(to url: URL, parameters: Parameters, queries: [String: String]) -> UIViewController {
return UserDetailViewController(id: parameters.id) return UserDetailViewController(id: parameters.id)
} }
} }

View File

@ -219,6 +219,7 @@
430EC1DD20598F7600F84EA2 /* Frameworks */, 430EC1DD20598F7600F84EA2 /* Frameworks */,
430EC1DE20598F7600F84EA2 /* Headers */, 430EC1DE20598F7600F84EA2 /* Headers */,
430EC1DF20598F7600F84EA2 /* Resources */, 430EC1DF20598F7600F84EA2 /* Resources */,
437785B820EBDD810067EC31 /* ShellScript */,
); );
buildRules = ( buildRules = (
); );
@ -255,6 +256,7 @@
430EC2062059919F00F84EA2 /* Frameworks */, 430EC2062059919F00F84EA2 /* Frameworks */,
430EC2072059919F00F84EA2 /* Headers */, 430EC2072059919F00F84EA2 /* Headers */,
430EC2082059919F00F84EA2 /* Resources */, 430EC2082059919F00F84EA2 /* Resources */,
437785B920EBDD8D0067EC31 /* ShellScript */,
); );
buildRules = ( buildRules = (
); );
@ -290,7 +292,7 @@
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastSwiftUpdateCheck = 0920; LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 0920; LastUpgradeCheck = 0940;
ORGANIZATIONNAME = woxtu; ORGANIZATIONNAME = woxtu;
TargetAttributes = { TargetAttributes = {
430EC1E020598F7600F84EA2 = { 430EC1E020598F7600F84EA2 = {
@ -362,6 +364,35 @@
}; };
/* End PBXResourcesBuildPhase section */ /* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
437785B820EBDD810067EC31 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
};
437785B920EBDD8D0067EC31 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
430EC1DC20598F7600F84EA2 /* Sources */ = { 430EC1DC20598F7600F84EA2 /* Sources */ = {
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
@ -599,6 +630,7 @@
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES; CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
@ -606,6 +638,7 @@
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
@ -659,6 +692,7 @@
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES; CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
@ -666,6 +700,7 @@
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0920" LastUpgradeVersion = "0940"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
<TestableReference <TestableReference
@ -56,7 +55,6 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0920" LastUpgradeVersion = "0940"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
<TestableReference <TestableReference
@ -56,7 +55,6 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"

View File

@ -10,9 +10,9 @@ import Foundation
struct AnyRoute<T> { struct AnyRoute<T> {
let pattern: Pattern let pattern: Pattern
let map: (URL, [String : String], [String : String]) -> T? let map: (URL, [String: String], [String: String]) -> T?
init<R>(_ route: R) where R : Route, R.Response == T { init<R>(_ route: R) where R: Route, R.Response == T {
self.pattern = Pattern(string: route.path) self.pattern = Pattern(string: route.path)
self.map = { url, parameters, queries in self.map = { url, parameters, queries in

View File

@ -10,6 +10,6 @@ import Foundation
extension NSRegularExpression { extension NSRegularExpression {
func stringByReplacingMatches(in string: String, options: NSRegularExpression.MatchingOptions = [], withTemplate templ: String) -> String { func stringByReplacingMatches(in string: String, options: NSRegularExpression.MatchingOptions = [], withTemplate templ: String) -> String {
return self.stringByReplacingMatches(in: string, options: options, range: NSMakeRange(0, string.count), withTemplate: templ) return self.stringByReplacingMatches(in: string, options: options, range: NSRange(location: 0, length: string.count), withTemplate: templ)
} }
} }

View File

@ -17,7 +17,7 @@ open class Navigator {
return UIApplication.shared.keyWindow?.rootViewController return UIApplication.shared.keyWindow?.rootViewController
} }
open static func append<R>(route: R) where R : Route, R.Response == UIViewController { open static func append<R>(route: R) where R: Route, R.Response == UIViewController {
self.router.append(route: route) self.router.append(route: route)
} }

View File

@ -39,8 +39,8 @@ struct Pattern {
.map(Component.init) .map(Component.init)
} }
func match(url: URL) -> [String : String]? { func match(url: URL) -> [String: String]? {
let pathComponents = [url.host].flatMap { $0 } + url.pathComponents.dropFirst() // drop "/" let pathComponents = [url.host].compactMap { $0 } + url.pathComponents.dropFirst() // drop "/"
if self.scheme == url.scheme && self.pathComponents == pathComponents.map(Component.init) { if self.scheme == url.scheme && self.pathComponents == pathComponents.map(Component.init) {
return zip(self.pathComponents, pathComponents).reduce(into: [:]) { result, component in return zip(self.pathComponents, pathComponents).reduce(into: [:]) { result, component in
@ -54,8 +54,8 @@ struct Pattern {
} }
} }
extension Pattern.Component : Equatable { extension Pattern.Component: Equatable {
static func ==(lhs: Pattern.Component, rhs: Pattern.Component) -> Bool { static func == (lhs: Pattern.Component, rhs: Pattern.Component) -> Bool {
switch (lhs, rhs) { switch (lhs, rhs) {
case let (.constant(lhs), .constant(rhs)): return lhs == rhs case let (.constant(lhs), .constant(rhs)): return lhs == rhs
case let (.variable(lhs), .variable(rhs)): return lhs == rhs case let (.variable(lhs), .variable(rhs)): return lhs == rhs

View File

@ -9,20 +9,20 @@
import Foundation import Foundation
class PayloadDecoder { class PayloadDecoder {
func decode<T>(_ type: T.Type = T.self, from data: [String : String]) throws -> T where T : Decodable { func decode<T>(_ type: T.Type = T.self, from data: [String: String]) throws -> T where T: Decodable {
return try T(from: InnerDecoder(data: data)) return try T(from: InnerDecoder(data: data))
} }
class InnerDecoder : Decoder { class InnerDecoder: Decoder {
let data: [String : String] let data: [String: String]
var codingPath = [CodingKey]() var codingPath = [CodingKey]()
let userInfo = [CodingUserInfoKey : Any]() let userInfo = [CodingUserInfoKey: Any]()
init(data: [String : String]) { init(data: [String: String]) {
self.data = data self.data = data
} }
func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key : CodingKey { func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key: CodingKey {
return KeyedDecodingContainer(InnerKeyedDecodingContainer(referencing: self)) return KeyedDecodingContainer(InnerKeyedDecodingContainer(referencing: self))
} }
@ -35,7 +35,7 @@ class PayloadDecoder {
} }
} }
class InnerKeyedDecodingContainer<Key> : KeyedDecodingContainerProtocol where Key : CodingKey { class InnerKeyedDecodingContainer<Key>: KeyedDecodingContainerProtocol where Key: CodingKey {
let decoder: InnerDecoder let decoder: InnerDecoder
var codingPath: [CodingKey] { var codingPath: [CodingKey] {
@ -43,7 +43,7 @@ class PayloadDecoder {
} }
var allKeys: [Key] { var allKeys: [Key] {
return self.decoder.data.keys.flatMap(Key.init) return self.decoder.data.keys.compactMap(Key.init)
} }
init(referencing decoder: InnerDecoder) { init(referencing decoder: InnerDecoder) {
@ -58,7 +58,7 @@ class PayloadDecoder {
return self.decoder.data[key.stringValue] == nil return self.decoder.data[key.stringValue] == nil
} }
func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T : Decodable & LosslessStringConvertible { func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T: Decodable & LosslessStringConvertible {
guard let rawValue = self.decoder.data[key.stringValue] else { guard let rawValue = self.decoder.data[key.stringValue] else {
throw DecodingError.valueNotFound(type, .init(codingPath: self.codingPath, debugDescription: "No value associated with key '\(key)'.")) throw DecodingError.valueNotFound(type, .init(codingPath: self.codingPath, debugDescription: "No value associated with key '\(key)'."))
} }
@ -70,13 +70,13 @@ class PayloadDecoder {
return value return value
} }
func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T : Decodable { func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T: Decodable {
self.decoder.codingPath.append(key) self.decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() } defer { self.decoder.codingPath.removeLast() }
return try T(from: self.decoder) return try T(from: self.decoder)
} }
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> where NestedKey : CodingKey { func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> where NestedKey: CodingKey {
fatalError("It should not be called") fatalError("It should not be called")
} }
@ -93,7 +93,7 @@ class PayloadDecoder {
} }
} }
class InnerSingleValueDecodingContainer : SingleValueDecodingContainer { class InnerSingleValueDecodingContainer: SingleValueDecodingContainer {
let decoder: InnerDecoder let decoder: InnerDecoder
var codingPath: [CodingKey] { var codingPath: [CodingKey] {
@ -112,7 +112,7 @@ class PayloadDecoder {
} }
} }
func decode<T>(_ type: T.Type) throws -> T where T : Decodable & LosslessStringConvertible { func decode<T>(_ type: T.Type) throws -> T where T: Decodable & LosslessStringConvertible {
guard let key = self.codingPath.last else { guard let key = self.codingPath.last else {
fatalError("It should not be called") fatalError("It should not be called")
} }
@ -128,7 +128,7 @@ class PayloadDecoder {
return value return value
} }
func decode<T>(_ type: T.Type) throws -> T where T : Decodable { func decode<T>(_ type: T.Type) throws -> T where T: Decodable {
return try T(from: self.decoder) return try T(from: self.decoder)
} }
} }

View File

@ -10,10 +10,10 @@ import Foundation
public protocol Route { public protocol Route {
associatedtype Response associatedtype Response
associatedtype Parameters : Decodable = [String : String] associatedtype Parameters: Decodable = [String: String]
associatedtype Queries : Decodable = [String : String] associatedtype Queries: Decodable = [String: String]
var path: String { get } var path: String { get }
func map(to url: URL, parameters: Parameters, queries: Queries) -> Response func map(to url: URL, parameters: Parameters, queries: Queries) -> Response
} }

View File

@ -15,7 +15,7 @@ open class Router<T> {
} }
open func append<R>(route: R) where R : Route, R.Response == T { open func append<R>(route: R) where R: Route, R.Response == T {
self.routes.append(AnyRoute(route)) self.routes.append(AnyRoute(route))
} }

View File

@ -20,13 +20,13 @@ class AnyRouteTests: XCTestCase {
struct TestRoute: Route { struct TestRoute: Route {
let path = "/" let path = "/"
func map(to url: URL, parameters: [String : String], queries: [String : String]) -> TestResponse { func map(to url: URL, parameters: [String: String], queries: [String: String]) -> TestResponse {
return TestResponse(x1: parameters["x", default: ""], x2: queries["x", default: ""]) return TestResponse(x1: parameters["x", default: ""], x2: queries["x", default: ""])
} }
} }
let route = AnyRoute<TestResponse>(TestRoute()) let route = AnyRoute<TestResponse>(TestRoute())
let response = route.map(URL(string: "/")!, ["x" : "foo"], ["x" : "bar"]) let response = route.map(URL(string: "/")!, ["x": "foo"], ["x": "bar"])
XCTAssertEqual(response?.x1, "foo") XCTAssertEqual(response?.x1, "foo")
XCTAssertEqual(response?.x2, "bar") XCTAssertEqual(response?.x2, "bar")
} }
@ -54,7 +54,7 @@ class AnyRouteTests: XCTestCase {
} }
let route = AnyRoute<TestResponse>(TestRoute()) let route = AnyRoute<TestResponse>(TestRoute())
let response = route.map(URL(string: "/")!, ["x" : "foo"], ["x" : "bar"]) let response = route.map(URL(string: "/")!, ["x": "foo"], ["x": "bar"])
XCTAssertEqual(response?.x1, "foo") XCTAssertEqual(response?.x1, "foo")
XCTAssertEqual(response?.x2, "bar") XCTAssertEqual(response?.x2, "bar")
} }

View File

@ -24,6 +24,6 @@ class PatternTests: XCTestCase {
func testPatternMatch() { func testPatternMatch() {
XCTAssertNil(Pattern(string: "/x1/{x2}").match(url: URL(string: "/")!)) XCTAssertNil(Pattern(string: "/x1/{x2}").match(url: URL(string: "/")!))
XCTAssertEqual(Pattern(string: "/x1/{x2}").match(url: URL(string: "/x1/x2")!)!, ["x2" : "x2"]) XCTAssertEqual(Pattern(string: "/x1/{x2}").match(url: URL(string: "/x1/x2")!)!, ["x2": "x2"])
} }
} }

View File

@ -11,45 +11,45 @@ import XCTest
class PayloadDecoderTests: XCTestCase { class PayloadDecoderTests: XCTestCase {
func testDecodeString() { func testDecodeString() {
struct TestStruct : Decodable { struct TestStruct: Decodable {
let x: String let x: String
} }
let payload = ["x" : "x"] let payload = ["x": "x"]
XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload)) XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload))
XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, "x") XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, "x")
} }
func testDecodeInt() { func testDecodeInt() {
struct TestStruct : Decodable { struct TestStruct: Decodable {
let x: Int let x: Int
} }
let payload = ["x" : "42"] let payload = ["x": "42"]
XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload)) XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload))
XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, 42) XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, 42)
} }
func testDecodeOptional() { func testDecodeOptional() {
struct TestStruct : Decodable { struct TestStruct: Decodable {
let x: String? let x: String?
} }
let payload = [String : String]() let payload = [String: String]()
XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload)) XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload))
XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, nil) XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, nil)
} }
func testDecodeEnum() { func testDecodeEnum() {
enum TestEnum : String, Decodable { enum TestEnum: String, Decodable {
case type case type
} }
struct TestStruct : Decodable { struct TestStruct: Decodable {
let x: TestEnum let x: TestEnum
} }
let payload = ["x" : "type"] let payload = ["x": "type"]
XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload)) XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload))
XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, .type) XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, .type)
} }

View File

@ -16,14 +16,14 @@ class RouterTests: XCTestCase {
let q: String? let q: String?
} }
struct TestRoute : Route { struct TestRoute: Route {
let path = "/{p}" let path = "/{p}"
struct Parameters : Decodable { struct Parameters: Decodable {
let p: String let p: String
} }
struct Queries : Decodable { struct Queries: Decodable {
let q: String? let q: String?
} }