Skip to content

Commit

Permalink
refactor(stove-serde): arrow additions to the interface
Browse files Browse the repository at this point in the history
  • Loading branch information
osoykan committed Nov 29, 2024
1 parent 856724f commit 36b64d1
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 3 deletions.
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ subprojects.of("lib", "spring", "examples", "ktor") {
testImplementation(libs.kotest.runner.junit5)
testImplementation(libs.kotest.framework.api)
testImplementation(libs.kotest.property)
testImplementation(libs.kotest.arrow)
detektPlugins(libs.detekt.formatting)
}

Expand Down
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ kotest-runner-junit5 = { module = "io.kotest:kotest-runner-junit5", version.ref
kotest-property = { module = "io.kotest:kotest-property", version.ref = "kotest" }
kotest-framework-api = { module = "io.kotest:kotest-framework-api", version.ref = "kotest" }
ktor-server-tests-jvm = { module = "io.ktor:ktor-server-tests-jvm", version.ref = "ktor" }
kotest-arrow = { module = "io.kotest.extensions:kotest-assertions-arrow", version = "1.4.0" }

[bundles]
arrow-stack = ["arrow-core",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.trendyol.stove.testing.e2e.serialization

import arrow.core.*

/**
* Generic interface for serialization and deserialization operations.
*
Expand All @@ -25,6 +27,17 @@ interface StoveSerde<TIn : Any, TOut : Any> {
*/
fun <T : TIn> deserialize(value: TOut, clazz: Class<T>): T

/**
* Deserializes data from the target format into the specified type.
* Returns an [Either] to indicate success or failure.
* @param value The serialized data to deserialize
* @param clazz The target class to deserialize into
* @return The deserialized object or a [StoveSerdeProblem]
*/
fun <T : TIn> deserializeEither(value: TOut, clazz: Class<T>): Either<StoveSerdeProblem, T> = Either
.catch { deserialize(value, clazz) }
.mapLeft { StoveSerdeProblem.BecauseOfDeserialization(it.message ?: "Deserialization failed", it) }

/**
* Companion object containing default configurations and utility functions
*/
Expand All @@ -35,8 +48,36 @@ interface StoveSerde<TIn : Any, TOut : Any> {

val kotlinx = StoveKotlinx

inline fun <TIn : Any, TOut : Any, reified T : TIn> StoveSerde<TIn, TOut>.deserialize(
value: TOut
): T = deserialize(value, T::class.java)
/**
* Deserializes data from the target format into the specified type.
*/
inline fun <reified T : Any> StoveSerde<Any, ByteArray>.deserialize(value: ByteArray): T = deserialize(value, T::class.java)

/**
* Deserializes data from the target format into the specified type.
* Returns a [None] if deserialization fails.
*/
inline fun <reified T : Any> StoveSerde<Any, ByteArray>.deserializeOption(value: ByteArray): Option<T> =
deserializeEither(value, T::class.java).getOrNone()

/**
* Deserializes data from the target format into the specified type.
*/
inline fun <reified T : Any> StoveSerde<Any, String>.deserialize(value: String): T = deserialize(value, T::class.java)

/**
* Deserializes data from the target format into the specified type.
* Returns a [None] if deserialization fails.
*/
inline fun <reified T : Any> StoveSerde<Any, String>.deserializeOption(value: String): Option<T> =
deserializeEither(value, T::class.java).getOrNone()
}

sealed class StoveSerdeProblem(message: String, cause: Throwable? = null) : RuntimeException(message, cause) {
class BecauseOfSerialization(message: String, cause: Throwable? = null) : StoveSerdeProblem(message, cause)

class BecauseOfDeserialization(message: String, cause: Throwable? = null) : StoveSerdeProblem(message, cause)

class BecauseOfDeserializationButExpected(message: String, cause: Throwable? = null) : StoveSerdeProblem(message, cause)
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package com.trendyol.stove.testing.e2e.serialization

import arrow.core.None
import com.fasterxml.jackson.core.JsonParseException
import com.fasterxml.jackson.databind.MapperFeature
import com.google.gson.JsonSyntaxException
import com.trendyol.stove.testing.e2e.serialization.StoveSerde.Companion.deserialize
import com.trendyol.stove.testing.e2e.serialization.StoveSerde.Companion.deserializeOption
import com.trendyol.stove.testing.e2e.serialization.StoveSerde.StoveSerdeProblem
import io.kotest.assertions.arrow.core.shouldBeLeft
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.string.*
import io.kotest.matchers.types.shouldBeInstanceOf
import kotlinx.serialization.*

class SerializerTest : FunSpec({
Expand Down Expand Up @@ -53,6 +59,18 @@ class SerializerTest : FunSpec({
serializer.deserialize("invalid json", TestData::class.java)
}
}

test("should return None when invalid JSON is deserialized") {
val a = serializer.deserializeOption<TestData>("invalid json")
a shouldBe None
}

test("should return Left when invalid JSON is deserialized") {
val op = serializer.deserializeEither("invalid json", TestData::class.java)
op.shouldBeLeft()
op.value.message shouldContain "Unrecognized token 'invalid': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false')"
op.value.shouldBeInstanceOf<StoveSerdeProblem.BecauseOfDeserialization>()
}
}

context("StoveGsonStringSerializer") {
Expand Down Expand Up @@ -89,8 +107,10 @@ class SerializerTest : FunSpec({
test("should serialize and deserialize object correctly") {
val serialized = serializer.serialize(testData)
val deserialized = serializer.deserialize(serialized, TestData::class.java)
val deserializedTyped = serializer.deserialize<TestData>(serialized)

deserialized shouldBe testData
deserializedTyped shouldBe testData
serialized shouldContain "\"id\":1"
serialized shouldContain "\"name\":\"Test Item\""
}
Expand Down

0 comments on commit 36b64d1

Please sign in to comment.