aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorZach Smith <zach@driver.xyz>2018-03-16 18:47:30 +0100
committerZach Smith <zach@driver.xyz>2018-03-16 20:03:44 +0100
commitce099ac3ba85f71adeba0bb8398b69dc7cd2e8d1 (patch)
tree772e000647aeaf59bd8b22cd22661d3998f22f7e /src/test
parent96aa1fbf7608e3b9cd1ba06c57ab1f356409733d (diff)
downloaddriver-core-ce099ac3ba85f71adeba0bb8398b69dc7cd2e8d1.tar.gz
driver-core-ce099ac3ba85f71adeba0bb8398b69dc7cd2e8d1.tar.bz2
driver-core-ce099ac3ba85f71adeba0bb8398b69dc7cd2e8d1.zip
Add PatchSupport trait and tests
Diffstat (limited to 'src/test')
-rw-r--r--src/test/scala/xyz/driver/core/rest/PatchSupportTest.scala77
1 files changed, 77 insertions, 0 deletions
diff --git a/src/test/scala/xyz/driver/core/rest/PatchSupportTest.scala b/src/test/scala/xyz/driver/core/rest/PatchSupportTest.scala
new file mode 100644
index 0000000..dcb3a93
--- /dev/null
+++ b/src/test/scala/xyz/driver/core/rest/PatchSupportTest.scala
@@ -0,0 +1,77 @@
+package xyz.driver.core.rest
+
+import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
+import akka.http.scaladsl.model.{ContentTypes, HttpEntity, RequestEntity, StatusCodes}
+import akka.http.scaladsl.server.{Directives, Route}
+import akka.http.scaladsl.testkit.ScalatestRouteTest
+import org.scalatest.{FlatSpec, Matchers}
+import spray.json._
+import xyz.driver.core.{Id, Name}
+import xyz.driver.core.json._
+
+import scala.concurrent.Future
+
+class PatchSupportTest
+ extends FlatSpec with Matchers with ScalatestRouteTest with SprayJsonSupport with DefaultJsonProtocol
+ with Directives with PatchSupport {
+ case class Bar(name: Name[Bar], size: Int)
+ case class Foo(id: Id[Foo], name: Name[Foo], rank: Int, bar: Option[Bar])
+ implicit val barFormat: RootJsonFormat[Bar] = jsonFormat2(Bar)
+ implicit val fooFormat: RootJsonFormat[Foo] = jsonFormat4(Foo)
+
+ val testFoo: Foo = Foo(Id("1"), Name(s"Foo"), 1, Some(Bar(Name("Bar"), 10)))
+
+ def route(implicit patchRetrievable: PatchRetrievable[Foo]): Route =
+ Route.seal(path("api" / "v1" / "foos" / IdInPath[Foo]) { fooId =>
+ patch(as[Foo], fooId) { patchedFoo =>
+ complete(patchedFoo)
+ }
+ })
+
+ def jsonEntity(json: String): RequestEntity = HttpEntity(ContentTypes.`application/json`, json)
+
+ "PatchSupport" should "allow partial updates to an existing object" in {
+ implicit val fooPatchable: PatchRetrievable[Foo] = id => Future.successful(Some(testFoo.copy(id = id)))
+
+ Patch("/api/v1/foos/1", jsonEntity("""{"rank": 4}""")) ~> route ~> check {
+ handled shouldBe true
+ responseAs[Foo] shouldBe testFoo.copy(rank = 4)
+ }
+ }
+
+ it should "merge deeply nested objects" in {
+ implicit val fooPatchable: PatchRetrievable[Foo] = id => Future.successful(Some(testFoo.copy(id = id)))
+
+ Patch("/api/v1/foos/1", jsonEntity("""{"rank": 4, "bar": {"name": "My Bar"}}""")) ~> route ~> check {
+ handled shouldBe true
+ responseAs[Foo] shouldBe testFoo.copy(rank = 4, bar = Some(Bar(Name("My Bar"), 10)))
+ }
+ }
+
+ it should "return a 404 if the object is not found" in {
+ implicit val fooPatchable: PatchRetrievable[Foo] = _ => Future.successful(Option.empty[Foo])
+
+ Patch("/api/v1/foos/1", jsonEntity("""{"rank": 4}""")) ~> route ~> check {
+ handled shouldBe true
+ status shouldBe StatusCodes.NotFound
+ }
+ }
+
+ it should "handle nulls on optional values correctly" in {
+ implicit val fooPatchable: PatchRetrievable[Foo] = id => Future.successful(Some(testFoo.copy(id = id)))
+
+ Patch("/api/v1/foos/1", jsonEntity("""{"bar": null}""")) ~> route ~> check {
+ handled shouldBe true
+ responseAs[Foo] shouldBe testFoo.copy(bar = None)
+ }
+ }
+
+ it should "return a 400 for nulls on non-optional values" in {
+ implicit val fooPatchable: PatchRetrievable[Foo] = id => Future.successful(Some(testFoo.copy(id = id)))
+
+ Patch("/api/v1/foos/1", jsonEntity("""{"rank": null}""")) ~> route ~> check {
+ handled shouldBe true
+ status shouldBe StatusCodes.BadRequest
+ }
+ }
+}