| 1 |
package io.oxygenhub.android.secondfactor |
| 2 |
|
| 3 |
import io.oxygenhub.android.FakeHubApi |
| 4 |
import io.oxygenhub.android.MainDispatcherRule |
| 5 |
import io.oxygenhub.android.api.HubException |
| 6 |
import io.oxygenhub.android.api.PendingApproval |
| 7 |
import kotlinx.coroutines.test.runTest |
| 8 |
import org.junit.Assert.assertEquals |
| 9 |
import org.junit.Assert.assertNull |
| 10 |
import org.junit.Assert.assertTrue |
| 11 |
import org.junit.Rule |
| 12 |
import org.junit.Test |
| 13 |
|
| 14 |
class ApprovalsViewModelTest { |
| 15 |
@get:Rule val main = MainDispatcherRule() |
| 16 |
|
| 17 |
private val signIn = PendingApproval("ab12", "signin", "Sign in from Firefox on Linux, 203.0.113.9", listOf(12, 47, 83)) |
| 18 |
|
| 19 |
@Test |
| 20 |
fun theMessageIsTheOneTheHubChecks() { |
| 21 |
// oxygenhub's auth::phone::message, byte for byte. |
| 22 |
assertEquals("oxygenhub approval v1\nab12\n47\napprove", ApprovalMessage.of("ab12", 47, true).decodeToString()) |
| 23 |
assertEquals("oxygenhub approval v1\nab12\n47\ndeny", ApprovalMessage.of("ab12", 47, false).decodeToString()) |
| 24 |
assertEquals("00ff10", byteArrayOf(0, -1, 16).toHex()) |
| 25 |
} |
| 26 |
|
| 27 |
@Test |
| 28 |
fun aWaitingApprovalIsShownAndApprovingSignsTheNumberPicked() = runTest { |
| 29 |
val api = FakeHubApi() |
| 30 |
api.approvals = { listOf(signIn) } |
| 31 |
val vm = ApprovalsViewModel(api) |
| 32 |
vm.check() |
| 33 |
assertEquals(signIn, vm.waiting.value) |
| 34 |
var signed: String? = null |
| 35 |
vm.approve(signIn, 47) { m -> signed = m.decodeToString(); byteArrayOf(1, 2) } |
| 36 |
assertEquals("oxygenhub approval v1\nab12\n47\napprove", signed) |
| 37 |
assertEquals(listOf(Triple("ab12", true, 47L)), api.answers) |
| 38 |
assertTrue(api.calls.contains("answer ab12 true 47 true")) |
| 39 |
assertNull("answered: not shown again", vm.waiting.value) |
| 40 |
assertEquals("Approved: the browser is signing in.", vm.said.value) |
| 41 |
vm.check() |
| 42 |
assertNull("still listed until the hub catches up, but not shown again", vm.waiting.value) |
| 43 |
} |
| 44 |
|
| 45 |
@Test |
| 46 |
fun backingOutOfThePromptSendsNothing() = runTest { |
| 47 |
val api = FakeHubApi() |
| 48 |
api.approvals = { listOf(signIn) } |
| 49 |
val vm = ApprovalsViewModel(api) |
| 50 |
vm.check() |
| 51 |
vm.approve(signIn, 47) { null } |
| 52 |
assertTrue(api.answers.isEmpty()) |
| 53 |
assertEquals(signIn, vm.waiting.value) |
| 54 |
assertTrue(vm.said.value!!.startsWith("Not approved")) |
| 55 |
} |
| 56 |
|
| 57 |
@Test |
| 58 |
fun aWrongNumberAndANoAreSaidPlainly() = runTest { |
| 59 |
val api = FakeHubApi() |
| 60 |
api.approvals = { listOf(signIn) } |
| 61 |
api.answerState = { n -> if (n == 47L) "approved" else "denied" } |
| 62 |
val vm = ApprovalsViewModel(api) |
| 63 |
vm.check() |
| 64 |
vm.approve(signIn, 12) { byteArrayOf(1) } |
| 65 |
assertTrue(vm.said.value!!.contains("not the number")) |
| 66 |
val other = signIn.copy(id = "cd34") |
| 67 |
api.approvals = { listOf(other) } |
| 68 |
vm.check() |
| 69 |
vm.deny(other) |
| 70 |
assertEquals(Triple("cd34", false, 0L), api.answers.last()) |
| 71 |
assertTrue(vm.said.value!!.startsWith("Refused")) |
| 72 |
} |
| 73 |
|
| 74 |
@Test |
| 75 |
fun aHubThatCannotSayLeavesNothingShown() = runTest { |
| 76 |
val api = FakeHubApi() |
| 77 |
api.approvals = { throw HubException.Http(404, "no such API route") } |
| 78 |
val vm = ApprovalsViewModel(api) |
| 79 |
vm.check() |
| 80 |
assertNull(vm.waiting.value) |
| 81 |
} |
| 82 |
} |