-
-
Notifications
You must be signed in to change notification settings - Fork 481
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add capabilityi to build json body based on data class required…
… constructor fields
- Loading branch information
Showing
4 changed files
with
244 additions
and
0 deletions.
There are no files selected for viewing
57 changes: 57 additions & 0 deletions
57
consumer/src/main/kotlin/au/com/dius/pact/consumer/dsl/DslJsonBodyBuilder.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package au.com.dius.pact.consumer.dsl | ||
|
||
import org.apache.commons.lang3.time.DateFormatUtils.ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT | ||
import java.time.ZonedDateTime | ||
import kotlin.reflect.KClass | ||
import kotlin.reflect.KFunction | ||
import kotlin.reflect.full.primaryConstructor | ||
import kotlin.reflect.jvm.jvmErasure | ||
|
||
|
||
class DslJsonBodyBuilder { | ||
companion object { | ||
private val ISO_PATTERN = ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT.pattern | ||
} | ||
|
||
/** | ||
* Build a {@link LambdaDslJsonBody} based on the Data Object required constructor fields | ||
*/ | ||
fun basedOnRequiredConstructorFields(kClass: KClass<*>): (LambdaDslJsonBody) -> Unit = | ||
{ root: LambdaDslJsonBody -> | ||
root.run { | ||
val constructor = kClass.primaryConstructor | ||
fillBasedOnConstructorFields(constructor, root) | ||
} | ||
} | ||
|
||
private fun fillBasedOnConstructorFields( | ||
constructor: KFunction<Any>?, | ||
root: LambdaDslObject | ||
) { | ||
constructor?.parameters?.filterNot { it.isOptional }?.forEach { | ||
when (val baseField = it.type.jvmErasure) { | ||
String::class -> root.stringType(it.name) | ||
Boolean::class -> root.booleanType(it.name) | ||
Byte::class, | ||
Short::class, | ||
Int::class, | ||
Long::class, | ||
Float::class, | ||
Number::class, | ||
Double::class -> | ||
root.numberType(it.name) | ||
List::class -> root.array(it.name) {} | ||
ZonedDateTime::class -> root.datetime(it.name, ISO_PATTERN) | ||
else -> | ||
root.`object`(it.name) { objDsl -> | ||
objDsl.run { | ||
fillBasedOnConstructorFields( | ||
baseField.primaryConstructor, | ||
objDsl | ||
) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
consumer/src/main/kotlin/au/com/dius/pact/consumer/dsl/Extensions.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
165 changes: 165 additions & 0 deletions
165
consumer/src/test/kotlin/au/com/dius/pact/consumer/dsl/DslJsonBodyBuilderTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
package au.com.dius.pact.consumer.dsl | ||
|
||
import org.junit.jupiter.params.ParameterizedTest | ||
import org.junit.jupiter.params.provider.MethodSource | ||
import kotlin.reflect.KClass | ||
import org.assertj.core.api.Assertions.assertThat | ||
import org.junit.jupiter.api.Test | ||
import java.time.ZonedDateTime | ||
import java.util.stream.Stream | ||
|
||
internal class DslJsonBodyBuilderTest { | ||
private fun basedOnConstructor(classTest: KClass<*>) = | ||
DslJsonBodyBuilder().basedOnRequiredConstructorFields(classTest) | ||
|
||
@ParameterizedTest | ||
@MethodSource(value = ["stringPropertyOptionalProperties"]) | ||
internal fun `should not map string property optional with default constructor`( | ||
classTest: KClass<*> | ||
) { | ||
val actualJsonBody = LambdaDsl.newJsonBody(basedOnConstructor(classTest)) | ||
|
||
val expectedBody = | ||
LambdaDsl.newJsonBody { } | ||
|
||
assertThat(actualJsonBody.pactDslObject.toString()) | ||
.isEqualTo(expectedBody.pactDslObject.toString()) | ||
} | ||
|
||
@ParameterizedTest | ||
@MethodSource(value = ["stringPropertyNonOptionalProperties"]) | ||
internal fun `should map string property non-optional`(classTest: KClass<*>) { | ||
val actualJsonBody = LambdaDsl.newJsonBody(basedOnConstructor(classTest)) | ||
|
||
val expectedBody = | ||
LambdaDsl.newJsonBody { it.stringType("property") } | ||
|
||
assertThat(actualJsonBody.pactDslObject.toString()) | ||
.isEqualTo(expectedBody.pactDslObject.toString()) | ||
} | ||
|
||
@Test | ||
internal fun `should map string property non-optional with var`() { | ||
data class StringObjectRequiredProperty(var property: String) | ||
|
||
val actualJsonBody = LambdaDsl.newJsonBody(basedOnConstructor(StringObjectRequiredProperty::class)) | ||
|
||
val expectedBody = | ||
LambdaDsl.newJsonBody { it.stringType("property") } | ||
|
||
assertThat(actualJsonBody.pactDslObject.toString()) | ||
.isEqualTo(expectedBody.pactDslObject.toString()) | ||
} | ||
|
||
@Test | ||
internal fun `should map boolean property non-optional`() { | ||
data class BooleanObjectRequiredProperty(val property: Boolean) | ||
|
||
val actualJsonBody = LambdaDsl.newJsonBody(basedOnConstructor(BooleanObjectRequiredProperty::class)) | ||
|
||
val expectedBody = | ||
LambdaDsl.newJsonBody { it.booleanType("property") } | ||
|
||
assertThat(actualJsonBody.pactDslObject.toString()) | ||
.isEqualTo(expectedBody.pactDslObject.toString()) | ||
} | ||
|
||
@ParameterizedTest | ||
@MethodSource(value = ["numberPropertyNonOptional"]) | ||
internal fun `should map simple number property non-optional`(classTest: KClass<*>) { | ||
val actualJsonBody = LambdaDsl.newJsonBody(basedOnConstructor(classTest)) | ||
|
||
val expectedBody = | ||
LambdaDsl.newJsonBody { it.numberType("property") } | ||
|
||
assertThat(actualJsonBody.pactDslObject.toString()) | ||
.isEqualTo(expectedBody.pactDslObject.toString()) | ||
} | ||
|
||
@Test | ||
internal fun `should map zoned date time field for iso 8601`() { | ||
data class DatetimeRequiredProperty(val property: ZonedDateTime) | ||
|
||
val actualJsonBody = LambdaDsl.newJsonBody(basedOnConstructor(DatetimeRequiredProperty::class)) | ||
|
||
val expectedBody = | ||
LambdaDsl.newJsonBody { it.datetime("property", "yyyy-MM-dd'T'HH:mm:ssZZ") } | ||
|
||
assertThat(actualJsonBody.pactDslObject.toString()) | ||
.isEqualTo(expectedBody.pactDslObject.toString()) | ||
} | ||
|
||
@Test | ||
internal fun `should map array field`() { | ||
data class ListObjectRequiredProperty(val property: List<String>) | ||
|
||
val actualJsonBody = LambdaDsl.newJsonBody(basedOnConstructor(ListObjectRequiredProperty::class)) | ||
|
||
val expectedBody = | ||
LambdaDsl.newJsonBody { it.array("property") {} } | ||
|
||
assertThat(actualJsonBody.pactDslObject.toString()) | ||
.isEqualTo(expectedBody.pactDslObject.toString()) | ||
} | ||
|
||
@Test | ||
internal fun `should map inner object`() { | ||
data class InnerObjectRequiredProperty(val property: String) | ||
data class ObjectRequiredProperty(val inner: InnerObjectRequiredProperty) | ||
|
||
val actualJsonBody = LambdaDsl.newJsonBody(basedOnConstructor(ObjectRequiredProperty::class)) | ||
|
||
val expectedBody = | ||
LambdaDsl.newJsonBody { root -> | ||
root.`object`("inner") { it.stringType("property") } | ||
} | ||
|
||
assertThat(actualJsonBody.pactDslObject.toString()) | ||
.isEqualTo(expectedBody.pactDslObject.toString()) | ||
} | ||
|
||
companion object { | ||
@JvmStatic | ||
private fun numberPropertyNonOptional(): Stream<KClass<*>> { | ||
data class ByteObjectNonRequiredProperty(val property: Byte) | ||
data class ShortObjectNonRequiredProperty(val property: Short) | ||
data class IntObjectNonRequiredProperty(val property: Int) | ||
data class LongObjectNonRequiredProperty(val property: Long) | ||
data class FloatObjectNonRequiredProperty(val property: Float) | ||
data class DoubleObjectNonRequiredProperty(val property: Double) | ||
data class NumberObjectNonRequiredProperty(val property: Number) | ||
|
||
return Stream.of( | ||
ByteObjectNonRequiredProperty::class, | ||
ShortObjectNonRequiredProperty::class, | ||
IntObjectNonRequiredProperty::class, | ||
LongObjectNonRequiredProperty::class, | ||
FloatObjectNonRequiredProperty::class, | ||
DoubleObjectNonRequiredProperty::class, | ||
NumberObjectNonRequiredProperty::class, | ||
) | ||
} | ||
|
||
@JvmStatic | ||
private fun stringPropertyOptionalProperties(): Stream<KClass<*>> { | ||
data class StringObjectNonRequiredPropertyImmutable(val property: String = "") | ||
data class StringObjectNonRequiredPropertyMutable(var property: String = "") | ||
|
||
return Stream.of( | ||
StringObjectNonRequiredPropertyImmutable::class, | ||
StringObjectNonRequiredPropertyMutable::class, | ||
) | ||
} | ||
|
||
@JvmStatic | ||
private fun stringPropertyNonOptionalProperties(): Stream<KClass<*>> { | ||
data class StringObjectRequiredPropertyImmutable(val property: String) | ||
data class StringObjectRequiredPropertyMutable(var property: String) | ||
|
||
return Stream.of( | ||
StringObjectRequiredPropertyImmutable::class, | ||
StringObjectRequiredPropertyMutable::class, | ||
) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters