Skip to content

Commit 9910ba2

Browse files
Clean featureflags for json patch and xml pr commit
1 parent 92ded20 commit 9910ba2

7 files changed

Lines changed: 104 additions & 7 deletions

File tree

core-tests/e2e-tests/spring/spring-rest-bb/src/test/kotlin/org/evomaster/e2etests/spring/rest/bb/jsonpatch/BBJsonPatchTest.kt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@ import org.evomaster.core.EMConfig
55
import org.evomaster.core.output.OutputFormat
66
import org.evomaster.core.problem.rest.data.HttpVerb
77
import org.evomaster.e2etests.spring.rest.bb.SpringTestBase
8+
import org.evomaster.e2etests.utils.CoveredTargets
9+
import org.junit.jupiter.api.Assertions.assertFalse
810
import org.junit.jupiter.api.Assertions.assertTrue
911
import org.junit.jupiter.api.BeforeAll
12+
import org.junit.jupiter.api.Test
1013
import org.junit.jupiter.params.ParameterizedTest
1114
import org.junit.jupiter.params.provider.EnumSource
1215

@@ -69,4 +72,35 @@ class BBJsonPatchTest : SpringTestBase() {
6972
assertHasAtLeastOne(solution, HttpVerb.PATCH, 400, "/pets/{id}/sequence", null)
7073
}
7174
}
75+
76+
@Test
77+
fun testBlackBoxWithoutJsonPatchSupport() {
78+
val specificOpTargets = listOf(
79+
"JSON_PATCH_ADD",
80+
"JSON_PATCH_REMOVE",
81+
"JSON_PATCH_REPLACE",
82+
"JSON_PATCH_MOVE",
83+
"JSON_PATCH_COPY",
84+
"JSON_PATCH_TEST",
85+
"JSON_PATCH_SEQUENCE"
86+
)
87+
88+
runBlackBoxEM(OutputFormat.KOTLIN_JUNIT_5, "BBJsonPatchEM_NoSupport", 1000, 3, false) { args ->
89+
setOption(args, "enableJsonPatchGeneSupport", "false")
90+
91+
val solution = initAndRun(args)
92+
assertTrue(solution.individuals.size >= 1)
93+
}
94+
95+
val coveredWithFlagOff = specificOpTargets.count { CoveredTargets.isCovered(it) }
96+
println("=== Flag OFF: $coveredWithFlagOff/${specificOpTargets.size} operation-specific targets covered ===")
97+
specificOpTargets.forEach { target ->
98+
println(" [${ if (CoveredTargets.isCovered(target)) "X" else " " }] $target")
99+
}
100+
101+
assertFalse(
102+
CoveredTargets.areCovered(specificOpTargets),
103+
"Without enableJsonPatchGeneSupport, EvoMaster should NOT cover all JSON Patch operation targets"
104+
)
105+
}
72106
}

core-tests/e2e-tests/spring/spring-rest-bb/src/test/kotlin/org/evomaster/e2etests/spring/rest/bb/xml/BBXMLTest.kt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ import org.evomaster.core.EMConfig
55
import org.evomaster.core.output.OutputFormat
66
import org.evomaster.core.problem.rest.data.HttpVerb
77
import org.evomaster.e2etests.spring.rest.bb.SpringTestBase
8+
import org.evomaster.e2etests.utils.CoveredTargets
9+
import org.junit.jupiter.api.Assertions.assertFalse
810
import org.junit.jupiter.api.Assertions.assertTrue
911
import org.junit.jupiter.api.Assumptions.assumeTrue
1012
import org.junit.jupiter.api.BeforeAll
13+
import org.junit.jupiter.api.Test
1114
import org.junit.jupiter.params.ParameterizedTest
1215
import org.junit.jupiter.params.provider.EnumSource
1316

@@ -67,4 +70,41 @@ class BBXMLTest : SpringTestBase() {
6770
assertHasAtLeastOne(solution, HttpVerb.POST, 200, "/api/bbxml/projects", null)
6871
}
6972
}
73+
74+
@Test
75+
fun testBlackBoxWithoutXmlBodySupport() {
76+
// These targets require a well-formed XML body to reach a 200 response.
77+
// With enableXmlBodyGeneSupport=false, EvoMaster falls back to generic field
78+
// naming (schema ref name or 'body') instead of the actual JAXB element names,
79+
// so Spring's XML deserializer receives structurally wrong documents and returns
80+
// 400 for most requests → the 200-branch targets stay uncovered.
81+
val xmlBodyTargets = listOf(
82+
"XML_TO_STRING",
83+
"EMPLOYEE",
84+
"COMPANY",
85+
"DEPARTMENT",
86+
"ORGANIZATION",
87+
"PERSON_ATTR",
88+
"PROJECT",
89+
"PROJECTS"
90+
)
91+
92+
runBlackBoxEM(OutputFormat.KOTLIN_JUNIT_5, "BBXmlEM_NoSupport", 1000, 3, false) { args ->
93+
setOption(args, "enableXmlBodyGeneSupport", "false")
94+
95+
val solution = initAndRun(args)
96+
assertTrue(solution.individuals.size >= 1)
97+
}
98+
99+
val coveredWithFlagOff = xmlBodyTargets.count { CoveredTargets.isCovered(it) }
100+
println("=== Flag OFF: $coveredWithFlagOff/${xmlBodyTargets.size} XML body targets covered ===")
101+
xmlBodyTargets.forEach { target ->
102+
println(" [${if (CoveredTargets.isCovered(target)) "X" else " "}] $target")
103+
}
104+
105+
assertFalse(
106+
CoveredTargets.areCovered(xmlBodyTargets),
107+
"Without enableXmlBodyGeneSupport, EvoMaster should NOT cover all XML body targets"
108+
)
109+
}
70110
}

core-tests/e2e-tests/spring/spring-rest-h2-v1/src/test/java/org/evomaster/e2etests/spring/examples/adaptivehypermutation/DeterminismTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public void testDeterminismOfLog(boolean enableConstraintHandling){
2828
OpenAPI schema = (new OpenAPIParser()).readLocation("swagger-ahm/ahm.json", null, null).getOpenAPI();
2929
isDeterminismConsumer( new ArrayList<>(), (args) -> RestActionBuilderV3.INSTANCE
3030
.getModelsFromSwagger(schema, new LinkedHashMap<>(),
31-
new RestActionBuilderV3.Options(false,enableConstraintHandling,false,0.0,0.0,true,false,false)));
31+
new RestActionBuilderV3.Options(false,enableConstraintHandling,false,0.0,0.0,true,false,false,true,true)));
3232
}
3333

3434

core-tests/jdk-8/spring-rest-openapi-v2-tests/src/test/java/org/evomaster/e2etests/spring/examples/adaptivehypermutation/DeterminismTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public void testDeterminismOfLog(boolean enableConstraintHandling){
2727
OpenAPI schema = (new OpenAPIParser()).readLocation("swagger-ahm/ahm.json", null, null).getOpenAPI();
2828
isDeterminismConsumer( new ArrayList<>(), (args) -> {
2929
RestActionBuilderV3.INSTANCE.getModelsFromSwagger(schema, new LinkedHashMap<>(),
30-
new RestActionBuilderV3.Options(false,enableConstraintHandling,false,0.0,0.0,true,false,false));
30+
new RestActionBuilderV3.Options(false,enableConstraintHandling,false,0.0,0.0,true,false,false,true,true));
3131
});
3232
}
3333

core/src/main/kotlin/org/evomaster/core/EMConfig.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,6 +1372,16 @@ class EMConfig {
13721372
"Only available for JVM languages")
13731373
var dtoForRequestPayload = false
13741374

1375+
@Experimental
1376+
@Cfg("Enable JSON Patch (RFC 6902) gene support when the request Content-Type is 'application/json-patch+json'." +
1377+
" When false, such endpoints are treated as regular JSON bodies, reproducing the behavior before this feature was introduced.")
1378+
var enableJsonPatchGeneSupport = true
1379+
1380+
@Experimental
1381+
@Cfg("Enable XML-aware field naming for body genes when the request Content-Type is XML." +
1382+
" When false, body gene names fall back to the pre-feature behavior (schema ref name or 'body').")
1383+
var enableXmlBodyGeneSupport = true
1384+
13751385
@Important(6.0)
13761386
@Cfg("Host name or IP address of where the SUT EvoMaster Controller Driver is listening on." +
13771387
" This option is only needed for white-box testing.")

core/src/main/kotlin/org/evomaster/core/problem/rest/builder/RestActionBuilderV3.kt

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ object RestActionBuilderV3 {
115115
val enableAdvancedFormats: Boolean = true,
116116

117117
val inferFormatFromNames: Boolean = true,
118+
119+
val enableJsonPatchGeneSupport: Boolean = true,
120+
121+
val enableXmlBodyGeneSupport: Boolean = true,
118122
){
119123
constructor(config: EMConfig): this(
120124
enableConstraintHandling = config.enableSchemaConstraintHandling,
@@ -123,7 +127,9 @@ object RestActionBuilderV3 {
123127
probUseExamples = config.probRestExamples,
124128
usingWhiteBox = !config.blackBox,
125129
enableAdvancedFormats = config.enableAdvancedFormats,
126-
inferFormatFromNames = config.inferFormatFromNames
130+
inferFormatFromNames = config.inferFormatFromNames,
131+
enableJsonPatchGeneSupport = config.enableJsonPatchGeneSupport,
132+
enableXmlBodyGeneSupport = config.enableXmlBodyGeneSupport,
127133
)
128134

129135
init {
@@ -748,7 +754,8 @@ object RestActionBuilderV3 {
748754
listOf()
749755
}
750756

751-
val isJsonPatch = verb == HttpVerb.PATCH && bodies.keys.any { it.contains("json-patch") }
757+
val isJsonPatch = options.enableJsonPatchGeneSupport &&
758+
verb == HttpVerb.PATCH && bodies.keys.any { it.contains("json-patch") }
752759

753760
val name: String
754761
var gene: Gene
@@ -774,9 +781,13 @@ object RestActionBuilderV3 {
774781
}
775782
gene = JsonPatchDocumentGene(name, resourceGene)
776783
} else {
777-
// $ref schemas do not carry XML metadata; resolving the reference is required to obtain the correct XML element name from the target schema
778-
val deref = obj.schema.`$ref`?.let { ref -> SchemaUtils.getReferenceSchema(schemaHolder, currentSchema, ref, messages) } ?: obj.schema
779-
name = deref?.xml?.name ?: deref?.`$ref`?.substringAfterLast("/") ?: "body"
784+
if (options.enableXmlBodyGeneSupport) {
785+
// $ref schemas do not carry XML metadata; resolving the reference is required to obtain the correct XML element name from the target schema
786+
val deref = obj.schema.`$ref`?.let { ref -> SchemaUtils.getReferenceSchema(schemaHolder, currentSchema, ref, messages) } ?: obj.schema
787+
name = deref?.xml?.name ?: deref?.`$ref`?.substringAfterLast("/") ?: "body"
788+
} else {
789+
name = obj.schema.`$ref`?.substringAfterLast("/") ?: "body"
790+
}
780791
gene = getGene(name, obj.schema, schemaHolder, currentSchema, referenceClassDef = null, options = options, messages = messages, examples = examples)
781792
}
782793

docs/options.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,9 +287,11 @@ There are 3 types of options:
287287
|`enableAdvancedFormats`| __Boolean__. Whether to enable the handling of new type formats in OpenAPI schemas, e.g., the ones introduced in 3.1.0. *Default value*: `false`.|
288288
|`enableCustomizedMethodForMockObjectHandling`| __Boolean__. Whether to apply customized method (i.e., implement 'customizeMockingRPCExternalService' for external services or 'customizeMockingDatabase' for database) to handle mock object. *Default value*: `false`.|
289289
|`enableCustomizedMethodForScheduleTaskHandling`| __Boolean__. Whether to apply customized method (i.e., implement 'customizeScheduleTaskInvocation' for invoking schedule task) to invoke schedule task. *Default value*: `false`.|
290+
|`enableJsonPatchGeneSupport`| __Boolean__. Enable JSON Patch (RFC 6902) gene support when the request Content-Type is 'application/json-patch+json'. When false, such endpoints are treated as regular JSON bodies, reproducing the behavior before this feature was introduced. *Default value*: `true`.|
290291
|`enableRPCCustomizedTestOutput`| __Boolean__. Whether to enable customized RPC Test output if 'customizeRPCTestOutput' is implemented. *Default value*: `false`.|
291292
|`enableStaticFlakyInference`| __Boolean__. Specify whether to infer potential flakiness statically from response values, such as timestamps, UUIDs, hashes and runtime-specific messages. *Depends on*: `handleFlakiness=true`. *Default value*: `true`.|
292293
|`enableWriteSnapshotTests`| __Boolean__. Enable to print snapshots of the generated tests during the search in an interval defined in snapshotsInterval. *Default value*: `false`.|
294+
|`enableXmlBodyGeneSupport`| __Boolean__. Enable XML-aware field naming for body genes when the request Content-Type is XML. When false, body gene names fall back to the pre-feature behavior (schema ref name or 'body'). *Default value*: `true`.|
293295
|`execNumForDetectFlakiness`| __Int__. Specify the number of re-executions for detecting flakiness in tests. Set to 0 to disable re-execution based flakiness detection. *Constraints*: `min=0.0`. *Depends on*: `handleFlakiness=true`. *Default value*: `1`.|
294296
|`executiveSummary`| __Boolean__. Generate an executive summary, containing an example of each category of potential faults found.NOTE: This option is only meaningful when used in conjunction with test suite splitting. *Default value*: `false`.|
295297
|`expectationsActive`| __Boolean__. Enable Expectation Generation. If enabled, expectations will be generated. A variable called expectationsMasterSwitch is added to the test suite, with a default value of false. If set to true, an expectation that fails will cause the test case containing it to fail. *Default value*: `false`.|

0 commit comments

Comments
 (0)