PR Fixes. Move .initial factory method to test target. Rename given() to apply(chip:group:) and make it a member function

This commit is contained in:
Francisco Gindre 2021-12-20 19:27:30 -03:00
parent a2546abee6
commit e94021b4be
2 changed files with 42 additions and 38 deletions

View File

@ -58,19 +58,6 @@ struct RecoveryPhraseValidationState: Equatable {
extension RecoveryPhraseValidationState { extension RecoveryPhraseValidationState {
static func initial(
phrase: RecoveryPhrase,
missingIndices: [Int],
missingWordsChips: [PhraseChip.Kind]
) -> Self {
RecoveryPhraseValidationState(
phrase: phrase,
missingIndices: missingIndices,
missingWordChips: missingWordsChips,
completion: []
)
}
/// creates an initial `RecoveryPhraseValidationState` with no completions and random missing indices. /// creates an initial `RecoveryPhraseValidationState` with no completions and random missing indices.
/// - Note: Use this function to create a random validation puzzle for a given phrase. /// - Note: Use this function to create a random validation puzzle for a given phrase.
static func random(phrase: RecoveryPhrase) -> Self { static func random(phrase: RecoveryPhrase) -> Self {
@ -119,60 +106,60 @@ extension RecoveryPhraseValidationState {
} }
/// drives the state machine represented on this Enum by the action of applying a chip into a group of words containing an empty slot that has to be completed /// drives the state machine represented on this Enum by the action of applying a chip into a group of words containing an empty slot that has to be completed
static func given(_ state: RecoveryPhraseValidationState, apply chip: PhraseChip.Kind, into group: Int) -> Self { func apply(chip: PhraseChip.Kind, into group: Int) -> Self {
guard case let PhraseChip.Kind.unassigned(word) = chip else { return state } guard case let PhraseChip.Kind.unassigned(word) = chip else { return self }
switch state.step { switch self.step {
case .initial: case .initial:
guard let missingChipIndex = state.missingWordChips.firstIndex(of: chip) else { return state } guard let missingChipIndex = missingWordChips.firstIndex(of: chip) else { return self }
var newMissingWords = state.missingWordChips var newMissingWords = missingWordChips
newMissingWords[missingChipIndex] = .empty newMissingWords[missingChipIndex] = .empty
return RecoveryPhraseValidationState( return RecoveryPhraseValidationState(
phrase: state.phrase, phrase: phrase,
missingIndices: state.missingIndices, missingIndices: missingIndices,
missingWordChips: newMissingWords, missingWordChips: newMissingWords,
completion: [RecoveryPhraseStepCompletion(groupIndex: group, word: word)] completion: [RecoveryPhraseStepCompletion(groupIndex: group, word: word)]
) )
case .incomplete: case .incomplete:
guard let missingChipIndex = state.missingWordChips.firstIndex(of: chip) else { return state } guard let missingChipIndex = missingWordChips.firstIndex(of: chip) else { return self }
if state.completion.count < (RecoveryPhraseValidationState.phraseChunks - 1) { if completion.count < (RecoveryPhraseValidationState.phraseChunks - 1) {
var newMissingWords = state.missingWordChips var newMissingWords = missingWordChips
newMissingWords[missingChipIndex] = .empty newMissingWords[missingChipIndex] = .empty
var newCompletionState = Array(state.completion) var newCompletionState = Array(completion)
newCompletionState.append(RecoveryPhraseStepCompletion(groupIndex: group, word: word)) newCompletionState.append(RecoveryPhraseStepCompletion(groupIndex: group, word: word))
return RecoveryPhraseValidationState( return RecoveryPhraseValidationState(
phrase: state.phrase, phrase: phrase,
missingIndices: state.missingIndices, missingIndices: missingIndices,
missingWordChips: newMissingWords, missingWordChips: newMissingWords,
completion: newCompletionState completion: newCompletionState
) )
} else { } else {
var newCompletion = state.completion var newCompletion = completion
newCompletion.append(RecoveryPhraseStepCompletion(groupIndex: group, word: word)) newCompletion.append(RecoveryPhraseStepCompletion(groupIndex: group, word: word))
return RecoveryPhraseValidationState( return RecoveryPhraseValidationState(
phrase: state.phrase, phrase: phrase,
missingIndices: state.missingIndices, missingIndices: missingIndices,
missingWordChips: Array(repeating: .empty, count: RecoveryPhraseValidationState.phraseChunks), missingWordChips: Array(repeating: .empty, count: RecoveryPhraseValidationState.phraseChunks),
completion: newCompletion completion: newCompletion
) )
} }
default: default:
return state return self
} }
} }
static func pickWordsFromMissingIndices(indices: [Int], phrase: RecoveryPhrase) -> [PhraseChip.Kind] { static func pickWordsFromMissingIndices(indices: [Int], phrase: RecoveryPhrase) -> [PhraseChip.Kind] {
precondition((indices.count - 1) * wordGroupSize <= phrase.words.count) precondition((indices.count - 1) * Self.wordGroupSize <= phrase.words.count)
var words: [PhraseChip.Kind] = [] var words: [PhraseChip.Kind] = []
indices.enumerated().forEach({ index, position in indices.enumerated().forEach({ index, position in
let realIndex = (index * wordGroupSize) + position let realIndex = (index * Self.wordGroupSize) + position
words.append(.unassigned(word: phrase.words[realIndex])) words.append(.unassigned(word: phrase.words[realIndex]))
}) })
return words return words
@ -212,7 +199,7 @@ extension RecoveryPhraseValidationReducer {
return .none return .none
case let .drag(wordChip, group): case let .drag(wordChip, group):
state = .given(state, apply: wordChip, into: group) state = state.apply(chip: wordChip, into: group)
return .none return .none
case .validate: case .validate:

View File

@ -28,6 +28,8 @@ class RecoveryPhraseValidationTests: XCTestCase {
let indices = [1, 0, 5, 3] let indices = [1, 0, 5, 3]
let expected = ["salute", "boil", "cancel", "pizza"].map({ PhraseChip.Kind.unassigned(word: $0) }) let expected = ["salute", "boil", "cancel", "pizza"].map({ PhraseChip.Kind.unassigned(word: $0) })
let result = RecoveryPhraseValidationState.pickWordsFromMissingIndices(indices: indices, phrase: phrase) let result = RecoveryPhraseValidationState.pickWordsFromMissingIndices(indices: indices, phrase: phrase)
XCTAssertEqual(expected, result) XCTAssertEqual(expected, result)
@ -73,7 +75,7 @@ class RecoveryPhraseValidationTests: XCTestCase {
completion: [RecoveryPhraseStepCompletion(groupIndex: 1, word: "salute")] completion: [RecoveryPhraseStepCompletion(groupIndex: 1, word: "salute")]
) )
let result = RecoveryPhraseValidationState.given(initialStep, apply: missingWordChips[0], into: 1) let result = initialStep.apply(chip: missingWordChips[0], into: 1)
XCTAssertEqual(expectedStep, result) XCTAssertEqual(expectedStep, result)
} }
@ -120,7 +122,7 @@ class RecoveryPhraseValidationTests: XCTestCase {
completion: expectedCompletion completion: expectedCompletion
) )
let result = RecoveryPhraseValidationState.given(initialStep, apply: missingWordChips[3], into: 0) let result = initialStep.apply(chip: missingWordChips[3], into: 0)
XCTAssertEqual(expectedStep, result) XCTAssertEqual(expectedStep, result)
XCTAssertEqual(result.step, .incomplete) XCTAssertEqual(result.step, .incomplete)
@ -171,7 +173,7 @@ class RecoveryPhraseValidationTests: XCTestCase {
] ]
) )
let result = RecoveryPhraseValidationState.given(currentStep, apply: PhraseChip.Kind.unassigned(word: "boil"), into: 1) let result = currentStep.apply(chip: PhraseChip.Kind.unassigned(word: "boil"), into: 1)
XCTAssertEqual(expected, result) XCTAssertEqual(expected, result)
XCTAssertEqual(expected.step, result.step) XCTAssertEqual(expected.step, result.step)
@ -227,7 +229,7 @@ class RecoveryPhraseValidationTests: XCTestCase {
] ]
) )
let result = RecoveryPhraseValidationState.given(currentStep, apply: PhraseChip.Kind.unassigned(word: "cancel"), into: 2) let result = currentStep.apply(chip: PhraseChip.Kind.unassigned(word: "cancel"), into: 2)
XCTAssertEqual(expected, result) XCTAssertEqual(expected, result)
} }
@ -284,7 +286,7 @@ class RecoveryPhraseValidationTests: XCTestCase {
] ]
) )
let result = RecoveryPhraseValidationState.given(currentStep, apply: PhraseChip.Kind.unassigned(word: "pizza"), into: 3) let result = currentStep.apply(chip: PhraseChip.Kind.unassigned(word: "pizza"), into: 3)
XCTAssertEqual(expected, result) XCTAssertEqual(expected, result)
} }
@ -442,3 +444,18 @@ class RecoveryPhraseValidationTests: XCTestCase {
XCTAssertEqual(expected, result) XCTAssertEqual(expected, result)
} }
} }
extension RecoveryPhraseValidationState {
static func initial(
phrase: RecoveryPhrase,
missingIndices: [Int],
missingWordsChips: [PhraseChip.Kind]
) -> Self {
RecoveryPhraseValidationState(
phrase: phrase,
missingIndices: missingIndices,
missingWordChips: missingWordsChips,
completion: []
)
}
}