Skip to content

Commit ffd6da8

Browse files
authored
Merge branch 'main' into noop-provider
2 parents 15dba9e + 6e9aa29 commit ffd6da8

File tree

14 files changed

+155
-166
lines changed

14 files changed

+155
-166
lines changed

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{".":"0.2.3"}
1+
{".":"0.3.0"}

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# Changelog
22

3+
## [0.3.0](https://github.com/open-feature/kotlin-sdk/compare/v0.2.3...v0.3.0) (2024-04-08)
4+
5+
6+
### ⚠ BREAKING CHANGES
7+
8+
* remove kotlinx.serialization dependency
9+
10+
### 🔄 Refactoring
11+
12+
* remove kotlinx.serialization dependency ([3145d6c](https://github.com/open-feature/kotlin-sdk/commit/3145d6c41359598e8565a19d576863df82de6f16))
13+
314
## [0.2.3](https://github.com/open-feature/kotlin-sdk/compare/v0.2.2...v0.2.3) (2024-02-02)
415

516

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
<img alt="Specification" src="https://img.shields.io/static/v1?label=specification&message=v0.6.0&color=yellow&style=for-the-badge" />
1717
</a>
1818
<!-- x-release-please-start-version -->
19-
<a href="https://github.com/open-feature/kotlin-sdk/releases/tag/v0.2.3">
20-
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v0.2.3&color=blue&style=for-the-badge" />
19+
<a href="https://github.com/open-feature/kotlin-sdk/releases/tag/v0.3.0">
20+
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v0.3.0&color=blue&style=for-the-badge" />
2121
</a>
2222
<!-- x-release-please-end -->
2323
<br/>
@@ -48,7 +48,7 @@ Installation via Maven Central is preferred, using the following dependency:
4848
<!-- x-release-please-start-version -->
4949
```kotlin
5050
dependencies {
51-
api("dev.openfeature:android-sdk:0.2.3")
51+
api("dev.openfeature:android-sdk:0.3.0")
5252
}
5353
```
5454

android/build.gradle.kts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ plugins {
55
id("maven-publish")
66
id("signing")
77
id("org.jlleitschuh.gradle.ktlint")
8-
kotlin("plugin.serialization") version "1.8.10"
98
}
109

1110
val releaseVersion = project.extra["version"].toString()
@@ -98,7 +97,6 @@ publishing {
9897

9998
dependencies {
10099
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
101-
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2")
102100
testImplementation("junit:junit:4.13.2")
103101
testImplementation("org.mockito.kotlin:mockito-kotlin:5.1.0")
104102
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")

android/src/main/java/dev/openfeature/sdk/FlagEvaluationDetails.kt

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ import dev.openfeature.sdk.exceptions.ErrorCode
44

55
data class FlagEvaluationDetails<T>(
66
val flagKey: String,
7-
override val value: T,
8-
override val variant: String? = null,
9-
override val reason: String? = null,
10-
override val errorCode: ErrorCode? = null,
11-
override val errorMessage: String? = null
12-
) : BaseEvaluation<T> {
7+
val value: T,
8+
val variant: String? = null,
9+
val reason: String? = null,
10+
val errorCode: ErrorCode? = null,
11+
val errorMessage: String? = null,
12+
val metadata: EvaluationMetadata = EvaluationMetadata.EMPTY
13+
) {
1314
companion object
1415
}
1516

@@ -18,11 +19,12 @@ fun <T> FlagEvaluationDetails.Companion.from(
1819
flagKey: String
1920
): FlagEvaluationDetails<T> {
2021
return FlagEvaluationDetails(
21-
flagKey,
22-
providerEval.value,
23-
providerEval.variant,
24-
providerEval.reason,
25-
providerEval.errorCode,
26-
providerEval.errorMessage
22+
flagKey = flagKey,
23+
value = providerEval.value,
24+
variant = providerEval.variant,
25+
reason = providerEval.reason,
26+
errorCode = providerEval.errorCode,
27+
errorMessage = providerEval.errorMessage,
28+
metadata = providerEval.metadata
2729
)
2830
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package dev.openfeature.sdk
2+
3+
class EvaluationMetadata internal constructor(private val values: Map<String, Any>) {
4+
5+
fun getString(key: String): String? = values[key] as? String
6+
7+
fun getBoolean(key: String): Boolean? = values[key] as? Boolean
8+
9+
fun getInt(key: String): Int? = values[key] as? Int
10+
11+
fun getDouble(key: String): Double? = values[key] as? Double
12+
13+
companion object {
14+
fun builder(): Builder {
15+
return Builder()
16+
}
17+
18+
val EMPTY = EvaluationMetadata(emptyMap())
19+
}
20+
21+
override fun equals(other: Any?): Boolean {
22+
if (this === other) return true
23+
if (javaClass != other?.javaClass) return false
24+
25+
other as EvaluationMetadata
26+
27+
return values == other.values
28+
}
29+
30+
override fun hashCode(): Int {
31+
return values.hashCode()
32+
}
33+
}
34+
35+
class Builder {
36+
private val values: MutableMap<String, Any> = mutableMapOf()
37+
38+
fun putString(key: String, value: String): Builder {
39+
values[key] = value
40+
return this
41+
}
42+
43+
fun putInt(key: String, value: Int): Builder {
44+
values[key] = value
45+
return this
46+
}
47+
48+
fun putDouble(key: String, value: Double): Builder {
49+
values[key] = value
50+
return this
51+
}
52+
53+
fun putBoolean(key: String, value: Boolean): Builder {
54+
values[key] = value
55+
return this
56+
}
57+
58+
fun build(): EvaluationMetadata {
59+
return EvaluationMetadata(values.toMap())
60+
}
61+
}

android/src/main/java/dev/openfeature/sdk/ProviderEvaluation.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ data class ProviderEvaluation<T>(
77
val variant: String? = null,
88
val reason: String? = null,
99
val errorCode: ErrorCode? = null,
10-
val errorMessage: String? = null
10+
val errorMessage: String? = null,
11+
val metadata: EvaluationMetadata = EvaluationMetadata.EMPTY
1112
)
Lines changed: 1 addition & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,5 @@
11
package dev.openfeature.sdk
22

3-
import android.annotation.SuppressLint
4-
import dev.openfeature.sdk.exceptions.OpenFeatureError
5-
import kotlinx.serialization.KSerializer
6-
import kotlinx.serialization.Serializable
7-
import kotlinx.serialization.descriptors.PrimitiveKind
8-
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
9-
import kotlinx.serialization.encoding.Decoder
10-
import kotlinx.serialization.encoding.Encoder
11-
import kotlinx.serialization.json.JsonContentPolymorphicSerializer
12-
import kotlinx.serialization.json.JsonElement
13-
import kotlinx.serialization.json.jsonObject
14-
import java.text.SimpleDateFormat
15-
import java.util.Date
16-
import java.util.TimeZone
17-
18-
@Serializable(with = ValueSerializer::class)
193
sealed interface Value {
204

215
fun asString(): kotlin.String? = if (this is String) string else null
@@ -27,28 +11,20 @@ sealed interface Value {
2711
fun asStructure(): Map<kotlin.String, Value>? = if (this is Structure) structure else null
2812
fun isNull(): kotlin.Boolean = this is Null
2913

30-
@Serializable
3114
data class String(val string: kotlin.String) : Value
3215

33-
@Serializable
3416
data class Boolean(val boolean: kotlin.Boolean) : Value
3517

36-
@Serializable
3718
data class Integer(val integer: Int) : Value
3819

39-
@Serializable
4020
data class Double(val double: kotlin.Double) : Value
4121

42-
@Serializable
43-
data class Date(@Serializable(DateSerializer::class) val date: java.util.Date) : Value
22+
data class Date(val date: java.util.Date) : Value
4423

45-
@Serializable
4624
data class Structure(val structure: Map<kotlin.String, Value>) : Value
4725

48-
@Serializable
4926
data class List(val list: kotlin.collections.List<Value>) : Value
5027

51-
@Serializable
5228
object Null : Value {
5329
override fun equals(other: Any?): kotlin.Boolean {
5430
return other is Null
@@ -58,37 +34,4 @@ sealed interface Value {
5834
return javaClass.hashCode()
5935
}
6036
}
61-
}
62-
63-
object ValueSerializer : JsonContentPolymorphicSerializer<Value>(Value::class) {
64-
override fun selectDeserializer(element: JsonElement) = when (element.jsonObject.keys) {
65-
emptySet<String>() -> Value.Null.serializer()
66-
setOf("string") -> Value.String.serializer()
67-
setOf("boolean") -> Value.Boolean.serializer()
68-
setOf("integer") -> Value.Integer.serializer()
69-
setOf("double") -> Value.Double.serializer()
70-
setOf("date") -> Value.Date.serializer()
71-
setOf("list") -> Value.List.serializer()
72-
setOf("structure") -> Value.Structure.serializer()
73-
else -> throw OpenFeatureError.ParseError("couldn't find deserialization key for Value")
74-
}
75-
}
76-
77-
@SuppressLint("SimpleDateFormat")
78-
object DateSerializer : KSerializer<Date> {
79-
private val dateFormatter =
80-
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").apply { timeZone = TimeZone.getTimeZone("UTC") }
81-
private val fallbackDateFormatter =
82-
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").apply { timeZone = TimeZone.getTimeZone("UTC") }
83-
override val descriptor = PrimitiveSerialDescriptor("Instant", PrimitiveKind.STRING)
84-
override fun serialize(encoder: Encoder, value: Date) = encoder.encodeString(dateFormatter.format(value))
85-
override fun deserialize(decoder: Decoder): Date = with(decoder.decodeString()) {
86-
try {
87-
dateFormatter.parse(this)
88-
?: throw IllegalArgumentException("unable to parse $this")
89-
} catch (e: Exception) {
90-
fallbackDateFormatter.parse(this)
91-
?: throw IllegalArgumentException("unable to parse $this")
92-
}
93-
}
9437
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package dev.openfeature.sdk
2+
3+
import org.junit.Assert
4+
import org.junit.Test
5+
6+
class EvaluationMetadataTest {
7+
8+
private val metadata = EvaluationMetadata.builder()
9+
.putString("key1", "value1")
10+
.putInt("key2", 42)
11+
.putBoolean("key3", true)
12+
.putDouble("key4", 2.71828)
13+
.build()
14+
15+
@Test
16+
fun testAddAndGet() {
17+
Assert.assertEquals("value1", metadata.getString("key1"))
18+
Assert.assertEquals(42, metadata.getInt("key2"))
19+
Assert.assertEquals(true, metadata.getBoolean("key3"))
20+
Assert.assertEquals(2.71828, metadata.getDouble("key4"))
21+
}
22+
23+
@Test
24+
fun testGetNonExistentKey() {
25+
Assert.assertNull(metadata.getString("key5"))
26+
}
27+
28+
@Test
29+
fun testInvalidType() {
30+
Assert.assertNull(metadata.getString("key2"))
31+
Assert.assertNull(metadata.getInt("key3"))
32+
Assert.assertNull(metadata.getBoolean("key4"))
33+
Assert.assertNull(metadata.getDouble("key1"))
34+
}
35+
}

android/src/test/java/dev/openfeature/sdk/FlagEvaluationsTests.kt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ class FlagEvaluationsTests {
7676
Assert.assertEquals(booleanDetails, client.getBooleanDetails(key, false))
7777
Assert.assertEquals(booleanDetails, client.getBooleanDetails(key, false, FlagEvaluationOptions()))
7878

79-
val stringDetails = FlagEvaluationDetails(key, "tset")
79+
// in DoSomethingProvider, the string evaluation is special since it contains some metadata values
80+
val stringDetails = FlagEvaluationDetails(key, "tset", metadata = DoSomethingProvider.evaluationMetadata)
8081
Assert.assertEquals(stringDetails, client.getStringDetails(key, "test"))
8182
Assert.assertEquals(stringDetails, client.getStringDetails(key, "test", FlagEvaluationOptions()))
8283

@@ -93,6 +94,18 @@ class FlagEvaluationsTests {
9394
Assert.assertEquals(objectDetails, client.getObjectDetails(key, Value.Structure(mapOf()), FlagEvaluationOptions()))
9495
}
9596

97+
@Test
98+
fun testMetadataFlagEvaluation() = runTest {
99+
OpenFeatureAPI.setProvider(DoSomethingProvider())
100+
val client = OpenFeatureAPI.getClient()
101+
val key = "key"
102+
103+
val details = client.getStringDetails(key, "default")
104+
val metadata: EvaluationMetadata = details.metadata
105+
Assert.assertEquals("value1", metadata.getString("key1"))
106+
Assert.assertEquals(42, metadata.getInt("key2"))
107+
}
108+
96109
@Test
97110
fun testHooksAreFired() = runTest {
98111
OpenFeatureAPI.setProvider(NoOpProvider())

0 commit comments

Comments
 (0)