├── .gitignore ├── .sourcery.yml ├── .swift-version ├── .travis.yml ├── Example ├── Podfile ├── Podfile.lock ├── RoboKittenTests │ ├── Info.plist │ ├── Mocks │ │ └── Generated │ │ │ └── Mock.generated.swift │ └── RoboKittenControllerSpec.swift ├── SwiftyMock.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ ├── SwiftyMock-Example.xcscheme │ │ └── SwiftyMock-Tests.xcscheme ├── SwiftyMock.xcworkspace │ └── contents.xcworkspacedata ├── SwiftyMock │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ ├── RoboKitten │ │ ├── Implementations │ │ │ └── RoboKittenV1.swift │ │ ├── RoboKitten.swift │ │ └── RoboKittenController.swift │ └── ViewController.swift └── Tests │ ├── Calls │ ├── ReactiveMatchers.swift │ ├── SwiftyMockCallsSpec.swift │ └── SwiftyMockReactiveCallsSpec.swift │ └── Info.plist ├── LICENSE ├── README.md ├── SwiftyMock.podspec ├── SwiftyMock ├── Assets │ └── .gitkeep ├── Classes │ ├── .gitkeep │ ├── Core │ │ └── MockUtils.swift │ └── ReactiveCocoa │ │ └── ReactiveExtensions.swift └── Templates │ └── Mock.stencil └── _Pods.xcodeproj /.gitignore: -------------------------------------------------------------------------------- 1 | Example/DerivedData 2 | Example/Pods 3 | Example/SwiftyMock.xcodeproj/xcuserdata 4 | Example/SwiftyMock.xcworkspace/xcuserdata 5 | Example/.idea 6 | .DS_Store 7 | *.un~ 8 | -------------------------------------------------------------------------------- /.sourcery.yml: -------------------------------------------------------------------------------- 1 | sources: 2 | - ./Example/SwiftyMock/RoboKitten 3 | templates: 4 | - ./SwiftyMock/Templates 5 | output: 6 | path: ./Example/RoboKittenTests/Mocks/Generated 7 | args: 8 | testable: SwiftyMock_Example -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 4.1 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # references: 2 | # * http://www.objc.io/issue-6/travis-ci.html 3 | # * https://github.com/supermarin/xcpretty#usage 4 | 5 | osx_image: xcode9.4 6 | 7 | language: objective-c 8 | cache: cocoapods 9 | podfile: Example/Podfile 10 | 11 | before_install: 12 | - pod repo update --silent 13 | - pod update --project-directory=Example 14 | - pod install --project-directory=Example 15 | 16 | install: 17 | - gem install xcpretty --no-rdoc --no-ri --no-document --quiet 18 | 19 | script: 20 | - set -o pipefail && xcodebuild test -workspace Example/SwiftyMock.xcworkspace -scheme SwiftyMock-Tests -sdk iphonesimulator11.4 -destination 'platform=iOS Simulator,name=iPhone 6,OS=11.4' | xcpretty -c 21 | - pod lib lint --quick --allow-warnings 22 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '9.3' 2 | use_frameworks! 3 | #inhibit_all_warnings! 4 | 5 | def reusePods 6 | pod 'SwiftyMock/ReactiveCocoa', :path => '../' 7 | end 8 | 9 | def reuseTestPods 10 | reusePods 11 | pod 'Quick', '~> 1.2' 12 | # using 7.x-branch for now because of this issue fix https://github.com/Quick/Nimble/issues/478 13 | # switch to corresponding version once it's released 14 | pod 'Nimble', :git => 'https://github.com/Quick/Nimble', :branch => '7.x-branch' 15 | end 16 | 17 | target 'SwiftyMock_Example' do 18 | reusePods 19 | end 20 | 21 | target 'SwiftyMock_Tests' do 22 | reuseTestPods 23 | end 24 | 25 | target 'RoboKittenTests' do 26 | reuseTestPods 27 | end 28 | 29 | 30 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Nimble (7.1.2) 3 | - Quick (1.3.0) 4 | - ReactiveCocoa (7.1.0): 5 | - ReactiveSwift (~> 3.1) 6 | - ReactiveSwift (3.1.0): 7 | - Result (~> 3.2) 8 | - Result (3.2.4) 9 | - SwiftyMock/Core (0.2.3) 10 | - SwiftyMock/ReactiveCocoa (0.2.3): 11 | - ReactiveCocoa (~> 7.1) 12 | - SwiftyMock/Core 13 | 14 | DEPENDENCIES: 15 | - Nimble (from `https://github.com/Quick/Nimble`, branch `7.x-branch`) 16 | - Quick (~> 1.2) 17 | - SwiftyMock/ReactiveCocoa (from `../`) 18 | 19 | SPEC REPOS: 20 | https://github.com/cocoapods/specs.git: 21 | - Quick 22 | - ReactiveCocoa 23 | - ReactiveSwift 24 | - Result 25 | 26 | EXTERNAL SOURCES: 27 | Nimble: 28 | :branch: 7.x-branch 29 | :git: https://github.com/Quick/Nimble 30 | SwiftyMock: 31 | :path: "../" 32 | 33 | CHECKOUT OPTIONS: 34 | Nimble: 35 | :commit: 773bc7b5b8f3be2ba7ba9d52c6e38936dd393f69 36 | :git: https://github.com/Quick/Nimble 37 | 38 | SPEC CHECKSUMS: 39 | Nimble: c0980a3cf3e9d3b8774ef08167a47bede81cf84f 40 | Quick: 03278013f71aa05fe9ecabc94fbcc6835f1ee76f 41 | ReactiveCocoa: 105ad96f6b8711f1ee7d165fc96587479298053b 42 | ReactiveSwift: 5b26d2e988fe0eed2daf48c4054d1de74db50184 43 | Result: d2d07204ce72856f1fd9130bbe42c35a7b0fea10 44 | SwiftyMock: 7ee122cdeb33302fff589ad3400085f464ccd292 45 | 46 | PODFILE CHECKSUM: 96e31c8bbe54905dd223cce795d28a49935d24a1 47 | 48 | COCOAPODS: 1.5.3 49 | -------------------------------------------------------------------------------- /Example/RoboKittenTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Example/RoboKittenTests/Mocks/Generated/Mock.generated.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.13.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import Foundation 5 | import SwiftyMock 6 | @testable import SwiftyMock_Example 7 | 8 | class FakeLazyRoboKitten: LazyRoboKitten { 9 | let needsRestGetCall = FunctionVoidCall() 10 | let needsRestSetCall = FunctionCall() 11 | var needsRest: Bool { 12 | get { return stubCall(needsRestGetCall) } 13 | set { stubCall(needsRestSetCall, argument: newValue) } 14 | } 15 | 16 | let batteryStatusCall = FunctionVoidCall() 17 | func batteryStatus() -> Int { 18 | return stubCall(batteryStatusCall) 19 | } 20 | 21 | let jumpCall = FunctionCall<(x: Int, y: Int), Void>() 22 | func jump(x: Int, y: Int) { 23 | return stubCall(jumpCall, argument: (x: x, y: y), defaultValue: ()) 24 | } 25 | 26 | let canJumpAtCall = FunctionCall<(x: Int, y: Int), Bool>() 27 | func canJumpAt(x: Int, y: Int) -> Bool { 28 | return stubCall(canJumpAtCall, argument: (x: x, y: y)) 29 | } 30 | 31 | let restCall = FunctionCall<(Bool) -> (), Void>() 32 | func rest(_ completed: @escaping (Bool) -> ()) { 33 | return stubCall(restCall, argument: completed, defaultValue: ()) 34 | } 35 | } 36 | 37 | class FakeRoboKitten: RoboKitten { 38 | 39 | let batteryStatusCall = FunctionVoidCall() 40 | func batteryStatus() -> Int { 41 | return stubCall(batteryStatusCall) 42 | } 43 | 44 | let jumpCall = FunctionCall<(x: Int, y: Int), Void>() 45 | func jump(x: Int, y: Int) { 46 | return stubCall(jumpCall, argument: (x: x, y: y), defaultValue: ()) 47 | } 48 | 49 | let canJumpAtCall = FunctionCall<(x: Int, y: Int), Bool>() 50 | func canJumpAt(x: Int, y: Int) -> Bool { 51 | return stubCall(canJumpAtCall, argument: (x: x, y: y)) 52 | } 53 | 54 | let restCall = FunctionCall<(Bool) -> (), Void>() 55 | func rest(_ completed: @escaping (Bool) -> ()) { 56 | return stubCall(restCall, argument: completed, defaultValue: ()) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Example/RoboKittenTests/RoboKittenControllerSpec.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RoboKittenControllerSpec.swift 3 | // SwiftyMock 4 | // 5 | // Created by Paul Taykalo on 7/31/16. 6 | // Copyright © 2016 CocoaPods. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | @testable import SwiftyMock_Example 11 | 12 | import Quick 13 | import Nimble 14 | import SwiftyMock 15 | 16 | class RoboKittenControllerSpec: QuickSpec { 17 | override func spec() { 18 | describe("RoboKittenController") { 19 | var sut: RoboKittenController! 20 | var kittenMock: FakeRoboKitten! 21 | beforeEach { 22 | kittenMock = FakeRoboKitten() 23 | sut = RoboKittenController(kitten: kittenMock) 24 | } 25 | 26 | describe("when checked for battery status") { 27 | it("should return LOW battery status for battery level < 10") { 28 | kittenMock.batteryStatusCall.returns(5) 29 | expect(sut.batteryStatus()).to(equal(BatteyStatus.low)) 30 | } 31 | it("should return FULL battery status for battery level >= 100") { 32 | kittenMock.batteryStatusCall.returns(100) 33 | expect(sut.batteryStatus()).to(equal(BatteyStatus.full)) 34 | 35 | kittenMock.batteryStatusCall.returns(210) 36 | expect(sut.batteryStatus()).to(equal(BatteyStatus.full)) 37 | } 38 | 39 | it("should return NORMAL battery status for battery level between 10..100") { 40 | kittenMock.batteryStatusCall.returns(15) 41 | expect(sut.batteryStatus()).to(equal(BatteyStatus.normal)) 42 | 43 | kittenMock.batteryStatusCall.returns(30) 44 | expect(sut.batteryStatus()).to(equal(BatteyStatus.normal)) 45 | } 46 | } 47 | 48 | describe("when asked to jump somewhere") { 49 | beforeEach { 50 | kittenMock.canJumpAtCall.returns(false) 51 | } 52 | it("should ask kitten if it's available to jump there") { 53 | sut.jumpAt(x: 10, y: 20) 54 | expect(kittenMock.canJumpAtCall.called).to(beTruthy()) 55 | } 56 | 57 | it("should ask kitten if it's available to jump there with the same coords") { 58 | sut.jumpAt(x: 10, y: 20) 59 | expect(kittenMock.canJumpAtCall.capturedArgument?.x).to(equal(10)) 60 | expect(kittenMock.canJumpAtCall.capturedArgument?.y).to(equal(20)) 61 | } 62 | 63 | context("and kitten can jump there") { 64 | beforeEach { 65 | kittenMock.canJumpAtCall.returns(true) 66 | } 67 | it("should actually ask kitten to jump") { 68 | sut.jumpAt(x: 15, y: 30) 69 | expect(kittenMock.jumpCall.called).to(beTruthy()) 70 | expect(kittenMock.jumpCall.capturedArgument?.x).to(equal(15)) 71 | expect(kittenMock.jumpCall.capturedArgument?.y).to(equal(30)) 72 | } 73 | 74 | it("should actually ask kitten to jump only once per call") { 75 | sut.jumpAt(x: 18, y: 23) 76 | expect(kittenMock.jumpCall.callsCount).to(equal(1)) 77 | 78 | sut.jumpAt(x: 80, y: 15) 79 | expect(kittenMock.jumpCall.callsCount).to(equal(2)) 80 | } 81 | 82 | it("return success result") { 83 | expect(sut.jumpAt(x: 10, y: 20)).to(equal(Result.success)) 84 | } 85 | } 86 | 87 | context("and kitten cannot jump there") { 88 | beforeEach { 89 | kittenMock.canJumpAtCall.returns(false) 90 | } 91 | 92 | it("should shouldn't ask kitten to jump") { 93 | sut.jumpAt(x: 15, y: 30) 94 | expect(kittenMock.jumpCall.called).to(beFalsy()) 95 | } 96 | it("shouldreturn failure result") { 97 | expect(sut.jumpAt(x: 10, y: 20)).to(equal(Result.failure)) 98 | } 99 | } 100 | 101 | } 102 | 103 | describe("when asked to perform multiple jumps") { 104 | context("and kitten can perform all of them") { 105 | beforeEach { 106 | kittenMock.canJumpAtCall.returns(true) 107 | } 108 | it("should return success result") { 109 | expect(sut.jump(inSequence: [(x: 10, y: 20), (x: 12, y: 20)])).to(equal(Result.success)) 110 | } 111 | 112 | it("should call jump on each passed parameter in the correct order") { 113 | let sequence = [(x: 15, y: 21), (x: 23, y: 21)] 114 | sut.jump(inSequence: sequence) 115 | expect(kittenMock.jumpCall.callsCount).to(equal(2)) 116 | expect(kittenMock.jumpCall.capturedArguments[0].x).to(equal(15)) 117 | expect(kittenMock.jumpCall.capturedArguments[0].y).to(equal(21)) 118 | 119 | expect(kittenMock.jumpCall.capturedArguments[1].x).to(equal(23)) 120 | expect(kittenMock.jumpCall.capturedArguments[1].y).to(equal(21)) 121 | } 122 | } 123 | 124 | context("And kitten can not jump at some coordinates") { 125 | beforeEach { 126 | kittenMock.canJumpAtCall 127 | .on { $0.x < 0 }.returns(false) 128 | .on { $0.y < 0 }.returns(false) 129 | .returns(true) // in all other cases 130 | 131 | } 132 | context("and there are some coordinates where kitten cannot jump at in passed in sequence") { 133 | it("should return failure result") { 134 | expect(sut.jump(inSequence: [(x: -10, y: 20), (x: 12, y: 20)])).to(equal(Result.failure)) 135 | expect(sut.jump(inSequence: [(x: 10, y: -20), (x: 12, y: 20)])).to(equal(Result.failure)) 136 | expect(sut.jump(inSequence: [(x: 10, y: -20), (x: -12, y: 20)])).to(equal(Result.failure)) 137 | expect(sut.jump(inSequence: [(x: 10, y: -20), (x: 12, y: -20)])).to(equal(Result.failure)) 138 | } 139 | it("should not ask kitten to jump at all") { 140 | sut.jump(inSequence: [(x: -10, y: 20), (x: 12, y: 20)]) 141 | 142 | expect(kittenMock.jumpCall.called).to(beFalsy()) 143 | } 144 | } 145 | 146 | context("and there are no coordinates where kitten cannot jump at in passed in sequence") { 147 | it("should return success result in case if there's no coords where kittent cannot jump at") { 148 | expect(sut.jump(inSequence: [(x: 10, y: 20), (x: 12, y: 20)])).to(equal(Result.success)) 149 | } 150 | } 151 | } 152 | } 153 | 154 | context("when asked to rest") { 155 | 156 | it("should ask kitten to rest") { 157 | sut.rest { _ in } 158 | expect(kittenMock.restCall.called).to(beTruthy()) 159 | } 160 | 161 | context("and kitten rests successfully") { 162 | beforeEach { 163 | kittenMock.restCall.performs { completion in 164 | completion(true) 165 | } 166 | } 167 | it("should return successful result") { 168 | var result: Result? 169 | sut.rest { restResult in 170 | result = restResult 171 | } 172 | expect(result).to(equal(.success)) 173 | } 174 | } 175 | 176 | context("and kitten fails to rest") { 177 | beforeEach { 178 | kittenMock.restCall.performs { completion in 179 | completion(false) 180 | } 181 | } 182 | it("should return failure result") { 183 | var result: Result? 184 | sut.rest { restResult in 185 | result = restResult 186 | } 187 | expect(result).to(equal(.failure)) 188 | } 189 | } 190 | 191 | } 192 | } 193 | } 194 | } 195 | 196 | -------------------------------------------------------------------------------- /Example/SwiftyMock.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4ED4AA41E4DD3980A4CD50F8 /* Pods_SwiftyMock_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F2E0186E90C589DC306B4DE9 /* Pods_SwiftyMock_Example.framework */; }; 11 | 5BF3C0823C995244ED8DE121 /* Pods_SwiftyMock_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 86B1369ECEBF34CBD8BF24A7 /* Pods_SwiftyMock_Tests.framework */; }; 12 | 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD51AFB9204008FA782 /* AppDelegate.swift */; }; 13 | 607FACD81AFB9204008FA782 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD71AFB9204008FA782 /* ViewController.swift */; }; 14 | 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607FACD91AFB9204008FA782 /* Main.storyboard */; }; 15 | 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; }; 16 | 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; }; 17 | A7D119AA1D500828F6B64159 /* Pods_RoboKittenTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A380849D11951D85498E493C /* Pods_RoboKittenTests.framework */; }; 18 | D21AF4631FC62DF600C0DC5F /* SwiftyMockReactiveCallsSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21AF4611FC62CFF00C0DC5F /* SwiftyMockReactiveCallsSpec.swift */; }; 19 | D21AF4661FC638F200C0DC5F /* ReactiveMatchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21AF4641FC6324400C0DC5F /* ReactiveMatchers.swift */; }; 20 | D2AEE57F20F9559000FF7DC8 /* Mock.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2AEE57E20F9559000FF7DC8 /* Mock.generated.swift */; }; 21 | E434BE281D4AAE86000E7125 /* SwiftyMockCallsSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = E434BE271D4AAE86000E7125 /* SwiftyMockCallsSpec.swift */; }; 22 | E481D6901D4DDE61000E73AE /* RoboKittenControllerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = E481D68F1D4DDE61000E73AE /* RoboKittenControllerSpec.swift */; }; 23 | EEDBE358155D115C15126670 /* RoboKitten.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEDBEBCC4DF10B0C24246892 /* RoboKitten.swift */; }; 24 | EEDBE98564CE5D2A54750BFD /* RoboKittenV1.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEDBE0C70C380389995EB816 /* RoboKittenV1.swift */; }; 25 | EEDBEAB8D9887C15ED1D0632 /* RoboKittenController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEDBE8EC7249C454D04FB152 /* RoboKittenController.swift */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXContainerItemProxy section */ 29 | 607FACE61AFB9204008FA782 /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = 607FACC81AFB9204008FA782 /* Project object */; 32 | proxyType = 1; 33 | remoteGlobalIDString = 607FACCF1AFB9204008FA782; 34 | remoteInfo = SwiftyMock; 35 | }; 36 | E481D6881D4DDDBE000E73AE /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = 607FACC81AFB9204008FA782 /* Project object */; 39 | proxyType = 1; 40 | remoteGlobalIDString = 607FACCF1AFB9204008FA782; 41 | remoteInfo = SwiftyMock_Example; 42 | }; 43 | /* End PBXContainerItemProxy section */ 44 | 45 | /* Begin PBXFileReference section */ 46 | 3E6C27CCCE1CA5F8417EB860 /* Pods-SwiftyMock_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftyMock_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftyMock_Example/Pods-SwiftyMock_Example.release.xcconfig"; sourceTree = ""; }; 47 | 56FDD6DA44AC86C2E1654D1A /* Pods-SwiftyMock_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftyMock_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftyMock_Tests/Pods-SwiftyMock_Tests.debug.xcconfig"; sourceTree = ""; }; 48 | 607FACD01AFB9204008FA782 /* SwiftyMock_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftyMock_Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | 607FACD41AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50 | 607FACD51AFB9204008FA782 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 51 | 607FACD71AFB9204008FA782 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 52 | 607FACDA1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 53 | 607FACDC1AFB9204008FA782 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 54 | 607FACDF1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 55 | 607FACE51AFB9204008FA782 /* SwiftyMock_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftyMock_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | 607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 57 | 65CB55A6EFAA61CD166E6ABE /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; 58 | 780C71DD02D492D34BF6DC2F /* Pods-RoboKittenTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RoboKittenTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RoboKittenTests/Pods-RoboKittenTests.debug.xcconfig"; sourceTree = ""; }; 59 | 86B1369ECEBF34CBD8BF24A7 /* Pods_SwiftyMock_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwiftyMock_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 60 | 98A466BCCB5D6510F97AD7B2 /* SwiftyMock.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = SwiftyMock.podspec; path = ../SwiftyMock.podspec; sourceTree = ""; }; 61 | A380849D11951D85498E493C /* Pods_RoboKittenTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RoboKittenTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 62 | BE3E75F38E5B31874FC7F8C4 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; 63 | D21AF4611FC62CFF00C0DC5F /* SwiftyMockReactiveCallsSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftyMockReactiveCallsSpec.swift; sourceTree = ""; }; 64 | D21AF4641FC6324400C0DC5F /* ReactiveMatchers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactiveMatchers.swift; sourceTree = ""; }; 65 | D2AEE57E20F9559000FF7DC8 /* Mock.generated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Mock.generated.swift; sourceTree = ""; }; 66 | E434BE271D4AAE86000E7125 /* SwiftyMockCallsSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyMockCallsSpec.swift; sourceTree = ""; }; 67 | E481D6831D4DDDBE000E73AE /* RoboKittenTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RoboKittenTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 68 | E481D6871D4DDDBE000E73AE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 69 | E481D68F1D4DDE61000E73AE /* RoboKittenControllerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoboKittenControllerSpec.swift; sourceTree = ""; }; 70 | E6DD82C8225916729797ED83 /* Pods-RoboKittenTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RoboKittenTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RoboKittenTests/Pods-RoboKittenTests.release.xcconfig"; sourceTree = ""; }; 71 | EEDBE0C70C380389995EB816 /* RoboKittenV1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoboKittenV1.swift; sourceTree = ""; }; 72 | EEDBE8EC7249C454D04FB152 /* RoboKittenController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoboKittenController.swift; sourceTree = ""; }; 73 | EEDBEBCC4DF10B0C24246892 /* RoboKitten.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoboKitten.swift; sourceTree = ""; }; 74 | F2E0186E90C589DC306B4DE9 /* Pods_SwiftyMock_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwiftyMock_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 75 | F8922BE058C4D4604D03C886 /* Pods-SwiftyMock_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftyMock_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftyMock_Tests/Pods-SwiftyMock_Tests.release.xcconfig"; sourceTree = ""; }; 76 | FC5C9C80564A568114ED28E1 /* Pods-SwiftyMock_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftyMock_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftyMock_Example/Pods-SwiftyMock_Example.debug.xcconfig"; sourceTree = ""; }; 77 | /* End PBXFileReference section */ 78 | 79 | /* Begin PBXFrameworksBuildPhase section */ 80 | 607FACCD1AFB9204008FA782 /* Frameworks */ = { 81 | isa = PBXFrameworksBuildPhase; 82 | buildActionMask = 2147483647; 83 | files = ( 84 | 4ED4AA41E4DD3980A4CD50F8 /* Pods_SwiftyMock_Example.framework in Frameworks */, 85 | ); 86 | runOnlyForDeploymentPostprocessing = 0; 87 | }; 88 | 607FACE21AFB9204008FA782 /* Frameworks */ = { 89 | isa = PBXFrameworksBuildPhase; 90 | buildActionMask = 2147483647; 91 | files = ( 92 | 5BF3C0823C995244ED8DE121 /* Pods_SwiftyMock_Tests.framework in Frameworks */, 93 | ); 94 | runOnlyForDeploymentPostprocessing = 0; 95 | }; 96 | E481D6801D4DDDBE000E73AE /* Frameworks */ = { 97 | isa = PBXFrameworksBuildPhase; 98 | buildActionMask = 2147483647; 99 | files = ( 100 | A7D119AA1D500828F6B64159 /* Pods_RoboKittenTests.framework in Frameworks */, 101 | ); 102 | runOnlyForDeploymentPostprocessing = 0; 103 | }; 104 | /* End PBXFrameworksBuildPhase section */ 105 | 106 | /* Begin PBXGroup section */ 107 | 607FACC71AFB9204008FA782 = { 108 | isa = PBXGroup; 109 | children = ( 110 | 607FACF51AFB993E008FA782 /* Podspec Metadata */, 111 | 607FACD21AFB9204008FA782 /* Example for SwiftyMock */, 112 | 607FACE81AFB9204008FA782 /* Tests */, 113 | E481D6841D4DDDBE000E73AE /* RoboKittenTests */, 114 | 607FACD11AFB9204008FA782 /* Products */, 115 | D5147DA4ACDB782F513D0F5D /* Pods */, 116 | 873EEE7B7B336D48973398FC /* Frameworks */, 117 | ); 118 | sourceTree = ""; 119 | }; 120 | 607FACD11AFB9204008FA782 /* Products */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | 607FACD01AFB9204008FA782 /* SwiftyMock_Example.app */, 124 | 607FACE51AFB9204008FA782 /* SwiftyMock_Tests.xctest */, 125 | E481D6831D4DDDBE000E73AE /* RoboKittenTests.xctest */, 126 | ); 127 | name = Products; 128 | sourceTree = ""; 129 | }; 130 | 607FACD21AFB9204008FA782 /* Example for SwiftyMock */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | 607FACD51AFB9204008FA782 /* AppDelegate.swift */, 134 | 607FACD71AFB9204008FA782 /* ViewController.swift */, 135 | 607FACD91AFB9204008FA782 /* Main.storyboard */, 136 | 607FACDC1AFB9204008FA782 /* Images.xcassets */, 137 | 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */, 138 | 607FACD31AFB9204008FA782 /* Supporting Files */, 139 | EEDBEEADC2A4E4ED70D52927 /* RoboKitten */, 140 | ); 141 | name = "Example for SwiftyMock"; 142 | path = SwiftyMock; 143 | sourceTree = ""; 144 | }; 145 | 607FACD31AFB9204008FA782 /* Supporting Files */ = { 146 | isa = PBXGroup; 147 | children = ( 148 | 607FACD41AFB9204008FA782 /* Info.plist */, 149 | ); 150 | name = "Supporting Files"; 151 | sourceTree = ""; 152 | }; 153 | 607FACE81AFB9204008FA782 /* Tests */ = { 154 | isa = PBXGroup; 155 | children = ( 156 | E434BE261D4AAE4A000E7125 /* Calls */, 157 | 607FACE91AFB9204008FA782 /* Supporting Files */, 158 | ); 159 | path = Tests; 160 | sourceTree = ""; 161 | }; 162 | 607FACE91AFB9204008FA782 /* Supporting Files */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | 607FACEA1AFB9204008FA782 /* Info.plist */, 166 | ); 167 | name = "Supporting Files"; 168 | sourceTree = ""; 169 | }; 170 | 607FACF51AFB993E008FA782 /* Podspec Metadata */ = { 171 | isa = PBXGroup; 172 | children = ( 173 | 98A466BCCB5D6510F97AD7B2 /* SwiftyMock.podspec */, 174 | BE3E75F38E5B31874FC7F8C4 /* README.md */, 175 | 65CB55A6EFAA61CD166E6ABE /* LICENSE */, 176 | ); 177 | name = "Podspec Metadata"; 178 | sourceTree = ""; 179 | }; 180 | 873EEE7B7B336D48973398FC /* Frameworks */ = { 181 | isa = PBXGroup; 182 | children = ( 183 | F2E0186E90C589DC306B4DE9 /* Pods_SwiftyMock_Example.framework */, 184 | 86B1369ECEBF34CBD8BF24A7 /* Pods_SwiftyMock_Tests.framework */, 185 | A380849D11951D85498E493C /* Pods_RoboKittenTests.framework */, 186 | ); 187 | name = Frameworks; 188 | sourceTree = ""; 189 | }; 190 | D2AEE57D20F9559000FF7DC8 /* Generated */ = { 191 | isa = PBXGroup; 192 | children = ( 193 | D2AEE57E20F9559000FF7DC8 /* Mock.generated.swift */, 194 | ); 195 | path = Generated; 196 | sourceTree = ""; 197 | }; 198 | D5147DA4ACDB782F513D0F5D /* Pods */ = { 199 | isa = PBXGroup; 200 | children = ( 201 | FC5C9C80564A568114ED28E1 /* Pods-SwiftyMock_Example.debug.xcconfig */, 202 | 3E6C27CCCE1CA5F8417EB860 /* Pods-SwiftyMock_Example.release.xcconfig */, 203 | 56FDD6DA44AC86C2E1654D1A /* Pods-SwiftyMock_Tests.debug.xcconfig */, 204 | F8922BE058C4D4604D03C886 /* Pods-SwiftyMock_Tests.release.xcconfig */, 205 | 780C71DD02D492D34BF6DC2F /* Pods-RoboKittenTests.debug.xcconfig */, 206 | E6DD82C8225916729797ED83 /* Pods-RoboKittenTests.release.xcconfig */, 207 | ); 208 | name = Pods; 209 | sourceTree = ""; 210 | }; 211 | E434BE261D4AAE4A000E7125 /* Calls */ = { 212 | isa = PBXGroup; 213 | children = ( 214 | E434BE271D4AAE86000E7125 /* SwiftyMockCallsSpec.swift */, 215 | D21AF4611FC62CFF00C0DC5F /* SwiftyMockReactiveCallsSpec.swift */, 216 | D21AF4641FC6324400C0DC5F /* ReactiveMatchers.swift */, 217 | ); 218 | path = Calls; 219 | sourceTree = ""; 220 | }; 221 | E481D6841D4DDDBE000E73AE /* RoboKittenTests */ = { 222 | isa = PBXGroup; 223 | children = ( 224 | E481D6871D4DDDBE000E73AE /* Info.plist */, 225 | E481D68F1D4DDE61000E73AE /* RoboKittenControllerSpec.swift */, 226 | EEDBE0EC744C4D09DA6A1963 /* Mocks */, 227 | ); 228 | path = RoboKittenTests; 229 | sourceTree = ""; 230 | }; 231 | EEDBE0EC744C4D09DA6A1963 /* Mocks */ = { 232 | isa = PBXGroup; 233 | children = ( 234 | D2AEE57D20F9559000FF7DC8 /* Generated */, 235 | ); 236 | path = Mocks; 237 | sourceTree = ""; 238 | }; 239 | EEDBE37BD3F93F1EE0988A08 /* Implementations */ = { 240 | isa = PBXGroup; 241 | children = ( 242 | EEDBE0C70C380389995EB816 /* RoboKittenV1.swift */, 243 | ); 244 | path = Implementations; 245 | sourceTree = ""; 246 | }; 247 | EEDBEEADC2A4E4ED70D52927 /* RoboKitten */ = { 248 | isa = PBXGroup; 249 | children = ( 250 | EEDBEBCC4DF10B0C24246892 /* RoboKitten.swift */, 251 | EEDBE8EC7249C454D04FB152 /* RoboKittenController.swift */, 252 | EEDBE37BD3F93F1EE0988A08 /* Implementations */, 253 | ); 254 | path = RoboKitten; 255 | sourceTree = ""; 256 | }; 257 | /* End PBXGroup section */ 258 | 259 | /* Begin PBXNativeTarget section */ 260 | 607FACCF1AFB9204008FA782 /* SwiftyMock_Example */ = { 261 | isa = PBXNativeTarget; 262 | buildConfigurationList = 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "SwiftyMock_Example" */; 263 | buildPhases = ( 264 | C32EF44E3C05F3402819F3E1 /* [CP] Check Pods Manifest.lock */, 265 | 607FACCC1AFB9204008FA782 /* Sources */, 266 | 607FACCD1AFB9204008FA782 /* Frameworks */, 267 | 607FACCE1AFB9204008FA782 /* Resources */, 268 | 6A3F6B608A6F4760DAAA542E /* [CP] Embed Pods Frameworks */, 269 | ); 270 | buildRules = ( 271 | ); 272 | dependencies = ( 273 | ); 274 | name = SwiftyMock_Example; 275 | productName = SwiftyMock; 276 | productReference = 607FACD01AFB9204008FA782 /* SwiftyMock_Example.app */; 277 | productType = "com.apple.product-type.application"; 278 | }; 279 | 607FACE41AFB9204008FA782 /* SwiftyMock_Tests */ = { 280 | isa = PBXNativeTarget; 281 | buildConfigurationList = 607FACF21AFB9204008FA782 /* Build configuration list for PBXNativeTarget "SwiftyMock_Tests" */; 282 | buildPhases = ( 283 | 076287B0FFA270C0D181F7BF /* [CP] Check Pods Manifest.lock */, 284 | 607FACE11AFB9204008FA782 /* Sources */, 285 | 607FACE21AFB9204008FA782 /* Frameworks */, 286 | 607FACE31AFB9204008FA782 /* Resources */, 287 | 409972991AA0686BA8B28E43 /* [CP] Embed Pods Frameworks */, 288 | ); 289 | buildRules = ( 290 | ); 291 | dependencies = ( 292 | 607FACE71AFB9204008FA782 /* PBXTargetDependency */, 293 | ); 294 | name = SwiftyMock_Tests; 295 | productName = Tests; 296 | productReference = 607FACE51AFB9204008FA782 /* SwiftyMock_Tests.xctest */; 297 | productType = "com.apple.product-type.bundle.unit-test"; 298 | }; 299 | E481D6821D4DDDBE000E73AE /* RoboKittenTests */ = { 300 | isa = PBXNativeTarget; 301 | buildConfigurationList = E481D68A1D4DDDBE000E73AE /* Build configuration list for PBXNativeTarget "RoboKittenTests" */; 302 | buildPhases = ( 303 | 58C919E4579AAC652916579F /* [CP] Check Pods Manifest.lock */, 304 | E481D67F1D4DDDBE000E73AE /* Sources */, 305 | E481D6801D4DDDBE000E73AE /* Frameworks */, 306 | E481D6811D4DDDBE000E73AE /* Resources */, 307 | BECACC2C45CF5517A8987EB9 /* [CP] Embed Pods Frameworks */, 308 | ); 309 | buildRules = ( 310 | ); 311 | dependencies = ( 312 | E481D6891D4DDDBE000E73AE /* PBXTargetDependency */, 313 | ); 314 | name = RoboKittenTests; 315 | productName = RoboKittenTests; 316 | productReference = E481D6831D4DDDBE000E73AE /* RoboKittenTests.xctest */; 317 | productType = "com.apple.product-type.bundle.unit-test"; 318 | }; 319 | /* End PBXNativeTarget section */ 320 | 321 | /* Begin PBXProject section */ 322 | 607FACC81AFB9204008FA782 /* Project object */ = { 323 | isa = PBXProject; 324 | attributes = { 325 | LastSwiftUpdateCheck = 0730; 326 | LastUpgradeCheck = 0830; 327 | ORGANIZATIONNAME = CocoaPods; 328 | TargetAttributes = { 329 | 607FACCF1AFB9204008FA782 = { 330 | CreatedOnToolsVersion = 6.3.1; 331 | LastSwiftMigration = 0830; 332 | }; 333 | 607FACE41AFB9204008FA782 = { 334 | CreatedOnToolsVersion = 6.3.1; 335 | LastSwiftMigration = 0830; 336 | }; 337 | E481D6821D4DDDBE000E73AE = { 338 | CreatedOnToolsVersion = 7.3.1; 339 | LastSwiftMigration = 0830; 340 | TestTargetID = 607FACCF1AFB9204008FA782; 341 | }; 342 | }; 343 | }; 344 | buildConfigurationList = 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "SwiftyMock" */; 345 | compatibilityVersion = "Xcode 3.2"; 346 | developmentRegion = English; 347 | hasScannedForEncodings = 0; 348 | knownRegions = ( 349 | en, 350 | Base, 351 | ); 352 | mainGroup = 607FACC71AFB9204008FA782; 353 | productRefGroup = 607FACD11AFB9204008FA782 /* Products */; 354 | projectDirPath = ""; 355 | projectRoot = ""; 356 | targets = ( 357 | 607FACCF1AFB9204008FA782 /* SwiftyMock_Example */, 358 | 607FACE41AFB9204008FA782 /* SwiftyMock_Tests */, 359 | E481D6821D4DDDBE000E73AE /* RoboKittenTests */, 360 | ); 361 | }; 362 | /* End PBXProject section */ 363 | 364 | /* Begin PBXResourcesBuildPhase section */ 365 | 607FACCE1AFB9204008FA782 /* Resources */ = { 366 | isa = PBXResourcesBuildPhase; 367 | buildActionMask = 2147483647; 368 | files = ( 369 | 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */, 370 | 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */, 371 | 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */, 372 | ); 373 | runOnlyForDeploymentPostprocessing = 0; 374 | }; 375 | 607FACE31AFB9204008FA782 /* Resources */ = { 376 | isa = PBXResourcesBuildPhase; 377 | buildActionMask = 2147483647; 378 | files = ( 379 | ); 380 | runOnlyForDeploymentPostprocessing = 0; 381 | }; 382 | E481D6811D4DDDBE000E73AE /* Resources */ = { 383 | isa = PBXResourcesBuildPhase; 384 | buildActionMask = 2147483647; 385 | files = ( 386 | ); 387 | runOnlyForDeploymentPostprocessing = 0; 388 | }; 389 | /* End PBXResourcesBuildPhase section */ 390 | 391 | /* Begin PBXShellScriptBuildPhase section */ 392 | 076287B0FFA270C0D181F7BF /* [CP] Check Pods Manifest.lock */ = { 393 | isa = PBXShellScriptBuildPhase; 394 | buildActionMask = 2147483647; 395 | files = ( 396 | ); 397 | inputPaths = ( 398 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 399 | "${PODS_ROOT}/Manifest.lock", 400 | ); 401 | name = "[CP] Check Pods Manifest.lock"; 402 | outputPaths = ( 403 | "$(DERIVED_FILE_DIR)/Pods-SwiftyMock_Tests-checkManifestLockResult.txt", 404 | ); 405 | runOnlyForDeploymentPostprocessing = 0; 406 | shellPath = /bin/sh; 407 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 408 | showEnvVarsInLog = 0; 409 | }; 410 | 409972991AA0686BA8B28E43 /* [CP] Embed Pods Frameworks */ = { 411 | isa = PBXShellScriptBuildPhase; 412 | buildActionMask = 2147483647; 413 | files = ( 414 | ); 415 | inputPaths = ( 416 | "${SRCROOT}/Pods/Target Support Files/Pods-SwiftyMock_Tests/Pods-SwiftyMock_Tests-frameworks.sh", 417 | "${BUILT_PRODUCTS_DIR}/ReactiveCocoa/ReactiveCocoa.framework", 418 | "${BUILT_PRODUCTS_DIR}/ReactiveSwift/ReactiveSwift.framework", 419 | "${BUILT_PRODUCTS_DIR}/Result/Result.framework", 420 | "${BUILT_PRODUCTS_DIR}/SwiftyMock/SwiftyMock.framework", 421 | "${BUILT_PRODUCTS_DIR}/Nimble/Nimble.framework", 422 | "${BUILT_PRODUCTS_DIR}/Quick/Quick.framework", 423 | ); 424 | name = "[CP] Embed Pods Frameworks"; 425 | outputPaths = ( 426 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactiveCocoa.framework", 427 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactiveSwift.framework", 428 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Result.framework", 429 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyMock.framework", 430 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Nimble.framework", 431 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Quick.framework", 432 | ); 433 | runOnlyForDeploymentPostprocessing = 0; 434 | shellPath = /bin/sh; 435 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwiftyMock_Tests/Pods-SwiftyMock_Tests-frameworks.sh\"\n"; 436 | showEnvVarsInLog = 0; 437 | }; 438 | 58C919E4579AAC652916579F /* [CP] Check Pods Manifest.lock */ = { 439 | isa = PBXShellScriptBuildPhase; 440 | buildActionMask = 2147483647; 441 | files = ( 442 | ); 443 | inputPaths = ( 444 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 445 | "${PODS_ROOT}/Manifest.lock", 446 | ); 447 | name = "[CP] Check Pods Manifest.lock"; 448 | outputPaths = ( 449 | "$(DERIVED_FILE_DIR)/Pods-RoboKittenTests-checkManifestLockResult.txt", 450 | ); 451 | runOnlyForDeploymentPostprocessing = 0; 452 | shellPath = /bin/sh; 453 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 454 | showEnvVarsInLog = 0; 455 | }; 456 | 6A3F6B608A6F4760DAAA542E /* [CP] Embed Pods Frameworks */ = { 457 | isa = PBXShellScriptBuildPhase; 458 | buildActionMask = 2147483647; 459 | files = ( 460 | ); 461 | inputPaths = ( 462 | "${SRCROOT}/Pods/Target Support Files/Pods-SwiftyMock_Example/Pods-SwiftyMock_Example-frameworks.sh", 463 | "${BUILT_PRODUCTS_DIR}/ReactiveCocoa/ReactiveCocoa.framework", 464 | "${BUILT_PRODUCTS_DIR}/ReactiveSwift/ReactiveSwift.framework", 465 | "${BUILT_PRODUCTS_DIR}/Result/Result.framework", 466 | "${BUILT_PRODUCTS_DIR}/SwiftyMock/SwiftyMock.framework", 467 | ); 468 | name = "[CP] Embed Pods Frameworks"; 469 | outputPaths = ( 470 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactiveCocoa.framework", 471 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactiveSwift.framework", 472 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Result.framework", 473 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyMock.framework", 474 | ); 475 | runOnlyForDeploymentPostprocessing = 0; 476 | shellPath = /bin/sh; 477 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwiftyMock_Example/Pods-SwiftyMock_Example-frameworks.sh\"\n"; 478 | showEnvVarsInLog = 0; 479 | }; 480 | BECACC2C45CF5517A8987EB9 /* [CP] Embed Pods Frameworks */ = { 481 | isa = PBXShellScriptBuildPhase; 482 | buildActionMask = 2147483647; 483 | files = ( 484 | ); 485 | inputPaths = ( 486 | "${SRCROOT}/Pods/Target Support Files/Pods-RoboKittenTests/Pods-RoboKittenTests-frameworks.sh", 487 | "${BUILT_PRODUCTS_DIR}/ReactiveCocoa/ReactiveCocoa.framework", 488 | "${BUILT_PRODUCTS_DIR}/ReactiveSwift/ReactiveSwift.framework", 489 | "${BUILT_PRODUCTS_DIR}/Result/Result.framework", 490 | "${BUILT_PRODUCTS_DIR}/SwiftyMock/SwiftyMock.framework", 491 | "${BUILT_PRODUCTS_DIR}/Nimble/Nimble.framework", 492 | "${BUILT_PRODUCTS_DIR}/Quick/Quick.framework", 493 | ); 494 | name = "[CP] Embed Pods Frameworks"; 495 | outputPaths = ( 496 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactiveCocoa.framework", 497 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactiveSwift.framework", 498 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Result.framework", 499 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyMock.framework", 500 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Nimble.framework", 501 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Quick.framework", 502 | ); 503 | runOnlyForDeploymentPostprocessing = 0; 504 | shellPath = /bin/sh; 505 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RoboKittenTests/Pods-RoboKittenTests-frameworks.sh\"\n"; 506 | showEnvVarsInLog = 0; 507 | }; 508 | C32EF44E3C05F3402819F3E1 /* [CP] Check Pods Manifest.lock */ = { 509 | isa = PBXShellScriptBuildPhase; 510 | buildActionMask = 2147483647; 511 | files = ( 512 | ); 513 | inputPaths = ( 514 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 515 | "${PODS_ROOT}/Manifest.lock", 516 | ); 517 | name = "[CP] Check Pods Manifest.lock"; 518 | outputPaths = ( 519 | "$(DERIVED_FILE_DIR)/Pods-SwiftyMock_Example-checkManifestLockResult.txt", 520 | ); 521 | runOnlyForDeploymentPostprocessing = 0; 522 | shellPath = /bin/sh; 523 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 524 | showEnvVarsInLog = 0; 525 | }; 526 | /* End PBXShellScriptBuildPhase section */ 527 | 528 | /* Begin PBXSourcesBuildPhase section */ 529 | 607FACCC1AFB9204008FA782 /* Sources */ = { 530 | isa = PBXSourcesBuildPhase; 531 | buildActionMask = 2147483647; 532 | files = ( 533 | 607FACD81AFB9204008FA782 /* ViewController.swift in Sources */, 534 | 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */, 535 | EEDBE358155D115C15126670 /* RoboKitten.swift in Sources */, 536 | EEDBEAB8D9887C15ED1D0632 /* RoboKittenController.swift in Sources */, 537 | EEDBE98564CE5D2A54750BFD /* RoboKittenV1.swift in Sources */, 538 | ); 539 | runOnlyForDeploymentPostprocessing = 0; 540 | }; 541 | 607FACE11AFB9204008FA782 /* Sources */ = { 542 | isa = PBXSourcesBuildPhase; 543 | buildActionMask = 2147483647; 544 | files = ( 545 | E434BE281D4AAE86000E7125 /* SwiftyMockCallsSpec.swift in Sources */, 546 | D21AF4661FC638F200C0DC5F /* ReactiveMatchers.swift in Sources */, 547 | D21AF4631FC62DF600C0DC5F /* SwiftyMockReactiveCallsSpec.swift in Sources */, 548 | ); 549 | runOnlyForDeploymentPostprocessing = 0; 550 | }; 551 | E481D67F1D4DDDBE000E73AE /* Sources */ = { 552 | isa = PBXSourcesBuildPhase; 553 | buildActionMask = 2147483647; 554 | files = ( 555 | D2AEE57F20F9559000FF7DC8 /* Mock.generated.swift in Sources */, 556 | E481D6901D4DDE61000E73AE /* RoboKittenControllerSpec.swift in Sources */, 557 | ); 558 | runOnlyForDeploymentPostprocessing = 0; 559 | }; 560 | /* End PBXSourcesBuildPhase section */ 561 | 562 | /* Begin PBXTargetDependency section */ 563 | 607FACE71AFB9204008FA782 /* PBXTargetDependency */ = { 564 | isa = PBXTargetDependency; 565 | target = 607FACCF1AFB9204008FA782 /* SwiftyMock_Example */; 566 | targetProxy = 607FACE61AFB9204008FA782 /* PBXContainerItemProxy */; 567 | }; 568 | E481D6891D4DDDBE000E73AE /* PBXTargetDependency */ = { 569 | isa = PBXTargetDependency; 570 | target = 607FACCF1AFB9204008FA782 /* SwiftyMock_Example */; 571 | targetProxy = E481D6881D4DDDBE000E73AE /* PBXContainerItemProxy */; 572 | }; 573 | /* End PBXTargetDependency section */ 574 | 575 | /* Begin PBXVariantGroup section */ 576 | 607FACD91AFB9204008FA782 /* Main.storyboard */ = { 577 | isa = PBXVariantGroup; 578 | children = ( 579 | 607FACDA1AFB9204008FA782 /* Base */, 580 | ); 581 | name = Main.storyboard; 582 | sourceTree = ""; 583 | }; 584 | 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */ = { 585 | isa = PBXVariantGroup; 586 | children = ( 587 | 607FACDF1AFB9204008FA782 /* Base */, 588 | ); 589 | name = LaunchScreen.xib; 590 | sourceTree = ""; 591 | }; 592 | /* End PBXVariantGroup section */ 593 | 594 | /* Begin XCBuildConfiguration section */ 595 | 607FACED1AFB9204008FA782 /* Debug */ = { 596 | isa = XCBuildConfiguration; 597 | buildSettings = { 598 | ALWAYS_SEARCH_USER_PATHS = NO; 599 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 600 | CLANG_CXX_LIBRARY = "libc++"; 601 | CLANG_ENABLE_MODULES = YES; 602 | CLANG_ENABLE_OBJC_ARC = YES; 603 | CLANG_WARN_BOOL_CONVERSION = YES; 604 | CLANG_WARN_CONSTANT_CONVERSION = YES; 605 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 606 | CLANG_WARN_EMPTY_BODY = YES; 607 | CLANG_WARN_ENUM_CONVERSION = YES; 608 | CLANG_WARN_INFINITE_RECURSION = YES; 609 | CLANG_WARN_INT_CONVERSION = YES; 610 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 611 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 612 | CLANG_WARN_UNREACHABLE_CODE = YES; 613 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 614 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 615 | COPY_PHASE_STRIP = NO; 616 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 617 | ENABLE_STRICT_OBJC_MSGSEND = YES; 618 | ENABLE_TESTABILITY = YES; 619 | GCC_C_LANGUAGE_STANDARD = gnu99; 620 | GCC_DYNAMIC_NO_PIC = NO; 621 | GCC_NO_COMMON_BLOCKS = YES; 622 | GCC_OPTIMIZATION_LEVEL = 0; 623 | GCC_PREPROCESSOR_DEFINITIONS = ( 624 | "DEBUG=1", 625 | "$(inherited)", 626 | ); 627 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 628 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 629 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 630 | GCC_WARN_UNDECLARED_SELECTOR = YES; 631 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 632 | GCC_WARN_UNUSED_FUNCTION = YES; 633 | GCC_WARN_UNUSED_VARIABLE = YES; 634 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 635 | MTL_ENABLE_DEBUG_INFO = YES; 636 | ONLY_ACTIVE_ARCH = YES; 637 | SDKROOT = iphoneos; 638 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 639 | }; 640 | name = Debug; 641 | }; 642 | 607FACEE1AFB9204008FA782 /* Release */ = { 643 | isa = XCBuildConfiguration; 644 | buildSettings = { 645 | ALWAYS_SEARCH_USER_PATHS = NO; 646 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 647 | CLANG_CXX_LIBRARY = "libc++"; 648 | CLANG_ENABLE_MODULES = YES; 649 | CLANG_ENABLE_OBJC_ARC = YES; 650 | CLANG_WARN_BOOL_CONVERSION = YES; 651 | CLANG_WARN_CONSTANT_CONVERSION = YES; 652 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 653 | CLANG_WARN_EMPTY_BODY = YES; 654 | CLANG_WARN_ENUM_CONVERSION = YES; 655 | CLANG_WARN_INFINITE_RECURSION = YES; 656 | CLANG_WARN_INT_CONVERSION = YES; 657 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 658 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 659 | CLANG_WARN_UNREACHABLE_CODE = YES; 660 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 661 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 662 | COPY_PHASE_STRIP = NO; 663 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 664 | ENABLE_NS_ASSERTIONS = NO; 665 | ENABLE_STRICT_OBJC_MSGSEND = YES; 666 | GCC_C_LANGUAGE_STANDARD = gnu99; 667 | GCC_NO_COMMON_BLOCKS = YES; 668 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 669 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 670 | GCC_WARN_UNDECLARED_SELECTOR = YES; 671 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 672 | GCC_WARN_UNUSED_FUNCTION = YES; 673 | GCC_WARN_UNUSED_VARIABLE = YES; 674 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 675 | MTL_ENABLE_DEBUG_INFO = NO; 676 | SDKROOT = iphoneos; 677 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 678 | VALIDATE_PRODUCT = YES; 679 | }; 680 | name = Release; 681 | }; 682 | 607FACF01AFB9204008FA782 /* Debug */ = { 683 | isa = XCBuildConfiguration; 684 | baseConfigurationReference = FC5C9C80564A568114ED28E1 /* Pods-SwiftyMock_Example.debug.xcconfig */; 685 | buildSettings = { 686 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 687 | INFOPLIST_FILE = SwiftyMock/Info.plist; 688 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 689 | MODULE_NAME = ExampleApp; 690 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)"; 691 | PRODUCT_NAME = "$(TARGET_NAME)"; 692 | SWIFT_VERSION = 4.0; 693 | }; 694 | name = Debug; 695 | }; 696 | 607FACF11AFB9204008FA782 /* Release */ = { 697 | isa = XCBuildConfiguration; 698 | baseConfigurationReference = 3E6C27CCCE1CA5F8417EB860 /* Pods-SwiftyMock_Example.release.xcconfig */; 699 | buildSettings = { 700 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 701 | INFOPLIST_FILE = SwiftyMock/Info.plist; 702 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 703 | MODULE_NAME = ExampleApp; 704 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)"; 705 | PRODUCT_NAME = "$(TARGET_NAME)"; 706 | SWIFT_VERSION = 4.0; 707 | }; 708 | name = Release; 709 | }; 710 | 607FACF31AFB9204008FA782 /* Debug */ = { 711 | isa = XCBuildConfiguration; 712 | baseConfigurationReference = 56FDD6DA44AC86C2E1654D1A /* Pods-SwiftyMock_Tests.debug.xcconfig */; 713 | buildSettings = { 714 | FRAMEWORK_SEARCH_PATHS = ( 715 | "$(SDKROOT)/Developer/Library/Frameworks", 716 | "$(inherited)", 717 | ); 718 | GCC_PREPROCESSOR_DEFINITIONS = ( 719 | "DEBUG=1", 720 | "$(inherited)", 721 | ); 722 | INFOPLIST_FILE = Tests/Info.plist; 723 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 724 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)"; 725 | PRODUCT_NAME = "$(TARGET_NAME)"; 726 | SWIFT_VERSION = 4.0; 727 | }; 728 | name = Debug; 729 | }; 730 | 607FACF41AFB9204008FA782 /* Release */ = { 731 | isa = XCBuildConfiguration; 732 | baseConfigurationReference = F8922BE058C4D4604D03C886 /* Pods-SwiftyMock_Tests.release.xcconfig */; 733 | buildSettings = { 734 | FRAMEWORK_SEARCH_PATHS = ( 735 | "$(SDKROOT)/Developer/Library/Frameworks", 736 | "$(inherited)", 737 | ); 738 | INFOPLIST_FILE = Tests/Info.plist; 739 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 740 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)"; 741 | PRODUCT_NAME = "$(TARGET_NAME)"; 742 | SWIFT_VERSION = 4.0; 743 | }; 744 | name = Release; 745 | }; 746 | E481D68B1D4DDDBE000E73AE /* Debug */ = { 747 | isa = XCBuildConfiguration; 748 | baseConfigurationReference = 780C71DD02D492D34BF6DC2F /* Pods-RoboKittenTests.debug.xcconfig */; 749 | buildSettings = { 750 | BUNDLE_LOADER = "$(TEST_HOST)"; 751 | CLANG_ANALYZER_NONNULL = YES; 752 | DEBUG_INFORMATION_FORMAT = dwarf; 753 | INFOPLIST_FILE = RoboKittenTests/Info.plist; 754 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 755 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 756 | PRODUCT_BUNDLE_IDENTIFIER = com.stanfy.RoboKittenTests; 757 | PRODUCT_NAME = "$(TARGET_NAME)"; 758 | SWIFT_VERSION = 4.0; 759 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftyMock_Example.app/SwiftyMock_Example"; 760 | }; 761 | name = Debug; 762 | }; 763 | E481D68C1D4DDDBE000E73AE /* Release */ = { 764 | isa = XCBuildConfiguration; 765 | baseConfigurationReference = E6DD82C8225916729797ED83 /* Pods-RoboKittenTests.release.xcconfig */; 766 | buildSettings = { 767 | BUNDLE_LOADER = "$(TEST_HOST)"; 768 | CLANG_ANALYZER_NONNULL = YES; 769 | INFOPLIST_FILE = RoboKittenTests/Info.plist; 770 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 771 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 772 | PRODUCT_BUNDLE_IDENTIFIER = com.stanfy.RoboKittenTests; 773 | PRODUCT_NAME = "$(TARGET_NAME)"; 774 | SWIFT_VERSION = 4.0; 775 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftyMock_Example.app/SwiftyMock_Example"; 776 | }; 777 | name = Release; 778 | }; 779 | /* End XCBuildConfiguration section */ 780 | 781 | /* Begin XCConfigurationList section */ 782 | 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "SwiftyMock" */ = { 783 | isa = XCConfigurationList; 784 | buildConfigurations = ( 785 | 607FACED1AFB9204008FA782 /* Debug */, 786 | 607FACEE1AFB9204008FA782 /* Release */, 787 | ); 788 | defaultConfigurationIsVisible = 0; 789 | defaultConfigurationName = Release; 790 | }; 791 | 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "SwiftyMock_Example" */ = { 792 | isa = XCConfigurationList; 793 | buildConfigurations = ( 794 | 607FACF01AFB9204008FA782 /* Debug */, 795 | 607FACF11AFB9204008FA782 /* Release */, 796 | ); 797 | defaultConfigurationIsVisible = 0; 798 | defaultConfigurationName = Release; 799 | }; 800 | 607FACF21AFB9204008FA782 /* Build configuration list for PBXNativeTarget "SwiftyMock_Tests" */ = { 801 | isa = XCConfigurationList; 802 | buildConfigurations = ( 803 | 607FACF31AFB9204008FA782 /* Debug */, 804 | 607FACF41AFB9204008FA782 /* Release */, 805 | ); 806 | defaultConfigurationIsVisible = 0; 807 | defaultConfigurationName = Release; 808 | }; 809 | E481D68A1D4DDDBE000E73AE /* Build configuration list for PBXNativeTarget "RoboKittenTests" */ = { 810 | isa = XCConfigurationList; 811 | buildConfigurations = ( 812 | E481D68B1D4DDDBE000E73AE /* Debug */, 813 | E481D68C1D4DDDBE000E73AE /* Release */, 814 | ); 815 | defaultConfigurationIsVisible = 0; 816 | defaultConfigurationName = Release; 817 | }; 818 | /* End XCConfigurationList section */ 819 | }; 820 | rootObject = 607FACC81AFB9204008FA782 /* Project object */; 821 | } 822 | -------------------------------------------------------------------------------- /Example/SwiftyMock.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/SwiftyMock.xcodeproj/xcshareddata/xcschemes/SwiftyMock-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 57 | 63 | 64 | 65 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 88 | 90 | 96 | 97 | 98 | 99 | 100 | 101 | 107 | 109 | 115 | 116 | 117 | 118 | 120 | 121 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /Example/SwiftyMock.xcodeproj/xcshareddata/xcschemes/SwiftyMock-Tests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 55 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 74 | 76 | 77 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /Example/SwiftyMock.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/SwiftyMock/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SwiftyMock 4 | // 5 | // Created by Paul Taykalo on 07/29/2016. 6 | // Copyright (c) 2016 Paul Taykalo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | } 23 | 24 | -------------------------------------------------------------------------------- /Example/SwiftyMock/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Example/SwiftyMock/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Example/SwiftyMock/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Example/SwiftyMock/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Example/SwiftyMock/RoboKitten/Implementations/RoboKittenV1.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Paul Taykalo on 7/31/16. 3 | // Copyright (c) 2016 CocoaPods. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | 8 | class RoboKittenV1: RoboKitten { 9 | 10 | func batteryStatus() -> Int { 11 | return 0 12 | } 13 | 14 | func jump(x: Int, y: Int) { 15 | } 16 | 17 | func canJumpAt(x: Int, y: Int) -> Bool { 18 | return false 19 | } 20 | 21 | func rest(_ completed: @escaping (Bool) -> ()) { 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Example/SwiftyMock/RoboKitten/RoboKitten.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Paul Taykalo on 7/31/16. 3 | // Copyright (c) 2016 CocoaPods. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | 8 | // sourcery: Mock 9 | protocol RoboKitten { 10 | @discardableResult func batteryStatus() -> Int 11 | func jump(x: Int, y: Int) 12 | @discardableResult func canJumpAt(x: Int, y: Int) -> Bool 13 | func rest(_ completed: @escaping (Bool) -> ()) 14 | } 15 | 16 | // sourcery: Mock 17 | protocol LazyRoboKitten: RoboKitten { 18 | var needsRest: Bool { get set } 19 | } -------------------------------------------------------------------------------- /Example/SwiftyMock/RoboKitten/RoboKittenController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Paul Taykalo on 7/31/16. 3 | // Copyright (c) 2016 CocoaPods. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | 8 | enum BatteyStatus: Equatable { 9 | case low 10 | case normal 11 | case full 12 | } 13 | 14 | enum Result { 15 | case success 16 | case failure 17 | } 18 | 19 | 20 | class RoboKittenController { 21 | let kitten: RoboKitten 22 | 23 | init(kitten: RoboKitten) { 24 | self.kitten = kitten 25 | } 26 | 27 | @discardableResult func batteryStatus() -> BatteyStatus { 28 | if kitten.batteryStatus() >= 100 { 29 | return .full 30 | } 31 | if (kitten.batteryStatus() < 10) { 32 | return .low 33 | } 34 | return .normal 35 | } 36 | 37 | @discardableResult func jumpAt(x: Int, y: Int) -> Result { 38 | if kitten.canJumpAt(x: x, y: y) { 39 | kitten.jump(x: x, y: y) 40 | return .success 41 | } 42 | return .failure 43 | } 44 | 45 | @discardableResult func jump(inSequence sequence: [(x: Int, y: Int)]) -> Result { 46 | for coords in sequence { 47 | if !kitten.canJumpAt(x: coords.x, y: coords.y) { 48 | return .failure 49 | } 50 | } 51 | for coords in sequence { 52 | kitten.jump(x: coords.x, y: coords.y) 53 | } 54 | return .success 55 | } 56 | 57 | func rest(_ completion: @escaping (Result) -> ()) { 58 | kitten.rest { successfuly in 59 | switch successfuly { 60 | case true: completion(.success) 61 | case false: completion(.failure) 62 | } 63 | } 64 | } 65 | 66 | } 67 | 68 | -------------------------------------------------------------------------------- /Example/SwiftyMock/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // SwiftyMock 4 | // 5 | // Created by Paul Taykalo on 07/29/2016. 6 | // Copyright (c) 2016 Paul Taykalo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | } 14 | 15 | -------------------------------------------------------------------------------- /Example/Tests/Calls/ReactiveMatchers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReactiveMatchers.swift 3 | // SwiftyMock_Example 4 | // 5 | // Created by Alexander Voronov on 11/23/17. 6 | // Copyright © 2017 CocoaPods. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Quick 11 | import Nimble 12 | import Result 13 | import ReactiveSwift 14 | 15 | // MARK: - Send Value 16 | 17 | private func sendValue( 18 | where predicate: @escaping (V) -> Bool, 19 | expectation: @escaping (Signal.Event?, V?) -> ExpectationMessage 20 | ) -> Predicate where T.Value == V, T.Error == E { 21 | return Predicate { (actualExpression: Expression) throws -> PredicateResult in 22 | var actualEvent: Signal.Event? 23 | var actualValue: V? 24 | var satisfies: Bool = false 25 | let actualProducer = try actualExpression.evaluate() 26 | actualProducer?.producer.start { event in 27 | actualEvent = event 28 | if case let .value(value) = event { 29 | actualValue = value 30 | satisfies = predicate(value) 31 | } 32 | } 33 | guard actualValue != nil else { 34 | return PredicateResult( 35 | status: .fail, 36 | message: expectation(actualEvent, actualValue) 37 | ) 38 | } 39 | return PredicateResult( 40 | bool: satisfies, 41 | message: expectation(actualEvent, actualValue) 42 | ) 43 | } 44 | } 45 | 46 | func sendValue(where predicate: @escaping (V) -> Bool) -> Predicate where T.Value == V { 47 | return sendValue(where: predicate, expectation: { (actualEvent, actualValue) in 48 | .expectedCustomValueTo( 49 | "send value to satisfy predicate", 50 | message(forEvent: actualEvent, value: actualValue) 51 | ) 52 | }) 53 | } 54 | 55 | func sendValue(_ expectedValue: V) -> Predicate where T.Value == V { 56 | return sendValue(where: { $0 == expectedValue }, expectation: { (actualEvent, actualValue) in 57 | .expectedCustomValueTo( 58 | "send value <\(stringify(expectedValue))>", 59 | message(forEvent: actualEvent, value: actualValue) 60 | ) 61 | }) 62 | } 63 | 64 | func sendEmptyValue() -> Predicate where T.Value == Void { 65 | return sendValue(where: { true }, expectation: { (actualEvent, actualValue) in 66 | .expectedCustomValueTo( 67 | "send value ", 68 | message(forEvent: actualEvent, value: actualValue) 69 | ) 70 | }) 71 | } 72 | 73 | // MARK: - Send Value and Complete 74 | 75 | private func sendValueAndComplete( 76 | where predicate: @escaping (V) -> Bool, 77 | expectation: @escaping (Signal.Event?, V?) -> ExpectationMessage 78 | ) -> Predicate where T.Value == V, T.Error == E { 79 | return Predicate { (actualExpression: Expression) throws -> PredicateResult in 80 | var actualEvent: Signal.Event? 81 | var completed: Bool = false 82 | var actualValue: V? 83 | var satisfies: Bool = false 84 | let actualProducer = try actualExpression.evaluate() 85 | actualProducer?.producer.start { event in 86 | actualEvent = event 87 | if case let .value(value) = event { 88 | actualValue = value 89 | satisfies = predicate(value) 90 | } 91 | if case .completed = event { 92 | completed = true 93 | } else { 94 | completed = false 95 | } 96 | } 97 | guard actualValue != nil, completed else { 98 | return PredicateResult( 99 | status: .fail, 100 | message: expectation(actualEvent, actualValue) 101 | ) 102 | } 103 | return PredicateResult( 104 | bool: satisfies, 105 | message: expectation(actualEvent, actualValue) 106 | ) 107 | } 108 | } 109 | 110 | func sendValueAndComplete(where predicate: @escaping (V) -> Bool) -> Predicate where T.Value == V { 111 | return sendValueAndComplete(where: predicate, expectation: { (actualEvent, actualValue) in 112 | .expectedCustomValueTo( 113 | "send value to satisfy predicate and complete", 114 | message(forEvent: actualEvent, value: actualValue) 115 | ) 116 | }) 117 | } 118 | 119 | func sendValueAndComplete(_ expectedValue: V) -> Predicate where T.Value == V { 120 | return sendValue(where: { $0 == expectedValue }, expectation: { (actualEvent, actualValue) in 121 | .expectedCustomValueTo( 122 | "send value <\(stringify(expectedValue))> and complete", 123 | message(forEvent: actualEvent, value: actualValue) 124 | ) 125 | }) 126 | } 127 | 128 | func sendEmptyValueAndComplete() -> Predicate where T.Value == Void { 129 | return sendValue(where: { true }, expectation: { (actualEvent, actualValue) in 130 | .expectedCustomValueTo( 131 | "send value and complete", 132 | message(forEvent: actualEvent, value: actualValue) 133 | ) 134 | }) 135 | } 136 | 137 | // MARK: - Complete 138 | 139 | func complete() -> Predicate where T.Value == V, T.Error == E { 140 | return Predicate { (actualExpression: Expression) throws -> PredicateResult in 141 | var actualEvent: Signal.Event? 142 | var completed: Bool = false 143 | let actualProducer = try actualExpression.evaluate() 144 | actualProducer?.producer.start { event in 145 | actualEvent = event 146 | if case .completed = event { 147 | completed = true 148 | } 149 | } 150 | return PredicateResult( 151 | bool: completed, 152 | message: .expectedCustomValueTo("complete", message(forEvent: actualEvent)) 153 | ) 154 | } 155 | } 156 | 157 | // MARK: - Fail 158 | 159 | private func fail( 160 | where predicate: @escaping (E) -> Bool, 161 | expectation: @escaping (Signal.Event?, E?) -> ExpectationMessage 162 | ) -> Predicate where T.Value == V, T.Error == E { 163 | return Predicate { (actualExpression: Expression) throws -> PredicateResult in 164 | var actualEvent: Signal.Event? 165 | var actualError: E? 166 | var matches: Bool = false 167 | let actualProducer = try actualExpression.evaluate() 168 | actualProducer?.producer.start { event in 169 | actualEvent = event 170 | if case let .failed(error) = event { 171 | actualError = error 172 | matches = predicate(error) 173 | } 174 | } 175 | guard actualError != nil else { 176 | return PredicateResult( 177 | status: .fail, 178 | message: expectation(actualEvent, actualError) 179 | ) 180 | } 181 | return PredicateResult( 182 | bool: matches, 183 | message: expectation(actualEvent, actualError) 184 | ) 185 | } 186 | } 187 | 188 | func fail(where predicate: @escaping (E) -> Bool) -> Predicate where T.Error == E { 189 | return fail(where: predicate, expectation: { (actualEvent, actualError) in 190 | .expectedCustomValueTo( 191 | "send error to satisfy predicate", 192 | message(forEvent: actualEvent, error: actualError) 193 | ) 194 | }) 195 | } 196 | 197 | func fail(with expectedError: E) -> Predicate where T.Error == E { 198 | return fail(where: { errorMatchesExpectedError($0, expectedError: expectedError) }, expectation: { (actualEvent, actualError) in 199 | .expectedCustomValueTo( 200 | "send error <\(stringify(expectedError))>", 201 | message(forEvent: actualEvent, error: actualError) 202 | ) 203 | }) 204 | } 205 | 206 | func fail(with expectedError: E) -> Predicate where T.Error == E { 207 | return fail(where: { $0 == expectedError }, expectation: { (actualEvent, actualError) in 208 | .expectedCustomValueTo( 209 | "send error <\(stringify(expectedError))>", 210 | message(forEvent: actualEvent, error: actualError) 211 | ) 212 | }) 213 | } 214 | 215 | func failWithNoError() -> Predicate where T.Error == NoError { 216 | return fail(where: { _ in true }, expectation: { (actualEvent, actualError) in 217 | .expectedCustomValueTo( 218 | "send error ", 219 | message(forEvent: actualEvent, error: actualError) 220 | ) 221 | }) 222 | } 223 | 224 | // MARK: - Interrupt 225 | 226 | func interrupt() -> Predicate where T.Value == V, T.Error == E { 227 | return Predicate { (actualExpression: Expression) throws -> PredicateResult in 228 | var actualEvent: Signal.Event? 229 | var interrupted: Bool = false 230 | let actualProducer = try actualExpression.evaluate() 231 | actualProducer?.producer.start { event in 232 | actualEvent = event 233 | if case .interrupted = event { 234 | interrupted = true 235 | } 236 | } 237 | return PredicateResult( 238 | bool: interrupted, 239 | message: .expectedCustomValueTo("interrupt", message(forEvent: actualEvent)) 240 | ) 241 | } 242 | } 243 | 244 | // MARK: - Helpers 245 | 246 | private func errorMatchesExpectedError(_ actualError: Error, expectedError: T) -> Bool { 247 | return actualError._domain == expectedError._domain 248 | && actualError._code == expectedError._code 249 | } 250 | 251 | private func message(forEvent event: Signal.Event?) -> String { 252 | if let event = event { 253 | return "<\(stringify(event))> event" 254 | } 255 | return "no event" 256 | } 257 | 258 | private func message(forEvent event: Signal.Event?, value: V?) -> String { 259 | if let event = event { 260 | if case .value = event { 261 | return "<\(stringify(value))> value" 262 | } 263 | return "<\(stringify(event))> event with <\(stringify(value))> value" 264 | } 265 | return "no event" 266 | } 267 | 268 | private func message(forEvent event: Signal.Event?, error: E?) -> String { 269 | if let event = event { 270 | if case .failed = event { 271 | return "<\(stringify(error))> error" 272 | } 273 | return "<\(stringify(event))> event with <\(stringify(error))> error" 274 | } 275 | return "no event" 276 | } 277 | -------------------------------------------------------------------------------- /Example/Tests/Calls/SwiftyMockCallsSpec.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftyMockCallsSpec.swift 3 | // SwiftyMock 4 | // 5 | // Created by Paul Taykalo on 7/29/16. 6 | // Copyright © 2016 CocoaPods. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Quick 11 | import Nimble 12 | @testable import SwiftyMock 13 | 14 | protocol Calculator { 15 | func sum(left: Int, right: Int) -> Int 16 | } 17 | 18 | class TestCalculator: Calculator { 19 | let sum = FunctionCall<(left: Int, right: Int), Int>() 20 | @discardableResult func sum(left: Int, right: Int) -> Int { 21 | return stubCall(sum, argument: (left: left, right: right)) 22 | } 23 | } 24 | 25 | class SwiftyMockCallsSpec: QuickSpec { 26 | override func spec() { 27 | describe("SwiftyMockCalls") { 28 | describe("when correctly setup") { 29 | var sut: TestCalculator! 30 | beforeEach { 31 | sut = TestCalculator() 32 | } 33 | 34 | context("before calling stubbed method") { 35 | it("should tell that method wasnt' called") { 36 | expect(sut.sum.called).to(beFalsy()) 37 | } 38 | it("should have calls count equal to zero") { 39 | expect(sut.sum.callsCount).to(equal(0)) 40 | } 41 | it("should not have captured argumen") { 42 | expect(sut.sum.capturedArgument).to(beNil()) 43 | } 44 | 45 | it("should not have captured argumens") { 46 | expect(sut.sum.capturedArguments).to(beEmpty()) 47 | } 48 | 49 | } 50 | context("when calling method before stubbing") { 51 | it("should fail with assertion") { 52 | expect { sut.sum(left: 1,right: 2) }.to(throwAssertion()) 53 | } 54 | } 55 | context("when calling stubbed method") { 56 | context("with value stub") { 57 | beforeEach { 58 | sut.sum.returns(12) 59 | } 60 | it("should return stubbed value") { 61 | expect(sut.sum(left: 1,right:2)).to(equal(12)) 62 | } 63 | it("should have calls count equal number of calls") { 64 | sut.sum(left: 1,right:2) 65 | expect(sut.sum.callsCount).to(equal(1)) 66 | 67 | sut.sum(left: 2,right:3) 68 | sut.sum(left: 3,right:5) 69 | expect(sut.sum.callsCount).to(equal(3)) 70 | } 71 | 72 | it("tell that method was called") { 73 | sut.sum(left: 1,right:2) 74 | expect(sut.sum.called).to(beTruthy()) 75 | } 76 | } 77 | context("with logic stub") { 78 | beforeEach { 79 | sut.sum.performs { $0.left - $0.right } 80 | } 81 | it("should calculate method based on the stubbed block") { 82 | expect(sut.sum(left: 1, right:2)).to(equal(-1)) 83 | expect(sut.sum(left: 3, right:2)).to(equal(1)) 84 | } 85 | it("should have calls count equal number of calls") { 86 | sut.sum(left: 1,right:2) 87 | expect(sut.sum.callsCount).to(equal(1)) 88 | 89 | sut.sum(left: 2,right:3) 90 | sut.sum(left: 3,right:5) 91 | expect(sut.sum.callsCount).to(equal(3)) 92 | } 93 | it("should tell that method was called") { 94 | sut.sum(left: 1,right:2) 95 | expect(sut.sum.called).to(beTruthy()) 96 | } 97 | } 98 | context("with logic and value stub") { 99 | beforeEach { 100 | sut.sum.returns(12) 101 | sut.sum.performs { $0.left + $0.right} 102 | } 103 | it("should use logic stub instead of value") { 104 | expect(sut.sum(left: 15, right:12)).to(equal(27)) 105 | } 106 | } 107 | } 108 | 109 | context("when calling filtered value stubbed method") { 110 | beforeEach { 111 | sut.sum.returns(10) 112 | sut.sum.on { $0.left == 12 }.returns(0) 113 | sut.sum.on { $0.right == 15 }.returns(7) 114 | } 115 | context("when parameters matching filter") { 116 | it("should return filter srubbed value") { 117 | expect(sut.sum(left: 12,right:2)).to(equal(0)) 118 | expect(sut.sum(left: 0,right:15)).to(equal(7)) 119 | } 120 | } 121 | context("when parameters doesn't match filters") { 122 | it("should return default stubbed value") { 123 | expect(sut.sum(left: 13,right:2)).to(equal(10)) 124 | } 125 | } 126 | } 127 | 128 | context("when calling filtered block stubbed method") { 129 | beforeEach { 130 | sut.sum.performs { $0.left + $0.right } 131 | sut.sum.on { $0.left == 0 }.performs { _ in 0 } 132 | sut.sum.on { $0.right == 0 }.performs { _ in 12 } 133 | } 134 | context("when parameters matching filter") { 135 | it("should return call filter-based block") { 136 | expect(sut.sum(left: 0,right:2)).to(equal(0)) 137 | expect(sut.sum(left: 15,right:0)).to(equal(12)) 138 | } 139 | } 140 | context("when parameters doesn't match filters") { 141 | it("should return call default stubbed block") { 142 | expect(sut.sum(left: 13,right:2)).to(equal(15)) 143 | } 144 | } 145 | } 146 | 147 | 148 | context("when calling filtered stubbed with block method") { 149 | beforeEach { 150 | sut.sum.returns(17) 151 | sut.sum.on { $0.left == 12 }.performs { $0.left + $0.right } 152 | } 153 | context("when parameters matching filter") { 154 | it("should return calculated with stub value") { 155 | expect(sut.sum(left: 12,right:2)).to(equal(14)) 156 | expect(sut.sum(left: 12,right:12)).to(equal(24)) 157 | } 158 | } 159 | context("when parameters doesn't match filters") { 160 | it("should return default stubbed value") { 161 | expect(sut.sum(left: 13,right:2)).to(equal(17)) 162 | } 163 | } 164 | } 165 | } 166 | } 167 | } 168 | } 169 | 170 | -------------------------------------------------------------------------------- /Example/Tests/Calls/SwiftyMockReactiveCallsSpec.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftyMockReactiveCallsSpec.swift 3 | // SwiftyMock_Example 4 | // 5 | // Created by Alexander Voronov on 11/23/17. 6 | // Copyright © 2017 CocoaPods. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Quick 11 | import Nimble 12 | import ReactiveSwift 13 | import Result 14 | @testable import SwiftyMock 15 | 16 | protocol ReactiveCalculator { 17 | func sum(left: Int, right: Int) -> SignalProducer 18 | } 19 | 20 | class TestReactiveCalculator: ReactiveCalculator { 21 | init() {} 22 | 23 | let sum = ReactiveCall<(left: Int, right: Int), Int, TestError>() 24 | @discardableResult func sum(left: Int, right: Int) -> SignalProducer { 25 | return stubCall(sum, argument: (left: left, right: right)) 26 | } 27 | } 28 | 29 | struct TestError: Error, Equatable { 30 | let id: Int 31 | init() { id = 0 } 32 | init(id: Int) { self.id = id } 33 | } 34 | 35 | class SwiftyMockReactiveCallsSpec: QuickSpec { 36 | override func spec() { 37 | describe("SwiftyMockReactiveCalls") { 38 | describe("when correctly setup") { 39 | var sut: TestReactiveCalculator! 40 | beforeEach { 41 | sut = TestReactiveCalculator() 42 | } 43 | 44 | context("before calling stubbed method") { 45 | it("should tell that method wasn't called") { 46 | expect(sut.sum.called).to(beFalsy()) 47 | } 48 | it("should have calls count equal to zero") { 49 | expect(sut.sum.callsCount).to(equal(0)) 50 | } 51 | it("should not have captured argument") { 52 | expect(sut.sum.capturedArgument).to(beNil()) 53 | } 54 | it("should not have captured arguments") { 55 | expect(sut.sum.capturedArguments).to(beEmpty()) 56 | } 57 | } 58 | 59 | context("when calling method before stubbing") { 60 | fit("should return empty signal without any value") { 61 | expect { sut.sum(left: 1,right: 2) }.to(complete()) 62 | } 63 | } 64 | 65 | context("when calling stubbed method") { 66 | context("with value stub") { 67 | beforeEach { 68 | sut.sum.returns(.success(12)) 69 | } 70 | 71 | it("should return stubbed value and complete") { 72 | let result = sut.sum(left: 1, right: 2) 73 | expect(result).to(sendValue(12)) 74 | expect(result).to(complete()) 75 | } 76 | 77 | it("should have calls count equal number of calls") { 78 | sut.sum(left: 1, right: 2) 79 | expect(sut.sum.callsCount).to(equal(1)) 80 | 81 | sut.sum(left: 2, right: 3) 82 | sut.sum(left: 3, right: 5) 83 | expect(sut.sum.callsCount).to(equal(3)) 84 | } 85 | 86 | it("should tell that method was called") { 87 | sut.sum(left: 1,right: 2) 88 | expect(sut.sum.called).to(beTruthy()) 89 | } 90 | } 91 | 92 | context("with failure value stub") { 93 | beforeEach { 94 | sut.sum.returns(.failure(TestError())) 95 | } 96 | 97 | it("should return stubbed error") { 98 | expect(sut.sum(left: 1, right: 2)).to(fail(with: TestError())) 99 | } 100 | } 101 | 102 | context("with logic stub") { 103 | beforeEach { 104 | sut.sum.performs { .success($0.left - $0.right) } 105 | } 106 | 107 | it("should calculate method based on the stubbed block") { 108 | expect(sut.sum(left: 1, right: 2)).to(sendValue(-1)) 109 | expect(sut.sum(left: 3, right: 2)).to(sendValue(1)) 110 | } 111 | 112 | it("should have calls count equal number of calls") { 113 | sut.sum(left: 1, right: 2) 114 | expect(sut.sum.callsCount).to(equal(1)) 115 | 116 | sut.sum(left: 2, right: 3) 117 | sut.sum(left: 3, right: 5) 118 | expect(sut.sum.callsCount).to(equal(3)) 119 | } 120 | 121 | it("tell that method was called") { 122 | sut.sum(left: 1, right:2) 123 | expect(sut.sum.called).to(beTruthy()) 124 | } 125 | } 126 | 127 | context("with failure logic stub") { 128 | beforeEach { 129 | sut.sum.performs { _ in .failure(TestError()) } 130 | } 131 | 132 | it("should return stubbed error") { 133 | expect(sut.sum(left: 1, right: 2)).to(fail(with: TestError())) 134 | } 135 | } 136 | 137 | context("with value and logic stub") { 138 | beforeEach { 139 | sut.sum.returns(.success(12)) 140 | sut.sum.performs { .success($0.left + $0.right) } 141 | } 142 | 143 | it("should use logic stub instead of value") { 144 | expect(sut.sum(left: 15, right: 12)).to(sendValue(27)) 145 | } 146 | } 147 | 148 | context("with value and failure logic stub") { 149 | beforeEach { 150 | sut.sum.returns(.success(12)) 151 | sut.sum.performs { _ in .failure(TestError()) } 152 | } 153 | 154 | it("should use failure logic stub instead of value") { 155 | expect(sut.sum(left: 15, right: 12)).to(fail(with: TestError())) 156 | } 157 | } 158 | 159 | context("with failure value and logic stub") { 160 | beforeEach { 161 | sut.sum.returns(.failure(TestError())) 162 | sut.sum.performs { .success($0.left + $0.right) } 163 | } 164 | 165 | it("should use logic stub instead of failure value") { 166 | expect(sut.sum(left: 15, right: 12)).to(sendValue(27)) 167 | } 168 | } 169 | 170 | context("with failure value and failure logic stub") { 171 | beforeEach { 172 | sut.sum.returns(.failure(TestError(id: 0))) 173 | sut.sum.performs { _ in .failure(TestError(id: 1)) } 174 | } 175 | 176 | it("should use failure logic stub instead of failure value") { 177 | expect(sut.sum(left: 15, right: 12)).to(fail(with: TestError(id: 1))) 178 | } 179 | } 180 | } 181 | 182 | context("when calling filtered value stubbed method") { 183 | beforeEach { 184 | sut.sum.returns(.success(10)) 185 | sut.sum.on { $0.left == 12 }.returns(.success(0)) 186 | sut.sum.on { $0.right == 15 }.returns(.success(7)) 187 | sut.sum.on { $0.right == 42 }.returns(.failure(TestError())) 188 | } 189 | context("when parameters matching filter") { 190 | it("should return filter srubbed value") { 191 | expect(sut.sum(left: 12, right: 2)).to(sendValue(0)) 192 | expect(sut.sum(left: 0, right: 15)).to(sendValue(7)) 193 | expect(sut.sum(left: 23, right: 42)).to(fail(with: TestError())) 194 | } 195 | } 196 | context("when parameters don't match filters") { 197 | it("should return default stubbed value") { 198 | expect(sut.sum(left: 13, right: 2)).to(sendValue(10)) 199 | } 200 | } 201 | } 202 | 203 | context("when calling filtered block stubbed method") { 204 | beforeEach { 205 | sut.sum.performs { .success($0.left - $0.right) } 206 | sut.sum.on { $0.left == 0 }.performs { _ in .success(0) } 207 | sut.sum.on { $0.right == 0 }.performs { _ in .success(12) } 208 | sut.sum.on { $0.right == -1 }.performs { _ in .failure(TestError()) } 209 | } 210 | context("when parameters matching filter") { 211 | it("should return call filter-based block") { 212 | expect(sut.sum(left: 0, right: 2)).to(sendValue(0)) 213 | expect(sut.sum(left: 15, right: 0)).to(sendValue(12)) 214 | expect(sut.sum(left: 15, right: -1)).to(fail(with: TestError())) 215 | } 216 | } 217 | context("when parameters don't match filters") { 218 | it("should call default stubbed block") { 219 | expect(sut.sum(left: 13, right: 2)).to(sendValue(11)) 220 | } 221 | } 222 | } 223 | 224 | context("when calling filtered stubbed with block method") { 225 | beforeEach { 226 | sut.sum.returns(.success(17)) 227 | sut.sum.on { $0.left == 12 }.performs { .success($0.left - $0.right) } 228 | sut.sum.on { $0.right == 42 }.performs { _ in .failure(TestError()) } 229 | } 230 | context("when parameters matching filter") { 231 | it("should return calculated with stub value") { 232 | expect(sut.sum(left: 12, right: 2)).to(sendValue(10)) 233 | expect(sut.sum(left: 12, right: 12)).to(sendValue(0)) 234 | expect(sut.sum(left: 42, right: 12)).to(fail(with: TestError())) 235 | } 236 | } 237 | context("when parameters don't match filters") { 238 | it("should return default stubbed value") { 239 | expect(sut.sum(left: 13, right: 2)).to(sendValue(17)) 240 | } 241 | } 242 | } 243 | } 244 | } 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /Example/Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Stanfy 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwiftyMock [![Build Status](https://travis-ci.org/stanfy/SwiftyMock.svg?branch=master)](https://travis-ci.org/stanfy/SwiftyMock) 2 | 3 | This repository contains helpers that make mocking, stubbing and spying in Swift much easier 4 | 5 | # Example 6 | 7 | ## Protocol 8 | Imagine you have some protocol that describes some behaviour 9 | 10 | ```swift 11 | protocol RoboKitten { 12 | func batteryStatus() -> Int 13 | func jump(x x: Int, y: Int) -> Int 14 | func canJumpAt(x x: Int, y: Int) -> Bool 15 | func rest(completed: Bool -> () ) 16 | } 17 | ``` 18 | 19 | ## Protocol usage 20 | And this protocol is used somewhere 21 | 22 | ```swift 23 | class RoboKittenController { 24 | let kitten: RoboKitten 25 | 26 | init(kitten: RoboKitten) { 27 | self.kitten = kitten 28 | } 29 | 30 | func jumpAt(x x: Int, y: Int) -> Result { 31 | if kitten.canJumpAt(x: x, y: y) { 32 | kitten.jump(x: x, y: y) 33 | return .SUCCESS 34 | } 35 | return .FAILURE 36 | } 37 | ... 38 | } 39 | ``` 40 | ## Protocol mock 41 | 42 | So now you want to test how protocol is used as a dependency 43 | And you create to create mock implementation of protocol 44 | And create fake calls for each method you want to test 45 | So here how it will look like in SwiftyMock 46 | 47 | ```swift 48 | class RoboKittenMock: RoboKitten { 49 | 50 | let batteryStatusCall = FunctionCall<(), Int>() 51 | func batteryStatus() -> Int { 52 | return stubCall(batteryStatusCall, argument:()) 53 | } 54 | 55 | let jumpCall = FunctionCall<(x: Int, y: Int), Int>() 56 | func jump(x x: Int, y: Int) -> Int { 57 | return stubCall(jumpCall, argument: (x: x, y: y)) 58 | } 59 | 60 | let canJumpAtCall = FunctionCall<(x: Int, y: Int), Bool>() 61 | func canJumpAt(x x: Int, y: Int) -> Bool { 62 | return stubCall(canJumpAtCall, argument: (x: x, y: y)) 63 | } 64 | 65 | let restCall = FunctionCall (), ()>() 66 | func rest(completed: Bool -> ()) { 67 | return stubCall(restCall, argument: completed, defaultValue: ()) 68 | } 69 | } 70 | ``` 71 | 72 | ## Mock usage 73 | If setup was correct it's really easy to specify mock behaviour by using subbed methods 74 | 75 | ### Method stub 76 | Let's say we want to our mock to return some values 77 | It's really easy 78 | ```swift 79 | // like this 80 | kittenMock.canJumpAtCall.returns(false) 81 | 82 | // or like this 83 | kittenMock.jumpCall.returns(20) 84 | ``` 85 | 86 | Sometimes, you have bit more complex rules when and what to return 87 | ```swift 88 | // You can add as many filters you like 89 | // More specific rules overrides general rules 90 | kittenMock.canJumpAtCall 91 | .on { $0.x < 0 }.returns(false) 92 | .on { $0.y < 0 }.returns(false) 93 | .returns(true) // in all other cases 94 | 95 | ``` 96 | 97 | And sometimes you need even more complex mock behaviour, when you need for example to pass closures into mock 98 | ```swift 99 | protocol RoboKitten { 100 | func rest(completed: Bool -> () ) 101 | } 102 | 103 | kittenMock.restCall.performs { completion in 104 | print("Mock method was called! Remove this in prod version:))") 105 | completion(true) 106 | } 107 | ``` 108 | 109 | ### Method call check 110 | Also from time to time, you need to be sure that method was called 111 | ```swift 112 | beforeEach { 113 | // Since canjump method need to return somtehing we need to specify return value 114 | kittenMock.canJumpAtCall.returns(false) 115 | } 116 | it("should ask kitten if it's available to jump there") { 117 | sut.jumpAt(x: 10, y: 20) 118 | expect(kittenMock.canJumpAtCall.called).to(beTruthy()) 119 | } 120 | ``` 121 | 122 | Or you need to check that method was called exact number of times 123 | ```swift 124 | it("should actually ask kitten to jump only once per call") { 125 | sut.jumpAt(x: 18, y: 23) 126 | expect(kittenMock.jumpCall.callsCount).to(equal(1)) 127 | 128 | sut.jumpAt(x: 80, y: 15) 129 | expect(kittenMock.jumpCall.callsCount).to(equal(2)) 130 | } 131 | ``` 132 | 133 | All method calls are stored in the mock, so you can easily check if mock was called with correct parameters 134 | ```swift 135 | it("should ask kitten if it's available to jump there with the same coords") { 136 | sut.jumpAt(x: 10, y: 20) 137 | expect(kittenMock.canJumpAtCall.capturedArgument?.x).to(equal(10)) 138 | expect(kittenMock.canJumpAtCall.capturedArgument?.y).to(equal(20)) 139 | } 140 | ``` 141 | 142 | ## [ReactiveSwift](https://github.com/ReactiveCocoa/ReactiveSwift) stubs support 143 | API for methods that return `SignalProducer` or `Action` is pretty much the same as for usual methods stubs. 144 | 145 | Imagine RoboKitten protocol is a bit changed and returns SignalProducer instead of plain value, so we can keep and eye on battery status level. 146 | 147 | ```swift 148 | protocol RoboKitten { 149 | func batteryStatus() -> SignalProducer 150 | } 151 | ``` 152 | 153 | Now you create mock implementation of this protocol, but instead of `FunctionCall`, you're using `ReactiveCall`. 154 | The only difference is that we've added third type constraint to specify `Error`. 155 | 156 | ```swift 157 | class RoboKittenMock: RoboKitten { 158 | let batteryStatusCall = ReactiveCall<(), Int, NoError>() 159 | func batteryStatus() -> SignalProducer { 160 | return stubCall(batteryStatusCall, argument:()) 161 | } 162 | } 163 | ``` 164 | 165 | ### Method stub 166 | Since `SignalProducer` is constrained by **Value** and **Error** types, we need to allow user to choose, which one to stub call with. 167 | Luckily there's handy [Result](https://github.com/antitypical/Result) type and its implementation comes along with [ReactiveSwift](https://github.com/ReactiveCocoa/ReactiveSwift). 168 | Thus in order to stub `ReactiveCall`, you use `Result` instead of plain value as you did with `FunctionCall`. 169 | 170 | ```swift 171 | // like this 172 | kittenMock.batteryStatusCall.returns(.success(42)) 173 | // or 174 | kittenMock.batteryStatusCall.returns(Result(value: 42)) 175 | 176 | // or in case you want this stub to return failure 177 | kittenMock.batteryStatusCall.returns(.failure(ImagineThisIsError)) 178 | // or 179 | kittenMock.batteryStatusCall.returns(Result(error: ImagineThisIsError)) 180 | ``` 181 | 182 | Everything else stays the same :) 183 | 184 | # Matchers 185 | SwiftyMock doesn't have its own matchers, so you can use whatever matchers suits better for you :) 186 | 187 | # Templates 188 | You can generate mocks automatically with [Sourcery](https://github.com/krzysztofzablocki/Sourcery). 189 | First, create sourcery config yml and specify paths to sources, templates, generated output and testable import framework for tests. 190 | You can take a look at how `.sourcery.yml` here in the root looks like. 191 | ```yml 192 | sources: 193 | - ./Example/SwiftyMock/RoboKitten 194 | templates: 195 | - ./SwiftyMock/Templates 196 | output: 197 | path: ./Example/RoboKittenTests/Mocks/Generated 198 | args: 199 | testable: SwiftyMock_Example # here you specify your application module name, that you're importing for testing 200 | ``` 201 | Second, annotate protocols that you want to generate mocks for, with `// sourcery: Mock` comment: 202 | ```swift 203 | // sourcery: Mock 204 | protocol RoboKitten { 205 | // ... 206 | } 207 | ``` 208 | Third, run sourcery command `sourcery --config .sourcery.yml --watch` if you want to run service that will regenerate mocks every time your source files or templates change. 209 | Or `sourcery --config .sourcery.yml` if you want to generate mocks once. 210 | -------------------------------------------------------------------------------- /SwiftyMock.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'SwiftyMock' 3 | s.version = '0.2.3' 4 | s.summary = 'Some helpers to do Mocking in Swift.' 5 | s.description = <<-DESC 6 | Some helpers to do Mocking in Swift. 7 | Mostly useful for mocking via protocols. Simple solution. Handles most of the cases. Easy setup 8 | DESC 9 | 10 | s.homepage = 'https://github.com/Stanfy/SwiftyMock' 11 | s.license = { :type => 'MIT', :file => 'LICENSE' } 12 | s.author = { 'Stanfy' => 'hello@stanfy.com' } 13 | s.source = { :git => 'https://github.com/Stanfy/SwiftyMock.git', :tag => s.version.to_s } 14 | 15 | s.ios.deployment_target = '8.0' 16 | 17 | s.default_subspec = 'Core' 18 | 19 | s.subspec 'Core' do |cs| 20 | cs.source_files = 'SwiftyMock/Classes/Core/**/*' 21 | end 22 | 23 | s.subspec 'ReactiveCocoa' do |rs| 24 | rs.dependency 'SwiftyMock/Core' 25 | rs.dependency 'ReactiveCocoa', '~> 7.1' 26 | rs.source_files = 'SwiftyMock/Classes/ReactiveCocoa/**/*' 27 | end 28 | 29 | s.subspec 'Templates' do |ts| 30 | ts.dependency 'SwiftyMock/Core' 31 | ts.resources = 'SwiftyMock/Templates/**/*' 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /SwiftyMock/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanfy/SwiftyMock/c08979526ad04aa544387646464d58a4c15d7626/SwiftyMock/Assets/.gitkeep -------------------------------------------------------------------------------- /SwiftyMock/Classes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanfy/SwiftyMock/c08979526ad04aa544387646464d58a4c15d7626/SwiftyMock/Classes/.gitkeep -------------------------------------------------------------------------------- /SwiftyMock/Classes/Core/MockUtils.swift: -------------------------------------------------------------------------------- 1 | // A handy Utility for manual function calls testing. 2 | // Since Swift doesn't provide any access to runtime yet, we have to manually mock, stub and spy our calls 3 | 4 | // swiftlint:disable line_length 5 | 6 | // MARK: - Function Call Mock/Stub/Spy 7 | 8 | open class FunctionCall { 9 | 10 | // Spying Call's passed Arguments 11 | 12 | open fileprivate(set) var callsCount: Int = 0 13 | open var called: Bool { 14 | return callsCount > 0 15 | } 16 | 17 | // Stubbing Call with predefined Value 18 | open fileprivate(set) var stubbedValue: Value? 19 | open func returns(_ value: Value) { 20 | stubbedValue = value 21 | } 22 | 23 | // Stubbing Call with prefefined logic 24 | open fileprivate(set) var stubbedBlock: ((Arg) -> Value)? 25 | open func performs(_ block: @escaping (Arg) -> Value) { 26 | stubbedBlock = block 27 | } 28 | 29 | open fileprivate(set) var capturedArguments: [Arg] = [] 30 | open var capturedArgument: Arg? { 31 | return capturedArguments.last 32 | } 33 | 34 | fileprivate(set) var stubbedBlocks: [ReturnStub] = [] 35 | 36 | open func on(_ filter: @escaping (Arg) -> Bool) -> ReturnContext { 37 | let stub = ReturnStub(filter: filter) 38 | stubbedBlocks += [stub] 39 | return ReturnContext(call: self, stub: stub) 40 | } 41 | 42 | public init() {} 43 | 44 | func capture(_ argument: Arg) { 45 | callsCount += 1 46 | capturedArguments += [argument] 47 | } 48 | } 49 | 50 | public func stubCall(_ call: FunctionCall, argument: Arg, defaultValue: Value? = nil) -> Value { 51 | call.capture(argument) 52 | 53 | for stub in call.stubbedBlocks { 54 | if stub.filter(argument) { 55 | if case let .some(stubbedBlock) = stub.stubbedBlock { 56 | return stubbedBlock(argument) 57 | } 58 | 59 | if case let .some(stubbedValue) = stub.stubbedValue { 60 | return stubbedValue 61 | } 62 | } 63 | } 64 | 65 | if case let .some(stubbedBlock) = call.stubbedBlock { 66 | return stubbedBlock(argument) 67 | } 68 | 69 | if case let .some(stubbedValue) = call.stubbedValue { 70 | return stubbedValue 71 | } 72 | 73 | if case let .some(defaultValue) = defaultValue { 74 | return defaultValue 75 | } 76 | 77 | assertionFailure("stub doesnt' have value to return") 78 | 79 | return call.stubbedValue! 80 | } 81 | 82 | // MARK: - Helpers for stubbing 83 | 84 | open class ReturnContext { 85 | let call: FunctionCall 86 | let stub: ReturnStub 87 | init(call: FunctionCall, stub: ReturnStub) { 88 | self.call = call 89 | self.stub = stub 90 | } 91 | 92 | @discardableResult open func returns(_ value: Value) -> FunctionCall { 93 | stub.stubbedValue = value 94 | return call 95 | } 96 | 97 | @discardableResult open func performs(_ block: @escaping ((Arg) -> Value)) -> FunctionCall { 98 | stub.stubbedBlock = block 99 | return call 100 | } 101 | } 102 | 103 | open class ReturnStub { 104 | let filter: (Arg) -> Bool 105 | fileprivate(set) var stubbedValue: Value? 106 | fileprivate(set) var stubbedBlock: ((Arg) -> Value)? 107 | 108 | init(filter: @escaping (Arg) -> Bool) { 109 | self.filter = filter 110 | } 111 | } 112 | 113 | // MARK: - Function Call Mock/Stub/Spy Without Arguments 114 | 115 | public typealias FunctionVoidCall = FunctionCall 116 | 117 | public func stubCall(_ call: FunctionVoidCall, defaultValue: Value? = nil) -> Value { 118 | return stubCall(call, argument: (), defaultValue: defaultValue) 119 | } 120 | -------------------------------------------------------------------------------- /SwiftyMock/Classes/ReactiveCocoa/ReactiveExtensions.swift: -------------------------------------------------------------------------------- 1 | // A handy Utility for manual function calls testing. 2 | // Since Swift doesn't provide any access to runtime yet, we have to manually mock, stub and spy our calls 3 | 4 | // swiftlint:disable line_length 5 | 6 | // MARK: Reactive Function Call Mock/Stub/Spy 7 | 8 | import ReactiveSwift 9 | import Result 10 | 11 | // MARK: - Reactive Call Mock/Stub/Spy 12 | 13 | public typealias ReactiveCall = FunctionCall> 14 | public typealias ReactiveVoidCall = FunctionVoidCall> 15 | 16 | // Stub Signal Producer Call 17 | 18 | public func stubCall(_ call: ReactiveCall, argument: Arg, defaultValue: Result? = nil) -> SignalProducer { 19 | 20 | // returning empty signal producer if no default value provide, thus preventing failure assert 21 | if call.stubbedBlocks.isEmpty && call.stubbedBlock == nil && call.stubbedValue == nil && defaultValue == nil { 22 | call.capture(argument) 23 | return .empty 24 | } 25 | 26 | // otherwise - just repeating normal function stubbing flow 27 | let result: Result = stubCall(call, argument: argument, defaultValue: defaultValue) 28 | 29 | // and returning signal producer depending on result value 30 | return SignalProducer(result: result) 31 | } 32 | 33 | // MARK: - Function Call Mock/Stub/Spy Without Arguments 34 | 35 | public func stubCall(_ call: ReactiveVoidCall, defaultValue: Result? = nil) -> SignalProducer { 36 | return stubCall(call, argument: (), defaultValue: defaultValue) 37 | } 38 | 39 | // MARK: - Stub Action Call 40 | 41 | public func stubCall(_ call: ReactiveVoidCall, defaultValue: Result? = nil) -> Action { 42 | return Action { 43 | stubCall(call, defaultValue: defaultValue) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /SwiftyMock/Templates/Mock.stencil: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SwiftyMock 3 | {% if argument.testable %}@testable import {{ argument.testable }}{% endif %} 4 | 5 | {% macro functionCallType method %}{% if method.parameters.count == 0 %}FunctionVoidCall{% else %}FunctionCall{% endif %}{% endmacro %} 6 | 7 | {% macro functionCallArgumentsType method %}{% if method.parameters.count == 1 %}{{ method.parameters.first.typeName.unwrappedTypeName }}{% else %}({% for param in method.parameters %}{{ param.name }}: {{ param.typeName.unwrappedTypeName }}{% if not forloop.last %}, {% endif %}{% endfor %}){% endif %}{% endmacro %} 8 | 9 | {% macro functionCallReturnType method %}{% if not method.returnTypeName.isVoid %}{{ method.returnTypeName }}{% else %}Void{% endif %}{% endmacro %} 10 | 11 | {% macro stubCallArguments method %}{% if method.parameters.count > 0 %}, argument: {% if method.parameters.count == 1 %}{{ method.parameters.first.name }}{% else %}({% for param in method.parameters %}{{ param.name }}: {{ param.name }}{% if not forloop.last %}, {% endif %}{% endfor %}){% endif %}{% endif %}{% endmacro %} 12 | 13 | {% macro mockVariableGetterCall variable %}let {{ variable.name }}GetCall = FunctionVoidCall<{{ variable.typeName }}>(){% endmacro %} 14 | {% macro mockVariableSetterCall variable %}let {{ variable.name }}SetCall = FunctionCall<{{ variable.typeName }}, Void>(){% endmacro %} 15 | 16 | {% macro mockVariable variable %} 17 | {% call mockVariableGetterCall variable %} 18 | {% if variable.isMutable %}{% call mockVariableSetterCall variable %}{% endif %} 19 | var {{ variable.name }}: {{ variable.typeName }} { 20 | get { return stubCall({{ variable.name }}GetCall) } 21 | {% if variable.isMutable %}set { stubCall({{ variable.name }}SetCall, argument: newValue) }{% endif %} 22 | } 23 | {% endmacro %} 24 | 25 | {% for type in types.protocols where type|annotated:"Mock" %} 26 | class Fake{{ type.name }}: {{ type.name }} { 27 | {% for variable in type.allVariables|!definedInExtension %} 28 | {% call mockVariable variable %} 29 | {% if not forloop.last %} 30 | 31 | {% endif %} 32 | {% endfor %} 33 | 34 | {% for method in type.allMethods|!definedInExtension %} 35 | let {{ method.shortName }}Call = {% call functionCallType method %}<{% if method.parameters.count > 0 %}{% call functionCallArgumentsType method %}, {% endif %}{% call functionCallReturnType method %}>() 36 | func {{ method.name }}{% if method.throws %} throws{% endif %}{% if not method.returnTypeName.isVoid %} -> {{ method.returnTypeName }}{% endif %} { 37 | return stubCall({{ method.shortName }}Call{% call stubCallArguments method %}{% if method.returnTypeName.isVoid %}, defaultValue: ()){% else %}){% endif %} 38 | } 39 | {% if not forloop.last %} 40 | 41 | {% endif %} 42 | {% endfor %} 43 | } 44 | {% if not forloop.last %} 45 | 46 | {% endif %} 47 | {% endfor %} 48 | -------------------------------------------------------------------------------- /_Pods.xcodeproj: -------------------------------------------------------------------------------- 1 | Example/Pods/Pods.xcodeproj --------------------------------------------------------------------------------