Fix avatar loading in OS views when app is not running.

This commit is contained in:
Cody Henthorne
2024-08-19 14:10:20 -04:00
committed by mtang-signal
parent 8a4d9fc635
commit 71b5a9f865
22 changed files with 384 additions and 439 deletions

View File

@@ -1,42 +0,0 @@
package org.thoughtcrime.securesms
import androidx.test.core.app.ApplicationProvider
import org.junit.rules.TestRule
import org.junit.runner.Description
import org.junit.runners.model.Statement
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.dependencies.MockApplicationDependencyProvider
import org.thoughtcrime.securesms.keyvalue.KeyValueDataSet
import org.thoughtcrime.securesms.keyvalue.KeyValueStore
import org.thoughtcrime.securesms.keyvalue.MockKeyValuePersistentStorage
import org.thoughtcrime.securesms.keyvalue.SignalStore
/**
* Rule to setup [SignalStore] with a mock [KeyValueDataSet]. Must be used with Roboelectric.
*
* Can provide [defaultValues] to set the same values before each test and use [dataSet] directly to add any
* test specific values.
*
* The [dataSet] is reset at the beginning of each test to an empty state.
*/
class SignalStoreRule @JvmOverloads constructor(private val defaultValues: KeyValueDataSet.() -> Unit = {}) : TestRule {
var dataSet = KeyValueDataSet()
private set
override fun apply(base: Statement, description: Description): Statement {
return object : Statement() {
@Throws(Throwable::class)
override fun evaluate() {
if (!AppDependencies.isInitialized) {
AppDependencies.init(ApplicationProvider.getApplicationContext(), MockApplicationDependencyProvider())
}
dataSet = KeyValueDataSet()
SignalStore.testInject(KeyValueStore(MockKeyValuePersistentStorage.withDataSet(dataSet)))
defaultValues.invoke(dataSet)
base.evaluate()
}
}
}
}

View File

@@ -2,50 +2,34 @@ package org.thoughtcrime.securesms.components.emoji
import android.app.Application
import androidx.test.core.app.ApplicationProvider
import io.mockk.every
import io.mockk.mockkObject
import org.junit.Assert
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers
import org.mockito.Mock
import org.mockito.MockedStatic
import org.mockito.Mockito
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
import org.robolectric.ParameterizedRobolectricTestRunner
import org.robolectric.annotation.Config
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.emoji.EmojiSource.Companion.refresh
import org.thoughtcrime.securesms.keyvalue.KeyValueDataSet
import org.thoughtcrime.securesms.keyvalue.KeyValueStore
import org.thoughtcrime.securesms.keyvalue.MockKeyValuePersistentStorage
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.dependencies.MockApplicationDependencyProvider
import org.thoughtcrime.securesms.emoji.EmojiSource
@RunWith(ParameterizedRobolectricTestRunner::class)
@Config(manifest = Config.NONE, application = Application::class)
class EmojiUtilTest_isEmoji(private val input: String?, private val output: Boolean) {
@Rule
@JvmField
val rule: MockitoRule = MockitoJUnit.rule()
@Mock
private val applicationDependenciesMockedStatic: MockedStatic<AppDependencies>? = null
@Mock
private val attachmentSecretProviderMockedStatic: MockedStatic<AttachmentSecretProvider>? = null
@Throws(Exception::class)
@Test
fun isEmoji() {
val application = ApplicationProvider.getApplicationContext<Application>()
if (!AppDependencies.isInitialized) {
AppDependencies.init(ApplicationProvider.getApplicationContext(), MockApplicationDependencyProvider())
}
Mockito.`when`(AppDependencies.application).thenReturn(application)
Mockito.`when`(AttachmentSecretProvider.getInstance(ArgumentMatchers.any())).thenThrow(RuntimeException::class.java)
SignalStore.testInject(KeyValueStore(MockKeyValuePersistentStorage.withDataSet(KeyValueDataSet())))
refresh()
val source = EmojiSource.loadAssetBasedEmojis()
Assert.assertEquals(output, EmojiUtil.isEmoji(input))
mockkObject(EmojiSource) {
every { EmojiSource.latest } returns source
Assert.assertEquals(output, EmojiUtil.isEmoji(input))
}
}
companion object {

View File

@@ -4,6 +4,8 @@ import android.app.Application
import androidx.test.core.app.ApplicationProvider
import io.mockk.every
import io.mockk.mockkObject
import io.mockk.unmockkAll
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -12,12 +14,9 @@ import org.robolectric.annotation.Config
import org.thoughtcrime.securesms.assertIs
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.dependencies.MockApplicationDependencyProvider
import org.thoughtcrime.securesms.keyvalue.AccountValues
import org.thoughtcrime.securesms.keyvalue.KeyValueDataSet
import org.thoughtcrime.securesms.keyvalue.KeyValueStore
import org.thoughtcrime.securesms.keyvalue.MockKeyValuePersistentStorage
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.RemoteConfig
import org.whispersystems.signalservice.api.push.ServiceId
import java.util.UUID
@RunWith(RobolectricTestRunner::class)
@@ -32,15 +31,13 @@ class CrashConfigTest {
AppDependencies.init(ApplicationProvider.getApplicationContext(), MockApplicationDependencyProvider())
}
val store = KeyValueStore(
MockKeyValuePersistentStorage.withDataSet(
KeyValueDataSet().apply {
putString(AccountValues.KEY_ACI, UUID.randomUUID().toString())
}
)
)
mockkObject(SignalStore)
every { SignalStore.account.aci } returns ServiceId.ACI.from(UUID.randomUUID())
}
SignalStore.testInject(store)
@After
fun tearDown() {
unmockkAll()
}
@Test

View File

@@ -6,13 +6,15 @@ import android.app.Application
import androidx.test.core.app.ApplicationProvider
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.slot
import io.mockk.unmockkAll
import io.mockk.verify
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers
import org.hamcrest.Matchers.`is`
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
@@ -28,15 +30,18 @@ import org.signal.storageservice.protos.groups.GroupChangeResponse
import org.signal.storageservice.protos.groups.Member
import org.signal.storageservice.protos.groups.local.DecryptedGroup
import org.signal.storageservice.protos.groups.local.DecryptedMember
import org.thoughtcrime.securesms.SignalStoreRule
import org.thoughtcrime.securesms.TestZkGroupServer
import org.thoughtcrime.securesms.database.GroupStateTestData
import org.thoughtcrime.securesms.database.GroupTable
import org.thoughtcrime.securesms.database.model.databaseprotos.member
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.dependencies.MockApplicationDependencyProvider
import org.thoughtcrime.securesms.groups.v2.GroupCandidateHelper
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.testutil.SystemOutLogger
import org.thoughtcrime.securesms.util.RemoteConfig
import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations
@@ -73,12 +78,17 @@ class GroupManagerV2Test_edit {
private lateinit var manager: GroupManagerV2
@get:Rule
val signalStore: SignalStoreRule = SignalStoreRule()
@Suppress("UsePropertyAccessSyntax")
@Before
fun setUp() {
if (!AppDependencies.isInitialized) {
AppDependencies.init(ApplicationProvider.getApplicationContext(), MockApplicationDependencyProvider())
}
mockkObject(RemoteConfig)
mockkObject(SignalStore)
every { RemoteConfig.internalUser } returns false
ThreadUtil.enforceAssertions = false
Log.initialize(SystemOutLogger())
SignalProtocolLoggerProvider.setProvider(CustomSignalProtocolLogger())
@@ -106,6 +116,11 @@ class GroupManagerV2Test_edit {
)
}
@After
fun tearDown() {
unmockkAll()
}
private fun given(init: GroupStateTestData.() -> Unit) {
val data = GroupStateTestData(masterKey, groupOperations)
data.init()

View File

@@ -2,13 +2,14 @@ package org.thoughtcrime.securesms.groups.v2.processing
import android.annotation.SuppressLint
import android.app.Application
import androidx.test.core.app.ApplicationProvider
import io.mockk.every
import io.mockk.justRun
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.mockkStatic
import io.mockk.spyk
import io.mockk.unmockkObject
import io.mockk.unmockkAll
import io.mockk.unmockkStatic
import io.mockk.verify
import org.hamcrest.MatcherAssert.assertThat
@@ -16,7 +17,6 @@ import org.hamcrest.Matchers.hasItem
import org.hamcrest.Matchers.`is`
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
@@ -32,7 +32,6 @@ import org.signal.storageservice.protos.groups.local.DecryptedGroupChange
import org.signal.storageservice.protos.groups.local.DecryptedMember
import org.signal.storageservice.protos.groups.local.DecryptedString
import org.signal.storageservice.protos.groups.local.DecryptedTimer
import org.thoughtcrime.securesms.SignalStoreRule
import org.thoughtcrime.securesms.database.GroupStateTestData
import org.thoughtcrime.securesms.database.GroupTable
import org.thoughtcrime.securesms.database.RecipientTable
@@ -46,6 +45,7 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.requestingMember
import org.thoughtcrime.securesms.database.setNewDescription
import org.thoughtcrime.securesms.database.setNewTitle
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.dependencies.MockApplicationDependencyProvider
import org.thoughtcrime.securesms.groups.GroupId
import org.thoughtcrime.securesms.groups.GroupNotAMemberException
import org.thoughtcrime.securesms.groups.GroupsV2Authorization
@@ -54,6 +54,7 @@ import org.thoughtcrime.securesms.groups.v2.processing.GroupsV2StateProcessor.Pr
import org.thoughtcrime.securesms.jobmanager.JobManager
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob
import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.testutil.SystemOutLogger
@@ -100,11 +101,15 @@ class GroupsV2StateProcessorTest {
private lateinit var processor: GroupsV2StateProcessor
@get:Rule
val signalStore: SignalStoreRule = SignalStoreRule()
@Before
fun setUp() {
if (!AppDependencies.isInitialized) {
AppDependencies.init(ApplicationProvider.getApplicationContext(), MockApplicationDependencyProvider())
}
mockkObject(SignalStore)
every { SignalStore.internal.gv2IgnoreP2PChanges() } returns false
Log.initialize(SystemOutLogger())
SignalProtocolLoggerProvider.setProvider(CustomSignalProtocolLogger())
@@ -138,11 +143,7 @@ class GroupsV2StateProcessorTest {
@After
fun tearDown() {
unmockkStatic(AppDependencies::class)
unmockkObject(SignalDatabase)
unmockkObject(ProfileAndMessageHelper)
unmockkStatic(DecryptedGroupUtil::class)
unmockkStatic(Recipient::class)
unmockkAll()
}
private fun given(init: GroupStateTestData.() -> Unit) {

View File

@@ -3,7 +3,10 @@ package org.thoughtcrime.securesms.keyvalue
import android.app.Application
import androidx.test.core.app.ApplicationProvider
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.unmockkAll
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
@@ -18,6 +21,8 @@ import org.thoughtcrime.securesms.util.RemoteConfig
@Config(manifest = Config.NONE, application = Application::class)
class PaymentsValuesTest {
private lateinit var paymentValues: PaymentsValues
@Before
fun setup() {
if (!AppDependencies.isInitialized) {
@@ -25,29 +30,32 @@ class PaymentsValuesTest {
}
mockkObject(RemoteConfig)
mockkObject(SignalStore)
paymentValues = mockk()
every { paymentValues.paymentsAvailability } answers { callOriginal() }
every { SignalStore.payments } returns paymentValues
every { SignalStore.account.isRegistered } returns true
}
@After
fun tearDown() {
unmockkAll()
}
@Test
fun `when unregistered, expect NOT_IN_REGION`() {
setupStore(
KeyValueDataSet().apply {
putBoolean(AccountValues.KEY_IS_REGISTERED, false)
}
)
every { SignalStore.account.isRegistered } returns false
assertEquals(PaymentsAvailability.NOT_IN_REGION, SignalStore.payments.paymentsAvailability)
}
@Test
fun `when flag disabled and no account, expect DISABLED_REMOTELY`() {
setupStore(
KeyValueDataSet().apply {
putBoolean(AccountValues.KEY_IS_REGISTERED, true)
putString(AccountValues.KEY_E164, "+15551234567")
putBoolean(PaymentsValues.MOB_PAYMENTS_ENABLED, false)
}
)
every { SignalStore.account.e164 } returns "+15551234567"
every { paymentValues.mobileCoinPaymentsEnabled() } returns false
every { RemoteConfig.payments } returns false
every { RemoteConfig.paymentsCountryBlocklist } returns ""
@@ -56,14 +64,8 @@ class PaymentsValuesTest {
@Test
fun `when flag disabled but has account, expect WITHDRAW_ONLY`() {
setupStore(
KeyValueDataSet().apply {
putBoolean(AccountValues.KEY_IS_REGISTERED, true)
putString(AccountValues.KEY_E164, "+15551234567")
putBoolean(PaymentsValues.MOB_PAYMENTS_ENABLED, true)
}
)
every { SignalStore.account.e164 } returns "+15551234567"
every { paymentValues.mobileCoinPaymentsEnabled() } returns true
every { RemoteConfig.payments } returns false
every { RemoteConfig.paymentsCountryBlocklist } returns ""
@@ -72,14 +74,8 @@ class PaymentsValuesTest {
@Test
fun `when flag enabled and no account, expect REGISTRATION_AVAILABLE`() {
setupStore(
KeyValueDataSet().apply {
putBoolean(AccountValues.KEY_IS_REGISTERED, true)
putString(AccountValues.KEY_E164, "+15551234567")
putBoolean(PaymentsValues.MOB_PAYMENTS_ENABLED, false)
}
)
every { SignalStore.account.e164 } returns "+15551234567"
every { paymentValues.mobileCoinPaymentsEnabled() } returns false
every { RemoteConfig.payments } returns true
every { RemoteConfig.paymentsCountryBlocklist } returns ""
@@ -88,14 +84,8 @@ class PaymentsValuesTest {
@Test
fun `when flag enabled and has account, expect WITHDRAW_AND_SEND`() {
setupStore(
KeyValueDataSet().apply {
putBoolean(AccountValues.KEY_IS_REGISTERED, true)
putString(AccountValues.KEY_E164, "+15551234567")
putBoolean(PaymentsValues.MOB_PAYMENTS_ENABLED, true)
}
)
every { SignalStore.account.e164 } returns "+15551234567"
every { paymentValues.mobileCoinPaymentsEnabled() } returns true
every { RemoteConfig.payments } returns true
every { RemoteConfig.paymentsCountryBlocklist } returns ""
@@ -104,14 +94,8 @@ class PaymentsValuesTest {
@Test
fun `when flag enabled and no account and in the country blocklist, expect NOT_IN_REGION`() {
setupStore(
KeyValueDataSet().apply {
putBoolean(AccountValues.KEY_IS_REGISTERED, true)
putString(AccountValues.KEY_E164, "+15551234567")
putBoolean(PaymentsValues.MOB_PAYMENTS_ENABLED, false)
}
)
every { SignalStore.account.e164 } returns "+15551234567"
every { paymentValues.mobileCoinPaymentsEnabled() } returns false
every { RemoteConfig.payments } returns true
every { RemoteConfig.paymentsCountryBlocklist } returns "1"
@@ -120,31 +104,11 @@ class PaymentsValuesTest {
@Test
fun `when flag enabled and has account and in the country blocklist, expect WITHDRAW_ONLY`() {
setupStore(
KeyValueDataSet().apply {
putBoolean(AccountValues.KEY_IS_REGISTERED, true)
putString(AccountValues.KEY_E164, "+15551234567")
putBoolean(PaymentsValues.MOB_PAYMENTS_ENABLED, true)
}
)
every { SignalStore.account.e164 } returns "+15551234567"
every { paymentValues.mobileCoinPaymentsEnabled() } returns true
every { RemoteConfig.payments } returns true
every { RemoteConfig.paymentsCountryBlocklist } returns "1"
assertEquals(PaymentsAvailability.WITHDRAW_ONLY, SignalStore.payments.paymentsAvailability)
}
/**
* Account values will overwrite some values upon first access, so this takes care of that
*/
private fun setupStore(dataset: KeyValueDataSet) {
val store = KeyValueStore(
MockKeyValuePersistentStorage.withDataSet(
dataset.apply {
putString(AccountValues.KEY_ACI, "")
}
)
)
SignalStore.testInject(store)
}
}

View File

@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.megaphone
import android.app.Application
import android.net.Uri
import androidx.test.core.app.ApplicationProvider
import io.mockk.clearMocks
import io.mockk.every
import io.mockk.mockk
@@ -15,15 +16,15 @@ import org.junit.After
import org.junit.AfterClass
import org.junit.Before
import org.junit.BeforeClass
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import org.thoughtcrime.securesms.SignalStoreRule
import org.thoughtcrime.securesms.database.RemoteMegaphoneTable
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.database.model.RemoteMegaphoneRecord
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.dependencies.MockApplicationDependencyProvider
import org.thoughtcrime.securesms.util.toMillis
import java.time.LocalDateTime
import java.util.UUID
@@ -36,11 +37,11 @@ import java.util.UUID
@Config(manifest = Config.NONE, application = Application::class)
class RemoteMegaphoneRepositoryTest {
@get:Rule
val signalStore: SignalStoreRule = SignalStoreRule()
@Before
fun setUp() {
if (!AppDependencies.isInitialized) {
AppDependencies.init(ApplicationProvider.getApplicationContext(), MockApplicationDependencyProvider())
}
}
@After

View File

@@ -1,16 +1,24 @@
package org.thoughtcrime.securesms.notifications.profiles
import android.app.Application
import androidx.test.core.app.ApplicationProvider
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.unmockkAll
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.`is`
import org.hamcrest.Matchers.nullValue
import org.junit.Rule
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import org.thoughtcrime.securesms.SignalStoreRule
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.dependencies.MockApplicationDependencyProvider
import org.thoughtcrime.securesms.keyvalue.NotificationProfileValues
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.toMillis
import java.time.DayOfWeek
import java.time.LocalDateTime
@@ -43,8 +51,26 @@ class NotificationProfilesTest {
schedule = NotificationProfileSchedule(2)
)
@get:Rule
val signalStore: SignalStoreRule = SignalStoreRule()
private lateinit var notificationProfileValues: NotificationProfileValues
@Before
fun setUp() {
if (!AppDependencies.isInitialized) {
AppDependencies.init(ApplicationProvider.getApplicationContext(), MockApplicationDependencyProvider())
}
notificationProfileValues = mockk()
every { notificationProfileValues.manuallyEnabledUntil } returns 0
every { notificationProfileValues.manuallyDisabledAt } returns 0
mockkObject(SignalStore)
every { SignalStore.notificationProfile } returns notificationProfileValues
}
@After
fun tearDown() {
unmockkAll()
}
@Test
fun `when no profiles then return null`() {
@@ -59,9 +85,9 @@ class NotificationProfilesTest {
@Test
fun `when first is not enabled and second is manually enabled forever then return second`() {
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_PROFILE, second.id)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, Long.MAX_VALUE)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, 5000L)
every { notificationProfileValues.manuallyEnabledProfile } returns second.id
every { notificationProfileValues.manuallyEnabledUntil } returns Long.MAX_VALUE
every { notificationProfileValues.manuallyDisabledAt } returns 5000L
val profiles = listOf(first, second)
assertThat("active profile is profile second", NotificationProfiles.getActiveProfile(profiles, 3000L, utc), `is`(profiles[1]))
@@ -76,9 +102,9 @@ class NotificationProfilesTest {
@Test
fun `when first is scheduled and second is manually enabled forever within first's schedule then return second`() {
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_PROFILE, second.id)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, Long.MAX_VALUE)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC))
every { notificationProfileValues.manuallyEnabledProfile } returns second.id
every { notificationProfileValues.manuallyEnabledUntil } returns Long.MAX_VALUE
every { notificationProfileValues.manuallyDisabledAt } returns sunday830am.toMillis(ZoneOffset.UTC)
val schedule = NotificationProfileSchedule(id = 3L, true, start = 700, daysEnabled = setOf(DayOfWeek.SUNDAY))
val profiles = listOf(first.copy(schedule = schedule), second)
@@ -87,9 +113,9 @@ class NotificationProfilesTest {
@Test
fun `when first is scheduled and second is manually enabled forever before first's schedule start then return first`() {
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_PROFILE, second.id)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, Long.MAX_VALUE)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC))
every { notificationProfileValues.manuallyEnabledProfile } returns second.id
every { notificationProfileValues.manuallyEnabledUntil } returns Long.MAX_VALUE
every { notificationProfileValues.manuallyDisabledAt } returns sunday830am.toMillis(ZoneOffset.UTC)
val schedule = NotificationProfileSchedule(id = 3L, true, start = 900, daysEnabled = setOf(DayOfWeek.SUNDAY))
val profiles = listOf(first.copy(schedule = schedule), second)
@@ -108,9 +134,9 @@ class NotificationProfilesTest {
@Test
fun `when first and second have overlapping schedules and first is created before second and first is manually enabled within overlapping schedule then return first`() {
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_PROFILE, first.id)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, Long.MAX_VALUE)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC))
every { notificationProfileValues.manuallyEnabledProfile } returns first.id
every { notificationProfileValues.manuallyEnabledUntil } returns Long.MAX_VALUE
every { notificationProfileValues.manuallyDisabledAt } returns sunday830am.toMillis(ZoneOffset.UTC)
val firstSchedule = NotificationProfileSchedule(id = 3L, true, start = 700, daysEnabled = setOf(DayOfWeek.SUNDAY))
val secondSchedule = NotificationProfileSchedule(id = 4L, true, start = 700, daysEnabled = setOf(DayOfWeek.SUNDAY))
@@ -121,9 +147,9 @@ class NotificationProfilesTest {
@Test
fun `when profile is manually enabled for set time after schedule end and now is after schedule end but before manual then return profile`() {
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_PROFILE, first.id)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, sunday930am.toMillis(ZoneOffset.UTC))
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC))
every { notificationProfileValues.manuallyEnabledProfile } returns first.id
every { notificationProfileValues.manuallyEnabledUntil } returns sunday930am.toMillis(ZoneOffset.UTC)
every { notificationProfileValues.manuallyDisabledAt } returns sunday830am.toMillis(ZoneOffset.UTC)
val schedule = NotificationProfileSchedule(id = 3L, true, start = 700, end = 845, daysEnabled = setOf(DayOfWeek.SUNDAY))
val profiles = listOf(first.copy(schedule = schedule))
@@ -132,9 +158,9 @@ class NotificationProfilesTest {
@Test
fun `when profile is manually enabled for set time before schedule end and now is after manual but before schedule end then return null`() {
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_PROFILE, first.id)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, sunday9am.toMillis(ZoneOffset.UTC))
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC))
every { notificationProfileValues.manuallyEnabledProfile } returns first.id
every { notificationProfileValues.manuallyEnabledUntil } returns sunday9am.toMillis(ZoneOffset.UTC)
every { notificationProfileValues.manuallyDisabledAt } returns sunday830am.toMillis(ZoneOffset.UTC)
val schedule = NotificationProfileSchedule(id = 3L, true, start = 700, end = 1000, daysEnabled = setOf(DayOfWeek.SUNDAY))
val profiles = listOf(first.copy(schedule = schedule))
@@ -143,9 +169,9 @@ class NotificationProfilesTest {
@Test
fun `when profile is manually enabled yesterday and is scheduled also for today then return profile`() {
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_PROFILE, first.id)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, sunday9am.toMillis(ZoneOffset.UTC))
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC))
every { notificationProfileValues.manuallyEnabledProfile } returns first.id
every { notificationProfileValues.manuallyEnabledUntil } returns sunday9am.toMillis(ZoneOffset.UTC)
every { notificationProfileValues.manuallyDisabledAt } returns sunday830am.toMillis(ZoneOffset.UTC)
val schedule = NotificationProfileSchedule(id = 3L, enabled = true, start = 700, end = 900, daysEnabled = setOf(DayOfWeek.SUNDAY, DayOfWeek.MONDAY))
val profiles = listOf(first.copy(schedule = schedule))
@@ -154,9 +180,9 @@ class NotificationProfilesTest {
@Test
fun `when profile is manually disabled and schedule is on but with start after end and now is before end then return null`() {
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_PROFILE, 0)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, 0)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC))
every { notificationProfileValues.manuallyEnabledProfile } returns 0
every { notificationProfileValues.manuallyEnabledUntil } returns 0
every { notificationProfileValues.manuallyDisabledAt } returns sunday830am.toMillis(ZoneOffset.UTC)
val schedule = NotificationProfileSchedule(id = 3L, enabled = true, start = 2200, end = 1000, daysEnabled = DayOfWeek.values().toSet())
val profiles = listOf(first.copy(schedule = schedule))

View File

@@ -3,6 +3,9 @@ package org.thoughtcrime.securesms.recipients
import android.graphics.Color
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.unmockkAll
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
@@ -26,19 +29,23 @@ class Recipient_getChatColorsTest : BaseRecipientTest() {
@Before
fun setUp() {
wallpaperValues = mockk<WallpaperValues>()
chatColorsValues = mockk<ChatColorsValues>()
wallpaperValues = mockk()
chatColorsValues = mockk()
val globalWallpaper = createWallpaper(globalWallpaperChatColor)
every { wallpaperValues.wallpaper } answers { globalWallpaper }
every { chatColorsValues.chatColors } answers { globalChatColor }
val mockStore = mockk<SignalStore>()
SignalStore.testInject(mockStore)
mockkObject(SignalStore)
every { SignalStore.wallpaper } returns wallpaperValues
every { SignalStore.chatColors } returns chatColorsValues
}
@After
fun tearDown() {
unmockkAll()
}
@Test
fun `Given recipient has custom chat color set, when I getChatColors, then I expect the custom chat color`() {
// GIVEN

View File

@@ -2,35 +2,26 @@ package org.thoughtcrime.securesms.storage
import android.app.Application
import androidx.test.core.app.ApplicationProvider
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.unmockkObject
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.BeforeClass
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockedStatic
import org.mockito.Mockito
import org.mockito.Mockito.mock
import org.mockito.internal.configuration.plugins.Plugins
import org.mockito.internal.junit.JUnitRule
import org.mockito.junit.MockitoRule
import org.mockito.quality.Strictness
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.database.RecipientTable
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.dependencies.MockApplicationDependencyProvider
import org.thoughtcrime.securesms.keyvalue.AccountValues
import org.thoughtcrime.securesms.keyvalue.KeyValueDataSet
import org.thoughtcrime.securesms.keyvalue.KeyValueStore
import org.thoughtcrime.securesms.keyvalue.MockKeyValuePersistentStorage
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.testutil.EmptyLogger
import org.thoughtcrime.securesms.util.RemoteConfig
import org.whispersystems.signalservice.api.push.ServiceId.ACI
import org.whispersystems.signalservice.api.push.ServiceId.PNI
import org.whispersystems.signalservice.api.storage.SignalContactRecord
@@ -42,24 +33,23 @@ import java.util.UUID
@Config(application = Application::class)
class ContactRecordProcessorTest {
@Rule
@JvmField
val mockitoRule: MockitoRule = JUnitRule(Plugins.getMockitoLogger(), Strictness.STRICT_STUBS)
@Mock
lateinit var recipientTable: RecipientTable
@Mock
lateinit var remoteConfig: MockedStatic<RemoteConfig>
@Before
fun setup() {
val mockAccountValues = mock(AccountValues::class.java)
Mockito.lenient().`when`(mockAccountValues.isPrimaryDevice).thenReturn(true)
if (!AppDependencies.isInitialized) {
AppDependencies.init(ApplicationProvider.getApplicationContext(), MockApplicationDependencyProvider())
}
SignalStore.testInject(KeyValueStore(MockKeyValuePersistentStorage.withDataSet(KeyValueDataSet())))
mockkObject(SignalStore)
every { SignalStore.account.isPrimaryDevice } returns true
recipientTable = mockk(relaxed = true)
}
@After
fun tearDown() {
unmockkObject(SignalStore)
}
@Test

View File

@@ -1,60 +0,0 @@
package org.thoughtcrime.securesms.util;
import android.app.Application;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.ParameterizedRobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.thoughtcrime.securesms.SignalStoreRule;
import org.thoughtcrime.securesms.dependencies.AppDependencies;
import org.thoughtcrime.securesms.keyvalue.AccountValues;
import java.util.Arrays;
import java.util.Collection;
import kotlin.Unit;
import static junit.framework.TestCase.assertEquals;
@RunWith(ParameterizedRobolectricTestRunner.class)
@Config(manifest = Config.NONE, application = Application.class)
public class SignalMeUtilText_parseE164FromLink {
private final String input;
private final String output;
@ParameterizedRobolectricTestRunner.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{ "https://signal.me/#p/+15555555555", "+15555555555" },
{ "https://signal.me/#p/5555555555", null },
{ "https://signal.me", null },
{ "https://signal.me/#p/", null },
{ "signal.me/#p/+15555555555", null },
{ "sgnl://signal.me/#p/+15555555555", "+15555555555" },
{ "sgnl://signal.me/#p/5555555555", null },
{ "sgnl://signal.me", null },
{ "sgnl://signal.me/#p/", null },
{ "", null },
{ null, null }
});
}
@Rule
public SignalStoreRule signalStore = new SignalStoreRule(dataSet -> {
dataSet.putString(AccountValues.KEY_E164, "+15555555555");
return Unit.INSTANCE;
});
public SignalMeUtilText_parseE164FromLink(String input, String output) {
this.input = input;
this.output = output;
}
@Test
public void parse() {
assertEquals(output, SignalMeUtil.parseE164FromLink(AppDependencies.getApplication(), input));
}
}

View File

@@ -0,0 +1,64 @@
package org.thoughtcrime.securesms.util
import android.app.Application
import androidx.test.core.app.ApplicationProvider
import io.mockk.every
import io.mockk.mockkObject
import io.mockk.unmockkAll
import junit.framework.TestCase
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.ParameterizedRobolectricTestRunner
import org.robolectric.annotation.Config
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.dependencies.AppDependencies.application
import org.thoughtcrime.securesms.dependencies.MockApplicationDependencyProvider
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.SignalMeUtil.parseE164FromLink
@RunWith(ParameterizedRobolectricTestRunner::class)
@Config(manifest = Config.NONE, application = Application::class)
class SignalMeUtilText_parseE164FromLink(private val input: String?, private val output: String?) {
@Before
fun setUp() {
if (!AppDependencies.isInitialized) {
AppDependencies.init(ApplicationProvider.getApplicationContext(), MockApplicationDependencyProvider())
}
mockkObject(SignalStore)
every { SignalStore.account.e164 } returns "+15555555555"
}
@After
fun tearDown() {
unmockkAll()
}
@Test
fun parse() {
TestCase.assertEquals(output, parseE164FromLink(application, input))
}
companion object {
@JvmStatic
@ParameterizedRobolectricTestRunner.Parameters
fun data(): Collection<Array<Any?>> {
return listOf(
arrayOf("https://signal.me/#p/+15555555555", "+15555555555"),
arrayOf("https://signal.me/#p/5555555555", null),
arrayOf("https://signal.me", null),
arrayOf("https://signal.me/#p/", null),
arrayOf("signal.me/#p/+15555555555", null),
arrayOf("sgnl://signal.me/#p/+15555555555", "+15555555555"),
arrayOf("sgnl://signal.me/#p/5555555555", null),
arrayOf("sgnl://signal.me", null),
arrayOf("sgnl://signal.me/#p/", null),
arrayOf("", null),
arrayOf(null, null)
)
}
}
}