diff --git a/android/src/main/java/dev/openfeature/sdk/FlagEvaluationDetails.kt b/android/src/main/java/dev/openfeature/sdk/FlagEvaluationDetails.kt index 4851f3ee..ddea0591 100644 --- a/android/src/main/java/dev/openfeature/sdk/FlagEvaluationDetails.kt +++ b/android/src/main/java/dev/openfeature/sdk/FlagEvaluationDetails.kt @@ -4,12 +4,13 @@ import dev.openfeature.sdk.exceptions.ErrorCode data class FlagEvaluationDetails( val flagKey: String, - override val value: T, - override val variant: String? = null, - override val reason: String? = null, - override val errorCode: ErrorCode? = null, - override val errorMessage: String? = null -) : BaseEvaluation { + val value: T, + val variant: String? = null, + val reason: String? = null, + val errorCode: ErrorCode? = null, + val errorMessage: String? = null, + val metadata: EvaluationMetadata = EvaluationMetadata.EMPTY +) { companion object } @@ -18,11 +19,12 @@ fun FlagEvaluationDetails.Companion.from( flagKey: String ): FlagEvaluationDetails { return FlagEvaluationDetails( - flagKey, - providerEval.value, - providerEval.variant, - providerEval.reason, - providerEval.errorCode, - providerEval.errorMessage + flagKey = flagKey, + value = providerEval.value, + variant = providerEval.variant, + reason = providerEval.reason, + errorCode = providerEval.errorCode, + errorMessage = providerEval.errorMessage, + metadata = providerEval.metadata ) } \ No newline at end of file diff --git a/android/src/main/java/dev/openfeature/sdk/FlagEvaluationMetadata.kt b/android/src/main/java/dev/openfeature/sdk/FlagEvaluationMetadata.kt new file mode 100644 index 00000000..011b8cb1 --- /dev/null +++ b/android/src/main/java/dev/openfeature/sdk/FlagEvaluationMetadata.kt @@ -0,0 +1,61 @@ +package dev.openfeature.sdk + +class EvaluationMetadata internal constructor(private val values: Map) { + + fun getString(key: String): String? = values[key] as? String + + fun getBoolean(key: String): Boolean? = values[key] as? Boolean + + fun getInt(key: String): Int? = values[key] as? Int + + fun getDouble(key: String): Double? = values[key] as? Double + + companion object { + fun builder(): Builder { + return Builder() + } + + val EMPTY = EvaluationMetadata(emptyMap()) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as EvaluationMetadata + + return values == other.values + } + + override fun hashCode(): Int { + return values.hashCode() + } +} + +class Builder { + private val values: MutableMap = mutableMapOf() + + fun putString(key: String, value: String): Builder { + values[key] = value + return this + } + + fun putInt(key: String, value: Int): Builder { + values[key] = value + return this + } + + fun putDouble(key: String, value: Double): Builder { + values[key] = value + return this + } + + fun putBoolean(key: String, value: Boolean): Builder { + values[key] = value + return this + } + + fun build(): EvaluationMetadata { + return EvaluationMetadata(values.toMap()) + } +} \ No newline at end of file diff --git a/android/src/main/java/dev/openfeature/sdk/ProviderEvaluation.kt b/android/src/main/java/dev/openfeature/sdk/ProviderEvaluation.kt index a7af6298..9b3f0c6c 100644 --- a/android/src/main/java/dev/openfeature/sdk/ProviderEvaluation.kt +++ b/android/src/main/java/dev/openfeature/sdk/ProviderEvaluation.kt @@ -7,5 +7,6 @@ data class ProviderEvaluation( val variant: String? = null, val reason: String? = null, val errorCode: ErrorCode? = null, - val errorMessage: String? = null + val errorMessage: String? = null, + val metadata: EvaluationMetadata = EvaluationMetadata.EMPTY ) \ No newline at end of file diff --git a/android/src/test/java/dev/openfeature/sdk/EvaluationMetadataTest.kt b/android/src/test/java/dev/openfeature/sdk/EvaluationMetadataTest.kt new file mode 100644 index 00000000..e006e4b4 --- /dev/null +++ b/android/src/test/java/dev/openfeature/sdk/EvaluationMetadataTest.kt @@ -0,0 +1,35 @@ +package dev.openfeature.sdk + +import org.junit.Assert +import org.junit.Test + +class EvaluationMetadataTest { + + private val metadata = EvaluationMetadata.builder() + .putString("key1", "value1") + .putInt("key2", 42) + .putBoolean("key3", true) + .putDouble("key4", 2.71828) + .build() + + @Test + fun testAddAndGet() { + Assert.assertEquals("value1", metadata.getString("key1")) + Assert.assertEquals(42, metadata.getInt("key2")) + Assert.assertEquals(true, metadata.getBoolean("key3")) + Assert.assertEquals(2.71828, metadata.getDouble("key4")) + } + + @Test + fun testGetNonExistentKey() { + Assert.assertNull(metadata.getString("key5")) + } + + @Test + fun testInvalidType() { + Assert.assertNull(metadata.getString("key2")) + Assert.assertNull(metadata.getInt("key3")) + Assert.assertNull(metadata.getBoolean("key4")) + Assert.assertNull(metadata.getDouble("key1")) + } +} \ No newline at end of file diff --git a/android/src/test/java/dev/openfeature/sdk/FlagEvaluationsTests.kt b/android/src/test/java/dev/openfeature/sdk/FlagEvaluationsTests.kt index 9b3991b7..be661f65 100644 --- a/android/src/test/java/dev/openfeature/sdk/FlagEvaluationsTests.kt +++ b/android/src/test/java/dev/openfeature/sdk/FlagEvaluationsTests.kt @@ -76,7 +76,8 @@ class FlagEvaluationsTests { Assert.assertEquals(booleanDetails, client.getBooleanDetails(key, false)) Assert.assertEquals(booleanDetails, client.getBooleanDetails(key, false, FlagEvaluationOptions())) - val stringDetails = FlagEvaluationDetails(key, "tset") + // in DoSomethingProvider, the string evaluation is special since it contains some metadata values + val stringDetails = FlagEvaluationDetails(key, "tset", metadata = DoSomethingProvider.evaluationMetadata) Assert.assertEquals(stringDetails, client.getStringDetails(key, "test")) Assert.assertEquals(stringDetails, client.getStringDetails(key, "test", FlagEvaluationOptions())) @@ -93,6 +94,18 @@ class FlagEvaluationsTests { Assert.assertEquals(objectDetails, client.getObjectDetails(key, Value.Structure(mapOf()), FlagEvaluationOptions())) } + @Test + fun testMetadataFlagEvaluation() = runTest { + OpenFeatureAPI.setProvider(DoSomethingProvider()) + val client = OpenFeatureAPI.getClient() + val key = "key" + + val details = client.getStringDetails(key, "default") + val metadata: EvaluationMetadata = details.metadata + Assert.assertEquals("value1", metadata.getString("key1")) + Assert.assertEquals(42, metadata.getInt("key2")) + } + @Test fun testHooksAreFired() = runTest { OpenFeatureAPI.setProvider(NoOpProvider()) diff --git a/android/src/test/java/dev/openfeature/sdk/helpers/DoSomethingProvider.kt b/android/src/test/java/dev/openfeature/sdk/helpers/DoSomethingProvider.kt index 44c1c1a6..71d4ca6b 100644 --- a/android/src/test/java/dev/openfeature/sdk/helpers/DoSomethingProvider.kt +++ b/android/src/test/java/dev/openfeature/sdk/helpers/DoSomethingProvider.kt @@ -1,6 +1,7 @@ package dev.openfeature.sdk.helpers import dev.openfeature.sdk.EvaluationContext +import dev.openfeature.sdk.EvaluationMetadata import dev.openfeature.sdk.FeatureProvider import dev.openfeature.sdk.Hook import dev.openfeature.sdk.ProviderEvaluation @@ -19,6 +20,12 @@ class DoSomethingProvider( override val metadata: ProviderMetadata = DoSomethingProviderMetadata(), private var dispatcher: CoroutineDispatcher = Dispatchers.IO ) : FeatureProvider { + companion object { + val evaluationMetadata = EvaluationMetadata.builder() + .putString("key1", "value1") + .putInt("key2", 42) + .build() + } private var eventHandler = EventHandler(dispatcher) override fun initialize(initialContext: EvaluationContext?) { @@ -51,7 +58,10 @@ class DoSomethingProvider( defaultValue: String, context: EvaluationContext? ): ProviderEvaluation { - return ProviderEvaluation(defaultValue.reversed()) + return ProviderEvaluation( + value = defaultValue.reversed(), + metadata = evaluationMetadata + ) } override fun getIntegerEvaluation(