From 1ac1d69f9512d55d15e8218a9dbdff129bf96ddb Mon Sep 17 00:00:00 2001 From: andri lim Date: Wed, 20 Mar 2024 21:32:43 +0700 Subject: [PATCH] Add JsonValueRef compare operation (#89) --- json_serialization/value_ops.nim | 58 ++++++++++++- tests/test_valueref.nim | 139 ++++++++++++++++++++++++++----- 2 files changed, 174 insertions(+), 23 deletions(-) diff --git a/json_serialization/value_ops.nim b/json_serialization/value_ops.nim index 714223b..2246bf2 100644 --- a/json_serialization/value_ops.nim +++ b/json_serialization/value_ops.nim @@ -1,5 +1,5 @@ # json-serialization -# Copyright (c) 2023 Status Research & Development GmbH +# Copyright (c) 2023-2024 Status Research & Development GmbH # Licensed under either of # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) # * MIT license ([LICENSE-MIT](LICENSE-MIT)) @@ -79,4 +79,60 @@ proc delete*(obj: JsonValueRef, key: string) = raise newException(IndexDefect, "key not in object") obj.objVal.del(key) +func compare*(lhs, rhs: JsonValueRef): bool + +func compareObject(lhs, rhs: JsonValueRef): bool = + ## assume lhs.len >= rhs.len + ## null field and no field are treated equals + for k, v in lhs.objVal: + let rhsVal = rhs.objVal.getOrDefault(k, nil) + if rhsVal.isNil: + if v.kind != JsonValueKind.Null: + return false + else: + continue + if not compare(rhsVal, v): + return false + true + +func compare*(lhs, rhs: JsonValueRef): bool = + ## The difference between `==` and `compare` + ## lies in the object comparison. Null field `compare` + ## to non existent field will return true. + ## On the other hand, `==` will return false. + + if lhs.isNil and rhs.isNil: + return true + + if not lhs.isNil and rhs.isNil: + return false + + if lhs.isNil and not rhs.isNil: + return false + + if lhs.kind != rhs.kind: + return false + + case lhs.kind + of JsonValueKind.String: + lhs.strVal == rhs.strVal + of JsonValueKind.Number: + lhs.numVal == rhs.numVal + of JsonValueKind.Object: + if lhs.objVal.len >= rhs.objVal.len: + compareObject(lhs, rhs) + else: + compareObject(rhs, lhs) + of JsonValueKind.Array: + if lhs.arrayVal.len != rhs.arrayVal.len: + return false + for i, x in lhs.arrayVal: + if not compare(x, rhs.arrayVal[i]): + return false + true + of JsonValueKind.Bool: + lhs.boolVal == rhs.boolVal + of JsonValueKind.Null: + true + {.pop.} diff --git a/tests/test_valueref.nim b/tests/test_valueref.nim index 516df85..a4e3ba4 100644 --- a/tests/test_valueref.nim +++ b/tests/test_valueref.nim @@ -9,35 +9,130 @@ import unittest2, - ../json_serialization + ../json_serialization, + ../json_serialization/value_ops func jsonBool(x: bool): JsonValueRef[uint64] = JsonValueRef[uint64](kind: JsonValueKind.Bool, boolVal: x) +func jsonNull(): JsonValueRef[uint64] = + JsonValueRef[uint64](kind: JsonValueKind.Null) + suite "Test JsonValueRef": + let objA = JsonValueRef[uint64]( + kind: JsonValueKind.Object, + objVal: [ + ("a", jsonBool(true)), + ].toOrderedTable + ) + + let objA2 = JsonValueRef[uint64]( + kind: JsonValueKind.Object, + objVal: [ + ("a", jsonBool(true)), + ].toOrderedTable + ) + + let objABNull = JsonValueRef[uint64]( + kind: JsonValueKind.Object, + objVal: [ + ("a", jsonBool(true)), + ("b", jsonNull()) + ].toOrderedTable + ) + + let objAB = JsonValueRef[uint64]( + kind: JsonValueKind.Object, + objVal: [ + ("a", jsonBool(true)), + ("b", jsonBool(true)) + ].toOrderedTable + ) + + let objInArrayA = JsonValueRef[uint64]( + kind: JsonValueKind.Array, + arrayVal: @[ + objA + ] + ) + + let objInArrayA2 = JsonValueRef[uint64]( + kind: JsonValueKind.Array, + arrayVal: @[ + objA2 + ] + ) + + let objInArrayAB = JsonValueRef[uint64]( + kind: JsonValueKind.Array, + arrayVal: @[ + objAB + ] + ) + + let objInArrayABNull = JsonValueRef[uint64]( + kind: JsonValueKind.Array, + arrayVal: @[ + objABNull + ] + ) + + let objInObjA = JsonValueRef[uint64]( + kind: JsonValueKind.Object, + objVal: [ + ("x", objA) + ].toOrderedTable + ) + + let objInObjA2 = JsonValueRef[uint64]( + kind: JsonValueKind.Object, + objVal: [ + ("x", objA2) + ].toOrderedTable + ) + + let objInObjAB = JsonValueRef[uint64]( + kind: JsonValueKind.Object, + objVal: [ + ("x", objAB) + ].toOrderedTable + ) + + let objInObjABNull = JsonValueRef[uint64]( + kind: JsonValueKind.Object, + objVal: [ + ("x", objABNull) + ].toOrderedTable + ) + test "Test table keys equality": - let a = JsonValueRef[uint64]( - kind: JsonValueKind.Object, - objVal: [ - ("a", jsonBool(true)), - ].toOrderedTable - ) + check objA != objAB + check objA == objA2 + check objA != objABNull + check objAB != objABNull - let a2 = JsonValueRef[uint64]( - kind: JsonValueKind.Object, - objVal: [ - ("a", jsonBool(true)), - ].toOrderedTable - ) + check objInArrayA != objInArrayAB + check objInArrayA != objInArrayABNull + check objInArrayA == objInArrayA2 + check objInArrayAB != objInArrayABNull - let b = JsonValueRef[uint64]( - kind: JsonValueKind.Object, - objVal: [ - ("a", jsonBool(true)), - ("b", jsonBool(true)) - ].toOrderedTable - ) + check objInObjA != objInObjAB + check objInObjA != objInObjABNull + check objInObjA == objInObjA2 + check objInObjAB != objInObjABNull - check a != b - check a == a2 + test "Test compare": + check compare(objA, objAB) == false + check compare(objA, objA2) == true + check compare(objA, objABNull) == true + check compare(objAB, objABNull) == false + check compare(objInArrayA, objInArrayAB) == false + check compare(objInArrayA, objInArrayABNull) == true + check compare(objInArrayA, objInArrayA2) == true + check compare(objInArrayAB, objInArrayABNull) == false + + check compare(objInObjA, objInObjAB) == false + check compare(objInObjA, objInObjABNull) == true + check compare(objInObjA, objInObjA2) == true + check compare(objInObjAB, objInObjABNull) == false