Add parser

This commit is contained in:
Zhigang Fang
2016-06-18 12:31:43 +08:00
parent 80ee7f3b49
commit 33cd4b5a7e
12 changed files with 446 additions and 52 deletions

View File

@@ -8,12 +8,19 @@
/* Begin PBXBuildFile section */
0409FE901D145707001EBAA3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0409FE8F1D145707001EBAA3 /* AppDelegate.swift */; };
0409FE921D145707001EBAA3 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0409FE911D145707001EBAA3 /* ViewController.swift */; };
0409FE921D145707001EBAA3 /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0409FE911D145707001EBAA3 /* HomeViewController.swift */; };
0409FE951D145707001EBAA3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0409FE931D145707001EBAA3 /* Main.storyboard */; };
0409FE971D145707001EBAA3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0409FE961D145707001EBAA3 /* Assets.xcassets */; };
0409FE9A1D145707001EBAA3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0409FE981D145707001EBAA3 /* LaunchScreen.storyboard */; };
0409FEA51D145707001EBAA3 /* GiphySearchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0409FEA41D145707001EBAA3 /* GiphySearchTests.swift */; };
0409FEA51D145707001EBAA3 /* QuickConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0409FEA41D145707001EBAA3 /* QuickConfig.swift */; };
0409FEB01D145707001EBAA3 /* GiphySearchUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0409FEAF1D145707001EBAA3 /* GiphySearchUITests.swift */; };
0453382E1D14E8B200C5239B /* HomeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0453382D1D14E8B200C5239B /* HomeViewModel.swift */; };
045338301D14EA5D00C5239B /* GiphyAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0453382F1D14EA5D00C5239B /* GiphyAPI.swift */; };
045338321D14EA9A00C5239B /* GiphyAPITest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 045338311D14EA9A00C5239B /* GiphyAPITest.swift */; };
045338361D14EBD000C5239B /* Giphy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 045338351D14EBD000C5239B /* Giphy.swift */; };
0453383C1D14F0A100C5239B /* NotYetReleasedParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0453383B1D14F0A100C5239B /* NotYetReleasedParser.swift */; };
0453383E1D14FCA300C5239B /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0453383D1D14FCA300C5239B /* Result.swift */; };
04FAC7451D14E27800230CF3 /* Injector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04FAC7441D14E27800230CF3 /* Injector.swift */; };
14B32E654239D09C164A3F2B /* Pods_GiphySearchTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A8CB399D083241D2E4B2EF15 /* Pods_GiphySearchTests.framework */; };
3E0BAE035A5120D1ED29BBC6 /* Pods_GiphySearchUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B3A076BE654A5741DBC60FFA /* Pods_GiphySearchUITests.framework */; };
7F3846BE13129F0CA635AA00 /* Pods_GiphySearch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A8221C6E6BE8EFD3C0ECD317 /* Pods_GiphySearch.framework */; };
@@ -39,17 +46,24 @@
/* Begin PBXFileReference section */
0409FE8C1D145707001EBAA3 /* GiphySearch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GiphySearch.app; sourceTree = BUILT_PRODUCTS_DIR; };
0409FE8F1D145707001EBAA3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
0409FE911D145707001EBAA3 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
0409FE911D145707001EBAA3 /* HomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewController.swift; sourceTree = "<group>"; };
0409FE941D145707001EBAA3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
0409FE961D145707001EBAA3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
0409FE991D145707001EBAA3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
0409FE9B1D145707001EBAA3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0409FEA01D145707001EBAA3 /* GiphySearchTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GiphySearchTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
0409FEA41D145707001EBAA3 /* GiphySearchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GiphySearchTests.swift; sourceTree = "<group>"; };
0409FEA41D145707001EBAA3 /* QuickConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickConfig.swift; sourceTree = "<group>"; };
0409FEA61D145707001EBAA3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0409FEAB1D145707001EBAA3 /* GiphySearchUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GiphySearchUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
0409FEAF1D145707001EBAA3 /* GiphySearchUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GiphySearchUITests.swift; sourceTree = "<group>"; };
0409FEB11D145707001EBAA3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0453382D1D14E8B200C5239B /* HomeViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeViewModel.swift; sourceTree = "<group>"; };
0453382F1D14EA5D00C5239B /* GiphyAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GiphyAPI.swift; sourceTree = "<group>"; };
045338311D14EA9A00C5239B /* GiphyAPITest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GiphyAPITest.swift; sourceTree = "<group>"; };
045338351D14EBD000C5239B /* Giphy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Giphy.swift; sourceTree = "<group>"; };
0453383B1D14F0A100C5239B /* NotYetReleasedParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotYetReleasedParser.swift; sourceTree = "<group>"; };
0453383D1D14FCA300C5239B /* Result.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Result.swift; sourceTree = "<group>"; };
04FAC7441D14E27800230CF3 /* Injector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Injector.swift; sourceTree = "<group>"; };
0C7E0838CB946C82B888F7F3 /* Pods-GiphySearchUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GiphySearchUITests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-GiphySearchUITests/Pods-GiphySearchUITests.debug.xcconfig"; sourceTree = "<group>"; };
36B16EBFDCC5405A55B2E3F8 /* Pods-GiphySearch.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GiphySearch.debug.xcconfig"; path = "Pods/Target Support Files/Pods-GiphySearch/Pods-GiphySearch.debug.xcconfig"; sourceTree = "<group>"; };
437F19F5739EFE071BA53F4F /* Pods-GiphySearchUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GiphySearchUITests.release.xcconfig"; path = "Pods/Target Support Files/Pods-GiphySearchUITests/Pods-GiphySearchUITests.release.xcconfig"; sourceTree = "<group>"; };
@@ -114,12 +128,13 @@
0409FE8E1D145707001EBAA3 /* GiphySearch */ = {
isa = PBXGroup;
children = (
0409FE8F1D145707001EBAA3 /* AppDelegate.swift */,
0409FE911D145707001EBAA3 /* ViewController.swift */,
0409FE931D145707001EBAA3 /* Main.storyboard */,
0409FE961D145707001EBAA3 /* Assets.xcassets */,
0409FE981D145707001EBAA3 /* LaunchScreen.storyboard */,
0409FE9B1D145707001EBAA3 /* Info.plist */,
045338341D14EBC700C5239B /* Model */,
0453382C1D14E88F00C5239B /* View */,
0453382B1D14E88B00C5239B /* ViewModel */,
045338331D14EAED00C5239B /* API */,
04FAC7431D14E22500230CF3 /* Misc */,
0453383A1D14F08600C5239B /* Vendor */,
04FAC7441D14E27800230CF3 /* Injector.swift */,
);
path = GiphySearch;
sourceTree = "<group>";
@@ -127,7 +142,8 @@
0409FEA31D145707001EBAA3 /* GiphySearchTests */ = {
isa = PBXGroup;
children = (
0409FEA41D145707001EBAA3 /* GiphySearchTests.swift */,
0409FEA41D145707001EBAA3 /* QuickConfig.swift */,
045338311D14EA9A00C5239B /* GiphyAPITest.swift */,
0409FEA61D145707001EBAA3 /* Info.plist */,
);
path = GiphySearchTests;
@@ -142,6 +158,59 @@
path = GiphySearchUITests;
sourceTree = "<group>";
};
0453382B1D14E88B00C5239B /* ViewModel */ = {
isa = PBXGroup;
children = (
0453382D1D14E8B200C5239B /* HomeViewModel.swift */,
);
name = ViewModel;
sourceTree = "<group>";
};
0453382C1D14E88F00C5239B /* View */ = {
isa = PBXGroup;
children = (
0409FE911D145707001EBAA3 /* HomeViewController.swift */,
0409FE931D145707001EBAA3 /* Main.storyboard */,
);
name = View;
sourceTree = "<group>";
};
045338331D14EAED00C5239B /* API */ = {
isa = PBXGroup;
children = (
0453382F1D14EA5D00C5239B /* GiphyAPI.swift */,
);
name = API;
sourceTree = "<group>";
};
045338341D14EBC700C5239B /* Model */ = {
isa = PBXGroup;
children = (
045338351D14EBD000C5239B /* Giphy.swift */,
);
name = Model;
sourceTree = "<group>";
};
0453383A1D14F08600C5239B /* Vendor */ = {
isa = PBXGroup;
children = (
0453383B1D14F0A100C5239B /* NotYetReleasedParser.swift */,
0453383D1D14FCA300C5239B /* Result.swift */,
);
name = Vendor;
sourceTree = "<group>";
};
04FAC7431D14E22500230CF3 /* Misc */ = {
isa = PBXGroup;
children = (
0409FE9B1D145707001EBAA3 /* Info.plist */,
0409FE961D145707001EBAA3 /* Assets.xcassets */,
0409FE981D145707001EBAA3 /* LaunchScreen.storyboard */,
0409FE8F1D145707001EBAA3 /* AppDelegate.swift */,
);
name = Misc;
sourceTree = "<group>";
};
D893AA2AA20F5EC761C23427 /* Pods */ = {
isa = PBXGroup;
children = (
@@ -427,8 +496,14 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0409FE921D145707001EBAA3 /* ViewController.swift in Sources */,
0409FE921D145707001EBAA3 /* HomeViewController.swift in Sources */,
04FAC7451D14E27800230CF3 /* Injector.swift in Sources */,
0453382E1D14E8B200C5239B /* HomeViewModel.swift in Sources */,
045338361D14EBD000C5239B /* Giphy.swift in Sources */,
0409FE901D145707001EBAA3 /* AppDelegate.swift in Sources */,
045338301D14EA5D00C5239B /* GiphyAPI.swift in Sources */,
0453383E1D14FCA300C5239B /* Result.swift in Sources */,
0453383C1D14F0A100C5239B /* NotYetReleasedParser.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -436,7 +511,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0409FEA51D145707001EBAA3 /* GiphySearchTests.swift in Sources */,
045338321D14EA9A00C5239B /* GiphyAPITest.swift in Sources */,
0409FEA51D145707001EBAA3 /* QuickConfig.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@@ -5,10 +5,10 @@
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--View Controller-->
<!--Home View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="GiphySearch" customModuleProvider="target" sceneMemberID="viewController">
<viewController id="BYZ-38-t0r" customClass="HomeViewController" customModule="GiphySearch" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>

28
GiphySearch/Giphy.swift Normal file
View File

@@ -0,0 +1,28 @@
//
// Giphy.swift
// GiphySearch
//
// Created by Kyle Fang on 6/18/16.
// Copyright © 2016 Kyle Fang. All rights reserved.
//
import Foundation
import Curry
struct Giphy {
let id: String
let slug: String
let url: String
let images: String
}
extension Giphy: Parsable {
static var parser: Parser<Giphy> {
return curry(self.init)
<^> "id"
<*> "slug"
<*> "url"
<*> "images.fixed_width.url"
}
}

View File

@@ -0,0 +1,40 @@
//
// GiphyAPI.swift
// GiphySearch
//
// Created by Kyle Fang on 6/18/16.
// Copyright © 2016 Kyle Fang. All rights reserved.
//
import Foundation
import RxSwift
import RxCocoa
protocol GiphyAPIType {
func trending() -> Observable<[Giphy]>
func search(keyword:[String]) -> Observable<[Giphy]>
}
private let treandingAPI = NSURL(string: "https://api.giphy.com/v1/gifs/trending?api_key=dc6zaTOxFJmzC")!
private func searchAPI(keyword: [String]) -> NSURL {
return NSURL(string: "https://api.giphy.com/v1/gifs/search?q=\(keyword.joinWithSeparator("+"))&api_key=dc6zaTOxFJmzC")!
}
struct GiphyAPI : GiphyAPIType {
let session: NSURLSession = Injector.resolve(NSURLSession.self)
let responseParser = dictionaryParser(
key: "data",
parser: arrayParser(Giphy.parser)
)
func trending() -> Observable<[Giphy]> {
return session.rx_JSON(treandingAPI)
.flatMap({ self.responseParser.parse($0).toObservable() })
}
func search(keywords: [String]) -> Observable<[Giphy]> {
return session.rx_JSON(searchAPI(keywords))
.flatMap({self.responseParser.parse($0).toObservable()})
}
}

View File

@@ -8,11 +8,16 @@
import UIKit
class ViewController: UIViewController {
class HomeViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
Injector.resolve(GiphyAPI.self)
.trending()
.subscribe({
print($0)
})
}
override func didReceiveMemoryWarning() {

View File

@@ -0,0 +1,13 @@
//
// ViewModel.swift
// GiphySearch
//
// Created by Kyle Fang on 6/18/16.
// Copyright © 2016 Kyle Fang. All rights reserved.
//
import Foundation
class ViewModel {
}

View File

@@ -0,0 +1,29 @@
//
// Injector.swift
// GiphySearch
//
// Created by Kyle Fang on 6/18/16.
// Copyright © 2016 Kyle Fang. All rights reserved.
//
import Foundation
import Swinject
struct Injector {
static func initialRegisteration(container: Container) {
container.register(ViewModel.self) { _ in ViewModel() }
container.register(NSURLSession.self) { _ in .sharedSession() }
container.register(GiphyAPI.self, factory: { _ in GiphyAPI() })
}
static private(set) var sharedContainer = Container(registeringClosure: Injector.initialRegisteration)
static func resolve<T>(type: T.Type) -> T {
return self.sharedContainer.resolve(type)!
}
// mainly for testing
static func reset() {
self.sharedContainer = Container(registeringClosure: Injector.initialRegisteration)
}
}

View File

@@ -0,0 +1,162 @@
//
// NotYetReleasedParser.swift
// GiphySearch
//
// Created by Kyle Fang on 6/18/16.
// Copyright © 2016 Kyle Fang. All rights reserved.
//
// Please don't look at the code here... :(
// It's WIP
import Foundation
extension String : ErrorType {
}
struct Parser<T> {
let parse: (AnyObject) -> Result<T>
}
extension Parser {
static func failed(error: ErrorType) -> Parser<T> {
return Parser { _ in .Error(error) }
}
static func unit(value:T) -> Parser<T> {
return Parser { _ in .Success(value) }
}
func flatMap<U>(function: T-> Parser<U>) -> Parser<U> {
return Parser<U> { input in
self.parse(input).flatMap({function($0).parse(input)})
}
}
func map<U>(function: T->U) -> Parser<U> {
return self.flatMap({.unit(function($0))})
}
func apply<U>(applicative: Parser<T->U>) -> Parser<U> {
return applicative.flatMap({self.map($0)})
}
}
infix operator <^> { associativity left }
infix operator <*> { associativity left }
func <^><T, U>(left: T->U, right: Parser<T>) -> Parser<U> {
return right.map(left)
}
func <*><T, U>(left: Parser<T->U>, right: Parser<T>) -> Parser<U> {
return right.apply(left)
}
func dictionaryParser<T>(key key: String, parser: Parser<T>) -> Parser<T> {
let keys = key.componentsSeparatedByString(".").reverse()
return keys.reduce(parser, combine: { loop, currentKey in
return Parser<T> { input in
guard let dictionary = input as? NSDictionary else {
return .Error("\(input) is not an dictionary")
}
guard let value = dictionary[currentKey] else {
return .Error("key \(currentKey) does not exist in \(input)")
}
return loop.parse(value)
}
})
}
func arrayParser<T>(parser:Parser<T>) -> Parser<[T]> {
let arrayOfAnyObject = Parser<NSArray> { input in
guard let array = input as? NSArray else {
return .Error("\(input) is not an array")
}
return .Success(array)
}
return arrayOfAnyObject.flatMap({ array in
let arrayOfParser = array.map({parser.parse($0).toParser()})
return arrayOfParser.reduce(.unit([])) { loop, nextParser in
{result in {next in result+[next]}} <^> loop <*> nextParser
}
})
}
func optionalParser<T>(parser:Parser<T>) -> Parser<Optional<T>> {
return Parser { input in
if case .Success(let value) = parser.parse(input) {
return .Success(value)
}
return .Success(nil)
}
}
func <^><T:Parsable, U>(left: T->U, key: String ) -> Parser<U> {
return left <^> dictionaryParser(key: key, parser: T.parser)
}
func <*><T:Parsable, U>(left: Parser<T->U>, key: String) -> Parser<U> {
return left <*> dictionaryParser(key: key, parser: T.parser)
}
//: These are workaround because swift's lack of support in partial confirm to protocol, you can't do `extension Array: Parsable where Element: Parsable`
func <^><T:Parsable, U>(left: [T]->U, key: String ) -> Parser<U> {
return left <^> dictionaryParser(
key: key,
parser: arrayParser(T.parser)
)
}
func <*><T:Parsable, U>(left: Parser<[T]->U>, key: String) -> Parser<U> {
return left <*> dictionaryParser(
key: key,
parser: arrayParser(T.parser)
)
}
func <^><T:Parsable, U>(left: Optional<T>->U, key: String ) -> Parser<U> {
return left <^> optionalParser(dictionaryParser(key: key,parser: T.parser))
}
func <*><T:Parsable, U>(left: Parser<Optional<T>->U>, key: String) -> Parser<U> {
return left <*> optionalParser(dictionaryParser(key: key,parser: T.parser))
}
protocol Parsable {
static var parser: Parser<Self> { get }
}
extension Double: Parsable {
static var parser: Parser<Double> {
return Parser {
if let number = $0 as? Double {
return .Success(number)
}
return .Error("\($0) is not an number")
}
}
}
extension Int: Parsable {
static var parser: Parser<Int> {
return Double.parser.map(Int.init)
}
}
extension String: Parsable {
static var parser: Parser<String> {
return Parser {
if let string = $0 as? String {
return .Success(string)
}
return .Error("\($0) is not an string")
}
}
}

44
GiphySearch/Result.swift Normal file
View File

@@ -0,0 +1,44 @@
//
// Result.swift
// GiphySearch
//
// Created by Kyle Fang on 6/18/16.
// Copyright © 2016 Kyle Fang. All rights reserved.
//
import Foundation
import RxSwift
enum Result<T> {
case Success(T)
case Error(ErrorType)
}
extension Result {
func flatMap<U>(function: T->Result<U>) -> Result<U> {
switch self {
case .Success(let value): return function(value)
case .Error(let error): return .Error(error)
}
}
var value: T? {
switch self {
case .Success(let value): return value
default: return nil
}
}
func toObservable() -> Observable<T> {
switch self {
case .Success(let value): return .just(value)
case .Error(let error): return .error(error)
}
}
func toParser() -> Parser<T> {
switch self {
case .Success(let value): return .unit(value)
case .Error(let error): return .failed(error)
}
}
}

View File

@@ -0,0 +1,9 @@
//
// GiphyAPITest.swift
// GiphySearch
//
// Created by Kyle Fang on 6/18/16.
// Copyright © 2016 Kyle Fang. All rights reserved.
//
import Foundation

View File

@@ -1,36 +0,0 @@
//
// GiphySearchTests.swift
// GiphySearchTests
//
// Created by Kyle Fang on 6/18/16.
// Copyright © 2016 Kyle Fang. All rights reserved.
//
import XCTest
@testable import GiphySearch
class GiphySearchTests: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measureBlock {
// Put the code you want to measure the time of here.
}
}
}

View File

@@ -0,0 +1,24 @@
//
// GiphySearchTests.swift
// GiphySearchTests
//
// Created by Kyle Fang on 6/18/16.
// Copyright © 2016 Kyle Fang. All rights reserved.
//
@testable import GiphySearch
import Quick
class QuickConfig: QuickConfiguration {
override class func configure(configuration: Configuration) {
configuration.beforeEach {
Injector.reset()
}
}
}
extension Injector {
static func registerMock<T>(type:T.Type, withFactory factory:()->T) {
self.sharedContainer.register(type, factory: {_ in return factory() })
}
}