mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-22 12:08:34 +00:00
Fix avatar loading in OS views when app is not running.
This commit is contained in:
committed by
mtang-signal
parent
8a4d9fc635
commit
71b5a9f865
@@ -153,6 +153,7 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
|
|||||||
DatabaseSecretProvider.getOrCreateDatabaseSecret(this),
|
DatabaseSecretProvider.getOrCreateDatabaseSecret(this),
|
||||||
AttachmentSecretProvider.getInstance(this).getOrCreateAttachmentSecret());
|
AttachmentSecretProvider.getInstance(this).getOrCreateAttachmentSecret());
|
||||||
})
|
})
|
||||||
|
.addBlocking("signal-store", () -> SignalStore.init(this))
|
||||||
.addBlocking("logging", () -> {
|
.addBlocking("logging", () -> {
|
||||||
initializeLogging();
|
initializeLogging();
|
||||||
Log.i(TAG, "onCreate()");
|
Log.i(TAG, "onCreate()");
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ object BackupRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val db = KeyValueDatabase.createWithName(context, "$baseName.db")
|
val db = KeyValueDatabase.createWithName(context, "$baseName.db")
|
||||||
SignalStore(KeyValueStore(db))
|
SignalStore(context, KeyValueStore(db))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.thoughtcrime.securesms.emoji
|
package org.thoughtcrime.securesms.emoji
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
import androidx.annotation.WorkerThread
|
import androidx.annotation.WorkerThread
|
||||||
import org.thoughtcrime.securesms.components.emoji.Emoji
|
import org.thoughtcrime.securesms.components.emoji.Emoji
|
||||||
import org.thoughtcrime.securesms.components.emoji.EmojiPageModel
|
import org.thoughtcrime.securesms.components.emoji.EmojiPageModel
|
||||||
@@ -122,7 +123,8 @@ class EmojiSource(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadAssetBasedEmojis(): EmojiSource {
|
@VisibleForTesting
|
||||||
|
fun loadAssetBasedEmojis(): EmojiSource {
|
||||||
val emojiData: InputStream = AppDependencies.application.assets.open("emoji/emoji_data.json")
|
val emojiData: InputStream = AppDependencies.application.assets.open("emoji/emoji_data.json")
|
||||||
|
|
||||||
emojiData.use {
|
emojiData.use {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import android.annotation.SuppressLint
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.preference.PreferenceManager
|
import android.preference.PreferenceManager
|
||||||
import androidx.annotation.VisibleForTesting
|
|
||||||
import org.signal.core.util.Base64
|
import org.signal.core.util.Base64
|
||||||
import org.signal.core.util.logging.Log
|
import org.signal.core.util.logging.Log
|
||||||
import org.signal.libsignal.protocol.IdentityKey
|
import org.signal.libsignal.protocol.IdentityKey
|
||||||
@@ -73,17 +72,10 @@ class AccountValues internal constructor(store: KeyValueStore) : SignalStoreValu
|
|||||||
private const val KEY_USERNAME_SYNC_STATE = "phoneNumberPrivacy.usernameSyncState"
|
private const val KEY_USERNAME_SYNC_STATE = "phoneNumberPrivacy.usernameSyncState"
|
||||||
private const val KEY_USERNAME_SYNC_ERROR_COUNT = "phoneNumberPrivacy.usernameErrorCount"
|
private const val KEY_USERNAME_SYNC_ERROR_COUNT = "phoneNumberPrivacy.usernameErrorCount"
|
||||||
|
|
||||||
@VisibleForTesting
|
private const val KEY_E164 = "account.e164"
|
||||||
const val KEY_E164 = "account.e164"
|
private const val KEY_ACI = "account.aci"
|
||||||
|
private const val KEY_PNI = "account.pni"
|
||||||
@VisibleForTesting
|
private const val KEY_IS_REGISTERED = "account.is_registered"
|
||||||
const val KEY_ACI = "account.aci"
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
const val KEY_PNI = "account.pni"
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
const val KEY_IS_REGISTERED = "account.is_registered"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package org.thoughtcrime.securesms.keyvalue
|
package org.thoughtcrime.securesms.keyvalue
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Values for managing enable/disable state and corresponding alerts for Notification Profiles.
|
* Values for managing enable/disable state and corresponding alerts for Notification Profiles.
|
||||||
*/
|
*/
|
||||||
@@ -12,14 +10,9 @@ class NotificationProfileValues(store: KeyValueStore) : SignalStoreValues(store)
|
|||||||
private const val KEY_LAST_PROFILE_POPUP_TIME = "np.last_profile_popup_time"
|
private const val KEY_LAST_PROFILE_POPUP_TIME = "np.last_profile_popup_time"
|
||||||
private const val KEY_SEEN_TOOLTIP = "np.seen_tooltip"
|
private const val KEY_SEEN_TOOLTIP = "np.seen_tooltip"
|
||||||
|
|
||||||
@VisibleForTesting
|
private const val KEY_MANUALLY_ENABLED_PROFILE = "np.manually_enabled_profile"
|
||||||
const val KEY_MANUALLY_ENABLED_PROFILE = "np.manually_enabled_profile"
|
private const val KEY_MANUALLY_ENABLED_UNTIL = "np.manually_enabled_until"
|
||||||
|
private const val KEY_MANUALLY_DISABLED_AT = "np.manually_disabled_at"
|
||||||
@VisibleForTesting
|
|
||||||
const val KEY_MANUALLY_ENABLED_UNTIL = "np.manually_enabled_until"
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
const val KEY_MANUALLY_DISABLED_AT = "np.manually_disabled_at"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override fun onFirstEverAppLaunch() = Unit
|
public override fun onFirstEverAppLaunch() = Unit
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.thoughtcrime.securesms.keyvalue
|
package org.thoughtcrime.securesms.keyvalue
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting
|
|
||||||
import androidx.annotation.WorkerThread
|
import androidx.annotation.WorkerThread
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
@@ -33,6 +32,7 @@ class PaymentsValues internal constructor(store: KeyValueStore) : SignalStoreVal
|
|||||||
companion object {
|
companion object {
|
||||||
private val TAG = Log.tag(PaymentsValues::class.java)
|
private val TAG = Log.tag(PaymentsValues::class.java)
|
||||||
|
|
||||||
|
private const val MOB_PAYMENTS_ENABLED = "mob_payments_enabled"
|
||||||
private const val PAYMENTS_ENTROPY = "payments_entropy"
|
private const val PAYMENTS_ENTROPY = "payments_entropy"
|
||||||
private const val MOB_LEDGER = "mob_ledger"
|
private const val MOB_LEDGER = "mob_ledger"
|
||||||
private const val PAYMENTS_CURRENT_CURRENCY = "payments_current_currency"
|
private const val PAYMENTS_CURRENT_CURRENCY = "payments_current_currency"
|
||||||
@@ -50,9 +50,6 @@ class PaymentsValues internal constructor(store: KeyValueStore) : SignalStoreVal
|
|||||||
private const val SHOW_SAVE_RECOVERY_PHRASE = "mob_show_save_recovery_phrase"
|
private const val SHOW_SAVE_RECOVERY_PHRASE = "mob_show_save_recovery_phrase"
|
||||||
|
|
||||||
private val LARGE_BALANCE_THRESHOLD = Money.mobileCoin(BigDecimal.valueOf(500))
|
private val LARGE_BALANCE_THRESHOLD = Money.mobileCoin(BigDecimal.valueOf(500))
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
const val MOB_PAYMENTS_ENABLED = "mob_payments_enabled"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@get:JvmName("isPaymentLockEnabled")
|
@get:JvmName("isPaymentLockEnabled")
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
package org.thoughtcrime.securesms.keyvalue
|
package org.thoughtcrime.securesms.keyvalue
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import androidx.preference.PreferenceDataStore
|
import androidx.preference.PreferenceDataStore
|
||||||
import org.signal.core.util.ResettableLazy
|
|
||||||
import org.thoughtcrime.securesms.database.KeyValueDatabase
|
import org.thoughtcrime.securesms.database.KeyValueDatabase
|
||||||
import org.thoughtcrime.securesms.dependencies.AppDependencies.application
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple, encrypted key-value store.
|
* Simple, encrypted key-value store.
|
||||||
*/
|
*/
|
||||||
class SignalStore(private val store: KeyValueStore) {
|
class SignalStore(context: Application, private val store: KeyValueStore) {
|
||||||
|
|
||||||
val accountValues = AccountValues(store)
|
val accountValues = AccountValues(store)
|
||||||
val svrValues = SvrValues(store)
|
val svrValues = SvrValues(store)
|
||||||
@@ -39,15 +38,22 @@ class SignalStore(private val store: KeyValueStore) {
|
|||||||
val apkUpdateValues = ApkUpdateValues(store)
|
val apkUpdateValues = ApkUpdateValues(store)
|
||||||
val backupValues = BackupValues(store)
|
val backupValues = BackupValues(store)
|
||||||
|
|
||||||
val plainTextValues = PlainTextSharedPrefsDataStore(application)
|
val plainTextValues = PlainTextSharedPrefsDataStore(context)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private var instanceOverride: SignalStore? = null
|
private var instance: SignalStore? = null
|
||||||
private val _instance = ResettableLazy {
|
|
||||||
instanceOverride ?: SignalStore(KeyValueStore(KeyValueDatabase.getInstance(application)))
|
@JvmStatic
|
||||||
|
fun init(context: Application) {
|
||||||
|
if (instance == null) {
|
||||||
|
synchronized(SignalStore::class.java) {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = SignalStore(context, KeyValueStore(KeyValueDatabase.getInstance(context)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private val instance by _instance
|
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun onFirstEverAppLaunch() {
|
fun onFirstEverAppLaunch() {
|
||||||
@@ -114,7 +120,7 @@ class SignalStore(private val store: KeyValueStore) {
|
|||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
fun resetCache() {
|
fun resetCache() {
|
||||||
instance.store.resetCache()
|
instance!!.store.resetCache()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -122,144 +128,144 @@ class SignalStore(private val store: KeyValueStore) {
|
|||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun onPostBackupRestore() {
|
fun onPostBackupRestore() {
|
||||||
instance.store.resetCache()
|
instance!!.store.resetCache()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("account")
|
@get:JvmName("account")
|
||||||
val account: AccountValues
|
val account: AccountValues
|
||||||
get() = instance.accountValues
|
get() = instance!!.accountValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("svr")
|
@get:JvmName("svr")
|
||||||
val svr: SvrValues
|
val svr: SvrValues
|
||||||
get() = instance.svrValues
|
get() = instance!!.svrValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("registration")
|
@get:JvmName("registration")
|
||||||
val registration: RegistrationValues
|
val registration: RegistrationValues
|
||||||
get() = instance.registrationValues
|
get() = instance!!.registrationValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("pin")
|
@get:JvmName("pin")
|
||||||
val pin: PinValues
|
val pin: PinValues
|
||||||
get() = instance.pinValues
|
get() = instance!!.pinValues
|
||||||
|
|
||||||
val remoteConfig: RemoteConfigValues
|
val remoteConfig: RemoteConfigValues
|
||||||
get() = instance.remoteConfigValues
|
get() = instance!!.remoteConfigValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("storageService")
|
@get:JvmName("storageService")
|
||||||
val storageService: StorageServiceValues
|
val storageService: StorageServiceValues
|
||||||
get() = instance.storageServiceValues
|
get() = instance!!.storageServiceValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("uiHints")
|
@get:JvmName("uiHints")
|
||||||
val uiHints: UiHintValues
|
val uiHints: UiHintValues
|
||||||
get() = instance.uiHintValues
|
get() = instance!!.uiHintValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("tooltips")
|
@get:JvmName("tooltips")
|
||||||
val tooltips: TooltipValues
|
val tooltips: TooltipValues
|
||||||
get() = instance.tooltipValues
|
get() = instance!!.tooltipValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("misc")
|
@get:JvmName("misc")
|
||||||
val misc: MiscellaneousValues
|
val misc: MiscellaneousValues
|
||||||
get() = instance.miscValues
|
get() = instance!!.miscValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("internal")
|
@get:JvmName("internal")
|
||||||
val internal: InternalValues
|
val internal: InternalValues
|
||||||
get() = instance.internalValues
|
get() = instance!!.internalValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("emoji")
|
@get:JvmName("emoji")
|
||||||
val emoji: EmojiValues
|
val emoji: EmojiValues
|
||||||
get() = instance.emojiValues
|
get() = instance!!.emojiValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("settings")
|
@get:JvmName("settings")
|
||||||
val settings: SettingsValues
|
val settings: SettingsValues
|
||||||
get() = instance.settingsValues
|
get() = instance!!.settingsValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("certificate")
|
@get:JvmName("certificate")
|
||||||
val certificate: CertificateValues
|
val certificate: CertificateValues
|
||||||
get() = instance.certificateValues
|
get() = instance!!.certificateValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("phoneNumberPrivacy")
|
@get:JvmName("phoneNumberPrivacy")
|
||||||
val phoneNumberPrivacy: PhoneNumberPrivacyValues
|
val phoneNumberPrivacy: PhoneNumberPrivacyValues
|
||||||
get() = instance.phoneNumberPrivacyValues
|
get() = instance!!.phoneNumberPrivacyValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("onboarding")
|
@get:JvmName("onboarding")
|
||||||
val onboarding: OnboardingValues
|
val onboarding: OnboardingValues
|
||||||
get() = instance.onboardingValues
|
get() = instance!!.onboardingValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("wallpaper")
|
@get:JvmName("wallpaper")
|
||||||
val wallpaper: WallpaperValues
|
val wallpaper: WallpaperValues
|
||||||
get() = instance.wallpaperValues
|
get() = instance!!.wallpaperValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("payments")
|
@get:JvmName("payments")
|
||||||
val payments: PaymentsValues
|
val payments: PaymentsValues
|
||||||
get() = instance.paymentsValues
|
get() = instance!!.paymentsValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("inAppPayments")
|
@get:JvmName("inAppPayments")
|
||||||
val inAppPayments: InAppPaymentValues
|
val inAppPayments: InAppPaymentValues
|
||||||
get() = instance.inAppPaymentValues
|
get() = instance!!.inAppPaymentValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("proxy")
|
@get:JvmName("proxy")
|
||||||
val proxy: ProxyValues
|
val proxy: ProxyValues
|
||||||
get() = instance.proxyValues
|
get() = instance!!.proxyValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("rateLimit")
|
@get:JvmName("rateLimit")
|
||||||
val rateLimit: RateLimitValues
|
val rateLimit: RateLimitValues
|
||||||
get() = instance.rateLimitValues
|
get() = instance!!.rateLimitValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("chatColors")
|
@get:JvmName("chatColors")
|
||||||
val chatColors: ChatColorsValues
|
val chatColors: ChatColorsValues
|
||||||
get() = instance.chatColorsValues
|
get() = instance!!.chatColorsValues
|
||||||
|
|
||||||
val imageEditor: ImageEditorValues
|
val imageEditor: ImageEditorValues
|
||||||
get() = instance.imageEditorValues
|
get() = instance!!.imageEditorValues
|
||||||
|
|
||||||
val notificationProfile: NotificationProfileValues
|
val notificationProfile: NotificationProfileValues
|
||||||
get() = instance.notificationProfileValues
|
get() = instance!!.notificationProfileValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("releaseChannel")
|
@get:JvmName("releaseChannel")
|
||||||
val releaseChannel: ReleaseChannelValues
|
val releaseChannel: ReleaseChannelValues
|
||||||
get() = instance.releaseChannelValues
|
get() = instance!!.releaseChannelValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("story")
|
@get:JvmName("story")
|
||||||
val story: StoryValues
|
val story: StoryValues
|
||||||
get() = instance.storyValues
|
get() = instance!!.storyValues
|
||||||
|
|
||||||
val apkUpdate: ApkUpdateValues
|
val apkUpdate: ApkUpdateValues
|
||||||
get() = instance.apkUpdateValues
|
get() = instance!!.apkUpdateValues
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@get:JvmName("backup")
|
@get:JvmName("backup")
|
||||||
val backup: BackupValues
|
val backup: BackupValues
|
||||||
get() = instance.backupValues
|
get() = instance!!.backupValues
|
||||||
|
|
||||||
val groupsV2AciAuthorizationCache: GroupsV2AuthorizationSignalStoreCache
|
val groupsV2AciAuthorizationCache: GroupsV2AuthorizationSignalStoreCache
|
||||||
get() = GroupsV2AuthorizationSignalStoreCache.createAciCache(instance.store)
|
get() = GroupsV2AuthorizationSignalStoreCache.createAciCache(instance!!.store)
|
||||||
|
|
||||||
val plaintext: PlainTextSharedPrefsDataStore
|
val plaintext: PlainTextSharedPrefsDataStore
|
||||||
get() = instance.plainTextValues
|
get() = instance!!.plainTextValues
|
||||||
|
|
||||||
fun getPreferenceDataStore(): PreferenceDataStore {
|
fun getPreferenceDataStore(): PreferenceDataStore {
|
||||||
return SignalPreferenceDataStore(instance.store)
|
return SignalPreferenceDataStore(instance!!.store)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -268,25 +274,7 @@ class SignalStore(private val store: KeyValueStore) {
|
|||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun blockUntilAllWritesFinished() {
|
fun blockUntilAllWritesFinished() {
|
||||||
instance.store.blockUntilAllWritesFinished()
|
instance!!.store.blockUntilAllWritesFinished()
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows you to set a custom KeyValueStore to read from. Only for testing!
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
fun testInject(store: KeyValueStore) {
|
|
||||||
instanceOverride = SignalStore(store)
|
|
||||||
_instance.reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows you to set a custom SignalStore to read from. Only for testing!
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
fun testInject(store: SignalStore) {
|
|
||||||
instanceOverride = store
|
|
||||||
_instance.reset()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.thoughtcrime.securesms.providers
|
package org.thoughtcrime.securesms.providers
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
import android.content.ContentUris
|
import android.content.ContentUris
|
||||||
import android.content.ContentValues
|
import android.content.ContentValues
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
@@ -15,10 +16,16 @@ import android.net.Uri
|
|||||||
import android.os.ParcelFileDescriptor
|
import android.os.ParcelFileDescriptor
|
||||||
import org.signal.core.util.concurrent.SignalExecutors
|
import org.signal.core.util.concurrent.SignalExecutors
|
||||||
import org.signal.core.util.logging.Log
|
import org.signal.core.util.logging.Log
|
||||||
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
import org.thoughtcrime.securesms.BuildConfig
|
import org.thoughtcrime.securesms.BuildConfig
|
||||||
|
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider
|
||||||
|
import org.thoughtcrime.securesms.crypto.DatabaseSecretProvider
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||||
|
import org.thoughtcrime.securesms.database.SqlCipherLibraryLoader
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.profiles.AvatarHelper
|
import org.thoughtcrime.securesms.profiles.AvatarHelper
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
|
import org.thoughtcrime.securesms.recipients.RecipientCreator
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||||
import org.thoughtcrime.securesms.service.KeyCachingService
|
import org.thoughtcrime.securesms.service.KeyCachingService
|
||||||
import org.thoughtcrime.securesms.util.AdaptiveBitmapMetrics
|
import org.thoughtcrime.securesms.util.AdaptiveBitmapMetrics
|
||||||
@@ -54,6 +61,21 @@ class AvatarProvider : BaseContentProvider() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun init(): Application? {
|
||||||
|
val application = context as? ApplicationContext ?: return null
|
||||||
|
|
||||||
|
SqlCipherLibraryLoader.load()
|
||||||
|
SignalDatabase.init(
|
||||||
|
application,
|
||||||
|
DatabaseSecretProvider.getOrCreateDatabaseSecret(application),
|
||||||
|
AttachmentSecretProvider.getInstance(application).getOrCreateAttachmentSecret()
|
||||||
|
)
|
||||||
|
|
||||||
|
SignalStore.init(application)
|
||||||
|
|
||||||
|
return application
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(): Boolean {
|
override fun onCreate(): Boolean {
|
||||||
if (VERBOSE) Log.i(TAG, "onCreate called")
|
if (VERBOSE) Log.i(TAG, "onCreate called")
|
||||||
return true
|
return true
|
||||||
@@ -63,7 +85,9 @@ class AvatarProvider : BaseContentProvider() {
|
|||||||
override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? {
|
override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? {
|
||||||
if (VERBOSE) Log.i(TAG, "openFile() called!")
|
if (VERBOSE) Log.i(TAG, "openFile() called!")
|
||||||
|
|
||||||
if (KeyCachingService.isLocked(context)) {
|
val application = init() ?: return null
|
||||||
|
|
||||||
|
if (KeyCachingService.isLocked(application)) {
|
||||||
Log.w(TAG, "masterSecret was null, abandoning.")
|
Log.w(TAG, "masterSecret was null, abandoning.")
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -76,7 +100,7 @@ class AvatarProvider : BaseContentProvider() {
|
|||||||
if (uriMatcher.match(uri) == AVATAR) {
|
if (uriMatcher.match(uri) == AVATAR) {
|
||||||
if (VERBOSE) Log.i(TAG, "Loading avatar.")
|
if (VERBOSE) Log.i(TAG, "Loading avatar.")
|
||||||
try {
|
try {
|
||||||
val recipient = getRecipientId(uri)?.let { Recipient.resolved(it) } ?: return null
|
val recipient = getRecipientId(uri)?.let { RecipientCreator.forRecord(application, SignalDatabase.recipients.getRecord(it)) } ?: return null
|
||||||
return getParcelFileDescriptorForAvatar(recipient)
|
return getParcelFileDescriptorForAvatar(recipient)
|
||||||
} catch (ioe: IOException) {
|
} catch (ioe: IOException) {
|
||||||
Log.w(TAG, ioe)
|
Log.w(TAG, ioe)
|
||||||
@@ -91,6 +115,8 @@ class AvatarProvider : BaseContentProvider() {
|
|||||||
override fun query(uri: Uri, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String?): Cursor? {
|
override fun query(uri: Uri, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String?): Cursor? {
|
||||||
if (VERBOSE) Log.i(TAG, "query() called: $uri")
|
if (VERBOSE) Log.i(TAG, "query() called: $uri")
|
||||||
|
|
||||||
|
val application = init() ?: return null
|
||||||
|
|
||||||
if (SignalDatabase.instance == null) {
|
if (SignalDatabase.instance == null) {
|
||||||
Log.w(TAG, "SignalDatabase unavailable")
|
Log.w(TAG, "SignalDatabase unavailable")
|
||||||
return null
|
return null
|
||||||
@@ -99,8 +125,8 @@ class AvatarProvider : BaseContentProvider() {
|
|||||||
if (uriMatcher.match(uri) == AVATAR) {
|
if (uriMatcher.match(uri) == AVATAR) {
|
||||||
val recipientId = getRecipientId(uri) ?: return null
|
val recipientId = getRecipientId(uri) ?: return null
|
||||||
|
|
||||||
if (AvatarHelper.hasAvatar(context!!, recipientId)) {
|
if (AvatarHelper.hasAvatar(application, recipientId)) {
|
||||||
val file: File = AvatarHelper.getAvatarFile(context!!, recipientId)
|
val file: File = AvatarHelper.getAvatarFile(application, recipientId)
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
return createCursor(projection, file.name, file.length())
|
return createCursor(projection, file.name, file.length())
|
||||||
}
|
}
|
||||||
@@ -115,6 +141,8 @@ class AvatarProvider : BaseContentProvider() {
|
|||||||
override fun getType(uri: Uri): String? {
|
override fun getType(uri: Uri): String? {
|
||||||
if (VERBOSE) Log.i(TAG, "getType() called: $uri")
|
if (VERBOSE) Log.i(TAG, "getType() called: $uri")
|
||||||
|
|
||||||
|
init() ?: return null
|
||||||
|
|
||||||
if (SignalDatabase.instance == null) {
|
if (SignalDatabase.instance == null) {
|
||||||
Log.w(TAG, "SignalDatabase unavailable")
|
Log.w(TAG, "SignalDatabase unavailable")
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -9,24 +9,15 @@ import androidx.lifecycle.LiveData;
|
|||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
import androidx.lifecycle.Observer;
|
import androidx.lifecycle.Observer;
|
||||||
|
|
||||||
import com.annimon.stream.Stream;
|
|
||||||
|
|
||||||
import org.signal.core.util.ThreadUtil;
|
import org.signal.core.util.ThreadUtil;
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.conversation.colors.AvatarColor;
|
|
||||||
import org.thoughtcrime.securesms.database.CallLinkTable;
|
|
||||||
import org.thoughtcrime.securesms.database.DistributionListTables;
|
import org.thoughtcrime.securesms.database.DistributionListTables;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
|
||||||
import org.thoughtcrime.securesms.database.RecipientTable;
|
import org.thoughtcrime.securesms.database.RecipientTable;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
import org.thoughtcrime.securesms.database.model.DistributionListRecord;
|
|
||||||
import org.thoughtcrime.securesms.database.model.RecipientRecord;
|
|
||||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
@@ -198,62 +189,11 @@ public final class LiveRecipient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private @NonNull Recipient fetchAndCacheRecipientFromDisk(@NonNull RecipientId id) {
|
private @NonNull Recipient fetchAndCacheRecipientFromDisk(@NonNull RecipientId id) {
|
||||||
RecipientRecord record = recipientTable.getRecord(id);
|
Recipient recipient = RecipientCreator.forRecord(context, recipientTable.getRecord(id));
|
||||||
|
|
||||||
Recipient recipient;
|
|
||||||
if (record.getGroupId() != null) {
|
|
||||||
recipient = getGroupRecipientDetails(record);
|
|
||||||
} else if (record.getDistributionListId() != null) {
|
|
||||||
recipient = getDistributionListRecipientDetails(record);
|
|
||||||
} else if (record.getCallLinkRoomId() != null) {
|
|
||||||
recipient = getCallLinkRecipientDetails(record);
|
|
||||||
} else {
|
|
||||||
recipient = RecipientCreator.forIndividual(context, record);
|
|
||||||
}
|
|
||||||
|
|
||||||
RecipientIdCache.INSTANCE.put(recipient);
|
RecipientIdCache.INSTANCE.put(recipient);
|
||||||
return recipient;
|
return recipient;
|
||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
|
||||||
private @NonNull Recipient getGroupRecipientDetails(@NonNull RecipientRecord record) {
|
|
||||||
Optional<GroupRecord> groupRecord = groupDatabase.getGroup(record.getId());
|
|
||||||
|
|
||||||
if (groupRecord.isPresent()) {
|
|
||||||
return RecipientCreator.forGroup(groupRecord.get(), record);
|
|
||||||
} else {
|
|
||||||
return RecipientCreator.forUnknownGroup(record.getId(), record.getGroupId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@WorkerThread
|
|
||||||
private @NonNull Recipient getDistributionListRecipientDetails(@NonNull RecipientRecord record) {
|
|
||||||
DistributionListRecord groupRecord = distributionListTables.getList(Objects.requireNonNull(record.getDistributionListId()));
|
|
||||||
|
|
||||||
// TODO [stories] We'll have to see what the perf is like for very large distribution lists. We may not be able to support fetching all the members.
|
|
||||||
if (groupRecord != null) {
|
|
||||||
String title = groupRecord.isUnknown() ? null : groupRecord.getName();
|
|
||||||
List<RecipientId> members = Stream.of(groupRecord.getMembers()).filterNot(RecipientId::isUnknown).toList();
|
|
||||||
|
|
||||||
return RecipientCreator.forDistributionList(title, members, record);
|
|
||||||
}
|
|
||||||
|
|
||||||
return RecipientCreator.forDistributionList(null, null, record);
|
|
||||||
}
|
|
||||||
|
|
||||||
@WorkerThread
|
|
||||||
private @NonNull Recipient getCallLinkRecipientDetails(@NonNull RecipientRecord record) {
|
|
||||||
CallLinkTable.CallLink callLink = SignalDatabase.callLinks().getCallLinkByRoomId(Objects.requireNonNull(record.getCallLinkRoomId()));
|
|
||||||
|
|
||||||
if (callLink != null) {
|
|
||||||
String name = callLink.getState().getName();
|
|
||||||
|
|
||||||
return RecipientCreator.forCallLink(name, record, callLink.getAvatarColor());
|
|
||||||
}
|
|
||||||
|
|
||||||
return RecipientCreator.forCallLink(null, record, AvatarColor.UNKNOWN);
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized void set(@NonNull Recipient recipient) {
|
synchronized void set(@NonNull Recipient recipient) {
|
||||||
this.recipient.set(recipient);
|
this.recipient.set(recipient);
|
||||||
this.liveData.postValue(recipient);
|
this.liveData.postValue(recipient);
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ package org.thoughtcrime.securesms.recipients
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
|
import androidx.annotation.WorkerThread
|
||||||
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
|
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
|
||||||
import org.thoughtcrime.securesms.database.RecipientTable.RegisteredState
|
import org.thoughtcrime.securesms.database.RecipientTable.RegisteredState
|
||||||
|
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||||
import org.thoughtcrime.securesms.database.model.GroupRecord
|
import org.thoughtcrime.securesms.database.model.GroupRecord
|
||||||
import org.thoughtcrime.securesms.database.model.RecipientRecord
|
import org.thoughtcrime.securesms.database.model.RecipientRecord
|
||||||
import org.thoughtcrime.securesms.groups.GroupId
|
import org.thoughtcrime.securesms.groups.GroupId
|
||||||
@@ -101,6 +103,22 @@ object RecipientCreator {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@WorkerThread
|
||||||
|
fun forRecord(context: Context, record: RecipientRecord): Recipient {
|
||||||
|
val recipient = if (record.groupId != null) {
|
||||||
|
getGroupRecipientDetails(record)
|
||||||
|
} else if (record.distributionListId != null) {
|
||||||
|
getDistributionListRecipientDetails(record)
|
||||||
|
} else if (record.callLinkRoomId != null) {
|
||||||
|
getCallLinkRecipientDetails(record)
|
||||||
|
} else {
|
||||||
|
forIndividual(context, record)
|
||||||
|
}
|
||||||
|
|
||||||
|
return recipient
|
||||||
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun forUnknown(): Recipient {
|
fun forUnknown(): Recipient {
|
||||||
return Recipient.UNKNOWN
|
return Recipient.UNKNOWN
|
||||||
@@ -186,4 +204,43 @@ object RecipientCreator {
|
|||||||
note = record.note
|
note = record.note
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
private fun getGroupRecipientDetails(record: RecipientRecord): Recipient {
|
||||||
|
val groupRecord = SignalDatabase.groups.getGroup(record.id)
|
||||||
|
|
||||||
|
return if (groupRecord.isPresent) {
|
||||||
|
forGroup(groupRecord.get(), record)
|
||||||
|
} else {
|
||||||
|
forUnknownGroup(record.id, record.groupId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
private fun getDistributionListRecipientDetails(record: RecipientRecord): Recipient {
|
||||||
|
val groupRecord = SignalDatabase.distributionLists.getList(record.distributionListId!!)
|
||||||
|
|
||||||
|
// TODO [stories] We'll have to see what the perf is like for very large distribution lists. We may not be able to support fetching all the members.
|
||||||
|
if (groupRecord != null) {
|
||||||
|
val title = if (groupRecord.isUnknown) null else groupRecord.name
|
||||||
|
val members = groupRecord.members.filterNot { it.isUnknown }
|
||||||
|
|
||||||
|
return forDistributionList(title, members, record)
|
||||||
|
}
|
||||||
|
|
||||||
|
return forDistributionList(null, null, record)
|
||||||
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
private fun getCallLinkRecipientDetails(record: RecipientRecord): Recipient {
|
||||||
|
val callLink = SignalDatabase.callLinks.getCallLinkByRoomId(record.callLinkRoomId!!)
|
||||||
|
|
||||||
|
if (callLink != null) {
|
||||||
|
val name = callLink.state.name
|
||||||
|
|
||||||
|
return forCallLink(name, record, callLink.avatarColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
return forCallLink(null, record, AvatarColor.UNKNOWN)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,50 +2,34 @@ package org.thoughtcrime.securesms.components.emoji
|
|||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.mockkObject
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
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.ParameterizedRobolectricTestRunner
|
||||||
import org.robolectric.annotation.Config
|
import org.robolectric.annotation.Config
|
||||||
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider
|
|
||||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||||
import org.thoughtcrime.securesms.emoji.EmojiSource.Companion.refresh
|
import org.thoughtcrime.securesms.dependencies.MockApplicationDependencyProvider
|
||||||
import org.thoughtcrime.securesms.keyvalue.KeyValueDataSet
|
import org.thoughtcrime.securesms.emoji.EmojiSource
|
||||||
import org.thoughtcrime.securesms.keyvalue.KeyValueStore
|
|
||||||
import org.thoughtcrime.securesms.keyvalue.MockKeyValuePersistentStorage
|
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
|
||||||
|
|
||||||
@RunWith(ParameterizedRobolectricTestRunner::class)
|
@RunWith(ParameterizedRobolectricTestRunner::class)
|
||||||
@Config(manifest = Config.NONE, application = Application::class)
|
@Config(manifest = Config.NONE, application = Application::class)
|
||||||
class EmojiUtilTest_isEmoji(private val input: String?, private val output: Boolean) {
|
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)
|
@Throws(Exception::class)
|
||||||
@Test
|
@Test
|
||||||
fun isEmoji() {
|
fun isEmoji() {
|
||||||
val application = ApplicationProvider.getApplicationContext<Application>()
|
if (!AppDependencies.isInitialized) {
|
||||||
|
AppDependencies.init(ApplicationProvider.getApplicationContext(), MockApplicationDependencyProvider())
|
||||||
|
}
|
||||||
|
|
||||||
Mockito.`when`(AppDependencies.application).thenReturn(application)
|
val source = EmojiSource.loadAssetBasedEmojis()
|
||||||
Mockito.`when`(AttachmentSecretProvider.getInstance(ArgumentMatchers.any())).thenThrow(RuntimeException::class.java)
|
|
||||||
SignalStore.testInject(KeyValueStore(MockKeyValuePersistentStorage.withDataSet(KeyValueDataSet())))
|
|
||||||
refresh()
|
|
||||||
|
|
||||||
Assert.assertEquals(output, EmojiUtil.isEmoji(input))
|
mockkObject(EmojiSource) {
|
||||||
|
every { EmojiSource.latest } returns source
|
||||||
|
Assert.assertEquals(output, EmojiUtil.isEmoji(input))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import android.app.Application
|
|||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockkObject
|
import io.mockk.mockkObject
|
||||||
|
import io.mockk.unmockkAll
|
||||||
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
@@ -12,12 +14,9 @@ import org.robolectric.annotation.Config
|
|||||||
import org.thoughtcrime.securesms.assertIs
|
import org.thoughtcrime.securesms.assertIs
|
||||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||||
import org.thoughtcrime.securesms.dependencies.MockApplicationDependencyProvider
|
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.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.util.RemoteConfig
|
import org.thoughtcrime.securesms.util.RemoteConfig
|
||||||
|
import org.whispersystems.signalservice.api.push.ServiceId
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
@RunWith(RobolectricTestRunner::class)
|
||||||
@@ -32,15 +31,13 @@ class CrashConfigTest {
|
|||||||
AppDependencies.init(ApplicationProvider.getApplicationContext(), MockApplicationDependencyProvider())
|
AppDependencies.init(ApplicationProvider.getApplicationContext(), MockApplicationDependencyProvider())
|
||||||
}
|
}
|
||||||
|
|
||||||
val store = KeyValueStore(
|
mockkObject(SignalStore)
|
||||||
MockKeyValuePersistentStorage.withDataSet(
|
every { SignalStore.account.aci } returns ServiceId.ACI.from(UUID.randomUUID())
|
||||||
KeyValueDataSet().apply {
|
}
|
||||||
putString(AccountValues.KEY_ACI, UUID.randomUUID().toString())
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
SignalStore.testInject(store)
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
unmockkAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -6,13 +6,15 @@ import android.app.Application
|
|||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
|
import io.mockk.mockkObject
|
||||||
import io.mockk.slot
|
import io.mockk.slot
|
||||||
|
import io.mockk.unmockkAll
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
import org.hamcrest.MatcherAssert.assertThat
|
import org.hamcrest.MatcherAssert.assertThat
|
||||||
import org.hamcrest.Matchers
|
import org.hamcrest.Matchers
|
||||||
import org.hamcrest.Matchers.`is`
|
import org.hamcrest.Matchers.`is`
|
||||||
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.robolectric.RobolectricTestRunner
|
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.Member
|
||||||
import org.signal.storageservice.protos.groups.local.DecryptedGroup
|
import org.signal.storageservice.protos.groups.local.DecryptedGroup
|
||||||
import org.signal.storageservice.protos.groups.local.DecryptedMember
|
import org.signal.storageservice.protos.groups.local.DecryptedMember
|
||||||
import org.thoughtcrime.securesms.SignalStoreRule
|
|
||||||
import org.thoughtcrime.securesms.TestZkGroupServer
|
import org.thoughtcrime.securesms.TestZkGroupServer
|
||||||
import org.thoughtcrime.securesms.database.GroupStateTestData
|
import org.thoughtcrime.securesms.database.GroupStateTestData
|
||||||
import org.thoughtcrime.securesms.database.GroupTable
|
import org.thoughtcrime.securesms.database.GroupTable
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.member
|
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.groups.v2.GroupCandidateHelper
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger
|
import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
import org.thoughtcrime.securesms.testutil.SystemOutLogger
|
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.ClientZkOperations
|
||||||
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api
|
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api
|
||||||
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations
|
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations
|
||||||
@@ -73,12 +78,17 @@ class GroupManagerV2Test_edit {
|
|||||||
|
|
||||||
private lateinit var manager: GroupManagerV2
|
private lateinit var manager: GroupManagerV2
|
||||||
|
|
||||||
@get:Rule
|
|
||||||
val signalStore: SignalStoreRule = SignalStoreRule()
|
|
||||||
|
|
||||||
@Suppress("UsePropertyAccessSyntax")
|
@Suppress("UsePropertyAccessSyntax")
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
|
if (!AppDependencies.isInitialized) {
|
||||||
|
AppDependencies.init(ApplicationProvider.getApplicationContext(), MockApplicationDependencyProvider())
|
||||||
|
}
|
||||||
|
|
||||||
|
mockkObject(RemoteConfig)
|
||||||
|
mockkObject(SignalStore)
|
||||||
|
every { RemoteConfig.internalUser } returns false
|
||||||
|
|
||||||
ThreadUtil.enforceAssertions = false
|
ThreadUtil.enforceAssertions = false
|
||||||
Log.initialize(SystemOutLogger())
|
Log.initialize(SystemOutLogger())
|
||||||
SignalProtocolLoggerProvider.setProvider(CustomSignalProtocolLogger())
|
SignalProtocolLoggerProvider.setProvider(CustomSignalProtocolLogger())
|
||||||
@@ -106,6 +116,11 @@ class GroupManagerV2Test_edit {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
unmockkAll()
|
||||||
|
}
|
||||||
|
|
||||||
private fun given(init: GroupStateTestData.() -> Unit) {
|
private fun given(init: GroupStateTestData.() -> Unit) {
|
||||||
val data = GroupStateTestData(masterKey, groupOperations)
|
val data = GroupStateTestData(masterKey, groupOperations)
|
||||||
data.init()
|
data.init()
|
||||||
|
|||||||
@@ -2,13 +2,14 @@ package org.thoughtcrime.securesms.groups.v2.processing
|
|||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.justRun
|
import io.mockk.justRun
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import io.mockk.mockkObject
|
import io.mockk.mockkObject
|
||||||
import io.mockk.mockkStatic
|
import io.mockk.mockkStatic
|
||||||
import io.mockk.spyk
|
import io.mockk.spyk
|
||||||
import io.mockk.unmockkObject
|
import io.mockk.unmockkAll
|
||||||
import io.mockk.unmockkStatic
|
import io.mockk.unmockkStatic
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
import org.hamcrest.MatcherAssert.assertThat
|
import org.hamcrest.MatcherAssert.assertThat
|
||||||
@@ -16,7 +17,6 @@ import org.hamcrest.Matchers.hasItem
|
|||||||
import org.hamcrest.Matchers.`is`
|
import org.hamcrest.Matchers.`is`
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.robolectric.RobolectricTestRunner
|
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.DecryptedMember
|
||||||
import org.signal.storageservice.protos.groups.local.DecryptedString
|
import org.signal.storageservice.protos.groups.local.DecryptedString
|
||||||
import org.signal.storageservice.protos.groups.local.DecryptedTimer
|
import org.signal.storageservice.protos.groups.local.DecryptedTimer
|
||||||
import org.thoughtcrime.securesms.SignalStoreRule
|
|
||||||
import org.thoughtcrime.securesms.database.GroupStateTestData
|
import org.thoughtcrime.securesms.database.GroupStateTestData
|
||||||
import org.thoughtcrime.securesms.database.GroupTable
|
import org.thoughtcrime.securesms.database.GroupTable
|
||||||
import org.thoughtcrime.securesms.database.RecipientTable
|
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.setNewDescription
|
||||||
import org.thoughtcrime.securesms.database.setNewTitle
|
import org.thoughtcrime.securesms.database.setNewTitle
|
||||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||||
|
import org.thoughtcrime.securesms.dependencies.MockApplicationDependencyProvider
|
||||||
import org.thoughtcrime.securesms.groups.GroupId
|
import org.thoughtcrime.securesms.groups.GroupId
|
||||||
import org.thoughtcrime.securesms.groups.GroupNotAMemberException
|
import org.thoughtcrime.securesms.groups.GroupNotAMemberException
|
||||||
import org.thoughtcrime.securesms.groups.GroupsV2Authorization
|
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.jobmanager.JobManager
|
||||||
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob
|
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob
|
||||||
import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob
|
import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger
|
import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
import org.thoughtcrime.securesms.testutil.SystemOutLogger
|
import org.thoughtcrime.securesms.testutil.SystemOutLogger
|
||||||
@@ -100,11 +101,15 @@ class GroupsV2StateProcessorTest {
|
|||||||
|
|
||||||
private lateinit var processor: GroupsV2StateProcessor
|
private lateinit var processor: GroupsV2StateProcessor
|
||||||
|
|
||||||
@get:Rule
|
|
||||||
val signalStore: SignalStoreRule = SignalStoreRule()
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
|
if (!AppDependencies.isInitialized) {
|
||||||
|
AppDependencies.init(ApplicationProvider.getApplicationContext(), MockApplicationDependencyProvider())
|
||||||
|
}
|
||||||
|
|
||||||
|
mockkObject(SignalStore)
|
||||||
|
every { SignalStore.internal.gv2IgnoreP2PChanges() } returns false
|
||||||
|
|
||||||
Log.initialize(SystemOutLogger())
|
Log.initialize(SystemOutLogger())
|
||||||
SignalProtocolLoggerProvider.setProvider(CustomSignalProtocolLogger())
|
SignalProtocolLoggerProvider.setProvider(CustomSignalProtocolLogger())
|
||||||
|
|
||||||
@@ -138,11 +143,7 @@ class GroupsV2StateProcessorTest {
|
|||||||
|
|
||||||
@After
|
@After
|
||||||
fun tearDown() {
|
fun tearDown() {
|
||||||
unmockkStatic(AppDependencies::class)
|
unmockkAll()
|
||||||
unmockkObject(SignalDatabase)
|
|
||||||
unmockkObject(ProfileAndMessageHelper)
|
|
||||||
unmockkStatic(DecryptedGroupUtil::class)
|
|
||||||
unmockkStatic(Recipient::class)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun given(init: GroupStateTestData.() -> Unit) {
|
private fun given(init: GroupStateTestData.() -> Unit) {
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ package org.thoughtcrime.securesms.keyvalue
|
|||||||
import android.app.Application
|
import android.app.Application
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
|
import io.mockk.mockk
|
||||||
import io.mockk.mockkObject
|
import io.mockk.mockkObject
|
||||||
|
import io.mockk.unmockkAll
|
||||||
|
import org.junit.After
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -18,6 +21,8 @@ import org.thoughtcrime.securesms.util.RemoteConfig
|
|||||||
@Config(manifest = Config.NONE, application = Application::class)
|
@Config(manifest = Config.NONE, application = Application::class)
|
||||||
class PaymentsValuesTest {
|
class PaymentsValuesTest {
|
||||||
|
|
||||||
|
private lateinit var paymentValues: PaymentsValues
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
if (!AppDependencies.isInitialized) {
|
if (!AppDependencies.isInitialized) {
|
||||||
@@ -25,29 +30,32 @@ class PaymentsValuesTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mockkObject(RemoteConfig)
|
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
|
@Test
|
||||||
fun `when unregistered, expect NOT_IN_REGION`() {
|
fun `when unregistered, expect NOT_IN_REGION`() {
|
||||||
setupStore(
|
every { SignalStore.account.isRegistered } returns false
|
||||||
KeyValueDataSet().apply {
|
|
||||||
putBoolean(AccountValues.KEY_IS_REGISTERED, false)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
assertEquals(PaymentsAvailability.NOT_IN_REGION, SignalStore.payments.paymentsAvailability)
|
assertEquals(PaymentsAvailability.NOT_IN_REGION, SignalStore.payments.paymentsAvailability)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when flag disabled and no account, expect DISABLED_REMOTELY`() {
|
fun `when flag disabled and no account, expect DISABLED_REMOTELY`() {
|
||||||
setupStore(
|
every { SignalStore.account.e164 } returns "+15551234567"
|
||||||
KeyValueDataSet().apply {
|
every { paymentValues.mobileCoinPaymentsEnabled() } returns false
|
||||||
putBoolean(AccountValues.KEY_IS_REGISTERED, true)
|
|
||||||
putString(AccountValues.KEY_E164, "+15551234567")
|
|
||||||
putBoolean(PaymentsValues.MOB_PAYMENTS_ENABLED, false)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
every { RemoteConfig.payments } returns false
|
every { RemoteConfig.payments } returns false
|
||||||
every { RemoteConfig.paymentsCountryBlocklist } returns ""
|
every { RemoteConfig.paymentsCountryBlocklist } returns ""
|
||||||
|
|
||||||
@@ -56,14 +64,8 @@ class PaymentsValuesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when flag disabled but has account, expect WITHDRAW_ONLY`() {
|
fun `when flag disabled but has account, expect WITHDRAW_ONLY`() {
|
||||||
setupStore(
|
every { SignalStore.account.e164 } returns "+15551234567"
|
||||||
KeyValueDataSet().apply {
|
every { paymentValues.mobileCoinPaymentsEnabled() } returns true
|
||||||
putBoolean(AccountValues.KEY_IS_REGISTERED, true)
|
|
||||||
putString(AccountValues.KEY_E164, "+15551234567")
|
|
||||||
putBoolean(PaymentsValues.MOB_PAYMENTS_ENABLED, true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
every { RemoteConfig.payments } returns false
|
every { RemoteConfig.payments } returns false
|
||||||
every { RemoteConfig.paymentsCountryBlocklist } returns ""
|
every { RemoteConfig.paymentsCountryBlocklist } returns ""
|
||||||
|
|
||||||
@@ -72,14 +74,8 @@ class PaymentsValuesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when flag enabled and no account, expect REGISTRATION_AVAILABLE`() {
|
fun `when flag enabled and no account, expect REGISTRATION_AVAILABLE`() {
|
||||||
setupStore(
|
every { SignalStore.account.e164 } returns "+15551234567"
|
||||||
KeyValueDataSet().apply {
|
every { paymentValues.mobileCoinPaymentsEnabled() } returns false
|
||||||
putBoolean(AccountValues.KEY_IS_REGISTERED, true)
|
|
||||||
putString(AccountValues.KEY_E164, "+15551234567")
|
|
||||||
putBoolean(PaymentsValues.MOB_PAYMENTS_ENABLED, false)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
every { RemoteConfig.payments } returns true
|
every { RemoteConfig.payments } returns true
|
||||||
every { RemoteConfig.paymentsCountryBlocklist } returns ""
|
every { RemoteConfig.paymentsCountryBlocklist } returns ""
|
||||||
|
|
||||||
@@ -88,14 +84,8 @@ class PaymentsValuesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when flag enabled and has account, expect WITHDRAW_AND_SEND`() {
|
fun `when flag enabled and has account, expect WITHDRAW_AND_SEND`() {
|
||||||
setupStore(
|
every { SignalStore.account.e164 } returns "+15551234567"
|
||||||
KeyValueDataSet().apply {
|
every { paymentValues.mobileCoinPaymentsEnabled() } returns true
|
||||||
putBoolean(AccountValues.KEY_IS_REGISTERED, true)
|
|
||||||
putString(AccountValues.KEY_E164, "+15551234567")
|
|
||||||
putBoolean(PaymentsValues.MOB_PAYMENTS_ENABLED, true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
every { RemoteConfig.payments } returns true
|
every { RemoteConfig.payments } returns true
|
||||||
every { RemoteConfig.paymentsCountryBlocklist } returns ""
|
every { RemoteConfig.paymentsCountryBlocklist } returns ""
|
||||||
|
|
||||||
@@ -104,14 +94,8 @@ class PaymentsValuesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when flag enabled and no account and in the country blocklist, expect NOT_IN_REGION`() {
|
fun `when flag enabled and no account and in the country blocklist, expect NOT_IN_REGION`() {
|
||||||
setupStore(
|
every { SignalStore.account.e164 } returns "+15551234567"
|
||||||
KeyValueDataSet().apply {
|
every { paymentValues.mobileCoinPaymentsEnabled() } returns false
|
||||||
putBoolean(AccountValues.KEY_IS_REGISTERED, true)
|
|
||||||
putString(AccountValues.KEY_E164, "+15551234567")
|
|
||||||
putBoolean(PaymentsValues.MOB_PAYMENTS_ENABLED, false)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
every { RemoteConfig.payments } returns true
|
every { RemoteConfig.payments } returns true
|
||||||
every { RemoteConfig.paymentsCountryBlocklist } returns "1"
|
every { RemoteConfig.paymentsCountryBlocklist } returns "1"
|
||||||
|
|
||||||
@@ -120,31 +104,11 @@ class PaymentsValuesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when flag enabled and has account and in the country blocklist, expect WITHDRAW_ONLY`() {
|
fun `when flag enabled and has account and in the country blocklist, expect WITHDRAW_ONLY`() {
|
||||||
setupStore(
|
every { SignalStore.account.e164 } returns "+15551234567"
|
||||||
KeyValueDataSet().apply {
|
every { paymentValues.mobileCoinPaymentsEnabled() } returns true
|
||||||
putBoolean(AccountValues.KEY_IS_REGISTERED, true)
|
|
||||||
putString(AccountValues.KEY_E164, "+15551234567")
|
|
||||||
putBoolean(PaymentsValues.MOB_PAYMENTS_ENABLED, true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
every { RemoteConfig.payments } returns true
|
every { RemoteConfig.payments } returns true
|
||||||
every { RemoteConfig.paymentsCountryBlocklist } returns "1"
|
every { RemoteConfig.paymentsCountryBlocklist } returns "1"
|
||||||
|
|
||||||
assertEquals(PaymentsAvailability.WITHDRAW_ONLY, SignalStore.payments.paymentsAvailability)
|
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.megaphone
|
|||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import io.mockk.clearMocks
|
import io.mockk.clearMocks
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
@@ -15,15 +16,15 @@ import org.junit.After
|
|||||||
import org.junit.AfterClass
|
import org.junit.AfterClass
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.BeforeClass
|
import org.junit.BeforeClass
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.robolectric.RobolectricTestRunner
|
import org.robolectric.RobolectricTestRunner
|
||||||
import org.robolectric.annotation.Config
|
import org.robolectric.annotation.Config
|
||||||
import org.thoughtcrime.securesms.SignalStoreRule
|
|
||||||
import org.thoughtcrime.securesms.database.RemoteMegaphoneTable
|
import org.thoughtcrime.securesms.database.RemoteMegaphoneTable
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||||
import org.thoughtcrime.securesms.database.model.RemoteMegaphoneRecord
|
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 org.thoughtcrime.securesms.util.toMillis
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
@@ -36,11 +37,11 @@ import java.util.UUID
|
|||||||
@Config(manifest = Config.NONE, application = Application::class)
|
@Config(manifest = Config.NONE, application = Application::class)
|
||||||
class RemoteMegaphoneRepositoryTest {
|
class RemoteMegaphoneRepositoryTest {
|
||||||
|
|
||||||
@get:Rule
|
|
||||||
val signalStore: SignalStoreRule = SignalStoreRule()
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
|
if (!AppDependencies.isInitialized) {
|
||||||
|
AppDependencies.init(ApplicationProvider.getApplicationContext(), MockApplicationDependencyProvider())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|||||||
@@ -1,16 +1,24 @@
|
|||||||
package org.thoughtcrime.securesms.notifications.profiles
|
package org.thoughtcrime.securesms.notifications.profiles
|
||||||
|
|
||||||
import android.app.Application
|
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.MatcherAssert.assertThat
|
||||||
import org.hamcrest.Matchers.`is`
|
import org.hamcrest.Matchers.`is`
|
||||||
import org.hamcrest.Matchers.nullValue
|
import org.hamcrest.Matchers.nullValue
|
||||||
import org.junit.Rule
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.robolectric.RobolectricTestRunner
|
import org.robolectric.RobolectricTestRunner
|
||||||
import org.robolectric.annotation.Config
|
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.NotificationProfileValues
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.util.toMillis
|
import org.thoughtcrime.securesms.util.toMillis
|
||||||
import java.time.DayOfWeek
|
import java.time.DayOfWeek
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
@@ -43,8 +51,26 @@ class NotificationProfilesTest {
|
|||||||
schedule = NotificationProfileSchedule(2)
|
schedule = NotificationProfileSchedule(2)
|
||||||
)
|
)
|
||||||
|
|
||||||
@get:Rule
|
private lateinit var notificationProfileValues: NotificationProfileValues
|
||||||
val signalStore: SignalStoreRule = SignalStoreRule()
|
|
||||||
|
@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
|
@Test
|
||||||
fun `when no profiles then return null`() {
|
fun `when no profiles then return null`() {
|
||||||
@@ -59,9 +85,9 @@ class NotificationProfilesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when first is not enabled and second is manually enabled forever then return second`() {
|
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)
|
every { notificationProfileValues.manuallyEnabledProfile } returns second.id
|
||||||
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, Long.MAX_VALUE)
|
every { notificationProfileValues.manuallyEnabledUntil } returns Long.MAX_VALUE
|
||||||
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, 5000L)
|
every { notificationProfileValues.manuallyDisabledAt } returns 5000L
|
||||||
|
|
||||||
val profiles = listOf(first, second)
|
val profiles = listOf(first, second)
|
||||||
assertThat("active profile is profile second", NotificationProfiles.getActiveProfile(profiles, 3000L, utc), `is`(profiles[1]))
|
assertThat("active profile is profile second", NotificationProfiles.getActiveProfile(profiles, 3000L, utc), `is`(profiles[1]))
|
||||||
@@ -76,9 +102,9 @@ class NotificationProfilesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when first is scheduled and second is manually enabled forever within first's schedule then return second`() {
|
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)
|
every { notificationProfileValues.manuallyEnabledProfile } returns second.id
|
||||||
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, Long.MAX_VALUE)
|
every { notificationProfileValues.manuallyEnabledUntil } returns Long.MAX_VALUE
|
||||||
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC))
|
every { notificationProfileValues.manuallyDisabledAt } returns sunday830am.toMillis(ZoneOffset.UTC)
|
||||||
|
|
||||||
val schedule = NotificationProfileSchedule(id = 3L, true, start = 700, daysEnabled = setOf(DayOfWeek.SUNDAY))
|
val schedule = NotificationProfileSchedule(id = 3L, true, start = 700, daysEnabled = setOf(DayOfWeek.SUNDAY))
|
||||||
val profiles = listOf(first.copy(schedule = schedule), second)
|
val profiles = listOf(first.copy(schedule = schedule), second)
|
||||||
@@ -87,9 +113,9 @@ class NotificationProfilesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when first is scheduled and second is manually enabled forever before first's schedule start then return first`() {
|
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)
|
every { notificationProfileValues.manuallyEnabledProfile } returns second.id
|
||||||
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, Long.MAX_VALUE)
|
every { notificationProfileValues.manuallyEnabledUntil } returns Long.MAX_VALUE
|
||||||
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC))
|
every { notificationProfileValues.manuallyDisabledAt } returns sunday830am.toMillis(ZoneOffset.UTC)
|
||||||
|
|
||||||
val schedule = NotificationProfileSchedule(id = 3L, true, start = 900, daysEnabled = setOf(DayOfWeek.SUNDAY))
|
val schedule = NotificationProfileSchedule(id = 3L, true, start = 900, daysEnabled = setOf(DayOfWeek.SUNDAY))
|
||||||
val profiles = listOf(first.copy(schedule = schedule), second)
|
val profiles = listOf(first.copy(schedule = schedule), second)
|
||||||
@@ -108,9 +134,9 @@ class NotificationProfilesTest {
|
|||||||
|
|
||||||
@Test
|
@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`() {
|
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)
|
every { notificationProfileValues.manuallyEnabledProfile } returns first.id
|
||||||
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, Long.MAX_VALUE)
|
every { notificationProfileValues.manuallyEnabledUntil } returns Long.MAX_VALUE
|
||||||
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC))
|
every { notificationProfileValues.manuallyDisabledAt } returns sunday830am.toMillis(ZoneOffset.UTC)
|
||||||
|
|
||||||
val firstSchedule = NotificationProfileSchedule(id = 3L, true, start = 700, daysEnabled = setOf(DayOfWeek.SUNDAY))
|
val firstSchedule = NotificationProfileSchedule(id = 3L, true, start = 700, daysEnabled = setOf(DayOfWeek.SUNDAY))
|
||||||
val secondSchedule = NotificationProfileSchedule(id = 4L, 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
|
@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`() {
|
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)
|
every { notificationProfileValues.manuallyEnabledProfile } returns first.id
|
||||||
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, sunday930am.toMillis(ZoneOffset.UTC))
|
every { notificationProfileValues.manuallyEnabledUntil } returns sunday930am.toMillis(ZoneOffset.UTC)
|
||||||
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.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 schedule = NotificationProfileSchedule(id = 3L, true, start = 700, end = 845, daysEnabled = setOf(DayOfWeek.SUNDAY))
|
||||||
val profiles = listOf(first.copy(schedule = schedule))
|
val profiles = listOf(first.copy(schedule = schedule))
|
||||||
@@ -132,9 +158,9 @@ class NotificationProfilesTest {
|
|||||||
|
|
||||||
@Test
|
@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`() {
|
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)
|
every { notificationProfileValues.manuallyEnabledProfile } returns first.id
|
||||||
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, sunday9am.toMillis(ZoneOffset.UTC))
|
every { notificationProfileValues.manuallyEnabledUntil } returns sunday9am.toMillis(ZoneOffset.UTC)
|
||||||
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.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 schedule = NotificationProfileSchedule(id = 3L, true, start = 700, end = 1000, daysEnabled = setOf(DayOfWeek.SUNDAY))
|
||||||
val profiles = listOf(first.copy(schedule = schedule))
|
val profiles = listOf(first.copy(schedule = schedule))
|
||||||
@@ -143,9 +169,9 @@ class NotificationProfilesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when profile is manually enabled yesterday and is scheduled also for today then return profile`() {
|
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)
|
every { notificationProfileValues.manuallyEnabledProfile } returns first.id
|
||||||
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, sunday9am.toMillis(ZoneOffset.UTC))
|
every { notificationProfileValues.manuallyEnabledUntil } returns sunday9am.toMillis(ZoneOffset.UTC)
|
||||||
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.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 schedule = NotificationProfileSchedule(id = 3L, enabled = true, start = 700, end = 900, daysEnabled = setOf(DayOfWeek.SUNDAY, DayOfWeek.MONDAY))
|
||||||
val profiles = listOf(first.copy(schedule = schedule))
|
val profiles = listOf(first.copy(schedule = schedule))
|
||||||
@@ -154,9 +180,9 @@ class NotificationProfilesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when profile is manually disabled and schedule is on but with start after end and now is before end then return null`() {
|
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)
|
every { notificationProfileValues.manuallyEnabledProfile } returns 0
|
||||||
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, 0)
|
every { notificationProfileValues.manuallyEnabledUntil } returns 0
|
||||||
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC))
|
every { notificationProfileValues.manuallyDisabledAt } returns sunday830am.toMillis(ZoneOffset.UTC)
|
||||||
|
|
||||||
val schedule = NotificationProfileSchedule(id = 3L, enabled = true, start = 2200, end = 1000, daysEnabled = DayOfWeek.values().toSet())
|
val schedule = NotificationProfileSchedule(id = 3L, enabled = true, start = 2200, end = 1000, daysEnabled = DayOfWeek.values().toSet())
|
||||||
val profiles = listOf(first.copy(schedule = schedule))
|
val profiles = listOf(first.copy(schedule = schedule))
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ package org.thoughtcrime.securesms.recipients
|
|||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
|
import io.mockk.mockkObject
|
||||||
|
import io.mockk.unmockkAll
|
||||||
|
import org.junit.After
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -26,19 +29,23 @@ class Recipient_getChatColorsTest : BaseRecipientTest() {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
wallpaperValues = mockk<WallpaperValues>()
|
wallpaperValues = mockk()
|
||||||
chatColorsValues = mockk<ChatColorsValues>()
|
chatColorsValues = mockk()
|
||||||
|
|
||||||
val globalWallpaper = createWallpaper(globalWallpaperChatColor)
|
val globalWallpaper = createWallpaper(globalWallpaperChatColor)
|
||||||
every { wallpaperValues.wallpaper } answers { globalWallpaper }
|
every { wallpaperValues.wallpaper } answers { globalWallpaper }
|
||||||
every { chatColorsValues.chatColors } answers { globalChatColor }
|
every { chatColorsValues.chatColors } answers { globalChatColor }
|
||||||
|
|
||||||
val mockStore = mockk<SignalStore>()
|
mockkObject(SignalStore)
|
||||||
SignalStore.testInject(mockStore)
|
|
||||||
every { SignalStore.wallpaper } returns wallpaperValues
|
every { SignalStore.wallpaper } returns wallpaperValues
|
||||||
every { SignalStore.chatColors } returns chatColorsValues
|
every { SignalStore.chatColors } returns chatColorsValues
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
unmockkAll()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Given recipient has custom chat color set, when I getChatColors, then I expect the custom chat color`() {
|
fun `Given recipient has custom chat color set, when I getChatColors, then I expect the custom chat color`() {
|
||||||
// GIVEN
|
// GIVEN
|
||||||
|
|||||||
@@ -2,35 +2,26 @@ package org.thoughtcrime.securesms.storage
|
|||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import androidx.test.core.app.ApplicationProvider
|
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.assertEquals
|
||||||
import org.junit.Assert.assertFalse
|
import org.junit.Assert.assertFalse
|
||||||
import org.junit.Assert.assertTrue
|
import org.junit.Assert.assertTrue
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.BeforeClass
|
import org.junit.BeforeClass
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
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.RobolectricTestRunner
|
||||||
import org.robolectric.annotation.Config
|
import org.robolectric.annotation.Config
|
||||||
import org.signal.core.util.logging.Log
|
import org.signal.core.util.logging.Log
|
||||||
import org.thoughtcrime.securesms.database.RecipientTable
|
import org.thoughtcrime.securesms.database.RecipientTable
|
||||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||||
import org.thoughtcrime.securesms.dependencies.MockApplicationDependencyProvider
|
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.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.testutil.EmptyLogger
|
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.ACI
|
||||||
import org.whispersystems.signalservice.api.push.ServiceId.PNI
|
import org.whispersystems.signalservice.api.push.ServiceId.PNI
|
||||||
import org.whispersystems.signalservice.api.storage.SignalContactRecord
|
import org.whispersystems.signalservice.api.storage.SignalContactRecord
|
||||||
@@ -42,24 +33,23 @@ import java.util.UUID
|
|||||||
@Config(application = Application::class)
|
@Config(application = Application::class)
|
||||||
class ContactRecordProcessorTest {
|
class ContactRecordProcessorTest {
|
||||||
|
|
||||||
@Rule
|
|
||||||
@JvmField
|
|
||||||
val mockitoRule: MockitoRule = JUnitRule(Plugins.getMockitoLogger(), Strictness.STRICT_STUBS)
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
lateinit var recipientTable: RecipientTable
|
lateinit var recipientTable: RecipientTable
|
||||||
|
|
||||||
@Mock
|
|
||||||
lateinit var remoteConfig: MockedStatic<RemoteConfig>
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
val mockAccountValues = mock(AccountValues::class.java)
|
|
||||||
Mockito.lenient().`when`(mockAccountValues.isPrimaryDevice).thenReturn(true)
|
|
||||||
if (!AppDependencies.isInitialized) {
|
if (!AppDependencies.isInitialized) {
|
||||||
AppDependencies.init(ApplicationProvider.getApplicationContext(), MockApplicationDependencyProvider())
|
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
|
@Test
|
||||||
|
|||||||
@@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user