diff --git a/.sourcery.yml b/.sourcery.yml new file mode 100644 index 0000000..14a516c --- /dev/null +++ b/.sourcery.yml @@ -0,0 +1,8 @@ +sources: + - ./Example/SwiftyMock/RoboKitten +templates: + - ./SwiftyMock/Templates +output: + path: ./Example/RoboKittenTests/Mocks/Generated +args: + testable: SwiftyMock_Example \ No newline at end of file diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 4ab2d25..db50129 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -41,8 +41,8 @@ SPEC CHECKSUMS: ReactiveCocoa: 105ad96f6b8711f1ee7d165fc96587479298053b ReactiveSwift: 5b26d2e988fe0eed2daf48c4054d1de74db50184 Result: d2d07204ce72856f1fd9130bbe42c35a7b0fea10 - SwiftyMock: e0769d7dff9328adf0af2f977c98d861486393d5 + SwiftyMock: 7ee122cdeb33302fff589ad3400085f464ccd292 -PODFILE CHECKSUM: 2797c28d14fe41b5fd500d37769a81dfd8a59430 +PODFILE CHECKSUM: 96e31c8bbe54905dd223cce795d28a49935d24a1 COCOAPODS: 1.5.3 diff --git a/Example/RoboKittenTests/Mocks/Generated/Mock.generated.swift b/Example/RoboKittenTests/Mocks/Generated/Mock.generated.swift new file mode 100644 index 0000000..9fe0dc2 --- /dev/null +++ b/Example/RoboKittenTests/Mocks/Generated/Mock.generated.swift @@ -0,0 +1,58 @@ +// Generated using Sourcery 0.13.1 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT + +import Foundation +import SwiftyMock +@testable import SwiftyMock_Example + +class FakeLazyRoboKitten: LazyRoboKitten { + let needsRestGetCall = FunctionVoidCall() + let needsRestSetCall = FunctionCall() + var needsRest: Bool { + get { return stubCall(needsRestGetCall) } + set { stubCall(needsRestSetCall, argument: newValue) } + } + + let batteryStatusCall = FunctionVoidCall() + func batteryStatus() -> Int { + return stubCall(batteryStatusCall) + } + + let jumpCall = FunctionCall<(x: Int, y: Int), Void>() + func jump(x: Int, y: Int) { + return stubCall(jumpCall, argument: (x: x, y: y), defaultValue: ()) + } + + let canJumpAtCall = FunctionCall<(x: Int, y: Int), Bool>() + func canJumpAt(x: Int, y: Int) -> Bool { + return stubCall(canJumpAtCall, argument: (x: x, y: y)) + } + + let restCall = FunctionCall<(Bool) -> (), Void>() + func rest(_ completed: @escaping (Bool) -> ()) { + return stubCall(restCall, argument: completed, defaultValue: ()) + } +} + +class FakeRoboKitten: RoboKitten { + + let batteryStatusCall = FunctionVoidCall() + func batteryStatus() -> Int { + return stubCall(batteryStatusCall) + } + + let jumpCall = FunctionCall<(x: Int, y: Int), Void>() + func jump(x: Int, y: Int) { + return stubCall(jumpCall, argument: (x: x, y: y), defaultValue: ()) + } + + let canJumpAtCall = FunctionCall<(x: Int, y: Int), Bool>() + func canJumpAt(x: Int, y: Int) -> Bool { + return stubCall(canJumpAtCall, argument: (x: x, y: y)) + } + + let restCall = FunctionCall<(Bool) -> (), Void>() + func rest(_ completed: @escaping (Bool) -> ()) { + return stubCall(restCall, argument: completed, defaultValue: ()) + } +} diff --git a/Example/RoboKittenTests/Mocks/RoboKittenMock.swift b/Example/RoboKittenTests/Mocks/RoboKittenMock.swift deleted file mode 100644 index 6882a23..0000000 --- a/Example/RoboKittenTests/Mocks/RoboKittenMock.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// Created by Paul Taykalo on 7/31/16. -// Copyright (c) 2016 CocoaPods. All rights reserved. -// - -import Foundation -import SwiftyMock -@testable import SwiftyMock_Example - -class RoboKittenMock: RoboKitten { - - let batteryStatusCall = FunctionCall<(), Int>() - func batteryStatus() -> Int { - return stubCall(batteryStatusCall, argument:()) - } - - let jump = FunctionCall<(x: Int, y: Int), ()>() - func jump(x: Int, y: Int) { - return stubCall(jump, argument: (x: x, y: y), defaultValue:()) - } - - let canJump = FunctionCall<(x: Int, y: Int), Bool>() - func canJumpAt(x: Int, y: Int) -> Bool { - return stubCall(canJump, argument: (x: x, y: y)) - } - - let rest = FunctionCall<(Bool) -> (), ()>() - func rest(_ completed: @escaping (Bool) -> ()) { - stubCall(rest, argument: completed, defaultValue: ()) -// return stubCall(restCall, argument: completed, defaultValue: ()) - } - -} diff --git a/Example/RoboKittenTests/RoboKittenControllerSpec.swift b/Example/RoboKittenTests/RoboKittenControllerSpec.swift index 2b84daf..4fa9e24 100644 --- a/Example/RoboKittenTests/RoboKittenControllerSpec.swift +++ b/Example/RoboKittenTests/RoboKittenControllerSpec.swift @@ -17,9 +17,9 @@ class RoboKittenControllerSpec: QuickSpec { override func spec() { describe("RoboKittenController") { var sut: RoboKittenController! - var kittenMock: RoboKittenMock! + var kittenMock: FakeRoboKitten! beforeEach { - kittenMock = RoboKittenMock() + kittenMock = FakeRoboKitten() sut = RoboKittenController(kitten: kittenMock) } @@ -47,36 +47,36 @@ class RoboKittenControllerSpec: QuickSpec { describe("when asked to jump somewhere") { beforeEach { - kittenMock.canJump.returns(false) + kittenMock.canJumpAtCall.returns(false) } it("should ask kitten if it's available to jump there") { sut.jumpAt(x: 10, y: 20) - expect(kittenMock.canJump.called).to(beTruthy()) + expect(kittenMock.canJumpAtCall.called).to(beTruthy()) } it("should ask kitten if it's available to jump there with the same coords") { sut.jumpAt(x: 10, y: 20) - expect(kittenMock.canJump.capturedArgument?.x).to(equal(10)) - expect(kittenMock.canJump.capturedArgument?.y).to(equal(20)) + expect(kittenMock.canJumpAtCall.capturedArgument?.x).to(equal(10)) + expect(kittenMock.canJumpAtCall.capturedArgument?.y).to(equal(20)) } context("and kitten can jump there") { beforeEach { - kittenMock.canJump.returns(true) + kittenMock.canJumpAtCall.returns(true) } it("should actually ask kitten to jump") { sut.jumpAt(x: 15, y: 30) - expect(kittenMock.jump.called).to(beTruthy()) - expect(kittenMock.jump.capturedArgument?.x).to(equal(15)) - expect(kittenMock.jump.capturedArgument?.y).to(equal(30)) + expect(kittenMock.jumpCall.called).to(beTruthy()) + expect(kittenMock.jumpCall.capturedArgument?.x).to(equal(15)) + expect(kittenMock.jumpCall.capturedArgument?.y).to(equal(30)) } it("should actually ask kitten to jump only once per call") { sut.jumpAt(x: 18, y: 23) - expect(kittenMock.jump.callsCount).to(equal(1)) + expect(kittenMock.jumpCall.callsCount).to(equal(1)) sut.jumpAt(x: 80, y: 15) - expect(kittenMock.jump.callsCount).to(equal(2)) + expect(kittenMock.jumpCall.callsCount).to(equal(2)) } it("return success result") { @@ -86,12 +86,12 @@ class RoboKittenControllerSpec: QuickSpec { context("and kitten cannot jump there") { beforeEach { - kittenMock.canJump.returns(false) + kittenMock.canJumpAtCall.returns(false) } it("should shouldn't ask kitten to jump") { sut.jumpAt(x: 15, y: 30) - expect(kittenMock.jump.called).to(beFalsy()) + expect(kittenMock.jumpCall.called).to(beFalsy()) } it("shouldreturn failure result") { expect(sut.jumpAt(x: 10, y: 20)).to(equal(Result.failure)) @@ -103,7 +103,7 @@ class RoboKittenControllerSpec: QuickSpec { describe("when asked to perform multiple jumps") { context("and kitten can perform all of them") { beforeEach { - kittenMock.canJump.returns(true) + kittenMock.canJumpAtCall.returns(true) } it("should return success result") { expect(sut.jump(inSequence: [(x: 10, y: 20), (x: 12, y: 20)])).to(equal(Result.success)) @@ -112,21 +112,21 @@ class RoboKittenControllerSpec: QuickSpec { it("should call jump on each passed parameter in the correct order") { let sequence = [(x: 15, y: 21), (x: 23, y: 21)] sut.jump(inSequence: sequence) - expect(kittenMock.jump.callsCount).to(equal(2)) - expect(kittenMock.jump.capturedArguments[0].x).to(equal(15)) - expect(kittenMock.jump.capturedArguments[0].y).to(equal(21)) + expect(kittenMock.jumpCall.callsCount).to(equal(2)) + expect(kittenMock.jumpCall.capturedArguments[0].x).to(equal(15)) + expect(kittenMock.jumpCall.capturedArguments[0].y).to(equal(21)) - expect(kittenMock.jump.capturedArguments[1].x).to(equal(23)) - expect(kittenMock.jump.capturedArguments[1].y).to(equal(21)) + expect(kittenMock.jumpCall.capturedArguments[1].x).to(equal(23)) + expect(kittenMock.jumpCall.capturedArguments[1].y).to(equal(21)) } } context("And kitten can not jump at some coordinates") { beforeEach { - kittenMock.canJump + kittenMock.canJumpAtCall .on { $0.x < 0 }.returns(false) .on { $0.y < 0 }.returns(false) - .returns(true) // in all other cases + .returns(true) // in all other cases } context("and there are some coordinates where kitten cannot jump at in passed in sequence") { @@ -139,7 +139,7 @@ class RoboKittenControllerSpec: QuickSpec { it("should not ask kitten to jump at all") { sut.jump(inSequence: [(x: -10, y: 20), (x: 12, y: 20)]) - expect(kittenMock.jump.called).to(beFalsy()) + expect(kittenMock.jumpCall.called).to(beFalsy()) } } @@ -155,12 +155,12 @@ class RoboKittenControllerSpec: QuickSpec { it("should ask kitten to rest") { sut.rest { _ in } - expect(kittenMock.rest.called).to(beTruthy()) + expect(kittenMock.restCall.called).to(beTruthy()) } context("and kitten rests successfully") { beforeEach { - kittenMock.rest.performs { completion in + kittenMock.restCall.performs { completion in completion(true) } } @@ -175,7 +175,7 @@ class RoboKittenControllerSpec: QuickSpec { context("and kitten fails to rest") { beforeEach { - kittenMock.rest.performs { completion in + kittenMock.restCall.performs { completion in completion(false) } } diff --git a/Example/SwiftyMock.xcodeproj/project.pbxproj b/Example/SwiftyMock.xcodeproj/project.pbxproj index 6ce75c7..23bd88c 100644 --- a/Example/SwiftyMock.xcodeproj/project.pbxproj +++ b/Example/SwiftyMock.xcodeproj/project.pbxproj @@ -17,12 +17,12 @@ A7D119AA1D500828F6B64159 /* Pods_RoboKittenTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A380849D11951D85498E493C /* Pods_RoboKittenTests.framework */; }; D21AF4631FC62DF600C0DC5F /* SwiftyMockReactiveCallsSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21AF4611FC62CFF00C0DC5F /* SwiftyMockReactiveCallsSpec.swift */; }; D21AF4661FC638F200C0DC5F /* ReactiveMatchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21AF4641FC6324400C0DC5F /* ReactiveMatchers.swift */; }; + D2AEE57F20F9559000FF7DC8 /* Mock.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2AEE57E20F9559000FF7DC8 /* Mock.generated.swift */; }; E434BE281D4AAE86000E7125 /* SwiftyMockCallsSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = E434BE271D4AAE86000E7125 /* SwiftyMockCallsSpec.swift */; }; E481D6901D4DDE61000E73AE /* RoboKittenControllerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = E481D68F1D4DDE61000E73AE /* RoboKittenControllerSpec.swift */; }; EEDBE358155D115C15126670 /* RoboKitten.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEDBEBCC4DF10B0C24246892 /* RoboKitten.swift */; }; EEDBE98564CE5D2A54750BFD /* RoboKittenV1.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEDBE0C70C380389995EB816 /* RoboKittenV1.swift */; }; EEDBEAB8D9887C15ED1D0632 /* RoboKittenController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEDBE8EC7249C454D04FB152 /* RoboKittenController.swift */; }; - EEDBED3915A12D3BF5C227B3 /* RoboKittenMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEDBEDBDEDE79BAF07F7038A /* RoboKittenMock.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -62,6 +62,7 @@ BE3E75F38E5B31874FC7F8C4 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; D21AF4611FC62CFF00C0DC5F /* SwiftyMockReactiveCallsSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftyMockReactiveCallsSpec.swift; sourceTree = ""; }; D21AF4641FC6324400C0DC5F /* ReactiveMatchers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactiveMatchers.swift; sourceTree = ""; }; + D2AEE57E20F9559000FF7DC8 /* Mock.generated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Mock.generated.swift; sourceTree = ""; }; E434BE271D4AAE86000E7125 /* SwiftyMockCallsSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyMockCallsSpec.swift; sourceTree = ""; }; E481D6831D4DDDBE000E73AE /* RoboKittenTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RoboKittenTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; E481D6871D4DDDBE000E73AE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -70,7 +71,6 @@ EEDBE0C70C380389995EB816 /* RoboKittenV1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoboKittenV1.swift; sourceTree = ""; }; EEDBE8EC7249C454D04FB152 /* RoboKittenController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoboKittenController.swift; sourceTree = ""; }; EEDBEBCC4DF10B0C24246892 /* RoboKitten.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoboKitten.swift; sourceTree = ""; }; - EEDBEDBDEDE79BAF07F7038A /* RoboKittenMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoboKittenMock.swift; sourceTree = ""; }; F2E0186E90C589DC306B4DE9 /* Pods_SwiftyMock_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwiftyMock_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 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 = ""; }; 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 = ""; }; @@ -187,6 +187,14 @@ name = Frameworks; sourceTree = ""; }; + D2AEE57D20F9559000FF7DC8 /* Generated */ = { + isa = PBXGroup; + children = ( + D2AEE57E20F9559000FF7DC8 /* Mock.generated.swift */, + ); + path = Generated; + sourceTree = ""; + }; D5147DA4ACDB782F513D0F5D /* Pods */ = { isa = PBXGroup; children = ( @@ -223,7 +231,7 @@ EEDBE0EC744C4D09DA6A1963 /* Mocks */ = { isa = PBXGroup; children = ( - EEDBEDBDEDE79BAF07F7038A /* RoboKittenMock.swift */, + D2AEE57D20F9559000FF7DC8 /* Generated */, ); path = Mocks; sourceTree = ""; @@ -544,8 +552,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + D2AEE57F20F9559000FF7DC8 /* Mock.generated.swift in Sources */, E481D6901D4DDE61000E73AE /* RoboKittenControllerSpec.swift in Sources */, - EEDBED3915A12D3BF5C227B3 /* RoboKittenMock.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Example/SwiftyMock/RoboKitten/RoboKitten.swift b/Example/SwiftyMock/RoboKitten/RoboKitten.swift index a5496f7..fcd8220 100644 --- a/Example/SwiftyMock/RoboKitten/RoboKitten.swift +++ b/Example/SwiftyMock/RoboKitten/RoboKitten.swift @@ -5,9 +5,15 @@ import Foundation +// sourcery: Mock protocol RoboKitten { @discardableResult func batteryStatus() -> Int func jump(x: Int, y: Int) @discardableResult func canJumpAt(x: Int, y: Int) -> Bool - func rest(_ completed: @escaping (Bool) -> () ) + func rest(_ completed: @escaping (Bool) -> ()) } + +// sourcery: Mock +protocol LazyRoboKitten: RoboKitten { + var needsRest: Bool { get set } +} \ No newline at end of file diff --git a/README.md b/README.md index e59b34a..c321d86 100644 --- a/README.md +++ b/README.md @@ -52,19 +52,19 @@ class RoboKittenMock: RoboKitten { return stubCall(batteryStatusCall, argument:()) } - let jump = FunctionCall<(x: Int, y: Int), Int>() + let jumpCall = FunctionCall<(x: Int, y: Int), Int>() func jump(x x: Int, y: Int) -> Int { - return stubCall(jump, argument: (x: x, y: y)) + return stubCall(jumpCall, argument: (x: x, y: y)) } - let canJump = FunctionCall<(x: Int, y: Int), Bool>() + let canJumpAtCall = FunctionCall<(x: Int, y: Int), Bool>() func canJumpAt(x x: Int, y: Int) -> Bool { - return stubCall(canJump, argument: (x: x, y: y)) + return stubCall(canJumpAtCall, argument: (x: x, y: y)) } - let rest = FunctionCall (), ()>() + let restCall = FunctionCall (), ()>() func rest(completed: Bool -> ()) { - return stubCall(rest, argument: completed, defaultValue: ()) + return stubCall(restCall, argument: completed, defaultValue: ()) } } ``` @@ -77,20 +77,20 @@ Let's say we want to our mock to return some values It's really easy ```swift // like this -kittenMock.canJump.returns(false) +kittenMock.canJumpAtCall.returns(false) // or like this -kittenMock.jump.returns(20) +kittenMock.jumpCall.returns(20) ``` Sometimes, you have bit more complex rules when and what to return ```swift // You can add as many filters you like // More specific rules overrides general rules -kittenMock.canJump +kittenMock.canJumpAtCall .on { $0.x < 0 }.returns(false) .on { $0.y < 0 }.returns(false) - .returns(true) // in all other cases + .returns(true) // in all other cases ``` @@ -100,7 +100,7 @@ protocol RoboKitten { func rest(completed: Bool -> () ) } -kittenMock.rest.performs { completion in +kittenMock.restCall.performs { completion in print("Mock method was called! Remove this in prod version:))") completion(true) } @@ -111,11 +111,11 @@ Also from time to time, you need to be sure that method was called ```swift beforeEach { // Since canjump method need to return somtehing we need to specify return value - kittenMock.canJump.returns(false) + kittenMock.canJumpAtCall.returns(false) } it("should ask kitten if it's available to jump there") { sut.jumpAt(x: 10, y: 20) - expect(kittenMock.canJump.called).to(beTruthy()) + expect(kittenMock.canJumpAtCall.called).to(beTruthy()) } ``` @@ -123,10 +123,10 @@ Or you need to check that method was called exact number of times ```swift it("should actually ask kitten to jump only once per call") { sut.jumpAt(x: 18, y: 23) - expect(kittenMock.jump.callsCount).to(equal(1)) + expect(kittenMock.jumpCall.callsCount).to(equal(1)) sut.jumpAt(x: 80, y: 15) - expect(kittenMock.jump.callsCount).to(equal(2)) + expect(kittenMock.jumpCall.callsCount).to(equal(2)) } ``` @@ -134,8 +134,8 @@ All method calls are stored in the mock, so you can easily check if mock was cal ```swift it("should ask kitten if it's available to jump there with the same coords") { sut.jumpAt(x: 10, y: 20) - expect(kittenMock.canJump.capturedArgument?.x).to(equal(10)) - expect(kittenMock.canJump.capturedArgument?.y).to(equal(20)) + expect(kittenMock.canJumpAtCall.capturedArgument?.x).to(equal(10)) + expect(kittenMock.canJumpAtCall.capturedArgument?.y).to(equal(20)) } ``` @@ -182,4 +182,28 @@ kittenMock.batteryStatusCall.returns(Result(error: ImagineThisIsError)) Everything else stays the same :) # Matchers -SwiftyMock doesn't have it's own matchers, so you can use whatever matchers suits better for you :) +SwiftyMock doesn't have its own matchers, so you can use whatever matchers suits better for you :) + +# Templates +You can generate mocks automatically with [Sourcery](https://github.com/krzysztofzablocki/Sourcery). +First, create sourcery config yml and specify paths to sources, templates, generated output and testable import framework for tests. +You can take a look at how `.sourcery.yml` here in the root looks like. +```yml +sources: + - ./Example/SwiftyMock/RoboKitten +templates: + - ./SwiftyMock/Templates +output: + path: ./Example/RoboKittenTests/Mocks/Generated +args: + testable: SwiftyMock_Example # here you specify your application module name, that you're importing for testing +``` +Second, annotate protocols that you want to generate mocks for, with `// sourcery: Mock` comment: +```swift +// sourcery: Mock +protocol RoboKitten { + // ... +} +``` +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. +Or `sourcery --config .sourcery.yml` if you want to generate mocks once. diff --git a/SwiftyMock.podspec b/SwiftyMock.podspec index 1b5e423..40908ab 100644 --- a/SwiftyMock.podspec +++ b/SwiftyMock.podspec @@ -26,4 +26,8 @@ Pod::Spec.new do |s| rs.source_files = 'SwiftyMock/Classes/ReactiveCocoa/**/*' end + s.subspec 'Templates' do |ts| + ts.dependency 'SwiftyMock/Core' + ts.resources = 'SwiftyMock/Templates/**/*' + end end diff --git a/SwiftyMock/Templates/Mock.stencil b/SwiftyMock/Templates/Mock.stencil new file mode 100644 index 0000000..7a1115d --- /dev/null +++ b/SwiftyMock/Templates/Mock.stencil @@ -0,0 +1,47 @@ +import Foundation +import SwiftyMock +{% if argument.testable %}@testable import {{ argument.testable }}{% endif %} + +{% macro functionCallType method %}{% if method.parameters.count == 0 %}FunctionVoidCall{% else %}FunctionCall{% endif %}{% endmacro %} + +{% 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 %} + +{% macro functionCallReturnType method %}{% if not method.returnTypeName.isVoid %}{{ method.returnTypeName }}{% else %}Void{% endif %}{% endmacro %} + +{% 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 %} + +{% macro mockVariableGetterCall variable %}let {{ variable.name }}GetCall = FunctionVoidCall<{{ variable.typeName }}>(){% endmacro %} +{% macro mockVariableSetterCall variable %}let {{ variable.name }}SetCall = FunctionCall<{{ variable.typeName }}, Void>(){% endmacro %} + +{% macro mockVariable variable %} + {% call mockVariableGetterCall variable %} + {% if variable.isMutable %}{% call mockVariableSetterCall variable %}{% endif %} + var {{ variable.name }}: {{ variable.typeName }} { + get { return stubCall({{ variable.name }}GetCall) } + {% if variable.isMutable %}set { stubCall({{ variable.name }}SetCall, argument: newValue) }{% endif %} + } +{% endmacro %} + +{% for type in types.protocols where type|annotated:"Mock" %} +class Fake{{ type.name }}: {{ type.name }} { + {% for variable in type.allVariables|!definedInExtension %} + {% call mockVariable variable %} + {% if not forloop.last %} + + {% endif %} + {% endfor %} + + {% for method in type.allMethods|!definedInExtension %} + let {{ method.shortName }}Call = {% call functionCallType method %}<{% if method.parameters.count > 0 %}{% call functionCallArgumentsType method %}, {% endif %}{% call functionCallReturnType method %}>() + func {{ method.name }}{% if method.throws %} throws{% endif %}{% if not method.returnTypeName.isVoid %} -> {{ method.returnTypeName }}{% endif %} { + return stubCall({{ method.shortName }}Call{% call stubCallArguments method %}{% if method.returnTypeName.isVoid %}, defaultValue: ()){% else %}){% endif %} + } + {% if not forloop.last %} + + {% endif %} + {% endfor %} +} +{% if not forloop.last %} + +{% endif %} +{% endfor %}