Skip to content
Snippets Groups Projects
Commit 33256ca4 authored by Dariusz Rybicki's avatar Dariusz Rybicki
Browse files

Add CheckContactAuthFeature library

parent 0b255adc
No related branches found
No related tags found
2 merge requests!102Release 1.0.0,!81Messenger example - contact authorization improvements
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1400"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CheckContactAuthFeature"
BuildableName = "CheckContactAuthFeature"
BlueprintName = "CheckContactAuthFeature"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CheckContactAuthFeatureTests"
BuildableName = "CheckContactAuthFeatureTests"
BlueprintName = "CheckContactAuthFeatureTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CheckContactAuthFeature"
BuildableName = "CheckContactAuthFeature"
BlueprintName = "CheckContactAuthFeature"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
......@@ -20,6 +20,7 @@ let package = Package(
products: [
.library(name: "AppCore", targets: ["AppCore"]),
.library(name: "AppFeature", targets: ["AppFeature"]),
.library(name: "CheckContactAuthFeature", targets: ["CheckContactAuthFeature"]),
.library(name: "ContactFeature", targets: ["ContactFeature"]),
.library(name: "ContactsFeature", targets: ["ContactsFeature"]),
.library(name: "HomeFeature", targets: ["HomeFeature"]),
......@@ -97,6 +98,21 @@ let package = Package(
],
swiftSettings: swiftSettings
),
.target(
name: "CheckContactAuthFeature",
dependencies: [
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
.product(name: "XXClient", package: "elixxir-dapps-sdk-swift"),
.product(name: "XXMessengerClient", package: "elixxir-dapps-sdk-swift"),
.product(name: "XXModels", package: "client-ios-db"),
]
),
.testTarget(
name: "CheckContactAuthFeatureTests",
dependencies: [
.target(name: "CheckContactAuthFeature"),
]
),
.target(
name: "ContactFeature",
dependencies: [
......
......@@ -49,6 +49,16 @@
ReferencedContainer = "container:..">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CheckContactAuthFeatureTests"
BuildableName = "CheckContactAuthFeatureTests"
BlueprintName = "CheckContactAuthFeatureTests"
ReferencedContainer = "container:..">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
......
import ComposableArchitecture
import Foundation
import XCTestDynamicOverlay
import XXClient
import XXMessengerClient
public struct CheckContactAuthState: Equatable {
public enum Result: Equatable {
case success(Bool)
case failure(String)
}
public init(
contact: Contact,
isChecking: Bool = false,
result: Result? = nil
) {
self.contact = contact
self.isChecking = isChecking
self.result = result
}
public var contact: Contact
public var isChecking: Bool
public var result: Result?
}
public enum CheckContactAuthAction: Equatable {
case checkTapped
case didCheck(CheckContactAuthState.Result)
}
public struct CheckContactAuthEnvironment {
public init(
messenger: Messenger,
mainQueue: AnySchedulerOf<DispatchQueue>,
bgQueue: AnySchedulerOf<DispatchQueue>
) {
self.messenger = messenger
self.mainQueue = mainQueue
self.bgQueue = bgQueue
}
public var messenger: Messenger
public var mainQueue: AnySchedulerOf<DispatchQueue>
public var bgQueue: AnySchedulerOf<DispatchQueue>
}
#if DEBUG
extension CheckContactAuthEnvironment {
public static let unimplemented = CheckContactAuthEnvironment(
messenger: .unimplemented,
mainQueue: .unimplemented,
bgQueue: .unimplemented
)
}
#endif
public let checkContactAuthReducer = Reducer<CheckContactAuthState, CheckContactAuthAction, CheckContactAuthEnvironment>
{ state, action, env in
switch action {
case .checkTapped:
state.isChecking = true
state.result = nil
return Effect.result { [state] in
do {
let e2e = try env.messenger.e2e.tryGet()
let contactId = try state.contact.getId()
let result = try e2e.hasAuthenticatedChannel(partnerId: contactId)
return .success(.didCheck(.success(result)))
} catch {
return .success(.didCheck(.failure(error.localizedDescription)))
}
}
.subscribe(on: env.bgQueue)
.receive(on: env.mainQueue)
.eraseToEffect()
case .didCheck(let result):
state.isChecking = false
state.result = result
return .none
}
}
import ComposableArchitecture
import SwiftUI
import XXClient
public struct CheckContactAuthView: View {
public init(store: Store<CheckContactAuthState, CheckContactAuthAction>) {
self.store = store
}
let store: Store<CheckContactAuthState, CheckContactAuthAction>
struct ViewState: Equatable {
var username: String?
var email: String?
var phone: String?
var isChecking: Bool
var result: CheckContactAuthState.Result?
init(state: CheckContactAuthState) {
username = try? state.contact.getFact(.username)?.value
email = try? state.contact.getFact(.email)?.value
phone = try? state.contact.getFact(.phone)?.value
isChecking = state.isChecking
result = state.result
}
}
public var body: some View {
WithViewStore(store.scope(state: ViewState.init)) { viewStore in
Form {
Section {
Label(viewStore.username ?? "", systemImage: "person")
Label(viewStore.email ?? "", systemImage: "envelope")
Label(viewStore.phone ?? "", systemImage: "phone")
} header: {
Text("Facts")
}
Section {
Button {
viewStore.send(.checkTapped)
} label: {
HStack {
Text("Check")
Spacer()
if viewStore.isChecking {
ProgressView()
} else {
Image(systemName: "play")
}
}
}
.disabled(viewStore.isChecking)
}
if let result = viewStore.result {
Section {
HStack {
switch result {
case .success(true):
Text("Authorized")
Spacer()
Image(systemName: "person.fill.checkmark")
case .success(false):
Text("Not authorized")
Spacer()
Image(systemName: "person.fill.xmark")
case .failure(_):
Text("Checking status failed")
Spacer()
Image(systemName: "xmark")
}
}
if case .failure(let failure) = result {
Text(failure)
}
} header: {
Text("Result")
}
}
}
.navigationTitle("Check connection")
}
}
}
#if DEBUG
public struct CheckContactAuthView_Previews: PreviewProvider {
public static var previews: some View {
CheckContactAuthView(store: Store(
initialState: CheckContactAuthState(
contact: .unimplemented("contact-data".data(using: .utf8)!)
),
reducer: .empty,
environment: ()
))
}
}
#endif
import ComposableArchitecture
import XCTest
import XXClient
@testable import CheckContactAuthFeature
final class CheckContactAuthFeatureTests: XCTestCase {
func testCheck() {
var contact = Contact.unimplemented("contact-data".data(using: .utf8)!)
let contactId = "contact-id".data(using: .utf8)!
contact.getIdFromContact.run = { _ in contactId }
let store = TestStore(
initialState: CheckContactAuthState(
contact: contact
),
reducer: checkContactAuthReducer,
environment: .unimplemented
)
var didCheckPartnerId: [Data] = []
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.messenger.e2e.get = {
var e2e: E2E = .unimplemented
e2e.hasAuthenticatedChannel.run = { partnerId in
didCheckPartnerId.append(partnerId)
return true
}
return e2e
}
store.send(.checkTapped) {
$0.isChecking = true
$0.result = nil
}
store.receive(.didCheck(.success(true))) {
$0.isChecking = false
$0.result = .success(true)
}
}
func testCheckNoConnection() {
var contact = Contact.unimplemented("contact-data".data(using: .utf8)!)
let contactId = "contact-id".data(using: .utf8)!
contact.getIdFromContact.run = { _ in contactId }
let store = TestStore(
initialState: CheckContactAuthState(
contact: contact
),
reducer: checkContactAuthReducer,
environment: .unimplemented
)
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.messenger.e2e.get = {
var e2e: E2E = .unimplemented
e2e.hasAuthenticatedChannel.run = { _ in false }
return e2e
}
store.send(.checkTapped) {
$0.isChecking = true
$0.result = nil
}
store.receive(.didCheck(.success(false))) {
$0.isChecking = false
$0.result = .success(false)
}
}
func testCheckFailure() {
var contact = Contact.unimplemented("contact-data".data(using: .utf8)!)
let contactId = "contact-id".data(using: .utf8)!
contact.getIdFromContact.run = { _ in contactId }
let store = TestStore(
initialState: CheckContactAuthState(
contact: contact
),
reducer: checkContactAuthReducer,
environment: .unimplemented
)
struct Failure: Error {}
let error = Failure()
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.messenger.e2e.get = {
var e2e: E2E = .unimplemented
e2e.hasAuthenticatedChannel.run = { _ in throw error }
return e2e
}
store.send(.checkTapped) {
$0.isChecking = true
$0.result = nil
}
store.receive(.didCheck(.failure(error.localizedDescription))) {
$0.isChecking = false
$0.result = .failure(error.localizedDescription)
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment