Skip to content

Commit 3e579d1

Browse files
authored
Ensure @Serializable generated constructor is filtered out (#96)
1 parent ea9a686 commit 3e579d1

File tree

7 files changed

+73
-7
lines changed

7 files changed

+73
-7
lines changed

buildSrc/src/main/kotlin/Versions.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,8 @@ object Versions {
4949
const val testExtJunit = "1.1.5"
5050
const val testRunner = "1.5.2"
5151
}
52+
53+
object KotlinX {
54+
const val serialization = "1.5.0"
55+
}
5256
}

fixture/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ plugins {
2121
id("com.android.lint")
2222
id("com.vanniktech.maven.publish")
2323
id("org.jetbrains.dokka")
24+
id("org.jetbrains.kotlin.plugin.serialization") version Versions.kotlin
2425
}
2526

2627
apply(from = "$rootDir/gradle/scripts/jacoco.gradle.kts")
@@ -46,6 +47,8 @@ dependencies {
4647
testImplementation(kotlin("test-junit"))
4748
testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:${Versions.mockitoKotlin}")
4849

50+
testImplementation("org.jetbrains.kotlinx:kotlinx-serialization-json:${Versions.KotlinX.serialization}")
51+
4952
// Used for ComparisonTest
5053
@Suppress("GradleDependency")
5154
testImplementation("com.github.marcellogalhardo:kotlin-fixture:${Versions.marcellogalhardo}")

fixture/src/main/kotlin/com/appmattus/kotlinfixture/decorator/constructor/ConstructorStrategy.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 Appmattus Limited
2+
* Copyright 2020-2023 Appmattus Limited
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -28,4 +28,15 @@ interface ConstructorStrategy {
2828
* Returns [obj] constructors in the order to try when generating an instance.
2929
*/
3030
fun constructors(context: Context, obj: KClass<*>): Collection<KFunction<*>>
31+
32+
/**
33+
* Constructors of the class with Serializable constructors filtered out
34+
*/
35+
val KClass<*>.filteredConstructors: Collection<KFunction<*>>
36+
get() = constructors.filterNot { it.isSerializationConstructor() }
37+
38+
private fun KFunction<Any>.isSerializationConstructor(): Boolean {
39+
val lastParameterType = (parameters.lastOrNull()?.type?.classifier as? KClass<*>)?.qualifiedName
40+
return lastParameterType == "kotlinx.serialization.internal.SerializationConstructorMarker"
41+
}
3142
}

fixture/src/main/kotlin/com/appmattus/kotlinfixture/decorator/constructor/GreedyConstructorStrategy.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 Appmattus Limited
2+
* Copyright 2020-2023 Appmattus Limited
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -28,6 +28,6 @@ import kotlin.reflect.KFunction
2828
*/
2929
object GreedyConstructorStrategy : ConstructorStrategy {
3030
override fun constructors(context: Context, obj: KClass<*>): Collection<KFunction<*>> {
31-
return obj.constructors.sortedByDescending { it.parameters.size }
31+
return obj.filteredConstructors.sortedByDescending { it.parameters.size }
3232
}
3333
}

fixture/src/main/kotlin/com/appmattus/kotlinfixture/decorator/constructor/ModestConstructorStrategy.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 Appmattus Limited
2+
* Copyright 2020-2023 Appmattus Limited
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -28,6 +28,6 @@ import kotlin.reflect.KFunction
2828
*/
2929
object ModestConstructorStrategy : ConstructorStrategy {
3030
override fun constructors(context: Context, obj: KClass<*>): Collection<KFunction<*>> {
31-
return obj.constructors.sortedBy { it.parameters.size }
31+
return obj.filteredConstructors.sortedBy { it.parameters.size }
3232
}
3333
}

fixture/src/main/kotlin/com/appmattus/kotlinfixture/decorator/constructor/RandomConstructorStrategy.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 Appmattus Limited
2+
* Copyright 2020-2023 Appmattus Limited
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -25,6 +25,6 @@ import kotlin.reflect.KFunction
2525
*/
2626
object RandomConstructorStrategy : ConstructorStrategy {
2727
override fun constructors(context: Context, obj: KClass<*>): Collection<KFunction<*>> {
28-
return obj.constructors.shuffled(context.random)
28+
return obj.filteredConstructors.shuffled(context.random)
2929
}
3030
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2023 Appmattus Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.appmattus.kotlinfixture
18+
19+
import com.appmattus.kotlinfixture.config.TestGenerator.fixture
20+
import kotlinx.serialization.Serializable
21+
import kotlin.test.Test
22+
23+
class SerializableTest {
24+
25+
@Serializable
26+
private data class ErrorCodeDto(
27+
val errorCode: String,
28+
val errorDetail: String,
29+
val errorDescription: String
30+
)
31+
32+
@Test
33+
fun `serializing and deserializing ErrorCodeDto should result in original instance`() {
34+
repeat(100) {
35+
val original = fixture<ErrorCodeDto>()
36+
// Serializable generates synthetic constructors with nullable parameters so we ensure we verify we don't use that constructor
37+
@Suppress("SENSELESS_COMPARISON")
38+
runCatching {
39+
require(original.errorCode != null)
40+
require(original.errorDetail != null)
41+
require(original.errorDescription != null)
42+
}.onFailure {
43+
println(original)
44+
throw IllegalArgumentException()
45+
}
46+
}
47+
}
48+
}

0 commit comments

Comments
 (0)