2021-12-13 12:50:04 -08:00
|
|
|
//
|
|
|
|
// RecoveryPhraseValidationTests.swift
|
|
|
|
// secantTests
|
|
|
|
//
|
|
|
|
// Created by Francisco Gindre on 10/29/21.
|
|
|
|
//
|
|
|
|
// swiftlint:disable type_body_length
|
|
|
|
import XCTest
|
|
|
|
import ComposableArchitecture
|
|
|
|
@testable import secant_testnet
|
|
|
|
|
|
|
|
class RecoveryPhraseValidationTests: XCTestCase {
|
|
|
|
static let testScheduler = DispatchQueue.test
|
|
|
|
|
|
|
|
func testPickWordsFromMissingIndices() throws {
|
|
|
|
let words = [
|
|
|
|
"bring", "salute", "thank",
|
|
|
|
"require", "spirit", "toe",
|
|
|
|
// second chunk
|
|
|
|
"boil", "hill", "casino",
|
|
|
|
"trophy", "drink", "frown",
|
|
|
|
// third chunk
|
|
|
|
"bird", "grit", "close",
|
|
|
|
"morning", "bind", "cancel",
|
|
|
|
// Fourth chunk
|
|
|
|
"daughter", "salon", "quit",
|
|
|
|
"pizza", "just", "garlic"
|
|
|
|
]
|
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
let phrase = RecoveryPhrase(words: words.map { $0.redacted })
|
2021-12-13 12:50:04 -08:00
|
|
|
|
|
|
|
let indices = [1, 0, 5, 3]
|
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
let expected = [
|
|
|
|
"salute".redacted,
|
|
|
|
"boil".redacted,
|
|
|
|
"cancel".redacted,
|
|
|
|
"pizza".redacted
|
|
|
|
].map({ PhraseChip.Kind.unassigned(word: $0) })
|
2021-12-13 12:50:04 -08:00
|
|
|
|
|
|
|
let result = phrase.words(fromMissingIndices: indices)
|
|
|
|
|
|
|
|
XCTAssertEqual(expected, result)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testWhenInInitialStepChipIsDraggedIntoGroup1FollowingStepIsIncomplete() {
|
|
|
|
let words = [
|
|
|
|
"bring", "salute", "thank",
|
|
|
|
"require", "spirit", "toe",
|
|
|
|
// second chunk
|
|
|
|
"boil", "hill", "casino",
|
|
|
|
"trophy", "drink", "frown",
|
|
|
|
// third chunk
|
|
|
|
"bird", "grit", "close",
|
|
|
|
"morning", "bind", "cancel",
|
|
|
|
// Fourth chunk
|
|
|
|
"daughter", "salon", "quit",
|
|
|
|
"pizza", "just", "garlic"
|
|
|
|
]
|
|
|
|
|
|
|
|
let missingIndices = [1, 0, 5, 3]
|
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
let phrase = RecoveryPhrase(words: words.map { $0.redacted })
|
2021-12-13 12:50:04 -08:00
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
let missingWordChips: [PhraseChip.Kind] = [
|
|
|
|
"salute".redacted,
|
|
|
|
"boil".redacted,
|
|
|
|
"cancel".redacted,
|
|
|
|
"pizza".redacted
|
|
|
|
].map({ PhraseChip.Kind.unassigned(word: $0) })
|
2021-12-13 12:50:04 -08:00
|
|
|
|
2022-11-04 23:11:25 -07:00
|
|
|
let initialStep = RecoveryPhraseValidationFlowReducer.State(
|
2021-12-13 12:50:04 -08:00
|
|
|
phrase: phrase,
|
|
|
|
missingIndices: missingIndices,
|
|
|
|
missingWordChips: missingWordChips,
|
|
|
|
validationWords: []
|
|
|
|
)
|
|
|
|
|
2022-11-02 09:43:42 -07:00
|
|
|
let store = TestStore(
|
|
|
|
initialState: initialStep,
|
2022-11-04 23:11:25 -07:00
|
|
|
reducer: RecoveryPhraseValidationFlowReducer()
|
2022-11-02 09:43:42 -07:00
|
|
|
)
|
2021-12-13 12:50:04 -08:00
|
|
|
|
|
|
|
let expectedMissingChips = [
|
|
|
|
PhraseChip.Kind.empty,
|
2023-02-13 11:32:50 -08:00
|
|
|
PhraseChip.Kind.unassigned(word: "boil".redacted),
|
|
|
|
PhraseChip.Kind.unassigned(word: "cancel".redacted),
|
|
|
|
PhraseChip.Kind.unassigned(word: "pizza".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
]
|
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
let expectedValidationWords = [ValidationWord(groupIndex: 1, word: "salute".redacted)]
|
2021-12-13 12:50:04 -08:00
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
store.send(.move(wordChip: .unassigned(word: "salute".redacted), intoGroup: 1)) {
|
2021-12-13 12:50:04 -08:00
|
|
|
$0.validationWords = expectedValidationWords
|
|
|
|
$0.missingWordChips = expectedMissingChips
|
|
|
|
|
|
|
|
XCTAssertFalse($0.isComplete)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testWhenInInitialStepChipIsDraggedIntoGroup0FollowingStepIsIncompleteNextStateIsIncomplete() {
|
|
|
|
let words = [
|
|
|
|
"bring", "salute", "thank",
|
|
|
|
"require", "spirit", "toe",
|
|
|
|
// second chunk
|
|
|
|
"boil", "hill", "casino",
|
|
|
|
"trophy", "drink", "frown",
|
|
|
|
// third chunk
|
|
|
|
"bird", "grit", "close",
|
|
|
|
"morning", "bind", "cancel",
|
|
|
|
// Fourth chunk
|
|
|
|
"daughter", "salon", "quit",
|
|
|
|
"pizza", "just", "garlic"
|
|
|
|
]
|
|
|
|
|
|
|
|
let missingIndices = [1, 0, 5, 3]
|
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
let phrase = RecoveryPhrase(words: words.map { $0.redacted })
|
2021-12-13 12:50:04 -08:00
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
let missingWordChips = [
|
|
|
|
"salute".redacted,
|
|
|
|
"boil".redacted,
|
|
|
|
"cancel".redacted,
|
|
|
|
"pizza".redacted
|
|
|
|
].map({ PhraseChip.Kind.unassigned(word: $0) })
|
2021-12-13 12:50:04 -08:00
|
|
|
|
2022-11-04 23:11:25 -07:00
|
|
|
let initialStep = RecoveryPhraseValidationFlowReducer.State.initial(
|
2021-12-13 12:50:04 -08:00
|
|
|
phrase: phrase,
|
|
|
|
missingIndices: missingIndices,
|
|
|
|
missingWordsChips: missingWordChips
|
|
|
|
)
|
|
|
|
|
2022-11-02 09:43:42 -07:00
|
|
|
let store = TestStore(
|
|
|
|
initialState: initialStep,
|
2022-11-04 23:11:25 -07:00
|
|
|
reducer: RecoveryPhraseValidationFlowReducer()
|
2022-11-02 09:43:42 -07:00
|
|
|
)
|
2021-12-13 12:50:04 -08:00
|
|
|
|
|
|
|
let expectedMissingChips = [
|
2023-02-13 11:32:50 -08:00
|
|
|
PhraseChip.Kind.unassigned(word: "salute".redacted),
|
|
|
|
PhraseChip.Kind.unassigned(word: "boil".redacted),
|
|
|
|
PhraseChip.Kind.unassigned(word: "cancel".redacted),
|
2021-12-13 12:50:04 -08:00
|
|
|
PhraseChip.Kind.empty
|
|
|
|
]
|
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
let expectedValidationWords = [ValidationWord(groupIndex: 0, word: "pizza".redacted)]
|
2021-12-13 12:50:04 -08:00
|
|
|
|
|
|
|
store.send(.move(wordChip: missingWordChips[3], intoGroup: 0)) {
|
|
|
|
$0.missingWordChips = expectedMissingChips
|
|
|
|
$0.validationWords = expectedValidationWords
|
|
|
|
|
|
|
|
XCTAssertFalse($0.isComplete)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testWhenInIncompleteWith2CompletionsAndAChipIsDroppedInGroup3NextStateIsIncomplete() {
|
|
|
|
let words = [
|
|
|
|
"bring", "salute", "thank",
|
|
|
|
"require", "spirit", "toe",
|
|
|
|
// second chunk
|
|
|
|
"boil", "hill", "casino",
|
|
|
|
"trophy", "drink", "frown",
|
|
|
|
// third chunk
|
|
|
|
"bird", "grit", "close",
|
|
|
|
"morning", "bind", "cancel",
|
|
|
|
// Fourth chunk
|
|
|
|
"daughter", "salon", "quit",
|
|
|
|
"pizza", "just", "garlic"
|
|
|
|
]
|
|
|
|
|
|
|
|
let missingIndices = [1, 0, 5, 3]
|
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
let phrase = RecoveryPhrase(words: words.map { $0.redacted })
|
2021-12-13 12:50:04 -08:00
|
|
|
|
2022-11-04 23:11:25 -07:00
|
|
|
let currentStep = RecoveryPhraseValidationFlowReducer.State(
|
2021-12-13 12:50:04 -08:00
|
|
|
phrase: phrase,
|
|
|
|
missingIndices: missingIndices,
|
|
|
|
missingWordChips: [
|
|
|
|
PhraseChip.Kind.empty,
|
2023-02-13 11:32:50 -08:00
|
|
|
PhraseChip.Kind.unassigned(word: "boil".redacted),
|
|
|
|
PhraseChip.Kind.unassigned(word: "cancel".redacted),
|
|
|
|
PhraseChip.Kind.unassigned(word: "pizza".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
],
|
2023-02-13 11:32:50 -08:00
|
|
|
validationWords: [ValidationWord(groupIndex: 0, word: "salute".redacted)]
|
2021-12-13 12:50:04 -08:00
|
|
|
)
|
|
|
|
|
2022-11-02 09:43:42 -07:00
|
|
|
let store = TestStore(
|
|
|
|
initialState: currentStep,
|
2022-11-04 23:11:25 -07:00
|
|
|
reducer: RecoveryPhraseValidationFlowReducer()
|
2022-11-02 09:43:42 -07:00
|
|
|
)
|
2021-12-13 12:50:04 -08:00
|
|
|
|
|
|
|
let expectedMissingWordChips = [
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty,
|
2023-02-13 11:32:50 -08:00
|
|
|
PhraseChip.Kind.unassigned(word: "cancel".redacted),
|
|
|
|
PhraseChip.Kind.unassigned(word: "pizza".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
]
|
|
|
|
|
|
|
|
let expectedValidationWords = [
|
2023-02-13 11:32:50 -08:00
|
|
|
ValidationWord(groupIndex: 0, word: "salute".redacted),
|
|
|
|
ValidationWord(groupIndex: 1, word: "boil".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
]
|
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
store.send(.move(wordChip: PhraseChip.Kind.unassigned(word: "boil".redacted), intoGroup: 1)) {
|
2021-12-13 12:50:04 -08:00
|
|
|
$0.missingWordChips = expectedMissingWordChips
|
|
|
|
$0.validationWords = expectedValidationWords
|
|
|
|
|
|
|
|
XCTAssertFalse($0.isComplete)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testWhenInIncompleteWith2CompletionsAndAChipIsDroppedInGroup2NextStateIsIncomplete() {
|
|
|
|
let words = [
|
|
|
|
"bring", "salute", "thank",
|
|
|
|
"require", "spirit", "toe",
|
|
|
|
// second chunk
|
|
|
|
"boil", "hill", "casino",
|
|
|
|
"trophy", "drink", "frown",
|
|
|
|
// third chunk
|
|
|
|
"bird", "grit", "close",
|
|
|
|
"morning", "bind", "cancel",
|
|
|
|
// Fourth chunk
|
|
|
|
"daughter", "salon", "quit",
|
|
|
|
"pizza", "just", "garlic"
|
|
|
|
]
|
|
|
|
|
|
|
|
let missingIndices = [1, 0, 5, 3]
|
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
let phrase = RecoveryPhrase(words: words.map { $0.redacted })
|
2021-12-13 12:50:04 -08:00
|
|
|
|
2022-11-04 23:11:25 -07:00
|
|
|
let currentStep = RecoveryPhraseValidationFlowReducer.State(
|
2021-12-13 12:50:04 -08:00
|
|
|
phrase: phrase,
|
|
|
|
missingIndices: missingIndices,
|
|
|
|
missingWordChips: [
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty,
|
2023-02-13 11:32:50 -08:00
|
|
|
PhraseChip.Kind.unassigned(word: "cancel".redacted),
|
|
|
|
PhraseChip.Kind.unassigned(word: "pizza".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
],
|
|
|
|
validationWords: [
|
2023-02-13 11:32:50 -08:00
|
|
|
ValidationWord(groupIndex: 0, word: "salute".redacted),
|
|
|
|
ValidationWord(groupIndex: 1, word: "boil".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
]
|
|
|
|
)
|
|
|
|
|
2022-11-02 09:43:42 -07:00
|
|
|
let store = TestStore(
|
|
|
|
initialState: currentStep,
|
2022-11-04 23:11:25 -07:00
|
|
|
reducer: RecoveryPhraseValidationFlowReducer()
|
2022-11-02 09:43:42 -07:00
|
|
|
)
|
2021-12-13 12:50:04 -08:00
|
|
|
|
|
|
|
let expectedMissingWordChips = [
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty,
|
2023-02-13 11:32:50 -08:00
|
|
|
PhraseChip.Kind.unassigned(word: "pizza".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
]
|
|
|
|
|
|
|
|
let expectedValidationWords = [
|
2023-02-13 11:32:50 -08:00
|
|
|
ValidationWord(groupIndex: 0, word: "salute".redacted),
|
|
|
|
ValidationWord(groupIndex: 1, word: "boil".redacted),
|
|
|
|
ValidationWord(groupIndex: 2, word: "cancel".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
]
|
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
store.send(.move(wordChip: PhraseChip.Kind.unassigned(word: "cancel".redacted), intoGroup: 2)) {
|
2021-12-13 12:50:04 -08:00
|
|
|
$0.missingWordChips = expectedMissingWordChips
|
|
|
|
$0.validationWords = expectedValidationWords
|
|
|
|
|
|
|
|
XCTAssertFalse($0.isComplete)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testWhenInIncompleteWith3CompletionsAndAChipIsDroppedInGroup3NextStateIsComplete() {
|
|
|
|
let words = [
|
|
|
|
"bring", "salute", "thank",
|
|
|
|
"require", "spirit", "toe",
|
|
|
|
// second chunk
|
|
|
|
"boil", "hill", "casino",
|
|
|
|
"trophy", "drink", "frown",
|
|
|
|
// third chunk
|
|
|
|
"bird", "grit", "close",
|
|
|
|
"morning", "bind", "cancel",
|
|
|
|
// Fourth chunk
|
|
|
|
"daughter", "salon", "quit",
|
|
|
|
"pizza", "just", "garlic"
|
|
|
|
]
|
|
|
|
|
|
|
|
let missingIndices = [1, 0, 5, 3]
|
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
let phrase = RecoveryPhrase(words: words.map { $0.redacted })
|
2021-12-13 12:50:04 -08:00
|
|
|
|
2022-11-04 23:11:25 -07:00
|
|
|
let currentStep = RecoveryPhraseValidationFlowReducer.State(
|
2021-12-13 12:50:04 -08:00
|
|
|
phrase: phrase,
|
|
|
|
missingIndices: missingIndices,
|
|
|
|
missingWordChips: [
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty,
|
2023-02-13 11:32:50 -08:00
|
|
|
PhraseChip.Kind.unassigned(word: "pizza".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
],
|
|
|
|
validationWords: [
|
2023-02-13 11:32:50 -08:00
|
|
|
ValidationWord(groupIndex: 0, word: "salute".redacted),
|
|
|
|
ValidationWord(groupIndex: 1, word: "boil".redacted),
|
|
|
|
ValidationWord(groupIndex: 2, word: "cancel".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
]
|
|
|
|
)
|
|
|
|
|
2022-11-02 09:43:42 -07:00
|
|
|
let store = TestStore(
|
|
|
|
initialState: currentStep,
|
2022-11-04 23:11:25 -07:00
|
|
|
reducer: RecoveryPhraseValidationFlowReducer()
|
2022-11-18 02:34:33 -08:00
|
|
|
) {
|
|
|
|
$0.mainQueue = Self.testScheduler.eraseToAnyScheduler()
|
|
|
|
}
|
2021-12-13 12:50:04 -08:00
|
|
|
|
|
|
|
let expectedMissingWordChips = [
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty
|
|
|
|
]
|
|
|
|
|
|
|
|
let expectedValidationWords = [
|
2023-02-13 11:32:50 -08:00
|
|
|
ValidationWord(groupIndex: 0, word: "salute".redacted),
|
|
|
|
ValidationWord(groupIndex: 1, word: "boil".redacted),
|
|
|
|
ValidationWord(groupIndex: 2, word: "cancel".redacted),
|
|
|
|
ValidationWord(groupIndex: 3, word: "pizza".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
]
|
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
store.send(.move(wordChip: PhraseChip.Kind.unassigned(word: "pizza".redacted), intoGroup: 3)) {
|
2021-12-13 12:50:04 -08:00
|
|
|
$0.missingWordChips = expectedMissingWordChips
|
|
|
|
$0.validationWords = expectedValidationWords
|
|
|
|
|
|
|
|
XCTAssertTrue($0.isComplete)
|
|
|
|
XCTAssertTrue($0.isValid)
|
|
|
|
}
|
|
|
|
|
|
|
|
Self.testScheduler.advance(by: 2)
|
|
|
|
|
|
|
|
store.receive(.succeed) {
|
|
|
|
XCTAssertTrue($0.isComplete)
|
2022-12-01 06:31:30 -08:00
|
|
|
$0.destination = .success
|
2021-12-13 12:50:04 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testWhenInIncompleteWith3CompletionsAndAChipIsDroppedInGroup3NextStateIsFailure() {
|
|
|
|
let words = [
|
|
|
|
"bring", "salute", "thank",
|
|
|
|
"require", "spirit", "toe",
|
|
|
|
// second chunk
|
|
|
|
"boil", "hill", "casino",
|
|
|
|
"trophy", "drink", "frown",
|
|
|
|
// third chunk
|
|
|
|
"bird", "grit", "close",
|
|
|
|
"morning", "bind", "cancel",
|
|
|
|
// Fourth chunk
|
|
|
|
"daughter", "salon", "quit",
|
|
|
|
"pizza", "just", "garlic"
|
|
|
|
]
|
|
|
|
|
|
|
|
let missingIndices = [1, 0, 5, 3]
|
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
let phrase = RecoveryPhrase(words: words.map { $0.redacted })
|
2021-12-13 12:50:04 -08:00
|
|
|
|
2022-11-04 23:11:25 -07:00
|
|
|
let currentStep = RecoveryPhraseValidationFlowReducer.State(
|
2021-12-13 12:50:04 -08:00
|
|
|
phrase: phrase,
|
|
|
|
missingIndices: missingIndices,
|
|
|
|
missingWordChips: [
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty,
|
2023-02-13 11:32:50 -08:00
|
|
|
PhraseChip.Kind.unassigned(word: "pizza".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
],
|
|
|
|
validationWords: [
|
2023-02-13 11:32:50 -08:00
|
|
|
ValidationWord(groupIndex: 0, word: "salute".redacted),
|
|
|
|
ValidationWord(groupIndex: 2, word: "boil".redacted),
|
|
|
|
ValidationWord(groupIndex: 1, word: "cancel".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
]
|
|
|
|
)
|
|
|
|
|
2022-11-02 09:43:42 -07:00
|
|
|
let store = TestStore(
|
|
|
|
initialState: currentStep,
|
2022-11-04 23:11:25 -07:00
|
|
|
reducer: RecoveryPhraseValidationFlowReducer()
|
2022-11-18 02:34:33 -08:00
|
|
|
) { dependencies in
|
|
|
|
dependencies.feedbackGenerator = .noOp
|
|
|
|
dependencies.mainQueue = Self.testScheduler.eraseToAnyScheduler()
|
|
|
|
}
|
2021-12-13 12:50:04 -08:00
|
|
|
|
|
|
|
let expectedMissingWordChips = [
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty
|
|
|
|
]
|
|
|
|
|
|
|
|
let expectedValidationWords = [
|
2023-02-13 11:32:50 -08:00
|
|
|
ValidationWord(groupIndex: 0, word: "salute".redacted),
|
|
|
|
ValidationWord(groupIndex: 2, word: "boil".redacted),
|
|
|
|
ValidationWord(groupIndex: 1, word: "cancel".redacted),
|
|
|
|
ValidationWord(groupIndex: 3, word: "pizza".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
]
|
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
store.send(.move(wordChip: PhraseChip.Kind.unassigned(word: "pizza".redacted), intoGroup: 3)) {
|
2021-12-13 12:50:04 -08:00
|
|
|
$0.missingWordChips = expectedMissingWordChips
|
|
|
|
$0.validationWords = expectedValidationWords
|
|
|
|
|
|
|
|
XCTAssertTrue($0.isComplete)
|
|
|
|
}
|
|
|
|
|
|
|
|
Self.testScheduler.advance(by: 2)
|
|
|
|
|
2022-05-23 08:36:29 -07:00
|
|
|
store.receive(.failureFeedback)
|
2022-02-24 08:26:06 -08:00
|
|
|
|
2021-12-13 12:50:04 -08:00
|
|
|
store.receive(.fail) {
|
2022-12-01 06:31:30 -08:00
|
|
|
$0.destination = .failure
|
2021-12-13 12:50:04 -08:00
|
|
|
XCTAssertFalse($0.isValid)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testWhenAWordGroupDoesNotHaveACompletionItHasAnEmptyChipInTheGivenMissingIndex() {
|
|
|
|
let words = [
|
|
|
|
"bring", "salute", "thank",
|
|
|
|
"require", "spirit", "toe",
|
|
|
|
// second chunk
|
|
|
|
"boil", "hill", "casino",
|
|
|
|
"trophy", "drink", "frown",
|
|
|
|
// third chunk
|
|
|
|
"bird", "grit", "close",
|
|
|
|
"morning", "bind", "cancel",
|
|
|
|
// Fourth chunk
|
|
|
|
"daughter", "salon", "quit",
|
|
|
|
"pizza", "just", "garlic"
|
|
|
|
]
|
|
|
|
|
|
|
|
let missingIndices = [1, 0, 5, 3]
|
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
let phrase = RecoveryPhrase(words: words.map { $0.redacted })
|
2021-12-13 12:50:04 -08:00
|
|
|
|
2022-11-04 23:11:25 -07:00
|
|
|
let currentStep = RecoveryPhraseValidationFlowReducer.State(
|
2021-12-13 12:50:04 -08:00
|
|
|
phrase: phrase,
|
|
|
|
missingIndices: missingIndices,
|
|
|
|
missingWordChips: [
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty,
|
2023-02-13 11:32:50 -08:00
|
|
|
PhraseChip.Kind.unassigned(word: "pizza".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
],
|
|
|
|
validationWords: [
|
2023-02-13 11:32:50 -08:00
|
|
|
ValidationWord(groupIndex: 1, word: "boil".redacted),
|
|
|
|
ValidationWord(groupIndex: 2, word: "cancel".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
let result = currentStep.wordsChips(
|
|
|
|
for: 0,
|
|
|
|
groupSize: 6,
|
|
|
|
from: phrase.toGroups()[0]
|
|
|
|
)
|
|
|
|
|
|
|
|
let expected = [
|
2023-02-13 11:32:50 -08:00
|
|
|
PhraseChip.Kind.ordered(position: 1, word: "bring".redacted),
|
2021-12-13 12:50:04 -08:00
|
|
|
.empty,
|
2023-02-13 11:32:50 -08:00
|
|
|
.ordered(position: 3, word: "thank".redacted),
|
|
|
|
.ordered(position: 4, word: "require".redacted),
|
|
|
|
.ordered(position: 5, word: "spirit".redacted),
|
|
|
|
.ordered(position: 6, word: "toe".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
]
|
|
|
|
|
|
|
|
XCTAssertEqual(expected, result)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testWhenAWordGroupHasACompletionItHasABlueChipWithTheCompletedWordInTheGivenMissingIndex() {
|
|
|
|
let words = [
|
|
|
|
"bring", "salute", "thank",
|
|
|
|
"require", "spirit", "toe",
|
|
|
|
// second chunk
|
|
|
|
"boil", "hill", "casino",
|
|
|
|
"trophy", "drink", "frown",
|
|
|
|
// third chunk
|
|
|
|
"bird", "grit", "close",
|
|
|
|
"morning", "bind", "cancel",
|
|
|
|
// Fourth chunk
|
|
|
|
"daughter", "salon", "quit",
|
|
|
|
"pizza", "just", "garlic"
|
|
|
|
]
|
|
|
|
|
|
|
|
let missingIndices = [1, 0, 5, 3]
|
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
let phrase = RecoveryPhrase(words: words.map { $0.redacted })
|
2021-12-13 12:50:04 -08:00
|
|
|
|
2022-11-04 23:11:25 -07:00
|
|
|
let currentStep = RecoveryPhraseValidationFlowReducer.State(
|
2021-12-13 12:50:04 -08:00
|
|
|
phrase: phrase,
|
|
|
|
missingIndices: missingIndices,
|
|
|
|
missingWordChips: [
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty,
|
2023-02-13 11:32:50 -08:00
|
|
|
PhraseChip.Kind.unassigned(word: "pizza".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
],
|
|
|
|
validationWords: [
|
2023-02-13 11:32:50 -08:00
|
|
|
ValidationWord(groupIndex: 0, word: "salute".redacted),
|
|
|
|
ValidationWord(groupIndex: 1, word: "boil".redacted),
|
|
|
|
ValidationWord(groupIndex: 2, word: "cancel".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
let result = currentStep.wordsChips(
|
|
|
|
for: 0,
|
|
|
|
groupSize: 6,
|
|
|
|
from: phrase.toGroups()[0]
|
|
|
|
)
|
|
|
|
|
|
|
|
let expected = [
|
2023-02-13 11:32:50 -08:00
|
|
|
PhraseChip.Kind.ordered(position: 1, word: "bring".redacted),
|
|
|
|
.unassigned(word: "salute".redacted),
|
|
|
|
.ordered(position: 3, word: "thank".redacted),
|
|
|
|
.ordered(position: 4, word: "require".redacted),
|
|
|
|
.ordered(position: 5, word: "spirit".redacted),
|
|
|
|
.ordered(position: 6, word: "toe".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
]
|
|
|
|
|
|
|
|
XCTAssertEqual(expected, result)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testWhenRecoveryPhraseValidationStateIsNotCompleteResultingPhraseIsNil() {
|
|
|
|
let words = [
|
|
|
|
"bring", "salute", "thank",
|
|
|
|
"require", "spirit", "toe",
|
|
|
|
// second chunk
|
|
|
|
"boil", "hill", "casino",
|
|
|
|
"trophy", "drink", "frown",
|
|
|
|
// third chunk
|
|
|
|
"bird", "grit", "close",
|
|
|
|
"morning", "bind", "cancel",
|
|
|
|
// Fourth chunk
|
|
|
|
"daughter", "salon", "quit",
|
|
|
|
"pizza", "just", "garlic"
|
|
|
|
]
|
|
|
|
|
|
|
|
let missingIndices = [1, 0, 5, 3]
|
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
let phrase = RecoveryPhrase(words: words.map { $0.redacted })
|
2021-12-13 12:50:04 -08:00
|
|
|
|
2022-11-04 23:11:25 -07:00
|
|
|
let currentStep = RecoveryPhraseValidationFlowReducer.State(
|
2021-12-13 12:50:04 -08:00
|
|
|
phrase: phrase,
|
|
|
|
missingIndices: missingIndices,
|
|
|
|
missingWordChips: [
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty,
|
2023-02-13 11:32:50 -08:00
|
|
|
PhraseChip.Kind.unassigned(word: "pizza".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
],
|
|
|
|
validationWords: [
|
2023-02-13 11:32:50 -08:00
|
|
|
ValidationWord(groupIndex: 0, word: "salute".redacted),
|
|
|
|
ValidationWord(groupIndex: 1, word: "boil".redacted),
|
|
|
|
ValidationWord(groupIndex: 2, word: "cancel".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
XCTAssertNil(currentStep.resultingPhrase)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testRecoveryPhraseValidationStateIsNotCompleteAndNotValidWhenNotCompleted() {
|
|
|
|
let words = [
|
|
|
|
"bring", "salute", "thank",
|
|
|
|
"require", "spirit", "toe",
|
|
|
|
// second chunk
|
|
|
|
"boil", "hill", "casino",
|
|
|
|
"trophy", "drink", "frown",
|
|
|
|
// third chunk
|
|
|
|
"bird", "grit", "close",
|
|
|
|
"morning", "bind", "cancel",
|
|
|
|
// Fourth chunk
|
|
|
|
"daughter", "salon", "quit",
|
|
|
|
"pizza", "just", "garlic"
|
|
|
|
]
|
|
|
|
|
|
|
|
let missingIndices = [1, 0, 5, 3]
|
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
let phrase = RecoveryPhrase(words: words.map { $0.redacted })
|
2021-12-13 12:50:04 -08:00
|
|
|
|
2022-11-04 23:11:25 -07:00
|
|
|
let currentStep = RecoveryPhraseValidationFlowReducer.State(
|
2021-12-13 12:50:04 -08:00
|
|
|
phrase: phrase,
|
|
|
|
missingIndices: missingIndices,
|
|
|
|
missingWordChips: [
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty,
|
|
|
|
PhraseChip.Kind.empty,
|
2023-02-13 11:32:50 -08:00
|
|
|
PhraseChip.Kind.unassigned(word: "pizza".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
],
|
|
|
|
validationWords: [
|
2023-02-13 11:32:50 -08:00
|
|
|
ValidationWord(groupIndex: 0, word: "salute".redacted),
|
|
|
|
ValidationWord(groupIndex: 1, word: "boil".redacted),
|
|
|
|
ValidationWord(groupIndex: 2, word: "cancel".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
XCTAssertFalse(currentStep.isComplete)
|
|
|
|
XCTAssertFalse(currentStep.isValid)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testCreateResultPhraseFromCompletion() {
|
|
|
|
let words = [
|
|
|
|
"bring", "salute", "thank",
|
|
|
|
"require", "spirit", "toe",
|
|
|
|
// second chunk
|
|
|
|
"boil", "hill", "casino",
|
|
|
|
"trophy", "drink", "frown",
|
|
|
|
// third chunk
|
|
|
|
"bird", "grit", "close",
|
|
|
|
"morning", "bind", "cancel",
|
|
|
|
// Fourth chunk
|
|
|
|
"daughter", "salon", "quit",
|
|
|
|
"pizza", "just", "garlic"
|
|
|
|
]
|
|
|
|
|
|
|
|
let missingIndices = [1, 0, 5, 3]
|
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
let phrase = RecoveryPhrase(words: words.map { $0.redacted })
|
2021-12-13 12:50:04 -08:00
|
|
|
|
|
|
|
let completion = [
|
2023-02-13 11:32:50 -08:00
|
|
|
ValidationWord(groupIndex: 0, word: "salute".redacted),
|
|
|
|
ValidationWord(groupIndex: 1, word: "boil".redacted),
|
|
|
|
ValidationWord(groupIndex: 2, word: "cancel".redacted),
|
|
|
|
ValidationWord(groupIndex: 3, word: "pizza".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
]
|
|
|
|
|
2022-11-04 23:11:25 -07:00
|
|
|
let result = RecoveryPhraseValidationFlowReducer.State(
|
2021-12-13 12:50:04 -08:00
|
|
|
phrase: phrase,
|
|
|
|
missingIndices: missingIndices,
|
|
|
|
missingWordChips: phrase.words(fromMissingIndices: missingIndices),
|
|
|
|
validationWords: completion,
|
2022-12-01 06:31:30 -08:00
|
|
|
destination: nil
|
2021-12-13 12:50:04 -08:00
|
|
|
)
|
|
|
|
|
|
|
|
XCTAssertTrue(result.isValid)
|
|
|
|
XCTAssertTrue(result.isComplete)
|
2023-02-13 11:32:50 -08:00
|
|
|
XCTAssertEqual(words.map { $0.redacted }, result.resultingPhrase)
|
2021-12-13 12:50:04 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
func testCreateResultPhraseInvalidPhraseFromCompletion() {
|
|
|
|
let words = [
|
|
|
|
"bring", "salute", "thank",
|
|
|
|
"require", "spirit", "toe",
|
|
|
|
// second chunk
|
|
|
|
"boil", "hill", "casino",
|
|
|
|
"trophy", "drink", "frown",
|
|
|
|
// third chunk
|
|
|
|
"bird", "grit", "close",
|
|
|
|
"morning", "bind", "cancel",
|
|
|
|
// Fourth chunk
|
|
|
|
"daughter", "salon", "quit",
|
|
|
|
"pizza", "just", "garlic"
|
|
|
|
]
|
|
|
|
|
|
|
|
let missingIndices = [1, 0, 5, 3]
|
|
|
|
|
2023-02-13 11:32:50 -08:00
|
|
|
let phrase = RecoveryPhrase(words: words.map { $0.redacted })
|
2021-12-13 12:50:04 -08:00
|
|
|
|
|
|
|
let completion = [
|
2023-02-13 11:32:50 -08:00
|
|
|
ValidationWord(groupIndex: 3, word: "salute".redacted),
|
|
|
|
ValidationWord(groupIndex: 1, word: "boil".redacted),
|
|
|
|
ValidationWord(groupIndex: 0, word: "cancel".redacted),
|
|
|
|
ValidationWord(groupIndex: 2, word: "pizza".redacted)
|
2021-12-13 12:50:04 -08:00
|
|
|
]
|
|
|
|
|
2022-11-04 23:11:25 -07:00
|
|
|
let result = RecoveryPhraseValidationFlowReducer.State(
|
2021-12-13 12:50:04 -08:00
|
|
|
phrase: phrase,
|
|
|
|
missingIndices: missingIndices,
|
|
|
|
missingWordChips: phrase.words(fromMissingIndices: missingIndices),
|
|
|
|
validationWords: completion,
|
2022-12-01 06:31:30 -08:00
|
|
|
destination: nil
|
2021-12-13 12:50:04 -08:00
|
|
|
)
|
|
|
|
|
|
|
|
XCTAssertFalse(result.isValid)
|
|
|
|
XCTAssertTrue(result.isComplete)
|
2023-02-13 11:32:50 -08:00
|
|
|
XCTAssertNotEqual(words.map { $0.redacted }, result.resultingPhrase)
|
2021-12-13 12:50:04 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-04 23:11:25 -07:00
|
|
|
extension RecoveryPhraseValidationFlowReducer.State {
|
2021-12-13 12:50:04 -08:00
|
|
|
static func initial(
|
|
|
|
phrase: RecoveryPhrase,
|
|
|
|
missingIndices: [Int],
|
|
|
|
missingWordsChips: [PhraseChip.Kind]
|
|
|
|
) -> Self {
|
2022-11-04 23:11:25 -07:00
|
|
|
RecoveryPhraseValidationFlowReducer.State(
|
2021-12-13 12:50:04 -08:00
|
|
|
phrase: phrase,
|
|
|
|
missingIndices: missingIndices,
|
|
|
|
missingWordChips: missingWordsChips,
|
|
|
|
validationWords: []
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|