Skip to content

Commit

Permalink
Migrate Quick/Nimble testing to XCTest
Browse files Browse the repository at this point in the history
[Tests] Remove Quick and Nimble in favor of XCTest
[Tests] Add multiple platform tests on Travis CI for swift 2.2 and 3
[Refactor] Remove broken Swift < 2.2 support
[Refactor] Replace duplicate swift 3 declarations with compatibility functions
[Docs] Add change log entry, document swift support and development
[Refactor] Move test descriptions into docblocks outside the functions
[Refactor] Test for fatalError with an internal shim
[Tests] Remove @testable where possible
  • Loading branch information
agentk committed Jul 23, 2016
1 parent 5050789 commit 9cdca55
Show file tree
Hide file tree
Showing 27 changed files with 1,095 additions and 901 deletions.
32 changes: 17 additions & 15 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,30 +1,29 @@
language: objective-c
osx_image: xcode7.3

branches:
except:
- gh-pages

before_install:
- brew update
- brew install carthage || brew outdated carthage || brew upgrade carthage
- carthage version

install:
- gem install xcpretty
- carthage bootstrap --no-use-binaries --platform Mac,iOS

env:
global:
- LC_CTYPE=en_US.UTF-8
- LANG=en_US.UTF-8
- FRAMEWORK_NAME="ReSwift"
- IOS_SDK=iphonesimulator9.3
- OSX_SDK=macosx10.11
- TVOS_SDK=appletvsimulator9.2
- WATCHOS_SDK=watchsimulator2.2
matrix:
- DESTINATION="OS=9.3,name=iPhone 6S Plus" SCHEME="iOS" SDK="$IOS_SDK" ACTION="test"
- UPDATE_DOCS="false"

matrix:
include:
- osx_image: xcode8
env: SCHEME="macOS" SDK="macosx10.12" DESTINATION="arch=x86_64"
- osx_image: xcode7.3
env: SCHEME="macOS" SDK="macosx10.11" DESTINATION="arch=x86_64" UPDATE_DOCS="true"
- osx_image: xcode7.3
env: SCHEME="iOS" SDK="iphonesimulator9.3" DESTINATION="OS=9.3,name=iPhone 6S Plus"
- osx_image: xcode7.3
env: SCHEME="tvOS" SDK="appletvsimulator9.2" DESTINATION="OS=9.2,name=Apple TV 1080p"

script:
- set -o pipefail
Expand All @@ -39,12 +38,15 @@ script:
ONLY_ACTIVE_ARCH=YES
GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES
GCC_GENERATE_TEST_COVERAGE_FILES=YES
"$ACTION"
test
| xcpretty -c

after_success:
- bash <(curl -s https://codecov.io/bash) -J ReSwift
- test $TRAVIS_PULL_REQUEST == "false" && test $TRAVIS_BRANCH == "master" && .scripts/update-gh-pages
- test $TRAVIS_PULL_REQUEST == "false" &&
test $TRAVIS_BRANCH == "master" &&
test $UPDATE_DOCS == "true" &&
.scripts/update-gh-pages

before_deploy:
- carthage build --no-skip-current
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
**Other**:

- Swift 3 preview compatibility, maintaining Swift 2 naming - (#126) @agentk
- Migrate Quick/Nimble testing to XCTest - (#127) @agentk

#2.0.0

Expand Down
2 changes: 0 additions & 2 deletions Cartfile.private

This file was deleted.

2 changes: 0 additions & 2 deletions Cartfile.resolved
Original file line number Diff line number Diff line change
@@ -1,2 +0,0 @@
github "Quick/Nimble" "v4.1.0"
github "Quick/Quick" "v0.9.2"
10 changes: 3 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ ReSwift is a [Redux](https://github.com/reactjs/redux)-like implementation of th

The ReSwift library is tiny - allowing users to dive into the code, understand every single line and [hopefully contribute](#contributing).

ReSwift also supports **Swift 2.2 through to Swift 3** without requiring you to make migration changes.

ReSwift is quickly growing beyond the core library, providing experimental extensions for routing and time traveling through past app states!

Excited? So are we 🎉
Expand Down Expand Up @@ -185,13 +187,7 @@ You can install ReSwift via [Carthage](https://github.com/Carthage/Carthage) by

# Checking out Source Code

After cloning this repository you need to use carthage to install testing frameworks that ReSwift depends on.

Due to an [issue in Nimble](https://github.com/Quick/Nimble/issues/213) at the moment, tvOS tests will fail if building Nimble / Quick from source. You can however install Nimble & Quick from binaries then rebuild OS X & iOS only. After checkout, run the following from the terminal:

```bash
carthage bootstrap && carthage bootstrap --no-use-binaries --platform ios,osx
```
ReSwift no longer has any carthage dependencies for development. Just checkout the project and run.

# Demo

Expand Down
207 changes: 77 additions & 130 deletions ReSwift.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ReSwift/CoreTypes/CombinedReducer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ public struct CombinedReducer: AnyReducer {
#else
return reducer._handleAction(action, state: currentState)
#endif
}!
}!
}
}
10 changes: 1 addition & 9 deletions ReSwift/CoreTypes/Reducer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,13 @@ public protocol AnyReducer {
}

public protocol Reducer: AnyReducer {
#if swift(>=2.2)
associatedtype ReducerStateType
#else
typealias ReducerStateType
#endif

func handleAction(action: Action, state: ReducerStateType?) -> ReducerStateType
}

extension Reducer {
public func _handleAction(action: Action, state: StateType?) -> StateType {
#if swift(>=3)
return withSpecificTypes(action: action, state: state, function: handleAction)
#else
return withSpecificTypes(action, state: state, function: handleAction)
#endif
return withSpecificTypes(action, state: state, function: handleAction)
}
}
128 changes: 61 additions & 67 deletions ReSwift/CoreTypes/Store.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class Store<State: StateType>: StoreType {

typealias SubscriptionType = Subscription<State>

// swiftlint:disable todo
// TODO: Setter should not be public; need way for store enhancers to modify appState anyway

/*private (set)*/ public var state: State! {
Expand Down Expand Up @@ -52,33 +53,24 @@ public class Store<State: StateType>: StoreType {
self.reducer = reducer

// Wrap the dispatch function with all middlewares
#if swift(>=3)
self.dispatchFunction = middleware
.reversed()
.reduce({ [unowned self] action in self._defaultDispatch(action: action) }) {
[weak self] dispatchFunction, middleware in
let getState = { self?.state }
return middleware(self?.dispatch, getState)(dispatchFunction)
}
#else
self.dispatchFunction = middleware
.reverse()
.reduce({ [unowned self] action in self._defaultDispatch(action) }) {
[weak self] dispatchFunction, middleware in
let getState = { self?.state }
return middleware(self?.dispatch, getState)(dispatchFunction)
}
#endif

self.dispatchFunction = middleware
.reversed()
.reduce({ [unowned self] action in
#if swift(>=3)
return self._defaultDispatch(action: action)
#else
return self._defaultDispatch(action)
#endif
}) {
[weak self] dispatchFunction, middleware in
let getState = { self?.state }
return middleware(self?.dispatch, getState)(dispatchFunction)
}

if let state = state {
self.state = state
} else {
#if swift(>=3)
dispatch(action: ReSwiftInit())
#else
dispatch(ReSwiftInit())
#endif
dispatch(ReSwiftInit())
}
}

Expand All @@ -91,61 +83,62 @@ public class Store<State: StateType>: StoreType {
return true
}

#if swift(>=3)
public func subscribe<S: StoreSubscriber
where S.StoreSubscriberStateType == State>(_ subscriber: S) {
subscribe(subscriber, selector: nil)
}
#else
public func subscribe<S: StoreSubscriber
where S.StoreSubscriberStateType == State>(subscriber: S) {
#if swift(>=3)
subscribe(subscriber: subscriber, selector: nil)
#else
subscribe(subscriber, selector: nil)
#endif
subscribe(subscriber, selector: nil)
}
#endif

#if swift(>=3)
public func subscribe<SelectedState, S: StoreSubscriber
where S.StoreSubscriberStateType == SelectedState>
(_ subscriber: S, selector: ((State) -> SelectedState)?) {
if !_isNewSubscriber(subscriber: subscriber) { return }

subscriptions.append(Subscription(subscriber: subscriber, selector: selector))

if let state = self.state {
subscriber._newState(state: selector?(state) ?? state)
}
}
#else
public func subscribe<SelectedState, S: StoreSubscriber
where S.StoreSubscriberStateType == SelectedState>
(subscriber: S, selector: ((State) -> SelectedState)?) {
#if swift(>=3)
if !_isNewSubscriber(subscriber: subscriber) { return }
#else
if !_isNewSubscriber(subscriber) { return }
#endif
if !_isNewSubscriber(subscriber) { return }

subscriptions.append(Subscription(subscriber: subscriber, selector: selector))

if let state = self.state {
#if swift(>=3)
subscriber._newState(state: selector?(state) ?? state)
#else
subscriber._newState(selector?(state) ?? state)
#endif
subscriber._newState(selector?(state) ?? state)
}
}
#endif

#if swift(>=3)
public func unsubscribe(_ subscriber: AnyStoreSubscriber) {
if let index = subscriptions.index(where: { return $0.subscriber === subscriber }) {
subscriptions.remove(at: index)
}
}
#else
public func unsubscribe(subscriber: AnyStoreSubscriber) {
#if swift(>=3)
if let index = subscriptions.index(where: { return $0.subscriber === subscriber }) {
subscriptions.remove(at: index)
}
#else
if let index = subscriptions.indexOf({ return $0.subscriber === subscriber }) {
subscriptions.removeAtIndex(index)
}
#endif
if let index = subscriptions.indexOf({ return $0.subscriber === subscriber }) {
subscriptions.removeAtIndex(index)
}
}
#endif

public func _defaultDispatch(action: Action) -> Any {
if isDispatching {
// Use Obj-C exception since throwing of exceptions can be verified through tests
#if swift(>=3)
NSException.raise(
"ReSwift:IllegalDispatchFromReducer" as NSExceptionName,
format: "Reducers may not dispatch actions.",
arguments: getVaList(["nil"]))
#else
NSException.raise(
"ReSwift:IllegalDispatchFromReducer",
format: "Reducers may not dispatch actions.",
arguments: getVaList(["nil"]))
#endif
guard !isDispatching else {
raiseFatalError(
"ReSwift:IllegalDispatchFromReducer - Reducers may not dispatch actions.")
}

isDispatching = true
Expand All @@ -163,7 +156,7 @@ public class Store<State: StateType>: StoreType {

#if swift(>=3)
@discardableResult
public func dispatch(action: Action) -> Any {
public func dispatch(_ action: Action) -> Any {
let returnValue = dispatchFunction(action)

return returnValue
Expand All @@ -177,11 +170,12 @@ public class Store<State: StateType>: StoreType {
#endif

#if swift(>=3)
public func dispatch(actionCreator actionCreatorProvider: ActionCreator) -> Any {
@discardableResult
public func dispatch(_ actionCreatorProvider: ActionCreator) -> Any {
let action = actionCreatorProvider(state: state, store: self)

if let action = action {
dispatch(action: action)
dispatch(action)
}

return action
Expand All @@ -199,8 +193,8 @@ public class Store<State: StateType>: StoreType {
#endif

#if swift(>=3)
public func dispatch(asyncActionCreator asyncActionCreatorProvider: AsyncActionCreator) {
dispatch(asyncActionCreator: asyncActionCreatorProvider, callback: nil)
public func dispatch(_ asyncActionCreatorProvider: AsyncActionCreator) {
dispatch(asyncActionCreatorProvider, callback: nil)
}
#else
public func dispatch(asyncActionCreatorProvider: AsyncActionCreator) {
Expand All @@ -209,13 +203,13 @@ public class Store<State: StateType>: StoreType {
#endif

#if swift(>=3)
public func dispatch(asyncActionCreator actionCreatorProvider: AsyncActionCreator,
public func dispatch(_ actionCreatorProvider: AsyncActionCreator,
callback: DispatchCallback?) {
actionCreatorProvider(state: state, store: self) { actionProvider in
let action = actionProvider(state: self.state, store: self)

if let action = action {
self.dispatch(action: action)
self.dispatch(action)
callback?(self.state)
}
}
Expand Down
4 changes: 0 additions & 4 deletions ReSwift/CoreTypes/StoreSubscriber.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,7 @@ public protocol AnyStoreSubscriber: class {
}

public protocol StoreSubscriber: AnyStoreSubscriber {
#if swift(>=2.2)
associatedtype StoreSubscriberStateType
#else
typealias StoreSubscriberStateType
#endif

func newState(state: StoreSubscriberStateType)
}
Expand Down
Loading

0 comments on commit 9cdca55

Please sign in to comment.