diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 85d9fc4..1152f2a 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -49,4 +49,8 @@ object Versions { const val testExtJunit = "1.1.5" const val testRunner = "1.5.2" } + + object KotlinX { + const val serialization = "1.5.0" + } } diff --git a/fixture/build.gradle.kts b/fixture/build.gradle.kts index 7ba8341..f020b81 100644 --- a/fixture/build.gradle.kts +++ b/fixture/build.gradle.kts @@ -21,6 +21,7 @@ plugins { id("com.android.lint") id("com.vanniktech.maven.publish") id("org.jetbrains.dokka") + id("org.jetbrains.kotlin.plugin.serialization") version Versions.kotlin } apply(from = "$rootDir/gradle/scripts/jacoco.gradle.kts") @@ -46,6 +47,8 @@ dependencies { testImplementation(kotlin("test-junit")) testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:${Versions.mockitoKotlin}") + testImplementation("org.jetbrains.kotlinx:kotlinx-serialization-json:${Versions.KotlinX.serialization}") + // Used for ComparisonTest @Suppress("GradleDependency") testImplementation("com.github.marcellogalhardo:kotlin-fixture:${Versions.marcellogalhardo}") diff --git a/fixture/src/main/kotlin/com/appmattus/kotlinfixture/decorator/constructor/ConstructorStrategy.kt b/fixture/src/main/kotlin/com/appmattus/kotlinfixture/decorator/constructor/ConstructorStrategy.kt index 5e61c1b..1f034da 100644 --- a/fixture/src/main/kotlin/com/appmattus/kotlinfixture/decorator/constructor/ConstructorStrategy.kt +++ b/fixture/src/main/kotlin/com/appmattus/kotlinfixture/decorator/constructor/ConstructorStrategy.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 Appmattus Limited + * Copyright 2020-2023 Appmattus Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,4 +28,15 @@ interface ConstructorStrategy { * Returns [obj] constructors in the order to try when generating an instance. */ fun constructors(context: Context, obj: KClass<*>): Collection> + + /** + * Constructors of the class with Serializable constructors filtered out + */ + val KClass<*>.filteredConstructors: Collection> + get() = constructors.filterNot { it.isSerializationConstructor() } + + private fun KFunction.isSerializationConstructor(): Boolean { + val lastParameterType = (parameters.lastOrNull()?.type?.classifier as? KClass<*>)?.qualifiedName + return lastParameterType == "kotlinx.serialization.internal.SerializationConstructorMarker" + } } diff --git a/fixture/src/main/kotlin/com/appmattus/kotlinfixture/decorator/constructor/GreedyConstructorStrategy.kt b/fixture/src/main/kotlin/com/appmattus/kotlinfixture/decorator/constructor/GreedyConstructorStrategy.kt index 7ba4793..6e8d32d 100644 --- a/fixture/src/main/kotlin/com/appmattus/kotlinfixture/decorator/constructor/GreedyConstructorStrategy.kt +++ b/fixture/src/main/kotlin/com/appmattus/kotlinfixture/decorator/constructor/GreedyConstructorStrategy.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 Appmattus Limited + * Copyright 2020-2023 Appmattus Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,6 @@ import kotlin.reflect.KFunction */ object GreedyConstructorStrategy : ConstructorStrategy { override fun constructors(context: Context, obj: KClass<*>): Collection> { - return obj.constructors.sortedByDescending { it.parameters.size } + return obj.filteredConstructors.sortedByDescending { it.parameters.size } } } diff --git a/fixture/src/main/kotlin/com/appmattus/kotlinfixture/decorator/constructor/ModestConstructorStrategy.kt b/fixture/src/main/kotlin/com/appmattus/kotlinfixture/decorator/constructor/ModestConstructorStrategy.kt index 621002f..9347ae9 100644 --- a/fixture/src/main/kotlin/com/appmattus/kotlinfixture/decorator/constructor/ModestConstructorStrategy.kt +++ b/fixture/src/main/kotlin/com/appmattus/kotlinfixture/decorator/constructor/ModestConstructorStrategy.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 Appmattus Limited + * Copyright 2020-2023 Appmattus Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,6 @@ import kotlin.reflect.KFunction */ object ModestConstructorStrategy : ConstructorStrategy { override fun constructors(context: Context, obj: KClass<*>): Collection> { - return obj.constructors.sortedBy { it.parameters.size } + return obj.filteredConstructors.sortedBy { it.parameters.size } } } diff --git a/fixture/src/main/kotlin/com/appmattus/kotlinfixture/decorator/constructor/RandomConstructorStrategy.kt b/fixture/src/main/kotlin/com/appmattus/kotlinfixture/decorator/constructor/RandomConstructorStrategy.kt index 2f02c53..29678c6 100644 --- a/fixture/src/main/kotlin/com/appmattus/kotlinfixture/decorator/constructor/RandomConstructorStrategy.kt +++ b/fixture/src/main/kotlin/com/appmattus/kotlinfixture/decorator/constructor/RandomConstructorStrategy.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 Appmattus Limited + * Copyright 2020-2023 Appmattus Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,6 @@ import kotlin.reflect.KFunction */ object RandomConstructorStrategy : ConstructorStrategy { override fun constructors(context: Context, obj: KClass<*>): Collection> { - return obj.constructors.shuffled(context.random) + return obj.filteredConstructors.shuffled(context.random) } } diff --git a/fixture/src/test/kotlin/com/appmattus/kotlinfixture/SerializableTest.kt b/fixture/src/test/kotlin/com/appmattus/kotlinfixture/SerializableTest.kt new file mode 100644 index 0000000..a3ad1d7 --- /dev/null +++ b/fixture/src/test/kotlin/com/appmattus/kotlinfixture/SerializableTest.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2023 Appmattus Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.appmattus.kotlinfixture + +import com.appmattus.kotlinfixture.config.TestGenerator.fixture +import kotlinx.serialization.Serializable +import kotlin.test.Test + +class SerializableTest { + + @Serializable + private data class ErrorCodeDto( + val errorCode: String, + val errorDetail: String, + val errorDescription: String + ) + + @Test + fun `serializing and deserializing ErrorCodeDto should result in original instance`() { + repeat(100) { + val original = fixture() + // Serializable generates synthetic constructors with nullable parameters so we ensure we verify we don't use that constructor + @Suppress("SENSELESS_COMPARISON") + runCatching { + require(original.errorCode != null) + require(original.errorDetail != null) + require(original.errorDescription != null) + }.onFailure { + println(original) + throw IllegalArgumentException() + } + } + } +}