Updated on 2026-08-14
This commit is contained in:
parent
ad0b09deae
commit
6480caeeed
13 changed files with 492 additions and 35 deletions
|
|
@ -1,6 +1,7 @@
|
|||
plugins {
|
||||
alias(deps.plugins.kotlin.jvm)
|
||||
alias(deps.plugins.kotlin.kapt)
|
||||
alias(deps.plugins.kotlin.serialization)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
|
|
@ -15,12 +16,13 @@ dependencies {
|
|||
kapt(deps.hilt.kapt)
|
||||
// endregion
|
||||
|
||||
// region Coroutines
|
||||
implementation(deps.kotlin.coroutines)
|
||||
// region Kotlin
|
||||
api(deps.kotlin.coroutines)
|
||||
api(deps.kotlin.serialization)
|
||||
// endregion
|
||||
|
||||
// region Time dependencies
|
||||
implementation(deps.jodatime)
|
||||
api(deps.jodatime)
|
||||
// endregion
|
||||
|
||||
testImplementation(deps.test.coroutine)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tangem.utils
|
||||
|
||||
import kotlinx.serialization.json.JsonArray
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import kotlinx.serialization.json.contentOrNull
|
||||
|
||||
/**
|
||||
* Extracts all string primitive values from a [JsonElement] tree (recursively into
|
||||
* objects and arrays). Non-string primitives are ignored.
|
||||
*/
|
||||
object JsonStringValuesExtractor {
|
||||
|
||||
fun extract(json: JsonElement): List<String> = json.extractStringValues()
|
||||
|
||||
private fun JsonElement.extractStringValues(): List<String> = when (this) {
|
||||
is JsonPrimitive -> if (isString) listOfNotNull(contentOrNull) else emptyList()
|
||||
is JsonObject -> values.flatMap { it.extractStringValues() }
|
||||
is JsonArray -> flatMap { it.extractStringValues() }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
package com.tangem.utils
|
||||
|
||||
import com.google.common.truth.Truth
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonNull
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class JsonStringValuesExtractorTest {
|
||||
|
||||
@Test
|
||||
fun `extract returns single value for string primitive`() {
|
||||
// Arrange
|
||||
val json = JsonPrimitive("hello")
|
||||
|
||||
// Act
|
||||
val actual = JsonStringValuesExtractor.extract(json)
|
||||
|
||||
// Assert
|
||||
Truth.assertThat(actual).containsExactly("hello")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extract returns empty for numeric primitive`() {
|
||||
// Arrange
|
||||
val json = JsonPrimitive(42)
|
||||
|
||||
// Act
|
||||
val actual = JsonStringValuesExtractor.extract(json)
|
||||
|
||||
// Assert
|
||||
Truth.assertThat(actual).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extract returns empty for boolean primitive`() {
|
||||
// Arrange
|
||||
val json = JsonPrimitive(true)
|
||||
|
||||
// Act
|
||||
val actual = JsonStringValuesExtractor.extract(json)
|
||||
|
||||
// Assert
|
||||
Truth.assertThat(actual).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extract returns empty for json null`() {
|
||||
// Act
|
||||
val actual = JsonStringValuesExtractor.extract(JsonNull)
|
||||
|
||||
// Assert
|
||||
Truth.assertThat(actual).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extract returns all string values from flat object`() {
|
||||
// Arrange
|
||||
val json = Json.parseToJsonElement(
|
||||
"""{"apiKey":"abc","secret":"xyz","count":42,"enabled":true}""",
|
||||
)
|
||||
|
||||
// Act
|
||||
val actual = JsonStringValuesExtractor.extract(json)
|
||||
|
||||
// Assert
|
||||
Truth.assertThat(actual).containsExactly("abc", "xyz")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extract returns all string values from flat array`() {
|
||||
// Arrange
|
||||
val json = Json.parseToJsonElement("""["one","two",3,true,null]""")
|
||||
|
||||
// Act
|
||||
val actual = JsonStringValuesExtractor.extract(json)
|
||||
|
||||
// Assert
|
||||
Truth.assertThat(actual).containsExactly("one", "two").inOrder()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extract recurses into nested objects`() {
|
||||
// Arrange
|
||||
val json = Json.parseToJsonElement(
|
||||
"""{"outer":{"inner":{"key":"deep"}},"top":"shallow"}""",
|
||||
)
|
||||
|
||||
// Act
|
||||
val actual = JsonStringValuesExtractor.extract(json)
|
||||
|
||||
// Assert
|
||||
Truth.assertThat(actual).containsExactly("deep", "shallow")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extract recurses into nested arrays`() {
|
||||
// Arrange
|
||||
val json = Json.parseToJsonElement("""[["a","b"],["c",["d"]]]""")
|
||||
|
||||
// Act
|
||||
val actual = JsonStringValuesExtractor.extract(json)
|
||||
|
||||
// Assert
|
||||
Truth.assertThat(actual).containsExactly("a", "b", "c", "d").inOrder()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extract handles mixed nested objects and arrays`() {
|
||||
// Arrange
|
||||
val json = Json.parseToJsonElement(
|
||||
"""{"keys":["k1","k2"],"nested":{"items":[{"name":"x"},{"name":"y"}]}}""",
|
||||
)
|
||||
|
||||
// Act
|
||||
val actual = JsonStringValuesExtractor.extract(json)
|
||||
|
||||
// Assert
|
||||
Truth.assertThat(actual).containsExactly("k1", "k2", "x", "y")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extract returns empty for empty object`() {
|
||||
// Arrange
|
||||
val json = Json.parseToJsonElement("""{}""")
|
||||
|
||||
// Act
|
||||
val actual = JsonStringValuesExtractor.extract(json)
|
||||
|
||||
// Assert
|
||||
Truth.assertThat(actual).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extract returns empty for empty array`() {
|
||||
// Arrange
|
||||
val json = Json.parseToJsonElement("""[]""")
|
||||
|
||||
// Act
|
||||
val actual = JsonStringValuesExtractor.extract(json)
|
||||
|
||||
// Assert
|
||||
Truth.assertThat(actual).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extract preserves duplicate values`() {
|
||||
// Arrange — extractor does NOT dedupe; that's the caller's concern
|
||||
val json = Json.parseToJsonElement("""{"a":"same","b":"same","c":"other"}""")
|
||||
|
||||
// Act
|
||||
val actual = JsonStringValuesExtractor.extract(json)
|
||||
|
||||
// Assert
|
||||
Truth.assertThat(actual).containsExactly("same", "same", "other")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extract returns empty string when string primitive is empty`() {
|
||||
// Arrange
|
||||
val json = Json.parseToJsonElement("""{"a":"","b":"x"}""")
|
||||
|
||||
// Act
|
||||
val actual = JsonStringValuesExtractor.extract(json)
|
||||
|
||||
// Assert — extractor returns "" too; filtering is caller's job
|
||||
Truth.assertThat(actual).containsExactly("", "x")
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue