Skip to content

Commit 0baef1f

Browse files
authored
Merge pull request #1343 from WebFuzzing/phg/dtoFixesWFD
Bug fixing in DTOs
2 parents 9906149 + d62c230 commit 0baef1f

File tree

7 files changed

+69
-16
lines changed

7 files changed

+69
-16
lines changed

core/src/main/kotlin/org/evomaster/core/output/dto/DtoWriter.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class DtoWriter(
5959
private fun calculateDtos(actionDefinitions: List<Action>) {
6060
actionDefinitions.forEach { action ->
6161
action.getViewOfChildren().find { it is BodyParam }
62-
.let {
62+
?.let {
6363
val primaryGene = (it as BodyParam).primaryGene()
6464
val choiceGene = primaryGene.getWrappedGene(ChoiceGene::class.java)
6565
if (choiceGene != null) {

core/src/main/kotlin/org/evomaster/core/output/dto/GeneToDto.kt

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,23 +38,23 @@ class GeneToDto(
3838

3939
/**
4040
* @param leafGene to obtain the refType if the component is defined with a name
41-
* @param actionName to provide a fallback on the DTO named with the action if the component is defined inline
41+
* @param fallback to provide a fallback on the DTO named with the action if the component is defined inline
4242
*
4343
* @return the DTO name that will be used to instantiate the first variable
4444
*/
45-
fun getRootDtoName(leafGene: Gene, actionName: String): String {
45+
fun getDtoName(leafGene: Gene, fallback: String): String {
4646
return when (leafGene) {
47-
is ObjectGene -> leafGene.refType?:TestWriterUtils.safeVariableName(actionName)
47+
is ObjectGene -> leafGene.refType?:StringUtils.capitalization(TestWriterUtils.safeVariableName(fallback))
4848
is ArrayGene<*> -> {
4949
val template = leafGene.template
5050
if (template is ObjectGene) {
51-
template.refType?:TestWriterUtils.safeVariableName(actionName)
51+
template.refType?:StringUtils.capitalization(TestWriterUtils.safeVariableName(fallback))
5252
} else {
5353
// TODO handle arrays of basic data types
54-
return getListType(actionName, template)
54+
return getListType(fallback, template)
5555
}
5656
}
57-
else -> throw IllegalStateException("Gene $leafGene is not supported for DTO payloads for action: $actionName")
57+
else -> throw IllegalStateException("Gene $leafGene is not supported for DTO payloads for action: $fallback")
5858
}
5959
}
6060

@@ -68,7 +68,7 @@ class GeneToDto(
6868
fun getDtoCall(gene: Gene, dtoName: String, counter: Int): DtoCall {
6969
return when(gene) {
7070
is ObjectGene -> getObjectDtoCall(gene, dtoName, counter)
71-
is ArrayGene<*> -> getArrayDtoCall(gene, dtoName, counter)
71+
is ArrayGene<*> -> getArrayDtoCall(gene, dtoName, counter, null)
7272
else -> throw RuntimeException("BUG: Gene $gene (with type ${this::class.java.simpleName}) should not be creating DTOs")
7373
}
7474
}
@@ -88,36 +88,36 @@ class GeneToDto(
8888
val attributeName = it.name
8989
when (leafGene) {
9090
is ObjectGene -> {
91-
val childDtoCall = getDtoCall(leafGene, StringUtils.capitalization(attributeName), counter)
91+
val childDtoCall = getDtoCall(leafGene, getDtoName(leafGene, attributeName), counter)
9292

9393
result.addAll(childDtoCall.objectCalls)
9494
result.add(dtoOutput.getSetterStatement(dtoVarName, attributeName, childDtoCall.varName))
9595
}
9696
is ArrayGene<*> -> {
97-
val childDtoCall = getDtoCall(leafGene, StringUtils.capitalization(attributeName), counter)
97+
val childDtoCall = getArrayDtoCall(leafGene, getDtoName(leafGene, attributeName), counter, attributeName)
9898

9999
result.addAll(childDtoCall.objectCalls)
100100
result.add(dtoOutput.getSetterStatement(dtoVarName, attributeName, childDtoCall.varName))
101101
}
102102
else -> {
103-
result.add(dtoOutput.getSetterStatement(dtoVarName, attributeName, it.getValueAsPrintableString(targetFormat = null)))
103+
result.add(dtoOutput.getSetterStatement(dtoVarName, attributeName, "${leafGene.getValueAsPrintableString(targetFormat = null)}${getValueSuffix(leafGene)}"))
104104
}
105105
}
106106
}
107107

108108
return DtoCall(dtoVarName, result)
109109
}
110110

111-
private fun getArrayDtoCall(gene: ArrayGene<*>, dtoName: String, counter: Int): DtoCall {
111+
private fun getArrayDtoCall(gene: ArrayGene<*>, dtoName: String, counter: Int, targetAttribute: String?): DtoCall {
112112
val result = mutableListOf<String>()
113113
val template = gene.template
114114

115115
val listType = getListType(dtoName,template)
116-
val listVarName = "list_${listType}_${counter}"
116+
val listVarName = "list_${targetAttribute?:dtoName}_${counter}"
117117
result.add(dtoOutput.getNewListStatement(listType, listVarName))
118118

119119
if (template is ObjectGene) {
120-
val childDtoName = StringUtils.capitalization(template.refType?: gene.name)
120+
val childDtoName = template.refType?:StringUtils.capitalization(gene.name)
121121
var listCounter = 1
122122
gene.getViewOfElements().forEach {
123123
val childDtoCall = getDtoCall(it,childDtoName, listCounter++)
@@ -126,7 +126,8 @@ class GeneToDto(
126126
}
127127
} else {
128128
gene.getViewOfElements().forEach {
129-
result.add(dtoOutput.getAddElementToListStatement(listVarName, it.getValueAsPrintableString(targetFormat = null)))
129+
val leafGene = it.getLeafGene()
130+
result.add(dtoOutput.getAddElementToListStatement(listVarName, "${leafGene.getValueAsPrintableString(targetFormat = null)}${getValueSuffix(leafGene)}"))
130131
}
131132
}
132133

@@ -152,4 +153,14 @@ class GeneToDto(
152153
else -> throw Exception("Not supported gene at the moment: ${gene?.javaClass?.simpleName} for field $fieldName")
153154
}
154155
}
156+
157+
// According to documentation, a trailing constant is only needed for Long, Hexadecimal and Float
158+
// https://kotlinlang.org/docs/numbers.html#literal-constants-for-numbers
159+
private fun getValueSuffix(gene: Gene): String {
160+
return when (gene) {
161+
is LongGene -> "L"
162+
is FloatGene -> "f"
163+
else -> ""
164+
}
165+
}
155166
}

core/src/main/kotlin/org/evomaster/core/output/dto/JvmDtoOutput.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ abstract class JvmDtoOutput: DtoOutput {
1515
}
1616

1717
protected fun addImports(lines: Lines) {
18+
lines.addStatement("import java.util.List")
1819
lines.addStatement("import java.util.Optional")
1920
lines.addEmpty()
2021
lines.addStatement("import com.fasterxml.jackson.annotation.JsonInclude")

core/src/main/kotlin/org/evomaster/core/output/service/HttpWsTestCaseWriter.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ abstract class HttpWsTestCaseWriter : ApiTestCaseWriter() {
136136
if (leafGene is ObjectGene || leafGene is ArrayGene<*>) {
137137
val geneToDto = GeneToDto(format)
138138

139-
val dtoName = geneToDto.getRootDtoName(leafGene, actionName)
139+
val dtoName = geneToDto.getDtoName(leafGene, actionName)
140140
val dtoCall = geneToDto.getDtoCall(leafGene, dtoName, counter++)
141141

142142
dtoCall.objectCalls.forEach {

core/src/test/kotlin/org/evomaster/core/output/dto/DtoWriterTest.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,16 @@ class DtoWriterTest {
345345
}
346346
}
347347

348+
@Test
349+
fun noDtosWhenNoBodyParam() {
350+
val dtoWriter = DtoWriter(outputFormat)
351+
val actionCluster = initRestSchema("noBody.yaml")
352+
353+
dtoWriter.write(outputTestSuitePath, TEST_PACKAGE, actionCluster.values.map { it.copy() })
354+
355+
assertEquals(dtoWriter.getCollectedDtos().size, 0)
356+
}
357+
348358
private fun initRestSchema(openApiLocation: String) : Map<String, Action> {
349359
val restSchema = RestSchema(OpenApiAccess.getOpenAPIFromResource("/swagger/dto-writer/$openApiLocation"))
350360
val actionCluster = mutableMapOf<String, Action>()
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
openapi: 3.0.0
2+
info:
3+
title: No body API
4+
version: 1.0.0
5+
servers:
6+
- url: http://localhost:5000
7+
paths:
8+
/example:
9+
get:
10+
summary: Example with no body params
11+
parameters:
12+
- in: query
13+
name: aQueryParam
14+
schema:
15+
type: string
16+
- in: header
17+
name: aHeaderParam
18+
schema:
19+
type: string
20+
responses:
21+
'200':
22+
description: OK

e2e-tests/spring-rest-openapi-v3/src/main/resources/static/openapi-dto.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ components:
128128
type: integer
129129
address:
130130
$ref: "#/components/schemas/Address"
131+
key:
132+
$ref: "#/components/schemas/SuperKey"
131133
required:
132134
- name
133135
- age
@@ -144,3 +146,10 @@ components:
144146
required:
145147
- street
146148
- country
149+
SuperKey:
150+
type: object
151+
properties:
152+
key:
153+
type: string
154+
value:
155+
type: string

0 commit comments

Comments
 (0)