Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Generated using Sourcery 0.13.1 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 0.14.0 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT

import Foundation
Expand Down
4 changes: 4 additions & 0 deletions Example/SwiftyMock.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
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 */; };
D2E357F5213DE087009417DA /* SwiftyMockReactiveEventsCallsSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E357F4213DE087009417DA /* SwiftyMockReactiveEventsCallsSpec.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 */; };
Expand Down Expand Up @@ -63,6 +64,7 @@
D21AF4611FC62CFF00C0DC5F /* SwiftyMockReactiveCallsSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftyMockReactiveCallsSpec.swift; sourceTree = "<group>"; };
D21AF4641FC6324400C0DC5F /* ReactiveMatchers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactiveMatchers.swift; sourceTree = "<group>"; };
D2AEE57E20F9559000FF7DC8 /* Mock.generated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Mock.generated.swift; sourceTree = "<group>"; };
D2E357F4213DE087009417DA /* SwiftyMockReactiveEventsCallsSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftyMockReactiveEventsCallsSpec.swift; sourceTree = "<group>"; };
E434BE271D4AAE86000E7125 /* SwiftyMockCallsSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyMockCallsSpec.swift; sourceTree = "<group>"; };
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 = "<group>"; };
Expand Down Expand Up @@ -213,6 +215,7 @@
children = (
E434BE271D4AAE86000E7125 /* SwiftyMockCallsSpec.swift */,
D21AF4611FC62CFF00C0DC5F /* SwiftyMockReactiveCallsSpec.swift */,
D2E357F4213DE087009417DA /* SwiftyMockReactiveEventsCallsSpec.swift */,
D21AF4641FC6324400C0DC5F /* ReactiveMatchers.swift */,
);
path = Calls;
Expand Down Expand Up @@ -542,6 +545,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D2E357F5213DE087009417DA /* SwiftyMockReactiveEventsCallsSpec.swift in Sources */,
E434BE281D4AAE86000E7125 /* SwiftyMockCallsSpec.swift in Sources */,
D21AF4661FC638F200C0DC5F /* ReactiveMatchers.swift in Sources */,
D21AF4631FC62DF600C0DC5F /* SwiftyMockReactiveCallsSpec.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
147 changes: 123 additions & 24 deletions Example/Tests/Calls/ReactiveMatchers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,21 +137,12 @@ func sendEmptyValueAndComplete<T: SignalProducerConvertible>() -> Predicate<T> w
// MARK: - Complete

func complete<T: SignalProducerConvertible, V, E>() -> Predicate<T> where T.Value == V, T.Error == E {
return Predicate { (actualExpression: Expression<T>) throws -> PredicateResult in
var actualEvent: Signal<V, E>.Event?
var completed: Bool = false
let actualProducer = try actualExpression.evaluate()
actualProducer?.producer.start { event in
actualEvent = event
if case .completed = event {
completed = true
}
}
return PredicateResult(
bool: completed,
message: .expectedCustomValueTo("complete", message(forEvent: actualEvent))
return sendEvent(where: { $0.isCompleted }, expectation: { actualEvent in
.expectedCustomValueTo(
"complete",
message(forEvent: actualEvent)
)
}
})
}

// MARK: - Fail
Expand Down Expand Up @@ -224,38 +215,146 @@ func failWithNoError<T: SignalProducerConvertible>() -> Predicate<T> where T.Err
// MARK: - Interrupt

func interrupt<T: SignalProducerConvertible, V, E>() -> Predicate<T> where T.Value == V, T.Error == E {
return sendEvent(where: { $0.isInterrupted }, expectation: { actualEvent in
.expectedCustomValueTo(
"interrupt",
message(forEvent: actualEvent)
)
})
}

// MARK: - Event

private func sendEvent<T: SignalProducerConvertible, V, E>(
where predicate: @escaping (Signal<V, E>.Event) -> Bool,
expectation: @escaping (Signal<V, E>.Event?) -> ExpectationMessage
) -> Predicate<T> where T.Value == V, T.Error == E {
return Predicate { (actualExpression: Expression<T>) throws -> PredicateResult in
var actualEvent: Signal<V, E>.Event?
var interrupted: Bool = false
var satisfies: Bool = false
let actualProducer = try actualExpression.evaluate()
actualProducer?.producer.start { event in
actualEvent = event
if case .interrupted = event {
interrupted = true
}
satisfies = predicate(event)
}
return PredicateResult(
bool: interrupted,
message: .expectedCustomValueTo("interrupt", message(forEvent: actualEvent))
bool: satisfies,
message: expectation(actualEvent)
)
}
}

func sendEvent<T: SignalProducerConvertible, V, E>(where predicate: @escaping (Signal<V, E>.Event) -> Bool) -> Predicate<T> where T.Value == V, T.Error == E {
return sendEvent(where: predicate, expectation: { actualEvent in
.expectedCustomValueTo(
"send event to satisfy predicate",
message(forEvent: actualEvent)
)
})
}

func sendEvent<T: SignalProducerConvertible, V: Equatable, E: Equatable>(_ expectedEvent: Signal<V, E>.Event) -> Predicate<T> where T.Value == V, T.Error == E {
return sendEvent(where: { $0 == expectedEvent }, expectation: { actualEvent in
.expectedCustomValueTo(
"send " + message(forEvent: expectedEvent),
message(forEvent: actualEvent)
)
})
}

// MARK: - Events

private func sendEvents<T: SignalProducerConvertible, V, E>(
where predicate: @escaping ([Signal<V, E>.Event]) -> Bool,
expectation: @escaping ([Signal<V, E>.Event]) -> ExpectationMessage
) -> Predicate<T> where T.Value == V, T.Error == E {
return Predicate { (actualExpression: Expression<T>) throws -> PredicateResult in
var actualEvents: [Signal<V, E>.Event] = []
var satisfies: Bool = false
let actualProducer = try actualExpression.evaluate()
actualProducer?.producer
.on(event: { event in
actualEvents.append(event)
})
.on(terminated: {
satisfies = predicate(actualEvents)
})
.start()
return PredicateResult(
bool: satisfies,
message: expectation(actualEvents)
)
}
}

func sendEvents<T: SignalProducerConvertible, V, E>(where predicate: @escaping ([Signal<V, E>.Event]) -> Bool) -> Predicate<T> where T.Value == V, T.Error == E {
return sendEvents(where: predicate, expectation: { actualEvents in
.expectedCustomValueTo(
"send events to satisfy predicate",
message(forEvents: actualEvents)
)
})
}

func sendEvents<T: SignalProducerConvertible, V: Equatable, E: Equatable>(_ expectedEvents: [Signal<V, E>.Event]) -> Predicate<T> where T.Value == V, T.Error == E {
return sendEvents(where: { $0 == expectedEvents }, expectation: { actualEvents in
.expectedCustomValueTo(
"send " + message(forEvents: expectedEvents),
message(forEvents: actualEvents)
)
})
}

func sendEvents<T: SignalProducerConvertible, V, E>(whereAll predicate: @escaping (Signal<V, E>.Event) -> Bool) -> Predicate<T> where T.Value == V, T.Error == E {
return sendEvents(where: { events in !events.contains(where: { !predicate($0) }) }, expectation: { actualEvents in
.expectedCustomValueTo(
"send all events to satisfy predicate",
message(forEvents: actualEvents)
)
})
}

func sendEvents<T: SignalProducerConvertible, V, E>(whereAny predicate: @escaping (Signal<V, E>.Event) -> Bool) -> Predicate<T> where T.Value == V, T.Error == E {
return sendEvents(where: { events in events.contains(where: predicate) }, expectation: { actualEvents in
.expectedCustomValueTo(
"send at least one event to satisfy predicate",
message(forEvents: actualEvents)
)
})
}

// MARK: - Helpers

private func errorMatchesExpectedError<T: Error>(_ actualError: Error, expectedError: T) -> Bool {
fileprivate extension Signal.Event {
var isInterrupted: Bool {
if case .interrupted = event { return true }
return false
}
}

extension Signal.Event: Equatable where Signal.Value: Equatable, Signal.Error: Equatable {}

fileprivate func errorMatchesExpectedError<T: Error>(_ actualError: Error, expectedError: T) -> Bool {
return actualError._domain == expectedError._domain
&& actualError._code == expectedError._code
}

private func message<V, E>(forEvent event: Signal<V, E>.Event?) -> String {
fileprivate func message<V, E>(forEvents events: [Signal<V, E>.Event]?) -> String {
if let events = events {
let stringifiedEvents = events.map(stringify).joined(separator: ", ")
return "<[\(stringifiedEvents)]> events"
}
return "no events"
}

fileprivate func message<V, E>(forEvent event: Signal<V, E>.Event?) -> String {
if let event = event {
return "<\(stringify(event))> event"
}
return "no event"
}

private func message<V, E>(forEvent event: Signal<V, E>.Event?, value: V?) -> String {
fileprivate func message<V, E>(forEvent event: Signal<V, E>.Event?, value: V?) -> String {
if let event = event {
if case .value = event {
return "<\(stringify(value))> value"
Expand All @@ -265,7 +364,7 @@ private func message<V, E>(forEvent event: Signal<V, E>.Event?, value: V?) -> St
return "no event"
}

private func message<V, E>(forEvent event: Signal<V, E>.Event?, error: E?) -> String {
fileprivate func message<V, E>(forEvent event: Signal<V, E>.Event?, error: E?) -> String {
if let event = event {
if case .failed = event {
return "<\(stringify(error))> error"
Expand Down
4 changes: 2 additions & 2 deletions Example/Tests/Calls/SwiftyMockCallsSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import Quick
import Nimble
@testable import SwiftyMock

protocol Calculator {
fileprivate protocol Calculator {
func sum(left: Int, right: Int) -> Int
}

class TestCalculator: Calculator {
fileprivate class TestCalculator: Calculator {
let sum = FunctionCall<(left: Int, right: Int), Int>()
@discardableResult func sum(left: Int, right: Int) -> Int {
return stubCall(sum, argument: (left: left, right: right))
Expand Down
12 changes: 6 additions & 6 deletions Example/Tests/Calls/SwiftyMockReactiveCallsSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ import ReactiveSwift
import Result
@testable import SwiftyMock

protocol ReactiveCalculator {
fileprivate protocol ReactiveCalculator {
func sum(left: Int, right: Int) -> SignalProducer<Int, TestError>
}

class TestReactiveCalculator: ReactiveCalculator {
fileprivate class TestReactiveCalculator: ReactiveCalculator {
init() {}

let sum = ReactiveCall<(left: Int, right: Int), Int, TestError>()
Expand All @@ -26,7 +26,7 @@ class TestReactiveCalculator: ReactiveCalculator {
}
}

struct TestError: Error, Equatable {
fileprivate struct TestError: Error, Equatable {
let id: Int
init() { id = 0 }
init(id: Int) { self.id = id }
Expand Down Expand Up @@ -57,7 +57,7 @@ class SwiftyMockReactiveCallsSpec: QuickSpec {
}

context("when calling method before stubbing") {
fit("should return empty signal without any value") {
it("should return empty signal without any value") {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hehe

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, seems like we need Danger 😅

expect { sut.sum(left: 1,right: 2) }.to(complete())
}
}
Expand Down Expand Up @@ -224,8 +224,8 @@ class SwiftyMockReactiveCallsSpec: QuickSpec {
context("when calling filtered stubbed with block method") {
beforeEach {
sut.sum.returns(.success(17))
sut.sum.on { $0.left == 12 }.performs { .success($0.left - $0.right) }
sut.sum.on { $0.right == 42 }.performs { _ in .failure(TestError()) }
sut.sum.on { $0.left == 12 }.performs { .success($0.left - $0.right) }
sut.sum.on { $0.left == 42 }.performs { _ in .failure(TestError()) }
}
context("when parameters matching filter") {
it("should return calculated with stub value") {
Expand Down
Loading