Initial commit
This initial commit includes HUSH specific changes starting at this commit:
d14637012c
This commit is contained in:
43
app/src/androidTest/java/cash/z/ecc/android/MemoTest.kt
Normal file
43
app/src/androidTest/java/cash/z/ecc/android/MemoTest.kt
Normal file
@@ -0,0 +1,43 @@
|
||||
package cash.z.ecc.android
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import kotlinx.coroutines.delay
|
||||
import org.junit.Ignore
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
@Ignore("It'd need additional implementation changes to have this one working.")
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
// @RunWith(Parameterized::class)
|
||||
class MemoTest(val input: String, val output: String) {
|
||||
|
||||
// @Test
|
||||
// fun testExtractValidAddress() = runBlocking {
|
||||
// val result = MemoUtil.findAddressInMemo(input, ::validateMemo)
|
||||
// assertEquals(output, result)
|
||||
// }
|
||||
|
||||
suspend fun validateMemo(memo: String): Boolean {
|
||||
delay(20)
|
||||
return true
|
||||
}
|
||||
|
||||
companion object {
|
||||
val validTaddr = "tmWGKMEpxSUf97H12MmGtgiER1drVbGjzWM"
|
||||
val validZaddr = "ztestsapling1ukadr59p0hxcl2pq8mfagnfx3h74nsusdkm59gkys7hxze92whxj54mfdn3n37zusum7w4jlj35"
|
||||
val invalidAddr = "ztestsaplinn9ukadr59p0hxcl2pq8mfagnfx3h74nsusdkm59gkys7hxze92whxj54mfdn3n37zusum7w4jlj35"
|
||||
|
||||
@JvmStatic
|
||||
@Parameterized.Parameters
|
||||
fun data() = listOf(
|
||||
arrayOf(
|
||||
"thanks for the food reply-to: $validZaddr",
|
||||
validZaddr
|
||||
),
|
||||
arrayOf(
|
||||
"thanks for the food reply-to: $validTaddr",
|
||||
validTaddr
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package cash.z.ecc.android.integration
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import cash.z.ecc.android.ext.WalletZecFormmatter
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ConversionsTest {
|
||||
|
||||
@Test
|
||||
fun testToZatoshi() {
|
||||
val input = "1"
|
||||
val result = WalletZecFormmatter.toZatoshi(input)
|
||||
Assert.assertEquals(100_000_000L, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToZecString_short() {
|
||||
val input = Zatoshi(112_340_000L)
|
||||
val result = WalletZecFormmatter.toZecStringShort(input)
|
||||
Assert.assertEquals("1.1234", result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToZecString_shortRoundUp() {
|
||||
val input = Zatoshi(112_355_600L)
|
||||
val result = WalletZecFormmatter.toZecStringShort(input)
|
||||
Assert.assertEquals("1.1236", result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToZecString_shortRoundDown() {
|
||||
val input = Zatoshi(112_343_999L)
|
||||
val result = WalletZecFormmatter.toZecStringShort(input)
|
||||
Assert.assertEquals("1.1234", result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToZecString_shortRoundHalfEven() {
|
||||
val input = Zatoshi(112_345_000L)
|
||||
val result = WalletZecFormmatter.toZecStringShort(input)
|
||||
Assert.assertEquals("1.1234", result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToZecString_shortRoundHalfOdd() {
|
||||
val input = Zatoshi(112_355_000L)
|
||||
val result = WalletZecFormmatter.toZecStringShort(input)
|
||||
Assert.assertEquals("1.1236", result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToBigDecimal_noCommas() {
|
||||
val input = "1000"
|
||||
val result = WalletZecFormmatter.toBigDecimal(input)!!
|
||||
Assert.assertEquals(1000, result.longValueExact())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToBigDecimal_thousandComma() {
|
||||
val input = "1,000"
|
||||
val result = WalletZecFormmatter.toBigDecimal(input)!!
|
||||
Assert.assertEquals(1000, result.longValueExact())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToBigDecimal_thousandCommaWithDecimal() {
|
||||
val input = "1,000.00"
|
||||
val result = WalletZecFormmatter.toBigDecimal(input)!!
|
||||
Assert.assertEquals(1000, result.longValueExact())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToBigDecimal_oneDecimal() {
|
||||
val input = "1.000"
|
||||
val result = WalletZecFormmatter.toBigDecimal(input)!!
|
||||
Assert.assertEquals(1, result.longValueExact())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToBigDecimal_thousandWithThinSpace() {
|
||||
val input = "1 000"
|
||||
val result = WalletZecFormmatter.toBigDecimal(input)!!
|
||||
Assert.assertEquals(1000, result.longValueExact())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToBigDecimal_oneWithThinSpace() {
|
||||
val input = "1.000 000"
|
||||
val result = WalletZecFormmatter.toBigDecimal(input)!!
|
||||
Assert.assertEquals(1, result.longValueExact())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToBigDecimal_oneDecimalWithComma() {
|
||||
val input = "1.000,00"
|
||||
val result = WalletZecFormmatter.toBigDecimal(input)!!
|
||||
Assert.assertEquals(1, result.longValueExact())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToZecString_full() {
|
||||
val input = Zatoshi(112_341_123L)
|
||||
val result = WalletZecFormmatter.toZecStringFull(input)
|
||||
Assert.assertEquals("1.12341123", result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToZecString_fullRoundUp() {
|
||||
val input = Zatoshi(112_355_678L)
|
||||
val result = WalletZecFormmatter.toZecStringFull(input)
|
||||
Assert.assertEquals("1.12355678", result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToZecString_fullRoundDown() {
|
||||
val input = Zatoshi(112_349_999L)
|
||||
val result = WalletZecFormmatter.toZecStringFull(input)
|
||||
Assert.assertEquals("1.12349999", result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToZecString_fullRoundHalfEven() {
|
||||
val input = Zatoshi(112_250_009L)
|
||||
val result = WalletZecFormmatter.toZecStringFull(input)
|
||||
Assert.assertEquals("1.12250009", result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToZecString_fullRoundHalfOdd() {
|
||||
val input = Zatoshi(112_350_004L)
|
||||
val result = WalletZecFormmatter.toZecStringFull(input)
|
||||
Assert.assertEquals("1.12350004", result)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package cash.z.ecc.android.integration
|
||||
|
||||
import android.content.Context
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import cash.z.ecc.android.lockbox.LockBox
|
||||
import cash.z.ecc.android.sdk.Initializer
|
||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||
import cash.z.ecc.kotlin.mnemonic.Mnemonics
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import okio.Buffer
|
||||
import okio.GzipSink
|
||||
import okio.buffer
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class IntegrationTest {
|
||||
|
||||
private lateinit var appContext: Context
|
||||
private val network = ZcashNetwork.Testnet
|
||||
private val mnemonics = Mnemonics()
|
||||
private val phrase =
|
||||
"human pulse approve subway climb stairs mind gentle raccoon warfare fog roast sponsor" +
|
||||
" under absorb spirit hurdle animal original honey owner upper empower describe"
|
||||
|
||||
@Before
|
||||
fun start() {
|
||||
appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSeed_generation() {
|
||||
val seed = mnemonics.toSeed(phrase.toCharArray())
|
||||
assertEquals(
|
||||
"Generated incorrect BIP-39 seed!",
|
||||
"f4e3d38d9c244da7d0407e19a93c80429614ee82dcf62c141235751c9f1228905d12a1f275f" +
|
||||
"5c22f6fb7fcd9e0a97f1676e0eec53fdeeeafe8ce8aa39639b9fe",
|
||||
seed.toHex()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSeed_storage() {
|
||||
val seed = mnemonics.toSeed(phrase.toCharArray())
|
||||
val lb = LockBox(appContext)
|
||||
lb.setBytes("seed", seed)
|
||||
assertTrue(seed.contentEquals(lb.getBytes("seed")!!))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPhrase_storage() {
|
||||
val lb = LockBox(appContext)
|
||||
val phraseChars = phrase.toCharArray()
|
||||
lb.setCharsUtf8("phrase", phraseChars)
|
||||
assertTrue(phraseChars.contentEquals(lb.getCharsUtf8("phrase")!!))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPhrase_maxLengthStorage() {
|
||||
val lb = LockBox(appContext)
|
||||
// find and expose the max length
|
||||
var acceptedSize = 256
|
||||
while (acceptedSize > 0) {
|
||||
try {
|
||||
lb.setCharsUtf8("temp", nextString(acceptedSize).toCharArray())
|
||||
break
|
||||
} catch (t: Throwable) {
|
||||
}
|
||||
acceptedSize--
|
||||
}
|
||||
|
||||
val maxSeedPhraseLength = 8 * 24 + 23 // 215 (max length of each word is 8)
|
||||
assertTrue(
|
||||
"LockBox does not support the maximum length seed phrase." +
|
||||
" Expected: $maxSeedPhraseLength but was: $acceptedSize",
|
||||
acceptedSize > maxSeedPhraseLength
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("It'd need additional implementation changes to have this one working.")
|
||||
fun testAddress() = runTest {
|
||||
val seed = mnemonics.toSeed(phrase.toCharArray())
|
||||
val initializer = Initializer.new(appContext) { config ->
|
||||
// config.newWallet(seed, network)
|
||||
}
|
||||
assertEquals(
|
||||
"Generated incorrect z-address!",
|
||||
"zs1gn2ah0zqhsxnrqwuvwmgxpl5h3ha033qexhsz8tems53fw877f4gug353eefd6z8z3n4zxty65c",
|
||||
// initializer.rustBackend.getShieldedAddress()
|
||||
)
|
||||
initializer.erase()
|
||||
}
|
||||
|
||||
private fun ByteArray.toHex(): String {
|
||||
val sb = StringBuilder(size * 2)
|
||||
for (b in this)
|
||||
sb.append(String.format("%02x", b))
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
fun String.gzip(): ByteArray {
|
||||
val result = Buffer()
|
||||
val sink = GzipSink(result).buffer()
|
||||
sink.use {
|
||||
sink.write(toByteArray())
|
||||
}
|
||||
return result.readByteArray()
|
||||
}
|
||||
|
||||
fun nextString(length: Int): String {
|
||||
val allowedChars = "ACGT"
|
||||
return (1..length)
|
||||
.map { allowedChars.random() }
|
||||
.joinToString("")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package cash.z.ecc.android.integration
|
||||
|
||||
import android.content.Context
|
||||
import androidx.test.filters.LargeTest
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import cash.z.ecc.android.lockbox.LockBox
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
|
||||
class LockBoxTest {
|
||||
|
||||
lateinit var lockBox: LockBox
|
||||
lateinit var appContext: Context
|
||||
private val hex = ('a'..'f') + ('0'..'9')
|
||||
private val iterations = 50
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
lockBox = LockBox(appContext)
|
||||
lockBox.clear()
|
||||
}
|
||||
|
||||
@Test
|
||||
@LargeTest
|
||||
@Ignore("This test is extremely slow")
|
||||
fun testLongString() {
|
||||
var successCount = 0
|
||||
repeat(iterations) {
|
||||
val sampleHex = List(500) { hex.random() }.joinToString("")
|
||||
|
||||
lockBox["longStr"] = sampleHex
|
||||
val actual: String = lockBox["longStr"]!!
|
||||
if (sampleHex == actual) successCount++
|
||||
lockBox.clear()
|
||||
}
|
||||
assertEquals(iterations, successCount)
|
||||
}
|
||||
|
||||
@Test
|
||||
@LargeTest
|
||||
@Ignore("This test is extremely slow")
|
||||
fun testShortString() {
|
||||
var successCount = 0
|
||||
repeat(iterations) {
|
||||
val sampleHex = List(50) { hex.random() }.joinToString("")
|
||||
|
||||
lockBox["shortStr"] = sampleHex
|
||||
val actual: String = lockBox["shortStr"]!!
|
||||
if (sampleHex == actual) successCount++
|
||||
lockBox.clear()
|
||||
}
|
||||
assertEquals(iterations, successCount)
|
||||
}
|
||||
|
||||
@Test
|
||||
@LargeTest
|
||||
@Ignore("This test is extremely slow")
|
||||
fun testGiantString() {
|
||||
var successCount = 0
|
||||
repeat(iterations) {
|
||||
val sampleHex = List(2500) { hex.random() }.joinToString("")
|
||||
|
||||
lockBox["giantStr"] = sampleHex
|
||||
val actual: String = lockBox["giantStr"]!!
|
||||
if (sampleHex == actual) successCount++
|
||||
lockBox.clear()
|
||||
}
|
||||
assertEquals(iterations, successCount)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package cash.z.ecc.android.preference
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.lang.reflect.Modifier
|
||||
import kotlin.reflect.full.memberProperties
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class PreferenceKeysTest {
|
||||
@SmallTest
|
||||
@Test
|
||||
@Throws(IllegalAccessException::class)
|
||||
fun fields_public_static_and_final() {
|
||||
PreferenceKeys::class.java.fields.forEach {
|
||||
val modifiers = it.modifiers
|
||||
assertThat(Modifier.isFinal(modifiers), equalTo(true))
|
||||
assertThat(Modifier.isStatic(modifiers), equalTo(true))
|
||||
assertThat(Modifier.isPublic(modifiers), equalTo(true))
|
||||
}
|
||||
}
|
||||
|
||||
// This test is primary to prevent copy-paste errors in preference keys
|
||||
@SmallTest
|
||||
@Test
|
||||
fun key_values_unique() {
|
||||
val fieldValueSet = mutableSetOf<String>()
|
||||
|
||||
PreferenceKeys::class.memberProperties
|
||||
.map { it.getter.call() }
|
||||
.map { it as String }
|
||||
.forEach {
|
||||
assertThat("Duplicate key $it", fieldValueSet.contains(it), equalTo(false))
|
||||
|
||||
fieldValueSet.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package cash.z.ecc.android.preference
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import cash.z.ecc.android.preference.model.DefaultValue
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.lang.reflect.Modifier
|
||||
import kotlin.reflect.full.memberProperties
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class PreferencesTest {
|
||||
@SmallTest
|
||||
@Test
|
||||
@Throws(IllegalAccessException::class)
|
||||
fun fields_public_static_and_final() {
|
||||
Preferences::class.java.fields.forEach {
|
||||
val modifiers = it.modifiers
|
||||
assertThat(Modifier.isFinal(modifiers), equalTo(true))
|
||||
assertThat(Modifier.isStatic(modifiers), equalTo(true))
|
||||
assertThat(Modifier.isPublic(modifiers), equalTo(true))
|
||||
}
|
||||
}
|
||||
|
||||
// This test is primary to prevent copy-paste errors in preference keys
|
||||
@SmallTest
|
||||
@Test
|
||||
fun key_values_unique() {
|
||||
val fieldValueSet = mutableSetOf<String>()
|
||||
|
||||
Preferences::class.memberProperties
|
||||
.map { it.getter.call(Preferences) }
|
||||
.map { it as DefaultValue<*> }
|
||||
.forEach {
|
||||
assertThat(
|
||||
"Duplicate key ${it.key}",
|
||||
fieldValueSet.contains(it.key),
|
||||
equalTo(false)
|
||||
)
|
||||
|
||||
fieldValueSet.add(it.key)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package cash.z.ecc.android.test
|
||||
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.testing.FragmentScenario
|
||||
import androidx.navigation.Navigation
|
||||
import androidx.navigation.testing.TestNavHostController
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
|
||||
data class FragmentNavigationScenario<T : Fragment>(
|
||||
val fragmentScenario: FragmentScenario<T>,
|
||||
val navigationController: TestNavHostController
|
||||
) {
|
||||
|
||||
companion object {
|
||||
fun <T : Fragment> new(
|
||||
fragmentScenario: FragmentScenario<T>,
|
||||
@IdRes currentDestination: Int
|
||||
): FragmentNavigationScenario<T> {
|
||||
val navController = TestNavHostController(ApplicationProvider.getApplicationContext())
|
||||
|
||||
fragmentScenario.onFragment {
|
||||
navController.setGraph(cash.z.ecc.android.R.navigation.mobile_navigation)
|
||||
navController.setCurrentDestination(currentDestination)
|
||||
|
||||
Navigation.setViewNavController(it.requireView(), navController)
|
||||
}
|
||||
|
||||
return FragmentNavigationScenario(fragmentScenario, navController)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package cash.z.ecc.android.test
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.PowerManager
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.Before
|
||||
import java.lang.AssertionError
|
||||
|
||||
/**
|
||||
* Subclass this for UI tests to ensure they run correctly. This helps when developers run tests
|
||||
* against a physical device that might have gone to sleep.
|
||||
*/
|
||||
open class UiTestPrerequisites {
|
||||
@Before
|
||||
fun verifyScreenOn() {
|
||||
if (!isScreenOn()) {
|
||||
throw AssertionError("Screen must be on for UI tests to run") // $NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
|
||||
private fun isScreenOn(): Boolean {
|
||||
val powerService = ApplicationProvider.getApplicationContext<Context>()
|
||||
.getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||
return powerService.isInteractive
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package cash.z.ecc.android.ui.home
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import androidx.fragment.app.testing.FragmentScenario
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.action.ViewActions
|
||||
import androidx.test.espresso.intent.Intents
|
||||
import androidx.test.espresso.intent.Intents.intended
|
||||
import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import cash.z.ecc.android.preference.Preferences
|
||||
import cash.z.ecc.android.preference.SharedPreferenceFactory
|
||||
import cash.z.ecc.android.preference.model.get
|
||||
import cash.z.ecc.android.test.FragmentNavigationScenario
|
||||
import cash.z.ecc.android.test.UiTestPrerequisites
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class AutoshieldingInformationFragmentTest : UiTestPrerequisites() {
|
||||
@Test
|
||||
@MediumTest
|
||||
fun dismiss_returns_home_when_autoshield_not_available() {
|
||||
val fragmentNavigationScenario = newScenario(isAutoshieldAvailable = false)
|
||||
|
||||
onView(withId(cash.z.ecc.android.R.id.button_autoshield_dismiss)).also {
|
||||
it.perform(ViewActions.click())
|
||||
}
|
||||
|
||||
assertThat(
|
||||
fragmentNavigationScenario.navigationController.currentDestination?.id,
|
||||
equalTo(cash.z.ecc.android.R.id.nav_home)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
fun dismiss_starts_autoshield_when_autoshield_available() {
|
||||
val fragmentNavigationScenario = newScenario(isAutoshieldAvailable = true)
|
||||
|
||||
onView(withId(cash.z.ecc.android.R.id.button_autoshield_dismiss)).also {
|
||||
it.perform(ViewActions.click())
|
||||
}
|
||||
|
||||
assertThat(
|
||||
fragmentNavigationScenario.navigationController.currentDestination?.id,
|
||||
equalTo(cash.z.ecc.android.R.id.nav_shield_final)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
fun clicking_more_info_launches_browser() {
|
||||
val fragmentNavigationScenario = newScenario(isAutoshieldAvailable = false)
|
||||
|
||||
onView(withId(cash.z.ecc.android.R.id.button_autoshield_more_info)).also {
|
||||
it.perform(ViewActions.click())
|
||||
}
|
||||
|
||||
assertThat(
|
||||
fragmentNavigationScenario.navigationController.currentDestination?.id,
|
||||
equalTo(cash.z.ecc.android.R.id.nav_autoshielding_info_details)
|
||||
)
|
||||
|
||||
// Note: it is difficult to verify that the browser is launched, because of how the
|
||||
// navigation component works.
|
||||
}
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
fun starting_fragment_does_not_launch_activities() {
|
||||
Intents.init()
|
||||
try {
|
||||
val fragmentNavigationScenario = newScenario(isAutoshieldAvailable = false)
|
||||
|
||||
// The test framework launches an Activity to host the Fragment under test
|
||||
// Since the class name is not a public API, this could break in the future with newer
|
||||
// versions of the AndroidX Test libraries.
|
||||
intended(
|
||||
hasComponent(
|
||||
ComponentName(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
"androidx.test.core.app.InstrumentationActivityInvoker\$BootstrapActivity"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// Verifying that no other Activities (e.g. the link view) are launched without explicit
|
||||
// user interaction
|
||||
Intents.assertNoUnverifiedIntents()
|
||||
|
||||
assertThat(
|
||||
fragmentNavigationScenario.navigationController.currentDestination?.id,
|
||||
equalTo(cash.z.ecc.android.R.id.nav_autoshielding_info)
|
||||
)
|
||||
} finally {
|
||||
Intents.release()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
fun display_fragment_sets_preference() {
|
||||
newScenario(isAutoshieldAvailable = false)
|
||||
|
||||
assertThat(
|
||||
Preferences.isAcknowledgedAutoshieldingInformationPrompt.get(ApplicationProvider.getApplicationContext<Context>()),
|
||||
equalTo(true)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
fun back_navigates_home() {
|
||||
val fragmentNavigationScenario = newScenario(isAutoshieldAvailable = false)
|
||||
|
||||
fragmentNavigationScenario.fragmentScenario.onFragment {
|
||||
// Probably closest we can come to simulating back with the navigation test framework
|
||||
fragmentNavigationScenario.navigationController.navigateUp()
|
||||
}
|
||||
|
||||
assertThat(
|
||||
fragmentNavigationScenario.navigationController.currentDestination?.id,
|
||||
equalTo(cash.z.ecc.android.R.id.nav_home)
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun newScenario(isAutoshieldAvailable: Boolean): FragmentNavigationScenario<AutoshieldingInformationFragment> {
|
||||
// Clear preferences for each scenario, as this most closely reflects how this fragment
|
||||
// is used in the app, as it is displayed usually on first launch
|
||||
SharedPreferenceFactory.getSharedPreferences(ApplicationProvider.getApplicationContext())
|
||||
.edit().clear().apply()
|
||||
|
||||
val scenario = FragmentScenario.launchInContainer(
|
||||
AutoshieldingInformationFragment::class.java,
|
||||
HomeFragmentDirections.actionNavHomeToAutoshieldingInfo(isAutoshieldAvailable).arguments,
|
||||
cash.z.ecc.android.R.style.ZcashTheme,
|
||||
null
|
||||
)
|
||||
|
||||
return FragmentNavigationScenario.new(
|
||||
scenario,
|
||||
cash.z.ecc.android.R.id.nav_autoshielding_info
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user