From 00e475c43478f8fe8522218d8da8c58938a31450 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Wed, 13 Jan 2016 15:40:02 +0100 Subject: [PATCH 1/2] Add utility function for comparing json_objects --- json_object.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++ json_object.h | 20 +++++++++++++ 2 files changed, 101 insertions(+) diff --git a/json_object.c b/json_object.c index e611103..38e69c6 100644 --- a/json_object.c +++ b/json_object.c @@ -992,3 +992,84 @@ struct json_object* json_object_array_get_idx(const struct json_object *jso, return (struct json_object*)array_list_get_idx(jso->o.c_array, idx); } +static int json_array_equal(struct json_object* jso1, + struct json_object* jso2) +{ + int len, i; + + len = json_object_array_length(jso1); + if (len != json_object_array_length(jso2)) + return 0; + + for (i = 0; i < len; i++) { + if (!json_object_equal(json_object_array_get_idx(jso1, i), + json_object_array_get_idx(jso2, i))) + return 0; + } + return 1; +} + +static int json_object_all_values_equal(struct json_object* jso1, + struct json_object* jso2) +{ + struct json_object_iter iter; + struct json_object *sub; + + /* Iterate over jso1 keys and see if they exist and are equal in jso2 */ + json_object_object_foreachC(jso1, iter) { + if (!lh_table_lookup_ex(jso1->o.c_object, (void*)iter.key, + (void**)&sub)) + return 0; + if (!json_object_equal(iter.val, sub)) + return 0; + } + + /* Iterate over jso2 keys to see if any exist that are not in jso1 */ + json_object_object_foreachC(jso2, iter) { + if (!lh_table_lookup_ex(jso1->o.c_object, (void*)iter.key, + (void**)&sub)) + return 0; + } + + return 1; +} + +int json_object_equal(struct json_object* jso1, struct json_object* jso2) +{ + if (jso1 == jso2) + return 1; + + if (!jso1 || !jso2) + return 0; + + if (jso1->o_type != jso2->o_type) + return 0; + + switch(jso1->o_type) { + case json_type_boolean: + return (jso1->o.c_boolean == jso2->o.c_boolean); + + case json_type_double: + return (jso1->o.c_double == jso2->o.c_double); + + case json_type_int: + return (jso1->o.c_int64 == jso2->o.c_int64); + + case json_type_string: + return (jso1->o.c_string.len == jso2->o.c_string.len && + memcmp(get_string_component(jso1), + get_string_component(jso2), + jso1->o.c_string.len) == 0); + + case json_type_object: + return json_object_all_values_equal(jso1, jso2); + + case json_type_array: + return json_array_equal(jso1, jso2); + + case json_type_null: + return 1; + }; + + return 0; +} diff --git a/json_object.h b/json_object.h index 99b8edf..ee53524 100644 --- a/json_object.h +++ b/json_object.h @@ -691,6 +691,26 @@ extern const char* json_object_get_string(struct json_object *obj); */ extern int json_object_get_string_len(const struct json_object *obj); +/** Check if two json_object's are equal + * + * If the passed objects are equal 1 will be returned. + * Equality is defined as follows: + * - json_objects of different types are never equal + * - json_objects of the same primitive type are equal if the + * c-representation of their value is equal + * - json-arrays are considered equal if all values at the same + * indices are equal (same order) + * - Complex json_objects are considered equal if all + * contained objects referenced by their key are equal, + * regardless their order. + * + * @param obj1 the first json_object instance + * @param obj2 the second json_object instance + * @returns whether both objects are equal or not + */ +extern int json_object_equal(struct json_object *obj1, + struct json_object *obj2); + #ifdef __cplusplus } #endif From dec5fcd50b74cbdc1f3cd28131d8d777dea1844e Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Wed, 13 Jan 2016 15:40:08 +0100 Subject: [PATCH 2/2] Add some basic tests for verifying json_object_equal behavior Do some basic checks on ints, doubles, strings, arrays and "complex" objects. --- .gitignore | 1 + tests/Makefile.am | 1 + tests/test_compare.c | 145 ++++++++++++++++++++++++++++++++++++ tests/test_compare.expected | 13 ++++ tests/test_compare.test | 12 +++ 5 files changed, 172 insertions(+) create mode 100644 tests/test_compare.c create mode 100644 tests/test_compare.expected create mode 100755 tests/test_compare.test diff --git a/.gitignore b/.gitignore index 7d3dbf9..57aa6d1 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,7 @@ /tests/test_null /tests/test_printbuf /tests/test_set_serializer +/tests/test_compare /tests/*.vg.out /tests/*.log /tests/*.trs diff --git a/tests/Makefile.am b/tests/Makefile.am index dd34348..79b196b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -16,6 +16,7 @@ TESTS+= test_locale.test TESTS+= test_charcase.test TESTS+= test_printbuf.test TESTS+= test_set_serializer.test +TESTS+= test_compare.test check_PROGRAMS= check_PROGRAMS += $(TESTS:.test=) diff --git a/tests/test_compare.c b/tests/test_compare.c new file mode 100644 index 0000000..30c6e50 --- /dev/null +++ b/tests/test_compare.c @@ -0,0 +1,145 @@ +/* +* Tests if json_object_equal behaves correct. +*/ + +#include +#include +#include "config.h" + +#include "json_inttypes.h" +#include "json_object.h" +#include "json_tokener.h" + +int main() +{ + /* integer tests */ + struct json_object *int1 = json_object_new_int(0); + struct json_object *int2 = json_object_new_int(1); + struct json_object *int3 = json_object_new_int(1); + + if (!json_object_equal(int1, int2)) + printf("JSON integer comparision is correct\n"); + else + printf("JSON integer comparision failed\n"); + + if (json_object_equal(int1, int1)) + printf("JSON same object comparision is correct\n"); + else + printf("JSON same object comparision failed\n"); + + if (json_object_equal(int2, int3)) + printf("JSON same integer comparision is correct\n"); + else + printf("JSON same integer comparision failed\n"); + + json_object_put(int1); + json_object_put(int2); + json_object_put(int3); + + /* string tests */ + struct json_object *str1 = json_object_new_string("TESTSTRING"); + struct json_object *str2 = json_object_new_string("TESTSTRING"); + struct json_object *str3 = json_object_new_string("DIFFERENT"); + + if (json_object_equal(str1, str2)) + printf("Comparing equal strings is correct\n"); + else + printf("Comparing equal strings failed\n"); + + if (!json_object_equal(str1, str3)) + printf("Comparing different strings is correct\n"); + else + printf("Comparing different strings failed\n"); + + json_object_put(str1); + json_object_put(str2); + json_object_put(str3); + + /* double tests */ + struct json_object *dbl1 = json_object_new_double(3.14159); + struct json_object *dbl2 = json_object_new_double(3.14159); + struct json_object *dbl3 = json_object_new_double(3.0); + + if (json_object_equal(dbl1, dbl2)) + printf("Comparing equal doubles is correct\n"); + else + printf("Comparing equal doubles failed\n"); + + if (!json_object_equal(dbl1, dbl3)) + printf("Comparing different doubles is correct\n"); + else + printf("Comparing different doubles failed\n"); + + json_object_put(dbl1); + json_object_put(dbl2); + json_object_put(dbl3); + + /* array tests */ + struct json_object *ar1 = json_object_new_array(); + struct json_object *ar2 = json_object_new_array(); + struct json_object *ar3 = json_object_new_array(); + struct json_object *ar4 = json_object_new_array(); + + json_object_array_add(ar1, json_object_new_int(1)); + json_object_array_add(ar1, json_object_new_int(2)); + + json_object_array_add(ar2, json_object_new_int(1)); + json_object_array_add(ar2, json_object_new_int(2)); + + json_object_array_add(ar3, json_object_new_int(1)); + json_object_array_add(ar3, json_object_new_int(1)); + + if (json_object_equal(ar1, ar2)) + printf("Comparing equal arrays is correct\n"); + else + printf("Comparing equal arrays failed\n"); + + json_object_array_add(ar2, json_object_new_int(1)); + if (!json_object_equal(ar1, ar2)) + printf("Comparing arrays of different len is correct\n"); + else + printf("Comparing arrays of different len failed\n"); + + if (!json_object_equal(ar1, ar3)) + printf("Comparing different arrays is correct\n"); + else + printf("Comparing different arrays failed\n"); + + if (!json_object_equal(ar1, ar4)) + printf("Comparing different arrays (one empty) is correct\n"); + else + printf("Comparing different arrays (one empty) failed\n"); + + json_object_put(ar1); + json_object_put(ar2); + json_object_put(ar3); + json_object_put(ar4); + + /* object tests */ + struct json_object *obj1 = json_object_new_object(); + struct json_object *obj2 = json_object_new_object(); + + json_object_object_add(obj1, "test1", json_object_new_int(123)); + json_object_object_add(obj1, "test2", json_object_new_int(321)); + + json_object_object_add(obj2, "test2", json_object_new_int(123)); + json_object_object_add(obj2, "test1", json_object_new_int(321)); + + /* key-order is different between obj1 and obj2, should still be equal */ + if (json_object_equal(obj1, obj2)) + printf("Comparing JSON object with different key order is correct\n"); + else + printf("Comparing JSON object with different key order is incorrect\n"); + + /* make obj2 look different to obj1 */ + json_object_object_add(obj2, "test3", json_object_new_int(234)); + if (!json_object_equal(obj1, obj2)) + printf("Comparing different objects is correct\n"); + else + printf("Comparing different objects is incorrect\n"); + + json_object_put(obj1); + json_object_put(obj2); + + return 0; +} diff --git a/tests/test_compare.expected b/tests/test_compare.expected new file mode 100644 index 0000000..46f03c4 --- /dev/null +++ b/tests/test_compare.expected @@ -0,0 +1,13 @@ +JSON integer comparision is correct +JSON same object comparision is correct +JSON same integer comparision is correct +Comparing equal strings is correct +Comparing different strings is correct +Comparing equal doubles is correct +Comparing different doubles is correct +Comparing equal arrays is correct +Comparing arrays of different len is correct +Comparing different arrays is correct +Comparing different arrays (one empty) is correct +Comparing JSON object with different key order is correct +Comparing different objects is correct diff --git a/tests/test_compare.test b/tests/test_compare.test new file mode 100755 index 0000000..bcc4ff3 --- /dev/null +++ b/tests/test_compare.test @@ -0,0 +1,12 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +run_output_test test_compare +exit $?