-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: 🚀 Provide Play-Json body encoder (#114)
Co-authored-by: jbwheatley <jackbwheatley@gmail.com>
- Loading branch information
1 parent
8571095
commit 5fad42c
Showing
7 changed files
with
303 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 51 additions & 0 deletions
51
play-json/src/main/scala/pact4s/playjson/JsonConversion.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package pact4s.playjson | ||
|
||
import au.com.dius.pact.consumer.dsl.{DslPart, PactDslJsonArray, PactDslJsonBody, PactDslJsonRootValue} | ||
import play.api.libs.json._ | ||
|
||
private[playjson] object JsonConversion { | ||
|
||
private def addFieldToBuilder(builder: PactDslJsonBody, fieldName: String, json: JsValue): PactDslJsonBody = | ||
json match { | ||
case JsNull => builder.nullValue(fieldName) | ||
case JsTrue => builder.booleanValue(fieldName, true) | ||
case JsFalse => builder.booleanValue(fieldName, false) | ||
case JsNumber(num) => builder.numberValue(fieldName, num) | ||
case JsString(str) => builder.stringValue(fieldName, str) | ||
case JsArray(array) => addArrayToJsonBody(builder, fieldName, array.toSeq) | ||
case jsonObject: JsObject => builder.`object`(fieldName, addJsonObjToBuilder(new PactDslJsonBody(), jsonObject)) | ||
} | ||
|
||
private def addJsonObjToBuilder(builder: PactDslJsonBody, jsonObj: JsObject): PactDslJsonBody = | ||
jsonObj.value.foldLeft(builder) { case (b, (s, j)) => | ||
addFieldToBuilder(b, s, j) | ||
} | ||
|
||
private def addArrayToJsonBody(builder: PactDslJsonBody, fieldName: String, array: Seq[JsValue]): PactDslJsonBody = | ||
addArrayValuesToArray(builder.array(fieldName), array).closeArray().asBody() | ||
|
||
private def addArrayValuesToArray(builder: PactDslJsonArray, array: Seq[JsValue]): PactDslJsonArray = | ||
array | ||
.foldLeft(builder) { (arrayBody, json) => | ||
json match { | ||
case JsNull => arrayBody.nullValue() | ||
case JsTrue => arrayBody.booleanValue(true) | ||
case JsFalse => arrayBody.booleanValue(false) | ||
case JsNumber(num) => arrayBody.numberValue(num) | ||
case JsString(str) => arrayBody.stringValue(str) | ||
case JsArray(arr) => addArrayValuesToArray(arrayBody.array(), arr.toSeq).closeArray().asArray() | ||
case jsonObj: JsObject => addJsonObjToBuilder(arrayBody.`object`(), jsonObj).closeObject().asArray() | ||
} | ||
} | ||
|
||
def jsonToPactDslJsonBody(json: JsValue): DslPart = | ||
json match { | ||
case JsNull => throw new IllegalArgumentException("Content cannot be null json value if set") | ||
case JsFalse => PactDslJsonRootValue.booleanType(false) | ||
case JsTrue => PactDslJsonRootValue.booleanType(true) | ||
case JsNumber(num) => PactDslJsonRootValue.numberType(num) | ||
case JsString(str) => PactDslJsonRootValue.stringType(str) | ||
case JsArray(arr) => addArrayValuesToArray(new PactDslJsonArray(), arr.toSeq) | ||
case jsonObj: JsObject => addJsonObjToBuilder(new PactDslJsonBody(), jsonObj) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package pact4s.playjson | ||
|
||
import au.com.dius.pact.core.model.messaging.Message | ||
import pact4s.algebras.{MessagePactDecoder, PactBodyJsonEncoder, PactDslJsonBodyEncoder} | ||
import pact4s.playjson.JsonConversion.jsonToPactDslJsonBody | ||
import pact4s.provider.ProviderState | ||
import play.api.libs.json.{Format, Json, Reads, Writes} | ||
|
||
import scala.util.Try | ||
|
||
object implicits { | ||
implicit def pactBodyEncoder[A](implicit writes: Writes[A]): PactBodyJsonEncoder[A] = | ||
(a: A) => Json.toJson(a).toString() | ||
|
||
implicit def pactDslJsonBodyConverter[A](implicit writes: Writes[A]): PactDslJsonBodyEncoder[A] = (a: A) => | ||
jsonToPactDslJsonBody(Json.toJson(a)) | ||
|
||
implicit def messagePactDecoder[A](implicit reads: Reads[A]): MessagePactDecoder[A] = (message: Message) => | ||
Try(Json.parse(message.contentsAsString()).as[A]).toEither | ||
|
||
implicit val providerStateFormat: Format[ProviderState] = Json.format[ProviderState] | ||
} |
82 changes: 82 additions & 0 deletions
82
play-json/src/test/java11+/pact4s/playjson/JsonConversionTests.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package pact4s.playjson | ||
|
||
import munit.FunSuite | ||
import pact4s.playjson.JsonConversion.jsonToPactDslJsonBody | ||
import play.api.libs.json.{JsNull, JsValue, Json} | ||
|
||
class JsonConversionTests extends FunSuite { | ||
|
||
def testRoundTrip(json: JsValue): Unit = | ||
assertEquals(Json.parse(jsonToPactDslJsonBody(json).getBody.toString), json) | ||
|
||
test("array-less JSON should round-trip with PactDslJsonBody") { | ||
val json = Json.obj( | ||
"key1" -> Json.toJson("value1"), | ||
"key2" -> Json.obj( | ||
"key2.1" -> Json.toJson(true), | ||
"key2.2" -> JsNull, | ||
"key2.3" -> Json.obj() | ||
), | ||
"key3" -> Json.toJson(1), | ||
"key4" -> Json.toJson(2.34) | ||
) | ||
|
||
testRoundTrip(json) | ||
} | ||
|
||
test("should raise exception if json is a top-level array") { | ||
val json = Json.arr( | ||
Json.toJson(1), | ||
Json.toJson(2), | ||
Json.toJson(3) | ||
) | ||
testRoundTrip(json) | ||
} | ||
|
||
test("should roundtrip an empty json object") { | ||
testRoundTrip(Json.obj()) | ||
} | ||
|
||
test("should work if JSON object contains a nested simple array") { | ||
val json = Json.obj( | ||
"array" -> Json.toJson(List(1, 2, 3)) | ||
) | ||
testRoundTrip(json) | ||
} | ||
|
||
test("should work if JSON object contains a nested array of objects") { | ||
val json = Json.obj( | ||
"array" -> Json.toJson( | ||
List( | ||
Json.obj("f" -> Json.toJson("g")), | ||
Json.obj("f" -> Json.toJson("h")) | ||
) | ||
) | ||
) | ||
testRoundTrip(json) | ||
} | ||
|
||
test("should work if JSON object contains an array of array") { | ||
val json = Json.obj( | ||
"array" -> Json.toJson( | ||
List( | ||
Json.toJson(List(1, 2, 3)), | ||
Json.toJson(List(4, 5, 6)) | ||
) | ||
) | ||
) | ||
testRoundTrip(json) | ||
} | ||
|
||
test("should encode top level string") { | ||
assertEquals(jsonToPactDslJsonBody(Json.toJson("pact4s")).getBody.asString(), "pact4s") | ||
} | ||
|
||
test("should encode top level boolean") { | ||
assertEquals(jsonToPactDslJsonBody(Json.toJson(true)).getBody.asBoolean().booleanValue(), true) | ||
} | ||
|
||
test("should encode top level number") { | ||
assertEquals(jsonToPactDslJsonBody(Json.toJson(12)).getBody.asNumber().intValue(), 12) | ||
} | ||
} |
82 changes: 82 additions & 0 deletions
82
play-json/src/test/java8/pact4s/playjson/JsonConversionTests.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package pact4s.playjson | ||
|
||
import munit.FunSuite | ||
import pact4s.playjson.JsonConversion.jsonToPactDslJsonBody | ||
import play.api.libs.json.{JsNull, JsValue, Json} | ||
|
||
class JsonConversionTests extends FunSuite { | ||
|
||
def testRoundTrip(json: JsValue): Unit = | ||
assertEquals(Json.parse(jsonToPactDslJsonBody(json).getBody.toString), json) | ||
|
||
test("array-less JSON should round-trip with PactDslJsonBody") { | ||
val json = Json.obj( | ||
"key1" -> Json.toJson("value1"), | ||
"key2" -> Json.obj( | ||
"key2.1" -> Json.toJson(true), | ||
"key2.2" -> JsNull, | ||
"key2.3" -> Json.obj() | ||
), | ||
"key3" -> Json.toJson(1), | ||
"key4" -> Json.toJson(2.34) | ||
) | ||
|
||
testRoundTrip(json) | ||
} | ||
|
||
test("should raise exception if json is a top-level array") { | ||
val json = Json.arr( | ||
Json.toJson(1), | ||
Json.toJson(2), | ||
Json.toJson(3) | ||
) | ||
testRoundTrip(json) | ||
} | ||
|
||
test("should roundtrip an empty json object") { | ||
testRoundTrip(Json.obj()) | ||
} | ||
|
||
test("should work if JSON object contains a nested simple array") { | ||
val json = Json.obj( | ||
"array" -> Json.toJson(List(1, 2, 3)) | ||
) | ||
testRoundTrip(json) | ||
} | ||
|
||
test("should work if JSON object contains a nested array of objects") { | ||
val json = Json.obj( | ||
"array" -> Json.toJson( | ||
List( | ||
Json.obj("f" -> Json.toJson("g")), | ||
Json.obj("f" -> Json.toJson("h")) | ||
) | ||
) | ||
) | ||
testRoundTrip(json) | ||
} | ||
|
||
test("should work if JSON object contains an array of array") { | ||
val json = Json.obj( | ||
"array" -> Json.toJson( | ||
List( | ||
Json.toJson(List(1, 2, 3)), | ||
Json.toJson(List(4, 5, 6)) | ||
) | ||
) | ||
) | ||
testRoundTrip(json) | ||
} | ||
|
||
test("should encode top level string") { | ||
assertEquals(jsonToPactDslJsonBody(Json.toJson("pact4s")).getBody.asInstanceOf[String], "pact4s") | ||
} | ||
|
||
test("should encode top level boolean") { | ||
assertEquals(jsonToPactDslJsonBody(Json.toJson(true)).getBody.asInstanceOf[Boolean], true) | ||
} | ||
|
||
test("should encode top level number") { | ||
assertEquals(jsonToPactDslJsonBody(Json.toJson(12)).getBody.asInstanceOf[BigDecimal].toInt, 12) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters