diff --git a/consumer/junit5/src/main/kotlin/au/com/dius/pact/consumer/junit5/PactConsumerTestExt.kt b/consumer/junit5/src/main/kotlin/au/com/dius/pact/consumer/junit5/PactConsumerTestExt.kt index bb15342e6..015f92241 100644 --- a/consumer/junit5/src/main/kotlin/au/com/dius/pact/consumer/junit5/PactConsumerTestExt.kt +++ b/consumer/junit5/src/main/kotlin/au/com/dius/pact/consumer/junit5/PactConsumerTestExt.kt @@ -531,7 +531,7 @@ class PactConsumerTestExt : Extension, BeforeTestExecutionCallback, BeforeAllCal pactsToWrite.merge( Pair(pact.consumer, pact.provider), - Pair(pact as BasePact, version) + Pair(pact, version) ) { (currentPact, currentVersion), _ -> val mergedPact = currentPact.mergeInteractions(pact.interactions) as BasePact Pair(mergedPact, maxOf(version, currentVersion)) diff --git a/consumer/junit5/src/test/groovy/au/com/dius/pact/consumer/junit5/JsonStringAtRootTest.groovy b/consumer/junit5/src/test/groovy/au/com/dius/pact/consumer/junit5/JsonStringAtRootTest.groovy new file mode 100644 index 000000000..f9d7c5048 --- /dev/null +++ b/consumer/junit5/src/test/groovy/au/com/dius/pact/consumer/junit5/JsonStringAtRootTest.groovy @@ -0,0 +1,38 @@ +package au.com.dius.pact.consumer.junit5 + +import au.com.dius.pact.consumer.MockServer +import au.com.dius.pact.consumer.dsl.PactDslJsonRootValue +import au.com.dius.pact.consumer.dsl.PactDslWithProvider +import au.com.dius.pact.core.model.PactSpecVersion +import au.com.dius.pact.core.model.V4Pact +import au.com.dius.pact.core.model.annotations.Pact +import org.apache.hc.client5.http.fluent.Request +import org.apache.hc.core5.http.ClassicHttpResponse +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(PactConsumerTestExt) +@PactTestFor(providerName = 'JsonStringAtRootTest', pactVersion = PactSpecVersion.V4) +class JsonStringAtRootTest { + final static String JOB_ID = '08f7a210-95db-4827-bcc8-d2025ba506cf' + + @Pact(consumer = 'Consumer') + V4Pact pact(PactDslWithProvider builder) { + builder + .uponReceiving('a request for some JSON') + .path('/endpoint') + .willRespondWith() + .status(201) + .body(PactDslJsonRootValue.uuid(JOB_ID)) + .toPact(V4Pact) + } + + @Test + void test(MockServer mockServer) { + ClassicHttpResponse httpResponse = Request.get("${mockServer.url}/endpoint") + .execute().returnResponse() as ClassicHttpResponse + assert httpResponse.code == 201 + assert httpResponse.getHeader('content-type').value == 'application/json; charset=UTF-8' + assert httpResponse.entity.content.text == '"' + JOB_ID + '"' + } +} diff --git a/core/model/src/main/kotlin/au/com/dius/pact/core/model/OptionalBody.kt b/core/model/src/main/kotlin/au/com/dius/pact/core/model/OptionalBody.kt index 60f10c366..e50f34554 100644 --- a/core/model/src/main/kotlin/au/com/dius/pact/core/model/OptionalBody.kt +++ b/core/model/src/main/kotlin/au/com/dius/pact/core/model/OptionalBody.kt @@ -179,7 +179,7 @@ data class OptionalBody @JvmOverloads constructor( mapOf( "content" to JsonParser.parseString(valueAsString()), "contentType" to contentType.toString(), - "encoded" to false + "encoded" to "json" ) } else { mapOf( diff --git a/core/model/src/main/kotlin/au/com/dius/pact/core/model/PactWriter.kt b/core/model/src/main/kotlin/au/com/dius/pact/core/model/PactWriter.kt index d73367359..5fc073db2 100644 --- a/core/model/src/main/kotlin/au/com/dius/pact/core/model/PactWriter.kt +++ b/core/model/src/main/kotlin/au/com/dius/pact/core/model/PactWriter.kt @@ -56,7 +56,7 @@ object DefaultPactWriter : PactWriter, KLogging() { * @param pactSpecVersion Pact version to use to control writing */ override fun writePact(pact: Pact, writer: PrintWriter, pactSpecVersion: PactSpecVersion) : Result { - val json = if (pactSpecVersion == PactSpecVersion.V4) { + val json = if (pactSpecVersion >= PactSpecVersion.V4) { Json.prettyPrint(pact.sortInteractions().asV4Pact() .expect { "Failed to upcast to a V4 pact" }.toMap(pactSpecVersion)) } else { diff --git a/core/model/src/main/kotlin/au/com/dius/pact/core/model/V4Pact.kt b/core/model/src/main/kotlin/au/com/dius/pact/core/model/V4Pact.kt index c0f2c55fc..28de57ea2 100644 --- a/core/model/src/main/kotlin/au/com/dius/pact/core/model/V4Pact.kt +++ b/core/model/src/main/kotlin/au/com/dius/pact/core/model/V4Pact.kt @@ -59,12 +59,14 @@ fun bodyFromJson(field: String, json: JsonValue, headers: Map): Opt val bodyBytes = if (encoded) { when (encoding) { "base64" -> Base64.getDecoder().decode(Json.toString(jsonBody["content"])) - "json" -> Json.toString(jsonBody["content"]).toByteArray(contentType.asCharset()) + "json" -> jsonBody["content"].serialise().toByteArray(contentType.asCharset()) else -> { logger.warn { "Unrecognised body encoding scheme '$encoding', will use the raw body" } Json.toString(jsonBody["content"]).toByteArray(contentType.asCharset()) } } + } else if (contentType.isJson()) { + jsonBody["content"].serialise().toByteArray(contentType.asCharset()) } else { Json.toString(jsonBody["content"]).toByteArray(contentType.asCharset()) } diff --git a/core/model/src/test/groovy/au/com/dius/pact/core/model/OptionalBodySpec.groovy b/core/model/src/test/groovy/au/com/dius/pact/core/model/OptionalBodySpec.groovy index ba5f9fd7f..0dbbb72dc 100644 --- a/core/model/src/test/groovy/au/com/dius/pact/core/model/OptionalBodySpec.groovy +++ b/core/model/src/test/groovy/au/com/dius/pact/core/model/OptionalBodySpec.groovy @@ -163,8 +163,8 @@ class OptionalBodySpec extends Specification { body | v4Format OptionalBody.missing() | [:] OptionalBody.body(''.bytes, ContentType.UNKNOWN) | [content: ''] - OptionalBody.body('{}'.bytes, ContentType.UNKNOWN) | [content: new JsonValue.Object(), contentType: 'application/json', encoded: false] - OptionalBody.body('{}'.bytes, ContentType.JSON) | [content: new JsonValue.Object(), contentType: 'application/json', encoded: false] + OptionalBody.body('{}'.bytes, ContentType.UNKNOWN) | [content: new JsonValue.Object(), contentType: 'application/json', encoded: 'json'] + OptionalBody.body('{}'.bytes, ContentType.JSON) | [content: new JsonValue.Object(), contentType: 'application/json', encoded: 'json'] OptionalBody.body([0xff, 0xd8, 0xff, 0xe0] as byte[], new ContentType('image/jpeg')) | [content: '/9j/4A==', contentType: 'image/jpeg', encoded: 'base64', contentTypeHint: 'DEFAULT'] OptionalBody.body('kjlkjlkjkl'.bytes, new ContentType('application/other'), ContentTypeHint.BINARY) | [content: 'a2psa2psa2prbA==', contentType: 'application/other', encoded: 'base64', contentTypeHint: 'BINARY'] } diff --git a/core/model/src/test/groovy/au/com/dius/pact/core/model/PactWriterSpec.groovy b/core/model/src/test/groovy/au/com/dius/pact/core/model/PactWriterSpec.groovy index f5bd3a520..d4d43b005 100644 --- a/core/model/src/test/groovy/au/com/dius/pact/core/model/PactWriterSpec.groovy +++ b/core/model/src/test/groovy/au/com/dius/pact/core/model/PactWriterSpec.groovy @@ -345,7 +345,7 @@ class PactWriterSpec extends Specification { | "contents": { | "content": "this is a message", | "contentType": "application/json", - | "encoded": false + | "encoded": "json" | } | }, | "response": [ @@ -353,7 +353,7 @@ class PactWriterSpec extends Specification { | "contents": { | "content": "this is a response", | "contentType": "application/json", - | "encoded": false + | "encoded": "json" | } | } | ], diff --git a/core/model/src/test/groovy/au/com/dius/pact/core/model/V4PactKtSpec.groovy b/core/model/src/test/groovy/au/com/dius/pact/core/model/V4PactKtSpec.groovy index 1c0273b1e..377493b5b 100644 --- a/core/model/src/test/groovy/au/com/dius/pact/core/model/V4PactKtSpec.groovy +++ b/core/model/src/test/groovy/au/com/dius/pact/core/model/V4PactKtSpec.groovy @@ -18,4 +18,26 @@ class V4PactKtSpec extends Specification { [body: new JsonValue.StringValue('')] | OptionalBody.empty() [body: new JsonValue.Object([content: new JsonValue.StringValue('')])] | OptionalBody.empty() } + + @SuppressWarnings('LineLength') + def 'bodyFromJson - handling different types of encoding'() { + expect: + bodyFromJson('body', new JsonValue.Object([ + body: new JsonValue.Object([ + content: content, + encoded: encoding, + contentType: new JsonValue.StringValue(contentType) + ]) + ]), [:]) == body + + where: + + content | encoding | contentType | body + new JsonValue.Object([:]) | JsonValue.False.INSTANCE | 'application/json' | OptionalBody.body('{}'.bytes, ContentType.JSON) + new JsonValue.Object([:]) | JsonValue.False.INSTANCE | '' | OptionalBody.body('{}'.bytes, ContentType.JSON) + new JsonValue.StringValue('ABC') | JsonValue.False.INSTANCE | 'application/json' | OptionalBody.body('"ABC"'.bytes, ContentType.JSON) + new JsonValue.StringValue('ABC') | new JsonValue.StringValue('json') | 'application/json' | OptionalBody.body('"ABC"'.bytes, ContentType.JSON) + new JsonValue.StringValue('IkFCQyI=') | JsonValue.True.INSTANCE | 'application/json' | OptionalBody.body('"ABC"'.bytes, ContentType.JSON) + new JsonValue.StringValue('IkFCQyI=') | new JsonValue.StringValue('base64') | 'application/json' | OptionalBody.body('"ABC"'.bytes, ContentType.JSON) + } } diff --git a/core/support/src/test/groovy/au/com/dius/pact/core/support/JsonSpec.groovy b/core/support/src/test/groovy/au/com/dius/pact/core/support/JsonSpec.groovy index 7d14b6814..8371712de 100644 --- a/core/support/src/test/groovy/au/com/dius/pact/core/support/JsonSpec.groovy +++ b/core/support/src/test/groovy/au/com/dius/pact/core/support/JsonSpec.groovy @@ -83,4 +83,22 @@ class JsonSpec extends Specification { '{"a": "A", "b": 1, "c": [100], "d": {"href": "blah"}}' | '{\n "a": "A",\n "b": 1,\n "c": [\n 100\n ],\n "d": {\n "href": "blah"\n }\n}' } + @Unroll + def 'toString - #desc'() { + expect: + Json.INSTANCE.toString(json == null ? json : JsonParser.parseString(json)) == value + + where: + + desc | json | value + 'Null' | null | 'null' + 'Json Null' | 'null' | 'null' + 'Boolean True' | 'true' | 'true' + 'Boolean False' | 'false' | 'false' + 'integer' | '112' | '112' + 'float' | '112.66' | '112.66' + 'string' | '"hello"' | 'hello' + 'list' | '["hello", 1, true, {"a": "A"}]' | '["hello",1,true,{"a":"A"}]' + 'object' | '{"hello": "world", "list": [1, 2, 3]}' | '{"hello":"world","list":[1,2,3]}' + } }