Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JsonValueRef compare operation #89

Merged
merged 1 commit into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion json_serialization/value_ops.nim
Original file line number Diff line number Diff line change
@@ -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))
Expand Down Expand Up @@ -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.}
145 changes: 120 additions & 25 deletions tests/test_valueref.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
)

let a2 = JsonValueRef[uint64](
kind: JsonValueKind.Object,
objVal: [
("a", jsonBool(true)),
].toOrderedTable
)

let b = JsonValueRef[uint64](
kind: JsonValueKind.Object,
objVal: [
("a", jsonBool(true)),
("b", jsonBool(true))
].toOrderedTable
)

check a != b
check a == a2
check objA != objAB
check objA == objA2
check objA != objABNull
check objAB != objABNull

check objInArrayA != objInArrayAB
check objInArrayA != objInArrayABNull
check objInArrayA == objInArrayA2
check objInArrayAB != objInArrayABNull

check objInObjA != objInObjAB
check objInObjA != objInObjABNull
check objInObjA == objInObjA2
check objInObjAB != objInObjABNull

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