Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ReducerProtocol] - Support Non-Dependencies Environment in ReducerProtocol #97

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
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
91 changes: 51 additions & 40 deletions Sources/RxComposableArchitecture/TestSupport/TestStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -487,46 +487,12 @@ public final class TestStore<State, Action, ScopedState, ScopedAction, Environme
/// // ...
/// }
/// ```
@available(
iOS,
deprecated: 9999,
message:
"""
'Reducer' and `Environment` have been deprecated in favor of 'ReducerProtocol' and 'DependencyValues'.

See the migration guide for more information: https://pointfreeco.github.io/swift-composable-architecture/main/documentation/composablearchitecture/reducerprotocol
"""
)
@available(
macOS,
deprecated: 9999,
message:
"""
'Reducer' and `Environment` have been deprecated in favor of 'ReducerProtocol' and 'DependencyValues'.

See the migration guide for more information: https://pointfreeco.github.io/swift-composable-architecture/main/documentation/composablearchitecture/reducerprotocol
"""
)
@available(
tvOS,
deprecated: 9999,
message:
"""
'Reducer' and `Environment` have been deprecated in favor of 'ReducerProtocol' and 'DependencyValues'.

See the migration guide for more information: https://pointfreeco.github.io/swift-composable-architecture/main/documentation/composablearchitecture/reducerprotocol
"""
)
@available(
watchOS,
deprecated: 9999,
message:
"""
'Reducer' and `Environment` have been deprecated in favor of 'ReducerProtocol' and 'DependencyValues'.

See the migration guide for more information: https://pointfreeco.github.io/swift-composable-architecture/main/documentation/composablearchitecture/reducerprotocol
"""
)
///
/// 🗒️ in original Composable Architecture, environment is deprecated
/// but in our cases, we gonna use it to support `Environment` inside `ReducerProtocol`
/// so in the future, we will keep this implementation
/// if original Composable Architecture decided to delete this property
///
public var environment: Environment {
_read { yield self._environment.wrappedValue }
_modify { yield &self._environment.wrappedValue }
Expand Down Expand Up @@ -699,6 +665,51 @@ public final class TestStore<State, Action, ScopedState, ScopedAction, Environme
self.dependencies = dependencies
}

/// Hence here we are creating an init for supporting non-Dependencies Environment
/// we are using current Environment implementations
///
/// ⚠️ Use this init only if you are having case of non-Dependencies Environment
///
public init<R: ReducerProtocol>(
initialState: @autoclosure () -> State,
environment: Environment,
reducer prepareReducer: @escaping (Environment) -> R,
file: StaticString = #file,
line: UInt = #line
)
where
R.State == State,
R.Action == Action,
State == ScopedState,
State: Equatable,
Action == ScopedAction
{
let environment = TaskBox(wrappedValue: environment)
let reducer = TestReducer(
Reduce(
internal: { state, action in
prepareReducer(environment.wrappedValue).reduce(into: &state, action: action)
}
),
initialState: initialState()
)
self._environment = environment
self.file = file
self.fromScopedAction = { $0 }
self.line = line
self.reducer = reducer
self.timeout = 100 * NSEC_PER_MSEC
self.toScopedState = { $0 }
self.failingWhenNothingChange = true
self.useNewScope = true

self.store = Store(
initialState: initialState(),
reducer: reducer,
useNewScope: useNewScope
)
}

@available(
iOS,
deprecated: 9999,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//
// EnvironmentReducerProtocolTests.swift
//
//
// Created by andhika.setiadi on 17/08/23.
//

import XCTest
@testable import RxComposableArchitecture
@testable import XCTestDynamicOverlay

internal final class EnvironmentReducerProtocolTests: XCTestCase {

internal func testEnvironmentReducerProtocol_getSuccess() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

consider better name test case

struct Authenticator: ReducerProtocol {
typealias State = String
typealias Action = Void

internal var authenticatorService: AuthenticatorService

func reduce(into state: inout String, action: Void) -> Effect<Void> {
switch authenticatorService.getAuthResult() {
case let .success(successMessage):
state = successMessage
case let .failure(failureData):
state = failureData.message
}
return .none
}
}

let testStore = TestStore(
initialState: "",
environment: AuthenticatorService.mock,
reducer: Authenticator.init(authenticatorService:)
)

testStore.environment.getAuthResult = {
.success("success")
}

testStore.send(()) {
$0 = "success"
}

testStore.environment.getAuthResult = {
.failure(Failure(message: "Failed"))
}

testStore.send(()) {
$0 = "Failed"
}
}
}

private struct Failure: Error {
let message: String
}

private struct AuthenticatorService {
var getAuthResult: () -> Result<String, Failure>

static var mock: AuthenticatorService {
return AuthenticatorService(
getAuthResult: unimplemented(
"Unimplemented getAuthResult",
placeholder: .failure(
Failure(message: "Need Mock")
)
)
)
}
}