From 1723ebc50fc32b32d284bb2675033835a7754d61 Mon Sep 17 00:00:00 2001 From: Thorsten Hake Date: Sun, 28 Jan 2024 16:15:50 +0100 Subject: [PATCH] Generalize encoding/decoding tests (#168) * removed duplicate decoding tests and generalized tests to be used for other decoders * fixed decoding of short values * fixed decoding of fixed values --- .../avro4k/decoder/RecordDecoder.kt | 11 + .../avrokotlin/avro4k/RecordBuilderForTest.kt | 44 ++++ .../avro4k/decoder/ArrayDecoderTest.kt | 246 ++++++------------ .../decoder/AvroDefaultValuesDecoderTest.kt | 32 ++- .../avro4k/decoder/AvroInlineDecoderTest.kt | 28 -- .../avro4k/decoder/AvroNameDecoderTest.kt | 23 -- .../avro4k/decoder/BasicDecoderTest.kt | 75 ------ .../avro4k/decoder/BigDecimalDecoderTest.kt | 66 ----- .../avro4k/decoder/BigIntegerDecoderTest.kt | 32 --- .../avro4k/decoder/ByteArrayDecoderTest.kt | 130 +++------ .../avro4k/decoder/DateDecoderTest.kt | 92 ------- .../avrokotlin/avro4k/decoder/DecodeUtf8.kt | 22 ++ .../avro4k/decoder/EnumDecoderTest.kt | 36 --- .../avro4k/decoder/EnumDefaultDecoderTest.kt | 35 --- .../avro4k/decoder/FixedDecoderTest.kt | 37 --- .../avro4k/decoder/MapDecoderTest.kt | 108 -------- .../decoder/NamingStrategyDecoderTest.kt | 37 --- .../avro4k/decoder/NullableDecoderTest.kt | 85 ------ .../avro4k/decoder/SealedClassDecoderTest.kt | 35 --- .../avro4k/decoder/TransientDecoderTest.kt | 22 -- .../avro4k/decoder/URLDecoderTest.kt | 32 +-- .../avro4k/decoder/UUIDDecoderTest.kt | 56 +--- .../avro4k/decoder/ValueClassDecoderTest.kt | 25 -- .../avro4k/encoder/ArrayEncoderTest.kt | 127 --------- .../avro4k/encoder/AvroInlineEncoderTest.kt | 28 -- .../avro4k/encoder/AvroNameEncoderTest.kt | 20 -- .../avro4k/encoder/BasicEncoderTest.kt | 99 ------- .../avro4k/encoder/BigDecimalEncoderTest.kt | 90 ------- .../avro4k/encoder/BigIntegerEncoderTest.kt | 41 --- .../avro4k/encoder/ByteArrayEncoderTest.kt | 51 ---- .../avro4k/encoder/DateEncoderTest.kt | 107 -------- .../avro4k/encoder/EnumEncoderTest.kt | 34 --- .../avro4k/encoder/FixedEncoderTest.kt | 46 ---- .../avro4k/encoder/MapEncoderTest.kt | 68 ----- .../encoder/NamingStrategyEncoderTest.kt | 42 --- .../avro4k/encoder/NestedClassEncoderTest.kt | 65 ----- .../avro4k/encoder/NullableEncoderTest.kt | 35 --- .../avro4k/encoder/SealedClassEncoderTest.kt | 44 ---- .../avro4k/encoder/TransientEncoderTest.kt | 21 -- .../avro4k/encoder/URLEncoderTest.kt | 40 --- .../avro4k/encoder/UUIDEncoderTest.kt | 51 ---- .../avro4k/encoder/ValueClassEncoderTest.kt | 23 -- .../avro4k/endecode/ArrayEncoderTest.kt | 57 ++++ .../avro4k/endecode/AvroInlineEncoderTest.kt | 32 +++ .../avro4k/endecode/AvroNameEncoderTest.kt | 22 ++ .../avro4k/endecode/BigDecimalEncoderTest.kt | 74 ++++++ .../avro4k/endecode/BigIntegerEncoderTest.kt | 38 +++ .../avro4k/endecode/ByteArrayEncoderTest.kt | 56 ++++ .../avro4k/endecode/DateEncoderTest.kt | 96 +++++++ .../avrokotlin/avro4k/endecode/EnDecoder.kt | 125 +++++++++ .../avro4k/endecode/EnumEncoderTest.kt | 40 +++ .../avro4k/endecode/MapEncoderTest.kt | 75 ++++++ .../endecode/NamingStrategyEncoderTest.kt | 38 +++ .../avro4k/endecode/RecordEncodingTests.kt | 83 ++++++ .../avro4k/endecode/SealedClassEncoderTest.kt | 37 +++ .../avro4k/endecode/TransientEncoderTest.kt | 32 +++ .../avro4k/endecode/URLEncoderTest.kt | 36 +++ .../avro4k/endecode/UUIDEncoderTest.kt | 36 +++ .../avro4k/endecode/ValueClassEncoderTest.kt | 25 ++ 59 files changed, 1136 insertions(+), 2107 deletions(-) create mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/RecordBuilderForTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/decoder/AvroInlineDecoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/decoder/AvroNameDecoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/decoder/BasicDecoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/decoder/BigDecimalDecoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/decoder/BigIntegerDecoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/decoder/DateDecoderTest.kt create mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/decoder/DecodeUtf8.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/decoder/EnumDecoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/decoder/EnumDefaultDecoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/decoder/FixedDecoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/decoder/MapDecoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/decoder/NamingStrategyDecoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/decoder/NullableDecoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/decoder/SealedClassDecoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/decoder/TransientDecoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/decoder/ValueClassDecoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/encoder/ArrayEncoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/encoder/AvroInlineEncoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/encoder/AvroNameEncoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/encoder/BasicEncoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/encoder/BigDecimalEncoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/encoder/BigIntegerEncoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/encoder/ByteArrayEncoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/encoder/DateEncoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/encoder/EnumEncoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/encoder/FixedEncoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/encoder/MapEncoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/encoder/NamingStrategyEncoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/encoder/NestedClassEncoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/encoder/NullableEncoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/encoder/SealedClassEncoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/encoder/TransientEncoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/encoder/URLEncoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/encoder/UUIDEncoderTest.kt delete mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/encoder/ValueClassEncoderTest.kt create mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/endecode/ArrayEncoderTest.kt create mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/endecode/AvroInlineEncoderTest.kt create mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/endecode/AvroNameEncoderTest.kt create mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/endecode/BigDecimalEncoderTest.kt create mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/endecode/BigIntegerEncoderTest.kt create mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/endecode/ByteArrayEncoderTest.kt create mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/endecode/DateEncoderTest.kt create mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/endecode/EnDecoder.kt create mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/endecode/EnumEncoderTest.kt create mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/endecode/MapEncoderTest.kt create mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/endecode/NamingStrategyEncoderTest.kt create mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/endecode/RecordEncodingTests.kt create mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/endecode/SealedClassEncoderTest.kt create mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/endecode/TransientEncoderTest.kt create mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/endecode/URLEncoderTest.kt create mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/endecode/UUIDEncoderTest.kt create mode 100644 src/test/kotlin/com/github/avrokotlin/avro4k/endecode/ValueClassEncoderTest.kt diff --git a/src/main/kotlin/com/github/avrokotlin/avro4k/decoder/RecordDecoder.kt b/src/main/kotlin/com/github/avrokotlin/avro4k/decoder/RecordDecoder.kt index 5856ea0d..46b9eab1 100644 --- a/src/main/kotlin/com/github/avrokotlin/avro4k/decoder/RecordDecoder.kt +++ b/src/main/kotlin/com/github/avrokotlin/avro4k/decoder/RecordDecoder.kt @@ -15,6 +15,7 @@ import kotlinx.serialization.encoding.CompositeDecoder import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.modules.SerializersModule import org.apache.avro.Schema +import org.apache.avro.generic.GenericFixed import org.apache.avro.generic.GenericRecord import java.nio.ByteBuffer @@ -60,6 +61,7 @@ class RecordDecoder( is Array<*> -> ByteArrayDecoder((value as Array).toByteArray(), serializersModule) is ByteArray -> ByteArrayDecoder(value, serializersModule) is ByteBuffer -> ByteArrayDecoder(value.array(), serializersModule) + is GenericFixed -> ByteArrayDecoder(value.bytes(), serializersModule) else -> this } } else { @@ -160,6 +162,15 @@ class RecordDecoder( } } + override fun decodeShort(): Short { + return when (val v = fieldValue()) { + is Short -> v + is Int -> v.toShort() + null -> throw SerializationException("Cannot decode as a Short") + else -> throw SerializationException("Unsupported type for Short ${v.javaClass}") + } + } + override fun decodeLong(): Long { return when (val v = fieldValue()) { is Long -> v diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/RecordBuilderForTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/RecordBuilderForTest.kt new file mode 100644 index 00000000..ed0e3541 --- /dev/null +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/RecordBuilderForTest.kt @@ -0,0 +1,44 @@ +package com.github.avrokotlin.avro4k + +import org.apache.avro.Schema +import org.apache.avro.generic.GenericData +import org.apache.avro.generic.GenericRecord + +data class RecordBuilderForTest( + val fields: List +) { + fun createRecord(schema: Schema): GenericRecord { + val record = GenericData.Record(schema) + fields.forEachIndexed { index, value -> + val fieldSchema = schema.fields[index].schema() + record.put(index, convertValue(value, fieldSchema)) + } + return record + } + + private fun convertValue( + value: Any?, + schema: Schema + ): Any? { + return when (value) { + is RecordBuilderForTest -> value.createRecord(schema) + is Map<*, *> -> createMap(schema, value) + is List<*> -> createList(schema, value) + else -> value + } + } + + fun createList(schema: Schema, value: List<*>): List<*> { + val valueSchema = schema.elementType + return value.map { convertValue(it, valueSchema) } + } + + fun createMap(schema: Schema, value: Map): Map { + val valueSchema = schema.valueType + return value.mapValues { convertValue(it.value, valueSchema) } + } +} + +fun record(vararg fields: Any?): RecordBuilderForTest { + return RecordBuilderForTest(listOf(*fields)) +} \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/ArrayDecoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/ArrayDecoderTest.kt index 8577e449..81216e72 100644 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/ArrayDecoderTest.kt +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/ArrayDecoderTest.kt @@ -1,8 +1,8 @@ package com.github.avrokotlin.avro4k.decoder import com.github.avrokotlin.avro4k.Avro -import io.kotest.matchers.shouldBe import io.kotest.core.spec.style.WordSpec +import io.kotest.matchers.shouldBe import kotlinx.serialization.Serializable import org.apache.avro.Schema import org.apache.avro.generic.GenericData @@ -30,166 +30,90 @@ data class Record(val str: String, val double: Double) class ArrayDecoderTest : WordSpec({ - "Decoder" should { - - "support array for an Array of booleans" { - val schema = Avro.default.schema(TestArrayBooleans.serializer()) - val record = GenericData.Record(schema) - record.put("booleans", arrayOf(true, false, true)) - Avro.default.fromRecord(TestArrayBooleans.serializer(), record).booleans.toList() shouldBe - listOf(true, false, true) - } - - "support list for an Array of booleans" { - val schema = Avro.default.schema(TestArrayBooleans.serializer()) - val record = GenericData.Record(schema) - record.put("booleans", listOf(true, false, true)) - Avro.default.fromRecord(TestArrayBooleans.serializer(), record).booleans.toList() shouldBe - listOf(true, false, true) - } - - "support GenericData.Array for an Array of booleans" { - val schema = Avro.default.schema(TestArrayBooleans.serializer()) - val record = GenericData.Record(schema) - record.put("booleans", - GenericData.Array(Schema.createArray(Schema.create(Schema.Type.BOOLEAN)), listOf(true, false, true))) - Avro.default.fromRecord(TestArrayBooleans.serializer(), record).booleans.toList() shouldBe - listOf(true, false, true) - } - - "support array for a List of doubles" { - - val schema = Avro.default.schema(TestListDoubles.serializer()) - val record = GenericData.Record(schema) - record.put("doubles", arrayOf(12.54, 23.5, 9123.2314)) - Avro.default.fromRecord(TestListDoubles.serializer(), record) shouldBe - TestListDoubles(listOf(12.54, 23.5, 9123.2314)) - } - - "support list for a List of doubles" { - - val schema = Avro.default.schema(TestListDoubles.serializer()) - val record = GenericData.Record(schema) - record.put("doubles", listOf(12.54, 23.5, 9123.2314)) - Avro.default.fromRecord(TestListDoubles.serializer(), record) shouldBe - TestListDoubles(listOf(12.54, 23.5, 9123.2314)) - } - - "support GenericData.Array for a List of doubles" { - - val schema = Avro.default.schema(TestListDoubles.serializer()) - val record = GenericData.Record(schema) - record.put("doubles", - GenericData.Array(Schema.createArray(Schema.create(Schema.Type.DOUBLE)), listOf(12.54, 23.5, 9123.2314))) - Avro.default.fromRecord(TestListDoubles.serializer(), record) shouldBe - TestListDoubles(listOf(12.54, 23.5, 9123.2314)) - } - - "support array for a List of records" { - - val containerSchema = Avro.default.schema(TestListRecords.serializer()) - val recordSchema = Avro.default.schema(Record.serializer()) - - val record1 = GenericData.Record(recordSchema) - record1.put("str", "qwe") - record1.put("double", 123.4) - - val record2 = GenericData.Record(recordSchema) - record2.put("str", "wer") - record2.put("double", 8234.324) - - val container = GenericData.Record(containerSchema) - container.put("records", arrayOf(record1, record2)) - - Avro.default.fromRecord(TestListRecords.serializer(), container) shouldBe - TestListRecords(listOf(Record("qwe", 123.4), Record("wer", 8234.324))) - } - - "support list for a List of records" { - - val containerSchema = Avro.default.schema(TestListRecords.serializer()) - val recordSchema = Avro.default.schema(Record.serializer()) - - val record1 = GenericData.Record(recordSchema) - record1.put("str", "qwe") - record1.put("double", 123.4) - - val record2 = GenericData.Record(recordSchema) - record2.put("str", "wer") - record2.put("double", 8234.324) - - val container = GenericData.Record(containerSchema) - container.put("records", listOf(record1, record2)) - - Avro.default.fromRecord(TestListRecords.serializer(), container) shouldBe - TestListRecords(listOf(Record("qwe", 123.4), Record("wer", 8234.324))) - } - - "support array for a Set of records" { - - val containerSchema = Avro.default.schema(TestSetRecords.serializer()) - val recordSchema = Avro.default.schema(Record.serializer()) - - val record1 = GenericData.Record(recordSchema) - record1.put("str", "qwe") - record1.put("double", 123.4) - - val record2 = GenericData.Record(recordSchema) - record2.put("str", "wer") - record2.put("double", 8234.324) - - val container = GenericData.Record(containerSchema) - container.put("records", arrayOf(record1, record2)) - - Avro.default.fromRecord(TestSetRecords.serializer(), container) shouldBe - TestSetRecords(setOf(Record("qwe", 123.4), Record("wer", 8234.324))) - } - - "support GenericData.Array for a Set of records" { - - val containerSchema = Avro.default.schema(TestSetRecords.serializer()) - val recordSchema = Avro.default.schema(Record.serializer()) - - val record1 = GenericData.Record(recordSchema) - record1.put("str", "qwe") - record1.put("double", 123.4) - - val record2 = GenericData.Record(recordSchema) - record2.put("str", "wer") - record2.put("double", 8234.324) - - val container = GenericData.Record(containerSchema) - container.put("records", - GenericData.Array(Schema.createArray(Schema.create(Schema.Type.STRING)), listOf(record1, record2))) - - Avro.default.fromRecord(TestSetRecords.serializer(), container) shouldBe - TestSetRecords(setOf(Record("qwe", 123.4), Record("wer", 8234.324))) - } - - "support array for a Set of strings" { - val schema = Avro.default.schema(TestSetString.serializer()) - val record = GenericData.Record(schema) - record.put("strings", arrayOf("Qwe", "324", "q")) - Avro.default.fromRecord(TestSetString.serializer(), record) shouldBe - TestSetString(setOf("Qwe", "324", "q")) - } - - "support list for a Set of strings" { - val schema = Avro.default.schema(TestSetString.serializer()) - val record = GenericData.Record(schema) - record.put("strings", arrayOf("Qwe", "324", "q")) - Avro.default.fromRecord(TestSetString.serializer(), record) shouldBe - TestSetString(setOf("Qwe", "324", "q")) - } - - "support GenericData.Array for a Set of strings" { - val schema = Avro.default.schema(TestSetString.serializer()) - val record = GenericData.Record(schema) - record.put("strings", - GenericData.Array(Schema.createArray(Schema.create(Schema.Type.STRING)), listOf("Qwe", "324", "q"))) - Avro.default.fromRecord(TestSetString.serializer(), record) shouldBe - TestSetString(setOf("Qwe", "324", "q")) + "Decoder" should { + listOf( + "array" to arrayOf(true, false, true), + "list" to listOf(true, false, true), + "GenericData.Array" to GenericData.Array( + Schema.createArray(Schema.create(Schema.Type.BOOLEAN)), listOf(true, false, true) + ) + ).forEach { + "support ${it.first} for an Array of booleans" { + val schema = Avro.default.schema(TestArrayBooleans.serializer()) + val record = GenericData.Record(schema) + record.put("booleans", it.second) + Avro.default.fromRecord(TestArrayBooleans.serializer(), record).booleans.toList() shouldBe listOf( + true, false, true + ) + } + } + listOf( + "array" to arrayOf(12.54, 23.5, 9123.2314), + "list" to listOf(12.54, 23.5, 9123.2314), + "GenericData.Array" to GenericData.Array( + Schema.createArray(Schema.create(Schema.Type.DOUBLE)), listOf(12.54, 23.5, 9123.2314) + ) + ).forEach { + "support ${it.first} for a List of doubles" { + val schema = Avro.default.schema(TestListDoubles.serializer()) + val record = GenericData.Record(schema) + record.put("doubles", it.second) + Avro.default.fromRecord(TestListDoubles.serializer(), record) shouldBe TestListDoubles( + listOf( + 12.54, 23.5, 9123.2314 + ) + ) + } + } + val recordSchema = Avro.default.schema(Record.serializer()) + val records = listOf(GenericData.Record(recordSchema).apply { + put("str", "qwe") + put("double", 123.4) + }, GenericData.Record(recordSchema).apply { + put("str", "wer") + put("double", 8234.324) + }) + listOf( + "array" to records.toTypedArray(), + "list" to records, + "GenericData.Array" to GenericData.Array( + Schema.createArray(recordSchema), records + ) + ).forEach { + "support ${it.first} for a List of records" { + val containerSchema = Avro.default.schema(TestListRecords.serializer()) + val container = GenericData.Record(containerSchema) + container.put("records", it.second) + + Avro.default.fromRecord( + TestListRecords.serializer(), container + ) shouldBe TestListRecords(listOf(Record("qwe", 123.4), Record("wer", 8234.324))) + } + "support ${it.first} for a Set of records" { + val containerSchema = Avro.default.schema(TestSetRecords.serializer()) + val container = GenericData.Record(containerSchema) + container.put("records", it.second) + + Avro.default.fromRecord( + TestSetRecords.serializer(), container + ) shouldBe TestSetRecords(setOf(Record("qwe", 123.4), Record("wer", 8234.324))) + } + } + + listOf( + "array" to arrayOf("Qwe", "324", "q"), + "list" to listOf("Qwe", "324", "q"), + "GenericData.Array" to GenericData.Array( + Schema.createArray(Schema.create(Schema.Type.STRING)), listOf("Qwe", "324", "q") + ) + ).forEach { + "support ${it.first} for a Set of strings" { + val schema = Avro.default.schema(TestSetString.serializer()) + val record = GenericData.Record(schema) + record.put("strings", it.second) + Avro.default.fromRecord(TestSetString.serializer(), record) shouldBe TestSetString(setOf("Qwe", "324", "q")) + } + } } - } }) \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/AvroDefaultValuesDecoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/AvroDefaultValuesDecoderTest.kt index f04a17ca..73213729 100644 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/AvroDefaultValuesDecoderTest.kt +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/AvroDefaultValuesDecoderTest.kt @@ -1,9 +1,6 @@ package com.github.avrokotlin.avro4k.decoder -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.AvroDefault -import com.github.avrokotlin.avro4k.AvroName -import com.github.avrokotlin.avro4k.ScalePrecision +import com.github.avrokotlin.avro4k.* import com.github.avrokotlin.avro4k.io.AvroDecodeFormat import com.github.avrokotlin.avro4k.serializer.BigDecimalSerializer import io.kotest.core.spec.style.FunSpec @@ -51,6 +48,23 @@ data class ContainerWithDefaultFields( @Serializable(BigDecimalSerializer::class) val bigDecimal : BigDecimal ) +@Serializable +@AvroEnumDefault("UNKNOWN") +enum class EnumWithDefault { + UNKNOWN, A +} + +@Serializable +@AvroEnumDefault("UNKNOWN") +enum class FutureEnumWithDefault { + UNKNOWN, A, C +} + +@Serializable +data class Wrap(val value: EnumWithDefault) + +@Serializable +data class FutureWrap(val value: FutureEnumWithDefault) class AvroDefaultValuesDecoderTest : FunSpec({ test("test default values correctly decoded") { @@ -73,5 +87,15 @@ class AvroDefaultValuesDecoderTest : FunSpec({ deserialized.emptyFooList.shouldBeEmpty() deserialized.filledFooList.shouldContainExactly(FooElement("bar")) deserialized.bigDecimal.shouldBe(BigDecimal.ZERO) + + } + test("Decoding enum with an unknown or future value uses default value") { + val encoded = Avro.default.encodeToByteArray( + FutureWrap.serializer(), + FutureWrap(FutureEnumWithDefault.C) + ) + val decoded = Avro.default.decodeFromByteArray(Wrap.serializer(), encoded) + + decoded shouldBe Wrap(EnumWithDefault.UNKNOWN) } }) \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/AvroInlineDecoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/AvroInlineDecoderTest.kt deleted file mode 100644 index ead21411..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/AvroInlineDecoderTest.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.github.avrokotlin.avro4k.decoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.AvroInline -import com.github.avrokotlin.avro4k.ListRecord -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec -import kotlinx.serialization.Serializable -import org.apache.avro.util.Utf8 - -class AvroInlineDecoderTest : FunSpec({ - - test("decode @AvroInline") { - - val schema = Avro.default.schema(Product.serializer()) - val record = ListRecord(schema, listOf(Utf8("123"), Utf8("sneakers"))) - Avro.default.fromRecord(Product.serializer(), record) shouldBe Product("123", Name("sneakers")) - } - -}) { - - @Serializable - @AvroInline - data class Name(val value: String) - - @Serializable - data class Product(val id: String, val name: Name) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/AvroNameDecoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/AvroNameDecoderTest.kt deleted file mode 100644 index f501d93c..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/AvroNameDecoderTest.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.github.avrokotlin.avro4k.decoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.AvroName -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec -import kotlinx.serialization.Serializable -import org.apache.avro.generic.GenericData -import org.apache.avro.util.Utf8 - -class AvroNameDecoderTest : FunSpec({ - - test("decoder should take into account @AvroName on fields") { - val schema = Avro.default.schema(Foo.serializer()) - val record = GenericData.Record(schema) - record.put("bar", Utf8("hello")) - Avro.default.fromRecord(Foo.serializer(), record) shouldBe Foo("hello") - } -}) { - - @Serializable - data class Foo(@AvroName("bar") val foo: String) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/BasicDecoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/BasicDecoderTest.kt deleted file mode 100644 index db5261ba..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/BasicDecoderTest.kt +++ /dev/null @@ -1,75 +0,0 @@ -package com.github.avrokotlin.avro4k.decoder - -import com.github.avrokotlin.avro4k.Avro -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec -import kotlinx.serialization.Serializable -import org.apache.avro.generic.GenericData - -@Serializable -data class FooString(val str: String) - -@Serializable -data class FooDouble(val d: Double) - -@Serializable -data class FooBoolean(val b: Boolean) - -@Serializable -data class FooFloat(val f: Float) - -@Serializable -data class FooLong(val l: Long) - -@Serializable -data class FooInt(val i: Int) - -@Serializable -data class FooByte(val b: Byte) - -class BasicDecoderTest : FunSpec({ - - test("decode strings") { - val schema = Avro.default.schema(FooString.serializer()) - val record = GenericData.Record(schema) - record.put("str", "hello") - Avro.default.fromRecord(FooString.serializer(), record) shouldBe FooString("hello") - } - test("decode longs") { - val schema = Avro.default.schema(FooLong.serializer()) - val record = GenericData.Record(schema) - record.put("l", 123456L) - Avro.default.fromRecord(FooLong.serializer(), record) shouldBe FooLong(123456L) - } - test("decode doubles") { - val schema = Avro.default.schema(FooDouble.serializer()) - val record = GenericData.Record(schema) - record.put("d", 123.435) - Avro.default.fromRecord(FooDouble.serializer(), record) shouldBe FooDouble(123.435) - } - test("decode booleans") { - val schema = Avro.default.schema(FooBoolean.serializer()) - val record = GenericData.Record(schema) - record.put("b", true) - Avro.default.fromRecord(FooBoolean.serializer(), record) shouldBe FooBoolean(true) - } - test("decode floats") { - val schema = Avro.default.schema(FooFloat.serializer()) - val record = GenericData.Record(schema) - record.put("f", 123.435F) - Avro.default.fromRecord(FooFloat.serializer(), record) shouldBe FooFloat(123.435F) - } - test("decode ints") { - val schema = Avro.default.schema(FooInt.serializer()) - val record = GenericData.Record(schema) - record.put("i", 123) - Avro.default.fromRecord(FooInt.serializer(), record) shouldBe FooInt(123) - } - test("decode bytes") { - val schema = Avro.default.schema(FooByte.serializer()) - val record = GenericData.Record(schema) - record.put("b", 123.toByte()) - Avro.default.fromRecord(FooByte.serializer(), record) shouldBe FooByte(123) - } -}) - diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/BigDecimalDecoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/BigDecimalDecoderTest.kt deleted file mode 100644 index 7f01cb44..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/BigDecimalDecoderTest.kt +++ /dev/null @@ -1,66 +0,0 @@ -@file:UseSerializers(BigDecimalSerializer::class) - -package com.github.avrokotlin.avro4k.decoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.serializer.BigDecimalSerializer -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec -import kotlinx.serialization.Serializable -import kotlinx.serialization.UseSerializers -import org.apache.avro.Conversions -import org.apache.avro.LogicalTypes -import org.apache.avro.Schema -import org.apache.avro.SchemaBuilder -import org.apache.avro.generic.GenericData -import org.apache.avro.util.Utf8 -import java.math.BigDecimal - -class BigDecimalDecoderTest : FunSpec({ - - test("decode big decimals from bytes") { - - val logical = LogicalTypes.decimal(8, 2) - - val schema = SchemaBuilder.record("Test").fields() - .name("b").type(logical.addToSchema(Schema.create(Schema.Type.BYTES))).noDefault() - .endRecord() - - val bytes = Conversions.DecimalConversion().toBytes(BigDecimal("12.34"), schema.getField("b").schema(), logical) - - val record = GenericData.Record(schema) - record.put("b", bytes) - - Avro.default.fromRecord(Test.serializer(), record) shouldBe Test(BigDecimal("12.34")) - } - - test("decode big decimals from strings") { - - val schema = SchemaBuilder.record("Test").fields() - .name("b").type(Schema.create(Schema.Type.STRING)).noDefault() - .endRecord() - - val record = GenericData.Record(schema) - record.put("b", Utf8("12.34")) - - Avro.default.fromRecord(Test.serializer(), record) shouldBe Test(BigDecimal("12.34")) - } - - test("decode big decimals from fixed") { - - val logical = LogicalTypes.decimal(10, 8) - - val schema = SchemaBuilder.record("Test").fields() - .name("b").type(logical.addToSchema(Schema.createFixed("b", null, null, 8))).noDefault() - .endRecord() - - val record = GenericData.Record(schema) - record.put("b", byteArrayOf(0, 4, 98, -43, 55, 43, -114, 0)) - - Avro.default.fromRecord(Test.serializer(), record) shouldBe Test(BigDecimal("12345678.00000000")) - } -}) { - - @Serializable - data class Test(val b: BigDecimal) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/BigIntegerDecoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/BigIntegerDecoderTest.kt deleted file mode 100644 index 2eb4ffc1..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/BigIntegerDecoderTest.kt +++ /dev/null @@ -1,32 +0,0 @@ -@file:UseSerializers(BigIntegerSerializer::class) - -package com.github.avrokotlin.avro4k.decoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.serializer.BigIntegerSerializer -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec -import kotlinx.serialization.Serializable -import kotlinx.serialization.UseSerializers -import org.apache.avro.Schema -import org.apache.avro.SchemaBuilder -import org.apache.avro.generic.GenericData -import org.apache.avro.util.Utf8 -import java.math.BigInteger - -class BigIntegerDecoderTest : FunSpec({ - - test("decode big integer from string") { - - val schema = SchemaBuilder.record("Test").fields().name("b").type(Schema.create(Schema.Type.STRING)).noDefault().endRecord() - - val record = GenericData.Record(schema) - record.put("b", Utf8("1927398217318546456532973912379127391279312983719")) - - Avro.default.fromRecord(Test.serializer(), record) shouldBe Test(BigInteger("1927398217318546456532973912379127391279312983719")) - } -}) { - - @Serializable - data class Test(val b: BigInteger) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/ByteArrayDecoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/ByteArrayDecoderTest.kt index a87df853..b0070987 100644 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/ByteArrayDecoderTest.kt +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/ByteArrayDecoderTest.kt @@ -1,105 +1,51 @@ package com.github.avrokotlin.avro4k.decoder import com.github.avrokotlin.avro4k.Avro +import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec import kotlinx.serialization.Serializable +import org.apache.avro.Schema import org.apache.avro.generic.GenericData import java.nio.ByteBuffer -class ByteArrayDecoderTest : FunSpec({ - - test("decode ByteBuffer to ByteArray") { - val schema = Avro.default.schema(ByteArrayTest.serializer()) - val record = GenericData.Record(schema) - record.put("z", ByteBuffer.wrap(byteArrayOf(1, 4, 9))) - Avro.default.fromRecord(ByteArrayTest.serializer(), record).z shouldBe byteArrayOf(1, 4, 9) - } - - test("decode ByteBuffer to List") { - val schema = Avro.default.schema(ListByteTest.serializer()) - val record = GenericData.Record(schema) - record.put("z", ByteBuffer.wrap(byteArrayOf(1, 4, 9))) - Avro.default.fromRecord(ListByteTest.serializer(), record).z shouldBe listOf(1, 4, 9) - } - - test("decode ByteBuffer to Array") { - val schema = Avro.default.schema(ArrayByteTest.serializer()) - val record = GenericData.Record(schema) - record.put("z", ByteBuffer.wrap(byteArrayOf(1, 4, 9))) - Avro.default.fromRecord(ArrayByteTest.serializer(), record).z shouldBe arrayOf(1, 4, 9) - } - - test("decode ByteArray to ByteArray") { - val schema = Avro.default.schema(ByteArrayTest.serializer()) - val record = GenericData.Record(schema) - record.put("z", byteArrayOf(1, 4, 9)) - Avro.default.fromRecord(ByteArrayTest.serializer(), record).z shouldBe byteArrayOf(1, 4, 9) - } - - test("decode ByteArray to List") { - val schema = Avro.default.schema(ListByteTest.serializer()) - val record = GenericData.Record(schema) - record.put("z", byteArrayOf(1, 4, 9)) - Avro.default.fromRecord(ListByteTest.serializer(), record).z shouldBe listOf(1, 4, 9) - } - - test("decode ByteArray to Array") { - val schema = Avro.default.schema(ArrayByteTest.serializer()) - val record = GenericData.Record(schema) - record.put("z", byteArrayOf(1, 4, 9)) - Avro.default.fromRecord(ArrayByteTest.serializer(), record).z shouldBe arrayOf(1, 4, 9) - } - - test("decode Array to ByteArray") { - val schema = Avro.default.schema(ByteArrayTest.serializer()) - val record = GenericData.Record(schema) - record.put("z", arrayOf(1, 4, 9)) - Avro.default.fromRecord(ByteArrayTest.serializer(), record).z shouldBe byteArrayOf(1, 4, 9) - } - - test("decode Array to List") { - val schema = Avro.default.schema(ListByteTest.serializer()) - val record = GenericData.Record(schema) - record.put("z", arrayOf(1, 4, 9)) - Avro.default.fromRecord(ListByteTest.serializer(), record).z shouldBe listOf(1, 4, 9) - } - - test("decode Array to Array") { - val schema = Avro.default.schema(ArrayByteTest.serializer()) - val record = GenericData.Record(schema) - record.put("z", arrayOf(1, 4, 9)) - Avro.default.fromRecord(ArrayByteTest.serializer(), record).z shouldBe arrayOf(1, 4, 9) - } - - test("decode List to ByteArray") { - val schema = Avro.default.schema(ByteArrayTest.serializer()) - val record = GenericData.Record(schema) - record.put("z", listOf(1, 4, 9)) - Avro.default.fromRecord(ByteArrayTest.serializer(), record).z shouldBe byteArrayOf(1, 4, 9) - } - - test("decode List to List") { - val schema = Avro.default.schema(ListByteTest.serializer()) - val record = GenericData.Record(schema) - record.put("z", listOf(1, 4, 9)) - Avro.default.fromRecord(ListByteTest.serializer(), record).z shouldBe listOf(1, 4, 9) - } - - test("decode List to Array") { - val schema = Avro.default.schema(ArrayByteTest.serializer()) - val record = GenericData.Record(schema) - record.put("z", listOf(1, 4, 9)) - Avro.default.fromRecord(ArrayByteTest.serializer(), record).z shouldBe arrayOf(1, 4, 9) - } +class ByteArrayDecoderTest : StringSpec({ + val byteArray = byteArrayOf(1, 4, 9) + listOf( + "ByteBuffer" to ByteBuffer.wrap(byteArray), + "ByteArray" to byteArray, + "Array" to arrayOf(1, 4, 9), + "GenericData.Array" to GenericData.Array( + Schema.createArray(Schema.create(Schema.Type.BYTES)), + byteArray.toList() + ) + ).forEach { + "decode ${it.first} to ByteArray" { + val schema = Avro.default.schema(ByteArrayTest.serializer()) + val record = GenericData.Record(schema) + record.put("z", it.second) + Avro.default.fromRecord(ByteArrayTest.serializer(), record).z shouldBe byteArrayOf(1, 4, 9) + } + "decode ${it.first} to List" { + val schema = Avro.default.schema(ListByteTest.serializer()) + val record = GenericData.Record(schema) + record.put("z", it.second) + Avro.default.fromRecord(ListByteTest.serializer(), record).z shouldBe listOf(1, 4, 9) + } + "decode ${it.first} to Array" { + val schema = Avro.default.schema(ArrayByteTest.serializer()) + val record = GenericData.Record(schema) + record.put("z", it.second) + Avro.default.fromRecord(ArrayByteTest.serializer(), record).z shouldBe arrayOf(1, 4, 9) + } + } }) { - @Serializable - data class ByteArrayTest(val z: ByteArray) + @Serializable + data class ByteArrayTest(val z: ByteArray) - @Serializable - data class ArrayByteTest(val z: Array) + @Serializable + data class ArrayByteTest(val z: Array) - @Serializable - data class ListByteTest(val z: List) + @Serializable + data class ListByteTest(val z: List) } diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/DateDecoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/DateDecoderTest.kt deleted file mode 100644 index 9032d91a..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/DateDecoderTest.kt +++ /dev/null @@ -1,92 +0,0 @@ -@file:UseSerializers( - LocalDateTimeSerializer::class, - LocalDateSerializer::class, - LocalTimeSerializer::class, - TimestampSerializer::class, -) - -package com.github.avrokotlin.avro4k.decoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.serializer.* -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec -import kotlinx.serialization.Serializable -import kotlinx.serialization.UseSerializers -import org.apache.avro.generic.GenericData -import java.sql.Timestamp -import java.time.Instant -import java.time.LocalDate -import java.time.LocalDateTime -import java.time.LocalTime -import java.time.temporal.ChronoUnit - -class DateDecoderTest : FunSpec({ - - test("decode int to LocalTime") { - val schema = Avro.default.schema(WithLocalTime.serializer()) - val record = GenericData.Record(schema) - record.put("z", 46245000) - Avro.default.fromRecord(WithLocalTime.serializer(), record) shouldBe - WithLocalTime(LocalTime.of(12, 50, 45)) - } - - test("decode int to LocalDate") { - val schema = Avro.default.schema(WithLocalDate.serializer()) - val record = GenericData.Record(schema) - record.put("z", 17784) - Avro.default.fromRecord(WithLocalDate.serializer(), record) shouldBe - WithLocalDate(LocalDate.of(2018, 9, 10)) - } - - test("decode long to LocalDateTime") { - val schema = Avro.default.schema(WithLocalDateTime.serializer()) - val record = GenericData.Record(schema) - record.put("z", 1536580739000L) - Avro.default.fromRecord(WithLocalDateTime.serializer(), record) shouldBe - WithLocalDateTime(LocalDateTime.of(2018, 9, 10, 11, 58, 59)) - } - - test("decode long to Timestamp") { - val schema = Avro.default.schema(WithTimestamp.serializer()) - val record = GenericData.Record(schema) - record.put("z", 1538312231000L) - Avro.default.fromRecord(WithTimestamp.serializer(), record) shouldBe - WithTimestamp(Timestamp(1538312231000L)) - } - - test("decode long to Instant") { - val schema = Avro.default.schema(WithInstant.serializer()) - val record = GenericData.Record(schema) - record.put("z", 1538312231000L) - Avro.default.fromRecord(WithInstant.serializer(), record) shouldBe - WithInstant(Instant.ofEpochMilli(1538312231000L)) - } - - test("decode long to Instant with microseconds") { - val schema = Avro.default.schema(WithInstantAndMicros.serializer()) - val record = GenericData.Record(schema) - record.put("z", 1538312231000100L) - Avro.default.fromRecord(WithInstantAndMicros.serializer(), record) shouldBe - WithInstantAndMicros(Instant.ofEpochMilli(1538312231000L).plus(100, ChronoUnit.MICROS)) - } -}) { - - @Serializable - data class WithLocalTime(val z: LocalTime) - - @Serializable - data class WithLocalDate(val z: LocalDate) - - @Serializable - data class WithLocalDateTime(val z: LocalDateTime) - - @Serializable - data class WithTimestamp(val z: Timestamp) - - @Serializable - data class WithInstant(@Serializable(with = InstantSerializer::class) val z: Instant) - - @Serializable - data class WithInstantAndMicros(@Serializable(with = InstantToMicroSerializer::class) val z: Instant) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/DecodeUtf8.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/DecodeUtf8.kt new file mode 100644 index 00000000..f8ad79a4 --- /dev/null +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/DecodeUtf8.kt @@ -0,0 +1,22 @@ +package com.github.avrokotlin.avro4k.decoder + +import com.github.avrokotlin.avro4k.Avro +import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.shouldBe +import kotlinx.serialization.Serializable +import org.apache.avro.generic.GenericData +import org.apache.avro.util.Utf8 + +class DecodeUtf8 : StringSpec({ + "decode utf8" { + @Serializable + data class Foo(val a: String) + + val schema = Avro.default.schema(Foo.serializer()) + + val record = GenericData.Record(schema) + record.put("a", Utf8("utf8-string")) + Avro.default.fromRecord(Foo.serializer(), record) shouldBe Foo("utf8-string") + } +}) { +} \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/EnumDecoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/EnumDecoderTest.kt deleted file mode 100644 index 57c96645..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/EnumDecoderTest.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.github.avrokotlin.avro4k.decoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.schema.Wine -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.StringSpec -import kotlinx.serialization.Serializable -import org.apache.avro.generic.GenericData - -@Serializable -data class MyWine(val wine: Wine) - -@Serializable -data class NullableWine(val wine: Wine?) - -class EnumDecoderTest : StringSpec({ - - "support enums" { - val schema = Avro.default.schema(MyWine.serializer()) - val record = GenericData.Record(schema) - record.put("wine", GenericData.EnumSymbol(schema.getField("wine").schema(), "Malbec")) - Avro.default.fromRecord(MyWine.serializer(), record) shouldBe MyWine(Wine.Malbec) - } - "support nullable enums" { - val schema = Avro.default.schema(NullableWine.serializer()) - - val record1 = GenericData.Record(schema) - record1.put("wine", GenericData.EnumSymbol(schema.getField("wine").schema(), "Shiraz")) - Avro.default.fromRecord(NullableWine.serializer(), record1) shouldBe NullableWine(Wine.Shiraz) - - val record2 = GenericData.Record(schema) - record2.put("wine", null) - Avro.default.fromRecord(NullableWine.serializer(), record2) shouldBe NullableWine(null) - } - -}) \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/EnumDefaultDecoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/EnumDefaultDecoderTest.kt deleted file mode 100644 index f408dfb5..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/EnumDefaultDecoderTest.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.github.avrokotlin.avro4k.decoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.AvroEnumDefault -import kotlinx.serialization.Serializable -import io.kotest.core.spec.style.FunSpec -import io.kotest.matchers.shouldBe - - -class EnumDefaultDecoderTest : FunSpec({ - test("Decoding enum with an unknown or future value uses default value") { - val encoded = Avro.default.encodeToByteArray(FutureWrap.serializer(), FutureWrap(FutureEnumWithDefault.C)) - val decoded = Avro.default.decodeFromByteArray(Wrap.serializer(), encoded) - - decoded shouldBe Wrap(EnumWithDefault.UNKNOWN) - } -}) { - @Serializable - @AvroEnumDefault("UNKNOWN") - enum class EnumWithDefault { - UNKNOWN, A, B - } - - @Serializable - @AvroEnumDefault("UNKNOWN") - enum class FutureEnumWithDefault { - UNKNOWN, A, B, C - } - - @Serializable - data class Wrap(val value: EnumWithDefault) - - @Serializable - data class FutureWrap(val value: FutureEnumWithDefault) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/FixedDecoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/FixedDecoderTest.kt deleted file mode 100644 index 079450e5..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/FixedDecoderTest.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.github.avrokotlin.avro4k.decoder - -import com.github.avrokotlin.avro4k.Avro -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec -import kotlinx.serialization.Serializable -import org.apache.avro.Schema -import org.apache.avro.SchemaBuilder -import org.apache.avro.generic.GenericData - -class FixedDecoderTest : FunSpec({ - - test("decode bytes to String") { - val schema = SchemaBuilder.record("FixedString").fields() - .name("z").type(Schema.createFixed("z", null, "ns", 10)).noDefault() - .endRecord() - val record = GenericData.Record(schema) - record.put("z", byteArrayOf(115, 97, 109)) - Avro.default.fromRecord(FixedString.serializer(), record) shouldBe FixedString("sam") - } - -// test("support nullables of fixed") { -// val schema = AvroSchema[NullableFixedType] -// val record = new GenericData . Record (schema) -// record.put("z", new GenericData . Fixed (AvroSchema[FixedValueType], Array[Byte](115, 97, 109))) -// Decoder[NullableFixedType].decode(record, schema, DefaultFieldMapper) shouldBe NullableFixedType(Some( -// FixedValueType("sam"))) -// } - -}) { - - @Serializable - data class FixedString(val z: String) - - @Serializable - data class NullableFixedType(val z: FixedString?) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/MapDecoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/MapDecoderTest.kt deleted file mode 100644 index 229837bb..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/MapDecoderTest.kt +++ /dev/null @@ -1,108 +0,0 @@ -package com.github.avrokotlin.avro4k.decoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.ListRecord -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.StringSpec -import kotlinx.serialization.Serializable -import org.apache.avro.generic.GenericData -import org.apache.avro.util.Utf8 -import java.nio.ByteBuffer - -class MapDecoderTest : StringSpec({ - - "decode a Map from strings/longs" { - - val schema = Avro.default.schema(MapStringLong.serializer()) - - val record = GenericData.Record(schema) - record.put("a", mapOf("x" to 152134L, "y" to 917823L)) - - Avro.default.fromRecord(MapStringLong.serializer(), record) shouldBe MapStringLong(mapOf("x" to 152134L, "y" to 917823L)) - } - - "decode a Map from utf8s/longs" { - - val schema = Avro.default.schema(MapStringLong.serializer()) - - val record = GenericData.Record(schema) - record.put("a", mapOf(Utf8("x") to 152134L, Utf8("y") to 917823L)) - - Avro.default.fromRecord(MapStringLong.serializer(), record) shouldBe MapStringLong(mapOf("x" to 152134L, "y" to 917823L)) - } - - "decode a Map from utf8s/utf8s" { - - val schema = Avro.default.schema(MapStringString.serializer()) - - val record = GenericData.Record(schema) - record.put("a", mapOf(Utf8("x") to Utf8("a"), Utf8("y") to Utf8("b"))) - - Avro.default.fromRecord(MapStringString.serializer(), record) shouldBe MapStringString(mapOf("x" to "a", "y" to "b")) - } - - "decode a Map from utf8s/ByteBuffer" { - - val schema = Avro.default.schema(MapStringByteArray.serializer()) - - val record = GenericData.Record(schema) - record.put("a", mapOf( - Utf8("a") to ByteBuffer.wrap("x".toByteArray()), - Utf8("b") to ByteBuffer.wrap("y".toByteArray()), - Utf8("c") to ByteBuffer.wrap("z".toByteArray()) - )) - - Avro.default.fromRecord(MapStringByteArray.serializer(), record) shouldBe MapStringByteArray(mapOf( - "a" to "x".toByteArray(), - "b" to "y".toByteArray(), - "c" to "z".toByteArray() - )) - } - - "decode a Map of records" { - - val schema = Avro.default.schema(MapStringStructure.serializer()) - val fooSchema = Avro.default.schema(Foo.serializer()) - - val xRecord = ListRecord(fooSchema, Utf8("x"), true) - val yRecord = ListRecord(fooSchema, Utf8("y"), false) - - val record = GenericData.Record(schema) - record.put("a", mapOf("a" to xRecord, "b" to yRecord)) - - Avro.default.fromRecord(MapStringStructure.serializer(), record) shouldBe - MapStringStructure(mapOf("a" to Foo("x", true), "b" to Foo("y", false))) - } -}) { - - @Serializable - data class MapStringLong(val a: Map) - - @Serializable - data class MapStringString(val a: Map) - - @Serializable - data class MapStringByteArray(val a: Map) { - override fun equals(other: Any?): Boolean{ - if (this === other) return true - if (other?.javaClass != javaClass) return false - - other as MapStringByteArray - - if (a.size != other.a.size) return false - if (a.keys != other.a.keys) return false - - return a.map { - it.value.contentEquals(other.a[it.key]!!) - }.all { it } - } - - override fun hashCode() = a.hashCode() - } - - @Serializable - data class Foo(val a: String, val b: Boolean) - - @Serializable - data class MapStringStructure(val a: Map) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/NamingStrategyDecoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/NamingStrategyDecoderTest.kt deleted file mode 100644 index ecbab66b..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/NamingStrategyDecoderTest.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.github.avrokotlin.avro4k.decoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.AvroConfiguration -import com.github.avrokotlin.avro4k.schema.PascalCaseNamingStrategy -import com.github.avrokotlin.avro4k.schema.SnakeCaseNamingStrategy -import io.kotest.core.spec.style.WordSpec -import io.kotest.matchers.shouldBe -import kotlinx.serialization.Serializable -import org.apache.avro.generic.GenericData -import org.apache.avro.util.Utf8 - -class NamingStrategyDecoderTest : WordSpec({ - "Decoder" should { - - "support decoding fields with snake_casing" { - val snakeCaseAvro = Avro(AvroConfiguration(SnakeCaseNamingStrategy)) - val record = GenericData.Record(snakeCaseAvro.schema(Foo.serializer())).apply { - put("foo_bar",Utf8("hello")) - } - - snakeCaseAvro.fromRecord(Foo.serializer(), record) shouldBe Foo("hello") - } - - "support decoding fields with PascalCasing" { - val pascalCaseAvro = Avro(AvroConfiguration(PascalCaseNamingStrategy)) - val record = GenericData.Record(pascalCaseAvro.schema(Foo.serializer())).apply { - put("FooBar",Utf8("hello")) - } - - pascalCaseAvro.fromRecord(Foo.serializer(), record) shouldBe Foo("hello") - } - } -}) { - @Serializable - data class Foo(val fooBar: String) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/NullableDecoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/NullableDecoderTest.kt deleted file mode 100644 index 1e774931..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/NullableDecoderTest.kt +++ /dev/null @@ -1,85 +0,0 @@ -package com.github.avrokotlin.avro4k.decoder - -import com.github.avrokotlin.avro4k.Avro -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.WordSpec -import kotlinx.serialization.Serializable -import org.apache.avro.generic.GenericData - -@Serializable -data class NullableBoolean(val b: Boolean?) - -@Serializable -data class NullableString(val s: String?) - -@Serializable -data class NullableNestedRecord(val nl: List?) - -class NullableDecoderTest : WordSpec({ - - "Decoder" should { - "support nullable strings" { - val schema = Avro.default.schema(NullableString.serializer()) - - val record1 = GenericData.Record(schema) - record1.put("s", "hello") - Avro.default.fromRecord(NullableString.serializer(), record1) shouldBe NullableString("hello") - - val record2 = GenericData.Record(schema) - record2.put("s", null) - Avro.default.fromRecord(NullableString.serializer(), record2) shouldBe NullableString(null) - } -// "support decoding required fields as Option" in { -// val requiredStringSchema = AvroSchema[RequiredString] -// -// val requiredStringRecord = new GenericData . Record (requiredStringSchema) -// requiredStringRecord.put("s", "hello") -// Decoder[OptionString].decode(requiredStringRecord, -// requiredStringSchema, -// DefaultFieldMapper) shouldBe OptionString(Some("hello")) -// } - "support nullable booleans" { - val schema = Avro.default.schema(NullableBoolean.serializer()) - - val record1 = GenericData.Record(schema) - record1.put("b", true) - Avro.default.fromRecord(NullableBoolean.serializer(), record1) shouldBe NullableBoolean(true) - - val record2 = GenericData.Record(schema) - record2.put("b", null) - Avro.default.fromRecord(NullableBoolean.serializer(), record2) shouldBe NullableBoolean(null) - } -// "if a field is missing, use default value" in { -// val schema = AvroSchema[OptionStringDefault] -// -// val record1 = new GenericData . Record (AvroSchema[SchemaWithoutExpectedField]) -// -// Decoder[OptionStringDefault].decode(record1, -// schema, -// DefaultFieldMapper) shouldBe OptionStringDefault(Some("cupcat")) -// } -// "if an enum field is missing, use default value" in { -// val schema = AvroSchema[OptionEnumDefault] -// -// val record1 = new GenericData . Record (AvroSchema[SchemaWithoutExpectedField]) -// Decoder[OptionEnumDefault].decode(record1, schema, DefaultFieldMapper) shouldBe OptionEnumDefault(Some( -// CuppersOptionEnum)) -// } - "support nullable List of nested records" { - val nullableStringSchema = Avro.default.schema(NullableString.serializer()) - val nullableListSchema = Avro.default.schema(NullableNestedRecord.serializer()) - - val string = GenericData.Record(nullableStringSchema) - string.put("s", "hello") - val record1 = GenericData.Record(nullableListSchema) - record1.put("nl", listOf(string)) - - Avro.default.fromRecord(NullableNestedRecord.serializer(), record1) shouldBe NullableNestedRecord(listOf(NullableString("hello"))) - - val record2 = GenericData.Record(nullableListSchema) - record2.put("nl", null) - Avro.default.fromRecord(NullableNestedRecord.serializer(), record2) shouldBe NullableNestedRecord(null) - } - } - -}) \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/SealedClassDecoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/SealedClassDecoderTest.kt deleted file mode 100644 index 659d46d7..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/SealedClassDecoderTest.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.github.avrokotlin.avro4k.decoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.schema.Operation.Binary -import com.github.avrokotlin.avro4k.schema.ReferencingNullableSealedClass -import com.github.avrokotlin.avro4k.schema.ReferencingSealedClass -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.StringSpec -import org.apache.avro.generic.GenericData - -class SealedClassDecoderTest : StringSpec({ - "support sealed classes" { - val schema = Avro.default.schema(ReferencingSealedClass.serializer()) - val record = GenericData.Record(schema) - val addSchema = Avro.default.schema(Binary.Add.serializer()) - val addRecord = GenericData.Record(addSchema) - addRecord.put("left",1) - addRecord.put("right",2) - record.put("notNullable", addRecord) - Avro.default.fromRecord(ReferencingSealedClass.serializer(), record) shouldBe ReferencingSealedClass(Binary.Add(1,2)) - } - "support nullable sealed classes" { - val schema = Avro.default.schema(ReferencingNullableSealedClass.serializer()) - val record = GenericData.Record(schema) - val addSchema = Avro.default.schema(Binary.Add.serializer()) - val addRecord = GenericData.Record(addSchema) - addRecord.put("left",1) - addRecord.put("right",2) - record.put("nullable", addRecord) - Avro.default.fromRecord(ReferencingNullableSealedClass.serializer(), record) shouldBe ReferencingNullableSealedClass(Binary.Add(1,2)) - - record.put("nullable",null) - Avro.default.fromRecord(ReferencingNullableSealedClass.serializer(), record) shouldBe ReferencingNullableSealedClass(null) - } -}) \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/TransientDecoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/TransientDecoderTest.kt deleted file mode 100644 index 78d68b2e..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/TransientDecoderTest.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.github.avrokotlin.avro4k.decoder - -import com.github.avrokotlin.avro4k.Avro -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec -import kotlinx.serialization.Serializable -import kotlinx.serialization.Transient -import org.apache.avro.generic.GenericData - -class TransientDecoderTest : FunSpec({ - - test("decoder should populate transient fields with default") { - - val schema = Avro.default.schema(TransientFoo.serializer()) - val record = GenericData.Record(schema) - record.put("a", "hello") - Avro.default.fromRecord(TransientFoo.serializer(), record) shouldBe TransientFoo("hello", "world") - } -}) { - @Serializable - data class TransientFoo(val a: String, @Transient val b: String = "world") -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/URLDecoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/URLDecoderTest.kt index f733e082..beae1450 100644 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/URLDecoderTest.kt +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/URLDecoderTest.kt @@ -4,8 +4,8 @@ package com.github.avrokotlin.avro4k.decoder import com.github.avrokotlin.avro4k.Avro import com.github.avrokotlin.avro4k.serializer.URLSerializer -import io.kotest.matchers.shouldBe import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers import org.apache.avro.generic.GenericData @@ -14,16 +14,6 @@ import java.net.URL class URLDecoderTest : FunSpec({ - test("decode String to URL") { - - val schema = Avro.default.schema(TestUrl.serializer()) - - val record = GenericData.Record(schema) - record.put("b", "http://www.sksamuel.com") - - Avro.default.fromRecord(TestUrl.serializer(), record) shouldBe TestUrl(URL("http://www.sksamuel.com")) - } - test("decode UT8 to URL") { val schema = Avro.default.schema(TestUrl.serializer()) @@ -32,26 +22,6 @@ class URLDecoderTest : FunSpec({ record.put("b", Utf8("http://www.sksamuel.com")) Avro.default.fromRecord(TestUrl.serializer(), record) shouldBe TestUrl(URL("http://www.sksamuel.com")) } - - test("decode list of Strings to URL") { - - val schema = Avro.default.schema(TestUrlList.serializer()) - - val record = GenericData.Record(schema) - record.put("urls", listOf("http://www.sksamuel.com", "https://sksamuel.com")) - Avro.default.fromRecord(TestUrlList.serializer(), record) shouldBe TestUrlList(listOf(URL("http://www.sksamuel.com"), URL("https://sksamuel.com"))) - - } - - test("decode list of UT8s to URL") { - - val schema = Avro.default.schema(TestUrlList.serializer()) - - val record = GenericData.Record(schema) - record.put("urls", listOf(Utf8("http://www.sksamuel.com"), Utf8("https://sksamuel.com"))) - Avro.default.fromRecord(TestUrlList.serializer(), record) shouldBe TestUrlList(listOf(URL("http://www.sksamuel.com"), URL("https://sksamuel.com"))) - - } }) { @Serializable diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/UUIDDecoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/UUIDDecoderTest.kt index a5ab4317..11fa6bff 100644 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/UUIDDecoderTest.kt +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/UUIDDecoderTest.kt @@ -4,8 +4,8 @@ package com.github.avrokotlin.avro4k.decoder import com.github.avrokotlin.avro4k.Avro import com.github.avrokotlin.avro4k.serializer.UUIDSerializer -import io.kotest.matchers.shouldBe import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.shouldBe import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers import org.apache.avro.generic.GenericData @@ -14,17 +14,9 @@ import java.util.* class UUIDDecoderTest : StringSpec({ - "decode uuids" { - - val uuid = UUID.randomUUID() - val schema = Avro.default.schema(UUIDTest.serializer()) - val record = GenericData.Record(schema) - record.put("uuid", uuid.toString()) - - Avro.default.fromRecord(UUIDTest.serializer(), record) shouldBe UUIDTest(uuid) - } - - "decode UUIDSs encoded as Utf8" { + "decode UUIDs encoded as Utf8" { + @Serializable + data class UUIDTest(val uuid: UUID) val uuid = UUID.randomUUID() val schema = Avro.default.schema(UUIDTest.serializer()) @@ -34,42 +26,4 @@ class UUIDDecoderTest : StringSpec({ Avro.default.fromRecord(UUIDTest.serializer(), record) shouldBe UUIDTest(uuid) } - - "decode list of uuids" { - - val uuid1 = UUID.randomUUID() - val uuid2 = UUID.randomUUID() - val schema = Avro.default.schema(UUIDListTest.serializer()) - - val record = GenericData.Record(schema) - record.put("uuids", listOf(uuid1.toString(), uuid2.toString())) - - Avro.default.fromRecord(UUIDListTest.serializer(), record) shouldBe UUIDListTest(listOf(uuid1, uuid2)) - } - - "decode nullable UUIDs" { - - val uuid = UUID.randomUUID() - val schema = Avro.default.schema(UUIDNullableTest.serializer()) - - val record1 = GenericData.Record(schema) - record1.put("uuid", uuid.toString()) - - Avro.default.fromRecord(UUIDNullableTest.serializer(), record1) shouldBe UUIDNullableTest(uuid) - - val record2 = GenericData.Record(schema) - record2.put("uuid", null) - - Avro.default.fromRecord(UUIDNullableTest.serializer(), record2) shouldBe UUIDNullableTest(null) - } -}) { - @Serializable - data class UUIDTest(val uuid: UUID) - - @Serializable - data class UUIDListTest(val uuids: List) - - - @Serializable - data class UUIDNullableTest(val uuid: UUID?) -} +}) diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/ValueClassDecoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/ValueClassDecoderTest.kt deleted file mode 100644 index 7f339c24..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/decoder/ValueClassDecoderTest.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.github.avrokotlin.avro4k.decoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.schema.ValueClassSchemaTest -import com.github.avrokotlin.avro4k.schema.ValueClassSchemaTest.ContainsInlineTest -import com.github.avrokotlin.avro4k.schema.ValueClassSchemaTest.StringWrapper -import io.kotest.core.spec.style.StringSpec -import io.kotest.matchers.shouldBe -import org.apache.avro.generic.GenericData -import java.util.UUID - -class ValueClassDecoderTest : StringSpec({ - - "decode value class" { - - val id = StringWrapper("100500") - val uuid = ValueClassSchemaTest.UuidWrapper(UUID.randomUUID()) - val schema = Avro.default.schema(ContainsInlineTest.serializer()) - val record = GenericData.Record(schema) - record.put("id", id.a) - record.put("uuid", uuid.uuid.toString()) - - Avro.default.fromRecord(ContainsInlineTest.serializer(), record) shouldBe ContainsInlineTest(id, uuid) - } -}) \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/ArrayEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/ArrayEncoderTest.kt deleted file mode 100644 index 26a4772d..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/ArrayEncoderTest.kt +++ /dev/null @@ -1,127 +0,0 @@ -package com.github.avrokotlin.avro4k.encoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.ListRecord -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.WordSpec -import kotlinx.serialization.Serializable -import org.apache.avro.generic.GenericData -import org.apache.avro.util.Utf8 - -class ArrayEncoderTest : WordSpec({ - - "Encoder" should { - "generate GenericData.Array for an Array" { - - val schema = Avro.default.schema(ArrayBooleanTest.serializer()) - val arraySchema = schema.getField("a").schema() - val record = Avro.default.toRecord(ArrayBooleanTest.serializer(), ArrayBooleanTest(arrayOf(true, false, true))) - record shouldBe ListRecord(schema, listOf(GenericData.Array(arraySchema, listOf(true, false, true)))) - } - "support GenericData.Array for an Array with other fields" { - - val schema = Avro.default.schema(ArrayBooleanWithOthersTest.serializer()) - val arraySchema = schema.getField("b").schema() - val record = Avro.default.toRecord(ArrayBooleanWithOthersTest.serializer(), ArrayBooleanWithOthersTest("foo", arrayOf(true, false, true), 123L)) - record shouldBe ListRecord( - schema, - Utf8("foo"), - GenericData.Array(arraySchema, listOf(true, false, true)), - 123L - ) - } - "generate GenericData.Array for a List" { - - val schema = Avro.default.schema(ListStringTest.serializer()) - val arraySchema = schema.getField("a").schema() - val record = Avro.default.toRecord(ListStringTest.serializer(), ListStringTest(listOf("we23", "54z"))) - record shouldBe ListRecord( - schema, - listOf(GenericData.Array(arraySchema, listOf(Utf8("we23"), Utf8("54z")))) - ) - } - "generate GenericData.Array for a Set" { - - val schema = Avro.default.schema(SetLongTest.serializer()) - val arraySchema = schema.getField("a").schema() - val expected = ListRecord(schema, listOf(GenericData.Array(arraySchema, listOf(123L, 643L, 912)))) - val actual = Avro.default.toRecord(SetLongTest.serializer(), SetLongTest(setOf(123L, 643L, 912L))) - actual shouldBe expected - } -// "generate array for an Array of records" { -// @Serializable -// data class Nested(val goo: String) -// -// @Serializable -// data class Test(val array: Array) -// -// val schema = Avro.default.schema(Test.serializer()) -// val nestedSchema = Avro.default.schema(Nested.serializer()) -// -// val record = Avro.default.toRecord(Test.serializer(), Test(arrayOf(Nested("qwe"), Nested("dfsg")))) -// record shouldBe ImmutableRecord( -// schema, -// arrayListOf( -// arrayListOf( -// ImmutableRecord(nestedSchema, arrayListOf(Utf8("qwe"))), -// ImmutableRecord(nestedSchema, arrayListOf(Utf8("dfsg"))) -// ) -// ) -// ) -// } -// "generate array for a List of records" { -// @Serializable -// data class Nested(val goo: String) -// -// @Serializable -// data class Test(val list: List) -// -// val schema = Avro.default.schema(Test.serializer()) -// val nestedSchema = Avro.default.schema(Nested.serializer()) -// -// val record = Avro.default.toRecord(Test.serializer(), Test(listOf(Nested("qwe"), Nested("dfsg")))) -// record shouldBe ImmutableRecord( -// schema, -// arrayListOf( -// arrayListOf( -// ImmutableRecord(nestedSchema, arrayListOf(Utf8("qwe"))), -// ImmutableRecord(nestedSchema, arrayListOf(Utf8("dfsg"))) -// ) -// ) -// ) -// } -// "generate array for a Set of records" { -// @Serializable -// data class Nested(val goo: String) -// -// @Serializable -// data class Test(val set: Set) -// -// val schema = Avro.default.schema(Test.serializer()) -// val nestedSchema = Avro.default.schema(Nested.serializer()) -// -// val record = Avro.default.toRecord(Test.serializer(), Test(setOf(Nested("qwe"), Nested("dfsg")))) -// record shouldBe ImmutableRecord( -// schema, -// arrayListOf( -// arrayListOf( -// ImmutableRecord(nestedSchema, arrayListOf(Utf8("qwe"))), -// ImmutableRecord(nestedSchema, arrayListOf(Utf8("dfsg"))) -// ) -// ) -// ) -// } - } -}) { - @Serializable - data class ArrayBooleanTest(val a: Array) - - @Serializable - data class ArrayBooleanWithOthersTest(val a: String, val b: Array, val c: Long) - - @Serializable - data class SetLongTest(val a: Set) - - @Serializable - data class ListStringTest(val a: List) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/AvroInlineEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/AvroInlineEncoderTest.kt deleted file mode 100644 index fd894cd7..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/AvroInlineEncoderTest.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.github.avrokotlin.avro4k.encoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.AvroInline -import com.github.avrokotlin.avro4k.ListRecord -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec -import kotlinx.serialization.Serializable -import org.apache.avro.util.Utf8 - -class AvroInlineEncoderTest : FunSpec({ - - test("encode @AvroInline") { - - val schema = Avro.default.schema(Product.serializer()) - val record = Avro.default.toRecord(Product.serializer(), Product("123", Name("sneakers"))) - record shouldBe ListRecord(schema, listOf(Utf8("123"), Utf8("sneakers"))) - } - -}) { - - @Serializable - @AvroInline - data class Name(val value: String) - - @Serializable - data class Product(val id: String, val name: Name) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/AvroNameEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/AvroNameEncoderTest.kt deleted file mode 100644 index 950cbed7..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/AvroNameEncoderTest.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.github.avrokotlin.avro4k.encoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.AvroName -import com.github.avrokotlin.avro4k.ListRecord -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec -import kotlinx.serialization.Serializable -import org.apache.avro.util.Utf8 - -class AvroNameEncoderTest : FunSpec({ - - test("encoder should take into account @AvroName on fields") { - val schema = Avro.default.schema(Foo.serializer()) - Avro.default.toRecord(Foo.serializer(), Foo("hello")) shouldBe ListRecord(schema, listOf(Utf8("hello"))) - } -}) { - @Serializable - data class Foo(@AvroName("bar") val foo: String) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/BasicEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/BasicEncoderTest.kt deleted file mode 100644 index b4f1e17f..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/BasicEncoderTest.kt +++ /dev/null @@ -1,99 +0,0 @@ -package com.github.avrokotlin.avro4k.encoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.ListRecord -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.WordSpec -import kotlinx.serialization.Serializable -import org.apache.avro.Schema -import org.apache.avro.SchemaBuilder -import org.apache.avro.generic.GenericData -import org.apache.avro.util.Utf8 - -class BasicEncoderTest : WordSpec({ - - "Encoder" should { - "encode strings as UTF8" { - - val schema = Avro.default.schema(StringFoo.serializer()) - val record = Avro.default.toRecord(StringFoo.serializer(), StringFoo("hello")) - record shouldBe ListRecord(schema, Utf8("hello")) - } - "encode strings as GenericFixed and pad bytes when schema is Type.FIXED" { - - val schema = SchemaBuilder.record("Foo").fields() - .name("s").type(Schema.createFixed("FixedString", null, null, 7)).noDefault() - .endRecord() - - (Avro.default.toRecord(StringFoo.serializer(), schema, StringFoo("hello"))["s"] as GenericData.Fixed).bytes() shouldBe - byteArrayOf(104, 101, 108, 108, 111, 0, 0) - } - "encode longs" { - - val schema = Avro.default.schema(LongFoo.serializer()) - val record = Avro.default.toRecord(LongFoo.serializer(), LongFoo(123456L)) - record shouldBe ListRecord(schema, 123456L) - } - "encode doubles" { - - val schema = Avro.default.schema(DoubleFoo.serializer()) - val record = Avro.default.toRecord(DoubleFoo.serializer(), DoubleFoo(123.435)) - record shouldBe ListRecord(schema, 123.435) - } - "encode booleans" { - - val schema = Avro.default.schema(BooleanFoo.serializer()) - val record = Avro.default.toRecord(BooleanFoo.serializer(), BooleanFoo(true)) - record shouldBe ListRecord(schema, true) - } - "encode floats" { - - val schema = Avro.default.schema(FloatFoo.serializer()) - val record = Avro.default.toRecord(FloatFoo.serializer(), FloatFoo(123.435F)) - record shouldBe ListRecord(schema, 123.435F) - } - "encode ints" { - - val schema = Avro.default.schema(IntFoo.serializer()) - val record = Avro.default.toRecord(IntFoo.serializer(), IntFoo(123)) - record shouldBe ListRecord(schema, 123) - } - "encode shorts" { - - val schema = Avro.default.schema(ShortFoo.serializer()) - val record = Avro.default.toRecord(ShortFoo.serializer(), ShortFoo(123.toShort())) - record shouldBe ListRecord(schema, 123.toShort()) - } - "encode bytes" { - - val schema = Avro.default.schema(ByteFoo.serializer()) - val record = Avro.default.toRecord(ByteFoo.serializer(), ByteFoo(123.toByte())) - record shouldBe ListRecord(schema, 123.toByte()) - } - } - -}) { - @Serializable - data class StringFoo(val s: String) - - @Serializable - data class LongFoo(val l: Long) - - @Serializable - data class DoubleFoo(val d: Double) - - @Serializable - data class BooleanFoo(val d: Boolean) - - @Serializable - data class FloatFoo(val d: Float) - - @Serializable - data class IntFoo(val i: Int) - - @Serializable - data class ShortFoo(val s: Short) - - @Serializable - data class ByteFoo(val b: Byte) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/BigDecimalEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/BigDecimalEncoderTest.kt deleted file mode 100644 index d045f538..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/BigDecimalEncoderTest.kt +++ /dev/null @@ -1,90 +0,0 @@ -@file:UseSerializers(BigDecimalSerializer::class) - -package com.github.avrokotlin.avro4k.encoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.ListRecord -import com.github.avrokotlin.avro4k.serializer.BigDecimalSerializer -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec -import kotlinx.serialization.Serializable -import kotlinx.serialization.UseSerializers -import org.apache.avro.Conversions -import org.apache.avro.LogicalTypes -import org.apache.avro.Schema -import org.apache.avro.SchemaBuilder -import org.apache.avro.generic.GenericFixed -import org.apache.avro.util.Utf8 -import java.math.BigDecimal - -class BigDecimalEncoderTest : FunSpec({ - - test("use byte array for decimal") { - - val schema = Avro.default.schema(BigDecimalTest.serializer()) - - val obj = BigDecimalTest(BigDecimal("12.34")) - val s = schema.getField("decimal").schema() - val bytes = Conversions.DecimalConversion().toBytes(BigDecimal("12.34"), s, s.logicalType) - - Avro.default.toRecord(BigDecimalTest.serializer(), schema, obj) shouldBe ListRecord(schema, bytes) - } - - test("allow decimals to be encoded as strings") { - - val schema = SchemaBuilder.record("Test").fields() - .name("decimal").type(Schema.create(Schema.Type.STRING)).noDefault() - .endRecord() - - Avro.default.toRecord(BigDecimalTest.serializer(), schema, BigDecimalTest(BigDecimal("123.456"))) shouldBe - ListRecord(schema, Utf8("123.456")) - } - -// test("Allow Override of roundingMode") { -// -// data class Test(@ScalePrecision(2, 10) val decimal: BigDecimal) -// -// implicit val sp = -// val schema = AvroSchema[Test] -// val s = schema.getField("decimal").schema() -// -// implicit val roundingMode = RoundingMode.HALF_UP -// -// val bytesRoundedDown = Conversions.DecimalConversion().toBytes(BigDecimal(12.34).bigDecimal, s, s.getLogicalType) -// Encoder[Test].encode(Test(12.3449), schema, DefaultFieldMapper) shouldBe ImmutableRecord(schema, Vector(bytesRoundedDown)) -// -// val bytesRoundedUp = Conversions.DecimalConversion().toBytes(BigDecimal(12.35).bigDecimal, s, s.getLogicalType) -// Encoder[Test].encode(Test(12.345), schema, DefaultFieldMapper) shouldBe ImmutableRecord(schema, Vector(bytesRoundedUp)) -// } - - test("support nullable big decimals") { - - val schema = Avro.default.schema(NullableBigDecimalTest.serializer()) - - val s = schema.getField("big").schema().types.first { it.type != Schema.Type.NULL } - val bytes = Conversions.DecimalConversion().toBytes(BigDecimal("123.4").setScale(2), s, s.logicalType) - - Avro.default.toRecord(NullableBigDecimalTest.serializer(), schema, NullableBigDecimalTest(BigDecimal("123.4"))) shouldBe ListRecord(schema, bytes) - Avro.default.toRecord(NullableBigDecimalTest.serializer(), schema, NullableBigDecimalTest(null)) shouldBe ListRecord(schema, null) - } - - test("allow bigdecimals to be encoded as generic fixed") { - - - //Schema needs to have the precision of 16 in order to serialize a 8 digit integer with a scale of 8 - val decimal = LogicalTypes.decimal(16, 8).addToSchema(Schema.createFixed("decimal", null, null, 8)) - - val schema = SchemaBuilder.record("Test").fields() - .name("decimal").type(decimal).noDefault() - .endRecord() - - val big = Avro.default.toRecord(BigDecimalTest.serializer(), schema, BigDecimalTest(BigDecimal("12345678"))).get("decimal") as GenericFixed - big.bytes() shouldBe byteArrayOf(0, 4, 98, -43, 55, 43, -114, 0) - } -}) { - @Serializable - data class BigDecimalTest(val decimal: BigDecimal) - - @Serializable - data class NullableBigDecimalTest(val big: BigDecimal?) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/BigIntegerEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/BigIntegerEncoderTest.kt deleted file mode 100644 index f6641520..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/BigIntegerEncoderTest.kt +++ /dev/null @@ -1,41 +0,0 @@ -@file:UseSerializers(BigIntegerSerializer::class) - -package com.github.avrokotlin.avro4k.encoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.ListRecord -import com.github.avrokotlin.avro4k.serializer.BigIntegerSerializer -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec -import kotlinx.serialization.Serializable -import kotlinx.serialization.UseSerializers -import org.apache.avro.util.Utf8 -import java.math.BigInteger - -class BigIntegerEncoderTest : FunSpec({ - - test("use string for bigint") { - - val schema = Avro.default.schema(BigIntegerTest.serializer()) - - val test = BigIntegerTest(BigInteger("123123123123213213213123214325365477686789676234")) - - Avro.default.toRecord(BigIntegerTest.serializer(), schema, test) shouldBe ListRecord(schema, Utf8("123123123123213213213123214325365477686789676234")) - } - - test("encode nullable big ints") { - - val schema = Avro.default.schema(NullableBigIntegerTest.serializer()) - Avro.default.toRecord(NullableBigIntegerTest.serializer(), schema, NullableBigIntegerTest(BigInteger("12312312312321312365477686789676234"))) shouldBe - ListRecord(schema, Utf8("12312312312321312365477686789676234")) - Avro.default.toRecord(NullableBigIntegerTest.serializer(), schema, NullableBigIntegerTest(null)) shouldBe ListRecord(schema, null) - - } -}) { - @Serializable - data class BigIntegerTest(val b: BigInteger) - - - @Serializable - data class NullableBigIntegerTest(val b: BigInteger?) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/ByteArrayEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/ByteArrayEncoderTest.kt deleted file mode 100644 index 90bc28bc..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/ByteArrayEncoderTest.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.github.avrokotlin.avro4k.encoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.ListRecord -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec -import kotlinx.serialization.Serializable -import org.apache.avro.Schema -import org.apache.avro.SchemaBuilder -import org.apache.avro.generic.GenericFixed -import java.nio.ByteBuffer - -class ByteArrayEncoderTest : FunSpec({ - - test("encode ByteArray to ByteBuffer to ") { - val schema = Avro.default.schema(ByteArrayTest.serializer()) - Avro.default.toRecord(ByteArrayTest.serializer(), ByteArrayTest(byteArrayOf(1, 4, 9))) shouldBe - ListRecord(schema, ByteBuffer.wrap(byteArrayOf(1,4,9))) - } - - test("encode List to ByteBuffer") { - val schema = Avro.default.schema(ListByteTest.serializer()) - Avro.default.toRecord(ListByteTest.serializer(), ListByteTest(listOf(1, 4, 9))) shouldBe - ListRecord(schema, ByteBuffer.wrap(byteArrayOf(1,4,9))) - } - - test("encode Array to ByteBuffer") { - val schema = Avro.default.schema(ArrayByteTest.serializer()) - Avro.default.toRecord(ArrayByteTest.serializer(), ArrayByteTest(arrayOf(1, 4, 9))) shouldBe - ListRecord(schema, ByteBuffer.wrap(byteArrayOf(1,4,9))) - } - - test("encode ByteArray as FIXED when schema is Type.Fixed") { - val schema = SchemaBuilder.record("ByteArrayTest").fields() - .name("z").type(Schema.createFixed("ByteArray", null, null, 8)).noDefault() - .endRecord() - val record = Avro.default.toRecord(ByteArrayTest.serializer(), schema, ByteArrayTest(byteArrayOf(1, 4, 9))) - val fixed = record.get("z") as GenericFixed - fixed.bytes() shouldBe byteArrayOf(0, 0, 0, 0, 0, 1, 4, 9) - } -}) { - - @Serializable - data class ByteArrayTest(val z: ByteArray) - - @Serializable - data class ArrayByteTest(val z: Array) - - @Serializable - data class ListByteTest(val z: List) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/DateEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/DateEncoderTest.kt deleted file mode 100644 index e4455046..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/DateEncoderTest.kt +++ /dev/null @@ -1,107 +0,0 @@ -@file:UseSerializers( - LocalDateTimeSerializer::class, - LocalDateSerializer::class, - LocalTimeSerializer::class, - TimestampSerializer::class, -) - -package com.github.avrokotlin.avro4k.encoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.ListRecord -import com.github.avrokotlin.avro4k.serializer.* -import io.kotest.core.spec.style.FunSpec -import io.kotest.matchers.shouldBe -import kotlinx.serialization.Serializable -import kotlinx.serialization.UseSerializers -import java.sql.Timestamp -import java.time.Instant -import java.time.LocalDate -import java.time.LocalDateTime -import java.time.LocalTime -import java.time.temporal.ChronoUnit - -class DateEncoderTest : FunSpec({ - - test("encode LocalTime as an Int") { - - val schema = Avro.default.schema(LocalTimeTest.serializer()) - Avro.default.toRecord(LocalTimeTest.serializer(), LocalTimeTest(LocalTime.of(12, 50, 45))) shouldBe - ListRecord(schema, 46245000) - } - - test("encode nullable LocalTime") { - - val schema = Avro.default.schema(NullableLocalTimeTest.serializer()) - Avro.default.toRecord(NullableLocalTimeTest.serializer(), NullableLocalTimeTest(LocalTime.of(12, 50, 45))) shouldBe ListRecord(schema, 46245000) - Avro.default.toRecord(NullableLocalTimeTest.serializer(), NullableLocalTimeTest(null)) shouldBe ListRecord(schema, null) - } - - test("encode LocalDate as an Int") { - - val schema = Avro.default.schema(LocalDateTest.serializer()) - Avro.default.toRecord(LocalDateTest.serializer(), LocalDateTest(LocalDate.of(2018, 9, 10))) shouldBe - ListRecord(schema, 17784) - } - - test("encode LocalDateTime as Long") { - - val schema = Avro.default.schema(LocalDateTimeTest.serializer()) - Avro.default.toRecord(LocalDateTimeTest.serializer(), LocalDateTimeTest(LocalDateTime.of(2018, 9, 10, 11, 58, 59))) shouldBe - ListRecord(schema, 1536580739000L) - } - - test("encode Timestamp as Long") { - - val schema = Avro.default.schema(TimestampTest.serializer()) - Avro.default.toRecord(TimestampTest.serializer(), TimestampTest(Timestamp.from(Instant.ofEpochMilli(1538312231000L)))) shouldBe - ListRecord(schema, 1538312231000L) - } - - test("encode nullable Timestamp as Long") { - - val schema = Avro.default.schema(NullableTimestampTest.serializer()) - Avro.default.toRecord(NullableTimestampTest.serializer(), NullableTimestampTest(null)) shouldBe ListRecord(schema, null) - Avro.default.toRecord(NullableTimestampTest.serializer(), NullableTimestampTest(Timestamp.from(Instant.ofEpochMilli(1538312231000L)))) shouldBe - ListRecord(schema, 1538312231000L) - } - - test("encode Instant as Long") { - - val schema = Avro.default.schema(InstantMillisTest.serializer()) - Avro.default.toRecord(InstantMillisTest.serializer(), InstantMillisTest(Instant.ofEpochMilli(1538312231000L))) shouldBe - ListRecord(schema, 1538312231000L) - } - - test("encode Instant with microseconds as Long") { - - val schema = Avro.default.schema(InstantMicrosTest.serializer()) - val time = Instant.ofEpochMilli(1538312231000L).plus(5, ChronoUnit.MICROS) - - Avro.default.toRecord(InstantMicrosTest.serializer(), InstantMicrosTest(time)) shouldBe ListRecord(schema, 1538312231000005L) - } -}) { - @Serializable - data class LocalTimeTest(val t: LocalTime) - - @Serializable - data class NullableLocalTimeTest(val t: LocalTime?) - - @Serializable - data class LocalDateTest(val d: LocalDate) - - @Serializable - data class LocalDateTimeTest(val dt: LocalDateTime) - - @Serializable - data class TimestampTest(val t: Timestamp) - - @Serializable - data class NullableTimestampTest(val t: Timestamp?) - - @Serializable - data class InstantMillisTest(@Serializable(with = InstantSerializer::class) val i: Instant) - - @Serializable - data class InstantMicrosTest(@Serializable(with = InstantToMicroSerializer::class) val i: Instant) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/EnumEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/EnumEncoderTest.kt deleted file mode 100644 index fe9b7df2..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/EnumEncoderTest.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.github.avrokotlin.avro4k.encoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.ListRecord -import com.github.avrokotlin.avro4k.decoder.MyWine -import com.github.avrokotlin.avro4k.decoder.NullableWine -import com.github.avrokotlin.avro4k.schema.Wine -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec -import org.apache.avro.generic.GenericData - -class EnumEncoderTest : FunSpec({ - - test("support enums") { - val schema = Avro.default.schema(MyWine.serializer()) - Avro.default.toRecord(MyWine.serializer(), schema, MyWine(Wine.Malbec)) shouldBe - ListRecord( - schema, - GenericData.EnumSymbol(schema.getField("wine").schema(), "Malbec") - ) - } - - test("support nullable enums") { - val schema = Avro.default.schema(NullableWine.serializer()) - - val record1 = GenericData.Record(schema) - record1.put("wine", GenericData.EnumSymbol(schema.getField("wine").schema(), "Shiraz")) - Avro.default.fromRecord(NullableWine.serializer(), record1) shouldBe NullableWine(Wine.Shiraz) - - val record2 = GenericData.Record(schema) - record2.put("wine", null) - Avro.default.fromRecord(NullableWine.serializer(), record2) shouldBe NullableWine(null) - } -}) \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/FixedEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/FixedEncoderTest.kt deleted file mode 100644 index 3d84b8ec..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/FixedEncoderTest.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.github.avrokotlin.avro4k.encoder - -import com.github.avrokotlin.avro4k.Avro -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec -import kotlinx.serialization.Serializable -import org.apache.avro.Schema -import org.apache.avro.SchemaBuilder -import org.apache.avro.generic.GenericData - -class FixedEncoderTest : FunSpec({ - - test("encode strings as GenericFixed when schema is Type.FIXED") { - - val schema = SchemaBuilder.record("foo").fields() - .name("a").type(Schema.createFixed("a", null, null, 5)).noDefault() - .endRecord() - - val record = Avro.default.toRecord(StringFoo.serializer(), schema, StringFoo("hello")) - record[0] shouldBe GenericData.get().createFixed( - null, - byteArrayOf(104, 101, 108, 108, 111), - Schema.createFixed("a", null, null, 5) - ) - } - - test("encode byte arrays as GenericFixed when schema is Type.FIXED") { - - val schema = SchemaBuilder.record("foo").fields() - .name("a").type(Schema.createFixed("a", null, null, 5)).noDefault() - .endRecord() - - val record = Avro.default.toRecord(ByteArrayFoo.serializer(), schema, ByteArrayFoo(byteArrayOf(1, 2, 3, 4, 5))) - record[0] shouldBe GenericData.get().createFixed( - null, - byteArrayOf(1, 2, 3, 4, 5), - Schema.createFixed("a", null, null, 5) - ) - } -}) { - @Serializable - data class StringFoo(val s: String) - - @Serializable - data class ByteArrayFoo(val s: ByteArray) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/MapEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/MapEncoderTest.kt deleted file mode 100644 index 88e2dea0..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/MapEncoderTest.kt +++ /dev/null @@ -1,68 +0,0 @@ -package com.github.avrokotlin.avro4k.encoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.ListRecord -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.StringSpec -import kotlinx.serialization.Serializable -import org.apache.avro.util.Utf8 -import java.nio.ByteBuffer - -class MapEncoderTest : StringSpec({ - - "encode a Map" { - - val schema = Avro.default.schema(StringBooleanTest.serializer()) - val record = Avro.default.toRecord(StringBooleanTest.serializer(), StringBooleanTest(mapOf("a" to true, "b" to false, "c" to true))) - record shouldBe ListRecord(schema, mapOf(Utf8("a") to true, Utf8("b") to false, Utf8("c") to true)) - } - - "encode a Map" { - - val schema = Avro.default.schema(StringStringTest.serializer()) - val record = Avro.default.toRecord(StringStringTest.serializer(), StringStringTest(mapOf("a" to "x", "b" to "y", "c" to "z"))) - record shouldBe ListRecord(schema, mapOf(Utf8("a") to Utf8("x"), Utf8("b") to Utf8("y"), Utf8("c") to Utf8("z"))) - } - - "encode a Map" { - - val schema = Avro.default.schema(StringByteArrayTest.serializer()) - val record = Avro.default.toRecord(StringByteArrayTest.serializer(), StringByteArrayTest(mapOf( - "a" to "x".toByteArray(), - "b" to "y".toByteArray(), - "c" to "z".toByteArray() - ))) - record shouldBe ListRecord(schema, mapOf( - Utf8("a") to ByteBuffer.wrap("x".toByteArray()), - Utf8("b") to ByteBuffer.wrap("y".toByteArray()), - Utf8("c") to ByteBuffer.wrap("z".toByteArray()) - )) - } - - "encode a Map of records" { - - val schema = Avro.default.schema(StringFooTest.serializer()) - val fooSchema = Avro.default.schema(Foo.serializer()) - - val record = Avro.default.toRecord(StringFooTest.serializer(), StringFooTest(mapOf("a" to Foo("x", true), "b" to Foo("y", false)))) - val xRecord = ListRecord(fooSchema, Utf8("x"), true) - val yRecord = ListRecord(fooSchema, Utf8("y"), false) - - record shouldBe ListRecord(schema, mapOf(Utf8("a") to xRecord, Utf8("b") to yRecord)) - } -}) { - @Serializable - data class StringBooleanTest(val a: Map) - - @Serializable - data class StringStringTest(val a: Map) - - @Serializable - data class StringByteArrayTest(val a: Map) - - @Serializable - data class Foo(val a: String, val b: Boolean) - - @Serializable - data class StringFooTest(val a: Map) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/NamingStrategyEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/NamingStrategyEncoderTest.kt deleted file mode 100644 index 86d1f301..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/NamingStrategyEncoderTest.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.github.avrokotlin.avro4k.encoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.AvroConfiguration -import com.github.avrokotlin.avro4k.ListRecord -import com.github.avrokotlin.avro4k.schema.PascalCaseNamingStrategy -import com.github.avrokotlin.avro4k.schema.SnakeCaseNamingStrategy -import io.kotest.core.spec.style.WordSpec -import io.kotest.matchers.shouldBe -import kotlinx.serialization.Serializable -import org.apache.avro.util.Utf8 - -class NamingStrategyEncoderTest : WordSpec({ - "Encoder" should { - "support encoding fields with snake_casing" { - val snakeCaseAvro = Avro(AvroConfiguration(SnakeCaseNamingStrategy)) - - val schema = snakeCaseAvro.schema(Foo.serializer()) - - val record = snakeCaseAvro.toRecord(Foo.serializer(), Foo("hello")) - - record.hasField("foo_bar") shouldBe true - - record shouldBe ListRecord(schema, listOf(Utf8("hello"))) - } - - "support encoding fields with PascalCasing" { - val pascalCaseAvro = Avro(AvroConfiguration(PascalCaseNamingStrategy)) - - val schema = pascalCaseAvro.schema(Foo.serializer()) - - val record = pascalCaseAvro.toRecord(Foo.serializer(), Foo("hello")) - - record.hasField("FooBar") shouldBe true - - record shouldBe ListRecord(schema, listOf(Utf8("hello"))) - } - } -}) { - @Serializable - data class Foo(val fooBar: String) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/NestedClassEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/NestedClassEncoderTest.kt deleted file mode 100644 index fc6fb479..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/NestedClassEncoderTest.kt +++ /dev/null @@ -1,65 +0,0 @@ -@file:UseSerializers( - TimestampSerializer::class -) - -package com.github.avrokotlin.avro4k.encoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.ListRecord -import com.github.avrokotlin.avro4k.serializer.TimestampSerializer -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec -import kotlinx.serialization.Serializable -import kotlinx.serialization.UseSerializers -import org.apache.avro.util.Utf8 - -@Serializable -data class County(val name: String, val towns: List, val ceremonial: Boolean, val lat: Double, val long: Double) - -@Serializable -data class Town(val name: String, val population: Int) - -@Serializable -data class Birthplace(val name: String, val town: Town) - -@Serializable -data class ProductName(val value: String) - -@Serializable -data class Product(val name: ProductName?) - -class NestedClassEncoderTest : FunSpec({ - - val townSchema = Avro.default.schema(Town.serializer()) - val birthplaceSchema = Avro.default.schema(Birthplace.serializer()) - - test("!encode nested class") { - val b = Birthplace("sammy", Town("Hardwick", 123)) - val record = Avro.default.toRecord(Birthplace.serializer(), b) - record shouldBe ListRecord( - birthplaceSchema, - Utf8("sammy"), - ListRecord( - townSchema, - Utf8("Hardwick"), - 123 - ) - ) - } - - test("!encode nested nullable class") { - - val nameSchema = Avro.default.schema(ProductName.serializer()) - val prodSchema = Avro.default.schema(Product.serializer()) - - val p = Product(ProductName("big shoes")) - val record = Avro.default.toRecord(Product.serializer(), p) - record shouldBe ListRecord( - prodSchema, - ListRecord( - nameSchema, - Utf8("big shoes") - ) - ) - } -}) \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/NullableEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/NullableEncoderTest.kt deleted file mode 100644 index 4710f1d3..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/NullableEncoderTest.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.github.avrokotlin.avro4k.encoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.ListRecord -import com.github.avrokotlin.avro4k.decoder.NullableBoolean -import com.github.avrokotlin.avro4k.decoder.NullableString -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec -import org.apache.avro.util.Utf8 - -class NullableEncoderTest : FunSpec({ - - test("encode nullable strings") { - val schema = Avro.default.schema(NullableString.serializer()) - - Avro.default.toRecord(NullableString.serializer(), NullableString("hello")) shouldBe - ListRecord(schema, Utf8("hello")) - - Avro.default.toRecord(NullableString.serializer(), NullableString(null)) shouldBe - ListRecord(schema, null) - } - - test("encode nullable booleans") { - val schema = Avro.default.schema(NullableBoolean.serializer()) - - Avro.default.toRecord(NullableBoolean.serializer(), NullableBoolean(true)) shouldBe - ListRecord(schema, true) - - Avro.default.toRecord(NullableBoolean.serializer(), NullableBoolean(false)) shouldBe - ListRecord(schema, false) - - Avro.default.toRecord(NullableBoolean.serializer(), NullableBoolean(null)) shouldBe - ListRecord(schema, null) - } -}) \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/SealedClassEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/SealedClassEncoderTest.kt deleted file mode 100644 index 23496b02..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/SealedClassEncoderTest.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.github.avrokotlin.avro4k.encoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.ListRecord -import com.github.avrokotlin.avro4k.schema.Operation -import com.github.avrokotlin.avro4k.schema.ReferencingNullableSealedClass -import com.github.avrokotlin.avro4k.schema.ReferencingSealedClass -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.StringSpec -import org.apache.avro.generic.GenericData - -class SealedClassEncoderTest : StringSpec({ - - "support sealed classes" { - val schema = Avro.default.schema(ReferencingSealedClass.serializer()) - val record = GenericData.Record(schema) - val addSchema = Avro.default.schema(Operation.Binary.Add.serializer()) - val addRecord = GenericData.Record(addSchema) - addRecord.put("left", 1) - addRecord.put("right", 2) - record.put("notNullable", addRecord) - Avro.default.toRecord( - ReferencingSealedClass.serializer(), - ReferencingSealedClass(Operation.Binary.Add(1, 2)) - ) shouldBe ListRecord(schema,ListRecord(addSchema,1,2)) - } - "support nullable sealed classes" { - val schema = Avro.default.schema(ReferencingNullableSealedClass.serializer()) - val addSchema = Avro.default.schema(Operation.Binary.Add.serializer()) - - Avro.default.toRecord( - ReferencingNullableSealedClass.serializer(), ReferencingNullableSealedClass( - Operation.Binary.Add(1, 2) - ) - ) shouldBe ListRecord(schema,ListRecord(addSchema,1,2)) - - - Avro.default.toRecord( - ReferencingNullableSealedClass.serializer(), ReferencingNullableSealedClass( - null - ) - ) shouldBe ListRecord(schema,null) - } -}) \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/TransientEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/TransientEncoderTest.kt deleted file mode 100644 index 00c328c8..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/TransientEncoderTest.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.github.avrokotlin.avro4k.encoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.ListRecord -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec -import kotlinx.serialization.Serializable -import org.apache.avro.util.Utf8 - -class TransientEncoderTest : FunSpec({ - - test("encoder should skip @Transient fields") { - - val schema = Avro.default.schema(Test.serializer()) - val record = Avro.default.toRecord(Test.serializer(), Test("a", "b", "c")) - record shouldBe ListRecord(schema, Utf8("a"), Utf8("c")) - } -}) { - @Serializable - data class Test(val a: String, @kotlinx.serialization.Transient val b: String = "foo", val c: String) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/URLEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/URLEncoderTest.kt deleted file mode 100644 index 23b4f358..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/URLEncoderTest.kt +++ /dev/null @@ -1,40 +0,0 @@ -@file:UseSerializers(URLSerializer::class) - -package com.github.avrokotlin.avro4k.encoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.ListRecord -import com.github.avrokotlin.avro4k.serializer.URLSerializer -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec -import kotlinx.serialization.Serializable -import kotlinx.serialization.UseSerializers -import org.apache.avro.util.Utf8 -import java.net.URL - -class URLEncoderTest : FunSpec({ - - test("use string for URL") { - - val schema = Avro.default.schema(UrlTest.serializer()) - - val test = UrlTest(URL("http://www.sksamuel.com")) - - Avro.default.toRecord(UrlTest.serializer(), schema, test) shouldBe ListRecord(schema, Utf8("http://www.sksamuel.com")) - } - - test("encode nullable URLs") { - - val schema = Avro.default.schema(NullableUrlTest.serializer()) - Avro.default.toRecord(NullableUrlTest.serializer(), schema, NullableUrlTest(URL("http://www.sksamuel.com"))) shouldBe - ListRecord(schema, Utf8("http://www.sksamuel.com")) - Avro.default.toRecord(NullableUrlTest.serializer(), schema, NullableUrlTest(null)) shouldBe ListRecord(schema, null) - - } -}) { - @Serializable - data class UrlTest(val b: URL) - - @Serializable - data class NullableUrlTest(val b: URL?) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/UUIDEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/UUIDEncoderTest.kt deleted file mode 100644 index 3ab806b1..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/UUIDEncoderTest.kt +++ /dev/null @@ -1,51 +0,0 @@ -@file:UseSerializers(UUIDSerializer::class) - -package com.github.avrokotlin.avro4k.encoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.ListRecord -import com.github.avrokotlin.avro4k.serializer.UUIDSerializer -import io.kotest.matchers.shouldBe -import io.kotest.core.spec.style.FunSpec -import kotlinx.serialization.Serializable -import kotlinx.serialization.UseSerializers -import org.apache.avro.util.Utf8 -import java.util.* - -class UUIDEncoderTest : FunSpec({ - - test("encode uuids") { - - val uuid = UUID.randomUUID() - val schema = Avro.default.schema(UUIDTest.serializer()) - Avro.default.toRecord(UUIDTest.serializer(), UUIDTest(uuid)) shouldBe - ListRecord(schema, Utf8(uuid.toString())) - } - - test("encode lists of uuids") { - - val uuid1 = UUID.randomUUID() - val uuid2 = UUID.randomUUID() - val schema = Avro.default.schema(UUIDList.serializer()) - val actual = Avro.default.toRecord(UUIDList.serializer(), UUIDList(listOf(uuid1, uuid2))) - val expected = ListRecord(schema, listOf(listOf(Utf8(uuid1.toString()), Utf8(uuid2.toString())))) - actual shouldBe expected - } - - test("encode nullable uuids") { - - val uuid = UUID.randomUUID() - val schema = Avro.default.schema(NullableUUIDTest.serializer()) - Avro.default.toRecord(NullableUUIDTest.serializer(), NullableUUIDTest(uuid)) shouldBe ListRecord(schema, Utf8(uuid.toString())) - Avro.default.toRecord(NullableUUIDTest.serializer(), NullableUUIDTest(null)) shouldBe ListRecord(schema, null) - } -}) { - @Serializable - data class UUIDTest(val uuid: UUID) - - @Serializable - data class UUIDList(val uuids: List) - - @Serializable - data class NullableUUIDTest(val uuid: UUID?) -} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/ValueClassEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/ValueClassEncoderTest.kt deleted file mode 100644 index 17a83fbf..00000000 --- a/src/test/kotlin/com/github/avrokotlin/avro4k/encoder/ValueClassEncoderTest.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.github.avrokotlin.avro4k.encoder - -import com.github.avrokotlin.avro4k.Avro -import com.github.avrokotlin.avro4k.ListRecord -import com.github.avrokotlin.avro4k.schema.ValueClassSchemaTest -import io.kotest.core.spec.style.StringSpec -import io.kotest.matchers.shouldBe -import org.apache.avro.util.Utf8 -import java.util.UUID - -class ValueClassEncoderTest : StringSpec({ - - "encode value class" { - - val id = ValueClassSchemaTest.StringWrapper("100500") - val uuid = UUID.randomUUID() - val uuidStr = uuid.toString() - val uuidW = ValueClassSchemaTest.UuidWrapper(uuid) - val schema = Avro.default.schema(ValueClassSchemaTest.ContainsInlineTest.serializer()) - Avro.default.toRecord(ValueClassSchemaTest.ContainsInlineTest.serializer(), - ValueClassSchemaTest.ContainsInlineTest(id, uuidW)) shouldBe ListRecord(schema, Utf8(id.a), Utf8(uuidStr)) - } -}) \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/ArrayEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/ArrayEncoderTest.kt new file mode 100644 index 00000000..ff525f00 --- /dev/null +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/ArrayEncoderTest.kt @@ -0,0 +1,57 @@ +package com.github.avrokotlin.avro4k.endecode + +import com.github.avrokotlin.avro4k.record +import io.kotest.core.factory.TestFactory +import io.kotest.core.spec.style.WordSpec +import io.kotest.core.spec.style.wordSpec +import kotlinx.serialization.Serializable + +class ArrayEncoderTest : WordSpec({ + includeForEveryEncoder { arrayEncodingTests(it) } +}) + +@Suppress("ArrayInDataClass") +fun arrayEncodingTests(encoderToTest: EnDecoder): TestFactory { + return wordSpec { + "en-/decoder" should { + "generate GenericData.Array for an Array" { + @Serializable + data class ArrayBooleanTest(val a: Array) + + val value = ArrayBooleanTest(arrayOf(true, false, true)) + encoderToTest.testEncodeDecode(value, record(value.a.asList())) + } + "support GenericData.Array for an Array with other fields" { + @Serializable + data class ArrayBooleanWithOthersTest(val a: String, val b: Array, val c: Long) + + val value = ArrayBooleanWithOthersTest("foo", arrayOf(true, false, true), 123L) + encoderToTest.testEncodeDecode( + value, record( + "foo", + listOf(true, false, true), + 123L + ) + ) + } + + "generate GenericData.Array for a List" { + @Serializable + data class ListStringTest(val a: List) + encoderToTest.testEncodeDecode( + ListStringTest(listOf("we23", "54z")), record( + listOf("we23", "54z") + ) + ) + } + "generate GenericData.Array for a Set" { + @Serializable + data class SetLongTest(val a: Set) + + val value = SetLongTest(setOf(123L, 643L, 912L)) + val record = record(listOf(123L, 643L, 912)) + encoderToTest.testEncodeDecode(value, record) + } + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/AvroInlineEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/AvroInlineEncoderTest.kt new file mode 100644 index 00000000..30da47fe --- /dev/null +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/AvroInlineEncoderTest.kt @@ -0,0 +1,32 @@ +package com.github.avrokotlin.avro4k.endecode + +import com.github.avrokotlin.avro4k.AvroInline +import com.github.avrokotlin.avro4k.record +import io.kotest.core.factory.TestFactory +import io.kotest.core.spec.style.FunSpec +import io.kotest.core.spec.style.stringSpec +import kotlinx.serialization.Serializable + +class AvroInlineEncoderTest : FunSpec({ + includeForEveryEncoder { + inlineEncodingTests(it) + } +}) + +fun inlineEncodingTests(encoderToTest: EnDecoder): TestFactory { + return stringSpec { + "encode/decode @AvroInline" { + @Serializable + @AvroInline + data class Name(val value: String) + + @Serializable + data class Product(val id: String, val name: Name) + encoderToTest.testEncodeDecode( + Product("123", Name("sneakers")), + record("123", "sneakers") + ) + } + } +} + diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/AvroNameEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/AvroNameEncoderTest.kt new file mode 100644 index 00000000..2e0c4509 --- /dev/null +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/AvroNameEncoderTest.kt @@ -0,0 +1,22 @@ +package com.github.avrokotlin.avro4k.endecode + +import com.github.avrokotlin.avro4k.AvroName +import com.github.avrokotlin.avro4k.record +import io.kotest.core.factory.TestFactory +import io.kotest.core.spec.style.FunSpec +import io.kotest.core.spec.style.stringSpec +import kotlinx.serialization.Serializable + +class AvroNameEncoderTest : FunSpec({ + includeForEveryEncoder { avroNameEncodingTests(it) } +}) + +fun avroNameEncodingTests(endecoder: EnDecoder): TestFactory { + return stringSpec { + "take into account @AvroName on fields" { + @Serializable + data class Foo(@AvroName("bar") val foo: String) + endecoder.testEncodeDecode(Foo("hello"), record("hello")) + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/BigDecimalEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/BigDecimalEncoderTest.kt new file mode 100644 index 00000000..7130b704 --- /dev/null +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/BigDecimalEncoderTest.kt @@ -0,0 +1,74 @@ +@file:UseSerializers(BigDecimalSerializer::class) + +package com.github.avrokotlin.avro4k.endecode + +import com.github.avrokotlin.avro4k.record +import com.github.avrokotlin.avro4k.serializer.BigDecimalSerializer +import io.kotest.core.factory.TestFactory +import io.kotest.core.spec.style.FunSpec +import io.kotest.core.spec.style.stringSpec +import kotlinx.serialization.Serializable +import kotlinx.serialization.UseSerializers +import org.apache.avro.Conversions +import org.apache.avro.LogicalTypes +import org.apache.avro.Schema +import org.apache.avro.SchemaBuilder +import org.apache.avro.generic.GenericData +import java.math.BigDecimal + +class BigDecimalEncoderTest : FunSpec({ + includeForEveryEncoder { bigDecimalEncoderTests(it) } +}) +fun bigDecimalEncoderTests(encoderToTest: EnDecoder): TestFactory { + @Serializable + data class BigDecimalTest(val decimal: BigDecimal) + + return stringSpec { + "use byte array for BigDecimal" { + val schema = encoderToTest.avro.schema(BigDecimalTest.serializer()) + val obj = BigDecimalTest(BigDecimal("12.34")) + val s = schema.getField("decimal").schema() + val bytes = Conversions.DecimalConversion().toBytes(obj.decimal, s, s.logicalType) + + encoderToTest.testEncodeDecode(value = obj, shouldMatch = record(bytes), schema = schema) + } + + "allow BigDecimal to be en-/decoded as strings" { + val decimalSchema = Schema.create(Schema.Type.STRING) + val schema = SchemaBuilder.record("Test").fields() + .name("decimal").type(decimalSchema).noDefault() + .endRecord() + encoderToTest.testEncodeDecode( + value = BigDecimalTest(BigDecimal("123.456")), + shouldMatch = record("123.456"), + schema = schema + ) + } + "support nullable big decimals" { + @Serializable + data class NullableBigDecimalTest(val big: BigDecimal?) + + val schema = encoderToTest.avro.schema(NullableBigDecimalTest.serializer()) + + val obj = NullableBigDecimalTest(BigDecimal("123.40")) + val bigSchema = schema.getField("big").schema().types[1] //Nullable is encoded as Union + val bytes = Conversions.DecimalConversion().toBytes(obj.big, bigSchema, bigSchema.logicalType) + encoderToTest.testEncodeDecode(obj, record(bytes)) + encoderToTest.testEncodeDecode(NullableBigDecimalTest(null), record(null)) + } + + "allow BigDecimal to be en-/decoded as generic fixed" { + //Schema needs to have the precision of 16 in order to serialize a 8 digit integer with a scale of 8 + val decimal = LogicalTypes.decimal(16, 8).addToSchema(Schema.createFixed("decimal", null, null, 8)) + + val schema = SchemaBuilder.record("Test").fields() + .name("decimal").type(decimal).noDefault() + .endRecord() + encoderToTest.testEncodeDecode( + value = BigDecimalTest(BigDecimal("12345678.00000000")), + shouldMatch = record(GenericData.Fixed(decimal, byteArrayOf(0, 4, 98, -43, 55, 43, -114, 0))), + schema = schema + ) + } + } +} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/BigIntegerEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/BigIntegerEncoderTest.kt new file mode 100644 index 00000000..0596a1bc --- /dev/null +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/BigIntegerEncoderTest.kt @@ -0,0 +1,38 @@ +@file:UseSerializers(BigIntegerSerializer::class) + +package com.github.avrokotlin.avro4k.endecode + +import com.github.avrokotlin.avro4k.record +import com.github.avrokotlin.avro4k.serializer.BigIntegerSerializer +import io.kotest.core.factory.TestFactory +import io.kotest.core.spec.style.FunSpec +import io.kotest.core.spec.style.stringSpec +import kotlinx.serialization.Serializable +import kotlinx.serialization.UseSerializers +import java.math.BigInteger + +class BigIntegerEncoderTest : FunSpec({ + includeForEveryEncoder { bigIntegerEncoderTests(it) } +}) +fun bigIntegerEncoderTests(encoderToTest: EnDecoder): TestFactory { + return stringSpec { + "use string for BigInteger" { + @Serializable + data class BigIntegerTest(val b: BigInteger) + + val test = BigIntegerTest(BigInteger("123123123123213213213123214325365477686789676234")) + encoderToTest.testEncodeDecode(test, record("123123123123213213213123214325365477686789676234")) + } + + "encode nullable BigInteger" { + @Serializable + data class NullableBigIntegerTest(val b: BigInteger?) + encoderToTest.testEncodeDecode( + NullableBigIntegerTest(BigInteger("12312312312321312365477686789676234")), + record("12312312312321312365477686789676234") + ) + encoderToTest.testEncodeDecode(NullableBigIntegerTest(null), record(null)) + + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/ByteArrayEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/ByteArrayEncoderTest.kt new file mode 100644 index 00000000..796219f9 --- /dev/null +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/ByteArrayEncoderTest.kt @@ -0,0 +1,56 @@ +package com.github.avrokotlin.avro4k.endecode + +import com.github.avrokotlin.avro4k.record +import io.kotest.core.factory.TestFactory +import io.kotest.core.spec.style.FunSpec +import io.kotest.core.spec.style.stringSpec +import kotlinx.serialization.Serializable +import org.apache.avro.Schema +import org.apache.avro.SchemaBuilder +import org.apache.avro.generic.GenericData +import java.nio.ByteBuffer + +class ByteArrayEncoderTest : FunSpec({ + includeForEveryEncoder { byteArrayEncoderTests(it) } +}) + +fun byteArrayEncoderTests(encoderToTest: EnDecoder): TestFactory { + return stringSpec { + @Serializable + data class ByteArrayTest(val z: ByteArray) + + fun avroByteArray(vararg bytes: Byte) = ByteBuffer.wrap(bytes) + "encode/decode ByteArray" { + encoderToTest.testEncodeDecode( + ByteArrayTest(byteArrayOf(1, 4, 9)), record(avroByteArray(1, 4, 9)) + ) + } + "encode/decode List" { + @Serializable + data class ListByteTest(val z: List) + encoderToTest.testEncodeDecode(ListByteTest(listOf(1, 4, 9)), record(avroByteArray(1, 4, 9))) + } + + "encode/decode Array to ByteBuffer" { + @Serializable + data class ArrayByteTest(val z: Array) + encoderToTest.testEncodeDecode(ArrayByteTest(arrayOf(1, 4, 9)), record(avroByteArray(1, 4, 9))) + } + + "encode/decode ByteArray as FIXED when schema is Type.Fixed" { + val fixedSchema = Schema.createFixed("ByteArray", null, null, 8) + val schema = + SchemaBuilder.record("ByteArrayTest").fields().name("z").type(fixedSchema).noDefault().endRecord() + val unpaddedByteArray = byteArrayOf(1, 4, 9) + val paddedByteArray = byteArrayOf(0, 0, 0, 0, 0, 1, 4, 9) + val encoded = encoderToTest.testEncodeIsEqual( + value = ByteArrayTest(unpaddedByteArray), + shouldMatch = record(GenericData.Fixed(fixedSchema, paddedByteArray)), + schema = schema + ) + encoderToTest.testDecodeIsEqual( + byteArray = encoded, value = ByteArrayTest(paddedByteArray), readSchema = schema + ) + } + } +} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/DateEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/DateEncoderTest.kt new file mode 100644 index 00000000..1a4432aa --- /dev/null +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/DateEncoderTest.kt @@ -0,0 +1,96 @@ +@file:UseSerializers( + LocalDateTimeSerializer::class, + LocalDateSerializer::class, + LocalTimeSerializer::class, + TimestampSerializer::class, +) + +package com.github.avrokotlin.avro4k.endecode + +import com.github.avrokotlin.avro4k.record +import com.github.avrokotlin.avro4k.serializer.* +import io.kotest.core.factory.TestFactory +import io.kotest.core.spec.style.FunSpec +import io.kotest.core.spec.style.stringSpec +import kotlinx.serialization.Serializable +import kotlinx.serialization.UseSerializers +import java.sql.Timestamp +import java.time.Instant +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalTime +import java.time.temporal.ChronoUnit + +class DateEncoderTest : FunSpec({ + includeForEveryEncoder { dateEncoderTests(it) } +}) + +fun dateEncoderTests(encoderToTest: EnDecoder): TestFactory { + return stringSpec { + "encode/decode LocalTime as an Int" { + @Serializable + data class LocalTimeTest(val t: LocalTime) + encoderToTest.testEncodeDecode(LocalTimeTest(LocalTime.of(12, 50, 45)), record(46245000)) + } + + "encode/decode nullable LocalTime" { + @Serializable + data class NullableLocalTimeTest(val t: LocalTime?) + encoderToTest.testEncodeDecode(NullableLocalTimeTest(LocalTime.of(12, 50, 45)), record(46245000)) + encoderToTest.testEncodeDecode(NullableLocalTimeTest(null), record(null)) + } + + "encode/decode LocalDate as an Int" { + @Serializable + data class LocalDateTest(val d: LocalDate) + encoderToTest.testEncodeDecode(LocalDateTest(LocalDate.of(2018, 9, 10)), record(17784)) + } + + "encode/decode LocalDateTime as Long" { + @Serializable + data class LocalDateTimeTest(val dt: LocalDateTime) + encoderToTest.testEncodeDecode( + LocalDateTimeTest(LocalDateTime.of(2018, 9, 10, 11, 58, 59)), + record(1536580739000L) + ) + } + + "encode/decode Timestamp as Long" { + @Serializable + data class TimestampTest(val t: Timestamp) + encoderToTest.testEncodeDecode( + TimestampTest(Timestamp.from(Instant.ofEpochMilli(1538312231000L))), + record(1538312231000L) + ) + } + + "encode/decode nullable Timestamp as Long" { + @Serializable + data class NullableTimestampTest(val t: Timestamp?) + encoderToTest.testEncodeDecode(NullableTimestampTest(null), record(null)) + encoderToTest.testEncodeDecode( + NullableTimestampTest(Timestamp.from(Instant.ofEpochMilli(1538312231000L))), + record(1538312231000L) + ) + } + + "encode/decode Instant as Long" { + @Serializable + data class InstantMillisTest(@Serializable(with = InstantSerializer::class) val i: Instant) + encoderToTest.testEncodeDecode( + InstantMillisTest(Instant.ofEpochMilli(1538312231000L)), + record(1538312231000L) + ) + } + + "encode/decode Instant with microseconds as Long" { + @Serializable + data class InstantMicrosTest(@Serializable(with = InstantToMicroSerializer::class) val i: Instant) + + encoderToTest.testEncodeDecode( + InstantMicrosTest(Instant.ofEpochMilli(1538312231000L).plus(5, ChronoUnit.MICROS)), + record(1538312231000005L) + ) + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/EnDecoder.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/EnDecoder.kt new file mode 100644 index 00000000..a283fa52 --- /dev/null +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/EnDecoder.kt @@ -0,0 +1,125 @@ +package com.github.avrokotlin.avro4k.endecode + +import com.github.avrokotlin.avro4k.Avro +import com.github.avrokotlin.avro4k.RecordBuilderForTest +import io.kotest.assertions.fail +import io.kotest.assertions.withClue +import io.kotest.core.factory.TestFactory +import io.kotest.core.spec.DslDrivenSpec +import io.kotest.matchers.equality.shouldBeEqualToComparingFields +import io.kotest.matchers.shouldBe +import io.kotest.mpp.newInstanceNoArgConstructorOrObjectInstance +import kotlinx.serialization.DeserializationStrategy +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerializationStrategy +import kotlinx.serialization.serializer +import org.apache.avro.Schema +import org.apache.avro.generic.GenericDatumReader +import org.apache.avro.generic.GenericDatumWriter +import org.apache.avro.generic.GenericRecord +import org.apache.avro.io.Decoder +import org.apache.avro.io.DecoderFactory +import org.apache.avro.io.Encoder +import org.apache.avro.io.EncoderFactory +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream +import java.io.InputStream + + +sealed interface EnDecoder { + val name: String + var avro: Avro + fun encodeGenericRecordForComparison(value: GenericRecord, schema: Schema): ByteArray + + fun decode( + byteArray: ByteArray, + deserializer: DeserializationStrategy, + readSchema: Schema, + writeSchema: Schema + ): T + + fun encode(value: T, serializer: SerializationStrategy, schema: Schema): ByteArray +} + +class AvroLibEnDecoder : EnDecoder { + override var avro: Avro = Avro.default + override val name: String = "AvroLibrary" + override fun encode(value: T, serializer: SerializationStrategy, schema: Schema): ByteArray { + val asRecord = avro.toRecord(serializer, schema, value) + return encodeGenericRecordForComparison(asRecord, schema) + } + + override fun encodeGenericRecordForComparison(value: GenericRecord, schema: Schema): ByteArray { + val writer = GenericDatumWriter(schema) + val byteArrayOutputStream = ByteArrayOutputStream() + val encoder = avroLibEncoder(schema, byteArrayOutputStream) + writer.write(value, encoder) + encoder.flush() + return byteArrayOutputStream.toByteArray() + } + + override fun decode( + byteArray: ByteArray, + deserializer: DeserializationStrategy, + readSchema: Schema, + writeSchema: Schema + ): T { + val input = ByteArrayInputStream(byteArray) + val reader = GenericDatumReader(writeSchema, readSchema) + val genericData = reader.read(null, avroLibDecoder(writeSchema, input)) + return avro.fromRecord(deserializer,genericData) + } + + fun avroLibEncoder(schema: Schema, outputStream: ByteArrayOutputStream): Encoder = + EncoderFactory.get().jsonEncoder(schema, outputStream) + + fun avroLibDecoder(schema: Schema, inputStream: InputStream) : Decoder = + DecoderFactory.get().jsonDecoder(schema, inputStream) +} + +inline fun EnDecoder.testEncodeDecode( + value: T, + shouldMatch: RecordBuilderForTest, + serializer: KSerializer = avro.serializersModule.serializer(), + schema: Schema = avro.schema(serializer) +) { + val encoded = testEncodeIsEqual(value, shouldMatch, serializer, schema) + testDecodeIsEqual(encoded, value,serializer, schema) +} + +inline fun EnDecoder.testEncodeIsEqual( + value: T, + shouldMatch: RecordBuilderForTest, + serializer: SerializationStrategy = avro.serializersModule.serializer(), + schema: Schema = avro.schema(serializer) +) : ByteArray{ + val record = shouldMatch.createRecord(schema) + val encodedValue = encode(value, serializer, schema) + withClue("Encoded result was not equal to the encoded result of the apache avro library.") { + encodedValue shouldBe encodeGenericRecordForComparison(record, schema) + } + return encodedValue +} +inline fun EnDecoder.testDecodeIsEqual( + byteArray: ByteArray, + value: T, + serializer: KSerializer = avro.serializersModule.serializer(), + readSchema: Schema = avro.schema(serializer), + writeSchema: Schema = readSchema +) : T { + val decodedValue = decode(byteArray, serializer, readSchema, writeSchema) + withClue("Decoded result was not equal to the passed value.") { + if (decodedValue == null && value != null) { + fail("Decoded value is null but '$value' is expected.") + } else if (decodedValue != null && value != null) { + decodedValue shouldBeEqualToComparingFields value + } + } + return decodedValue +} + +fun DslDrivenSpec.includeForEveryEncoder(createFactoryToInclude: (EnDecoder) -> TestFactory) { + EnDecoder::class.sealedSubclasses.map { it.newInstanceNoArgConstructorOrObjectInstance() }.forEach { + include(it.name, createFactoryToInclude.invoke(it)) + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/EnumEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/EnumEncoderTest.kt new file mode 100644 index 00000000..63ec5da4 --- /dev/null +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/EnumEncoderTest.kt @@ -0,0 +1,40 @@ +package com.github.avrokotlin.avro4k.endecode + +import com.github.avrokotlin.avro4k.record +import com.github.avrokotlin.avro4k.schema.Wine +import io.kotest.core.factory.TestFactory +import io.kotest.core.spec.style.FunSpec +import io.kotest.core.spec.style.stringSpec +import kotlinx.serialization.Serializable +import org.apache.avro.generic.GenericData + +class EnumEncoderTest : FunSpec({ + includeForEveryEncoder { enumEncoderTests(it) } +}) +fun enumEncoderTests(enDecoder: EnDecoder): TestFactory { + @Serializable + data class MyWine(val wine: Wine) + + @Serializable + data class NullableWine(val wine: Wine?) + return stringSpec { + "support enums" { + enDecoder.testEncodeDecode( + MyWine(Wine.Malbec), record( + GenericData.EnumSymbol( + null, Wine.Malbec + ) + ) + ) + } + + "support nullable enums" { + val enumSchema = enDecoder.avro.schema(NullableWine.serializer()).getField("wine").schema().types[1] + enDecoder.testEncodeDecode(NullableWine(Wine.Shiraz), record( + GenericData.EnumSymbol(enumSchema, Wine.Shiraz) + ) + ) + enDecoder.testEncodeDecode(NullableWine(null), record(null)) + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/MapEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/MapEncoderTest.kt new file mode 100644 index 00000000..61f94eea --- /dev/null +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/MapEncoderTest.kt @@ -0,0 +1,75 @@ +package com.github.avrokotlin.avro4k.endecode + +import com.github.avrokotlin.avro4k.record +import io.kotest.core.factory.TestFactory +import io.kotest.core.spec.style.StringSpec +import io.kotest.core.spec.style.stringSpec +import kotlinx.serialization.Serializable +import java.nio.ByteBuffer + +class MapEncoderTest : StringSpec({ + includeForEveryEncoder { mapEncoderTests(it) } +}) + +fun mapEncoderTests(enDecoder: EnDecoder): TestFactory { + return stringSpec { + + "encode/decode a Map" { + @Serializable + data class StringBooleanTest(val a: Map) + enDecoder.testEncodeDecode( + StringBooleanTest(mapOf("a" to true, "b" to false, "c" to true)), + record(mapOf("a" to true, "b" to false, "c" to true)) + ) + } + + "encode/decode a Map" { + + @Serializable + data class StringStringTest(val a: Map) + enDecoder.testEncodeDecode( + StringStringTest(mapOf("a" to "x", "b" to "y", "c" to "z")), + record(mapOf("a" to "x", "b" to "y", "c" to "z")) + ) + } + + "encode/decode a Map" { + @Serializable + data class StringByteArrayTest(val a: Map) + enDecoder.testEncodeDecode( + StringByteArrayTest( + mapOf( + "a" to "x".toByteArray(), + "b" to "y".toByteArray(), + "c" to "z".toByteArray() + ) + ), + record( + mapOf( + "a" to ByteBuffer.wrap("x".toByteArray()), + "b" to ByteBuffer.wrap("y".toByteArray()), + "c" to ByteBuffer.wrap("z".toByteArray()) + ) + ) + ) + } + + "encode/decode a Map of records" { + + @Serializable + data class Foo(val a: String, val b: Boolean) + + @Serializable + data class StringFooTest(val a: Map) + enDecoder.testEncodeDecode( + StringFooTest(mapOf("a" to Foo("x", true), "b" to Foo("y", false))), + record( + mapOf( + "a" to record("x", true), + "b" to record("y", false) + ) + ) + ) + } + } +} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/NamingStrategyEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/NamingStrategyEncoderTest.kt new file mode 100644 index 00000000..1db07213 --- /dev/null +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/NamingStrategyEncoderTest.kt @@ -0,0 +1,38 @@ +package com.github.avrokotlin.avro4k.endecode + +import com.github.avrokotlin.avro4k.Avro +import com.github.avrokotlin.avro4k.AvroConfiguration +import com.github.avrokotlin.avro4k.record +import com.github.avrokotlin.avro4k.schema.PascalCaseNamingStrategy +import com.github.avrokotlin.avro4k.schema.SnakeCaseNamingStrategy +import io.kotest.core.factory.TestFactory +import io.kotest.core.spec.style.WordSpec +import io.kotest.core.spec.style.stringSpec +import io.kotest.matchers.shouldNotBe +import kotlinx.serialization.Serializable + +class NamingStrategyEncoderTest : WordSpec({ + includeForEveryEncoder { namingStrategyEncoderTests(it) } +}) + +fun namingStrategyEncoderTests(enDecoder: EnDecoder): TestFactory { + return stringSpec { + @Serializable + data class Foo(val fooBar: String) + + "encode/decode fields with snake_casing" { + enDecoder.avro = Avro(AvroConfiguration(SnakeCaseNamingStrategy)) + val schema = enDecoder.avro.schema(Foo.serializer()) + schema.getField("foo_bar") shouldNotBe null + enDecoder.testEncodeDecode(Foo("hello"), record("hello")) + } + + "encode/decode fields with PascalCasing" { + enDecoder.avro = Avro(AvroConfiguration(PascalCaseNamingStrategy)) + val schema = enDecoder.avro.schema(Foo.serializer()) + schema.getField("FooBar") shouldNotBe null + enDecoder.testEncodeDecode(Foo("hello"), record("hello")) + } + + } +} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/RecordEncodingTests.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/RecordEncodingTests.kt new file mode 100644 index 00000000..b84b8a53 --- /dev/null +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/RecordEncodingTests.kt @@ -0,0 +1,83 @@ +package com.github.avrokotlin.avro4k.endecode + +import com.github.avrokotlin.avro4k.record +import io.kotest.core.factory.TestFactory +import io.kotest.core.spec.style.WordSpec +import io.kotest.core.spec.style.stringSpec +import kotlinx.serialization.Serializable +import org.apache.avro.Schema +import org.apache.avro.SchemaBuilder +import org.apache.avro.generic.GenericData + +class RecordEncodingTests : WordSpec({ + includeForEveryEncoder { recordEncodingTests(it) } +}) + +fun recordEncodingTests(encoderToTest: EnDecoder): TestFactory { + @Serializable + data class StringFoo(val s: String) + return stringSpec { + "encode/decode strings as UTF8" { + encoderToTest.testEncodeDecode(StringFoo("hello"), record("hello")) + } + "encode/decode strings as GenericFixed and pad bytes when schema is Type.FIXED" { + val fixedSchema = Schema.createFixed("FixedString", null, null, 7) + val schema = SchemaBuilder.record("Foo").fields().name("s").type(fixedSchema).noDefault().endRecord() + val encoded = encoderToTest.testEncodeIsEqual( + value = StringFoo("hello"), + shouldMatch = record(GenericData.Fixed(fixedSchema, byteArrayOf(104, 101, 108, 108, 111, 0, 0))), + schema = schema + ) + encoderToTest.testDecodeIsEqual(encoded, StringFoo(String("hello".toByteArray() + byteArrayOf(0, 0)))) + } + "encode/decode nullable string" { + @Serializable + data class NullableString(val a: String?) + encoderToTest.testEncodeDecode(NullableString("hello"), record("hello")) + encoderToTest.testEncodeDecode(NullableString(null), record(null)) + } + "encode/decode longs" { + @Serializable + data class LongFoo(val l: Long) + encoderToTest.testEncodeDecode(LongFoo(123456L), record(123456L)) + } + "encode/decode doubles" { + + @Serializable + data class DoubleFoo(val d: Double) + encoderToTest.testEncodeDecode(DoubleFoo(123.435), record(123.435)) + } + "encode/decode booleans" { + @Serializable + data class BooleanFoo(val d: Boolean) + encoderToTest.testEncodeDecode(BooleanFoo(false), record(false)) + } + "encode/decode nullable booleans" { + @Serializable + data class NullableBoolean(val a: Boolean?) + encoderToTest.testEncodeDecode(NullableBoolean(true), record(true)) + encoderToTest.testEncodeDecode(NullableBoolean(null), record(null)) + } + "encode/decode floats" { + @Serializable + data class FloatFoo(val d: Float) + encoderToTest.testEncodeDecode(FloatFoo(123.435F), record(123.435F)) + } + "encode/decode ints" { + @Serializable + data class IntFoo(val i: Int) + encoderToTest.testEncodeDecode(IntFoo(123), record(123)) + } + "encode/decode shorts" { + @Serializable + data class ShortFoo(val s: Short) + encoderToTest.testEncodeDecode(ShortFoo(123.toShort()), record(123.toShort())) + } + "encode/decode bytes" { + @Serializable + data class ByteFoo(val b: Byte) + encoderToTest.testEncodeDecode(ByteFoo(123.toByte()), record(123.toByte())) + } + + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/SealedClassEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/SealedClassEncoderTest.kt new file mode 100644 index 00000000..cd6f3017 --- /dev/null +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/SealedClassEncoderTest.kt @@ -0,0 +1,37 @@ +package com.github.avrokotlin.avro4k.endecode + +import com.github.avrokotlin.avro4k.Avro +import com.github.avrokotlin.avro4k.record +import com.github.avrokotlin.avro4k.schema.Operation +import com.github.avrokotlin.avro4k.schema.ReferencingNullableSealedClass +import com.github.avrokotlin.avro4k.schema.ReferencingSealedClass +import io.kotest.core.factory.TestFactory +import io.kotest.core.spec.style.StringSpec +import io.kotest.core.spec.style.stringSpec + + +class SealedClassEncoderTest : StringSpec({ + includeForEveryEncoder { sealedClassEncoderTests(it) } +}) + +fun sealedClassEncoderTests(encoderToTest: EnDecoder): TestFactory { + return stringSpec { + "encode/decode sealed classes" { + val addSchema = encoderToTest.avro.schema(Operation.Binary.Add.serializer()) + encoderToTest.testEncodeDecode( + ReferencingSealedClass(Operation.Binary.Add(1, 2)), record(record(1, 2).createRecord(addSchema)) + ) + } + "encode/decode nullable sealed classes" { + val addSchema = Avro.default.schema(Operation.Binary.Add.serializer()) + + encoderToTest.testEncodeDecode( + ReferencingNullableSealedClass( + Operation.Binary.Add(1, 2) + ), record(record(1, 2).createRecord(addSchema)) + ) + + encoderToTest.testEncodeDecode(ReferencingNullableSealedClass(null), record(null)) + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/TransientEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/TransientEncoderTest.kt new file mode 100644 index 00000000..cdf1d62e --- /dev/null +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/TransientEncoderTest.kt @@ -0,0 +1,32 @@ +package com.github.avrokotlin.avro4k.endecode + +import com.github.avrokotlin.avro4k.Avro +import com.github.avrokotlin.avro4k.record +import io.kotest.core.factory.TestFactory +import io.kotest.core.spec.style.FunSpec +import io.kotest.core.spec.style.stringSpec +import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient +import org.apache.avro.generic.GenericData + +class TransientEncoderTest : FunSpec({ + includeForEveryEncoder { transientEncoderTests(it) } +}) +fun transientEncoderTests(encoderToTest: EnDecoder): TestFactory { + @Serializable + data class Foo(val a: String, @Transient val b: String = "foo", val c: String) + return stringSpec { + "should skip @Transient fields" { + val value = Foo("a", "b", "c") + encoderToTest.testEncodeIsEqual(value, record("a", "c")) + } + "decoder should populate transient fields with default" { + val schema = Avro.default.schema(Foo.serializer()) + val record = GenericData.Record(schema) + record.put("a", "hello") + + val encoded = encoderToTest.testEncodeIsEqual(Foo("a", "b","c"), record("a", "c")) + encoderToTest.testDecodeIsEqual(encoded, Foo(a = "a", c="c")) + } + } +} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/URLEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/URLEncoderTest.kt new file mode 100644 index 00000000..5037c042 --- /dev/null +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/URLEncoderTest.kt @@ -0,0 +1,36 @@ +@file:UseSerializers(URLSerializer::class) + +package com.github.avrokotlin.avro4k.endecode + +import com.github.avrokotlin.avro4k.record +import com.github.avrokotlin.avro4k.serializer.URLSerializer +import io.kotest.core.factory.TestFactory +import io.kotest.core.spec.style.FunSpec +import io.kotest.core.spec.style.stringSpec +import kotlinx.serialization.Serializable +import kotlinx.serialization.UseSerializers +import java.net.URL + +class URLEncoderTest : FunSpec({ + includeForEveryEncoder { urlEncoderTests(it) } +}) +fun urlEncoderTests(enDecoder: EnDecoder): TestFactory { + return stringSpec { + "encode/decode URLs as string" { + @Serializable + data class UrlTest(val b: URL) + + val test = UrlTest(URL("https://www.sksamuel.com")) + enDecoder.testEncodeDecode(test, record("https://www.sksamuel.com")) + } + + "encode/decode nullable URLs" { + @Serializable + data class NullableUrlTest(val b: URL?) + enDecoder.testEncodeDecode( + NullableUrlTest(URL("https://www.sksamuel.com")), record("https://www.sksamuel.com") + ) + enDecoder.testEncodeDecode(NullableUrlTest(null), record(null)) + } + } +} diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/UUIDEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/UUIDEncoderTest.kt new file mode 100644 index 00000000..fbe9765d --- /dev/null +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/UUIDEncoderTest.kt @@ -0,0 +1,36 @@ +@file:UseSerializers(UUIDSerializer::class) + +package com.github.avrokotlin.avro4k.endecode + +import com.github.avrokotlin.avro4k.record +import com.github.avrokotlin.avro4k.serializer.UUIDSerializer +import io.kotest.core.factory.TestFactory +import io.kotest.core.spec.style.FunSpec +import io.kotest.core.spec.style.stringSpec +import kotlinx.serialization.Serializable +import kotlinx.serialization.UseSerializers +import java.util.* + +class UUIDEncoderTest : FunSpec({ + includeForEveryEncoder { uuidEncoderTests(it) } +}) +fun uuidEncoderTests(encoderToTest: EnDecoder): TestFactory { + return stringSpec { + "encode/decode UUIDs" { + @Serializable + data class UUIDTest(val uuid: UUID) + + val uuid = UUID.randomUUID() + encoderToTest.testEncodeDecode(UUIDTest(uuid), record(uuid.toString())) + } + + "encode/decode nullable UUIDs" { + @Serializable + data class NullableUUIDTest(val uuid: UUID?) + + val uuid = UUID.randomUUID() + encoderToTest.testEncodeDecode(NullableUUIDTest(uuid), record(uuid.toString())) + encoderToTest.testEncodeDecode(NullableUUIDTest(null), record(null)) + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/ValueClassEncoderTest.kt b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/ValueClassEncoderTest.kt new file mode 100644 index 00000000..ca1f0ddb --- /dev/null +++ b/src/test/kotlin/com/github/avrokotlin/avro4k/endecode/ValueClassEncoderTest.kt @@ -0,0 +1,25 @@ +package com.github.avrokotlin.avro4k.endecode + +import com.github.avrokotlin.avro4k.record +import com.github.avrokotlin.avro4k.schema.ValueClassSchemaTest +import io.kotest.core.factory.TestFactory +import io.kotest.core.spec.style.StringSpec +import io.kotest.core.spec.style.stringSpec +import java.util.* + +class ValueClassEncoderTest : StringSpec({ + includeForEveryEncoder { valueClassEncoderTests(it) } +}) +fun valueClassEncoderTests(encoderToTest: EnDecoder): TestFactory { + return stringSpec { + "encode/decode value class" { + val uuid = UUID.randomUUID() + encoderToTest.testEncodeDecode( + ValueClassSchemaTest.ContainsInlineTest( + ValueClassSchemaTest.StringWrapper("100500"), ValueClassSchemaTest.UuidWrapper(uuid) + ), + record("100500", uuid.toString()) + ) + } + } +} \ No newline at end of file