Skip to content

Commit

Permalink
feat: validate list type as per default
Browse files Browse the repository at this point in the history
  • Loading branch information
samukce committed Jan 4, 2023
1 parent 94760cb commit ba38e5d
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,25 @@ class DslJsonBodyBuilder {
) {
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) {}
Double::class -> root.numberType(it.name)
String::class -> root.stringType(it.name)
Boolean::class -> root.booleanType(it.name)
ZonedDateTime::class -> root.datetime(it.name, ISO_PATTERN)
List::class -> root.array(it.name) { arr ->
arr.run {
fillBasedOnConstructorFields(
it.type.arguments.first().type?.jvmErasure,
arr,
alreadyProcessedObject + baseField
)
}
}
else ->
root.`object`(it.name) { objDsl ->
objDsl.run {
Expand All @@ -58,4 +65,36 @@ class DslJsonBodyBuilder {
}
}
}

private fun fillBasedOnConstructorFields(
listTypeCLass: KClass<*>?,
rootArray: LambdaDslJsonArray,
alreadyProcessedObject: Set<KClass<*>> = setOf()
) {
when(listTypeCLass) {
Byte::class,
Short::class,
Int::class,
Long::class,
Float::class,
Number::class,
Double::class -> rootArray.numberType(1)
String::class -> rootArray.stringType(listTypeCLass.simpleName)
Boolean::class -> rootArray.booleanType(true)
ZonedDateTime::class -> rootArray.datetimeExpression("now", ISO_PATTERN)
else -> {
rootArray.`object` { objDsl ->
objDsl.run {
if (!alreadyProcessedObject.contains(listTypeCLass)) {
fillBasedOnConstructorFields(
listTypeCLass?.primaryConstructor,
objDsl,
alreadyProcessedObject
)
}
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,107 @@ internal class DslJsonBodyBuilderTest {
}

@Test
internal fun `should map array field`() {
data class ListObjectRequiredProperty(val property: List<String>)
internal fun `should map array field with non empty set for string type`() {
data class ListObjectRequiredProperty(val properties: List<String>)

val actualJsonBody = LambdaDsl.newJsonBody(basedOnConstructor(ListObjectRequiredProperty::class))

val expectedBody =
LambdaDsl.newJsonBody { it.array("property") {} }
LambdaDsl.newJsonBody { it.array("properties") { arr ->
arr.stringType("String")
} }

assertThat(actualJsonBody.pactDslObject.toString(), `is`(equalTo(expectedBody.pactDslObject.toString())))
}

@Test
internal fun `should map array field with non empty set for boolean type`() {
data class ListObjectRequiredProperty(val properties: List<Boolean>)

val actualJsonBody = LambdaDsl.newJsonBody(basedOnConstructor(ListObjectRequiredProperty::class))

val expectedBody =
LambdaDsl.newJsonBody { it.array("properties") { arr ->
arr.booleanType(true)
} }

assertThat(actualJsonBody.pactDslObject.toString(), `is`(equalTo(expectedBody.pactDslObject.toString())))
}

@Test
internal fun `should map array field with non empty set for datetime type`() {
data class ListObjectRequiredProperty(val properties: List<ZonedDateTime>)

val actualJsonBody = LambdaDsl.newJsonBody(basedOnConstructor(ListObjectRequiredProperty::class))

val expectedBody =
LambdaDsl.newJsonBody { it.array("properties") { arr ->
arr.datetimeExpression("now", "yyyy-MM-dd'T'HH:mm:ssZZ")
} }

assertThat(actualJsonBody.pactDslObject.toString(), `is`(equalTo(expectedBody.pactDslObject.toString())))
}

@ParameterizedTest
@MethodSource(value = ["listWithNumberProperties"])
internal fun `should map array field with non empty set for number type`(classTest: KClass<*>) {
val actualJsonBody = LambdaDsl.newJsonBody(basedOnConstructor(classTest))

val expectedBody =
LambdaDsl.newJsonBody { it.array("properties") { arr ->
arr.numberType(1)
} }

assertThat(actualJsonBody.pactDslObject.toString(), `is`(equalTo(expectedBody.pactDslObject.toString())))
}

@Test
internal fun `should map array field with list of object`() {
data class InnerObject(val property: String)
data class ListObjectRequiredProperty(val properties: List<InnerObject>)

val actualJsonBody = LambdaDsl.newJsonBody(basedOnConstructor(ListObjectRequiredProperty::class))

val expectedBody =
LambdaDsl.newJsonBody { it.array("properties") { arr ->
arr.`object` { obj ->
obj.stringType("property")
}
} }

assertThat(actualJsonBody.pactDslObject.toString(), `is`(equalTo(expectedBody.pactDslObject.toString())))
}

@Test
internal fun `should map array field with inner object without optional property`() {
data class InnerObject(val property: String = "")
data class ListObjectRequiredProperty(val properties: List<InnerObject>)

val actualJsonBody = LambdaDsl.newJsonBody(basedOnConstructor(ListObjectRequiredProperty::class))

val expectedBody =
LambdaDsl.newJsonBody { it.array("properties") { arr ->
arr.`object` { }
} }

assertThat(actualJsonBody.pactDslObject.toString(), `is`(equalTo(expectedBody.pactDslObject.toString())))
}

data class SecondListProperty(val third: List<FirstListProperty>, val property: String)
data class FirstListProperty(val second: List<SecondListProperty>)
@Test
internal fun `should map array inner object with loop reference keeping other fields`() {
val actualJsonBody = LambdaDsl.newJsonBody(basedOnConstructor(FirstListProperty::class))

val expectedBody =
LambdaDsl.newJsonBody { root ->
root.array("second") {
it.`object` { sec ->
sec.array("third") { loop -> loop.`object`{ } }
sec.stringType("property")
}
}
}

assertThat(actualJsonBody.pactDslObject.toString(), `is`(equalTo(expectedBody.pactDslObject.toString())))
}
Expand Down Expand Up @@ -237,5 +331,27 @@ internal class DslJsonBodyBuilderTest {
StringObjectRequiredPropertyMutable::class,
)
}

@JvmStatic
@Suppress("UnusedPrivateMember")
private fun listWithNumberProperties(): Stream<KClass<*>> {
data class ByteObjectNonRequiredProperty(val properties: List<Byte>)
data class ShortObjectNonRequiredProperty(val properties: List<Short>)
data class IntObjectNonRequiredProperty(val properties: List<Int>)
data class LongObjectNonRequiredProperty(val properties: List<Long>)
data class FloatObjectNonRequiredProperty(val properties: List<Float>)
data class DoubleObjectNonRequiredProperty(val properties: List<Double>)
data class NumberObjectNonRequiredProperty(val properties: List<Number>)

return Stream.of(
ByteObjectNonRequiredProperty::class,
ShortObjectNonRequiredProperty::class,
IntObjectNonRequiredProperty::class,
LongObjectNonRequiredProperty::class,
FloatObjectNonRequiredProperty::class,
DoubleObjectNonRequiredProperty::class,
NumberObjectNonRequiredProperty::class,
)
}
}
}

0 comments on commit ba38e5d

Please sign in to comment.