diffson.TestJsonPatch.scala Maven / Gradle / Ivy
/*
* Copyright 2024 Diffson Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package diffson
package jsonpatch
import jsonpointer._
import cats.implicits._
import org.scalatest._
import org.scalatest.flatspec.AnyFlatSpec
import scala.util.Try
import scala.language.implicitConversions
import org.scalatest.matchers.should.Matchers
abstract class TestJsonPatch[Json](implicit Json: Jsony[Json])
extends AnyFlatSpec
with Matchers
with TestProtocol[Json] {
// add
"applying an 'add' operation" should "add the field to the object if it does not exist" in {
val op = Add[Json](parsePointer("/lbl"), 17)
op[Try](parseJson("{}")).get should be(parseJson("{ \"lbl\": 17 } "))
}
it should "add a value with an empty string as the key" in {
val op = Add[Json](parsePointer("/foo/"), 17)
op[Try](parseJson("{ \"foo\": {} }")).get should be(parseJson("{ \"foo\": {\"\": 17 } }"))
}
it should "replace the value if the pointer is the root" in {
val op = Add[Json](parsePointer(""), 17)
op[Try](parseJson("[1, 2, 3, 4]")).get should be(17: Json)
}
it should "replace the field value if it does exist" in {
val op = Add[Json](parsePointer("/lbl"), 17)
op[Try](parseJson("{ \"lbl\": true }")).get should be(parseJson("{ \"lbl\": 17 } "))
}
it should "add an element to the array at the given index" in {
val op1 = Add[Json](parsePointer("/1"), 17)
op1[Try](parseJson("[1, 2, 3]")).get should be(parseJson("[1, 17, 2, 3]"))
val op2 = Add[Json](parsePointer("/0"), 17)
op2[Try](parseJson("[1, 2, 3]")).get should be(parseJson("[17, 1, 2, 3]"))
}
it should "add an element at the end of the array if the last element is '-'" in {
val op = Add[Json](parsePointer("/-"), 17)
op[Try](parseJson("[1, 2, 3]")).get should be(parseJson("[1, 2, 3, 17]"))
}
it should "create a nested field if needed" in {
val op = Add[Json](parsePointer("/lbl/lbl"), 17)
op[Try](parseJson("{ \"lbl\": {} }")).get should be(parseJson("{ \"lbl\": { \"lbl\": 17 } }"))
}
it should "throw an error if some element is missing in the middle of the path" in {
a[PatchException] should be thrownBy {
val op = Add[Json](parsePointer("/lbl/lbl"), 17)
op[Try](parseJson("{}")).get
}
}
it should "throw an error if adding an element out of the array boundaries" in {
a[PatchException] should be thrownBy {
val op = Add[Json](parsePointer("/178"), 17)
op[Try](parseJson("[1, 2]")).get
}
}
// remove
"removing a label of an object" should "result in the object being amputated from this label" in {
val op = Remove[Json](parsePointer("/lbl"))
op[Try](parseJson("{ \"lbl\": 17, \"toto\": true }")).get should be(parseJson("{ \"toto\": true }"))
}
"removing an element of an array" should "result in the array being amputated from this element" in {
val op = Remove[Json](parsePointer("/2"))
op[Try](parseJson("[1, 2, 3, 4, 5]")).get should be(parseJson("[1, 2, 4, 5]"))
}
"removing the '-' element of an array" should "result in an error being thrown" in {
a[PatchException] should be thrownBy {
val op = Remove[Json](parsePointer("/-"))
op[Try](parseJson("[1, 2, 3, 4]")).get
}
}
"removing an element out of the array boundaries" should "result in an error being thrown" in {
a[PatchException] should be thrownBy {
val op = Remove[Json](parsePointer("/20"))
op[Try](parseJson("[1, 2, 3, 4]")).get
}
}
"removing an unknown label from an object" should "result in an error being thrown" in {
a[PatchException] should be thrownBy {
val op = Remove[Json](parsePointer("/toto"))
op[Try](parseJson("{}")).get
}
}
"removing the root" should "result in an error being thrown" in {
a[PatchException] should be thrownBy {
val op = Remove[Json](parsePointer("/"))
op[Try](parseJson("{}")).get
}
}
// replace
"replacing an element in an object" should "result in this element being replaced" in {
val op = Replace[Json](parsePointer("/lbl/lbl"), 17)
op[Try](parseJson("""{"lbl": {"lbl": true, "gruik": 1}, "toto": 3}""")).get should be(
parseJson("""{"lbl": {"lbl": 17, "gruik": 1}, "toto": 3}"""))
}
"replacing an element in an array" should "result in this element being replaced" in {
val op = Replace[Json](parsePointer("/3"), 17)
op[Try](parseJson("[true, false, true, true, true]")).get should be(parseJson("[true, false, true, 17,true]"))
}
"replacing the root" should "result in the value being completely replaced" in {
val op = Replace[Json](parsePointer(""), 17)
op[Try](parseJson("[1, 2, 3]")).get should be(17: Json)
}
"replacing a non-existing element in an object" should "result in an error being thrown" in {
a[PatchException] should be thrownBy {
val op = Replace[Json](parsePointer("/1/lbl"), 17)
op[Try](parseJson("[1, {}, true]")).get
}
}
"replacing the '-' element of an array" should "result in an error being thrown" in {
a[PatchException] should be thrownBy {
val op = Replace[Json](parsePointer("/-"), 17)
op[Try](parseJson("[1, 2, 3, 4]")).get
}
}
"replacing an element out of the array boundaries" should "result in an error being thrown" in {
a[PatchException] should be thrownBy {
val op = Replace[Json](parsePointer("/20"), 17)
op[Try](parseJson("[1, 2, 3, 4]")).get
}
a[PatchException] should be thrownBy {
val op = Replace[Json](parsePointer("/array/3/sub1"), 17)
op[Try](parseJson("{\"array\":[\"bar1\",\"bar2\",{\"sub1\":\"bar3\"}]}")).get
}
}
// move
"moving a value from an object to an array" should "result in the value being added to the array and removed from the object" in {
val op = Move(parsePointer("/0/lbl"), parsePointer("/1/1"))
op[Try](parseJson("[{ \"lbl\": 17, \"toto\": true }, [1, 2], \"plop\"]")).get should be(
parseJson("[{ \"toto\": true }, [1, 17, 2], \"plop\"]"))
}
"moving a value in a sub element" should "result in an error being thrown" in {
a[PatchException] should be thrownBy {
val op = Move(parsePointer("/0"), parsePointer("/0/toto"))
op[Try](parseJson("0")).get
}
}
"moving the root" should "result in an error being thrown" in {
a[PatchException] should be thrownBy {
val op = Move(parsePointer(""), parsePointer("/toto"))
op[Try](parseJson("0")).get
}
}
// copy
"copying an element in an object" should "result in this element being copied in the expected path" in {
val op = Copy[Json](parsePointer("/root/a"), parsePointer("/root/c"))
op.apply[Try](parseJson("""{"root": {"a": 1, "b": "B"}}""")).get shouldBe parseJson(
"""{"root": {"a": 1, "b": "B", "c": 1}}""")
}
// test
"testing an existing element of an object" should "succeed and not modify the original object" in {
val op = Test[Json](parsePointer("/a/b/3"), 6)
val initial = """{"a": {"b": [0,2,4,6] } }"""
op.apply[Try](parseJson(initial)).get shouldBe parseJson(initial)
}
"testing an existing element with a non-expected value" should "result in an error being thrown" in {
a[PatchException] should be thrownBy {
val op = Test[Json](parsePointer("/a"), 2)
op.apply[Try](parseJson("""{ "a": 1 }""")).get
}
}
"testing a non-existing element in an object" should "result in an error being thrown" in {
a[PatchException] should be thrownBy {
val op = Test[Json](parsePointer("/b"), 1)
op.apply[Try](parseJson("""{ "a": 1 }""")).get
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy