summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Göransson <david.goransson90@gmail.com>2024-02-26 16:58:36 +0100
committerAlbin <albin@mullvad.net>2024-02-27 09:33:31 +0100
commit81ca0ca0ef00e7d6907d2c9a4ce98211f4dd7eff (patch)
treedf3c3c9a259857225554a3ce79c9302c5d769278
parentb04a45035cb42501ac81fd4e9202c2cb4abcb162 (diff)
downloadmullvadvpn-81ca0ca0ef00e7d6907d2c9a4ce98211f4dd7eff.tar.xz
mullvadvpn-81ca0ca0ef00e7d6907d2c9a4ce98211f4dd7eff.zip
Implement sentence naming of tests
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/RedeemVoucherDialogTest.kt11
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/RedeemVoucherDialog.kt26
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VoucherDialogUiState.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/PaymentAvailabilityExtensions.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModel.kt2
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/applist/ApplicationsProviderTest.kt2
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/relaylist/RelayNameComparatorTest.kt44
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ConnectionProxyTest.kt6
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionDeviceDataSourceTest.kt4
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/AccountExpiryNotificationUseCaseTest.kt6
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/NewDeviceUseNotificationCaseTest.kt21
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCaseTest.kt12
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/PlayPaymentUseCaseTest.kt23
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/TunnelStateNotificationUseCaseTest.kt6
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/VersionNotificationUseCaseTest.kt60
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/utils/VoucherRegexHelperParameterizedTest.kt2
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt97
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ChangelogViewModelTest.kt23
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModelTest.kt107
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModelTest.kt10
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/FilterViewModelTest.kt94
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModelTest.kt85
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModelTest.kt151
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/PaymentViewModelTest.kt29
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ReportProblemViewModelTest.kt214
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/SelectLocationViewModelTest.kt58
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/SettingsViewModelTest.kt101
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/SplitTunnelingViewModelTest.kt12
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModelTest.kt27
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelTest.kt115
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt167
-rw-r--r--android/lib/billing/src/androidTest/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingRepositoryTest.kt2
-rw-r--r--android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/extension/ProductDetailsResultToPaymentAvailability.kt2
-rw-r--r--android/lib/billing/src/test/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingPaymentRepositoryTest.kt358
-rw-r--r--android/lib/model/src/test/kotlin/net/mullvad/mullvadvpn/model/LatitudeTest.kt4
-rw-r--r--android/lib/model/src/test/kotlin/net/mullvad/mullvadvpn/model/LongitudeTest.kt6
-rw-r--r--android/lib/payment/src/main/kotlin/net/mullvad/mullvadvpn/lib/payment/model/PaymentAvailability.kt2
37 files changed, 1000 insertions, 893 deletions
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/RedeemVoucherDialogTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/RedeemVoucherDialogTest.kt
index d61fa31a8c..34a8a8908f 100644
--- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/RedeemVoucherDialogTest.kt
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/RedeemVoucherDialogTest.kt
@@ -56,8 +56,7 @@ class RedeemVoucherDialogTest {
val mockedClickHandler: (Boolean) -> Unit = mockk(relaxed = true)
setContentWithTheme {
RedeemVoucherDialog(
- uiState =
- VoucherDialogUiState(voucherViewModelState = VoucherDialogState.Success(0)),
+ uiState = VoucherDialogUiState(voucherState = VoucherDialogState.Success(0)),
onVoucherInputChange = {},
onRedeem = {},
onDismiss = mockedClickHandler
@@ -98,8 +97,7 @@ class RedeemVoucherDialogTest {
// Arrange
setContentWithTheme {
RedeemVoucherDialog(
- uiState =
- VoucherDialogUiState(voucherViewModelState = VoucherDialogState.Verifying),
+ uiState = VoucherDialogUiState(voucherState = VoucherDialogState.Verifying),
onVoucherInputChange = {},
onRedeem = {},
onDismiss = {}
@@ -116,8 +114,7 @@ class RedeemVoucherDialogTest {
// Arrange
setContentWithTheme {
RedeemVoucherDialog(
- uiState =
- VoucherDialogUiState(voucherViewModelState = VoucherDialogState.Success(0)),
+ uiState = VoucherDialogUiState(voucherState = VoucherDialogState.Success(0)),
onVoucherInputChange = {},
onRedeem = {},
onDismiss = {}
@@ -136,7 +133,7 @@ class RedeemVoucherDialogTest {
RedeemVoucherDialog(
uiState =
VoucherDialogUiState(
- voucherViewModelState = VoucherDialogState.Error(ERROR_MESSAGE)
+ voucherState = VoucherDialogState.Error(ERROR_MESSAGE)
),
onVoucherInputChange = {},
onRedeem = {},
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/RedeemVoucherDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/RedeemVoucherDialog.kt
index 339de8f3a9..a9029a3758 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/RedeemVoucherDialog.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/RedeemVoucherDialog.kt
@@ -119,14 +119,14 @@ fun RedeemVoucherDialog(
) {
AlertDialog(
title = {
- if (uiState.voucherViewModelState !is VoucherDialogState.Success)
+ if (uiState.voucherState !is VoucherDialogState.Success)
Text(
text = stringResource(id = R.string.enter_voucher_code),
)
},
confirmButton = {
Column {
- if (uiState.voucherViewModelState !is VoucherDialogState.Success) {
+ if (uiState.voucherState !is VoucherDialogState.Success) {
VariantButton(
text = stringResource(id = R.string.redeem),
onClick = { onRedeem(uiState.voucherInput) },
@@ -138,13 +138,11 @@ fun RedeemVoucherDialog(
text =
stringResource(
id =
- if (uiState.voucherViewModelState is VoucherDialogState.Success)
+ if (uiState.voucherState is VoucherDialogState.Success)
R.string.got_it
else R.string.cancel
),
- onClick = {
- onDismiss(uiState.voucherViewModelState is VoucherDialogState.Success)
- }
+ onClick = { onDismiss(uiState.voucherState is VoucherDialogState.Success) }
)
}
},
@@ -153,11 +151,9 @@ fun RedeemVoucherDialog(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
- if (uiState.voucherViewModelState is VoucherDialogState.Success) {
+ if (uiState.voucherState is VoucherDialogState.Success) {
val days: Int =
- (uiState.voucherViewModelState.addedTime /
- DateTimeConstants.SECONDS_PER_DAY)
- .toInt()
+ (uiState.voucherState.addedTime / DateTimeConstants.SECONDS_PER_DAY).toInt()
val message =
stringResource(
R.string.added_to_your_account,
@@ -190,9 +186,7 @@ fun RedeemVoucherDialog(
},
containerColor = MaterialTheme.colorScheme.background,
titleContentColor = MaterialTheme.colorScheme.onBackground,
- onDismissRequest = {
- onDismiss(uiState.voucherViewModelState is VoucherDialogState.Success)
- },
+ onDismissRequest = { onDismiss(uiState.voucherState is VoucherDialogState.Success) },
properties =
DialogProperties(
securePolicy =
@@ -257,7 +251,7 @@ private fun EnterVoucherBody(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.height(Dimens.listIconSize).fillMaxWidth()
) {
- if (uiState.voucherViewModelState is VoucherDialogState.Verifying) {
+ if (uiState.voucherState is VoucherDialogState.Verifying) {
MullvadCircularProgressIndicatorSmall()
Text(
text = stringResource(id = R.string.verifying_voucher),
@@ -265,9 +259,9 @@ private fun EnterVoucherBody(
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.bodySmall
)
- } else if (uiState.voucherViewModelState is VoucherDialogState.Error) {
+ } else if (uiState.voucherState is VoucherDialogState.Error) {
Text(
- text = uiState.voucherViewModelState.errorMessage,
+ text = uiState.voucherState.errorMessage,
color = MaterialTheme.colorScheme.error,
style = MaterialTheme.typography.bodySmall
)
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VoucherDialogUiState.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VoucherDialogUiState.kt
index e719bda529..c143dda0e8 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VoucherDialogUiState.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VoucherDialogUiState.kt
@@ -2,7 +2,7 @@ package net.mullvad.mullvadvpn.compose.state
data class VoucherDialogUiState(
val voucherInput: String = "",
- val voucherViewModelState: VoucherDialogState = VoucherDialogState.Default
+ val voucherState: VoucherDialogState = VoucherDialogState.Default
) {
companion object {
val INITIAL = VoucherDialogUiState()
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/PaymentAvailabilityExtensions.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/PaymentAvailabilityExtensions.kt
index 6a69a807f1..aa75c2403a 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/PaymentAvailabilityExtensions.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/PaymentAvailabilityExtensions.kt
@@ -10,7 +10,7 @@ fun PaymentAvailability.toPaymentState(): PaymentState =
is PaymentAvailability.Error.Other -> PaymentState.Error.Generic
is PaymentAvailability.ProductsAvailable -> PaymentState.PaymentAvailable(products)
PaymentAvailability.ProductsUnavailable -> PaymentState.NoPayment
- PaymentAvailability.NoProductsFounds -> PaymentState.NoProductsFounds
+ PaymentAvailability.NoProductsFound -> PaymentState.NoProductsFounds
PaymentAvailability.Loading -> PaymentState.Loading
// Unrecoverable error states
PaymentAvailability.Error.DeveloperError,
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModel.kt
index b26429f18b..8022332650 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModel.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModel.kt
@@ -49,7 +49,7 @@ class VoucherDialogViewModel(
_shared
.flatMapLatest {
combine(vmState, voucherInput) { state, input ->
- VoucherDialogUiState(voucherInput = input, voucherViewModelState = state)
+ VoucherDialogUiState(voucherInput = input, voucherState = state)
}
}
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), VoucherDialogUiState.INITIAL)
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/applist/ApplicationsProviderTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/applist/ApplicationsProviderTest.kt
index 1b37184915..62ceaa7ebe 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/applist/ApplicationsProviderTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/applist/ApplicationsProviderTest.kt
@@ -23,7 +23,7 @@ class ApplicationsProviderTest {
}
@Test
- fun test_get_apps() {
+ fun `fetch all apps should work`() {
val launchWithInternetPackageName = "launch_with_internet_package_name"
val launchWithoutInternetPackageName = "launch_without_internet_package_name"
val nonLaunchWithInternetPackageName = "non_launch_with_internet_package_name"
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/relaylist/RelayNameComparatorTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/relaylist/RelayNameComparatorTest.kt
index 6fe71ae443..1532328729 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/relaylist/RelayNameComparatorTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/relaylist/RelayNameComparatorTest.kt
@@ -14,40 +14,40 @@ class RelayNameComparatorTest {
}
@Test
- fun test_compare_respect_numbers_in_name() {
+ fun `given two relays with same prefix but different numbers comparator should return lowest number first`() {
val relay9 =
RelayItem.Relay(
name = "se9-wireguard",
location = mockk(),
locationName = "mock",
- active = false
+ active = false,
)
val relay10 =
RelayItem.Relay(
name = "se10-wireguard",
location = mockk(),
locationName = "mock",
- active = false
+ active = false,
)
relay9 assertOrderBothDirection relay10
}
@Test
- fun test_compare_same_name() {
+ fun `given two relays with same name with number in name comparator should return 0`() {
val relay9a =
RelayItem.Relay(
name = "se9-wireguard",
location = mockk(),
locationName = "mock",
- active = false
+ active = false,
)
val relay9b =
RelayItem.Relay(
name = "se9-wireguard",
location = mockk(),
locationName = "mock",
- active = false
+ active = false,
)
assertTrue(RelayNameComparator.compare(relay9a, relay9b) == 0)
@@ -55,7 +55,7 @@ class RelayNameComparatorTest {
}
@Test
- fun test_compare_only_numbers_in_name() {
+ fun `comparator should be able to handle name of only numbers`() {
val relay001 =
RelayItem.Relay(name = "001", location = mockk(), locationName = "mock", active = false)
val relay1 =
@@ -72,20 +72,20 @@ class RelayNameComparatorTest {
}
@Test
- fun test_compare_without_numbers_in_name() {
+ fun `given two relays with same name and without number comparator should return 0`() {
val relay9a =
RelayItem.Relay(
name = "se-wireguard",
location = mockk(),
locationName = "mock",
- active = false
+ active = false,
)
val relay9b =
RelayItem.Relay(
name = "se-wireguard",
location = mockk(),
locationName = "mock",
- active = false
+ active = false,
)
assertTrue(RelayNameComparator.compare(relay9a, relay9b) == 0)
@@ -93,54 +93,54 @@ class RelayNameComparatorTest {
}
@Test
- fun test_compare_with_trailing_zeros_in_name() {
+ fun `given two relays with leading zeroes comparator should return lowest number first`() {
val relay001 =
RelayItem.Relay(
name = "se001-wireguard",
location = mockk(),
locationName = "mock",
- active = false
+ active = false,
)
val relay005 =
RelayItem.Relay(
name = "se005-wireguard",
location = mockk(),
locationName = "mock",
- active = false
+ active = false,
)
relay001 assertOrderBothDirection relay005
}
@Test
- fun test_compare_prefix_and_numbers() {
+ fun `given 4 relays comparator should sort by prefix then number`() {
val relayAr2 =
RelayItem.Relay(
name = "ar2-wireguard",
location = mockk(),
locationName = "mock",
- active = false
+ active = false,
)
val relayAr8 =
RelayItem.Relay(
name = "ar8-wireguard",
location = mockk(),
locationName = "mock",
- active = false
+ active = false,
)
val relaySe5 =
RelayItem.Relay(
name = "se5-wireguard",
location = mockk(),
locationName = "mock",
- active = false
+ active = false,
)
val relaySe10 =
RelayItem.Relay(
name = "se10-wireguard",
location = mockk(),
locationName = "mock",
- active = false
+ active = false,
)
relayAr2 assertOrderBothDirection relayAr8
@@ -149,7 +149,7 @@ class RelayNameComparatorTest {
}
@Test
- fun test_compare_suffix_and_numbers() {
+ fun `given two relays with same prefix and number comparator should sort by suffix`() {
val relay2c =
RelayItem.Relay(
name = "se2-cloud",
@@ -162,14 +162,14 @@ class RelayNameComparatorTest {
name = "se2-wireguard",
location = mockk(),
locationName = "mock",
- active = false
+ active = false,
)
relay2c assertOrderBothDirection relay2w
}
@Test
- fun test_compare_different_length() {
+ fun `given two relays with same prefix, but one with no suffix, the one with no suffix should come first`() {
val relay22a =
RelayItem.Relay(
name = "se22",
@@ -182,7 +182,7 @@ class RelayNameComparatorTest {
name = "se22-wireguard",
location = mockk(),
locationName = "mock",
- active = false
+ active = false,
)
relay22a assertOrderBothDirection relay22b
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ConnectionProxyTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ConnectionProxyTest.kt
index 4da6c4fdaf..8fd21c5533 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ConnectionProxyTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ConnectionProxyTest.kt
@@ -50,7 +50,7 @@ class ConnectionProxyTest {
}
@Test
- fun test_initialize_connection_proxy() {
+ fun `initialize connection proxy should work`() {
// Arrange
val eventType = slot<KClass<Event.TunnelStateChange>>()
every { mockedDispatchingHandler.registerHandler(capture(eventType), any()) } just Runs
@@ -60,7 +60,7 @@ class ConnectionProxyTest {
}
@Test
- fun test_tunnel_normal_connect_disconnect() {
+ fun `normal connect and disconnect should not crash`() {
// Arrange
every { connection.send(any()) } just Runs
every { mockedDispatchingHandler.registerHandler(any<KClass<Event>>(), any()) } just Runs
@@ -71,7 +71,7 @@ class ConnectionProxyTest {
}
@Test
- fun test_tunnel_handle_crash_on_connect() {
+ fun `connect should catch DeadObjectException`() {
// Arrange
every { connection.send(any()) } throws DeadObjectException()
every { mockedDispatchingHandler.registerHandler(any<KClass<Event>>(), any()) } just Runs
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionDeviceDataSourceTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionDeviceDataSourceTest.kt
index 8f17f37bbd..81b518199c 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionDeviceDataSourceTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionDeviceDataSourceTest.kt
@@ -47,7 +47,7 @@ class ServiceConnectionDeviceDataSourceTest {
}
@Test
- fun test_get_devices_list() {
+ fun `get device should work`() {
// Arrange
every { connection.send(any()) } just Runs
every { mockedDispatchingHandler.registerHandler(any<KClass<Event>>(), any()) } just Runs
@@ -58,7 +58,7 @@ class ServiceConnectionDeviceDataSourceTest {
}
@Test
- fun test_catch_exception_on_devices_list() {
+ fun `get device should catch DeadObjectException`() {
// Arrange
every { connection.send(any()) } throws DeadObjectException()
every { mockedDispatchingHandler.registerHandler(any<KClass<Event>>(), any()) } just Runs
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/AccountExpiryNotificationUseCaseTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/AccountExpiryNotificationUseCaseTest.kt
index f068642bec..39bfae63d8 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/AccountExpiryNotificationUseCaseTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/AccountExpiryNotificationUseCaseTest.kt
@@ -41,7 +41,7 @@ class AccountExpiryNotificationUseCaseTest {
}
@Test
- fun `ensure notifications are empty by default`() = runTest {
+ fun `initial state should be empty`() = runTest {
// Arrange, Act, Assert
accountExpiryNotificationUseCase.notifications().test {
assertTrue { awaitItem().isEmpty() }
@@ -49,7 +49,7 @@ class AccountExpiryNotificationUseCaseTest {
}
@Test
- fun `ensure account expiry within 3 days generates notification`() = runTest {
+ fun `account that expires within 3 days should emit a notification`() = runTest {
// Arrange, Act, Assert
accountExpiryNotificationUseCase.notifications().test {
assertTrue { awaitItem().isEmpty() }
@@ -64,7 +64,7 @@ class AccountExpiryNotificationUseCaseTest {
}
@Test
- fun `ensure an expire of 4 days in the future does not produce a notification`() = runTest {
+ fun `account that expires in 4 days should not emit a notification`() = runTest {
// Arrange, Act, Assert
accountExpiryNotificationUseCase.notifications().test {
assertTrue { awaitItem().isEmpty() }
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/NewDeviceUseNotificationCaseTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/NewDeviceUseNotificationCaseTest.kt
index 5e4403c38d..691bb99131 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/NewDeviceUseNotificationCaseTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/NewDeviceUseNotificationCaseTest.kt
@@ -48,25 +48,26 @@ class NewDeviceUseNotificationCaseTest {
}
@Test
- fun `ensure empty by default`() = runTest {
+ fun `initial state should be empty`() = runTest {
// Arrange, Act, Assert
newDeviceNotificationUseCase.notifications().test { assertTrue { awaitItem().isEmpty() } }
}
@Test
- fun `ensure NewDevice notification is created and contains device name`() = runTest {
- newDeviceNotificationUseCase.notifications().test {
- // Arrange, Act
- awaitItem()
- newDeviceNotificationUseCase.newDeviceCreated()
+ fun `when newDeviceCreated is called notifications should emit NewDevice notification containing device name`() =
+ runTest {
+ newDeviceNotificationUseCase.notifications().test {
+ // Arrange, Act
+ awaitItem()
+ newDeviceNotificationUseCase.newDeviceCreated()
- // Assert
- assertEquals(awaitItem(), listOf(InAppNotification.NewDevice(deviceName)))
+ // Assert
+ assertEquals(awaitItem(), listOf(InAppNotification.NewDevice(deviceName)))
+ }
}
- }
@Test
- fun `ensure NewDevice notification is cleared`() = runTest {
+ fun `clearNewDeviceCreatedNotification should clear notifications`() = runTest {
newDeviceNotificationUseCase.notifications().test {
// Arrange, Act
awaitItem()
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCaseTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCaseTest.kt
index 6563f7e6e9..d40e8d8e18 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCaseTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCaseTest.kt
@@ -36,14 +36,14 @@ class OutOfTimeUseCaseTest {
}
@Test
- fun `No events should result in no expiry`() = runTest {
+ fun `no events should result in no expiry`() = runTest {
// Arrange
// Act, Assert
outOfTimeUseCase.isOutOfTime().test { assertEquals(null, awaitItem()) }
}
@Test
- fun `Tunnel is blocking because out of time should emit true`() = runTest {
+ fun `tunnel is blocking because out of time should emit true`() = runTest {
// Arrange
// Act, Assert
val errorStateCause = ErrorStateCause.AuthFailed("[EXPIRED_ACCOUNT]")
@@ -58,7 +58,7 @@ class OutOfTimeUseCaseTest {
}
@Test
- fun `Tunnel is connected should emit false`() = runTest {
+ fun `tunnel is connected should emit false`() = runTest {
// Arrange
val expiredAccountExpiry = AccountExpiry.Available(DateTime.now().plusDays(1))
val tunnelStateChanges =
@@ -86,7 +86,7 @@ class OutOfTimeUseCaseTest {
}
@Test
- fun `Account expiry that has expired should emit true`() = runTest {
+ fun `account expiry that has expired should emit true`() = runTest {
// Arrange
val expiredAccountExpiry = AccountExpiry.Available(DateTime.now().minusDays(1))
// Act, Assert
@@ -98,7 +98,7 @@ class OutOfTimeUseCaseTest {
}
@Test
- fun `Account expiry that has not expired should emit false`() = runTest {
+ fun `account expiry that has not expired should emit false`() = runTest {
// Arrange
val expiredAccountExpiry = AccountExpiry.Available(DateTime.now().plusDays(1))
@@ -111,7 +111,7 @@ class OutOfTimeUseCaseTest {
}
@Test
- fun `Account that expires without new expiry event`() = runTest {
+ fun `account that expires without new expiry event should emit true`() = runTest {
// Arrange
val expiredAccountExpiry = AccountExpiry.Available(DateTime.now().plusSeconds(62))
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/PlayPaymentUseCaseTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/PlayPaymentUseCaseTest.kt
index fb85629a9c..a07fefabe3 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/PlayPaymentUseCaseTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/PlayPaymentUseCaseTest.kt
@@ -21,7 +21,7 @@ class PlayPaymentUseCaseTest {
private val playPaymentUseCase = PlayPaymentUseCase(mockPaymentRepository)
@Test
- fun testUpdatePaymentAvailability() = runTest {
+ fun `queryPaymentAvailability call should result in updated paymentAvailability`() = runTest {
// Arrange
val productsUnavailable = PaymentAvailability.ProductsUnavailable
val paymentRepositoryQueryPaymentAvailabilityFlow = flow { emit(productsUnavailable) }
@@ -37,7 +37,7 @@ class PlayPaymentUseCaseTest {
}
@Test
- fun testUpdatePurchaseResult() = runTest {
+ fun `purchaseProduct call should result in updated purchaseResult`() = runTest {
// Arrange
val fetchingProducts = PurchaseResult.FetchingProducts
val productId = ProductId("productId")
@@ -54,7 +54,7 @@ class PlayPaymentUseCaseTest {
}
@Test
- fun testPurchaseProduct() = runTest {
+ fun `purchaseProduct call should invoke purchaseProduct on repository`() = runTest {
// Arrange
val productId = ProductId("productId")
@@ -66,16 +66,17 @@ class PlayPaymentUseCaseTest {
}
@Test
- fun testQueryPaymentAvailability() = runTest {
- // Act
- playPaymentUseCase.queryPaymentAvailability()
+ fun `queryPaymentAvailability should invoke queryPaymentAvailability on repository`() =
+ runTest {
+ // Act
+ playPaymentUseCase.queryPaymentAvailability()
- // Assert
- coVerify { mockPaymentRepository.queryPaymentAvailability() }
- }
+ // Assert
+ coVerify { mockPaymentRepository.queryPaymentAvailability() }
+ }
@Test
- fun testResetPurchaseResult() = runTest {
+ fun `resetPurchaseResult call should result in purchaseResult null`() = runTest {
// Arrange
val completedSuccess = PurchaseResult.Completed.Success
val productId = ProductId("productId")
@@ -94,7 +95,7 @@ class PlayPaymentUseCaseTest {
}
@Test
- fun testVerifyPurchases() = runTest {
+ fun `verifyPurchases call should invoke verifyPurchases on repository`() = runTest {
// Act
playPaymentUseCase.verifyPurchases()
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/TunnelStateNotificationUseCaseTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/TunnelStateNotificationUseCaseTest.kt
index 244c735ee9..82126099d8 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/TunnelStateNotificationUseCaseTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/TunnelStateNotificationUseCaseTest.kt
@@ -55,13 +55,13 @@ class TunnelStateNotificationUseCaseTest {
}
@Test
- fun `ensure notifications are empty by default`() = runTest {
+ fun `initial state should be empty`() = runTest {
// Arrange, Act, Assert
tunnelStateNotificationUseCase.notifications().test { assertTrue { awaitItem().isEmpty() } }
}
@Test
- fun `ensure TunnelState with error will produce TunnelStateError notification`() = runTest {
+ fun `when TunnelState is error use case should emit TunnelStateError notification`() = runTest {
tunnelStateNotificationUseCase.notifications().test {
// Arrange, Act
assertEquals(emptyList(), awaitItem())
@@ -76,7 +76,7 @@ class TunnelStateNotificationUseCaseTest {
}
@Test
- fun `ensure disconnecting TunnelState with blocking will produce TunnelStateBlocked notification`() =
+ fun `when TunnelState is Disconnecting with blocking use case should emit TunnelStateBlocked notification`() =
runTest {
tunnelStateNotificationUseCase.notifications().test {
// Arrange, Act
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/VersionNotificationUseCaseTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/VersionNotificationUseCaseTest.kt
index 12f7207280..fbc677b461 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/VersionNotificationUseCaseTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/VersionNotificationUseCaseTest.kt
@@ -69,44 +69,50 @@ class VersionNotificationUseCaseTest {
}
@Test
- fun `ensure notifications are empty by default`() = runTest {
+ fun `initial state should be empty`() = runTest {
// Arrange, Act, Assert
versionNotificationUseCase.notifications().test { assertTrue { awaitItem().isEmpty() } }
}
@Test
- fun `ensure UpdateAvailable notification is created`() = runTest {
- versionNotificationUseCase.notifications().test {
- // Arrange, Act
- val upgradeVersionInfo =
- VersionInfo("1.0", "1.1", isOutdated = true, isSupported = true)
- serviceConnectionState.value =
- ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
- awaitItem()
- versionInfo.value = upgradeVersionInfo
+ fun `when a new version is available use case should emit UpdateAvailable with new version`() =
+ runTest {
+ versionNotificationUseCase.notifications().test {
+ // Arrange, Act
+ val upgradeVersionInfo =
+ VersionInfo("1.0", "1.1", isOutdated = true, isSupported = true)
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ awaitItem()
+ versionInfo.value = upgradeVersionInfo
- // Assert
- assertEquals(awaitItem(), listOf(InAppNotification.UpdateAvailable(upgradeVersionInfo)))
+ // Assert
+ assertEquals(
+ awaitItem(),
+ listOf(InAppNotification.UpdateAvailable(upgradeVersionInfo))
+ )
+ }
}
- }
@Test
- fun `ensure UnsupportedVersion notification is created`() = runTest {
- versionNotificationUseCase.notifications().test {
- // Arrange, Act
- val upgradeVersionInfo = VersionInfo("1.0", "", isOutdated = false, isSupported = false)
- serviceConnectionState.value =
- ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
- awaitItem()
- versionInfo.value = upgradeVersionInfo
+ fun `when an unsupported version use case should emit UnsupportedVersion notification`() =
+ runTest {
+ versionNotificationUseCase.notifications().test {
+ // Arrange, Act
+ val upgradeVersionInfo =
+ VersionInfo("1.0", "", isOutdated = false, isSupported = false)
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ awaitItem()
+ versionInfo.value = upgradeVersionInfo
- // Assert
- assertEquals(
- awaitItem(),
- listOf(InAppNotification.UnsupportedVersion(upgradeVersionInfo))
- )
+ // Assert
+ assertEquals(
+ awaitItem(),
+ listOf(InAppNotification.UnsupportedVersion(upgradeVersionInfo))
+ )
+ }
}
- }
companion object {
private const val CACHE_EXTENSION_CLASS = "net.mullvad.mullvadvpn.util.CacheExtensionsKt"
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/utils/VoucherRegexHelperParameterizedTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/utils/VoucherRegexHelperParameterizedTest.kt
index 1722e81a9d..abe325ba43 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/utils/VoucherRegexHelperParameterizedTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/utils/VoucherRegexHelperParameterizedTest.kt
@@ -14,7 +14,7 @@ private const val IS_UNACCEPTED_FORMAT = false
@ExtendWith(TestCoroutineRule::class)
class VoucherRegexHelperParameterizedTest {
- @ParameterizedTest
+ @ParameterizedTest(name = "Voucher format {1} should be valid: {0}")
@MethodSource("data")
fun testVoucherFormat(isValid: Boolean, voucher: String) {
assertEquals(VoucherRegexHelper.validate(voucher), isValid)
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt
index 637c531039..61758c2d1d 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt
@@ -63,7 +63,7 @@ class AccountViewModelTest {
private lateinit var viewModel: AccountViewModel
@BeforeEach
- fun setUp() {
+ fun setup() {
mockkStatic(CACHE_EXTENSION_CLASS)
mockkStatic(PURCHASE_RESULT_EXTENSIONS_CLASS)
every { mockServiceConnectionManager.authTokenCache() } returns mockAuthTokenCache
@@ -88,7 +88,7 @@ class AccountViewModelTest {
}
@Test
- fun testAccountLoggedInState() = runTest {
+ fun `given device state LoggedIn uiState should contain accountNumber`() = runTest {
// Act, Assert
viewModel.uiState.test {
awaitItem() // Default state
@@ -99,7 +99,7 @@ class AccountViewModelTest {
}
@Test
- fun testOnLogoutClick() {
+ fun `onLogoutClick should invoke logout on AccountRepository`() {
// Act
viewModel.onLogoutClick()
@@ -108,20 +108,21 @@ class AccountViewModelTest {
}
@Test
- fun testBillingProductsUnavailableState() = runTest {
- // Arrange in setup
+ fun `when paymentAvailability emits ProductsUnavailable uiState should be NoPayment`() =
+ runTest {
+ // Arrange in setup
- // Act, Assert
- viewModel.uiState.test {
- awaitItem() // Default state
- paymentAvailability.tryEmit(PaymentAvailability.ProductsUnavailable)
- val result = awaitItem().billingPaymentState
- assertIs<PaymentState.NoPayment>(result)
+ // Act, Assert
+ viewModel.uiState.test {
+ awaitItem() // Default state
+ paymentAvailability.tryEmit(PaymentAvailability.ProductsUnavailable)
+ val result = awaitItem().billingPaymentState
+ assertIs<PaymentState.NoPayment>(result)
+ }
}
- }
@Test
- fun testBillingProductsGenericErrorState() = runTest {
+ fun `when paymentAvailability emits ErrorOther uiState should be ErrorGeneric`() = runTest {
// Act, Assert
viewModel.uiState.test {
awaitItem() // Default state
@@ -132,34 +133,38 @@ class AccountViewModelTest {
}
@Test
- fun testBillingProductsBillingErrorState() = runTest {
- // Act, Assert
- viewModel.uiState.test {
- awaitItem() // Default state
- paymentAvailability.tryEmit(PaymentAvailability.Error.BillingUnavailable)
- val result = awaitItem().billingPaymentState
- assertIs<PaymentState.Error.Billing>(result)
+ fun `when paymentAvailability emits ErrorBillingUnavailable uiState should be ErrorBilling`() =
+ runTest {
+ // Act, Assert
+ viewModel.uiState.test {
+ awaitItem() // Default state
+ paymentAvailability.tryEmit(PaymentAvailability.Error.BillingUnavailable)
+ val result = awaitItem().billingPaymentState
+ assertIs<PaymentState.Error.Billing>(result)
+ }
}
- }
@Test
- fun testBillingProductsPaymentAvailableState() = runTest {
- // Arrange
- val mockProduct: PaymentProduct = mockk()
- val expectedProductList = listOf(mockProduct)
+ fun `when paymentAvailability emits ProductsAvailable uiState should be Available with products`() =
+ runTest {
+ // Arrange
+ val mockProduct: PaymentProduct = mockk()
+ val expectedProductList = listOf(mockProduct)
- // Act, Assert
- viewModel.uiState.test {
- awaitItem() // Default state
- paymentAvailability.tryEmit(PaymentAvailability.ProductsAvailable(listOf(mockProduct)))
- val result = awaitItem().billingPaymentState
- assertIs<PaymentState.PaymentAvailable>(result)
- assertLists(expectedProductList, result.products)
+ // Act, Assert
+ viewModel.uiState.test {
+ awaitItem() // Default state
+ paymentAvailability.tryEmit(
+ PaymentAvailability.ProductsAvailable(listOf(mockProduct))
+ )
+ val result = awaitItem().billingPaymentState
+ assertIs<PaymentState.PaymentAvailable>(result)
+ assertLists(expectedProductList, result.products)
+ }
}
- }
@Test
- fun testStartBillingPayment() {
+ fun `startBillingPayment should invoke purchaseProduct on PaymentUseCase`() {
// Arrange
val mockProductId = ProductId("MOCK")
val mockActivityProvider = mockk<() -> Activity>()
@@ -172,7 +177,7 @@ class AccountViewModelTest {
}
@Test
- fun testOnClosePurchaseResultDialogSuccessful() {
+ fun `onClosePurchaseResultDialog with success should invoke fetchAccountExpiry on AccountRepository`() {
// Arrange
// Act
@@ -180,11 +185,21 @@ class AccountViewModelTest {
// Assert
verify { mockAccountRepository.fetchAccountExpiry() }
+ }
+
+ @Test
+ fun `onClosePurchaseResultDialog with success should invoke resetPurchaseResult on PaymentUseCase`() {
+ // Arrange
+
+ // Act
+ viewModel.onClosePurchaseResultDialog(success = true)
+
+ // Assert
coVerify { mockPaymentUseCase.resetPurchaseResult() }
}
@Test
- fun testOnClosePurchaseResultDialogNotSuccessful() {
+ fun `onClosePurchaseResultDialog with success false should invoke queryPaymentAvailability on PaymentUseCase`() {
// Arrange
// Act
@@ -192,6 +207,16 @@ class AccountViewModelTest {
// Assert
coVerify { mockPaymentUseCase.queryPaymentAvailability() }
+ }
+
+ @Test
+ fun `onClosePurchaseResultDialog with success false should invoke resetPurchaseResult on PaymentUseCase`() {
+ // Arrange
+
+ // Act
+ viewModel.onClosePurchaseResultDialog(success = false)
+
+ // Assert
coVerify { mockPaymentUseCase.resetPurchaseResult() }
}
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ChangelogViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ChangelogViewModelTest.kt
index d9a5ae534e..46126f5ad8 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ChangelogViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ChangelogViewModelTest.kt
@@ -8,8 +8,9 @@ import io.mockk.impl.annotations.MockK
import io.mockk.just
import io.mockk.mockkStatic
import io.mockk.unmockkAll
-import kotlin.test.assertNotNull
+import kotlin.test.assertEquals
import kotlinx.coroutines.test.runTest
+import net.mullvad.mullvadvpn.BuildConfig
import net.mullvad.mullvadvpn.lib.common.test.TestCoroutineRule
import net.mullvad.mullvadvpn.repository.ChangelogRepository
import org.junit.jupiter.api.AfterEach
@@ -38,7 +39,7 @@ class ChangelogViewModelTest {
}
@Test
- fun testUpToDateVersionCodeShouldNotEmitChangelog() = runTest {
+ fun `given up to date version code uiSideEffect should not emit`() = runTest {
// Arrange
every { mockedChangelogRepository.getVersionCodeOfMostRecentChangelogShowed() } returns
buildVersionCode
@@ -49,18 +50,26 @@ class ChangelogViewModelTest {
}
@Test
- fun testNotUpToDateVersionCodeShouldEmitChangelog() = runTest {
+ fun `given old version code uiSideEffect should emit ChangeLog`() = runTest {
// Arrange
- every { mockedChangelogRepository.getVersionCodeOfMostRecentChangelogShowed() } returns -1
- every { mockedChangelogRepository.getLastVersionChanges() } returns listOf("bla", "bla")
+ val version = -1
+ val changes = listOf("first change", "second change")
+ every { mockedChangelogRepository.getVersionCodeOfMostRecentChangelogShowed() } returns
+ version
+ every { mockedChangelogRepository.getLastVersionChanges() } returns changes
viewModel = ChangelogViewModel(mockedChangelogRepository, buildVersionCode, false)
// Given a new version with a change log we should return it
- viewModel.uiSideEffect.test { assertNotNull(awaitItem()) }
+ viewModel.uiSideEffect.test {
+ assertEquals(
+ awaitItem(),
+ Changelog(version = BuildConfig.VERSION_NAME, changes = changes)
+ )
+ }
}
@Test
- fun testEmptyChangelogShouldNotEmitChangelog() = runTest {
+ fun `given old version code and empty change log uiSideEffect should not emit`() = runTest {
// Arrange
every { mockedChangelogRepository.getVersionCodeOfMostRecentChangelogShowed() } returns -1
every { mockedChangelogRepository.getLastVersionChanges() } returns emptyList()
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModelTest.kt
index 05dae1d53d..545422b6f2 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModelTest.kt
@@ -154,12 +154,12 @@ class ConnectViewModelTest {
}
@Test
- fun testInitialState() = runTest {
+ fun `uiState should emit initial state by default`() = runTest {
viewModel.uiState.test { assertEquals(ConnectUiState.INITIAL, awaitItem()) }
}
@Test
- fun testTunnelRealStateUpdate() = runTest {
+ fun `given change in tunnelRealState uiState should emit new tunnelRealState`() = runTest {
val tunnelRealStateTestItem = TunnelState.Connected(mockk(relaxed = true), null)
viewModel.uiState.test {
@@ -173,7 +173,7 @@ class ConnectViewModelTest {
}
@Test
- fun testTunnelUiStateUpdate() = runTest {
+ fun `given change in tunnelUiState uiState should emit new tunnelUiState`() = runTest {
val tunnelUiStateTestItem = TunnelState.Connected(mockk(), mockk())
viewModel.uiState.test {
@@ -187,22 +187,28 @@ class ConnectViewModelTest {
}
@Test
- fun testSelectedLocationUpdate() = runTest {
- val selectedRelayItem =
- RelayItem.Country(name = "Name", code = "Code", expanded = false, cities = emptyList())
- selectedRelayItemFlow.value = selectedRelayItem
+ fun `given RelayListUseCase returns new selectedRelayItem uiState should emit new selectedRelayItem`() =
+ runTest {
+ val selectedRelayItem =
+ RelayItem.Country(
+ name = "Name",
+ code = "Code",
+ expanded = false,
+ cities = emptyList()
+ )
+ selectedRelayItemFlow.value = selectedRelayItem
- viewModel.uiState.test {
- assertEquals(ConnectUiState.INITIAL, awaitItem())
- serviceConnectionState.value =
- ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
- val result = awaitItem()
- assertEquals(selectedRelayItem, result.selectedRelayItem)
+ viewModel.uiState.test {
+ assertEquals(ConnectUiState.INITIAL, awaitItem())
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ val result = awaitItem()
+ assertEquals(selectedRelayItem, result.selectedRelayItem)
+ }
}
- }
@Test
- fun testLocationUpdate() = runTest {
+ fun `given new location in tunnel state uiState should emit new location`() = runTest {
val locationTestItem =
GeoIpLocation(
ipv4 = mockk(relaxed = true),
@@ -231,7 +237,7 @@ class ConnectViewModelTest {
}
@Test
- fun testLocationUpdateNullLocation() =
+ fun `initial state should not include any location`() =
// Arrange
runTest {
val locationTestItem = null
@@ -248,7 +254,7 @@ class ConnectViewModelTest {
}
@Test
- fun testOnDisconnectClick() = runTest {
+ fun `onDisconnectClick should invoke disconnect on ConnectionProxy`() = runTest {
val mockConnectionProxy: ConnectionProxy = mockk(relaxed = true)
every { mockServiceConnectionManager.connectionProxy() } returns mockConnectionProxy
viewModel.onDisconnectClick()
@@ -256,7 +262,7 @@ class ConnectViewModelTest {
}
@Test
- fun testOnReconnectClick() = runTest {
+ fun `onReconnectClick should invoke reconnect on ConnectionProxy`() = runTest {
val mockConnectionProxy: ConnectionProxy = mockk(relaxed = true)
every { mockServiceConnectionManager.connectionProxy() } returns mockConnectionProxy
viewModel.onReconnectClick()
@@ -264,7 +270,7 @@ class ConnectViewModelTest {
}
@Test
- fun testOnConnectClick() = runTest {
+ fun `onConnectClick should invoke connect on ConnectionProxy`() = runTest {
val mockConnectionProxy: ConnectionProxy = mockk(relaxed = true)
every { mockServiceConnectionManager.connectionProxy() } returns mockConnectionProxy
viewModel.onConnectClick()
@@ -272,7 +278,7 @@ class ConnectViewModelTest {
}
@Test
- fun testOnCancelClick() = runTest {
+ fun `onCancelClick should invoke disconnect on ConnectionProxy`() = runTest {
val mockConnectionProxy: ConnectionProxy = mockk(relaxed = true)
every { mockServiceConnectionManager.connectionProxy() } returns mockConnectionProxy
viewModel.onCancelClick()
@@ -280,43 +286,46 @@ class ConnectViewModelTest {
}
@Test
- fun testErrorNotificationState() = runTest {
- // Arrange
- val mockErrorState: ErrorState = mockk()
- val expectedConnectNotificationState = InAppNotification.TunnelStateError(mockErrorState)
- val tunnelUiState = TunnelState.Error(mockErrorState)
- notifications.value = listOf(expectedConnectNotificationState)
+ fun `given InAppNotificationController returns TunnelStateError notification uiState should emit notification`() =
+ runTest {
+ // Arrange
+ val mockErrorState: ErrorState = mockk()
+ val expectedConnectNotificationState =
+ InAppNotification.TunnelStateError(mockErrorState)
+ val tunnelUiState = TunnelState.Error(mockErrorState)
+ notifications.value = listOf(expectedConnectNotificationState)
- // Act, Assert
- viewModel.uiState.test {
- assertEquals(ConnectUiState.INITIAL, awaitItem())
- serviceConnectionState.value =
- ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
- eventNotifierTunnelUiState.notify(tunnelUiState)
- val result = awaitItem()
- assertEquals(expectedConnectNotificationState, result.inAppNotification)
+ // Act, Assert
+ viewModel.uiState.test {
+ assertEquals(ConnectUiState.INITIAL, awaitItem())
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ eventNotifierTunnelUiState.notify(tunnelUiState)
+ val result = awaitItem()
+ assertEquals(expectedConnectNotificationState, result.inAppNotification)
+ }
}
- }
@Test
- fun testOnShowAccountClick() = runTest {
- // Arrange
- val mockToken = "4444 5555 6666 7777"
- val mockAuthTokenCache: AuthTokenCache = mockk(relaxed = true)
- every { mockServiceConnectionManager.authTokenCache() } returns mockAuthTokenCache
- coEvery { mockAuthTokenCache.fetchAuthToken() } returns mockToken
+ fun `onShowAccountClick call should result in uiSideEffect emitting OpenAccountManagementPageInBrowser`() =
+ runTest {
+ // Arrange
+ val mockToken = "4444 5555 6666 7777"
+ val mockAuthTokenCache: AuthTokenCache = mockk(relaxed = true)
+ every { mockServiceConnectionManager.authTokenCache() } returns mockAuthTokenCache
+ coEvery { mockAuthTokenCache.fetchAuthToken() } returns mockToken
- // Act, Assert
- viewModel.uiSideEffect.test {
- viewModel.onManageAccountClick()
- val action = awaitItem()
- assertIs<ConnectViewModel.UiSideEffect.OpenAccountManagementPageInBrowser>(action)
- assertEquals(mockToken, action.token)
+ // Act, Assert
+ viewModel.uiSideEffect.test {
+ viewModel.onManageAccountClick()
+ val action = awaitItem()
+ assertIs<ConnectViewModel.UiSideEffect.OpenAccountManagementPageInBrowser>(action)
+ assertEquals(mockToken, action.token)
+ }
}
- }
@Test
- fun testOutOfTimeUiSideEffect() = runTest {
+ fun `given OutOfTimeUseCase returns true uiSideEffect should emit OutOfTime`() = runTest {
// Arrange
val deferred = async { viewModel.uiSideEffect.first() }
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModelTest.kt
index 3f7966e8bd..11244e9df4 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModelTest.kt
@@ -61,7 +61,7 @@ class DeviceRevokedViewModelTest {
}
@Test
- fun testUiStateWhenServiceNotConnected() = runTest {
+ fun `when service connection is Disconnected then uiState should be UNKNOWN`() = runTest {
// Arrange, Act, Assert
viewModel.uiState.test {
serviceConnectionState.value = ServiceConnectionState.Disconnected
@@ -70,7 +70,7 @@ class DeviceRevokedViewModelTest {
}
@Test
- fun testUiStateWhenServiceConnectedButNotReady() = runTest {
+ fun `when service connection is ConnectedNotReady then uiState should be UNKNOWN`() = runTest {
// Arrange, Act, Assert
viewModel.uiState.test {
serviceConnectionState.value = ServiceConnectionState.ConnectedNotReady(mockk())
@@ -79,7 +79,7 @@ class DeviceRevokedViewModelTest {
}
@Test
- fun testUiStateWhenServiceConnectedAndReady() = runTest {
+ fun `when service connection is ConnectedReady uiState should be SECURED`() = runTest {
// Arrange
val mockedContainer =
mockk<ServiceConnectionContainer>().apply {
@@ -104,7 +104,7 @@ class DeviceRevokedViewModelTest {
}
@Test
- fun testGoToLoginWhenDisconnected() {
+ fun `onGoToLoginClicked should invoke logout on AccountRepository`() {
// Arrange
val mockedContainer =
mockk<ServiceConnectionContainer>().also {
@@ -122,7 +122,7 @@ class DeviceRevokedViewModelTest {
}
@Test
- fun testGoToLoginWhenConnected() {
+ fun `onGoToLoginClicked should invoke disconnect before logout when connected`() {
// Arrange
val mockedContainer =
mockk<ServiceConnectionContainer>().also {
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/FilterViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/FilterViewModelTest.kt
index 210ed88666..fda88bff79 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/FilterViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/FilterViewModelTest.kt
@@ -71,59 +71,63 @@ class FilterViewModelTest {
}
@Test
- fun testSetSelectedOwnership() = runTest {
- // Arrange
- val mockOwnership = Ownership.Rented
- // Assert
- viewModel.uiState.test {
- assertEquals(awaitItem().selectedOwnership, Ownership.MullvadOwned)
- viewModel.setSelectedOwnership(mockOwnership)
- assertEquals(mockOwnership, awaitItem().selectedOwnership)
+ fun `setSelectedOwnership with Rented should emit uiState where selectedOwnership is Rented`() =
+ runTest {
+ // Arrange
+ val mockOwnership = Ownership.Rented
+ // Assert
+ viewModel.uiState.test {
+ assertEquals(awaitItem().selectedOwnership, Ownership.MullvadOwned)
+ viewModel.setSelectedOwnership(mockOwnership)
+ assertEquals(mockOwnership, awaitItem().selectedOwnership)
+ }
}
- }
@Test
- fun testSetSelectedProvider() = runTest {
- // Arrange
- val mockSelectedProvidersList = Provider("ptisp", false)
- // Assert
- viewModel.uiState.test {
- assertLists(awaitItem().selectedProviders, mockSelectedProviders)
- viewModel.setSelectedProvider(true, mockSelectedProvidersList)
- assertLists(
- listOf(mockSelectedProvidersList) + mockSelectedProviders,
- awaitItem().selectedProviders
- )
+ fun `setSelectionProvider should emit uiState where selectedProviders include the selected provider`() =
+ runTest {
+ // Arrange
+ val mockSelectedProvidersList = Provider("ptisp", false)
+ // Assert
+ viewModel.uiState.test {
+ assertLists(awaitItem().selectedProviders, mockSelectedProviders)
+ viewModel.setSelectedProvider(true, mockSelectedProvidersList)
+ assertLists(
+ listOf(mockSelectedProvidersList) + mockSelectedProviders,
+ awaitItem().selectedProviders
+ )
+ }
}
- }
@Test
- fun testSetAllProviders() = runTest {
- // Arrange
- val mockProvidersList = dummyListOfAllProviders
- // Act
- viewModel.setAllProviders(true)
- // Assert
- viewModel.uiState.test {
- val state = awaitItem()
- assertEquals(mockProvidersList, state.selectedProviders)
+ fun `setAllProvider with true should emit uiState with selectedProviders includes all providers`() =
+ runTest {
+ // Arrange
+ val mockProvidersList = dummyListOfAllProviders
+ // Act
+ viewModel.setAllProviders(true)
+ // Assert
+ viewModel.uiState.test {
+ val state = awaitItem()
+ assertEquals(mockProvidersList, state.selectedProviders)
+ }
}
- }
@Test
- fun testOnApplyButtonClicked() = runTest {
- // Arrange
- val mockOwnership = Ownership.MullvadOwned.toOwnershipConstraint()
- val mockSelectedProviders =
- mockSelectedProviders.toConstraintProviders(dummyListOfAllProviders)
- // Act
- viewModel.onApplyButtonClicked()
- // Assert
- coVerify {
- mockRelayListFilterUseCase.updateOwnershipAndProviderFilter(
- mockOwnership,
- mockSelectedProviders
- )
+ fun `onApplyButtonClicked should invoke updateOwnershipAndProviderFilter on RelayListFilterUseCase`() =
+ runTest {
+ // Arrange
+ val mockOwnership = Ownership.MullvadOwned.toOwnershipConstraint()
+ val mockSelectedProviders =
+ mockSelectedProviders.toConstraintProviders(dummyListOfAllProviders)
+ // Act
+ viewModel.onApplyButtonClicked()
+ // Assert
+ coVerify {
+ mockRelayListFilterUseCase.updateOwnershipAndProviderFilter(
+ mockOwnership,
+ mockSelectedProviders
+ )
+ }
}
- }
}
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModelTest.kt
index f677615c24..3271fe57eb 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModelTest.kt
@@ -66,7 +66,7 @@ class LoginViewModelTest {
}
@Test
- fun testIsInternetAvailableWithoutInternet() = runTest {
+ fun `given no internet when logging in then show no internet error`() = runTest {
turbineScope {
// Arrange
every { connectivityUseCase.isInternetAvailable() } returns false
@@ -87,12 +87,12 @@ class LoginViewModelTest {
}
@Test
- fun testDefaultState() = runTest {
+ fun `initial state should be initial`() = runTest {
loginViewModel.uiState.test { assertEquals(LoginUiState.INITIAL, awaitItem()) }
}
@Test
- fun testCreateAccount() = runTest {
+ fun `createAccount call should result in NavigateToWelcome side effect`() = runTest {
turbineScope {
// Arrange
val uiStates = loginViewModel.uiState.testIn(backgroundScope)
@@ -109,7 +109,7 @@ class LoginViewModelTest {
}
@Test
- fun testLoginWithValidAccount() = runTest {
+ fun `given valid account when logging in then navigate to connect view`() = runTest {
turbineScope {
// Arrange
val uiStates = loginViewModel.uiState.testIn(backgroundScope)
@@ -128,7 +128,7 @@ class LoginViewModelTest {
}
@Test
- fun testLoginWithInvalidAccount() = runTest {
+ fun `given invalid account when logging in then show invalid credentials`() = runTest {
loginViewModel.uiState.test {
// Arrange
coEvery { mockedAccountRepository.login(any()) } returns LoginResult.InvalidAccount
@@ -142,34 +142,36 @@ class LoginViewModelTest {
}
@Test
- fun testLoginWithTooManyDevicesError() = runTest {
- turbineScope {
- // Arrange
- val uiStates = loginViewModel.uiState.testIn(backgroundScope)
- val sideEffects = loginViewModel.uiSideEffect.testIn(backgroundScope)
- coEvery {
- mockedDeviceRepository.refreshAndAwaitDeviceListWithTimeout(
- any(),
- any(),
- any(),
- any()
- )
- } returns DeviceListEvent.Available(DUMMY_ACCOUNT_TOKEN, listOf())
- coEvery { mockedAccountRepository.login(any()) } returns LoginResult.MaxDevicesReached
+ fun `given account with max devices reached when logging devices reached then navigate to too many devices`() =
+ runTest {
+ turbineScope {
+ // Arrange
+ val uiStates = loginViewModel.uiState.testIn(backgroundScope)
+ val sideEffects = loginViewModel.uiSideEffect.testIn(backgroundScope)
+ coEvery {
+ mockedDeviceRepository.refreshAndAwaitDeviceListWithTimeout(
+ any(),
+ any(),
+ any(),
+ any()
+ )
+ } returns DeviceListEvent.Available(DUMMY_ACCOUNT_TOKEN, listOf())
+ coEvery { mockedAccountRepository.login(any()) } returns
+ LoginResult.MaxDevicesReached
- // Act, Assert
- uiStates.skipDefaultItem()
- loginViewModel.login(DUMMY_ACCOUNT_TOKEN)
- assertEquals(Loading.LoggingIn, uiStates.awaitItem().loginState)
- assertEquals(
- LoginUiSideEffect.TooManyDevices(AccountToken(DUMMY_ACCOUNT_TOKEN)),
- sideEffects.awaitItem()
- )
+ // Act, Assert
+ uiStates.skipDefaultItem()
+ loginViewModel.login(DUMMY_ACCOUNT_TOKEN)
+ assertEquals(Loading.LoggingIn, uiStates.awaitItem().loginState)
+ assertEquals(
+ LoginUiSideEffect.TooManyDevices(AccountToken(DUMMY_ACCOUNT_TOKEN)),
+ sideEffects.awaitItem()
+ )
+ }
}
- }
@Test
- fun testLoginWithRpcError() = runTest {
+ fun `given RpcError when logging in then show unknown error with message`() = runTest {
loginViewModel.uiState.test {
// Arrange
coEvery { mockedAccountRepository.login(any()) } returns LoginResult.RpcError
@@ -186,7 +188,7 @@ class LoginViewModelTest {
}
@Test
- fun testLoginWithUnknownError() = runTest {
+ fun `given OtherError when logging in then show unknown error with message`() = runTest {
loginViewModel.uiState.test {
// Arrange
coEvery { mockedAccountRepository.login(any()) } returns LoginResult.OtherError
@@ -203,20 +205,21 @@ class LoginViewModelTest {
}
@Test
- fun testAccountHistory() = runTest {
- loginViewModel.uiState.test {
- // Act, Assert
- skipDefaultItem()
- accountHistoryTestEvents.emit(AccountHistory.Available(DUMMY_ACCOUNT_TOKEN))
- assertEquals(
- LoginUiState.INITIAL.copy(lastUsedAccount = AccountToken(DUMMY_ACCOUNT_TOKEN)),
- awaitItem()
- )
+ fun `on new accountHistory emission uiState should include lastUsedAccount matching accountHistory`() =
+ runTest {
+ loginViewModel.uiState.test {
+ // Act, Assert
+ skipDefaultItem()
+ accountHistoryTestEvents.emit(AccountHistory.Available(DUMMY_ACCOUNT_TOKEN))
+ assertEquals(
+ LoginUiState.INITIAL.copy(lastUsedAccount = AccountToken(DUMMY_ACCOUNT_TOKEN)),
+ awaitItem()
+ )
+ }
}
- }
@Test
- fun testClearingAccountHistory() = runTest {
+ fun `clearAccountHistory should invoke clearAccountHistory on AccountRepository`() = runTest {
// Act, Assert
loginViewModel.clearAccountHistory()
verify { mockedAccountRepository.clearAccountHistory() }
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModelTest.kt
index 0df34e0747..a5171b2ea6 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModelTest.kt
@@ -71,7 +71,7 @@ class OutOfTimeViewModelTest {
private lateinit var viewModel: OutOfTimeViewModel
@BeforeEach
- fun setUp() {
+ fun setup() {
mockkStatic(SERVICE_CONNECTION_MANAGER_EXTENSIONS)
mockkStatic(PURCHASE_RESULT_EXTENSIONS_CLASS)
@@ -110,7 +110,7 @@ class OutOfTimeViewModelTest {
}
@Test
- fun testSitePaymentClick() = runTest {
+ fun `when clicking on site payment then open website account view`() = runTest {
// Arrange
val mockToken = "4444 5555 6666 7777"
val mockAuthTokenCache: AuthTokenCache = mockk(relaxed = true)
@@ -127,7 +127,7 @@ class OutOfTimeViewModelTest {
}
@Test
- fun testUpdateTunnelState() = runTest {
+ fun `when tunnel state changes then ui should be updated`() = runTest {
// Arrange
val tunnelRealStateTestItem = TunnelState.Connected(mockk(), mockk())
@@ -143,21 +143,22 @@ class OutOfTimeViewModelTest {
}
@Test
- fun testOpenConnectScreen() = runTest {
- // Arrange
- val mockExpiryDate: DateTime = mockk()
- every { mockExpiryDate.isAfter(any<ReadableInstant>()) } returns true
+ fun `when OutOfTimeUseCase returns false uiSideEffect should emit OpenConnectScreen`() =
+ runTest {
+ // Arrange
+ val mockExpiryDate: DateTime = mockk()
+ every { mockExpiryDate.isAfter(any<ReadableInstant>()) } returns true
- // Act, Assert
- viewModel.uiSideEffect.test {
- outOfTimeFlow.value = false
- val action = awaitItem()
- assertIs<OutOfTimeViewModel.UiSideEffect.OpenConnectScreen>(action)
+ // Act, Assert
+ viewModel.uiSideEffect.test {
+ outOfTimeFlow.value = false
+ val action = awaitItem()
+ assertIs<OutOfTimeViewModel.UiSideEffect.OpenConnectScreen>(action)
+ }
}
- }
@Test
- fun testOnDisconnectClick() = runTest {
+ fun `onDisconnectClick should invoke disconnect on ConnectionProxy`() = runTest {
// Arrange
val mockProxy: ConnectionProxy = mockk(relaxed = true)
every { mockServiceConnectionManager.connectionProxy() } returns mockProxy
@@ -170,70 +171,74 @@ class OutOfTimeViewModelTest {
}
@Test
- fun testBillingProductsUnavailableState() = runTest {
- // Arrange
- val productsUnavailable = PaymentAvailability.ProductsUnavailable
- paymentAvailabilityFlow.value = productsUnavailable
- serviceConnectionStateFlow.value =
- ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ fun `when paymentAvailability emits ProductsUnavailable uiState should include state NoPayment`() =
+ runTest {
+ // Arrange
+ val productsUnavailable = PaymentAvailability.ProductsUnavailable
+ paymentAvailabilityFlow.value = productsUnavailable
+ serviceConnectionStateFlow.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
- // Act, Assert
- viewModel.uiState.test {
- val result = awaitItem().billingPaymentState
- assertIs<PaymentState.NoPayment>(result)
+ // Act, Assert
+ viewModel.uiState.test {
+ val result = awaitItem().billingPaymentState
+ assertIs<PaymentState.NoPayment>(result)
+ }
}
- }
@Test
- fun testBillingProductsGenericErrorState() = runTest {
- // Arrange
- val paymentAvailabilityError = PaymentAvailability.Error.Other(mockk())
- paymentAvailabilityFlow.value = paymentAvailabilityError
- serviceConnectionStateFlow.value =
- ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ fun `when paymentAvailability emits ErrorOther uiState should include state ErrorGeneric`() =
+ runTest {
+ // Arrange
+ val paymentAvailabilityError = PaymentAvailability.Error.Other(mockk())
+ paymentAvailabilityFlow.value = paymentAvailabilityError
+ serviceConnectionStateFlow.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
- // Act, Assert
- viewModel.uiState.test {
- val result = awaitItem().billingPaymentState
- assertIs<PaymentState.Error.Generic>(result)
+ // Act, Assert
+ viewModel.uiState.test {
+ val result = awaitItem().billingPaymentState
+ assertIs<PaymentState.Error.Generic>(result)
+ }
}
- }
@Test
- fun testBillingProductsBillingErrorState() = runTest {
- // Arrange
- val paymentAvailabilityError = PaymentAvailability.Error.BillingUnavailable
- paymentAvailabilityFlow.value = paymentAvailabilityError
- serviceConnectionStateFlow.value =
- ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ fun `when paymentAvailability emits ErrorBillingUnavailable uiState should be ErrorBilling`() =
+ runTest {
+ // Arrange
+ val paymentAvailabilityError = PaymentAvailability.Error.BillingUnavailable
+ paymentAvailabilityFlow.value = paymentAvailabilityError
+ serviceConnectionStateFlow.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
- // Act, Assert
- viewModel.uiState.test {
- val result = awaitItem().billingPaymentState
- assertIs<PaymentState.Error.Billing>(result)
+ // Act, Assert
+ viewModel.uiState.test {
+ val result = awaitItem().billingPaymentState
+ assertIs<PaymentState.Error.Billing>(result)
+ }
}
- }
@Test
- fun testBillingProductsPaymentAvailableState() = runTest {
- // Arrange
- val mockProduct: PaymentProduct = mockk()
- val expectedProductList = listOf(mockProduct)
- val productsAvailable = PaymentAvailability.ProductsAvailable(listOf(mockProduct))
- paymentAvailabilityFlow.value = productsAvailable
- serviceConnectionStateFlow.value =
- ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ fun `when paymentAvailability emits ProductsAvailable uiState should be Available with products`() =
+ runTest {
+ // Arrange
+ val mockProduct: PaymentProduct = mockk()
+ val expectedProductList = listOf(mockProduct)
+ val productsAvailable = PaymentAvailability.ProductsAvailable(listOf(mockProduct))
+ paymentAvailabilityFlow.value = productsAvailable
+ serviceConnectionStateFlow.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
- // Act, Assert
- viewModel.uiState.test {
- val result = awaitItem().billingPaymentState
- assertIs<PaymentState.PaymentAvailable>(result)
- assertLists(expectedProductList, result.products)
+ // Act, Assert
+ viewModel.uiState.test {
+ val result = awaitItem().billingPaymentState
+ assertIs<PaymentState.PaymentAvailable>(result)
+ assertLists(expectedProductList, result.products)
+ }
}
- }
@Test
- fun testOnClosePurchaseResultDialogSuccessful() {
+ fun `onClosePurchaseResultDialog with success should invoke fetchAccountExpiry on AccountRepository`() {
// Arrange
// Act
@@ -241,11 +246,21 @@ class OutOfTimeViewModelTest {
// Assert
verify { mockAccountRepository.fetchAccountExpiry() }
+ }
+
+ @Test
+ fun `onClosePurchaseResultDialog with success should invoke resetPurchaseResult on PaymentUseCase`() {
+ // Arrange
+
+ // Act
+ viewModel.onClosePurchaseResultDialog(success = true)
+
+ // Assert
coVerify { mockPaymentUseCase.resetPurchaseResult() }
}
@Test
- fun testOnClosePurchaseResultDialogNotSuccessful() {
+ fun `onClosePurchaseResultDialog with success false should invoke queryPaymentAvailability on PaymentUseCase`() {
// Arrange
// Act
@@ -253,6 +268,16 @@ class OutOfTimeViewModelTest {
// Assert
coVerify { mockPaymentUseCase.queryPaymentAvailability() }
+ }
+
+ @Test
+ fun `onClosePurchaseResultDialog with success false should invoke resetPurchaseResult on PaymentUseCase`() {
+ // Arrange
+
+ // Act
+ viewModel.onClosePurchaseResultDialog(success = false)
+
+ // Assert
coVerify { mockPaymentUseCase.resetPurchaseResult() }
}
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/PaymentViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/PaymentViewModelTest.kt
index 1e2fba3c96..49e98c95e6 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/PaymentViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/PaymentViewModelTest.kt
@@ -27,7 +27,7 @@ class PaymentViewModelTest {
private lateinit var viewModel: PaymentViewModel
@BeforeEach
- fun setUp() {
+ fun setup() {
coEvery { mockPaymentUseCase.purchaseResult } returns purchaseResult
viewModel = PaymentViewModel(paymentUseCase = mockPaymentUseCase)
@@ -39,24 +39,25 @@ class PaymentViewModelTest {
}
@Test
- fun testBillingUserCancelled() = runTest {
- // Arrange
- val result = PurchaseResult.Completed.Cancelled
- purchaseResult.value = result
-
- // Act, Assert
- viewModel.uiState.test {
- assertEquals(PaymentDialogData(), awaitItem().paymentDialogData)
+ fun `given PaymentUseCase purchaseResult emits cancelled uiSideEffect should emit PaymentCancelled`() =
+ runTest {
+ // Arrange
+ val result = PurchaseResult.Completed.Cancelled
purchaseResult.value = result
- }
- viewModel.uiSideEffect.test {
- assertEquals(PaymentUiSideEffect.PaymentCancelled, awaitItem())
+ // Act, Assert
+ viewModel.uiState.test {
+ assertEquals(PaymentDialogData(), awaitItem().paymentDialogData)
+ purchaseResult.value = result
+ }
+
+ viewModel.uiSideEffect.test {
+ assertEquals(PaymentUiSideEffect.PaymentCancelled, awaitItem())
+ }
}
- }
@Test
- fun testBillingPurchaseSuccess() = runTest {
+ fun `purchaseResult emitting Success should result in success dialog state`() = runTest {
// Arrange
val result = PurchaseResult.Completed.Success
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ReportProblemViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ReportProblemViewModelTest.kt
index 6ea1a85ed2..80cb2d5e58 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ReportProblemViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ReportProblemViewModelTest.kt
@@ -32,7 +32,7 @@ class ReportProblemViewModelTest {
private lateinit var viewModel: ReportProblemViewModel
@BeforeEach
- fun setUp() {
+ fun setup() {
MockKAnnotations.init(this)
coEvery { mockMullvadProblemReport.collectLogs() } returns true
coEvery { mockProblemReportRepository.problemReport } returns problemReportFlow
@@ -45,129 +45,135 @@ class ReportProblemViewModelTest {
}
@Test
- fun sendReportFailedToCollectLogs() = runTest {
- // Arrange
- coEvery { mockMullvadProblemReport.sendReport(any()) } returns
- SendProblemReportResult.Error.CollectLog
- val email = "my@email.com"
+ fun `when sendReport returns CollectLog error then uiState should emit sendingState with CollectLog error`() =
+ runTest {
+ // Arrange
+ coEvery { mockMullvadProblemReport.sendReport(any()) } returns
+ SendProblemReportResult.Error.CollectLog
+ val email = "my@email.com"
- // Act, Assert
- viewModel.uiState.test {
- assertEquals(null, awaitItem().sendingState)
- viewModel.sendReport(email, "My description")
- assertEquals(SendingReportUiState.Sending, awaitItem().sendingState)
- assertEquals(
- SendingReportUiState.Error(SendProblemReportResult.Error.CollectLog),
- awaitItem().sendingState
- )
+ // Act, Assert
+ viewModel.uiState.test {
+ assertEquals(null, awaitItem().sendingState)
+ viewModel.sendReport(email, "My description")
+ assertEquals(SendingReportUiState.Sending, awaitItem().sendingState)
+ assertEquals(
+ SendingReportUiState.Error(SendProblemReportResult.Error.CollectLog),
+ awaitItem().sendingState
+ )
+ }
}
- }
@Test
- fun sendReportFailedToSendReport() = runTest {
- // Arrange
- coEvery { mockMullvadProblemReport.sendReport(any()) } returns
- SendProblemReportResult.Error.SendReport
- val email = "my@email.com"
+ fun `when sendReport returns SendReport error then uiState should emit sendingState with SendReport error`() =
+ runTest {
+ // Arrange
+ coEvery { mockMullvadProblemReport.sendReport(any()) } returns
+ SendProblemReportResult.Error.SendReport
+ val email = "my@email.com"
- // Act, Assert
- viewModel.uiState.test {
- assertEquals(null, awaitItem().sendingState)
- viewModel.sendReport(email, "My description")
- assertEquals(SendingReportUiState.Sending, awaitItem().sendingState)
- assertEquals(
- SendingReportUiState.Error(SendProblemReportResult.Error.SendReport),
- awaitItem().sendingState
- )
+ // Act, Assert
+ viewModel.uiState.test {
+ assertEquals(null, awaitItem().sendingState)
+ viewModel.sendReport(email, "My description")
+ assertEquals(SendingReportUiState.Sending, awaitItem().sendingState)
+ assertEquals(
+ SendingReportUiState.Error(SendProblemReportResult.Error.SendReport),
+ awaitItem().sendingState
+ )
+ }
}
- }
@Test
- fun sendReportWithoutEmailSuccessfully() = runTest {
- // Arrange
- coEvery { mockMullvadProblemReport.sendReport(any()) } returns
- SendProblemReportResult.Success
- val email = ""
- val description = "My description"
+ fun `when sendReport with no email returns Success then uiState should emit sendingState with Success`() =
+ runTest {
+ // Arrange
+ coEvery { mockMullvadProblemReport.sendReport(any()) } returns
+ SendProblemReportResult.Success
+ val email = ""
+ val description = "My description"
- coEvery { mockProblemReportRepository.setDescription(any()) } answers
- {
- problemReportFlow.value = problemReportFlow.value.copy(description = arg(0))
- }
+ coEvery { mockProblemReportRepository.setDescription(any()) } answers
+ {
+ problemReportFlow.value = problemReportFlow.value.copy(description = arg(0))
+ }
- // Act, Assert
- viewModel.uiState.test {
- assertEquals(ReportProblemUiState(), awaitItem())
- viewModel.updateDescription(description)
- assertEquals(ReportProblemUiState(description = description), awaitItem())
+ // Act, Assert
+ viewModel.uiState.test {
+ assertEquals(ReportProblemUiState(), awaitItem())
+ viewModel.updateDescription(description)
+ assertEquals(ReportProblemUiState(description = description), awaitItem())
- viewModel.sendReport(email, description, true)
- assertEquals(
- ReportProblemUiState(SendingReportUiState.Sending, email, description),
- awaitItem()
- )
- assertEquals(
- ReportProblemUiState(
- SendingReportUiState.Success(null),
- "",
- "",
- ),
- awaitItem()
- )
+ viewModel.sendReport(email, description, true)
+ assertEquals(
+ ReportProblemUiState(SendingReportUiState.Sending, email, description),
+ awaitItem()
+ )
+ assertEquals(
+ ReportProblemUiState(
+ SendingReportUiState.Success(null),
+ "",
+ "",
+ ),
+ awaitItem()
+ )
+ }
}
- }
@Test
- fun sendReportSuccessfully() = runTest {
- // Arrange
- coEvery { mockMullvadProblemReport.collectLogs() } returns true
- coEvery { mockMullvadProblemReport.sendReport(any()) } returns
- SendProblemReportResult.Success
- val email = "my@email.com"
- val description = "My description"
+ fun `when sendReport with email returns Success then uiState should emit sendingState with Success`() =
+ runTest {
+ // Arrange
+ coEvery { mockMullvadProblemReport.collectLogs() } returns true
+ coEvery { mockMullvadProblemReport.sendReport(any()) } returns
+ SendProblemReportResult.Success
+ val email = "my@email.com"
+ val description = "My description"
- // This might look a bit weird, and is not optimal. An alternative would be to use the real
- // ProblemReportRepository, but that would complicate the other tests. This is a compromise.
- coEvery { mockProblemReportRepository.setEmail(any()) } answers
- {
- problemReportFlow.value = problemReportFlow.value.copy(email = arg(0))
- }
- coEvery { mockProblemReportRepository.setDescription(any()) } answers
- {
- problemReportFlow.value = problemReportFlow.value.copy(description = arg(0))
- }
+ // This might look a bit weird, and is not optimal. An alternative would be to use the
+ // real
+ // ProblemReportRepository, but that would complicate the other tests. This is a
+ // compromise.
+ coEvery { mockProblemReportRepository.setEmail(any()) } answers
+ {
+ problemReportFlow.value = problemReportFlow.value.copy(email = arg(0))
+ }
+ coEvery { mockProblemReportRepository.setDescription(any()) } answers
+ {
+ problemReportFlow.value = problemReportFlow.value.copy(description = arg(0))
+ }
- // Act, Assert
- viewModel.uiState.test {
- assertEquals(awaitItem(), ReportProblemUiState(null, "", ""))
- viewModel.updateEmail(email)
- awaitItem()
- viewModel.updateDescription(description)
- awaitItem()
-
- viewModel.sendReport(email, description)
-
- assertEquals(
- ReportProblemUiState(
- SendingReportUiState.Sending,
- email,
- description,
- ),
+ // Act, Assert
+ viewModel.uiState.test {
+ assertEquals(awaitItem(), ReportProblemUiState(null, "", ""))
+ viewModel.updateEmail(email)
awaitItem()
- )
- assertEquals(
- ReportProblemUiState(
- SendingReportUiState.Success(email),
- "",
- "",
- ),
+ viewModel.updateDescription(description)
awaitItem()
- )
+
+ viewModel.sendReport(email, description)
+
+ assertEquals(
+ ReportProblemUiState(
+ SendingReportUiState.Sending,
+ email,
+ description,
+ ),
+ awaitItem()
+ )
+ assertEquals(
+ ReportProblemUiState(
+ SendingReportUiState.Success(email),
+ "",
+ "",
+ ),
+ awaitItem()
+ )
+ }
}
- }
@Test
- fun testUpdateEmail() = runTest {
+ fun `updateEmail should invoke setEmail on ProblemReportRepository`() = runTest {
// Arrange
val email = "my@email.com"
@@ -179,7 +185,7 @@ class ReportProblemViewModelTest {
}
@Test
- fun testUpdateDescription() = runTest {
+ fun `updateDescription should invoke updateDescription on ProblemReportRepository`() = runTest {
// Arrange
val description = "My description"
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/SelectLocationViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/SelectLocationViewModelTest.kt
index 4224563d3b..d8bcc7080f 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/SelectLocationViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/SelectLocationViewModelTest.kt
@@ -78,12 +78,12 @@ class SelectLocationViewModelTest {
}
@Test
- fun testInitialState() = runTest {
+ fun `initial state should be loading`() = runTest {
assertEquals(SelectLocationUiState.Loading, viewModel.uiState.value)
}
@Test
- fun testUpdateLocations() = runTest {
+ fun `given relayListWithSelection emits update uiState should contain new update`() = runTest {
// Arrange
val mockCountries = listOf<RelayItem.Country>(mockk(), mockk())
val mockCustomList = listOf<RelayItem.CustomList>(mockk())
@@ -108,32 +108,34 @@ class SelectLocationViewModelTest {
}
@Test
- fun testUpdateLocationsNoSelectedRelay() = runTest {
- // Arrange
- val mockCustomList = listOf<RelayItem.CustomList>(mockk())
- val mockCountries = listOf<RelayItem.Country>(mockk(), mockk())
- val selectedItem: RelayItem? = null
- every { mockCountries.filterOnSearchTerm(any(), selectedItem) } returns mockCountries
- relayListWithSelectionFlow.value = RelayList(mockCustomList, mockCountries, selectedItem)
+ fun `given relayListWithSelection emits update with no selections selectedItem should be null`() =
+ runTest {
+ // Arrange
+ val mockCustomList = listOf<RelayItem.CustomList>(mockk())
+ val mockCountries = listOf<RelayItem.Country>(mockk(), mockk())
+ val selectedItem: RelayItem? = null
+ every { mockCountries.filterOnSearchTerm(any(), selectedItem) } returns mockCountries
+ relayListWithSelectionFlow.value =
+ RelayList(mockCustomList, mockCountries, selectedItem)
- // Act, Assert
- viewModel.uiState.test {
- val actualState = awaitItem()
- assertIs<SelectLocationUiState.Data>(actualState)
- assertIs<RelayListState.RelayList>(actualState.relayListState)
- assertLists(
- mockCountries,
- (actualState.relayListState as RelayListState.RelayList).countries
- )
- assertEquals(
- selectedItem,
- (actualState.relayListState as RelayListState.RelayList).selectedItem
- )
+ // Act, Assert
+ viewModel.uiState.test {
+ val actualState = awaitItem()
+ assertIs<SelectLocationUiState.Data>(actualState)
+ assertIs<RelayListState.RelayList>(actualState.relayListState)
+ assertLists(
+ mockCountries,
+ (actualState.relayListState as RelayListState.RelayList).countries
+ )
+ assertEquals(
+ selectedItem,
+ (actualState.relayListState as RelayListState.RelayList).selectedItem
+ )
+ }
}
- }
@Test
- fun testSelectRelayAndClose() = runTest {
+ fun `on selectRelay call uiSideEffect should emit CloseScreen and connect`() = runTest {
// Arrange
val mockRelayItem: RelayItem.Country = mockk()
val mockLocation: GeographicLocationConstraint.Country = mockk(relaxed = true)
@@ -158,7 +160,7 @@ class SelectLocationViewModelTest {
}
@Test
- fun testFilterRelay() = runTest {
+ fun `on onSearchTermInput call uiState should emit with filtered countries`() = runTest {
// Arrange
val mockCustomList = listOf<RelayItem.CustomList>(mockk())
val mockCountries = listOf<RelayItem.Country>(mockk(), mockk())
@@ -193,7 +195,7 @@ class SelectLocationViewModelTest {
}
@Test
- fun testFilterNotFound() = runTest {
+ fun `when onSearchTermInput returns empty result uiState should return empty list`() = runTest {
// Arrange
val mockCustomList = listOf<RelayItem.CustomList>(mockk())
val mockCountries = emptyList<RelayItem.Country>()
@@ -220,7 +222,7 @@ class SelectLocationViewModelTest {
}
@Test
- fun testRemoveOwnerFilter() = runTest {
+ fun `removeOwnerFilter should invoke use case with Constraint Any Ownership`() = runTest {
// Arrange
val mockSelectedProviders: Constraint<Providers> = mockk()
every { mockRelayListFilterUseCase.selectedProviders() } returns
@@ -238,7 +240,7 @@ class SelectLocationViewModelTest {
}
@Test
- fun testRemoveProviderFilter() = runTest {
+ fun `removeProviderFilter should invoke use case with Constraint Any Provider`() = runTest {
// Arrange
val mockSelectedOwnership: Constraint<Ownership> = mockk()
every { mockRelayListFilterUseCase.selectedOwnership() } returns
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/SettingsViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/SettingsViewModelTest.kt
index b52ab53ef6..0eace9ca43 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/SettingsViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/SettingsViewModelTest.kt
@@ -47,7 +47,7 @@ class SettingsViewModelTest {
private lateinit var viewModel: SettingsViewModel
@BeforeEach
- fun setUp() {
+ fun setup() {
mockkStatic(CACHE_EXTENSION_CLASS)
val deviceState = MutableStateFlow<DeviceState>(DeviceState.LoggedOut)
mockAppVersionInfoCache =
@@ -75,72 +75,75 @@ class SettingsViewModelTest {
}
@Test
- fun test_device_state_default_state() = runTest {
+ fun `uiState should return isLoggedIn false by default`() = runTest {
// Act, Assert
viewModel.uiState.test { assertEquals(false, awaitItem().isLoggedIn) }
}
@Test
- fun test_device_state_supported_version_state() = runTest {
- // Arrange
- val versionInfoTestItem =
- VersionInfo(
- currentVersion = "1.0",
- upgradeVersion = "1.0",
- isOutdated = false,
- isSupported = true
- )
- every { mockAppVersionInfoCache.version } returns "1.0"
- every { mockAppVersionInfoCache.isSupported } returns true
- every { mockAppVersionInfoCache.isOutdated } returns false
+ fun `when AppVersionInfoCache returns isOutdated false uiState should return isUpdateAvailable false`() =
+ runTest {
+ // Arrange
+ val versionInfoTestItem =
+ VersionInfo(
+ currentVersion = "1.0",
+ upgradeVersion = "1.0",
+ isOutdated = false,
+ isSupported = true
+ )
+ every { mockAppVersionInfoCache.version } returns "1.0"
+ every { mockAppVersionInfoCache.isSupported } returns true
+ every { mockAppVersionInfoCache.isOutdated } returns false
- // Act, Assert
- viewModel.uiState.test {
- awaitItem() // Wait for initial value
+ // Act, Assert
+ viewModel.uiState.test {
+ awaitItem() // Wait for initial value
- serviceConnectionState.value =
- ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
- versionInfo.value = versionInfoTestItem
- val result = awaitItem()
- assertEquals(false, result.isUpdateAvailable)
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ versionInfo.value = versionInfoTestItem
+ val result = awaitItem()
+ assertEquals(false, result.isUpdateAvailable)
+ }
}
- }
@Test
- fun test_device_state_unsupported_version_state() = runTest {
- // Arrange
- every { mockAppVersionInfoCache.isSupported } returns false
- every { mockAppVersionInfoCache.isOutdated } returns false
- every { mockAppVersionInfoCache.version } returns ""
+ fun `when AppVersionInfoCache returns isSupported false uiState should return isUpdateAvailable true`() =
+ runTest {
+ // Arrange
+ every { mockAppVersionInfoCache.isSupported } returns false
+ every { mockAppVersionInfoCache.isOutdated } returns false
+ every { mockAppVersionInfoCache.version } returns ""
- // Act, Assert
- viewModel.uiState.test {
- awaitItem()
+ // Act, Assert
+ viewModel.uiState.test {
+ awaitItem()
- serviceConnectionState.value =
- ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
- val result = awaitItem()
- assertEquals(true, result.isUpdateAvailable)
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ val result = awaitItem()
+ assertEquals(true, result.isUpdateAvailable)
+ }
}
- }
@Test
- fun test_device_state_outdated_version_state() = runTest {
- // Arrange
- every { mockAppVersionInfoCache.isSupported } returns true
- every { mockAppVersionInfoCache.isOutdated } returns true
- every { mockAppVersionInfoCache.version } returns ""
+ fun `when AppVersionInfoCache returns isOutdated true uiState should return isUpdateAvailable true`() =
+ runTest {
+ // Arrange
+ every { mockAppVersionInfoCache.isSupported } returns true
+ every { mockAppVersionInfoCache.isOutdated } returns true
+ every { mockAppVersionInfoCache.version } returns ""
- // Act, Assert
- viewModel.uiState.test {
- awaitItem()
+ // Act, Assert
+ viewModel.uiState.test {
+ awaitItem()
- serviceConnectionState.value =
- ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
- val result = awaitItem()
- assertEquals(true, result.isUpdateAvailable)
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ val result = awaitItem()
+ assertEquals(true, result.isUpdateAvailable)
+ }
}
- }
companion object {
private const val CACHE_EXTENSION_CLASS = "net.mullvad.mullvadvpn.util.CacheExtensionsKt"
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/SplitTunnelingViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/SplitTunnelingViewModelTest.kt
index c0d349e1da..11b253e5ea 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/SplitTunnelingViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/SplitTunnelingViewModelTest.kt
@@ -53,7 +53,7 @@ class SplitTunnelingViewModelTest {
}
@Test
- fun test_has_progress_on_start() = runTest {
+ fun `initial state should be loading`() = runTest {
initTestSubject(emptyList())
val actualState: SplitTunnelingUiState = testSubject.uiState.value
@@ -65,7 +65,7 @@ class SplitTunnelingViewModelTest {
}
@Test
- fun test_empty_app_list() = runTest {
+ fun `empty app list should work`() = runTest {
every { mockedSplitTunneling.excludedAppsChange = captureLambda() } answers
{
lambda<(Set<String>) -> Unit>().invoke(emptySet())
@@ -86,7 +86,7 @@ class SplitTunnelingViewModelTest {
}
@Test
- fun test_apps_list_delivered() = runTest {
+ fun `includedApps and excludedApps should both be included in uiState`() = runTest {
val appExcluded = AppData("test.excluded", 0, "testName1")
val appNotExcluded = AppData("test.not.excluded", 0, "testName2")
every { mockedSplitTunneling.excludedAppsChange = captureLambda() } answers
@@ -119,7 +119,7 @@ class SplitTunnelingViewModelTest {
}
@Test
- fun test_include_app() = runTest {
+ fun `include app should work`() = runTest {
var excludedAppsCallback = slot<(Set<String>) -> Unit>()
val app = AppData("test", 0, "testName")
every { mockedSplitTunneling.includeApp(app.packageName) } just runs
@@ -165,7 +165,7 @@ class SplitTunnelingViewModelTest {
}
@Test
- fun test_add_app_to_excluded() = runTest {
+ fun `onExcludeApp should result in new uiState with app excluded`() = runTest {
var excludedAppsCallback = slot<(Set<String>) -> Unit>()
val app = AppData("test", 0, "testName")
every { mockedSplitTunneling.excludeApp(app.packageName) } just runs
@@ -212,7 +212,7 @@ class SplitTunnelingViewModelTest {
}
@Test
- fun test_disabled_state() = runTest {
+ fun `when split tunneling is disabled uiState should be disabled`() = runTest {
every { mockedSplitTunneling.excludedAppsChange = captureLambda() } answers
{
lambda<(Set<String>) -> Unit>().invoke(emptySet())
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModelTest.kt
index 7c54cd2c5e..6934384643 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModelTest.kt
@@ -42,7 +42,7 @@ class VoucherDialogViewModelTest {
private lateinit var viewModel: VoucherDialogViewModel
@BeforeEach
- fun setUp() {
+ fun setup() {
every { mockServiceConnectionManager.connectionState } returns serviceConnectionState
viewModel =
@@ -58,9 +58,8 @@ class VoucherDialogViewModelTest {
}
@Test
- fun testSubmitVoucher() = runTest {
+ fun `ensure onRedeem invokes submit on VoucherRedeemer with same voucher code`() = runTest {
val voucher = DUMMY_INVALID_VOUCHER
- val dummyStringResource = DUMMY_STRING_RESOURCE
// Arrange
every { mockServiceConnectionManager.voucherRedeemer() } returns mockVoucherRedeemer
@@ -69,7 +68,7 @@ class VoucherDialogViewModelTest {
VoucherSubmissionResult.Ok(mockVoucherSubmission)
// Act
- assertIs<VoucherDialogState.Default>(viewModel.uiState.value.voucherViewModelState)
+ assertIs<VoucherDialogState.Default>(viewModel.uiState.value.voucherState)
viewModel.onRedeem(voucher)
// Assert
@@ -77,7 +76,7 @@ class VoucherDialogViewModelTest {
}
@Test
- fun testInsertInvalidVoucher() = runTest {
+ fun `given invalid voucher when redeeming then show error`() = runTest {
val voucher = DUMMY_INVALID_VOUCHER
val dummyStringResource = DUMMY_STRING_RESOURCE
@@ -94,13 +93,13 @@ class VoucherDialogViewModelTest {
serviceConnectionState.value =
ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
viewModel.onRedeem(voucher)
- assertTrue { awaitItem().voucherViewModelState is VoucherDialogState.Verifying }
- assertTrue { awaitItem().voucherViewModelState is VoucherDialogState.Error }
+ assertTrue { awaitItem().voucherState is VoucherDialogState.Verifying }
+ assertTrue { awaitItem().voucherState is VoucherDialogState.Error }
}
}
@Test
- fun testInsertValidVoucher() = runTest {
+ fun `given valid voucher when redeeming then show success`() = runTest {
val voucher = DUMMY_VALID_VOUCHER
val dummyStringResource = DUMMY_STRING_RESOURCE
@@ -117,13 +116,13 @@ class VoucherDialogViewModelTest {
serviceConnectionState.value =
ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
viewModel.onRedeem(voucher)
- assertTrue { awaitItem().voucherViewModelState is VoucherDialogState.Verifying }
- assertTrue { awaitItem().voucherViewModelState is VoucherDialogState.Success }
+ assertTrue { awaitItem().voucherState is VoucherDialogState.Verifying }
+ assertTrue { awaitItem().voucherState is VoucherDialogState.Success }
}
}
@Test
- fun testResetStateAfterChangingInput() = runTest {
+ fun `when voucher input is changed then clear error`() = runTest {
val voucher = DUMMY_INVALID_VOUCHER
val dummyStringResource = DUMMY_STRING_RESOURCE
@@ -140,10 +139,10 @@ class VoucherDialogViewModelTest {
serviceConnectionState.value =
ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
viewModel.onRedeem(voucher)
- assertTrue { awaitItem().voucherViewModelState is VoucherDialogState.Verifying }
- assertTrue { awaitItem().voucherViewModelState is VoucherDialogState.Error }
+ assertTrue { awaitItem().voucherState is VoucherDialogState.Verifying }
+ assertTrue { awaitItem().voucherState is VoucherDialogState.Error }
viewModel.onVoucherInputChange(DUMMY_VALID_VOUCHER)
- assertTrue { awaitItem().voucherViewModelState is VoucherDialogState.Default }
+ assertTrue { awaitItem().voucherState is VoucherDialogState.Default }
}
}
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelTest.kt
index 5d44dca487..11992c40c0 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelTest.kt
@@ -48,7 +48,7 @@ class VpnSettingsViewModelTest {
private lateinit var viewModel: VpnSettingsViewModel
@BeforeEach
- fun setUp() {
+ fun setup() {
every { mockSettingsRepository.settingsUpdates } returns mockSettingsUpdate
every { mockPortRangeUseCase.portRanges() } returns portRangeFlow
@@ -70,18 +70,20 @@ class VpnSettingsViewModelTest {
}
@Test
- fun test_select_quantum_resistant_state_select() = runTest {
- val quantumResistantState = QuantumResistantState.On
- every { mockSettingsRepository.setWireguardQuantumResistant(quantumResistantState) } returns
- Unit
- viewModel.onSelectQuantumResistanceSetting(quantumResistantState)
- verify(exactly = 1) {
- mockSettingsRepository.setWireguardQuantumResistant(quantumResistantState)
+ fun `onSelectQuantumResistanceSetting should invoke setWireguardQuantumResistant on SettingsRepository`() =
+ runTest {
+ val quantumResistantState = QuantumResistantState.On
+ every {
+ mockSettingsRepository.setWireguardQuantumResistant(quantumResistantState)
+ } returns Unit
+ viewModel.onSelectQuantumResistanceSetting(quantumResistantState)
+ verify(exactly = 1) {
+ mockSettingsRepository.setWireguardQuantumResistant(quantumResistantState)
+ }
}
- }
@Test
- fun test_update_quantum_resistant_default_state() = runTest {
+ fun `quantumResistant should be Off in uiState in initial state`() = runTest {
// Arrange
val expectedResistantState = QuantumResistantState.Off
@@ -92,66 +94,69 @@ class VpnSettingsViewModelTest {
}
@Test
- fun test_update_quantum_resistant_update_state() = runTest {
- val defaultResistantState = QuantumResistantState.Off
- val expectedResistantState = QuantumResistantState.On
- val mockSettings: Settings = mockk(relaxed = true)
- val mockTunnelOptions: TunnelOptions = mockk(relaxed = true)
- val mockWireguardTunnelOptions: WireguardTunnelOptions = mockk(relaxed = true)
+ fun `when SettingsRepository emits quantumResistant On uiState should emit quantumResistant On`() =
+ runTest {
+ val defaultResistantState = QuantumResistantState.Off
+ val expectedResistantState = QuantumResistantState.On
+ val mockSettings: Settings = mockk(relaxed = true)
+ val mockTunnelOptions: TunnelOptions = mockk(relaxed = true)
+ val mockWireguardTunnelOptions: WireguardTunnelOptions = mockk(relaxed = true)
- every { mockSettings.tunnelOptions } returns mockTunnelOptions
- every { mockTunnelOptions.wireguard } returns mockWireguardTunnelOptions
- every { mockWireguardTunnelOptions.quantumResistant } returns expectedResistantState
- every { mockSettings.relaySettings } returns mockk<RelaySettings.Normal>(relaxed = true)
+ every { mockSettings.tunnelOptions } returns mockTunnelOptions
+ every { mockTunnelOptions.wireguard } returns mockWireguardTunnelOptions
+ every { mockWireguardTunnelOptions.quantumResistant } returns expectedResistantState
+ every { mockSettings.relaySettings } returns mockk<RelaySettings.Normal>(relaxed = true)
- viewModel.uiState.test {
- assertEquals(defaultResistantState, awaitItem().quantumResistant)
- mockSettingsUpdate.value = mockSettings
- assertEquals(expectedResistantState, awaitItem().quantumResistant)
+ viewModel.uiState.test {
+ assertEquals(defaultResistantState, awaitItem().quantumResistant)
+ mockSettingsUpdate.value = mockSettings
+ assertEquals(expectedResistantState, awaitItem().quantumResistant)
+ }
}
- }
@Test
- fun test_update_wireguard_port_state() = runTest {
- // Arrange
- val expectedPort: Constraint<Port> = Constraint.Only(Port(99))
- val mockSettings: Settings = mockk(relaxed = true)
- val mockRelaySettings: RelaySettings.Normal = mockk()
- val mockRelayConstraints: RelayConstraints = mockk()
- val mockWireguardConstraints: WireguardConstraints = mockk()
+ fun `when SettingsRepository emits Constraint Only then uiState should emit custom and selectedWireguardPort with port of Constraint`() =
+ runTest {
+ // Arrange
+ val expectedPort: Constraint<Port> = Constraint.Only(Port(99))
+ val mockSettings: Settings = mockk(relaxed = true)
+ val mockRelaySettings: RelaySettings.Normal = mockk()
+ val mockRelayConstraints: RelayConstraints = mockk()
+ val mockWireguardConstraints: WireguardConstraints = mockk()
- every { mockSettings.relaySettings } returns mockRelaySettings
- every { mockRelaySettings.relayConstraints } returns mockRelayConstraints
- every { mockRelayConstraints.wireguardConstraints } returns mockWireguardConstraints
- every { mockWireguardConstraints.port } returns expectedPort
+ every { mockSettings.relaySettings } returns mockRelaySettings
+ every { mockRelaySettings.relayConstraints } returns mockRelayConstraints
+ every { mockRelayConstraints.wireguardConstraints } returns mockWireguardConstraints
+ every { mockWireguardConstraints.port } returns expectedPort
- // Act, Assert
- viewModel.uiState.test {
- assertIs<Constraint.Any<Port>>(awaitItem().selectedWireguardPort)
- mockSettingsUpdate.value = mockSettings
- assertEquals(expectedPort, awaitItem().customWireguardPort)
- assertEquals(expectedPort, awaitItem().selectedWireguardPort)
+ // Act, Assert
+ viewModel.uiState.test {
+ assertIs<Constraint.Any<Port>>(awaitItem().selectedWireguardPort)
+ mockSettingsUpdate.value = mockSettings
+ assertEquals(expectedPort, awaitItem().customWireguardPort)
+ assertEquals(expectedPort, awaitItem().selectedWireguardPort)
+ }
}
- }
@Test
- fun test_select_wireguard_port() = runTest {
- // Arrange
- val wireguardPort: Constraint<Port> = Constraint.Only(Port(99))
- val wireguardConstraints = WireguardConstraints(port = wireguardPort)
- every { mockRelayListUseCase.updateSelectedWireguardConstraints(any()) } returns Unit
+ fun `onWireguardPortSelected should invoke updateSelectedWireguardConstraint with Constraint Only with same port`() =
+ runTest {
+ // Arrange
+ val wireguardPort: Constraint<Port> = Constraint.Only(Port(99))
+ val wireguardConstraints = WireguardConstraints(port = wireguardPort)
+ every { mockRelayListUseCase.updateSelectedWireguardConstraints(any()) } returns Unit
- // Act
- viewModel.onWireguardPortSelected(wireguardPort)
+ // Act
+ viewModel.onWireguardPortSelected(wireguardPort)
- // Assert
- verify(exactly = 1) {
- mockRelayListUseCase.updateSelectedWireguardConstraints(wireguardConstraints)
+ // Assert
+ verify(exactly = 1) {
+ mockRelayListUseCase.updateSelectedWireguardConstraints(wireguardConstraints)
+ }
}
- }
@Test
- fun `given useCase systemVpnSettingsAvailable is true then uiState should be systemVpnSettingsAvailable=true`() =
+ fun `when useCase systemVpnSettingsAvailable is true then uiState should be systemVpnSettingsAvailable=true`() =
runTest {
val systemVpnSettingsAvailable = true
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt
index d0461a4ee5..74ea210a60 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt
@@ -69,7 +69,7 @@ class WelcomeViewModelTest {
private lateinit var viewModel: WelcomeViewModel
@BeforeEach
- fun setUp() {
+ fun setup() {
mockkStatic(SERVICE_CONNECTION_MANAGER_EXTENSIONS)
mockkStatic(PURCHASE_RESULT_EXTENSIONS_CLASS)
@@ -108,7 +108,7 @@ class WelcomeViewModelTest {
}
@Test
- fun testSitePaymentClick() = runTest {
+ fun `on onSitePaymentClick call uiSideEffect should emit OpenAccountView`() = runTest {
// Arrange
val mockToken = "4444 5555 6666 7777"
val mockAuthTokenCache: AuthTokenCache = mockk(relaxed = true)
@@ -125,9 +125,9 @@ class WelcomeViewModelTest {
}
@Test
- fun testUpdateTunnelState() = runTest {
+ fun `on new TunnelState uiState should include new TunnelState`() = runTest {
// Arrange
- val tunnelUiStateTestItem = TunnelState.Connected(mockk(), mockk())
+ val tunnelUiStateTestItem: TunnelState = mockk()
// Act, Assert
viewModel.uiState.test {
@@ -141,105 +141,110 @@ class WelcomeViewModelTest {
}
@Test
- fun testUpdateAccountNumber() = runTest {
- // Arrange
- val expectedAccountNumber = "4444555566667777"
- val device: Device = mockk()
- every { device.displayName() } returns ""
+ fun `when DeviceRepository returns LoggedIn uiState should include new accountNumber`() =
+ runTest {
+ // Arrange
+ val expectedAccountNumber = "4444555566667777"
+ val device: Device = mockk()
+ every { device.displayName() } returns ""
- // Act, Assert
- viewModel.uiState.test {
- assertEquals(WelcomeUiState(), awaitItem())
- paymentAvailabilityFlow.value = null
- deviceStateFlow.value =
- DeviceState.LoggedIn(
- accountAndDevice =
- AccountAndDevice(account_token = expectedAccountNumber, device = device)
- )
- serviceConnectionStateFlow.value =
- ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
- assertEquals(expectedAccountNumber, awaitItem().accountNumber)
+ // Act, Assert
+ viewModel.uiState.test {
+ assertEquals(WelcomeUiState(), awaitItem())
+ paymentAvailabilityFlow.value = null
+ deviceStateFlow.value =
+ DeviceState.LoggedIn(
+ accountAndDevice =
+ AccountAndDevice(account_token = expectedAccountNumber, device = device)
+ )
+ serviceConnectionStateFlow.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ assertEquals(expectedAccountNumber, awaitItem().accountNumber)
+ }
}
- }
@Test
- fun testOpenConnectScreen() = runTest {
- // Arrange
- val mockExpiryDate: DateTime = mockk()
- every { mockExpiryDate.isAfter(any<ReadableInstant>()) } returns true
+ fun `when OutOfTimeUseCase return false uiSideEffect should emit OpenConnectScreen`() =
+ runTest {
+ // Arrange
+ val mockExpiryDate: DateTime = mockk()
+ every { mockExpiryDate.isAfter(any<ReadableInstant>()) } returns true
- // Act, Assert
- viewModel.uiSideEffect.test {
- outOfTimeFlow.value = false
- val action = awaitItem()
- assertIs<WelcomeViewModel.UiSideEffect.OpenConnectScreen>(action)
+ // Act, Assert
+ viewModel.uiSideEffect.test {
+ outOfTimeFlow.value = false
+ val action = awaitItem()
+ assertIs<WelcomeViewModel.UiSideEffect.OpenConnectScreen>(action)
+ }
}
- }
@Test
- fun testBillingProductsUnavailableState() = runTest {
- // Arrange
- val productsUnavailable = PaymentAvailability.ProductsUnavailable
+ fun `when paymentAvailability emits ProductsUnavailable uiState should include state NoPayment`() =
+ runTest {
+ // Arrange
+ val productsUnavailable = PaymentAvailability.ProductsUnavailable
- // Act, Assert
- viewModel.uiState.test {
- // Default item
- awaitItem()
- paymentAvailabilityFlow.tryEmit(productsUnavailable)
- serviceConnectionStateFlow.value =
- ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
- val result = awaitItem().billingPaymentState
- assertIs<PaymentState.NoPayment>(result)
+ // Act, Assert
+ viewModel.uiState.test {
+ // Default item
+ awaitItem()
+ paymentAvailabilityFlow.tryEmit(productsUnavailable)
+ serviceConnectionStateFlow.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ val result = awaitItem().billingPaymentState
+ assertIs<PaymentState.NoPayment>(result)
+ }
}
- }
@Test
- fun testBillingProductsGenericErrorState() = runTest {
- // Arrange
- val paymentOtherError = PaymentAvailability.Error.Other(mockk())
- paymentAvailabilityFlow.tryEmit(paymentOtherError)
- serviceConnectionStateFlow.value =
- ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ fun `when paymentAvailability emits ErrorOther uiState should include state ErrorGeneric`() =
+ runTest {
+ // Arrange
+ val paymentOtherError = PaymentAvailability.Error.Other(mockk())
+ paymentAvailabilityFlow.tryEmit(paymentOtherError)
+ serviceConnectionStateFlow.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
- // Act, Assert
- viewModel.uiState.test {
- val result = awaitItem().billingPaymentState
- assertIs<PaymentState.Error.Generic>(result)
+ // Act, Assert
+ viewModel.uiState.test {
+ val result = awaitItem().billingPaymentState
+ assertIs<PaymentState.Error.Generic>(result)
+ }
}
- }
@Test
- fun testBillingProductsBillingErrorState() = runTest {
- // Arrange
- val paymentBillingError = PaymentAvailability.Error.BillingUnavailable
- paymentAvailabilityFlow.value = paymentBillingError
- serviceConnectionStateFlow.value =
- ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ fun `when paymentAvailability emits ErrorBillingUnavailable uiState should include state ErrorBilling`() =
+ runTest { // Arrange
+ val paymentBillingError = PaymentAvailability.Error.BillingUnavailable
+ paymentAvailabilityFlow.value = paymentBillingError
+ serviceConnectionStateFlow.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
- // Act, Assert
- viewModel.uiState.test {
- val result = awaitItem().billingPaymentState
- assertIs<PaymentState.Error.Billing>(result)
+ // Act, Assert
+ viewModel.uiState.test {
+ val result = awaitItem().billingPaymentState
+ assertIs<PaymentState.Error.Billing>(result)
+ }
}
- }
@Test
- fun testBillingProductsPaymentAvailableState() = runTest {
- // Arrange
- val mockProduct: PaymentProduct = mockk()
- val expectedProductList = listOf(mockProduct)
- val productsAvailable = PaymentAvailability.ProductsAvailable(listOf(mockProduct))
- paymentAvailabilityFlow.value = productsAvailable
- serviceConnectionStateFlow.value =
- ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ fun `when paymentAvailability emits ProductsAvailable uiState should include state Available with products`() =
+ runTest {
+ // Arrange
+ val mockProduct: PaymentProduct = mockk()
+ val expectedProductList = listOf(mockProduct)
+ val productsAvailable = PaymentAvailability.ProductsAvailable(listOf(mockProduct))
+ paymentAvailabilityFlow.value = productsAvailable
+ serviceConnectionStateFlow.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
- // Act, Assert
- viewModel.uiState.test {
- val result = awaitItem().billingPaymentState
- assertIs<PaymentState.PaymentAvailable>(result)
- assertLists(expectedProductList, result.products)
+ // Act, Assert
+ viewModel.uiState.test {
+ val result = awaitItem().billingPaymentState
+ assertIs<PaymentState.PaymentAvailable>(result)
+ assertLists(expectedProductList, result.products)
+ }
}
- }
companion object {
private const val SERVICE_CONNECTION_MANAGER_EXTENSIONS =
diff --git a/android/lib/billing/src/androidTest/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingRepositoryTest.kt b/android/lib/billing/src/androidTest/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingRepositoryTest.kt
index 386932681d..7ca3219cfb 100644
--- a/android/lib/billing/src/androidTest/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingRepositoryTest.kt
+++ b/android/lib/billing/src/androidTest/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingRepositoryTest.kt
@@ -52,7 +52,7 @@ class BillingRepositoryTest {
CapturingSlot()
@BeforeEach
- fun setUp() {
+ fun setup() {
mockkStatic(BILLING_CLIENT_CLASS)
mockkStatic(BILLING_CLIENT_KOTLIN_CLASS)
mockkStatic(BILLING_FLOW_PARAMS)
diff --git a/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/extension/ProductDetailsResultToPaymentAvailability.kt b/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/extension/ProductDetailsResultToPaymentAvailability.kt
index 37cc701724..2cb3e1371a 100644
--- a/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/extension/ProductDetailsResultToPaymentAvailability.kt
+++ b/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/extension/ProductDetailsResultToPaymentAvailability.kt
@@ -17,7 +17,7 @@ fun ProductDetailsResult.toPaymentAvailability(
productDetailsList.toPaymentProducts(productIdToPaymentStatus)
)
} else {
- PaymentAvailability.NoProductsFounds
+ PaymentAvailability.NoProductsFound
}
}
BillingClient.BillingResponseCode.BILLING_UNAVAILABLE ->
diff --git a/android/lib/billing/src/test/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingPaymentRepositoryTest.kt b/android/lib/billing/src/test/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingPaymentRepositoryTest.kt
index 21e13d5da8..c4d1b04905 100644
--- a/android/lib/billing/src/test/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingPaymentRepositoryTest.kt
+++ b/android/lib/billing/src/test/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingPaymentRepositoryTest.kt
@@ -40,7 +40,7 @@ class BillingPaymentRepositoryTest {
private lateinit var paymentRepository: BillingPaymentRepository
@BeforeEach
- fun setUp() {
+ fun setup() {
mockkStatic(PRODUCT_DETAILS_TO_PAYMENT_PRODUCT_EXT)
every { mockBillingRepository.purchaseEvents } returns purchaseEventFlow
@@ -53,7 +53,7 @@ class BillingPaymentRepositoryTest {
}
@Test
- fun testQueryAvailablePaymentProductsAvailable() = runTest {
+ fun `queryPaymentAvailability should return available products when billing is OK`() = runTest {
// Arrange
val expectedProduct: PaymentProduct = mockk()
val mockProduct: ProductDetails = mockk()
@@ -76,45 +76,47 @@ class BillingPaymentRepositoryTest {
}
@Test
- fun testQueryAvailablePaymentProductsUnavailable() = runTest {
- // Arrange
- val mockResult: ProductDetailsResult = mockk()
- every { mockResult.billingResult.responseCode } returns BillingResponseCode.OK
- every { mockResult.productDetailsList } returns emptyList()
- coEvery { mockBillingRepository.queryPurchases() } returns mockk(relaxed = true)
- coEvery { mockBillingRepository.queryProducts(any()) } returns mockResult
+ fun `queryPaymentAvailability should return NoProductsFound when billing is OK with no products `() =
+ runTest {
+ // Arrange
+ val mockResult: ProductDetailsResult = mockk()
+ every { mockResult.billingResult.responseCode } returns BillingResponseCode.OK
+ every { mockResult.productDetailsList } returns emptyList()
+ coEvery { mockBillingRepository.queryPurchases() } returns mockk(relaxed = true)
+ coEvery { mockBillingRepository.queryProducts(any()) } returns mockResult
- // Act, Assert
- paymentRepository.queryPaymentAvailability().test {
- // Loading
- awaitItem()
- val result = awaitItem()
- assertIs<PaymentAvailability.NoProductsFounds>(result)
- awaitComplete()
+ // Act, Assert
+ paymentRepository.queryPaymentAvailability().test {
+ // Loading
+ awaitItem()
+ val result = awaitItem()
+ assertIs<PaymentAvailability.NoProductsFound>(result)
+ awaitComplete()
+ }
}
- }
@Test
- fun testQueryAvailablePaymentBillingUnavailableError() = runTest {
- // Arrange
- val mockResult: ProductDetailsResult = mockk()
- every { mockResult.billingResult.responseCode } returns
- BillingResponseCode.BILLING_UNAVAILABLE
- coEvery { mockBillingRepository.queryPurchases() } returns mockk(relaxed = true)
- coEvery { mockBillingRepository.queryProducts(any()) } returns mockResult
+ fun `queryPaymentAvailability should return BillingUnavailable when billing is Unavailable `() =
+ runTest {
+ // Arrange
+ val mockResult: ProductDetailsResult = mockk()
+ every { mockResult.billingResult.responseCode } returns
+ BillingResponseCode.BILLING_UNAVAILABLE
+ coEvery { mockBillingRepository.queryPurchases() } returns mockk(relaxed = true)
+ coEvery { mockBillingRepository.queryProducts(any()) } returns mockResult
- // Act, Assert
- paymentRepository.queryPaymentAvailability().test {
- // Loading
- awaitItem()
- val result = awaitItem()
- assertIs<PaymentAvailability.Error.BillingUnavailable>(result)
- awaitComplete()
+ // Act, Assert
+ paymentRepository.queryPaymentAvailability().test {
+ // Loading
+ awaitItem()
+ val result = awaitItem()
+ assertIs<PaymentAvailability.Error.BillingUnavailable>(result)
+ awaitComplete()
+ }
}
- }
@Test
- fun testPurchaseBillingProductStartPurchaseFetchProductsError() = runTest {
+ fun `purchaseProduct should return FetchProductsError when billing is Unavailable`() = runTest {
// Arrange
val mockProductId = ProductId("MOCK")
val mockProductDetailsResult = mockk<ProductDetailsResult>()
@@ -134,85 +136,91 @@ class BillingPaymentRepositoryTest {
}
@Test
- fun testPurchaseBillingProductStartPurchaseNoProductsFoundError() = runTest {
- // Arrange
- val mockProductId = ProductId("MOCK")
- val mockProductDetailsResult = mockk<ProductDetailsResult>()
- every { mockProductDetailsResult.billingResult.responseCode } returns BillingResponseCode.OK
- every { mockProductDetailsResult.productDetailsList } returns emptyList()
- coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns
- mockProductDetailsResult
+ fun `purchaseProduct should return NoProductFound when billingRepository does not find any products`() =
+ runTest {
+ // Arrange
+ val mockProductId = ProductId("MOCK")
+ val mockProductDetailsResult = mockk<ProductDetailsResult>()
+ every { mockProductDetailsResult.billingResult.responseCode } returns
+ BillingResponseCode.OK
+ every { mockProductDetailsResult.productDetailsList } returns emptyList()
+ coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns
+ mockProductDetailsResult
- // Act, Assert
- paymentRepository.purchaseProduct(mockProductId, mockk()).test {
- assertIs<PurchaseResult.FetchingProducts>(awaitItem())
- val result = awaitItem()
- assertIs<PurchaseResult.Error.NoProductFound>(result)
- awaitComplete()
+ // Act, Assert
+ paymentRepository.purchaseProduct(mockProductId, mockk()).test {
+ assertIs<PurchaseResult.FetchingProducts>(awaitItem())
+ val result = awaitItem()
+ assertIs<PurchaseResult.Error.NoProductFound>(result)
+ awaitComplete()
+ }
}
- }
@Test
- fun testPurchaseBillingProductStartPurchaseTransactionIdError() = runTest {
- // Arrange
- val mockProductId = ProductId("MOCK")
- val mockProductDetailsResult = mockk<ProductDetailsResult>()
- val mockProductDetails: ProductDetails = mockk()
- every { mockProductDetails.productId } returns mockProductId.value
- every { mockProductDetailsResult.billingResult.responseCode } returns BillingResponseCode.OK
- every { mockProductDetailsResult.productDetailsList } returns listOf(mockProductDetails)
- coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns
- mockProductDetailsResult
- coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns
- PlayPurchaseInitResult.Error(PlayPurchaseInitError.OtherError)
+ fun `purchaseProduct should return TransactionIdError on PlayPurchaseInitError from PlayPurchaseRepository`() =
+ runTest {
+ // Arrange
+ val mockProductId = ProductId("MOCK")
+ val mockProductDetailsResult = mockk<ProductDetailsResult>()
+ val mockProductDetails: ProductDetails = mockk()
+ every { mockProductDetails.productId } returns mockProductId.value
+ every { mockProductDetailsResult.billingResult.responseCode } returns
+ BillingResponseCode.OK
+ every { mockProductDetailsResult.productDetailsList } returns listOf(mockProductDetails)
+ coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns
+ mockProductDetailsResult
+ coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns
+ PlayPurchaseInitResult.Error(PlayPurchaseInitError.OtherError)
- // Act, Assert
- paymentRepository.purchaseProduct(mockProductId, mockk()).test {
- assertIs<PurchaseResult.FetchingProducts>(awaitItem())
- assertIs<PurchaseResult.FetchingObfuscationId>(awaitItem())
- val result = awaitItem()
- assertIs<PurchaseResult.Error.TransactionIdError>(result)
- awaitComplete()
+ // Act, Assert
+ paymentRepository.purchaseProduct(mockProductId, mockk()).test {
+ assertIs<PurchaseResult.FetchingProducts>(awaitItem())
+ assertIs<PurchaseResult.FetchingObfuscationId>(awaitItem())
+ val result = awaitItem()
+ assertIs<PurchaseResult.Error.TransactionIdError>(result)
+ awaitComplete()
+ }
}
- }
@Test
- fun testPurchaseBillingProductStartPurchaseFlowBillingError() = runTest {
- // Arrange
- val mockProductId = ProductId("MOCK")
- val mockProductDetailsResult = mockk<ProductDetailsResult>()
- val mockProductDetails: ProductDetails = mockk()
- every { mockProductDetails.productId } returns mockProductId.value
- every { mockProductDetailsResult.billingResult.responseCode } returns BillingResponseCode.OK
- every { mockProductDetailsResult.productDetailsList } returns listOf(mockProductDetails)
- coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns
- mockProductDetailsResult
- val mockBillingResult: BillingResult = mockk()
- every { mockBillingResult.responseCode } returns BillingResponseCode.BILLING_UNAVAILABLE
- every { mockBillingResult.debugMessage } returns "Mock error"
- coEvery {
- mockBillingRepository.startPurchaseFlow(
- productDetails = any(),
- obfuscatedId = any(),
- activityProvider = any()
- )
- } returns mockBillingResult
- coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns
- PlayPurchaseInitResult.Ok("MOCK")
+ fun `purchaseProduct should return BillingError on billing unavailable from startPurchaseFlow`() =
+ runTest {
+ // Arrange
+ val mockProductId = ProductId("MOCK")
+ val mockProductDetailsResult = mockk<ProductDetailsResult>()
+ val mockProductDetails: ProductDetails = mockk()
+ every { mockProductDetails.productId } returns mockProductId.value
+ every { mockProductDetailsResult.billingResult.responseCode } returns
+ BillingResponseCode.OK
+ every { mockProductDetailsResult.productDetailsList } returns listOf(mockProductDetails)
+ coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns
+ mockProductDetailsResult
+ val mockBillingResult: BillingResult = mockk()
+ every { mockBillingResult.responseCode } returns BillingResponseCode.BILLING_UNAVAILABLE
+ every { mockBillingResult.debugMessage } returns "Mock error"
+ coEvery {
+ mockBillingRepository.startPurchaseFlow(
+ productDetails = any(),
+ obfuscatedId = any(),
+ activityProvider = any()
+ )
+ } returns mockBillingResult
+ coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns
+ PlayPurchaseInitResult.Ok("MOCK")
- // Act, Assert
- paymentRepository.purchaseProduct(mockProductId, mockk()).test {
- // Purchase started
- assertIs<PurchaseResult.FetchingProducts>(awaitItem())
- assertIs<PurchaseResult.FetchingObfuscationId>(awaitItem())
- val result = awaitItem()
- assertIs<PurchaseResult.Error.BillingError>(result)
- awaitComplete()
+ // Act, Assert
+ paymentRepository.purchaseProduct(mockProductId, mockk()).test {
+ // Purchase started
+ assertIs<PurchaseResult.FetchingProducts>(awaitItem())
+ assertIs<PurchaseResult.FetchingObfuscationId>(awaitItem())
+ val result = awaitItem()
+ assertIs<PurchaseResult.Error.BillingError>(result)
+ awaitComplete()
+ }
}
- }
@Test
- fun testPurchaseBillingProductPurchaseCanceled() = runTest {
+ fun `cancel during purchaseProduct should return in cancelled event`() = runTest {
// Arrange
val mockProductId = ProductId("MOCK")
val mockProductDetailsResult = mockk<ProductDetailsResult>()
@@ -248,50 +256,52 @@ class BillingPaymentRepositoryTest {
}
@Test
- fun testPurchaseBillingProductVerificationError() = runTest {
- // Arrange
- val mockProductId = ProductId("MOCK")
- val mockProductDetailsResult = mockk<ProductDetailsResult>()
- val mockProductDetails: ProductDetails = mockk()
- every { mockProductDetails.productId } returns mockProductId.value
- every { mockProductDetailsResult.billingResult.responseCode } returns BillingResponseCode.OK
- every { mockProductDetailsResult.productDetailsList } returns listOf(mockProductDetails)
- coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns
- mockProductDetailsResult
- val mockPurchaseToken = "TOKEN"
- val mockBillingPurchase: Purchase = mockk()
- val mockBillingResult: BillingResult = mockk()
- every { mockBillingPurchase.purchaseState } returns Purchase.PurchaseState.PURCHASED
- every { mockBillingResult.responseCode } returns BillingResponseCode.OK
- every { mockBillingPurchase.products } returns listOf(mockProductId.value)
- every { mockBillingPurchase.purchaseToken } returns mockPurchaseToken
- coEvery {
- mockBillingRepository.startPurchaseFlow(
- productDetails = any(),
- obfuscatedId = any(),
- activityProvider = any()
- )
- } returns mockBillingResult
- coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns
- PlayPurchaseInitResult.Ok("MOCK-ID")
- coEvery { mockPlayPurchaseRepository.verifyPlayPurchase(any()) } returns
- PlayPurchaseVerifyResult.Error(PlayPurchaseVerifyError.OtherError)
+ fun `purchaseProduct should emit VerificationError on verify error from playPurchase`() =
+ runTest {
+ // Arrange
+ val mockProductId = ProductId("MOCK")
+ val mockProductDetailsResult = mockk<ProductDetailsResult>()
+ val mockProductDetails: ProductDetails = mockk()
+ every { mockProductDetails.productId } returns mockProductId.value
+ every { mockProductDetailsResult.billingResult.responseCode } returns
+ BillingResponseCode.OK
+ every { mockProductDetailsResult.productDetailsList } returns listOf(mockProductDetails)
+ coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns
+ mockProductDetailsResult
+ val mockPurchaseToken = "TOKEN"
+ val mockBillingPurchase: Purchase = mockk()
+ val mockBillingResult: BillingResult = mockk()
+ every { mockBillingPurchase.purchaseState } returns Purchase.PurchaseState.PURCHASED
+ every { mockBillingResult.responseCode } returns BillingResponseCode.OK
+ every { mockBillingPurchase.products } returns listOf(mockProductId.value)
+ every { mockBillingPurchase.purchaseToken } returns mockPurchaseToken
+ coEvery {
+ mockBillingRepository.startPurchaseFlow(
+ productDetails = any(),
+ obfuscatedId = any(),
+ activityProvider = any()
+ )
+ } returns mockBillingResult
+ coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns
+ PlayPurchaseInitResult.Ok("MOCK-ID")
+ coEvery { mockPlayPurchaseRepository.verifyPlayPurchase(any()) } returns
+ PlayPurchaseVerifyResult.Error(PlayPurchaseVerifyError.OtherError)
- // Act, Assert
- paymentRepository.purchaseProduct(mockProductId, mockk()).test {
- assertIs<PurchaseResult.FetchingProducts>(awaitItem())
- assertIs<PurchaseResult.FetchingObfuscationId>(awaitItem())
- assertIs<PurchaseResult.BillingFlowStarted>(awaitItem())
- purchaseEventFlow.tryEmit(PurchaseEvent.Completed(listOf(mockBillingPurchase)))
- assertIs<PurchaseResult.VerificationStarted>(awaitItem())
- val result = awaitItem()
- assertIs<PurchaseResult.Error.VerificationError>(result)
- awaitComplete()
+ // Act, Assert
+ paymentRepository.purchaseProduct(mockProductId, mockk()).test {
+ assertIs<PurchaseResult.FetchingProducts>(awaitItem())
+ assertIs<PurchaseResult.FetchingObfuscationId>(awaitItem())
+ assertIs<PurchaseResult.BillingFlowStarted>(awaitItem())
+ purchaseEventFlow.tryEmit(PurchaseEvent.Completed(listOf(mockBillingPurchase)))
+ assertIs<PurchaseResult.VerificationStarted>(awaitItem())
+ val result = awaitItem()
+ assertIs<PurchaseResult.Error.VerificationError>(result)
+ awaitComplete()
+ }
}
- }
@Test
- fun testPurchaseBillingProductPurchaseCompleted() = runTest {
+ fun `purchaseProduct success should emit all events leading up to success`() = runTest {
// Arrange
val mockProductId = ProductId("MOCK")
val mockProductDetailsResult = mockk<ProductDetailsResult>()
@@ -334,41 +344,43 @@ class BillingPaymentRepositoryTest {
}
@Test
- fun testPurchaseBillingProductPurchasePending() = runTest {
- // Arrange
- val mockProductId = ProductId("MOCK")
- val mockProductDetailsResult = mockk<ProductDetailsResult>()
- val mockProductDetails: ProductDetails = mockk()
- every { mockProductDetails.productId } returns mockProductId.value
- every { mockProductDetailsResult.billingResult.responseCode } returns BillingResponseCode.OK
- every { mockProductDetailsResult.productDetailsList } returns listOf(mockProductDetails)
- coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns
- mockProductDetailsResult
- val mockBillingPurchase: Purchase = mockk()
- val mockBillingResult: BillingResult = mockk()
- every { mockBillingPurchase.purchaseState } returns Purchase.PurchaseState.PENDING
- every { mockBillingResult.responseCode } returns BillingResponseCode.OK
- coEvery {
- mockBillingRepository.startPurchaseFlow(
- productDetails = any(),
- obfuscatedId = any(),
- activityProvider = any()
- )
- } returns mockBillingResult
- coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns
- PlayPurchaseInitResult.Ok("MOCK")
+ fun `purchaseProduct where purchase gets stuck in pending should complete with pending`() =
+ runTest {
+ // Arrange
+ val mockProductId = ProductId("MOCK")
+ val mockProductDetailsResult = mockk<ProductDetailsResult>()
+ val mockProductDetails: ProductDetails = mockk()
+ every { mockProductDetails.productId } returns mockProductId.value
+ every { mockProductDetailsResult.billingResult.responseCode } returns
+ BillingResponseCode.OK
+ every { mockProductDetailsResult.productDetailsList } returns listOf(mockProductDetails)
+ coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns
+ mockProductDetailsResult
+ val mockBillingPurchase: Purchase = mockk()
+ val mockBillingResult: BillingResult = mockk()
+ every { mockBillingPurchase.purchaseState } returns Purchase.PurchaseState.PENDING
+ every { mockBillingResult.responseCode } returns BillingResponseCode.OK
+ coEvery {
+ mockBillingRepository.startPurchaseFlow(
+ productDetails = any(),
+ obfuscatedId = any(),
+ activityProvider = any()
+ )
+ } returns mockBillingResult
+ coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns
+ PlayPurchaseInitResult.Ok("MOCK")
- // Act, Assert
- paymentRepository.purchaseProduct(mockProductId, mockk()).test {
- assertIs<PurchaseResult.FetchingProducts>(awaitItem())
- assertIs<PurchaseResult.FetchingObfuscationId>(awaitItem())
- assertIs<PurchaseResult.BillingFlowStarted>(awaitItem())
- purchaseEventFlow.tryEmit(PurchaseEvent.Completed(listOf(mockBillingPurchase)))
- val result = awaitItem()
- assertIs<PurchaseResult.Completed.Pending>(result)
- awaitComplete()
+ // Act, Assert
+ paymentRepository.purchaseProduct(mockProductId, mockk()).test {
+ assertIs<PurchaseResult.FetchingProducts>(awaitItem())
+ assertIs<PurchaseResult.FetchingObfuscationId>(awaitItem())
+ assertIs<PurchaseResult.BillingFlowStarted>(awaitItem())
+ purchaseEventFlow.tryEmit(PurchaseEvent.Completed(listOf(mockBillingPurchase)))
+ val result = awaitItem()
+ assertIs<PurchaseResult.Completed.Pending>(result)
+ awaitComplete()
+ }
}
- }
companion object {
private const val PRODUCT_DETAILS_TO_PAYMENT_PRODUCT_EXT =
diff --git a/android/lib/model/src/test/kotlin/net/mullvad/mullvadvpn/model/LatitudeTest.kt b/android/lib/model/src/test/kotlin/net/mullvad/mullvadvpn/model/LatitudeTest.kt
index 8788c2123a..c883f20bfc 100644
--- a/android/lib/model/src/test/kotlin/net/mullvad/mullvadvpn/model/LatitudeTest.kt
+++ b/android/lib/model/src/test/kotlin/net/mullvad/mullvadvpn/model/LatitudeTest.kt
@@ -140,7 +140,7 @@ class LatitudeTest {
}
@Test
- fun `distanceTo with two positive latitudes`() {
+ fun `distanceTo with two positive latitudes should return distance`() {
val latFloat1 = 80f
val latitude1 = Latitude(latFloat1)
val latFloat2 = 30f
@@ -150,7 +150,7 @@ class LatitudeTest {
}
@Test
- fun `distanceTo with two negative latitudes`() {
+ fun `distanceTo with two negative latitudes should return distance`() {
val latFloat1 = -80f
val latitude1 = Latitude(latFloat1)
val latFloat2 = -30f
diff --git a/android/lib/model/src/test/kotlin/net/mullvad/mullvadvpn/model/LongitudeTest.kt b/android/lib/model/src/test/kotlin/net/mullvad/mullvadvpn/model/LongitudeTest.kt
index de94661ad0..69d3445417 100644
--- a/android/lib/model/src/test/kotlin/net/mullvad/mullvadvpn/model/LongitudeTest.kt
+++ b/android/lib/model/src/test/kotlin/net/mullvad/mullvadvpn/model/LongitudeTest.kt
@@ -119,7 +119,7 @@ class LongitudeTest {
}
@Test
- fun `distanceTo with two positive longitudes`() {
+ fun `distanceTo with two positive longitudes should return distance`() {
val longFloat1 = 80f
val longitude1 = Longitude(longFloat1)
val longFloat2 = 30f
@@ -129,7 +129,7 @@ class LongitudeTest {
}
@Test
- fun `distanceTo with two negative longitudes`() {
+ fun `distanceTo with two negative longitudes should return distance`() {
val longFloat1 = -80f
val longitude1 = Longitude(longFloat1)
val longFloat2 = -30f
@@ -141,7 +141,7 @@ class LongitudeTest {
}
@Test
- fun `distanceTo with wrapping value as shortest path`() {
+ fun `distanceTo with wrapping value should return shortest path as distance`() {
val longFloat1 = -170f
val longitude1 = Longitude(longFloat1)
val longFloat2 = 170f
diff --git a/android/lib/payment/src/main/kotlin/net/mullvad/mullvadvpn/lib/payment/model/PaymentAvailability.kt b/android/lib/payment/src/main/kotlin/net/mullvad/mullvadvpn/lib/payment/model/PaymentAvailability.kt
index 012237d825..43caa9d7e2 100644
--- a/android/lib/payment/src/main/kotlin/net/mullvad/mullvadvpn/lib/payment/model/PaymentAvailability.kt
+++ b/android/lib/payment/src/main/kotlin/net/mullvad/mullvadvpn/lib/payment/model/PaymentAvailability.kt
@@ -7,7 +7,7 @@ sealed interface PaymentAvailability {
data object ProductsUnavailable : PaymentAvailability
- data object NoProductsFounds : PaymentAvailability
+ data object NoProductsFound : PaymentAvailability
sealed interface Error : PaymentAvailability {
data object BillingUnavailable : Error