Updated on 2026-08-14
This commit is contained in:
parent
7503c2817c
commit
d6c6cef5f9
30 changed files with 49 additions and 437 deletions
1
core/deep-links/.gitignore
vendored
1
core/deep-links/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
/build
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
alias(deps.plugins.kotlin.kapt)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.core.deeplink"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
/* Common */
|
||||
implementation(projects.common.routing)
|
||||
|
||||
/* Core */
|
||||
implementation(projects.core.decompose)
|
||||
|
||||
/* Libs - AndroidX */
|
||||
implementation(deps.lifecycle.runtime.ktx)
|
||||
|
||||
/* Libs - Other */
|
||||
implementation(deps.timber)
|
||||
|
||||
/* DI */
|
||||
implementation(deps.hilt.android)
|
||||
kapt(deps.hilt.kapt)
|
||||
|
||||
/* Tests */
|
||||
testImplementation(deps.test.junit)
|
||||
testImplementation(deps.test.coroutine)
|
||||
testImplementation(deps.test.truth)
|
||||
testImplementation(deps.test.mockk)
|
||||
}
|
||||
1
core/deep-links/global/.gitignore
vendored
1
core/deep-links/global/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
/build
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.core.deeplink.global"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
/* Project */
|
||||
implementation(projects.core.deepLinks)
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
package com.tangem.core.deeplink
|
||||
|
||||
/**
|
||||
* Represents a deep link.
|
||||
*/
|
||||
abstract class DeepLink(val shouldHandleDelayed: Boolean = false) {
|
||||
|
||||
/**
|
||||
* ID of the deep link.
|
||||
*
|
||||
* By default, it is the same as the [uri].
|
||||
* */
|
||||
val id: String get() = uri
|
||||
|
||||
/**
|
||||
* URI of the deep link.
|
||||
*
|
||||
* **Note: Remember to add the URI in the AndroidManifest.xml file in the `app` module.**
|
||||
*
|
||||
* Query parameters will be received automatically.
|
||||
*
|
||||
* Path parameters can be added using the following syntax:
|
||||
* ```kotlin
|
||||
* "tangem://link" // Without parameters
|
||||
* "tangem://link/{param1}/{param2}" // With path parameters
|
||||
* ```
|
||||
* */
|
||||
abstract val uri: String
|
||||
|
||||
/**
|
||||
* Method to be called when this deep link is received.
|
||||
*
|
||||
* @param params Map of parameters received from the deep link.
|
||||
* */
|
||||
abstract fun onReceive(params: Map<String, String>)
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
package com.tangem.core.deeplink
|
||||
|
||||
import android.content.Intent
|
||||
|
||||
/**
|
||||
* Key to pass deeplink via intent
|
||||
*/
|
||||
const val DEEPLINK_KEY = "deeplink"
|
||||
const val WEBLINK_KEY = "link"
|
||||
|
||||
// TODO: Add tests
|
||||
/**
|
||||
* Provides functionality to handle deep links.
|
||||
*
|
||||
* Allows deep links to be launched, registered, or unregistered.
|
||||
*/
|
||||
interface DeepLinksRegistry {
|
||||
|
||||
/**
|
||||
* Finds matches registered deep links for the given [intent] and launches them.
|
||||
*
|
||||
* @return `true` if any deep link was received, `false` otherwise.
|
||||
*/
|
||||
fun launch(intent: Intent): Boolean
|
||||
|
||||
/**
|
||||
* Registers the given [deepLink].
|
||||
*/
|
||||
fun register(deepLink: DeepLink)
|
||||
|
||||
/**
|
||||
* Registers the given [deepLinks].
|
||||
*/
|
||||
fun register(deepLinks: Collection<DeepLink>)
|
||||
|
||||
/**
|
||||
* Unregisters the given [deepLinks].
|
||||
*/
|
||||
fun unregister(deepLinks: Collection<DeepLink>)
|
||||
|
||||
/**
|
||||
* Unregisters the given [deepLink].
|
||||
*/
|
||||
fun unregister(deepLink: DeepLink)
|
||||
|
||||
/**
|
||||
* Unregisters deep links with the given [ids].
|
||||
* */
|
||||
fun unregisterByIds(ids: Collection<String>)
|
||||
|
||||
/**
|
||||
* Triggers run last launched [Intent] with deeplink handlers that can handle delayed deeplink
|
||||
* of specific [deepLinkClass] after handle [Intent] clear that and second time no intent will be handled
|
||||
*/
|
||||
fun triggerDelayedDeeplink(deepLinkClass: Class<out DeepLink>)
|
||||
|
||||
fun cancelDelayedDeeplink()
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
package com.tangem.core.deeplink
|
||||
|
||||
object DeeplinkConst {
|
||||
const val TANGEM_SCHEME = "tangem"
|
||||
const val WALLET_ID_KEY = "user_wallet_id"
|
||||
const val NETWORK_ID_KEY = "network_id"
|
||||
const val TYPE_KEY = "type"
|
||||
const val TOKEN_ID_KEY = "token_id"
|
||||
const val DERIVATION_PATH_KEY = "derivation_path"
|
||||
const val TRANSACTION_ID_KEY = "transaction_id"
|
||||
const val NAME_KEY = "name"
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
package com.tangem.core.deeplink.converter
|
||||
|
||||
import com.tangem.core.deeplink.DeeplinkConst.TANGEM_SCHEME
|
||||
|
||||
/**
|
||||
* Builder class for constructing deep links with a fluent interface.
|
||||
*/
|
||||
internal class DeepLinkBuilder {
|
||||
private var scheme: String = TANGEM_SCHEME
|
||||
private var action: String = ""
|
||||
private val pathParams: MutableList<String> = mutableListOf()
|
||||
private val queryParams: MutableMap<String, String> = mutableMapOf()
|
||||
|
||||
/**
|
||||
* Sets the scheme for the deep link (e.g., "tangem", "https")
|
||||
*/
|
||||
fun setScheme(scheme: String): DeepLinkBuilder {
|
||||
this.scheme = scheme
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action for the deep link (e.g., "link", "wallet")
|
||||
*/
|
||||
fun setAction(action: String): DeepLinkBuilder {
|
||||
this.action = action
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a path parameter to the deep link
|
||||
*/
|
||||
fun addPathParam(param: String): DeepLinkBuilder {
|
||||
pathParams.add(param)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a query parameter to the deep link
|
||||
*/
|
||||
fun addQueryParam(key: String, value: String): DeepLinkBuilder {
|
||||
queryParams[key] = value
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the deep link URI string
|
||||
*/
|
||||
fun build(): String {
|
||||
val path = if (pathParams.isEmpty()) {
|
||||
action
|
||||
} else {
|
||||
"$action/${pathParams.joinToString("/")}"
|
||||
}
|
||||
|
||||
val queryString = if (queryParams.isEmpty()) {
|
||||
""
|
||||
} else {
|
||||
"?" + queryParams.entries.joinToString("&") { "${it.key}=${it.value}" }
|
||||
}
|
||||
|
||||
return "$scheme://$path$queryString"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
package com.tangem.core.deeplink.converter
|
||||
|
||||
import android.os.Bundle
|
||||
import com.tangem.common.routing.DeepLinkRoute
|
||||
import com.tangem.common.routing.DeepLinkScheme
|
||||
import com.tangem.core.deeplink.DEEPLINK_KEY
|
||||
import com.tangem.core.deeplink.DeeplinkConst.DERIVATION_PATH_KEY
|
||||
import com.tangem.core.deeplink.DeeplinkConst.NAME_KEY
|
||||
import com.tangem.core.deeplink.DeeplinkConst.NETWORK_ID_KEY
|
||||
import com.tangem.core.deeplink.DeeplinkConst.TOKEN_ID_KEY
|
||||
import com.tangem.core.deeplink.DeeplinkConst.TRANSACTION_ID_KEY
|
||||
import com.tangem.core.deeplink.DeeplinkConst.TYPE_KEY
|
||||
import com.tangem.core.deeplink.DeeplinkConst.WALLET_ID_KEY
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
object PayloadToDeeplinkConverter : Converter<Map<String, String>, String?> {
|
||||
|
||||
override fun convert(value: Map<String, String>): String? {
|
||||
return when {
|
||||
value[DEEPLINK_KEY] != null -> value[DEEPLINK_KEY]
|
||||
isTangemPushNotificationPayload(value) -> buildNotificationDeeplink(value)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun convertBundle(bundle: Bundle?): String? {
|
||||
if (bundle == null) return null
|
||||
val bundleDataMap = mutableMapOf<String, String>()
|
||||
for (key in bundle.keySet()) {
|
||||
val value = bundle.getString(key)
|
||||
if (value != null) {
|
||||
bundleDataMap[key] = value
|
||||
}
|
||||
}
|
||||
return convert(bundleDataMap)
|
||||
}
|
||||
|
||||
@Suppress("ReturnCount")
|
||||
private fun buildNotificationDeeplink(payload: Map<String, String>): String? {
|
||||
val type = payload[TYPE_KEY] ?: return null
|
||||
val networkId = payload[NETWORK_ID_KEY] ?: return null
|
||||
val tokenId = payload[TOKEN_ID_KEY] ?: return null
|
||||
val walletId = payload[WALLET_ID_KEY] ?: return null
|
||||
val derivationPath = payload[DERIVATION_PATH_KEY].orEmpty()
|
||||
val transactionId = payload[TRANSACTION_ID_KEY]
|
||||
val name = payload[NAME_KEY]
|
||||
|
||||
return DeepLinkBuilder().setScheme(DeepLinkScheme.Tangem.scheme).apply {
|
||||
setAction(DeepLinkRoute.TokenDetails.host)
|
||||
addQueryParam(NETWORK_ID_KEY, networkId)
|
||||
addQueryParam(TOKEN_ID_KEY, tokenId)
|
||||
addQueryParam(TYPE_KEY, type)
|
||||
addQueryParam(WALLET_ID_KEY, walletId)
|
||||
if (derivationPath.isNotBlank()) {
|
||||
addQueryParam(DERIVATION_PATH_KEY, derivationPath)
|
||||
}
|
||||
|
||||
transactionId?.let { addQueryParam(TRANSACTION_ID_KEY, it) }
|
||||
name?.let { addQueryParam(NAME_KEY, it) }
|
||||
}.build()
|
||||
}
|
||||
|
||||
private fun isTangemPushNotificationPayload(payload: Map<String, String>): Boolean {
|
||||
return payload.containsKey(TYPE_KEY) &&
|
||||
payload.containsKey(NETWORK_ID_KEY) &&
|
||||
payload.containsKey(TOKEN_ID_KEY) &&
|
||||
payload.containsKey(WALLET_ID_KEY)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
package com.tangem.core.deeplink.di
|
||||
|
||||
import com.tangem.core.deeplink.DeepLinksRegistry
|
||||
import com.tangem.core.deeplink.impl.DefaultDeepLinksRegistry
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object DeepLinksModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideDeepLinksRegistry(): DeepLinksRegistry {
|
||||
return DefaultDeepLinksRegistry()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,201 +0,0 @@
|
|||
package com.tangem.core.deeplink.impl
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.core.net.toUri
|
||||
import com.tangem.core.deeplink.DEEPLINK_KEY
|
||||
import com.tangem.core.deeplink.DeepLink
|
||||
import com.tangem.core.deeplink.DeepLinksRegistry
|
||||
import timber.log.Timber
|
||||
|
||||
internal class DefaultDeepLinksRegistry : DeepLinksRegistry {
|
||||
|
||||
private var registries: List<DeepLink> = emptyList()
|
||||
private var lastDeepLink: Uri? = null
|
||||
|
||||
override fun launch(intent: Intent): Boolean {
|
||||
// Try to get deeplink from data (direct deeplink flow)
|
||||
// Otherwise, try to get from extras (notification deeplink flow)
|
||||
val deepLinkExtras = intent.getStringExtra(DEEPLINK_KEY)?.toUri()
|
||||
val received = intent.data ?: deepLinkExtras ?: return false
|
||||
lastDeepLink = received
|
||||
var hasMatch = false
|
||||
|
||||
Timber.i(
|
||||
"""
|
||||
Received deep link intent
|
||||
|- Received URI: $received
|
||||
|- Registries: $registries
|
||||
""".trimIndent(),
|
||||
)
|
||||
registries.forEach { deepLink ->
|
||||
val expected = deepLink.uri.toUri()
|
||||
|
||||
if (!isMatches(expected, received)) return@forEach
|
||||
hasMatch = true
|
||||
|
||||
val params = getParams(expected, received)
|
||||
|
||||
logMatch(hasMatch, expected, received, params)
|
||||
|
||||
deepLink.onReceive(params)
|
||||
lastDeepLink = null // clear deeplink if it was handled
|
||||
}
|
||||
|
||||
if (!hasMatch) {
|
||||
logMatch(hasMatch, null, received, null)
|
||||
}
|
||||
|
||||
return hasMatch
|
||||
}
|
||||
|
||||
override fun register(deepLinks: Collection<DeepLink>) {
|
||||
registries = (registries + deepLinks).distinctBy(DeepLink::id)
|
||||
|
||||
Timber.d(
|
||||
"""
|
||||
Registered deep links
|
||||
|- Registries: $registries
|
||||
""".trimIndent(),
|
||||
)
|
||||
}
|
||||
|
||||
override fun register(deepLink: DeepLink) {
|
||||
registries = (registries + deepLink).distinctBy(DeepLink::id)
|
||||
|
||||
Timber.d(
|
||||
"""
|
||||
Registered deep link
|
||||
|- Registries: $registries
|
||||
""".trimIndent(),
|
||||
)
|
||||
}
|
||||
|
||||
override fun unregister(deepLinks: Collection<DeepLink>) {
|
||||
registries = registries.filter { it !in deepLinks }
|
||||
|
||||
Timber.d(
|
||||
"""
|
||||
Unregistered deep links
|
||||
|- Registries: $registries
|
||||
""".trimIndent(),
|
||||
)
|
||||
}
|
||||
|
||||
override fun unregister(deepLink: DeepLink) {
|
||||
registries = registries.filter { it.id != deepLink.id }
|
||||
|
||||
Timber.d(
|
||||
"""
|
||||
Unregistered deep link
|
||||
|- Registries: $registries
|
||||
""".trimIndent(),
|
||||
)
|
||||
}
|
||||
|
||||
override fun unregisterByIds(ids: Collection<String>) {
|
||||
registries = registries.filter { it.id !in ids }
|
||||
|
||||
Timber.d(
|
||||
"""
|
||||
Unregistered deep links
|
||||
|- Registries: $registries
|
||||
""".trimIndent(),
|
||||
)
|
||||
}
|
||||
|
||||
override fun triggerDelayedDeeplink(deepLinkClass: Class<out DeepLink>) {
|
||||
val received = lastDeepLink
|
||||
if (received != null) {
|
||||
var hasMatch = false
|
||||
registries
|
||||
.filterIsInstance(deepLinkClass)
|
||||
.forEach { deepLink ->
|
||||
if (!deepLink.shouldHandleDelayed) return@forEach
|
||||
val expected = deepLink.uri.toUri()
|
||||
if (!isMatches(expected, received)) return@forEach
|
||||
hasMatch = true
|
||||
|
||||
val params = getParams(expected, received)
|
||||
logMatch(hasMatch, expected, received, params)
|
||||
deepLink.onReceive(params)
|
||||
}
|
||||
|
||||
if (!hasMatch) {
|
||||
logMatch(hasMatch, null, received, null)
|
||||
}
|
||||
lastDeepLink = null // clear deeplink in any case handle or not
|
||||
}
|
||||
}
|
||||
|
||||
override fun cancelDelayedDeeplink() {
|
||||
lastDeepLink = null
|
||||
}
|
||||
|
||||
private fun logMatch(hasMatch: Boolean, expected: Uri?, received: Uri?, params: Map<String, String>?) {
|
||||
if (hasMatch) {
|
||||
Timber.i(
|
||||
"""
|
||||
Matched deep link
|
||||
|- Expected URI: $expected
|
||||
|- Received URI: $received
|
||||
|- Params: $params
|
||||
""".trimIndent(),
|
||||
)
|
||||
} else {
|
||||
Timber.i(
|
||||
"""
|
||||
No match found for deep link
|
||||
|- Received URI: $received
|
||||
|- Registries: $registries
|
||||
""".trimIndent(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isMatches(received: Uri, expected: Uri): Boolean {
|
||||
if (received == expected) return true
|
||||
if (received.authority != expected.authority ||
|
||||
received.pathSegments.size != expected.pathSegments.size
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
received.pathSegments.forEachIndexed { index, receivedSegment ->
|
||||
val expectedSegment = expected.pathSegments[index]
|
||||
if (receivedSegment != expectedSegment &&
|
||||
!(receivedSegment.startsWith(prefix = "{") && receivedSegment.endsWith(suffix = "}"))
|
||||
) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun getParams(received: Uri, expected: Uri): Map<String, String> {
|
||||
val params = mutableMapOf<String, String>()
|
||||
|
||||
received.pathSegments.forEachIndexed { index, receivedSegment ->
|
||||
val expectedSegment = expected.pathSegments[index]
|
||||
if (receivedSegment != expectedSegment &&
|
||||
receivedSegment.startsWith(prefix = "{") &&
|
||||
receivedSegment.endsWith(suffix = "}")
|
||||
) {
|
||||
val path = receivedSegment
|
||||
.replace(oldValue = "{", newValue = "")
|
||||
.replace(oldValue = "}", newValue = "")
|
||||
|
||||
params[path] = expectedSegment
|
||||
}
|
||||
}
|
||||
|
||||
expected.queryParameterNames.forEach { paramName ->
|
||||
expected.getQueryParameter(paramName)?.let { param ->
|
||||
params[paramName] = param
|
||||
}
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
}
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
package com.tangem.core.deeplink.converter
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.tangem.core.deeplink.DeeplinkConst
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
internal class DeepLinkBuilderTest {
|
||||
|
||||
private lateinit var deepLinkBuilder: DeepLinkBuilder
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
deepLinkBuilder = DeepLinkBuilder()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN default builder WHEN build THEN should return default scheme`() {
|
||||
// WHEN
|
||||
val result = deepLinkBuilder.build()
|
||||
|
||||
// THEN
|
||||
assertThat(result).isEqualTo("${DeeplinkConst.TANGEM_SCHEME}://")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN custom scheme WHEN setScheme THEN should use custom scheme`() {
|
||||
// GIVEN
|
||||
val customScheme = "https"
|
||||
|
||||
// WHEN
|
||||
val result = deepLinkBuilder
|
||||
.setScheme(customScheme)
|
||||
.build()
|
||||
|
||||
// THEN
|
||||
assertThat(result).isEqualTo("$customScheme://")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN action WHEN setAction THEN should include action in path`() {
|
||||
// GIVEN
|
||||
val action = "wallet"
|
||||
|
||||
// WHEN
|
||||
val result = deepLinkBuilder
|
||||
.setAction(action)
|
||||
.build()
|
||||
|
||||
// THEN
|
||||
assertThat(result).isEqualTo("${DeeplinkConst.TANGEM_SCHEME}://$action")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN path params WHEN addPathParam THEN should include params in path`() {
|
||||
// GIVEN
|
||||
val action = "wallet"
|
||||
val param1 = "123"
|
||||
val param2 = "456"
|
||||
|
||||
// WHEN
|
||||
val result = deepLinkBuilder
|
||||
.setAction(action)
|
||||
.addPathParam(param1)
|
||||
.addPathParam(param2)
|
||||
.build()
|
||||
|
||||
// THEN
|
||||
assertThat(result).isEqualTo("${DeeplinkConst.TANGEM_SCHEME}://$action/$param1/$param2")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN query params WHEN addQueryParam THEN should include params in query string`() {
|
||||
// GIVEN
|
||||
val action = "wallet"
|
||||
val key1 = "param1"
|
||||
val value1 = "value1"
|
||||
val key2 = "param2"
|
||||
val value2 = "value2"
|
||||
|
||||
// WHEN
|
||||
val result = deepLinkBuilder
|
||||
.setAction(action)
|
||||
.addQueryParam(key1, value1)
|
||||
.addQueryParam(key2, value2)
|
||||
.build()
|
||||
|
||||
// THEN
|
||||
assertThat(result).isEqualTo("${DeeplinkConst.TANGEM_SCHEME}://$action?$key1=$value1&$key2=$value2")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN complex deep link WHEN build THEN should construct correct URI`() {
|
||||
// GIVEN
|
||||
val scheme = "https"
|
||||
val action = "wallet"
|
||||
val pathParam = "123"
|
||||
val queryKey = "token"
|
||||
val queryValue = "abc"
|
||||
|
||||
// WHEN
|
||||
val result = deepLinkBuilder
|
||||
.setScheme(scheme)
|
||||
.setAction(action)
|
||||
.addPathParam(pathParam)
|
||||
.addQueryParam(queryKey, queryValue)
|
||||
.build()
|
||||
|
||||
// THEN
|
||||
assertThat(result).isEqualTo("$scheme://$action/$pathParam?$queryKey=$queryValue")
|
||||
}
|
||||
}
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
package com.tangem.core.deeplink.converter
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.tangem.core.deeplink.DEEPLINK_KEY
|
||||
import com.tangem.core.deeplink.DeeplinkConst.DERIVATION_PATH_KEY
|
||||
import com.tangem.core.deeplink.DeeplinkConst.NETWORK_ID_KEY
|
||||
import com.tangem.core.deeplink.DeeplinkConst.TOKEN_ID_KEY
|
||||
import com.tangem.core.deeplink.DeeplinkConst.TYPE_KEY
|
||||
import com.tangem.core.deeplink.DeeplinkConst.WALLET_ID_KEY
|
||||
import org.junit.Test
|
||||
|
||||
internal class PayloadToDeeplinkConverterTest {
|
||||
|
||||
@Test
|
||||
fun `GIVEN payload with deeplink key WHEN convert THEN should return deeplink value`() {
|
||||
// GIVEN
|
||||
val payload = mapOf(
|
||||
DEEPLINK_KEY to "tangem://token-details?networkId=ethereum&tokenId=0x123&type=token&user_wallet_id=wallet123" +
|
||||
"&derivation_path=m'0'0'0",
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val result = PayloadToDeeplinkConverter.convert(payload)
|
||||
|
||||
// THEN
|
||||
assertThat(result).isEqualTo(
|
||||
"tangem://token-details?networkId=ethereum&tokenId=0x123&type=token&user_wallet_id=wallet123&derivation_path=m'0'0'0",
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN valid push notification payload with all vital values WHEN convert THEN should return correct deeplink`() {
|
||||
// GIVEN
|
||||
val payload = mapOf(
|
||||
TYPE_KEY to "token",
|
||||
NETWORK_ID_KEY to "ethereum",
|
||||
TOKEN_ID_KEY to "0x123",
|
||||
WALLET_ID_KEY to "wallet123",
|
||||
DERIVATION_PATH_KEY to "m'0'0'0",
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val result = PayloadToDeeplinkConverter.convert(payload)
|
||||
|
||||
// THEN
|
||||
assertThat(result).isEqualTo(
|
||||
"tangem://token?network_id=ethereum&token_id=0x123&type=token&user_wallet_id=wallet123&derivation_path=m'0'0'0",
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN push notification payload without derivationPath WHEN convert THEN should return correct deeplink without derivation_path`() {
|
||||
// GIVEN
|
||||
val payload = mapOf(
|
||||
TYPE_KEY to "token",
|
||||
NETWORK_ID_KEY to "ethereum",
|
||||
TOKEN_ID_KEY to "0x123",
|
||||
WALLET_ID_KEY to "wallet123",
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val result = PayloadToDeeplinkConverter.convert(payload)
|
||||
|
||||
// THEN
|
||||
assertThat(result).isEqualTo(
|
||||
"tangem://token?network_id=ethereum&token_id=0x123&type=token&user_wallet_id=wallet123",
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN push notification payload with missing type WHEN convert THEN should return null`() {
|
||||
// GIVEN
|
||||
val payload = mapOf(
|
||||
NETWORK_ID_KEY to "ethereum",
|
||||
TOKEN_ID_KEY to "0x123",
|
||||
WALLET_ID_KEY to "wallet123",
|
||||
DERIVATION_PATH_KEY to "m'0'0'0",
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val result = PayloadToDeeplinkConverter.convert(payload)
|
||||
|
||||
// THEN
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN push notification payload with missing networkId WHEN convert THEN should return null`() {
|
||||
// GIVEN
|
||||
val payload = mapOf(
|
||||
TYPE_KEY to "token",
|
||||
TOKEN_ID_KEY to "0x123",
|
||||
WALLET_ID_KEY to "wallet123",
|
||||
DERIVATION_PATH_KEY to "m'0'0'0",
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val result = PayloadToDeeplinkConverter.convert(payload)
|
||||
|
||||
// THEN
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN push notification payload with missing tokenId WHEN convert THEN should return null`() {
|
||||
// GIVEN
|
||||
val payload = mapOf(
|
||||
TYPE_KEY to "token",
|
||||
NETWORK_ID_KEY to "ethereum",
|
||||
WALLET_ID_KEY to "wallet123",
|
||||
DERIVATION_PATH_KEY to "m'0'0'0",
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val result = PayloadToDeeplinkConverter.convert(payload)
|
||||
|
||||
// THEN
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN push notification payload with missing walletId WHEN convert THEN should return null`() {
|
||||
// GIVEN
|
||||
val payload = mapOf(
|
||||
TYPE_KEY to "token",
|
||||
NETWORK_ID_KEY to "ethereum",
|
||||
TOKEN_ID_KEY to "0x123",
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val result = PayloadToDeeplinkConverter.convert(payload)
|
||||
|
||||
// THEN
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN empty payload WHEN convert THEN should return null`() {
|
||||
// GIVEN
|
||||
val payload = emptyMap<String, String>()
|
||||
|
||||
// WHEN
|
||||
val result = PayloadToDeeplinkConverter.convert(payload)
|
||||
|
||||
// THEN
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue