diff --git a/core/src/test/kotlin/integration_tests/AllOfDiscriminatorTest.kt b/core/src/test/kotlin/integration_tests/AllOfDiscriminatorTest.kt index 684c27d49..b28cd17a3 100644 --- a/core/src/test/kotlin/integration_tests/AllOfDiscriminatorTest.kt +++ b/core/src/test/kotlin/integration_tests/AllOfDiscriminatorTest.kt @@ -6,10 +6,12 @@ import io.specmatic.core.HttpResponse import io.specmatic.core.pattern.parsedJSON import io.specmatic.core.pattern.parsedJSONObject import io.specmatic.core.utilities.exceptionCauseMessage +import io.specmatic.core.value.JSONObjectValue import io.specmatic.core.value.StringValue import io.specmatic.core.value.Value import io.specmatic.mock.NoMatchingScenario import io.specmatic.stub.HttpStub +import io.specmatic.test.TestExecutor import org.assertj.core.api.Assertions.* import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Nested @@ -771,4 +773,307 @@ class AllOfDiscriminatorTest { } } } + + @Test + fun `test generation with allOf discriminator and no examples`() { + val feature = OpenApiSpecification.fromYAML(""" + --- + openapi: 3.0.3 + info: + title: Vehicle API + version: 1.0.0 + paths: + /vehicle: + post: + summary: Add a new vehicle + requestBody: + required: true + content: + application/json: + schema: + ${'$'}ref: '#/components/schemas/Vehicle' + responses: + '201': + description: Vehicle created successfully + content: + text/plain: + schema: + type: string + + components: + schemas: + VehicleType: + type: object + required: + - type + properties: + type: + type: string + + Vehicle: + allOf: + - ${'$'}ref: '#/components/schemas/VehicleType' + - type: object + required: + - seatingCapacity + properties: + seatingCapacity: + type: integer + discriminator: + propertyName: "type" + mapping: + "car": "#/components/schemas/Transmission" + "bike": "#/components/schemas/SideCar" + + Transmission: + allOf: + - ${'$'}ref: '#/components/schemas/Vehicle' + - type: object + required: + - gearType + properties: + gearType: + type: string + + SideCar: + allOf: + - ${'$'}ref: '#/components/schemas/Vehicle' + - type: object + required: + - sidecarAvailable + properties: + sidecarAvailable: + type: boolean + """.trimIndent(), "").toFeature() + + val vehicleTypes = mutableSetOf() + + val results = feature.executeTests(object : TestExecutor { + override fun execute(request: HttpRequest): HttpResponse { + println(request.toLogString()) + val vehicleType = request.body.let { (it as JSONObjectValue).findFirstChildByPath("type")?.toStringLiteral() ?: "" } + + vehicleTypes.add(vehicleType) + + return HttpResponse.ok("success") + } + }) + + assertThat(vehicleTypes).containsAll(listOf("car", "bike")) + assertThat(results.testCount).isEqualTo(2) + } + + @Test + fun `test execution with allOf discriminator and one example`() { + val feature = OpenApiSpecification.fromYAML(""" + --- + openapi: 3.0.3 + info: + title: Vehicle API + version: 1.0.0 + paths: + /vehicle: + post: + summary: Add a new vehicle + requestBody: + required: true + content: + application/json: + schema: + ${'$'}ref: '#/components/schemas/Vehicle' + examples: + car: + value: + type: "car" + seatingCapacity: 4 + gearType: "MT" + responses: + '201': + description: Vehicle created successfully + content: + text/plain: + schema: + type: string + examples: + car: + value: "success" + + components: + schemas: + VehicleType: + type: object + required: + - type + properties: + type: + type: string + + Vehicle: + allOf: + - ${'$'}ref: '#/components/schemas/VehicleType' + - type: object + required: + - seatingCapacity + properties: + seatingCapacity: + type: integer + discriminator: + propertyName: "type" + mapping: + "car": "#/components/schemas/Transmission" + "bike": "#/components/schemas/SideCar" + + Transmission: + allOf: + - ${'$'}ref: '#/components/schemas/Vehicle' + - type: object + required: + - gearType + properties: + gearType: + type: string + + SideCar: + allOf: + - ${'$'}ref: '#/components/schemas/Vehicle' + - type: object + required: + - sidecarAvailable + properties: + sidecarAvailable: + type: boolean + """.trimIndent(), "").toFeature() + + val vehicleTypes = mutableSetOf() + + val results = feature.executeTests(object : TestExecutor { + override fun execute(request: HttpRequest): HttpResponse { + println(request.toLogString()) + + val requestJSON = request.body as JSONObjectValue + + val vehicleType = request.body.let { requestJSON.findFirstChildByPath("type")?.toStringLiteral() ?: "" } + + vehicleTypes.add(vehicleType) + + if(vehicleType == "car") { + assertThat(requestJSON.findFirstChildByPath("gearType")?.toStringLiteral()).isEqualTo("MT") + assertThat(requestJSON.findFirstChildByPath("seatingCapacity")?.toStringLiteral()).isEqualTo("4") + } + + return HttpResponse(201, "success") + } + }) + + assertThat(vehicleTypes).containsOnly("car") + assertThat(results.testCount).isEqualTo(1) + assertThat(results.success()).withFailMessage(results.report()).isTrue() + } + + @Test + fun `generative tests with allOf discriminator and one example`() { + val feature = OpenApiSpecification.fromYAML(""" + --- + openapi: 3.0.3 + info: + title: Vehicle API + version: 1.0.0 + paths: + /vehicle: + post: + summary: Add a new vehicle + requestBody: + required: true + content: + application/json: + schema: + ${'$'}ref: '#/components/schemas/Vehicle' + examples: + car: + value: + type: "car" + seatingCapacity: 4 + gearType: "MT" + responses: + '201': + description: Vehicle created successfully + content: + text/plain: + schema: + type: string + examples: + car: + value: "success" + + components: + schemas: + VehicleType: + type: object + required: + - type + properties: + type: + type: string + + Vehicle: + allOf: + - ${'$'}ref: '#/components/schemas/VehicleType' + - type: object + required: + - seatingCapacity + properties: + seatingCapacity: + type: integer + discriminator: + propertyName: "type" + mapping: + "car": "#/components/schemas/Transmission" + "bike": "#/components/schemas/SideCar" + + Transmission: + allOf: + - ${'$'}ref: '#/components/schemas/Vehicle' + - type: object + required: + - gearType + properties: + gearType: + type: string + + SideCar: + allOf: + - ${'$'}ref: '#/components/schemas/Vehicle' + - type: object + required: + - sidecarAvailable + properties: + sidecarAvailable: + type: boolean + """.trimIndent(), "").toFeature().enableGenerativeTesting(onlyPositive = true) + + val vehicleTypes = mutableSetOf() + + val results = feature.executeTests(object : TestExecutor { + override fun execute(request: HttpRequest): HttpResponse { + println(request.toLogString()) + val requestJSON = request.body as JSONObjectValue + + val vehicleType = request.body.let { + requestJSON.findFirstChildByPath("type")?.toStringLiteral() ?: "" } + + vehicleTypes.add(vehicleType) + + if(vehicleType == "car") { + assertThat(requestJSON.findFirstChildByPath("gearType")?.toStringLiteral()).isEqualTo("MT") + assertThat(requestJSON.findFirstChildByPath("seatingCapacity")?.toStringLiteral()).isEqualTo("4") + } + + return HttpResponse(201, body = "success") + } + }) + + assertThat(vehicleTypes).containsAll(listOf("car", "bike")) + assertThat(results.testCount).isEqualTo(2) + assertThat(results.success()).withFailMessage(results.report()).isTrue() + } } \ No newline at end of file diff --git a/core/src/test/kotlin/integration_tests/OneOfDiscriminatorTest.kt b/core/src/test/kotlin/integration_tests/OneOfDiscriminatorTest.kt index 56127afa0..f87d63991 100644 --- a/core/src/test/kotlin/integration_tests/OneOfDiscriminatorTest.kt +++ b/core/src/test/kotlin/integration_tests/OneOfDiscriminatorTest.kt @@ -587,11 +587,15 @@ components: val results = feature.executeTests(object : TestExecutor { override fun execute(request: HttpRequest): HttpResponse { + println(request.toLogString()) val jsonRequest = request.body as? JSONObjectValue ?: fail("Expected request to be a json object") assertThat(jsonRequest.jsonObject).containsKey("petType") petTypesSeen.add(jsonRequest.jsonObject["petType"]?.toStringLiteral() ?: "") + if(jsonRequest.jsonObject["petType"]?.toStringLiteral() == "dog") { + assertThat(jsonRequest.findFirstChildByPath("barkVolume")?.toStringLiteral()).isEqualTo("10") + } return HttpResponse.ok(parsedJSONObject("""{"name": "Spot", "age": 2, "petType": "dog", "barkVolume": 10}""")) } @@ -807,6 +811,10 @@ components: assertThat(jsonRequest.jsonObject).containsKey("petType") + if(jsonRequest.jsonObject["petType"]?.toStringLiteral() == "dog") { + assertThat(jsonRequest.findFirstChildByPath("barkVolume")?.toStringLiteral()).isEqualTo("10") + } + return HttpResponse.ok(parsedJSONObject("""{"name": "Spot", "age": 2, "petType": "dog", "barkVolume": 10}""")) } @@ -823,6 +831,7 @@ components: assertThat(petTypesSeen).containsAll(listOf("dog", "cat")) assertThat(results.testCount).isEqualTo(2) + assertThat(results.success()).withFailMessage(results.report()).isTrue() } } \ No newline at end of file