diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4f99316..420bfc1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,7 +1,7 @@
# Notes:
#
# Author: Paul Harris, June 2012
-# Additions: Joakim Soderberg, Febuary 2013
+# Additions: Joakim Soderberg, February 2013
#
# Supports: building static/shared, release/debug/etc, can also build html docs
# and some of the tests.
@@ -35,7 +35,7 @@
# >> make test (to run the tests, if you enabled them)
#
# Brief description on how it works:
-# There is a small heirachy of CMakeLists.txt files which define how the
+# There is a small hierarchy of CMakeLists.txt files which define how the
# project is built.
# Header file detection etc is done, and the results are written into config.h
# and jansson_config.h, which are generated from the corresponding
@@ -100,7 +100,7 @@ include (CheckFunctionKeywords)
include (CheckIncludeFiles)
include (CheckTypeSize)
-# supress format-truncation warning
+# suppress format-truncation warning
include (CheckCCompilerFlag)
check_c_compiler_flag(-Wno-format-truncation HAS_NO_FORMAT_TRUNCATION)
if (HAS_NO_FORMAT_TRUNCATION)
@@ -215,7 +215,7 @@ else ()
set (JSON_UINT8 "unsigned char")
endif ()
-# Check for ssize_t and SSIZE_T existance.
+# Check for ssize_t and SSIZE_T existence.
check_type_size(ssize_t SSIZE_T)
check_type_size(SSIZE_T UPPERCASE_SSIZE_T)
if(NOT HAVE_SSIZE_T)
diff --git a/README.rst b/README.rst
index 371e913..9570b8f 100644
--- a/README.rst
+++ b/README.rst
@@ -30,6 +30,18 @@ source distribution for details.
Compilation and Installation
----------------------------
+You can download and install Jansson using the `vcpkg `_ dependency manager:
+
+.. code-block:: bash
+
+ git clone https://github.com/Microsoft/vcpkg.git
+ cd vcpkg
+ ./bootstrap-vcpkg.sh
+ ./vcpkg integrate install
+ vcpkg install jansson
+
+The Jansson port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please `create an issue or pull request `_ on the vcpkg repository.
+
If you obtained a `source tarball`_ from the "Releases" section of the main
site just use the standard autotools commands::
diff --git a/cmake/CoverallsGenerateGcov.cmake b/cmake/CoverallsGenerateGcov.cmake
index 0c4c2b0..c4da8fb 100644
--- a/cmake/CoverallsGenerateGcov.cmake
+++ b/cmake/CoverallsGenerateGcov.cmake
@@ -102,8 +102,8 @@ if (GIT_FOUND)
message("Git branch: ${GIT_BRANCH}")
message("Git author: ${GIT_AUTHOR_NAME}")
message("Git e-mail: ${GIT_AUTHOR_EMAIL}")
- message("Git commiter name: ${GIT_COMMITTER_NAME}")
- message("Git commiter e-mail: ${GIT_COMMITTER_EMAIL}")
+ message("Git committer name: ${GIT_COMMITTER_NAME}")
+ message("Git committer e-mail: ${GIT_COMMITTER_EMAIL}")
message("Git commit message: ${GIT_COMMIT_MESSAGE}")
endif()
@@ -265,7 +265,7 @@ foreach (GCOV_FILE ${GCOV_FILES})
# Instead of trying to parse the source from the
# gcov file, simply read the file contents from the source file.
# (Parsing it from the gcov is hard because C-code uses ; in many places
- # which also happens to be the same as the CMake list delimeter).
+ # which also happens to be the same as the CMake list delimiter).
file(READ ${GCOV_SRC_PATH} GCOV_FILE_SOURCE)
string(REPLACE "\\" "\\\\" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")
diff --git a/cmake/FindSphinx.cmake b/cmake/FindSphinx.cmake
index 55539d4..3bf0a5d 100644
--- a/cmake/FindSphinx.cmake
+++ b/cmake/FindSphinx.cmake
@@ -241,27 +241,42 @@ endif ()
# ----------------------------------------------------------------------------
# determine Sphinx version
+# some quick experiments by @ploxiln
+# - sphinx 1.7 and later have the version output format like "sphinx-build 1.7.2"
+# - sphinx 1.2 through 1.6 have the version output format like "Sphinx (sphinx-build) 1.2.2"
+# - sphinx 1.1 and before do not have a "--version" flag, but it causes the help output like "-h" does which includes version like "Sphinx v1.0.2"
if (Sphinx-build_EXECUTABLE)
# intentionally use invalid -h option here as the help that is shown then
# will include the Sphinx version information
if (Sphinx_PYTHON_EXECUTABLE)
execute_process (
- COMMAND "${Sphinx_PYTHON_EXECUTABLE}" ${Sphinx_PYTHON_OPTIONS} "${Sphinx-build_EXECUTABLE}" -h
+ COMMAND "${Sphinx_PYTHON_EXECUTABLE}" ${Sphinx_PYTHON_OPTIONS} "${Sphinx-build_EXECUTABLE}" --version
OUTPUT_VARIABLE _Sphinx_VERSION
ERROR_VARIABLE _Sphinx_VERSION
)
elseif (UNIX)
execute_process (
- COMMAND "${Sphinx-build_EXECUTABLE}" -h
+ COMMAND "${Sphinx-build_EXECUTABLE}" --version
OUTPUT_VARIABLE _Sphinx_VERSION
ERROR_VARIABLE _Sphinx_VERSION
)
endif ()
# The sphinx version can also contain a "b" instead of the last dot.
- # For example "Sphinx v1.2b1" so we cannot just split on "."
- if (_Sphinx_VERSION MATCHES "Sphinx v([0-9]+\\.[0-9]+(\\.|b)[0-9]+)")
+ # For example "Sphinx v1.2b1" or "Sphinx 1.7.0b2" so we cannot just split on "."
+ if (_Sphinx_VERSION MATCHES "sphinx-build ([0-9]+\\.[0-9]+(\\.|a?|b?)([0-9]*)(b?)([0-9]*))")
set (Sphinx_VERSION_STRING "${CMAKE_MATCH_1}")
+ set (_SPHINX_VERSION_FOUND)
+ elseif (_Sphinx_VERSION MATCHES "Sphinx v([0-9]+\\.[0-9]+(\\.|b?)([0-9]*)(b?)([0-9]*))")
+ set (Sphinx_VERSION_STRING "${CMAKE_MATCH_1}")
+ set (_SPHINX_VERSION_FOUND)
+ elseif (_Sphinx_VERSION MATCHES "Sphinx \\(sphinx-build\\) ([0-9]+\\.[0-9]+(\\.|a?|b?)([0-9]*)(b?)([0-9]*))")
+ set (Sphinx_VERSION_STRING "${CMAKE_MATCH_1}")
+ set (_SPHINX_VERSION_FOUND)
+ endif ()
+endif ()
+
+if(_SPHINX_VERSION_FOUND)
string(REGEX REPLACE "([0-9]+)\\.[0-9]+(\\.|b)[0-9]+" "\\1" Sphinx_VERSION_MAJOR ${Sphinx_VERSION_STRING})
string(REGEX REPLACE "[0-9]+\\.([0-9]+)(\\.|b)[0-9]+" "\\1" Sphinx_VERSION_MINOR ${Sphinx_VERSION_STRING})
string(REGEX REPLACE "[0-9]+\\.[0-9]+(\\.|b)([0-9]+)" "\\1" Sphinx_VERSION_PATCH ${Sphinx_VERSION_STRING})
@@ -270,7 +285,6 @@ if (Sphinx-build_EXECUTABLE)
if (Sphinx_VERSION_PATCH EQUAL 0)
string (REGEX REPLACE "\\.0$" "" Sphinx_VERSION_STRING "${Sphinx_VERSION_STRING}")
endif ()
- endif()
endif ()
# ----------------------------------------------------------------------------
diff --git a/doc/apiref.rst b/doc/apiref.rst
index 5d8d41b..16f1ecb 100644
--- a/doc/apiref.rst
+++ b/doc/apiref.rst
@@ -726,6 +726,12 @@ allowed in object keys.
The value of any existing key is not changed. Returns 0 on success
or -1 on error.
+.. function:: int json_object_update_recursive(json_t *object, json_t *other)
+
+ Like :func:`json_object_update()`, but object values in *other* are
+ recursively merged with the corresponding values in *object* if they are also
+ objects, instead of overwriting them. Returns 0 on success or -1 on error.
+
.. function:: json_object_foreach(object, key, value)
Iterate over every key-value pair of ``object``, running the block
@@ -1351,7 +1357,11 @@ If no error or position information is needed, you can pass *NULL*.
It is important to note that this function can only succeed on stream
file descriptors (such as SOCK_STREAM). Using this function on a
non-stream file descriptor will result in undefined behavior. For
- non-stream file descriptors, see instead :func:`json_loadb()`.
+ non-stream file descriptors, see instead :func:`json_loadb()`. In
+ addition, please note that this function cannot be used on non-blocking
+ file descriptors (such as a non-blocking socket). Using this function
+ on non-blocking file descriptors has a high risk of data loss because
+ it does not support resuming.
This function requires POSIX and fails on all non-POSIX systems.
diff --git a/doc/tutorial.rst b/doc/tutorial.rst
index 56861c2..bb7a6c2 100644
--- a/doc/tutorial.rst
+++ b/doc/tutorial.rst
@@ -74,7 +74,7 @@ function::
static char *request(const char *url);
-It takes the URL as a parameter, preforms a HTTP GET request, and
+It takes the URL as a parameter, performs a HTTP GET request, and
returns a newly allocated string that contains the response body. If
the request fails, an error message is printed to stderr and the
return value is *NULL*. For full details, refer to :download:`the code
diff --git a/src/hashtable.h b/src/hashtable.h
index c112834..00d44a9 100644
--- a/src/hashtable.h
+++ b/src/hashtable.h
@@ -55,7 +55,7 @@ typedef struct hashtable {
*
* Returns 0 on success, -1 on error (out of memory).
*/
-int hashtable_init(hashtable_t *hashtable) JANSSON_ATTRS(warn_unused_result);
+int hashtable_init(hashtable_t *hashtable) JANSSON_ATTRS((warn_unused_result));
/**
* hashtable_close - Release all resources used by a hashtable object
diff --git a/src/jansson.def b/src/jansson.def
index ed72829..55b39c8 100644
--- a/src/jansson.def
+++ b/src/jansson.def
@@ -41,6 +41,7 @@ EXPORTS
json_object_update
json_object_update_existing
json_object_update_missing
+ json_object_update_recursive
json_object_iter
json_object_iter_at
json_object_iter_next
diff --git a/src/jansson.h b/src/jansson.h
index 1aa3c2c..3436465 100644
--- a/src/jansson.h
+++ b/src/jansson.h
@@ -40,9 +40,9 @@ extern "C" {
#endif
#if defined(__GNUC__) || defined(__clang__)
-#define JANSSON_ATTRS(...) __attribute__((__VA_ARGS__))
+#define JANSSON_ATTRS(x) __attribute__(x)
#else
-#define JANSSON_ATTRS(...)
+#define JANSSON_ATTRS(x)
#endif
/* types */
@@ -191,7 +191,7 @@ static JSON_INLINE enum json_error_code json_error_code(const json_error_t *e) {
void json_object_seed(size_t seed);
size_t json_object_size(const json_t *object);
-json_t *json_object_get(const json_t *object, const char *key) JANSSON_ATTRS(warn_unused_result);
+json_t *json_object_get(const json_t *object, const char *key) JANSSON_ATTRS((warn_unused_result));
int json_object_set_new(json_t *object, const char *key, json_t *value);
int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value);
int json_object_del(json_t *object, const char *key);
@@ -199,6 +199,7 @@ int json_object_clear(json_t *object);
int json_object_update(json_t *object, json_t *other);
int json_object_update_existing(json_t *object, json_t *other);
int json_object_update_missing(json_t *object, json_t *other);
+int json_object_update_recursive(json_t *object, json_t *other);
void *json_object_iter(json_t *object);
void *json_object_iter_at(json_t *object, const char *key);
void *json_object_key_to_iter(const char *key);
@@ -267,7 +268,7 @@ int json_object_update_missing_new(json_t *object, json_t *other)
}
size_t json_array_size(const json_t *array);
-json_t *json_array_get(const json_t *array, size_t index) JANSSON_ATTRS(warn_unused_result);
+json_t *json_array_get(const json_t *array, size_t index) JANSSON_ATTRS((warn_unused_result));
int json_array_set_new(json_t *array, size_t index, json_t *value);
int json_array_append_new(json_t *array, json_t *value);
int json_array_insert_new(json_t *array, size_t index, json_t *value);
@@ -308,9 +309,9 @@ int json_real_set(json_t *real, double value);
/* pack, unpack */
-json_t *json_pack(const char *fmt, ...) JANSSON_ATTRS(warn_unused_result);
-json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) JANSSON_ATTRS(warn_unused_result);
-json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap) JANSSON_ATTRS(warn_unused_result);
+json_t *json_pack(const char *fmt, ...) JANSSON_ATTRS((warn_unused_result));
+json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) JANSSON_ATTRS((warn_unused_result));
+json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap) JANSSON_ATTRS((warn_unused_result));
#define JSON_VALIDATE_ONLY 0x1
#define JSON_STRICT 0x2
@@ -321,8 +322,8 @@ int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char
/* sprintf */
-json_t *json_sprintf(const char *fmt, ...) JANSSON_ATTRS(warn_unused_result, format(printf, 1, 2));
-json_t *json_vsprintf(const char *fmt, va_list ap) JANSSON_ATTRS(warn_unused_result, format(printf, 1, 0));
+json_t *json_sprintf(const char *fmt, ...) JANSSON_ATTRS((warn_unused_result, format(printf, 1, 2)));
+json_t *json_vsprintf(const char *fmt, va_list ap) JANSSON_ATTRS((warn_unused_result, format(printf, 1, 0)));
/* equality */
@@ -332,8 +333,8 @@ int json_equal(const json_t *value1, const json_t *value2);
/* copying */
-json_t *json_copy(json_t *value) JANSSON_ATTRS(warn_unused_result);
-json_t *json_deep_copy(const json_t *value) JANSSON_ATTRS(warn_unused_result);
+json_t *json_copy(json_t *value) JANSSON_ATTRS((warn_unused_result));
+json_t *json_deep_copy(const json_t *value) JANSSON_ATTRS((warn_unused_result));
/* decoding */
@@ -346,12 +347,12 @@ json_t *json_deep_copy(const json_t *value) JANSSON_ATTRS(warn_unused_result);
typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data);
-json_t *json_loads(const char *input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
-json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
-json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
-json_t *json_loadfd(int input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
-json_t *json_load_file(const char *path, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
-json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
+json_t *json_loads(const char *input, size_t flags, json_error_t *error) JANSSON_ATTRS((warn_unused_result));
+json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) JANSSON_ATTRS((warn_unused_result));
+json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) JANSSON_ATTRS((warn_unused_result));
+json_t *json_loadfd(int input, size_t flags, json_error_t *error) JANSSON_ATTRS((warn_unused_result));
+json_t *json_load_file(const char *path, size_t flags, json_error_t *error) JANSSON_ATTRS((warn_unused_result));
+json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error) JANSSON_ATTRS((warn_unused_result));
/* encoding */
@@ -369,7 +370,7 @@ json_t *json_load_callback(json_load_callback_t callback, void *data, size_t fla
typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
-char *json_dumps(const json_t *json, size_t flags) JANSSON_ATTRS(warn_unused_result);
+char *json_dumps(const json_t *json, size_t flags) JANSSON_ATTRS((warn_unused_result));
size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags);
int json_dumpf(const json_t *json, FILE *output, size_t flags);
int json_dumpfd(const json_t *json, int output, size_t flags);
diff --git a/src/jansson_private.h b/src/jansson_private.h
index c7ce11a..42882a8 100644
--- a/src/jansson_private.h
+++ b/src/jansson_private.h
@@ -84,11 +84,11 @@ int jsonp_strtod(strbuffer_t *strbuffer, double *out);
int jsonp_dtostr(char *buffer, size_t size, double value, int prec);
/* Wrappers for custom memory functions */
-void* jsonp_malloc(size_t size) JANSSON_ATTRS(warn_unused_result);
+void* jsonp_malloc(size_t size) JANSSON_ATTRS((warn_unused_result));
void jsonp_free(void *ptr);
-char *jsonp_strndup(const char *str, size_t length) JANSSON_ATTRS(warn_unused_result);
-char *jsonp_strdup(const char *str) JANSSON_ATTRS(warn_unused_result);
-char *jsonp_strndup(const char *str, size_t len) JANSSON_ATTRS(warn_unused_result);
+char *jsonp_strndup(const char *str, size_t length) JANSSON_ATTRS((warn_unused_result));
+char *jsonp_strdup(const char *str) JANSSON_ATTRS((warn_unused_result));
+char *jsonp_strndup(const char *str, size_t len) JANSSON_ATTRS((warn_unused_result));
/* Circular reference check*/
/* Space for "0x", double the sizeof a pointer for the hex and a terminator. */
diff --git a/src/lookup3.h b/src/lookup3.h
index 2fe4c25..7a67e03 100644
--- a/src/lookup3.h
+++ b/src/lookup3.h
@@ -243,7 +243,7 @@ static uint32_t hashlittle(const void *key, size_t length, uint32_t initval)
* rest of the string. Every machine with memory protection I've seen
* does it on word boundaries, so is OK with this. But VALGRIND will
* still catch it and complain. The masking trick does make the hash
- * noticably faster for short strings (like English words).
+ * noticeably faster for short strings (like English words).
*/
#ifndef NO_MASKING_TRICK
diff --git a/src/strbuffer.h b/src/strbuffer.h
index a0276d4..75c02a2 100644
--- a/src/strbuffer.h
+++ b/src/strbuffer.h
@@ -16,7 +16,7 @@ typedef struct {
size_t size; /* bytes allocated */
} strbuffer_t;
-int strbuffer_init(strbuffer_t *strbuff) JANSSON_ATTRS(warn_unused_result);
+int strbuffer_init(strbuffer_t *strbuff) JANSSON_ATTRS((warn_unused_result));
void strbuffer_close(strbuffer_t *strbuff);
void strbuffer_clear(strbuffer_t *strbuff);
diff --git a/src/value.c b/src/value.c
index 7a000f8..e09a485 100644
--- a/src/value.c
+++ b/src/value.c
@@ -37,7 +37,7 @@ static JSON_INLINE int isnan(double x) { return x != x; }
static JSON_INLINE int isinf(double x) { return !isnan(x) && isnan(x - x); }
#endif
-json_t *do_deep_copy(const json_t *, hashtable_t *);
+json_t *do_deep_copy(const json_t *json, hashtable_t *parents);
static JSON_INLINE void json_init(json_t *json, json_type type)
{
@@ -214,6 +214,58 @@ int json_object_update_missing(json_t *object, json_t *other)
return 0;
}
+int do_object_update_recursive(json_t *object, json_t *other, hashtable_t *parents)
+{
+ const char *key;
+ json_t *value;
+ char loop_key[LOOP_KEY_LEN];
+ int res = 0;
+
+ if(!json_is_object(object) || !json_is_object(other))
+ return -1;
+
+ if(jsonp_loop_check(parents, other, loop_key, sizeof(loop_key)))
+ return -1;
+
+ json_object_foreach(other, key, value) {
+ json_t *v = json_object_get(object, key);
+
+ if(json_is_object(v) && json_is_object(value))
+ {
+ if(do_object_update_recursive(v, value, parents))
+ {
+ res = -1;
+ break;
+ }
+ }
+ else
+ {
+ if(json_object_set_nocheck(object, key, value))
+ {
+ res = -1;
+ break;
+ }
+ }
+ }
+
+ hashtable_del(parents, loop_key);
+
+ return res;
+}
+
+int json_object_update_recursive(json_t *object, json_t *other)
+{
+ int res;
+ hashtable_t parents_set;
+
+ if (hashtable_init(&parents_set))
+ return -1;
+ res = do_object_update_recursive(object, other, &parents_set);
+ hashtable_close(&parents_set);
+
+ return res;
+}
+
void *json_object_iter(json_t *json)
{
json_object_t *object;
@@ -329,7 +381,7 @@ static json_t *json_object_deep_copy(const json_t *object, hashtable_t *parents)
result = json_object();
if(!result)
- return NULL;
+ goto out;
/* Cannot use json_object_foreach because object has to be cast
non-const */
@@ -348,6 +400,8 @@ static json_t *json_object_deep_copy(const json_t *object, hashtable_t *parents)
}
iter = json_object_iter_next((json_t *)object, iter);
}
+
+out:
hashtable_del(parents, loop_key);
return result;
@@ -648,7 +702,7 @@ static json_t *json_array_deep_copy(const json_t *array, hashtable_t *parents)
result = json_array();
if(!result)
- return NULL;
+ goto out;
for(i = 0; i < json_array_size(array); i++)
{
@@ -659,6 +713,8 @@ static json_t *json_array_deep_copy(const json_t *array, hashtable_t *parents)
break;
}
}
+
+out:
hashtable_del(parents, loop_key);
return result;
diff --git a/test/suites/api/test_array.c b/test/suites/api/test_array.c
index 9991fa0..a1a0934 100644
--- a/test/suites/api/test_array.c
+++ b/test/suites/api/test_array.c
@@ -186,7 +186,7 @@ static void test_insert(void)
for(i = 0; i < 20; i++) {
if(json_array_insert(array, 0, seven))
- fail("unable to insert value at the begining of an array");
+ fail("unable to insert value at the beginning of an array");
}
for(i = 0; i < 20; i++) {
@@ -479,9 +479,9 @@ static void test_bad_args(void)
if(!json_array_extend(num, arr))
fail("json_array_extend did not return error for first argument non-array");
if(!json_array_extend(arr, NULL))
- fail("json_array_extend did not return error for second arguemnt non-array");
+ fail("json_array_extend did not return error for second argument non-array");
if(!json_array_extend(arr, num))
- fail("json_array_extend did not return error for second arguemnt non-array");
+ fail("json_array_extend did not return error for second argument non-array");
if(num->refcount != 1)
fail("unexpected reference count on num");
diff --git a/test/suites/api/test_dump.c b/test/suites/api/test_dump.c
index cd4af63..c97a105 100644
--- a/test/suites/api/test_dump.c
+++ b/test/suites/api/test_dump.c
@@ -13,6 +13,10 @@
#include
#endif
#include "util.h"
+#ifdef __MINGW32__
+#include
+#define pipe(fds) _pipe(fds, 1024, _O_BINARY)
+#endif
static int encode_null_callback(const char *buffer, size_t size, void *data)
{
diff --git a/test/suites/api/test_equal.c b/test/suites/api/test_equal.c
index 339bab6..ed1023f 100644
--- a/test/suites/api/test_equal.c
+++ b/test/suites/api/test_equal.c
@@ -159,7 +159,7 @@ static void test_equal_object()
static void test_equal_complex()
{
- json_t *value1, *value2;
+ json_t *value1, *value2, *value3;
const char *complex_json =
"{"
@@ -176,15 +176,25 @@ static void test_equal_complex()
value1 = json_loads(complex_json, 0, NULL);
value2 = json_loads(complex_json, 0, NULL);
+ value3 = json_loads(complex_json, 0, NULL);
if(!value1 || !value2)
fail("unable to parse JSON");
if(!json_equal(value1, value2))
- fail("json_equal fails for two inequal strings");
+ fail("json_equal fails for two equal objects");
+
+ json_array_set_new(json_object_get(json_object_get(value2, "object"),
+ "array-in-object"), 1, json_false());
+ if(json_equal(value1, value2))
+ fail("json_equal fails for two inequal objects");
+
+ json_object_set_new(json_object_get(json_object_get(value3, "object"),
+ "object-in-object"), "foo", json_string("baz"));
+ if(json_equal(value1, value3))
+ fail("json_equal fails for two inequal objects");
json_decref(value1);
json_decref(value2);
-
- /* TODO: There's no negative test case here */
+ json_decref(value3);
}
static void run_tests()
diff --git a/test/suites/api/test_object.c b/test/suites/api/test_object.c
index 0d320b3..5112fc7 100644
--- a/test/suites/api/test_object.c
+++ b/test/suites/api/test_object.c
@@ -59,7 +59,7 @@ static void test_update()
/* update an empty object with an empty object */
if(json_object_update(object, other))
- fail("unable to update an emtpy object with an empty object");
+ fail("unable to update an empty object with an empty object");
if(json_object_size(object) != 0)
fail("invalid size after update");
@@ -270,6 +270,86 @@ static void test_conditional_updates()
json_decref(other);
}
+static void test_recursive_updates()
+{
+ json_t *invalid, *object, *other, *barBefore, *barAfter;
+
+ invalid = json_integer(42);
+
+ object = json_pack("{sis{si}}", "foo", 1, "bar", "baz", 2);
+ other = json_pack("{sisisi}", "foo", 3, "bar", 4, "baz", 5);
+
+ if(!json_object_update_recursive(invalid, other))
+ fail("json_object_update_recursive accepted non-object argument");
+
+ json_decref(invalid);
+
+ if(json_object_update_recursive(object, other))
+ fail("json_object_update_recursive failed");
+
+ if(json_object_size(object) != 3)
+ fail("invalid size after update");
+
+ if(json_integer_value(json_object_get(object, "foo")) != 3)
+ fail("json_object_update_recursive failed to update existing key");
+
+ if(json_integer_value(json_object_get(object, "bar")) != 4)
+ fail("json_object_update_recursive failed to overwrite object");
+
+ if(json_integer_value(json_object_get(object, "baz")) != 5)
+ fail("json_object_update_recursive didn't add new item");
+
+ json_decref(object);
+ json_decref(other);
+
+ object = json_pack("{sis{si}}", "foo", 1, "bar", "baz", 2);
+ other = json_pack("{s{si}}", "bar", "baz", 3);
+ barBefore = json_object_get(object, "bar");
+
+ if(!barBefore)
+ fail("can't get bar object before json_object_update_recursive");
+
+ if(json_object_update_recursive(object, other))
+ fail("json_object_update_recursive failed");
+
+ if(json_object_size(object) != 2)
+ fail("invalid size after update");
+
+ if(!json_object_get(object, "foo"))
+ fail("json_object_update_recursive removed existing key");
+
+ if(json_integer_value(json_object_get(json_object_get(object, "bar"), "baz")) != 3)
+ fail("json_object_update_recursive failed to update nested value");
+
+ barAfter = json_object_get(object, "bar");
+ if(!barAfter)
+ fail("can't get bar object after json_object_update_recursive");
+
+ if(barBefore != barAfter)
+ fail("bar object reference changed after json_object_update_recursive");
+
+ json_decref(object);
+ json_decref(other);
+
+ /* check circular reference */
+ object = json_pack("{s{s{s{si}}}}", "foo", "bar", "baz", "xxx", 2);
+ other = json_pack("{s{s{si}}}", "foo", "bar", "baz", 2);
+ json_object_set(json_object_get(json_object_get(other, "foo"), "bar"), "baz",
+ json_object_get(other, "foo"));
+
+ if(!json_object_update_recursive(object, other))
+ fail("json_object_update_recursive update a circular reference!");
+
+ json_object_set_new(json_object_get(json_object_get(other, "foo"), "bar"), "baz",
+ json_integer(1));
+
+ if(json_object_update_recursive(object, other))
+ fail("json_object_update_recursive failed!");
+
+ json_decref(object);
+ json_decref(other);
+}
+
static void test_circular()
{
json_t *object1, *object2;
@@ -730,6 +810,7 @@ static void run_tests()
test_update();
test_set_many_keys();
test_conditional_updates();
+ test_recursive_updates();
test_circular();
test_set_nocheck();
test_iterators();