mirror of https://github.com/GOSTSec/sgminer
Con Kolivas
11 years ago
289 changed files with 17848 additions and 151 deletions
@ -0,0 +1,554 @@
@@ -0,0 +1,554 @@
|
||||
Version 2.5 |
||||
=========== |
||||
|
||||
Released 2013-09-19 |
||||
|
||||
* New features: |
||||
|
||||
- `json_pack()` and friends: Add format specifiers ``s#``, ``+`` and |
||||
``+#``. |
||||
|
||||
- Add ``JSON_DECODE_INT_AS_REAL`` decoding flag to treat all numbers |
||||
as real in the decoder (#123). |
||||
|
||||
- Add `json_array_foreach()`, paralleling `json_object_foreach()` |
||||
(#118). |
||||
|
||||
* Bug fixes: |
||||
|
||||
- `json_dumps()` and friends: Don't crash if json is *NULL* and |
||||
``JSON_ENCODE_ANY`` is set. |
||||
|
||||
- Fix a theoretical integer overflow in `jsonp_strdup()`. |
||||
|
||||
- Fix `l_isxdigit()` macro (#97). |
||||
|
||||
- Fix an off-by-one error in `json_array_remove()`. |
||||
|
||||
* Build: |
||||
|
||||
- Support CMake in addition to GNU Autotools (#106, #107, #112, |
||||
#115, #120, #127). |
||||
|
||||
- Support building for Android (#109). |
||||
|
||||
- Don't use ``-Werror`` by default. |
||||
|
||||
- Support building and testing with VPATH (#93). |
||||
|
||||
- Fix compilation when ``NDEBUG`` is defined (#128) |
||||
|
||||
* Tests: |
||||
|
||||
- Fix a refleak in ``test/bin/json_process.c``. |
||||
|
||||
* Documentation: |
||||
|
||||
- Clarify the return value of `json_load_callback_t`. |
||||
|
||||
- Document how to circumvent problems with separate heaps on Windows. |
||||
|
||||
- Fix memory leaks and warnings in ``github_commits.c``. |
||||
|
||||
- Use `json_decref()` properly in tutorial. |
||||
|
||||
* Other: |
||||
|
||||
- Make it possible to forward declare ``struct json_t``. |
||||
|
||||
|
||||
Version 2.4 |
||||
=========== |
||||
|
||||
Released 2012-09-23 |
||||
|
||||
* New features: |
||||
|
||||
- Add `json_boolean()` macro that returns the JSON true or false |
||||
value based on its argument (#86). |
||||
|
||||
- Add `json_load_callback()` that calls a callback function |
||||
repeatedly to read the JSON input (#57). |
||||
|
||||
- Add JSON_ESCAPE_SLASH encoding flag to escape all occurences of |
||||
``/`` with ``\/``. |
||||
|
||||
* Bug fixes: |
||||
|
||||
- Check for and reject NaN and Inf values for reals. Encoding these |
||||
values resulted in invalid JSON. |
||||
|
||||
- Fix `json_real_set()` to return -1 on error. |
||||
|
||||
* Build: |
||||
|
||||
- Jansson now builds on Windows with Visual Studio 2010, and |
||||
includes solution and project files in ``win32/vs2010/`` |
||||
directory. |
||||
|
||||
- Fix build warnings (#77, #78). |
||||
|
||||
- Add ``-no-undefined`` to LDFLAGS (#90). |
||||
|
||||
* Tests: |
||||
|
||||
- Fix the symbol exports test on Linux/PPC64 (#88). |
||||
|
||||
* Documentation: |
||||
|
||||
- Fix typos (#73, #84). |
||||
|
||||
|
||||
Version 2.3.1 |
||||
============= |
||||
|
||||
Released 2012-04-20 |
||||
|
||||
* Build issues: |
||||
|
||||
- Only use ``long long`` if ``strtoll()`` is also available. |
||||
|
||||
* Documentation: |
||||
|
||||
- Fix the names of library version constants in documentation. (#52) |
||||
|
||||
- Change the tutorial to use GitHub API v3. (#65) |
||||
|
||||
* Tests: |
||||
|
||||
- Make some tests locale independent. (#51) |
||||
|
||||
- Distribute the library exports test in the tarball. |
||||
|
||||
- Make test run on shells that don't support the ``export FOO=bar`` |
||||
syntax. |
||||
|
||||
|
||||
Version 2.3 |
||||
=========== |
||||
|
||||
Released 2012-01-27 |
||||
|
||||
* New features: |
||||
|
||||
- `json_unpack()` and friends: Add support for optional object keys |
||||
with the ``{s?o}`` syntax. |
||||
|
||||
- Add `json_object_update_existing()` and |
||||
`json_object_update_missing()`, for updating only existing keys or |
||||
only adding missing keys to an object. (#37) |
||||
|
||||
- Add `json_object_foreach()` for more convenient iteration over |
||||
objects. (#45, #46) |
||||
|
||||
- When decoding JSON, write the number of bytes that were read from |
||||
input to ``error.position`` also on success. This is handy with |
||||
``JSON_DISABLE_EOF_CHECK``. |
||||
|
||||
- Add support for decoding any JSON value, not just arrays or |
||||
objects. The support is enabled with the new ``JSON_DECODE_ANY`` |
||||
flag. Patch by Andrea Marchesini. (#4) |
||||
|
||||
* Bug fixes |
||||
|
||||
- Avoid problems with object's serial number growing too big. (#40, |
||||
#41) |
||||
|
||||
- Decoding functions now return NULL if the first argument is NULL. |
||||
Patch by Andrea Marchesini. |
||||
|
||||
- Include ``jansson_config.h.win32`` in the distribution tarball. |
||||
|
||||
- Remove ``+`` and leading zeros from exponents in the encoder. |
||||
(#39) |
||||
|
||||
- Make Jansson build and work on MinGW. (#39, #38) |
||||
|
||||
* Documentation |
||||
|
||||
- Note that the same JSON values must not be encoded in parallel by |
||||
separate threads. (#42) |
||||
|
||||
- Document MinGW support. |
||||
|
||||
|
||||
Version 2.2.1 |
||||
============= |
||||
|
||||
Released 2011-10-06 |
||||
|
||||
* Bug fixes: |
||||
|
||||
- Fix real number encoding and decoding under non-C locales. (#32) |
||||
|
||||
- Fix identifier decoding under non-UTF-8 locales. (#35) |
||||
|
||||
- `json_load_file()`: Open the input file in binary mode for maximum |
||||
compatiblity. |
||||
|
||||
* Documentation: |
||||
|
||||
- Clarify the lifecycle of the result of the ``s`` fromat of |
||||
`json_unpack()`. (#31) |
||||
|
||||
- Add some portability info. (#36) |
||||
|
||||
- Little clarifications here and there. |
||||
|
||||
* Other: |
||||
|
||||
- Some style fixes, issues detected by static analyzers. |
||||
|
||||
|
||||
Version 2.2 |
||||
=========== |
||||
|
||||
Released 2011-09-03 |
||||
|
||||
* New features: |
||||
|
||||
- `json_dump_callback()`: Pass the encoder output to a callback |
||||
function in chunks. |
||||
|
||||
* Bug fixes: |
||||
|
||||
- `json_string_set()`: Check that target is a string and value is |
||||
not NULL. |
||||
|
||||
* Other: |
||||
|
||||
- Documentation typo fixes and clarifications. |
||||
|
||||
|
||||
Version 2.1 |
||||
=========== |
||||
|
||||
Released 2011-06-10 |
||||
|
||||
* New features: |
||||
|
||||
- `json_loadb()`: Decode a string with a given size, useful if the |
||||
string is not null terminated. |
||||
|
||||
- Add ``JSON_ENCODE_ANY`` encoding flag to allow encoding any JSON |
||||
value. By default, only arrays and objects can be encoded. (#19) |
||||
|
||||
- Add ``JSON_REJECT_DUPLICATES`` decoding flag to issue a decoding |
||||
error if any JSON object in the input contins duplicate keys. (#3) |
||||
|
||||
- Add ``JSON_DISABLE_EOF_CHECK`` decoding flag to stop decoding after a |
||||
valid JSON input. This allows other data after the JSON data. |
||||
|
||||
* Bug fixes: |
||||
|
||||
- Fix an additional memory leak when memory allocation fails in |
||||
`json_object_set()` and friends. |
||||
|
||||
- Clear errno before calling `strtod()` for better portability. (#27) |
||||
|
||||
* Building: |
||||
|
||||
- Avoid set-but-not-used warning/error in a test. (#20) |
||||
|
||||
* Other: |
||||
|
||||
- Minor clarifications to documentation. |
||||
|
||||
|
||||
Version 2.0.1 |
||||
============= |
||||
|
||||
Released 2011-03-31 |
||||
|
||||
* Bug fixes: |
||||
|
||||
- Replace a few `malloc()` and `free()` calls with their |
||||
counterparts that support custom memory management. |
||||
|
||||
- Fix object key hashing in json_unpack() strict checking mode. |
||||
|
||||
- Fix the parentheses in ``JANSSON_VERSION_HEX`` macro. |
||||
|
||||
- Fix `json_object_size()` return value. |
||||
|
||||
- Fix a few compilation issues. |
||||
|
||||
* Portability: |
||||
|
||||
- Enhance portability of `va_copy()`. |
||||
|
||||
- Test framework portability enhancements. |
||||
|
||||
* Documentation: |
||||
|
||||
- Distribute ``doc/upgrading.rst`` with the source tarball. |
||||
|
||||
- Build documentation in strict mode in ``make distcheck``. |
||||
|
||||
|
||||
Version 2.0 |
||||
=========== |
||||
|
||||
Released 2011-02-28 |
||||
|
||||
This release is backwards incompatible with the 1.x release series. |
||||
See the chapter "Upgrading from older versions" in documentation for |
||||
details. |
||||
|
||||
* Backwards incompatible changes: |
||||
|
||||
- Unify unsigned integer usage in the API: All occurences of |
||||
unsigned int and unsigned long have been replaced with size_t. |
||||
|
||||
- Change JSON integer's underlying type to the widest signed integer |
||||
type available, i.e. long long if it's supported, otherwise long. |
||||
Add a typedef json_int_t that defines the type. |
||||
|
||||
- Change the maximum indentation depth to 31 spaces in encoder. This |
||||
frees up bits from the flags parameter of encoding functions |
||||
`json_dumpf()`, `json_dumps()` and `json_dump_file()`. |
||||
|
||||
- For future needs, add a flags parameter to all decoding functions |
||||
`json_loadf()`, `json_loads()` and `json_load_file()`. |
||||
|
||||
* New features |
||||
|
||||
- `json_pack()`, `json_pack_ex()`, `json_vpack_ex()`: Create JSON |
||||
values based on a format string. |
||||
|
||||
- `json_unpack()`, `json_unpack_ex()`, `json_vunpack_ex()`: Simple |
||||
value extraction and validation functionality based on a format |
||||
string. |
||||
|
||||
- Add column, position and source fields to the ``json_error_t`` |
||||
struct. |
||||
|
||||
- Enhance error reporting in the decoder. |
||||
|
||||
- ``JANSSON_VERSION`` et al.: Preprocessor constants that define the |
||||
library version. |
||||
|
||||
- `json_set_alloc_funcs()`: Set custom memory allocation functions. |
||||
|
||||
* Fix many portability issues, especially on Windows. |
||||
|
||||
* Configuration |
||||
|
||||
- Add file ``jansson_config.h`` that contains site specific |
||||
configuration. It's created automatically by the configure script, |
||||
or can be created by hand if the configure script cannot be used. |
||||
The file ``jansson_config.h.win32`` can be used without |
||||
modifications on Windows systems. |
||||
|
||||
- Add a section to documentation describing how to build Jansson on |
||||
Windows. |
||||
|
||||
- Documentation now requires Sphinx 1.0 or newer. |
||||
|
||||
|
||||
Version 1.3 |
||||
=========== |
||||
|
||||
Released 2010-06-13 |
||||
|
||||
* New functions: |
||||
|
||||
- `json_object_iter_set()`, `json_object_iter_set_new()`: Change |
||||
object contents while iterating over it. |
||||
|
||||
- `json_object_iter_at()`: Return an iterator that points to a |
||||
specific object item. |
||||
|
||||
* New encoding flags: |
||||
|
||||
- ``JSON_PRESERVE_ORDER``: Preserve the insertion order of object |
||||
keys. |
||||
|
||||
* Bug fixes: |
||||
|
||||
- Fix an error that occured when an array or object was first |
||||
encoded as empty, then populated with some data, and then |
||||
re-encoded |
||||
|
||||
- Fix the situation like above, but when the first encoding resulted |
||||
in an error |
||||
|
||||
* Documentation: |
||||
|
||||
- Clarify the documentation on reference stealing, providing an |
||||
example usage pattern |
||||
|
||||
|
||||
Version 1.2.1 |
||||
============= |
||||
|
||||
Released 2010-04-03 |
||||
|
||||
* Bug fixes: |
||||
|
||||
- Fix reference counting on ``true``, ``false`` and ``null`` |
||||
- Estimate real number underflows in decoder with 0.0 instead of |
||||
issuing an error |
||||
|
||||
* Portability: |
||||
|
||||
- Make ``int32_t`` available on all systems |
||||
- Support compilers that don't have the ``inline`` keyword |
||||
- Require Autoconf 2.60 (for ``int32_t``) |
||||
|
||||
* Tests: |
||||
|
||||
- Print test names correctly when ``VERBOSE=1`` |
||||
- ``test/suites/api``: Fail when a test fails |
||||
- Enhance tests for iterators |
||||
- Enhance tests for decoding texts that contain null bytes |
||||
|
||||
* Documentation: |
||||
|
||||
- Don't remove ``changes.rst`` in ``make clean`` |
||||
- Add a chapter on RFC conformance |
||||
|
||||
|
||||
Version 1.2 |
||||
=========== |
||||
|
||||
Released 2010-01-21 |
||||
|
||||
* New functions: |
||||
|
||||
- `json_equal()`: Test whether two JSON values are equal |
||||
- `json_copy()` and `json_deep_copy()`: Make shallow and deep copies |
||||
of JSON values |
||||
- Add a version of all functions taking a string argument that |
||||
doesn't check for valid UTF-8: `json_string_nocheck()`, |
||||
`json_string_set_nocheck()`, `json_object_set_nocheck()`, |
||||
`json_object_set_new_nocheck()` |
||||
|
||||
* New encoding flags: |
||||
|
||||
- ``JSON_SORT_KEYS``: Sort objects by key |
||||
- ``JSON_ENSURE_ASCII``: Escape all non-ASCII Unicode characters |
||||
- ``JSON_COMPACT``: Use a compact representation with all unneeded |
||||
whitespace stripped |
||||
|
||||
* Bug fixes: |
||||
|
||||
- Revise and unify whitespace usage in encoder: Add spaces between |
||||
array and object items, never append newline to output. |
||||
- Remove const qualifier from the ``json_t`` parameter in |
||||
`json_string_set()`, `json_integer_set()` and `json_real_set`. |
||||
- Use ``int32_t`` internally for representing Unicode code points |
||||
(int is not enough on all platforms) |
||||
|
||||
* Other changes: |
||||
|
||||
- Convert ``CHANGES`` (this file) to reStructured text and add it to |
||||
HTML documentation |
||||
- The test system has been refactored. Python is no longer required |
||||
to run the tests. |
||||
- Documentation can now be built by invoking ``make html`` |
||||
- Support for pkg-config |
||||
|
||||
|
||||
Version 1.1.3 |
||||
============= |
||||
|
||||
Released 2009-12-18 |
||||
|
||||
* Encode reals correctly, so that first encoding and then decoding a |
||||
real always produces the same value |
||||
* Don't export private symbols in ``libjansson.so`` |
||||
|
||||
|
||||
Version 1.1.2 |
||||
============= |
||||
|
||||
Released 2009-11-08 |
||||
|
||||
* Fix a bug where an error message was not produced if the input file |
||||
could not be opened in `json_load_file()` |
||||
* Fix an assertion failure in decoder caused by a minus sign without a |
||||
digit after it |
||||
* Remove an unneeded include of ``stdint.h`` in ``jansson.h`` |
||||
|
||||
|
||||
Version 1.1.1 |
||||
============= |
||||
|
||||
Released 2009-10-26 |
||||
|
||||
* All documentation files were not distributed with v1.1; build |
||||
documentation in make distcheck to prevent this in the future |
||||
* Fix v1.1 release date in ``CHANGES`` |
||||
|
||||
|
||||
Version 1.1 |
||||
=========== |
||||
|
||||
Released 2009-10-20 |
||||
|
||||
* API additions and improvements: |
||||
|
||||
- Extend array and object APIs |
||||
- Add functions to modify integer, real and string values |
||||
- Improve argument validation |
||||
- Use unsigned int instead of ``uint32_t`` for encoding flags |
||||
|
||||
* Enhance documentation |
||||
|
||||
- Add getting started guide and tutorial |
||||
- Fix some typos |
||||
- General clarifications and cleanup |
||||
|
||||
* Check for integer and real overflows and underflows in decoder |
||||
* Make singleton values thread-safe (``true``, ``false`` and ``null``) |
||||
* Enhance circular reference handling |
||||
* Don't define ``-std=c99`` in ``AM_CFLAGS`` |
||||
* Add C++ guards to ``jansson.h`` |
||||
* Minor performance and portability improvements |
||||
* Expand test coverage |
||||
|
||||
|
||||
Version 1.0.4 |
||||
============= |
||||
|
||||
Released 2009-10-11 |
||||
|
||||
* Relax Autoconf version requirement to 2.59 |
||||
* Make Jansson compile on platforms where plain ``char`` is unsigned |
||||
* Fix API tests for object |
||||
|
||||
|
||||
Version 1.0.3 |
||||
============= |
||||
|
||||
Released 2009-09-14 |
||||
|
||||
* Check for integer and real overflows and underflows in decoder |
||||
* Use the Python json module for tests, or simplejson if the json |
||||
module is not found |
||||
* Distribute changelog (this file) |
||||
|
||||
|
||||
Version 1.0.2 |
||||
============= |
||||
|
||||
Released 2009-09-08 |
||||
|
||||
* Handle EOF correctly in decoder |
||||
|
||||
|
||||
Version 1.0.1 |
||||
============= |
||||
|
||||
Released 2009-09-04 |
||||
|
||||
* Fixed broken `json_is_boolean()` |
||||
|
||||
|
||||
Version 1.0 |
||||
=========== |
||||
|
||||
Released 2009-08-25 |
||||
|
||||
* Initial release |
@ -1,4 +1,4 @@
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org> |
||||
Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
EXTRA_DIST = CHANGES LICENSE README.rst win32 |
||||
SUBDIRS = doc src test |
||||
|
||||
# "make distcheck" builds the dvi target, so use it to check that the
|
||||
# documentation is built correctly.
|
||||
dvi: |
||||
$(MAKE) SPHINXOPTS_EXTRA=-W html |
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig |
||||
pkgconfig_DATA = jansson.pc |
||||
|
||||
if GCC |
||||
# These flags are gcc specific
|
||||
export AM_CFLAGS = -Wall -Wextra -Wdeclaration-after-statement |
||||
endif |
@ -0,0 +1,63 @@
@@ -0,0 +1,63 @@
|
||||
Jansson README |
||||
============== |
||||
|
||||
.. image:: https://travis-ci.org/akheron/jansson.png |
||||
:alt: Build status |
||||
:target: https://travis-ci.org/akheron/jansson |
||||
|
||||
Jansson_ is a C library for encoding, decoding and manipulating JSON |
||||
data. Its main features and design principles are: |
||||
|
||||
- Simple and intuitive API and data model |
||||
|
||||
- Comprehensive documentation |
||||
|
||||
- No dependencies on other libraries |
||||
|
||||
- Full Unicode support (UTF-8) |
||||
|
||||
- Extensive test suite |
||||
|
||||
Jansson is licensed under the `MIT license`_; see LICENSE in the |
||||
source distribution for details. |
||||
|
||||
|
||||
Compilation and Installation |
||||
---------------------------- |
||||
|
||||
If you obtained a source tarball, just use the standard autotools |
||||
commands:: |
||||
|
||||
$ ./configure |
||||
$ make |
||||
$ make install |
||||
|
||||
To run the test suite, invoke:: |
||||
|
||||
$ make check |
||||
|
||||
If the source has been checked out from a Git repository, the |
||||
./configure script has to be generated first. The easiest way is to |
||||
use autoreconf:: |
||||
|
||||
$ autoreconf -i |
||||
|
||||
|
||||
Documentation |
||||
------------- |
||||
|
||||
Prebuilt HTML documentation is available at |
||||
http://www.digip.org/jansson/doc/. |
||||
|
||||
The documentation source is in the ``doc/`` subdirectory. To generate |
||||
HTML documentation, invoke:: |
||||
|
||||
$ make html |
||||
|
||||
Then, point your browser to ``doc/_build/html/index.html``. Sphinx_ |
||||
1.0 or newer is required to generate the documentation. |
||||
|
||||
|
||||
.. _Jansson: http://www.digip.org/jansson/ |
||||
.. _`MIT license`: http://www.opensource.org/licenses/mit-license.php |
||||
.. _Sphinx: http://sphinx.pocoo.org/ |
@ -0,0 +1,57 @@
@@ -0,0 +1,57 @@
|
||||
AC_PREREQ([2.60]) |
||||
AC_INIT([jansson], [2.5], [petri@digip.org]) |
||||
|
||||
AM_INIT_AUTOMAKE([1.10 foreign]) |
||||
|
||||
AC_CONFIG_SRCDIR([src/value.c]) |
||||
AC_CONFIG_HEADERS([config.h]) |
||||
|
||||
# Checks for programs. |
||||
AC_PROG_CC |
||||
AC_PROG_LIBTOOL |
||||
AM_CONDITIONAL([GCC], [test x$GCC = xyes]) |
||||
|
||||
# Checks for libraries. |
||||
|
||||
# Checks for header files. |
||||
AC_CHECK_HEADERS([locale.h]) |
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics. |
||||
AC_TYPE_INT32_T |
||||
AC_TYPE_LONG_LONG_INT |
||||
|
||||
AC_C_INLINE |
||||
case $ac_cv_c_inline in |
||||
yes) json_inline=inline;; |
||||
no) json_inline=;; |
||||
*) json_inline=$ac_cv_c_inline;; |
||||
esac |
||||
AC_SUBST([json_inline]) |
||||
|
||||
# Checks for library functions. |
||||
AC_CHECK_FUNCS([strtoll localeconv]) |
||||
|
||||
case "$ac_cv_type_long_long_int$ac_cv_func_strtoll" in |
||||
yesyes) json_have_long_long=1;; |
||||
*) json_have_long_long=0;; |
||||
esac |
||||
AC_SUBST([json_have_long_long]) |
||||
|
||||
case "$ac_cv_header_locale_h$ac_cv_func_localeconv" in |
||||
yesyes) json_have_localeconv=1;; |
||||
*) json_have_localeconv=0;; |
||||
esac |
||||
AC_SUBST([json_have_localeconv]) |
||||
|
||||
AC_CONFIG_FILES([ |
||||
jansson.pc |
||||
Makefile |
||||
doc/Makefile |
||||
src/Makefile |
||||
src/jansson_config.h |
||||
test/Makefile |
||||
test/bin/Makefile |
||||
test/suites/Makefile |
||||
test/suites/api/Makefile |
||||
]) |
||||
AC_OUTPUT |
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
EXTRA_DIST = conf.py apiref.rst changes.rst conformance.rst \
|
||||
gettingstarted.rst github_commits.c index.rst portability.rst \
|
||||
tutorial.rst upgrading.rst ext/refcounting.py |
||||
|
||||
SPHINXBUILD = sphinx-build |
||||
SPHINXOPTS = -d _build/doctrees $(SPHINXOPTS_EXTRA) |
||||
|
||||
html-local: |
||||
$(SPHINXBUILD) -b html $(SPHINXOPTS) $(srcdir) _build/html |
||||
|
||||
install-html-local: html |
||||
mkdir -p $(DESTDIR)$(htmldir) |
||||
cp -r _build/html $(DESTDIR)$(htmldir) |
||||
|
||||
uninstall-local: |
||||
rm -rf $(DESTDIR)$(htmldir) |
||||
|
||||
clean-local: |
||||
rm -rf _build |
||||
rm -f ext/refcounting.pyc |
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
To build the documentation, invoke |
||||
|
||||
make html |
||||
|
||||
Then point your browser to _build/html/index.html. |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
****************** |
||||
Changes in Jansson |
||||
****************** |
||||
|
||||
.. include:: ../CHANGES |
@ -0,0 +1,217 @@
@@ -0,0 +1,217 @@
|
||||
# -*- coding: utf-8 -*- |
||||
# |
||||
# Jansson documentation build configuration file, created by |
||||
# sphinx-quickstart on Sun Sep 5 21:47:20 2010. |
||||
# |
||||
# This file is execfile()d with the current directory set to its containing dir. |
||||
# |
||||
# Note that not all possible configuration values are present in this |
||||
# autogenerated file. |
||||
# |
||||
# All configuration values have a default; values that are commented out |
||||
# serve to show the default. |
||||
|
||||
import sys, os |
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory, |
||||
# add these directories to sys.path here. If the directory is relative to the |
||||
# documentation root, use os.path.abspath to make it absolute, like shown here. |
||||
sys.path.insert(0, os.path.abspath('ext')) |
||||
|
||||
# -- General configuration ----------------------------------------------------- |
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here. |
||||
needs_sphinx = '1.0' |
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions |
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. |
||||
extensions = ['refcounting'] |
||||
|
||||
# Add any paths that contain templates here, relative to this directory. |
||||
templates_path = ['_templates'] |
||||
|
||||
# The suffix of source filenames. |
||||
source_suffix = '.rst' |
||||
|
||||
# The encoding of source files. |
||||
#source_encoding = 'utf-8-sig' |
||||
|
||||
# The master toctree document. |
||||
master_doc = 'index' |
||||
|
||||
# General information about the project. |
||||
project = u'Jansson' |
||||
copyright = u'2009-2013, Petri Lehtinen' |
||||
|
||||
# The version info for the project you're documenting, acts as replacement for |
||||
# |version| and |release|, also used in various other places throughout the |
||||
# built documents. |
||||
# |
||||
# The short X.Y version. |
||||
version = '2.5' |
||||
# The full version, including alpha/beta/rc tags. |
||||
release = version |
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation |
||||
# for a list of supported languages. |
||||
#language = None |
||||
|
||||
# There are two options for replacing |today|: either, you set today to some |
||||
# non-false value, then it is used: |
||||
#today = '' |
||||
# Else, today_fmt is used as the format for a strftime call. |
||||
#today_fmt = '%B %d, %Y' |
||||
|
||||
# List of patterns, relative to source directory, that match files and |
||||
# directories to ignore when looking for source files. |
||||
exclude_patterns = ['_build'] |
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents. |
||||
default_role = 'c:func' |
||||
primary_domain = 'c' |
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text. |
||||
#add_function_parentheses = True |
||||
|
||||
# If true, the current module name will be prepended to all description |
||||
# unit titles (such as .. function::). |
||||
#add_module_names = True |
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the |
||||
# output. They are ignored by default. |
||||
#show_authors = False |
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use. |
||||
pygments_style = 'sphinx' |
||||
|
||||
# A list of ignored prefixes for module index sorting. |
||||
#modindex_common_prefix = [] |
||||
|
||||
|
||||
# -- Options for HTML output --------------------------------------------------- |
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for |
||||
# a list of builtin themes. |
||||
#html_theme = 'default' |
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme |
||||
# further. For a list of options available for each theme, see the |
||||
# documentation. |
||||
#html_theme_options = {} |
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory. |
||||
#html_theme_path = [] |
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to |
||||
# "<project> v<release> documentation". |
||||
#html_title = None |
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title. |
||||
#html_short_title = None |
||||
|
||||
# The name of an image file (relative to this directory) to place at the top |
||||
# of the sidebar. |
||||
#html_logo = None |
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the |
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 |
||||
# pixels large. |
||||
#html_favicon = None |
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here, |
||||
# relative to this directory. They are copied after the builtin static files, |
||||
# so a file named "default.css" will overwrite the builtin "default.css". |
||||
#html_static_path = ['_static'] |
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, |
||||
# using the given strftime format. |
||||
#html_last_updated_fmt = '%b %d, %Y' |
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to |
||||
# typographically correct entities. |
||||
#html_use_smartypants = True |
||||
|
||||
# Custom sidebar templates, maps document names to template names. |
||||
#html_sidebars = {} |
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to |
||||
# template names. |
||||
#html_additional_pages = {} |
||||
|
||||
# If false, no module index is generated. |
||||
#html_domain_indices = True |
||||
|
||||
# If false, no index is generated. |
||||
#html_use_index = True |
||||
|
||||
# If true, the index is split into individual pages for each letter. |
||||
#html_split_index = False |
||||
|
||||
# If true, links to the reST sources are added to the pages. |
||||
#html_show_sourcelink = True |
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. |
||||
#html_show_sphinx = True |
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. |
||||
#html_show_copyright = True |
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will |
||||
# contain a <link> tag referring to it. The value of this option must be the |
||||
# base URL from which the finished HTML is served. |
||||
#html_use_opensearch = '' |
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml"). |
||||
#html_file_suffix = None |
||||
|
||||
# Output file base name for HTML help builder. |
||||
htmlhelp_basename = 'Janssondoc' |
||||
|
||||
|
||||
# -- Options for LaTeX output -------------------------------------------------- |
||||
|
||||
# The paper size ('letter' or 'a4'). |
||||
#latex_paper_size = 'letter' |
||||
|
||||
# The font size ('10pt', '11pt' or '12pt'). |
||||
#latex_font_size = '10pt' |
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples |
||||
# (source start file, target name, title, author, documentclass [howto/manual]). |
||||
latex_documents = [ |
||||
('index', 'Jansson.tex', u'Jansson Documentation', |
||||
u'Petri Lehtinen', 'manual'), |
||||
] |
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of |
||||
# the title page. |
||||
#latex_logo = None |
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts, |
||||
# not chapters. |
||||
#latex_use_parts = False |
||||
|
||||
# If true, show page references after internal links. |
||||
#latex_show_pagerefs = False |
||||
|
||||
# If true, show URL addresses after external links. |
||||
#latex_show_urls = False |
||||
|
||||
# Additional stuff for the LaTeX preamble. |
||||
#latex_preamble = '' |
||||
|
||||
# Documents to append as an appendix to all manuals. |
||||
#latex_appendices = [] |
||||
|
||||
# If false, no module index is generated. |
||||
#latex_domain_indices = True |
||||
|
||||
|
||||
# -- Options for manual page output -------------------------------------------- |
||||
|
||||
# One entry per manual page. List of tuples |
||||
# (source start file, name, description, authors, manual section). |
||||
man_pages = [ |
||||
('index', 'jansson', u'Jansson Documentation', |
||||
[u'Petri Lehtinen'], 1) |
||||
] |
@ -0,0 +1,114 @@
@@ -0,0 +1,114 @@
|
||||
.. _rfc-conformance: |
||||
|
||||
*************** |
||||
RFC Conformance |
||||
*************** |
||||
|
||||
JSON is specified in :rfc:`4627`, *"The application/json Media Type |
||||
for JavaScript Object Notation (JSON)"*. |
||||
|
||||
Character Encoding |
||||
================== |
||||
|
||||
Jansson only supports UTF-8 encoded JSON texts. It does not support or |
||||
auto-detect any of the other encodings mentioned in the RFC, namely |
||||
UTF-16LE, UTF-16BE, UTF-32LE or UTF-32BE. Pure ASCII is supported, as |
||||
it's a subset of UTF-8. |
||||
|
||||
Strings |
||||
======= |
||||
|
||||
JSON strings are mapped to C-style null-terminated character arrays, |
||||
and UTF-8 encoding is used internally. Strings may not contain |
||||
embedded null characters, not even escaped ones. |
||||
|
||||
For example, trying to decode the following JSON text leads to a parse |
||||
error:: |
||||
|
||||
["this string contains the null character: \u0000"] |
||||
|
||||
All other Unicode codepoints U+0001 through U+10FFFF are allowed. |
||||
|
||||
Unicode normalization or any other transformation is never performed |
||||
on any strings (string values or object keys). When checking for |
||||
equivalence of strings or object keys, the comparison is performed |
||||
byte by byte between the original UTF-8 representations of the |
||||
strings. |
||||
|
||||
Numbers |
||||
======= |
||||
|
||||
.. _real-vs-integer: |
||||
|
||||
Real vs. Integer |
||||
---------------- |
||||
|
||||
JSON makes no distinction between real and integer numbers; Jansson |
||||
does. Real numbers are mapped to the ``double`` type and integers to |
||||
the ``json_int_t`` type, which is a typedef of ``long long`` or |
||||
``long``, depending on whether ``long long`` is supported by your |
||||
compiler or not. |
||||
|
||||
A JSON number is considered to be a real number if its lexical |
||||
representation includes one of ``e``, ``E``, or ``.``; regardless if |
||||
its actual numeric value is a true integer (e.g., all of ``1E6``, |
||||
``3.0``, ``400E-2``, and ``3.14E3`` are mathematical integers, but |
||||
will be treated as real values). With the ``JSON_DECODE_INT_AS_REAL`` |
||||
decoder flag set all numbers are interpreted as real. |
||||
|
||||
All other JSON numbers are considered integers. |
||||
|
||||
When encoding to JSON, real values are always represented |
||||
with a fractional part; e.g., the ``double`` value 3.0 will be |
||||
represented in JSON as ``3.0``, not ``3``. |
||||
|
||||
Overflow, Underflow & Precision |
||||
------------------------------- |
||||
|
||||
Real numbers whose absolute values are too small to be represented in |
||||
a C ``double`` will be silently estimated with 0.0. Thus, depending on |
||||
platform, JSON numbers very close to zero such as 1E-999 may result in |
||||
0.0. |
||||
|
||||
Real numbers whose absolute values are too large to be represented in |
||||
a C ``double`` will result in an overflow error (a JSON decoding |
||||
error). Thus, depending on platform, JSON numbers like 1E+999 or |
||||
-1E+999 may result in a parsing error. |
||||
|
||||
Likewise, integer numbers whose absolute values are too large to be |
||||
represented in the ``json_int_t`` type (see above) will result in an |
||||
overflow error (a JSON decoding error). Thus, depending on platform, |
||||
JSON numbers like 1000000000000000 may result in parsing error. |
||||
|
||||
Parsing JSON real numbers may result in a loss of precision. As long |
||||
as overflow does not occur (i.e. a total loss of precision), the |
||||
rounded approximate value is silently used. Thus the JSON number |
||||
1.000000000000000005 may, depending on platform, result in the |
||||
``double`` value 1.0. |
||||
|
||||
Signed zeros |
||||
------------ |
||||
|
||||
JSON makes no statement about what a number means; however Javascript |
||||
(ECMAscript) does state that +0.0 and -0.0 must be treated as being |
||||
distinct values, i.e. -0.0 |not-equal| 0.0. Jansson relies on the |
||||
underlying floating point library in the C environment in which it is |
||||
compiled. Therefore it is platform-dependent whether 0.0 and -0.0 will |
||||
be distinct values. Most platforms that use the IEEE 754 |
||||
floating-point standard will support signed zeros. |
||||
|
||||
Note that this only applies to floating-point; neither JSON, C, or |
||||
IEEE support the concept of signed integer zeros. |
||||
|
||||
.. |not-equal| unicode:: U+2260 |
||||
|
||||
Types |
||||
----- |
||||
|
||||
No support is provided in Jansson for any C numeric types other than |
||||
``json_int_t`` and ``double``. This excludes things such as unsigned |
||||
types, ``long double``, etc. Obviously, shorter types like ``short``, |
||||
``int``, ``long`` (if ``json_int_t`` is ``long long``) and ``float`` |
||||
are implicitly handled via the ordinary C type coercion rules (subject |
||||
to overflow semantics). Also, no support or hooks are provided for any |
||||
supplemental "bignum" type add-on packages. |
@ -0,0 +1,59 @@
@@ -0,0 +1,59 @@
|
||||
""" |
||||
refcounting |
||||
~~~~~~~~~~~ |
||||
|
||||
Reference count annotations for C API functions. Has the same |
||||
result as the sphinx.ext.refcounting extension but works for all |
||||
functions regardless of the signature, and the reference counting |
||||
information is written inline with the documentation instead of a |
||||
separate file. |
||||
|
||||
Adds a new directive "refcounting". The directive has no content |
||||
and one required positional parameter:: "new" or "borrow". |
||||
|
||||
Example: |
||||
|
||||
.. cfunction:: json_t *json_object(void) |
||||
|
||||
.. refcounting:: new |
||||
|
||||
<description of the json_object function> |
||||
|
||||
:copyright: Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
:license: MIT, see LICENSE for details. |
||||
""" |
||||
|
||||
from docutils import nodes |
||||
|
||||
class refcounting(nodes.emphasis): pass |
||||
|
||||
def visit(self, node): |
||||
self.visit_emphasis(node) |
||||
|
||||
def depart(self, node): |
||||
self.depart_emphasis(node) |
||||
|
||||
def html_visit(self, node): |
||||
self.body.append(self.starttag(node, 'em', '', CLASS='refcount')) |
||||
|
||||
def html_depart(self, node): |
||||
self.body.append('</em>') |
||||
|
||||
|
||||
def refcounting_directive(name, arguments, options, content, lineno, |
||||
content_offset, block_text, state, state_machine): |
||||
if arguments[0] == 'borrow': |
||||
text = 'Return value: Borrowed reference.' |
||||
elif arguments[0] == 'new': |
||||
text = 'Return value: New reference.' |
||||
else: |
||||
raise Error('Valid arguments: new, borrow') |
||||
|
||||
return [refcounting(text, text)] |
||||
|
||||
def setup(app): |
||||
app.add_node(refcounting, |
||||
html=(html_visit, html_depart), |
||||
latex=(visit, depart), |
||||
text=(visit, depart)) |
||||
app.add_directive('refcounting', refcounting_directive, 0, (1, 0, 0)) |
@ -0,0 +1,237 @@
@@ -0,0 +1,237 @@
|
||||
*************** |
||||
Getting Started |
||||
*************** |
||||
|
||||
.. highlight:: c |
||||
|
||||
Compiling and Installing Jansson |
||||
================================ |
||||
|
||||
The Jansson source is available at |
||||
http://www.digip.org/jansson/releases/. |
||||
|
||||
Unix-like systems (including MinGW) |
||||
----------------------------------- |
||||
|
||||
Unpack the source tarball and change to the source directory: |
||||
|
||||
.. parsed-literal:: |
||||
|
||||
bunzip2 -c jansson-|release|.tar.bz2 | tar xf - |
||||
cd jansson-|release| |
||||
|
||||
The source uses GNU Autotools (autoconf_, automake_, libtool_), so |
||||
compiling and installing is extremely simple:: |
||||
|
||||
./configure |
||||
make |
||||
make check |
||||
make install |
||||
|
||||
To change the destination directory (``/usr/local`` by default), use |
||||
the ``--prefix=DIR`` argument to ``./configure``. See ``./configure |
||||
--help`` for the list of all possible installation options. (There are |
||||
no options to customize the resulting Jansson binary.) |
||||
|
||||
The command ``make check`` runs the test suite distributed with |
||||
Jansson. This step is not strictly necessary, but it may find possible |
||||
problems that Jansson has on your platform. If any problems are found, |
||||
please report them. |
||||
|
||||
If you obtained the source from a Git repository (or any other source |
||||
control system), there's no ``./configure`` script as it's not kept in |
||||
version control. To create the script, the build system needs to be |
||||
bootstrapped. There are many ways to do this, but the easiest one is |
||||
to use ``autoreconf``:: |
||||
|
||||
autoreconf -vi |
||||
|
||||
This command creates the ``./configure`` script, which can then be |
||||
used as described above. |
||||
|
||||
.. _autoconf: http://www.gnu.org/software/autoconf/ |
||||
.. _automake: http://www.gnu.org/software/automake/ |
||||
.. _libtool: http://www.gnu.org/software/libtool/ |
||||
|
||||
|
||||
.. _build-cmake: |
||||
|
||||
CMake (various platforms, including Windows) |
||||
-------------------------------------------- |
||||
|
||||
Jansson can be built using CMake_. Create a build directory for an |
||||
out-of-tree build, change to that directory, and run ``cmake`` (or ``ccmake``, |
||||
``cmake-gui``, or similar) to configure the project. |
||||
|
||||
See the examples below for more detailed information. |
||||
|
||||
.. note:: In the below examples ``..`` is used as an argument for ``cmake``. |
||||
This is simply the path to the jansson project root directory. |
||||
In the example it is assumed you've created a sub-directory ``build`` |
||||
and are using that. You could use any path you want. |
||||
|
||||
.. _build-cmake-unix: |
||||
|
||||
Unix (Make files) |
||||
^^^^^^^^^^^^^^^^^ |
||||
Generating make files on unix: |
||||
|
||||
.. parsed-literal:: |
||||
|
||||
bunzip2 -c jansson-|release|.tar.bz2 | tar xf - |
||||
cd jansson-|release| |
||||
|
||||
mkdir build |
||||
cd build |
||||
cmake .. # or `ccmake ..` for a GUI. |
||||
|
||||
Then to build:: |
||||
|
||||
make |
||||
make check |
||||
make install |
||||
|
||||
Windows (Visual Studio) |
||||
^^^^^^^^^^^^^^^^^^^^^^^ |
||||
Creating Visual Studio project files from the command line: |
||||
|
||||
.. parsed-literal:: |
||||
|
||||
<unpack> |
||||
cd jansson-|release| |
||||
|
||||
md build |
||||
cd build |
||||
cmake -G "Visual Studio 10" .. |
||||
|
||||
You will now have a *Visual Studio Solution* in your build directory. |
||||
To run the unit tests build the ``RUN_TESTS`` project. |
||||
|
||||
If you prefer a GUI the ``cmake`` line in the above example can |
||||
be replaced with:: |
||||
|
||||
cmake-gui .. |
||||
|
||||
For command line help (including a list of available generators) |
||||
for CMake_ simply run:: |
||||
|
||||
cmake |
||||
|
||||
To list available CMake_ settings (and what they are currently set to) |
||||
for the project, run:: |
||||
|
||||
cmake -LH .. |
||||
|
||||
Mac OSX (Xcode) |
||||
^^^^^^^^^^^^^^^ |
||||
If you prefer using Xcode instead of make files on OSX, |
||||
do the following. (Use the same steps as |
||||
for :ref:`Unix <build-cmake-unix>`):: |
||||
|
||||
... |
||||
cmake -G "Xcode" .. |
||||
|
||||
Additional CMake settings |
||||
^^^^^^^^^^^^^^^^^^^^^^^^^ |
||||
|
||||
Shared library |
||||
"""""""""""""" |
||||
By default the CMake_ project will generate build files for building the |
||||
static library. To build the shared version use:: |
||||
|
||||
... |
||||
cmake -DBUILD_SHARED=1 .. |
||||
|
||||
Changing install directory (same as autoconf --prefix) |
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""" |
||||
Just as with the autoconf_ project you can change the destination directory |
||||
for ``make install``. The equivalent for autoconfs ``./configure --prefix`` |
||||
in CMake_ is:: |
||||
|
||||
... |
||||
cmake -DCMAKE_INSTALL_PREFIX:PATH=/some/other/path .. |
||||
make install |
||||
|
||||
.. _CMake: http://www.cmake.org |
||||
|
||||
Android |
||||
------- |
||||
|
||||
Jansson can be built for Android platforms. Android.mk is in the |
||||
source root directory. The configuration header file is located in the |
||||
``android`` directory in the source distribution. |
||||
|
||||
|
||||
Windows |
||||
------- |
||||
|
||||
**This method is deprecated**. Using :ref:`CMake <build-cmake>` is now |
||||
preferred. |
||||
|
||||
Jansson can be built with Visual Studio 2010 (and probably newer |
||||
versions, too). The solution and project files are in the |
||||
``win32/vs2010/`` directory in the source distribution. |
||||
|
||||
|
||||
Other Systems |
||||
------------- |
||||
|
||||
On non Unix-like systems, you may be unable to run the ``./configure`` |
||||
script. In this case, follow these steps. All the files mentioned can |
||||
be found in the ``src/`` directory. |
||||
|
||||
1. Create ``jansson_config.h`` (which has some platform-specific |
||||
parameters that are normally filled in by the ``./configure`` |
||||
script). Edit ``jansson_config.h.in``, replacing all ``@variable@`` |
||||
placeholders, and rename the file to ``jansson_config.h``. |
||||
|
||||
2. Make ``jansson.h`` and ``jansson_config.h`` available to the |
||||
compiler, so that they can be found when compiling programs that |
||||
use Jansson. |
||||
|
||||
3. Compile all the ``.c`` files (in the ``src/`` directory) into a |
||||
library file. Make the library available to the compiler, as in |
||||
step 2. |
||||
|
||||
|
||||
Building the Documentation |
||||
-------------------------- |
||||
|
||||
(This subsection describes how to build the HTML documentation you are |
||||
currently reading, so it can be safely skipped.) |
||||
|
||||
Documentation is in the ``doc/`` subdirectory. It's written in |
||||
reStructuredText_ with Sphinx_ annotations. To generate the HTML |
||||
documentation, invoke:: |
||||
|
||||
make html |
||||
|
||||
and point your browser to ``doc/_build/html/index.html``. Sphinx_ 1.0 |
||||
or newer is required to generate the documentation. |
||||
|
||||
.. _reStructuredText: http://docutils.sourceforge.net/rst.html |
||||
.. _Sphinx: http://sphinx.pocoo.org/ |
||||
|
||||
|
||||
Compiling Programs that Use Jansson |
||||
=================================== |
||||
|
||||
Jansson involves one C header file, :file:`jansson.h`, so it's enough |
||||
to put the line |
||||
|
||||
:: |
||||
|
||||
#include <jansson.h> |
||||
|
||||
in the beginning of every source file that uses Jansson. |
||||
|
||||
There's also just one library to link with, ``libjansson``. Compile and |
||||
link the program as follows:: |
||||
|
||||
cc -o prog prog.c -ljansson |
||||
|
||||
Starting from version 1.2, there's also support for pkg-config_:: |
||||
|
||||
cc -o prog prog.c `pkg-config --cflags --libs jansson` |
||||
|
||||
.. _pkg-config: http://pkg-config.freedesktop.org/ |
@ -0,0 +1,192 @@
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
* |
||||
* Jansson is free software; you can redistribute it and/or modify |
||||
* it under the terms of the MIT license. See LICENSE for details. |
||||
*/ |
||||
|
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
|
||||
#include <jansson.h> |
||||
#include <curl/curl.h> |
||||
|
||||
#define BUFFER_SIZE (256 * 1024) /* 256 KB */ |
||||
|
||||
#define URL_FORMAT "https://api.github.com/repos/%s/%s/commits"
|
||||
#define URL_SIZE 256 |
||||
|
||||
/* Return the offset of the first newline in text or the length of
|
||||
text if there's no newline */ |
||||
static int newline_offset(const char *text) |
||||
{ |
||||
const char *newline = strchr(text, '\n'); |
||||
if(!newline) |
||||
return strlen(text); |
||||
else |
||||
return (int)(newline - text); |
||||
} |
||||
|
||||
struct write_result |
||||
{ |
||||
char *data; |
||||
int pos; |
||||
}; |
||||
|
||||
static size_t write_response(void *ptr, size_t size, size_t nmemb, void *stream) |
||||
{ |
||||
struct write_result *result = (struct write_result *)stream; |
||||
|
||||
if(result->pos + size * nmemb >= BUFFER_SIZE - 1) |
||||
{ |
||||
fprintf(stderr, "error: too small buffer\n"); |
||||
return 0; |
||||
} |
||||
|
||||
memcpy(result->data + result->pos, ptr, size * nmemb); |
||||
result->pos += size * nmemb; |
||||
|
||||
return size * nmemb; |
||||
} |
||||
|
||||
static char *request(const char *url) |
||||
{ |
||||
CURL *curl = NULL; |
||||
CURLcode status; |
||||
char *data = NULL; |
||||
long code; |
||||
|
||||
curl_global_init(CURL_GLOBAL_ALL); |
||||
curl = curl_easy_init(); |
||||
if(!curl) |
||||
goto error; |
||||
|
||||
data = malloc(BUFFER_SIZE); |
||||
if(!data) |
||||
goto error; |
||||
|
||||
struct write_result write_result = { |
||||
.data = data, |
||||
.pos = 0 |
||||
}; |
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url); |
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_response); |
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &write_result); |
||||
|
||||
status = curl_easy_perform(curl); |
||||
if(status != 0) |
||||
{ |
||||
fprintf(stderr, "error: unable to request data from %s:\n", url); |
||||
fprintf(stderr, "%s\n", curl_easy_strerror(status)); |
||||
goto error; |
||||
} |
||||
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); |
||||
if(code != 200) |
||||
{ |
||||
fprintf(stderr, "error: server responded with code %ld\n", code); |
||||
goto error; |
||||
} |
||||
|
||||
curl_easy_cleanup(curl); |
||||
curl_global_cleanup(); |
||||
|
||||
/* zero-terminate the result */ |
||||
data[write_result.pos] = '\0'; |
||||
|
||||
return data; |
||||
|
||||
error: |
||||
if(data) |
||||
free(data); |
||||
if(curl) |
||||
curl_easy_cleanup(curl); |
||||
curl_global_cleanup(); |
||||
return NULL; |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
size_t i; |
||||
char *text; |
||||
char url[URL_SIZE]; |
||||
|
||||
json_t *root; |
||||
json_error_t error; |
||||
|
||||
if(argc != 3) |
||||
{ |
||||
fprintf(stderr, "usage: %s USER REPOSITORY\n\n", argv[0]); |
||||
fprintf(stderr, "List commits at USER's REPOSITORY.\n\n"); |
||||
return 2; |
||||
} |
||||
|
||||
snprintf(url, URL_SIZE, URL_FORMAT, argv[1], argv[2]); |
||||
|
||||
text = request(url); |
||||
if(!text) |
||||
return 1; |
||||
|
||||
root = json_loads(text, 0, &error); |
||||
free(text); |
||||
|
||||
if(!root) |
||||
{ |
||||
fprintf(stderr, "error: on line %d: %s\n", error.line, error.text); |
||||
return 1; |
||||
} |
||||
|
||||
if(!json_is_array(root)) |
||||
{ |
||||
fprintf(stderr, "error: root is not an array\n"); |
||||
json_decref(root); |
||||
return 1; |
||||
} |
||||
|
||||
for(i = 0; i < json_array_size(root); i++) |
||||
{ |
||||
json_t *data, *sha, *commit, *message; |
||||
const char *message_text; |
||||
|
||||
data = json_array_get(root, i); |
||||
if(!json_is_object(data)) |
||||
{ |
||||
fprintf(stderr, "error: commit data %d is not an object\n", (int)(i + 1)); |
||||
json_decref(root); |
||||
return 1; |
||||
} |
||||
|
||||
sha = json_object_get(data, "sha"); |
||||
if(!json_is_string(sha)) |
||||
{ |
||||
fprintf(stderr, "error: commit %d: sha is not a string\n", (int)(i + 1)); |
||||
return 1; |
||||
} |
||||
|
||||
commit = json_object_get(data, "commit"); |
||||
if(!json_is_object(commit)) |
||||
{ |
||||
fprintf(stderr, "error: commit %d: commit is not an object\n", (int)(i + 1)); |
||||
json_decref(root); |
||||
return 1; |
||||
} |
||||
|
||||
message = json_object_get(commit, "message"); |
||||
if(!json_is_string(message)) |
||||
{ |
||||
fprintf(stderr, "error: commit %d: message is not a string\n", (int)(i + 1)); |
||||
json_decref(root); |
||||
return 1; |
||||
} |
||||
|
||||
message_text = json_string_value(message); |
||||
printf("%.8s %.*s\n", |
||||
json_string_value(sha), |
||||
newline_offset(message_text), |
||||
message_text); |
||||
} |
||||
|
||||
json_decref(root); |
||||
return 0; |
||||
} |
@ -0,0 +1,53 @@
@@ -0,0 +1,53 @@
|
||||
Jansson Documentation |
||||
===================== |
||||
|
||||
This is the documentation for Jansson_ |release|, last updated |today|. |
||||
|
||||
Introduction |
||||
------------ |
||||
|
||||
Jansson_ is a C library for encoding, decoding and manipulating JSON |
||||
data. Its main features and design principles are: |
||||
|
||||
- Simple and intuitive API and data model |
||||
|
||||
- Comprehensive documentation |
||||
|
||||
- No dependencies on other libraries |
||||
|
||||
- Full Unicode support (UTF-8) |
||||
|
||||
- Extensive test suite |
||||
|
||||
Jansson is licensed under the `MIT license`_; see LICENSE in the |
||||
source distribution for details. |
||||
|
||||
Jansson is used in production and its API is stable. It works on |
||||
numerous platforms, including numerous Unix like systems and Windows. |
||||
It's suitable for use on any system, including desktop, server, and |
||||
small embedded systems. |
||||
|
||||
|
||||
.. _`MIT license`: http://www.opensource.org/licenses/mit-license.php |
||||
.. _Jansson: http://www.digip.org/jansson/ |
||||
|
||||
Contents |
||||
-------- |
||||
|
||||
.. toctree:: |
||||
:maxdepth: 2 |
||||
|
||||
gettingstarted |
||||
upgrading |
||||
tutorial |
||||
conformance |
||||
portability |
||||
apiref |
||||
changes |
||||
|
||||
|
||||
Indices and Tables |
||||
================== |
||||
|
||||
* :ref:`genindex` |
||||
* :ref:`search` |
@ -0,0 +1,52 @@
@@ -0,0 +1,52 @@
|
||||
*********** |
||||
Portability |
||||
*********** |
||||
|
||||
Thread safety |
||||
------------- |
||||
|
||||
Jansson is thread safe and has no mutable global state. The only |
||||
exception are the memory allocation functions, that should be set at |
||||
most once, and only on program startup. See |
||||
:ref:`apiref-custom-memory-allocation`. |
||||
|
||||
There's no locking performed inside Jansson's code, so a multithreaded |
||||
program must perform its own locking if JSON values are shared by |
||||
multiple threads. Jansson's reference counting semantics may make this |
||||
a bit harder than it seems, as it's possible to have a reference to a |
||||
value that's also stored inside a list or object. Modifying the |
||||
container (adding or removing values) may trigger concurrent access to |
||||
such values, as containers manage the reference count of their |
||||
contained values. Bugs involving concurrent incrementing or |
||||
decrementing of deference counts may be hard to track. |
||||
|
||||
The encoding functions (:func:`json_dumps()` and friends) track |
||||
reference loops by modifying the internal state of objects and arrays. |
||||
For this reason, encoding functions must not be run on the same JSON |
||||
values in two separate threads at the same time. As already noted |
||||
above, be especially careful if two arrays or objects share their |
||||
contained values with another array or object. |
||||
|
||||
If you want to make sure that two JSON value hierarchies do not |
||||
contain shared values, use :func:`json_deep_copy()` to make copies. |
||||
|
||||
Locale |
||||
------ |
||||
|
||||
Jansson works fine under any locale. |
||||
|
||||
However, if the host program is multithreaded and uses ``setlocale()`` |
||||
to switch the locale in one thread while Jansson is currently encoding |
||||
or decoding JSON data in another thread, the result may be wrong or |
||||
the program may even crash. |
||||
|
||||
Jansson uses locale specific functions for certain string conversions |
||||
in the encoder and decoder, and then converts the locale specific |
||||
values to/from the JSON representation. This fails if the locale |
||||
changes between the string conversion and the locale-to-JSON |
||||
conversion. This can only happen in multithreaded programs that use |
||||
``setlocale()``, because ``setlocale()`` switches the locale for all |
||||
running threads, not only the thread that calls ``setlocale()``. |
||||
|
||||
If your program uses ``setlocale()`` as described above, consider |
||||
using the thread-safe ``uselocale()`` instead. |
@ -0,0 +1,286 @@
@@ -0,0 +1,286 @@
|
||||
.. _tutorial: |
||||
|
||||
******** |
||||
Tutorial |
||||
******** |
||||
|
||||
.. highlight:: c |
||||
|
||||
In this tutorial, we create a program that fetches the latest commits |
||||
of a repository in GitHub_ over the web. `GitHub API`_ uses JSON, so |
||||
the result can be parsed using Jansson. |
||||
|
||||
To stick to the the scope of this tutorial, we will only cover the the |
||||
parts of the program related to handling JSON data. For the best user |
||||
experience, the full source code is available: |
||||
:download:`github_commits.c`. To compile it (on Unix-like systems with |
||||
gcc), use the following command:: |
||||
|
||||
gcc -o github_commits github_commits.c -ljansson -lcurl |
||||
|
||||
libcurl_ is used to communicate over the web, so it is required to |
||||
compile the program. |
||||
|
||||
The command line syntax is:: |
||||
|
||||
github_commits USER REPOSITORY |
||||
|
||||
``USER`` is a GitHub user ID and ``REPOSITORY`` is the repository |
||||
name. Please note that the GitHub API is rate limited, so if you run |
||||
the program too many times within a short period of time, the sever |
||||
starts to respond with an error. |
||||
|
||||
.. _GitHub: https://github.com/ |
||||
.. _GitHub API: http://developer.github.com/ |
||||
.. _libcurl: http://curl.haxx.se/ |
||||
|
||||
|
||||
.. _tutorial-github-commits-api: |
||||
|
||||
The GitHub Repo Commits API |
||||
=========================== |
||||
|
||||
The `GitHub Repo Commits API`_ is used by sending HTTP requests to |
||||
URLs like ``https://api.github.com/repos/USER/REPOSITORY/commits``, |
||||
where ``USER`` and ``REPOSITORY`` are the GitHub user ID and the name |
||||
of the repository whose commits are to be listed, respectively. |
||||
|
||||
GitHub responds with a JSON array of the following form: |
||||
|
||||
.. code-block:: none |
||||
|
||||
[ |
||||
{ |
||||
"sha": "<the commit ID>", |
||||
"commit": { |
||||
"message": "<the commit message>", |
||||
<more fields, not important to this tutorial...> |
||||
}, |
||||
<more fields...> |
||||
}, |
||||
{ |
||||
"sha": "<the commit ID>", |
||||
"commit": { |
||||
"message": "<the commit message>", |
||||
<more fields...> |
||||
}, |
||||
<more fields...> |
||||
}, |
||||
<more commits...> |
||||
] |
||||
|
||||
In our program, the HTTP request is sent using the following |
||||
function:: |
||||
|
||||
static char *request(const char *url); |
||||
|
||||
It takes the URL as a parameter, preforms 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 |
||||
<github_commits.c>`, as the actual implementation is not important |
||||
here. |
||||
|
||||
.. _GitHub Repo Commits API: http://developer.github.com/v3/repos/commits/ |
||||
|
||||
.. _tutorial-the-program: |
||||
|
||||
The Program |
||||
=========== |
||||
|
||||
First the includes:: |
||||
|
||||
#include <string.h> |
||||
#include <jansson.h> |
||||
|
||||
Like all the programs using Jansson, we need to include |
||||
:file:`jansson.h`. |
||||
|
||||
The following definitions are used to build the GitHub API request |
||||
URL:: |
||||
|
||||
#define URL_FORMAT "https://api.github.com/repos/%s/%s/commits" |
||||
#define URL_SIZE 256 |
||||
|
||||
The following function is used when formatting the result to find the |
||||
first newline in the commit message:: |
||||
|
||||
/* Return the offset of the first newline in text or the length of |
||||
text if there's no newline */ |
||||
static int newline_offset(const char *text) |
||||
{ |
||||
const char *newline = strchr(text, '\n'); |
||||
if(!newline) |
||||
return strlen(text); |
||||
else |
||||
return (int)(newline - text); |
||||
} |
||||
|
||||
The main function follows. In the beginning, we first declare a bunch |
||||
of variables and check the command line parameters:: |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
size_t i; |
||||
char *text; |
||||
char url[URL_SIZE]; |
||||
|
||||
json_t *root; |
||||
json_error_t error; |
||||
|
||||
if(argc != 3) |
||||
{ |
||||
fprintf(stderr, "usage: %s USER REPOSITORY\n\n", argv[0]); |
||||
fprintf(stderr, "List commits at USER's REPOSITORY.\n\n"); |
||||
return 2; |
||||
} |
||||
|
||||
Then we build the request URL using the user and repository names |
||||
given as command line parameters:: |
||||
|
||||
snprintf(url, URL_SIZE, URL_FORMAT, argv[1], argv[2]); |
||||
|
||||
This uses the ``URL_SIZE`` and ``URL_FORMAT`` constants defined above. |
||||
Now we're ready to actually request the JSON data over the web:: |
||||
|
||||
text = request(url); |
||||
if(!text) |
||||
return 1; |
||||
|
||||
If an error occurs, our function ``request`` prints the error and |
||||
returns *NULL*, so it's enough to just return 1 from the main |
||||
function. |
||||
|
||||
Next we'll call :func:`json_loads()` to decode the JSON text we got |
||||
as a response:: |
||||
|
||||
root = json_loads(text, 0, &error); |
||||
free(text); |
||||
|
||||
if(!root) |
||||
{ |
||||
fprintf(stderr, "error: on line %d: %s\n", error.line, error.text); |
||||
return 1; |
||||
} |
||||
|
||||
We don't need the JSON text anymore, so we can free the ``text`` |
||||
variable right after decoding it. If :func:`json_loads()` fails, it |
||||
returns *NULL* and sets error information to the :type:`json_error_t` |
||||
structure given as the second parameter. In this case, our program |
||||
prints the error information out and returns 1 from the main function. |
||||
|
||||
Now we're ready to extract the data out of the decoded JSON response. |
||||
The structure of the response JSON was explained in section |
||||
:ref:`tutorial-github-commits-api`. |
||||
|
||||
We check that the returned value really is an array:: |
||||
|
||||
if(!json_is_array(root)) |
||||
{ |
||||
fprintf(stderr, "error: root is not an array\n"); |
||||
json_decref(root); |
||||
return 1; |
||||
} |
||||
|
||||
Then we proceed to loop over all the commits in the array:: |
||||
|
||||
for(i = 0; i < json_array_size(root); i++) |
||||
{ |
||||
json_t *data, *sha, *commit, *message; |
||||
const char *message_text; |
||||
|
||||
data = json_array_get(root, i); |
||||
if(!json_is_object(data)) |
||||
{ |
||||
fprintf(stderr, "error: commit data %d is not an object\n", i + 1); |
||||
json_decref(root); |
||||
return 1; |
||||
} |
||||
... |
||||
|
||||
The function :func:`json_array_size()` returns the size of a JSON |
||||
array. First, we again declare some variables and then extract the |
||||
i'th element of the ``root`` array using :func:`json_array_get()`. |
||||
We also check that the resulting value is a JSON object. |
||||
|
||||
Next we'll extract the commit ID (a hexadecimal SHA-1 sum), |
||||
intermediate commit info object, and the commit message from that |
||||
object. We also do proper type checks:: |
||||
|
||||
sha = json_object_get(data, "sha"); |
||||
if(!json_is_string(sha)) |
||||
{ |
||||
fprintf(stderr, "error: commit %d: sha is not a string\n", i + 1); |
||||
json_decref(root); |
||||
return 1; |
||||
} |
||||
|
||||
commit = json_object_get(data, "commit"); |
||||
if(!json_is_object(commit)) |
||||
{ |
||||
fprintf(stderr, "error: commit %d: commit is not an object\n", i + 1); |
||||
json_decref(root); |
||||
return 1; |
||||
} |
||||
|
||||
message = json_object_get(commit, "message"); |
||||
if(!json_is_string(message)) |
||||
{ |
||||
fprintf(stderr, "error: commit %d: message is not a string\n", i + 1); |
||||
json_decref(root); |
||||
return 1; |
||||
} |
||||
... |
||||
|
||||
And finally, we'll print the first 8 characters of the commit ID and |
||||
the first line of the commit message. A C-style string is extracted |
||||
from a JSON string using :func:`json_string_value()`:: |
||||
|
||||
message_text = json_string_value(message); |
||||
printf("%.8s %.*s\n", |
||||
json_string_value(id), |
||||
newline_offset(message_text), |
||||
message_text); |
||||
} |
||||
|
||||
After sending the HTTP request, we decoded the JSON text using |
||||
:func:`json_loads()`, remember? It returns a *new reference* to the |
||||
JSON value it decodes. When we're finished with the value, we'll need |
||||
to decrease the reference count using :func:`json_decref()`. This way |
||||
Jansson can release the resources:: |
||||
|
||||
json_decref(root); |
||||
return 0; |
||||
|
||||
For a detailed explanation of reference counting in Jansson, see |
||||
:ref:`apiref-reference-count` in :ref:`apiref`. |
||||
|
||||
The program's ready, let's test it and view the latest commits in |
||||
Jansson's repository:: |
||||
|
||||
$ ./github_commits akheron jansson |
||||
1581f26a Merge branch '2.3' |
||||
aabfd493 load: Change buffer_pos to be a size_t |
||||
bd72efbd load: Avoid unexpected behaviour in macro expansion |
||||
e8fd3e30 Document and tweak json_load_callback() |
||||
873eddaf Merge pull request #60 from rogerz/contrib |
||||
bd2c0c73 Ignore the binary test_load_callback |
||||
17a51a4b Merge branch '2.3' |
||||
09c39adc Add json_load_callback to the list of exported symbols |
||||
cbb80baf Merge pull request #57 from rogerz/contrib |
||||
040bd7b0 Add json_load_callback() |
||||
2637faa4 Make test stripping locale independent |
||||
<...> |
||||
|
||||
|
||||
Conclusion |
||||
========== |
||||
|
||||
In this tutorial, we implemented a program that fetches the latest |
||||
commits of a GitHub repository using the GitHub Repo Commits API. |
||||
Jansson was used to decode the JSON response and to extract the commit |
||||
data. |
||||
|
||||
This tutorial only covered a small part of Jansson. For example, we |
||||
did not create or manipulate JSON values at all. Proceed to |
||||
:ref:`apiref` to explore all features of Jansson. |
@ -0,0 +1,76 @@
@@ -0,0 +1,76 @@
|
||||
.. highlight:: c |
||||
|
||||
****************** |
||||
Upgrading from 1.x |
||||
****************** |
||||
|
||||
This chapter lists the backwards incompatible changes introduced in |
||||
Jansson 2.0, and the steps that are needed for upgrading your code. |
||||
|
||||
**The incompatibilities are not dramatic.** The biggest change is that |
||||
all decoding functions now require and extra parameter. Most programs |
||||
can be modified to work with 2.0 by adding a ``0`` as the second |
||||
parameter to all calls of :func:`json_loads()`, :func:`json_loadf()` |
||||
and :func:`json_load_file()`. |
||||
|
||||
|
||||
Compatibility |
||||
============= |
||||
|
||||
Jansson 2.0 is backwards incompatible with the Jansson 1.x releases. |
||||
It is ABI incompatible, i.e. all programs dynamically linking to the |
||||
Jansson library need to be recompiled. It's also API incompatible, |
||||
i.e. the source code of programs using Jansson 1.x may need |
||||
modifications to make them compile against Jansson 2.0. |
||||
|
||||
All the 2.x releases are guaranteed to be backwards compatible for |
||||
both ABI and API, so no recompilation or source changes are needed |
||||
when upgrading from 2.x to 2.y. |
||||
|
||||
|
||||
List of Incompatible Changes |
||||
============================ |
||||
|
||||
**Decoding flags** |
||||
For future needs, a ``flags`` parameter was added as the second |
||||
parameter to all decoding functions, i.e. :func:`json_loads()`, |
||||
:func:`json_loadf()` and :func:`json_load_file()`. All calls to |
||||
these functions need to be changed by adding a ``0`` as the second |
||||
argument. For example:: |
||||
|
||||
/* old code */ |
||||
json_loads(input, &error); |
||||
|
||||
/* new code */ |
||||
json_loads(input, 0, &error); |
||||
|
||||
|
||||
**Underlying type of JSON integers** |
||||
The underlying C type of JSON integers has been changed from |
||||
:type:`int` to the widest available signed integer type, i.e. |
||||
:type:`long long` or :type:`long`, depending on whether |
||||
:type:`long long` is supported on your system or not. This makes |
||||
the whole 64-bit integer range available on most modern systems. |
||||
|
||||
``jansson.h`` has a typedef :type:`json_int_t` to the underlying |
||||
integer type. :type:`int` should still be used in most cases when |
||||
dealing with smallish JSON integers, as the compiler handles |
||||
implicit type coercion. Only when the full 64-bit range is needed, |
||||
:type:`json_int_t` should be explicitly used. |
||||
|
||||
|
||||
**Maximum encoder indentation depth** |
||||
The maximum argument of the ``JSON_INDENT()`` macro has been |
||||
changed from 255 to 31, to free up bits from the ``flags`` |
||||
parameter of :func:`json_dumps()`, :func:`json_dumpf()` and |
||||
:func:`json_dump_file()`. If your code uses a bigger indentation |
||||
than 31, it needs to be changed. |
||||
|
||||
|
||||
**Unsigned integers in API functions** |
||||
Version 2.0 unifies unsigned integer usage in the API. All uses of |
||||
:type:`unsigned int` and :type:`unsigned long` have been replaced |
||||
with :type:`size_t`. This includes flags, container sizes, etc. |
||||
This should not require source code changes, as both |
||||
:type:`unsigned int` and :type:`unsigned long` are usually |
||||
compatible with :type:`size_t`. |
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
prefix=@prefix@ |
||||
exec_prefix=@exec_prefix@ |
||||
libdir=@libdir@ |
||||
includedir=${prefix}/include |
||||
|
||||
Name: Jansson |
||||
Description: Library for encoding, decoding and manipulating JSON data |
||||
Version: @VERSION@ |
||||
Libs: -L${libdir} -ljansson |
||||
Cflags: -I${includedir} |
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
EXTRA_DIST = jansson.def |
||||
|
||||
include_HEADERS = jansson.h jansson_config.h |
||||
|
||||
lib_LTLIBRARIES = libjansson.la |
||||
libjansson_la_SOURCES = \
|
||||
dump.c \
|
||||
error.c \
|
||||
hashtable.c \
|
||||
hashtable.h \
|
||||
jansson_private.h \
|
||||
load.c \
|
||||
memory.c \
|
||||
pack_unpack.c \
|
||||
strbuffer.c \
|
||||
strbuffer.h \
|
||||
strconv.c \
|
||||
utf.c \
|
||||
utf.h \
|
||||
value.c |
||||
libjansson_la_LDFLAGS = \
|
||||
-no-undefined \
|
||||
-export-symbols-regex '^json_' \
|
||||
-version-info 9:0:5 |
@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org> |
||||
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
* |
||||
* This library is free software; you can redistribute it and/or modify |
||||
* it under the terms of the MIT license. See LICENSE for details. |
@ -1,5 +1,3 @@
@@ -1,5 +1,3 @@
|
||||
LIBRARY "jansson" |
||||
|
||||
EXPORTS |
||||
json_delete |
||||
json_true |
@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2012 Petri Lehtinen <petri@digip.org> |
||||
* Copyright (c) 2010-2013 Petri Lehtinen <petri@digip.org> |
||||
* |
||||
* Jansson is free software; you can redistribute it and/or modify |
||||
* it under the terms of the MIT license. See LICENSE for details. |
@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org> |
||||
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
* |
||||
* Jansson is free software; you can redistribute it and/or modify |
||||
* it under the terms of the MIT license. See LICENSE for details. |
@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org> |
||||
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
* |
||||
* Jansson is free software; you can redistribute it and/or modify |
||||
* it under the terms of the MIT license. See LICENSE for details. |
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
SUBDIRS = bin suites |
||||
EXTRA_DIST = scripts run-suites |
||||
|
||||
TESTS = run-suites |
||||
TESTS_ENVIRONMENT = \
|
||||
top_srcdir=$(top_srcdir) \
|
||||
top_builddir=$(top_builddir) |
||||
|
||||
clean-local: |
||||
rm -rf logs |
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
check_PROGRAMS = json_process |
||||
|
||||
AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src |
||||
LDFLAGS = -static # for speed and Valgrind |
||||
LDADD = $(top_builddir)/src/libjansson.la |
@ -0,0 +1,349 @@
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
* |
||||
* Jansson is free software; you can redistribute it and/or modify |
||||
* it under the terms of the MIT license. See LICENSE for details. |
||||
*/ |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include <config.h> |
||||
#endif |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <ctype.h> |
||||
#include <jansson.h> |
||||
|
||||
#ifdef HAVE_LOCALE_H |
||||
#include <locale.h> |
||||
#endif |
||||
|
||||
#if _WIN32 |
||||
#include <io.h> /* for _setmode() */ |
||||
#include <fcntl.h> /* for _O_BINARY */ |
||||
|
||||
static const char dir_sep = '\\'; |
||||
#else |
||||
static const char dir_sep = '/'; |
||||
#endif |
||||
|
||||
|
||||
struct config { |
||||
int indent; |
||||
int compact; |
||||
int preserve_order; |
||||
int ensure_ascii; |
||||
int sort_keys; |
||||
int strip; |
||||
int use_env; |
||||
} conf; |
||||
|
||||
#define l_isspace(c) ((c) == ' ' || (c) == '\n' || (c) == '\r' || (c) == '\t') |
||||
|
||||
/* Return a pointer to the first non-whitespace character of str.
|
||||
Modifies str so that all trailing whitespace characters are |
||||
replaced by '\0'. */ |
||||
static const char *strip(char *str) |
||||
{ |
||||
size_t length; |
||||
char *result = str; |
||||
while (*result && l_isspace(*result)) |
||||
result++; |
||||
|
||||
length = strlen(result); |
||||
if (length == 0) |
||||
return result; |
||||
|
||||
while (l_isspace(result[length - 1])) |
||||
result[--length] = '\0'; |
||||
|
||||
return result; |
||||
} |
||||
|
||||
|
||||
static char *loadfile(FILE *file) |
||||
{ |
||||
long fsize, ret; |
||||
char *buf; |
||||
|
||||
fseek(file, 0, SEEK_END); |
||||
fsize = ftell(file); |
||||
fseek(file, 0, SEEK_SET); |
||||
|
||||
buf = malloc(fsize+1); |
||||
ret = fread(buf, 1, fsize, file); |
||||
if (ret != fsize) |
||||
exit(1); |
||||
buf[fsize] = '\0'; |
||||
|
||||
return buf; |
||||
} |
||||
|
||||
|
||||
static void read_conf(FILE *conffile) |
||||
{ |
||||
char *buffer, *line, *val; |
||||
|
||||
buffer = loadfile(conffile); |
||||
line = strtok(buffer, "\r\n"); |
||||
while (line) { |
||||
val = strchr(line, '='); |
||||
if (!val) { |
||||
printf("invalid configuration line\n"); |
||||
break; |
||||
} |
||||
*val++ = '\0'; |
||||
|
||||
if (!strcmp(line, "JSON_INDENT")) |
||||
conf.indent = atoi(val); |
||||
if (!strcmp(line, "JSON_COMPACT")) |
||||
conf.compact = atoi(val); |
||||
if (!strcmp(line, "JSON_ENSURE_ASCII")) |
||||
conf.ensure_ascii = atoi(val); |
||||
if (!strcmp(line, "JSON_PRESERVE_ORDER")) |
||||
conf.preserve_order = atoi(val); |
||||
if (!strcmp(line, "JSON_SORT_KEYS")) |
||||
conf.sort_keys = atoi(val); |
||||
if (!strcmp(line, "STRIP")) |
||||
conf.strip = atoi(val); |
||||
|
||||
line = strtok(NULL, "\r\n"); |
||||
} |
||||
|
||||
free(buffer); |
||||
} |
||||
|
||||
|
||||
static int cmpfile(const char *str, const char *path, const char *fname) |
||||
{ |
||||
char filename[1024], *buffer; |
||||
int ret; |
||||
FILE *file; |
||||
|
||||
sprintf(filename, "%s%c%s", path, dir_sep, fname); |
||||
file = fopen(filename, "rb"); |
||||
if (!file) { |
||||
if (conf.strip) |
||||
strcat(filename, ".strip"); |
||||
else |
||||
strcat(filename, ".normal"); |
||||
file = fopen(filename, "rb"); |
||||
} |
||||
if (!file) { |
||||
printf("Error: test result file could not be opened.\n"); |
||||
exit(1); |
||||
} |
||||
|
||||
buffer = loadfile(file); |
||||
if (strcmp(buffer, str) != 0) |
||||
ret = 1; |
||||
else |
||||
ret = 0; |
||||
free(buffer); |
||||
fclose(file); |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
int use_conf(char *test_path) |
||||
{ |
||||
int ret; |
||||
size_t flags = 0; |
||||
char filename[1024], errstr[1024]; |
||||
char *buffer; |
||||
FILE *infile, *conffile; |
||||
json_t *json; |
||||
json_error_t error; |
||||
|
||||
sprintf(filename, "%s%cinput", test_path, dir_sep); |
||||
if (!(infile = fopen(filename, "rb"))) { |
||||
fprintf(stderr, "Could not open \"%s\"\n", filename); |
||||
return 2; |
||||
} |
||||
|
||||
sprintf(filename, "%s%cenv", test_path, dir_sep); |
||||
conffile = fopen(filename, "rb"); |
||||
if (conffile) { |
||||
read_conf(conffile); |
||||
fclose(conffile); |
||||
} |
||||
|
||||
if (conf.indent < 0 || conf.indent > 255) { |
||||
fprintf(stderr, "invalid value for JSON_INDENT: %d\n", conf.indent); |
||||
return 2; |
||||
} |
||||
|
||||
if (conf.indent) |
||||
flags |= JSON_INDENT(conf.indent); |
||||
|
||||
if (conf.compact) |
||||
flags |= JSON_COMPACT; |
||||
|
||||
if (conf.ensure_ascii) |
||||
flags |= JSON_ENSURE_ASCII; |
||||
|
||||
if (conf.preserve_order) |
||||
flags |= JSON_PRESERVE_ORDER; |
||||
|
||||
if (conf.sort_keys) |
||||
flags |= JSON_SORT_KEYS; |
||||
|
||||
if (conf.strip) { |
||||
/* Load to memory, strip leading and trailing whitespace */ |
||||
buffer = loadfile(infile); |
||||
json = json_loads(strip(buffer), 0, &error); |
||||
free(buffer); |
||||
} |
||||
else |
||||
json = json_loadf(infile, 0, &error); |
||||
|
||||
fclose(infile); |
||||
|
||||
if (!json) { |
||||
sprintf(errstr, "%d %d %d\n%s\n", |
||||
error.line, error.column, error.position, |
||||
error.text); |
||||
|
||||
ret = cmpfile(errstr, test_path, "error"); |
||||
return ret; |
||||
} |
||||
|
||||
buffer = json_dumps(json, flags); |
||||
ret = cmpfile(buffer, test_path, "output"); |
||||
free(buffer); |
||||
json_decref(json); |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
static int getenv_int(const char *name) |
||||
{ |
||||
char *value, *end; |
||||
long result; |
||||
|
||||
value = getenv(name); |
||||
if(!value) |
||||
return 0; |
||||
|
||||
result = strtol(value, &end, 10); |
||||
if(*end != '\0') |
||||
return 0; |
||||
|
||||
return (int)result; |
||||
} |
||||
|
||||
int use_env() |
||||
{ |
||||
int indent; |
||||
size_t flags = 0; |
||||
json_t *json; |
||||
json_error_t error; |
||||
|
||||
#ifdef _WIN32 |
||||
/* On Windows, set stdout and stderr to binary mode to avoid
|
||||
outputting DOS line terminators */ |
||||
_setmode(_fileno(stdout), _O_BINARY); |
||||
_setmode(_fileno(stderr), _O_BINARY); |
||||
#endif |
||||
|
||||
indent = getenv_int("JSON_INDENT"); |
||||
if(indent < 0 || indent > 255) { |
||||
fprintf(stderr, "invalid value for JSON_INDENT: %d\n", indent); |
||||
return 2; |
||||
} |
||||
|
||||
if(indent > 0) |
||||
flags |= JSON_INDENT(indent); |
||||
|
||||
if(getenv_int("JSON_COMPACT") > 0) |
||||
flags |= JSON_COMPACT; |
||||
|
||||
if(getenv_int("JSON_ENSURE_ASCII")) |
||||
flags |= JSON_ENSURE_ASCII; |
||||
|
||||
if(getenv_int("JSON_PRESERVE_ORDER")) |
||||
flags |= JSON_PRESERVE_ORDER; |
||||
|
||||
if(getenv_int("JSON_SORT_KEYS")) |
||||
flags |= JSON_SORT_KEYS; |
||||
|
||||
if(getenv_int("STRIP")) { |
||||
/* Load to memory, strip leading and trailing whitespace */ |
||||
size_t size = 0, used = 0; |
||||
char *buffer = NULL; |
||||
|
||||
while(1) { |
||||
size_t count; |
||||
|
||||
size = (size == 0 ? 128 : size * 2); |
||||
buffer = realloc(buffer, size); |
||||
if(!buffer) { |
||||
fprintf(stderr, "Unable to allocate %d bytes\n", (int)size); |
||||
return 1; |
||||
} |
||||
|
||||
count = fread(buffer + used, 1, size - used, stdin); |
||||
if(count < size - used) { |
||||
buffer[used + count] = '\0'; |
||||
break; |
||||
} |
||||
used += count; |
||||
} |
||||
|
||||
json = json_loads(strip(buffer), 0, &error); |
||||
free(buffer); |
||||
} |
||||
else |
||||
json = json_loadf(stdin, 0, &error); |
||||
|
||||
if(!json) { |
||||
fprintf(stderr, "%d %d %d\n%s\n", |
||||
error.line, error.column, |
||||
error.position, error.text); |
||||
return 1; |
||||
} |
||||
|
||||
json_dumpf(json, stdout, flags); |
||||
json_decref(json); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
int i; |
||||
char *test_path = NULL; |
||||
|
||||
#ifdef HAVE_SETLOCALE |
||||
setlocale(LC_ALL, ""); |
||||
#endif |
||||
|
||||
if (argc < 2) { |
||||
goto usage; |
||||
} |
||||
|
||||
for (i = 1; i < argc; i++) { |
||||
if (!strcmp(argv[i], "--strip")) |
||||
conf.strip = 1; |
||||
else if (!strcmp(argv[i], "--env")) |
||||
conf.use_env = 1; |
||||
else |
||||
test_path = argv[i]; |
||||
} |
||||
|
||||
if (conf.use_env) |
||||
return use_env(); |
||||
else |
||||
{ |
||||
if (!test_path) |
||||
goto usage; |
||||
|
||||
return use_conf(test_path); |
||||
} |
||||
|
||||
usage: |
||||
fprintf(stderr, "argc =%d\n", argc); |
||||
fprintf(stderr, "usage: %s [--strip] [--env] test_dir\n", argv[0]); |
||||
return 2; |
||||
} |
@ -0,0 +1,50 @@
@@ -0,0 +1,50 @@
|
||||
#!/bin/sh |
||||
|
||||
while [ -n "$1" ]; do |
||||
suite=$1 |
||||
if [ -x $top_srcdir/test/suites/$suite/run ]; then |
||||
SUITES="$SUITES $suite" |
||||
else |
||||
echo "No such suite: $suite" |
||||
exit 1 |
||||
fi |
||||
shift |
||||
done |
||||
|
||||
if [ -z "$SUITES" ]; then |
||||
suitedirs=$top_srcdir/test/suites/* |
||||
for suitedir in $suitedirs; do |
||||
if [ -d $suitedir ]; then |
||||
SUITES="$SUITES `basename $suitedir`" |
||||
fi |
||||
done |
||||
fi |
||||
|
||||
[ -z "$STOP" ] && STOP=0 |
||||
|
||||
suites_srcdir=$top_srcdir/test/suites |
||||
suites_builddir=suites |
||||
scriptdir=$top_srcdir/test/scripts |
||||
logdir=logs |
||||
bindir=bin |
||||
export suites_srcdir suites_builddir scriptdir logdir bindir |
||||
|
||||
passed=0 |
||||
failed=0 |
||||
for suite in $SUITES; do |
||||
echo "Suite: $suite" |
||||
if $suites_srcdir/$suite/run $suite; then |
||||
passed=$(($passed+1)) |
||||
else |
||||
failed=$(($failed+1)) |
||||
[ $STOP -eq 1 ] && break |
||||
fi |
||||
done |
||||
|
||||
if [ $failed -gt 0 ]; then |
||||
echo "$failed of $((passed+failed)) test suites failed" |
||||
exit 1 |
||||
else |
||||
echo "$passed test suites passed" |
||||
rm -rf $logdir |
||||
fi |
@ -0,0 +1,100 @@
@@ -0,0 +1,100 @@
|
||||
# Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
# |
||||
# Jansson is free software; you can redistribute it and/or modify |
||||
# it under the terms of the MIT license. See LICENSE for details. |
||||
|
||||
die() { |
||||
echo "$1" >&2 |
||||
exit 1 |
||||
} |
||||
|
||||
[ -n "$1" ] || die "Usage: $0 suite-name" |
||||
[ -n "$bindir" ] || die "Set bindir" |
||||
[ -n "$logdir" ] || die "Set logdir" |
||||
[ -n "$scriptdir" ] || die "Set scriptdir" |
||||
[ -n "$suites_srcdir" ] || die "Set suites_srcdir" |
||||
[ -n "$suites_builddir" ] || die "Set suites_builddir" |
||||
|
||||
json_process=$bindir/json_process |
||||
|
||||
suite_name=$1 |
||||
suite_srcdir=$suites_srcdir/$suite_name |
||||
suite_builddir=$suites_builddir/$suite_name |
||||
suite_log=$logdir/$suite_name |
||||
|
||||
[ -z "$VERBOSE" ] && VERBOSE=0 |
||||
[ -z "$STOP" ] && STOP=0 |
||||
|
||||
. $scriptdir/valgrind.sh |
||||
|
||||
rm -rf $suite_log |
||||
mkdir -p $suite_log |
||||
|
||||
for test_path in $suite_srcdir/*; do |
||||
test_name=$(basename $test_path) |
||||
test_builddir=$suite_builddir/$test_name |
||||
test_log=$suite_log/$test_name |
||||
|
||||
[ "$test_name" = "run" ] && continue |
||||
is_test || continue |
||||
|
||||
rm -rf $test_log |
||||
mkdir -p $test_log |
||||
if [ $VERBOSE -eq 1 ]; then |
||||
printf '%s... ' "$test_name" |
||||
fi |
||||
|
||||
run_test |
||||
case $? in |
||||
0) |
||||
# Success |
||||
if [ $VERBOSE -eq 1 ]; then |
||||
printf 'ok\n' |
||||
else |
||||
printf '.' |
||||
fi |
||||
rm -rf $test_log |
||||
;; |
||||
|
||||
77) |
||||
# Skip |
||||
if [ $VERBOSE -eq 1 ]; then |
||||
printf 'skipped\n' |
||||
else |
||||
printf 'S' |
||||
fi |
||||
rm -rf $test_log |
||||
;; |
||||
|
||||
*) |
||||
# Failure |
||||
if [ $VERBOSE -eq 1 ]; then |
||||
printf 'FAILED\n' |
||||
else |
||||
printf 'F' |
||||
fi |
||||
|
||||
[ $STOP -eq 1 ] && break |
||||
;; |
||||
esac |
||||
done |
||||
|
||||
if [ $VERBOSE -eq 0 ]; then |
||||
printf '\n' |
||||
fi |
||||
|
||||
if [ -n "$(ls -A $suite_log)" ]; then |
||||
for test_log in $suite_log/*; do |
||||
test_name=$(basename $test_log) |
||||
test_path=$suite_srcdir/$test_name |
||||
echo "=================================================================" |
||||
echo "$suite_name/$test_name" |
||||
echo "=================================================================" |
||||
show_error |
||||
echo |
||||
done |
||||
echo "=================================================================" |
||||
exit 1 |
||||
else |
||||
rm -rf $suite_log |
||||
fi |
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
# Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
# |
||||
# Jansson is free software; you can redistribute it and/or modify |
||||
# it under the terms of the MIT license. See LICENSE for details. |
||||
|
||||
[ -z "$VALGRIND" ] && VALGRIND=0 |
||||
|
||||
VALGRIND_CMDLINE="valgrind --leak-check=full --show-reachable=yes --track-origins=yes -q" |
||||
|
||||
if [ $VALGRIND -eq 1 ]; then |
||||
test_runner="$VALGRIND_CMDLINE" |
||||
json_process="$VALGRIND_CMDLINE $json_process" |
||||
else |
||||
test_runner="" |
||||
fi |
||||
|
||||
valgrind_check() { |
||||
if [ $VALGRIND -eq 1 ]; then |
||||
# Check for Valgrind error output. The valgrind option |
||||
# --error-exitcode is not enough because Valgrind doesn't |
||||
# think unfreed allocs are errors. |
||||
if grep -E -q '^==[0-9]+== ' $1; then |
||||
touch $test_log/valgrind_error |
||||
return 1 |
||||
fi |
||||
fi |
||||
} |
||||
|
||||
valgrind_show_error() { |
||||
if [ $VALGRIND -eq 1 -a -f $test_log/valgrind_error ]; then |
||||
echo "valgrind detected an error" |
||||
return 0 |
||||
fi |
||||
return 1 |
||||
} |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
SUBDIRS = api |
||||
EXTRA_DIST = invalid invalid-unicode valid |
@ -0,0 +1,34 @@
@@ -0,0 +1,34 @@
|
||||
EXTRA_DIST = run check-exports |
||||
|
||||
check_PROGRAMS = \
|
||||
test_array \
|
||||
test_copy \
|
||||
test_dump \
|
||||
test_dump_callback \
|
||||
test_equal \
|
||||
test_load \
|
||||
test_loadb \
|
||||
test_load_callback \
|
||||
test_memory_funcs \
|
||||
test_number \
|
||||
test_object \
|
||||
test_pack \
|
||||
test_simple \
|
||||
test_unpack |
||||
|
||||
test_array_SOURCES = test_array.c util.h |
||||
test_copy_SOURCES = test_copy.c util.h |
||||
test_dump_SOURCES = test_dump.c util.h |
||||
test_dump_callback_SOURCES = test_dump_callback.c util.h |
||||
test_load_SOURCES = test_load.c util.h |
||||
test_loadb_SOURCES = test_loadb.c util.h |
||||
test_memory_funcs_SOURCES = test_memory_funcs.c util.h |
||||
test_number_SOURCES = test_number.c util.h |
||||
test_object_SOURCES = test_object.c util.h |
||||
test_pack_SOURCES = test_pack.c util.h |
||||
test_simple_SOURCES = test_simple.c util.h |
||||
test_unpack_SOURCES = test_unpack.c util.h |
||||
|
||||
AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src |
||||
LDFLAGS = -static # for speed and Valgrind |
||||
LDADD = $(top_builddir)/src/libjansson.la |
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
#!/bin/sh |
||||
# |
||||
# This test checks that libjansson.so exports the correct symbols. |
||||
# |
||||
|
||||
SOFILE="../src/.libs/libjansson.so" |
||||
|
||||
# The list of symbols, which the shared object should export, is read |
||||
# from the def file, which is used in Windows builds |
||||
grep 'json_' $top_srcdir/src/jansson.def \ |
||||
| sed -e 's/ //g' \ |
||||
| sort \ |
||||
>$test_log/exports |
||||
|
||||
nm -D $SOFILE >/dev/null >$test_log/symbols 2>/dev/null \ |
||||
|| exit 77 # Skip if "nm -D" doesn't seem to work |
||||
|
||||
grep ' [DT] ' $test_log/symbols | cut -d' ' -f3 | grep -v '^_' | sort >$test_log/output |
||||
|
||||
if ! cmp -s $test_log/exports $test_log/output; then |
||||
diff -u $test_log/exports $test_log/output >&2 |
||||
exit 1 |
||||
fi |
@ -0,0 +1,36 @@
@@ -0,0 +1,36 @@
|
||||
#!/bin/sh |
||||
# |
||||
# Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
# |
||||
# Jansson is free software; you can redistribute it and/or modify |
||||
# it under the terms of the MIT license. See LICENSE for details. |
||||
|
||||
is_test() { |
||||
case "$test_name" in |
||||
*.c|check-exports) |
||||
return 0 |
||||
;; |
||||
*) |
||||
return 1 |
||||
;; |
||||
esac |
||||
} |
||||
|
||||
run_test() { |
||||
if [ "$test_name" = "check-exports" ]; then |
||||
test_log=$test_log $test_path >$test_log/stdout 2>$test_log/stderr |
||||
else |
||||
$test_runner $suite_builddir/${test_name%.c} \ |
||||
>$test_log/stdout \ |
||||
2>$test_log/stderr \ |
||||
|| return 1 |
||||
valgrind_check $test_log/stderr || return 1 |
||||
fi |
||||
} |
||||
|
||||
show_error() { |
||||
valgrind_show_error && return |
||||
cat $test_log/stderr |
||||
} |
||||
|
||||
. $top_srcdir/test/scripts/run-tests.sh |
@ -0,0 +1,432 @@
@@ -0,0 +1,432 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
* |
||||
* Jansson is free software; you can redistribute it and/or modify |
||||
* it under the terms of the MIT license. See LICENSE for details. |
||||
*/ |
||||
|
||||
#include <jansson.h> |
||||
#include "util.h" |
||||
|
||||
static void test_misc(void) |
||||
{ |
||||
json_t *array, *five, *seven, *value; |
||||
size_t i; |
||||
|
||||
array = json_array(); |
||||
five = json_integer(5); |
||||
seven = json_integer(7); |
||||
|
||||
if(!array) |
||||
fail("unable to create array"); |
||||
if(!five || !seven) |
||||
fail("unable to create integer"); |
||||
|
||||
if(json_array_size(array) != 0) |
||||
fail("empty array has nonzero size"); |
||||
|
||||
if(!json_array_append(array, NULL)) |
||||
fail("able to append NULL"); |
||||
|
||||
if(json_array_append(array, five)) |
||||
fail("unable to append"); |
||||
|
||||
if(json_array_size(array) != 1) |
||||
fail("wrong array size"); |
||||
|
||||
value = json_array_get(array, 0); |
||||
if(!value) |
||||
fail("unable to get item"); |
||||
if(value != five) |
||||
fail("got wrong value"); |
||||
|
||||
if(json_array_append(array, seven)) |
||||
fail("unable to append value"); |
||||
|
||||
if(json_array_size(array) != 2) |
||||
fail("wrong array size"); |
||||
|
||||
value = json_array_get(array, 1); |
||||
if(!value) |
||||
fail("unable to get item"); |
||||
if(value != seven) |
||||
fail("got wrong value"); |
||||
|
||||
if(json_array_set(array, 0, seven)) |
||||
fail("unable to set value"); |
||||
|
||||
if(!json_array_set(array, 0, NULL)) |
||||
fail("able to set NULL"); |
||||
|
||||
if(json_array_size(array) != 2) |
||||
fail("wrong array size"); |
||||
|
||||
value = json_array_get(array, 0); |
||||
if(!value) |
||||
fail("unable to get item"); |
||||
if(value != seven) |
||||
fail("got wrong value"); |
||||
|
||||
if(json_array_get(array, 2) != NULL) |
||||
fail("able to get value out of bounds"); |
||||
|
||||
if(!json_array_set(array, 2, seven)) |
||||
fail("able to set value out of bounds"); |
||||
|
||||
for(i = 2; i < 30; i++) { |
||||
if(json_array_append(array, seven)) |
||||
fail("unable to append value"); |
||||
|
||||
if(json_array_size(array) != i + 1) |
||||
fail("wrong array size"); |
||||
} |
||||
|
||||
for(i = 0; i < 30; i++) { |
||||
value = json_array_get(array, i); |
||||
if(!value) |
||||
fail("unable to get item"); |
||||
if(value != seven) |
||||
fail("got wrong value"); |
||||
} |
||||
|
||||
if(json_array_set_new(array, 15, json_integer(123))) |
||||
fail("unable to set new value"); |
||||
|
||||
value = json_array_get(array, 15); |
||||
if(!json_is_integer(value) || json_integer_value(value) != 123) |
||||
fail("json_array_set_new works incorrectly"); |
||||
|
||||
if(!json_array_set_new(array, 15, NULL)) |
||||
fail("able to set_new NULL value"); |
||||
|
||||
if(json_array_append_new(array, json_integer(321))) |
||||
fail("unable to append new value"); |
||||
|
||||
value = json_array_get(array, json_array_size(array) - 1); |
||||
if(!json_is_integer(value) || json_integer_value(value) != 321) |
||||
fail("json_array_append_new works incorrectly"); |
||||
|
||||
if(!json_array_append_new(array, NULL)) |
||||
fail("able to append_new NULL value"); |
||||
|
||||
json_decref(five); |
||||
json_decref(seven); |
||||
json_decref(array); |
||||
} |
||||
|
||||
static void test_insert(void) |
||||
{ |
||||
json_t *array, *five, *seven, *eleven, *value; |
||||
int i; |
||||
|
||||
array = json_array(); |
||||
five = json_integer(5); |
||||
seven = json_integer(7); |
||||
eleven = json_integer(11); |
||||
|
||||
if(!array) |
||||
fail("unable to create array"); |
||||
if(!five || !seven || !eleven) |
||||
fail("unable to create integer"); |
||||
|
||||
|
||||
if(!json_array_insert(array, 1, five)) |
||||
fail("able to insert value out of bounds"); |
||||
|
||||
|
||||
if(json_array_insert(array, 0, five)) |
||||
fail("unable to insert value in an empty array"); |
||||
|
||||
if(json_array_get(array, 0) != five) |
||||
fail("json_array_insert works incorrectly"); |
||||
|
||||
if(json_array_size(array) != 1) |
||||
fail("array size is invalid after insertion"); |
||||
|
||||
|
||||
if(json_array_insert(array, 1, seven)) |
||||
fail("unable to insert value at the end of an array"); |
||||
|
||||
if(json_array_get(array, 0) != five) |
||||
fail("json_array_insert works incorrectly"); |
||||
|
||||
if(json_array_get(array, 1) != seven) |
||||
fail("json_array_insert works incorrectly"); |
||||
|
||||
if(json_array_size(array) != 2) |
||||
fail("array size is invalid after insertion"); |
||||
|
||||
|
||||
if(json_array_insert(array, 1, eleven)) |
||||
fail("unable to insert value in the middle of an array"); |
||||
|
||||
if(json_array_get(array, 0) != five) |
||||
fail("json_array_insert works incorrectly"); |
||||
|
||||
if(json_array_get(array, 1) != eleven) |
||||
fail("json_array_insert works incorrectly"); |
||||
|
||||
if(json_array_get(array, 2) != seven) |
||||
fail("json_array_insert works incorrectly"); |
||||
|
||||
if(json_array_size(array) != 3) |
||||
fail("array size is invalid after insertion"); |
||||
|
||||
|
||||
if(json_array_insert_new(array, 2, json_integer(123))) |
||||
fail("unable to insert value in the middle of an array"); |
||||
|
||||
value = json_array_get(array, 2); |
||||
if(!json_is_integer(value) || json_integer_value(value) != 123) |
||||
fail("json_array_insert_new works incorrectly"); |
||||
|
||||
if(json_array_size(array) != 4) |
||||
fail("array size is invalid after insertion"); |
||||
|
||||
|
||||
for(i = 0; i < 20; i++) { |
||||
if(json_array_insert(array, 0, seven)) |
||||
fail("unable to insert value at the begining of an array"); |
||||
} |
||||
|
||||
for(i = 0; i < 20; i++) { |
||||
if(json_array_get(array, i) != seven) |
||||
fail("json_aray_insert works incorrectly"); |
||||
} |
||||
|
||||
if(json_array_size(array) != 24) |
||||
fail("array size is invalid after loop insertion"); |
||||
|
||||
json_decref(five); |
||||
json_decref(seven); |
||||
json_decref(eleven); |
||||
json_decref(array); |
||||
} |
||||
|
||||
static void test_remove(void) |
||||
{ |
||||
json_t *array, *five, *seven; |
||||
int i; |
||||
|
||||
array = json_array(); |
||||
five = json_integer(5); |
||||
seven = json_integer(7); |
||||
|
||||
if(!array) |
||||
fail("unable to create array"); |
||||
if(!five) |
||||
fail("unable to create integer"); |
||||
if(!seven) |
||||
fail("unable to create integer"); |
||||
|
||||
|
||||
if(!json_array_remove(array, 0)) |
||||
fail("able to remove an unexisting index"); |
||||
|
||||
|
||||
if(json_array_append(array, five)) |
||||
fail("unable to append"); |
||||
|
||||
if(!json_array_remove(array, 1)) |
||||
fail("able to remove an unexisting index"); |
||||
|
||||
if(json_array_remove(array, 0)) |
||||
fail("unable to remove"); |
||||
|
||||
if(json_array_size(array) != 0) |
||||
fail("array size is invalid after removing"); |
||||
|
||||
|
||||
if(json_array_append(array, five) || |
||||
json_array_append(array, seven) || |
||||
json_array_append(array, five) || |
||||
json_array_append(array, seven)) |
||||
fail("unable to append"); |
||||
|
||||
if(json_array_remove(array, 2)) |
||||
fail("unable to remove"); |
||||
|
||||
if(json_array_size(array) != 3) |
||||
fail("array size is invalid after removing"); |
||||
|
||||
if(json_array_get(array, 0) != five || |
||||
json_array_get(array, 1) != seven || |
||||
json_array_get(array, 2) != seven) |
||||
fail("remove works incorrectly"); |
||||
|
||||
json_decref(array); |
||||
|
||||
array = json_array(); |
||||
for(i = 0; i < 4; i++) { |
||||
json_array_append(array, five); |
||||
json_array_append(array, seven); |
||||
} |
||||
if(json_array_size(array) != 8) |
||||
fail("unable to append 8 items to array"); |
||||
|
||||
/* Remove an element from a "full" array. */ |
||||
json_array_remove(array, 5); |
||||
|
||||
json_decref(five); |
||||
json_decref(seven); |
||||
json_decref(array); |
||||
} |
||||
|
||||
static void test_clear(void) |
||||
{ |
||||
json_t *array, *five, *seven; |
||||
int i; |
||||
|
||||
array = json_array(); |
||||
five = json_integer(5); |
||||
seven = json_integer(7); |
||||
|
||||
if(!array) |
||||
fail("unable to create array"); |
||||
if(!five || !seven) |
||||
fail("unable to create integer"); |
||||
|
||||
for(i = 0; i < 10; i++) { |
||||
if(json_array_append(array, five)) |
||||
fail("unable to append"); |
||||
} |
||||
for(i = 0; i < 10; i++) { |
||||
if(json_array_append(array, seven)) |
||||
fail("unable to append"); |
||||
} |
||||
|
||||
if(json_array_size(array) != 20) |
||||
fail("array size is invalid after appending"); |
||||
|
||||
if(json_array_clear(array)) |
||||
fail("unable to clear"); |
||||
|
||||
if(json_array_size(array) != 0) |
||||
fail("array size is invalid after clearing"); |
||||
|
||||
json_decref(five); |
||||
json_decref(seven); |
||||
json_decref(array); |
||||
} |
||||
|
||||
static void test_extend(void) |
||||
{ |
||||
json_t *array1, *array2, *five, *seven; |
||||
int i; |
||||
|
||||
array1 = json_array(); |
||||
array2 = json_array(); |
||||
five = json_integer(5); |
||||
seven = json_integer(7); |
||||
|
||||
if(!array1 || !array2) |
||||
fail("unable to create array"); |
||||
if(!five || !seven) |
||||
fail("unable to create integer"); |
||||
|
||||
for(i = 0; i < 10; i++) { |
||||
if(json_array_append(array1, five)) |
||||
fail("unable to append"); |
||||
} |
||||
for(i = 0; i < 10; i++) { |
||||
if(json_array_append(array2, seven)) |
||||
fail("unable to append"); |
||||
} |
||||
|
||||
if(json_array_size(array1) != 10 || json_array_size(array2) != 10) |
||||
fail("array size is invalid after appending"); |
||||
|
||||
if(json_array_extend(array1, array2)) |
||||
fail("unable to extend"); |
||||
|
||||
for(i = 0; i < 10; i++) { |
||||
if(json_array_get(array1, i) != five) |
||||
fail("invalid array contents after extending"); |
||||
} |
||||
for(i = 10; i < 20; i++) { |
||||
if(json_array_get(array1, i) != seven) |
||||
fail("invalid array contents after extending"); |
||||
} |
||||
|
||||
json_decref(five); |
||||
json_decref(seven); |
||||
json_decref(array1); |
||||
json_decref(array2); |
||||
} |
||||
|
||||
static void test_circular() |
||||
{ |
||||
json_t *array1, *array2; |
||||
|
||||
/* the simple cases are checked */ |
||||
|
||||
array1 = json_array(); |
||||
if(!array1) |
||||
fail("unable to create array"); |
||||
|
||||
if(json_array_append(array1, array1) == 0) |
||||
fail("able to append self"); |
||||
|
||||
if(json_array_insert(array1, 0, array1) == 0) |
||||
fail("able to insert self"); |
||||
|
||||
if(json_array_append_new(array1, json_true())) |
||||
fail("failed to append true"); |
||||
|
||||
if(json_array_set(array1, 0, array1) == 0) |
||||
fail("able to set self"); |
||||
|
||||
json_decref(array1); |
||||
|
||||
|
||||
/* create circular references */ |
||||
|
||||
array1 = json_array(); |
||||
array2 = json_array(); |
||||
if(!array1 || !array2) |
||||
fail("unable to create array"); |
||||
|
||||
if(json_array_append(array1, array2) || |
||||
json_array_append(array2, array1)) |
||||
fail("unable to append"); |
||||
|
||||
/* circularity is detected when dumping */ |
||||
if(json_dumps(array1, 0) != NULL) |
||||
fail("able to dump circulars"); |
||||
|
||||
/* decref twice to deal with the circular references */ |
||||
json_decref(array1); |
||||
json_decref(array2); |
||||
json_decref(array1); |
||||
} |
||||
|
||||
static void test_array_foreach() |
||||
{ |
||||
size_t index; |
||||
json_t *array1, *array2, *value; |
||||
|
||||
array1 = json_pack("[sisisi]", "foo", 1, "bar", 2, "baz", 3); |
||||
array2 = json_array(); |
||||
|
||||
json_array_foreach(array1, index, value) { |
||||
json_array_append(array2, value); |
||||
} |
||||
|
||||
if(!json_equal(array1, array2)) |
||||
fail("json_array_foreach failed to iterate all elements"); |
||||
|
||||
json_decref(array1); |
||||
json_decref(array2); |
||||
} |
||||
|
||||
|
||||
static void run_tests() |
||||
{ |
||||
test_misc(); |
||||
test_insert(); |
||||
test_remove(); |
||||
test_clear(); |
||||
test_extend(); |
||||
test_circular(); |
||||
test_array_foreach(); |
||||
} |
@ -0,0 +1,318 @@
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
* |
||||
* Jansson is free software; you can redistribute it and/or modify |
||||
* it under the terms of the MIT license. See LICENSE for details. |
||||
*/ |
||||
|
||||
#include <string.h> |
||||
#include <jansson.h> |
||||
#include "util.h" |
||||
|
||||
static void test_copy_simple(void) |
||||
{ |
||||
json_t *value, *copy; |
||||
|
||||
if(json_copy(NULL)) |
||||
fail("copying NULL doesn't return NULL"); |
||||
|
||||
/* true */ |
||||
value = json_true(); |
||||
copy = json_copy(value); |
||||
if(value != copy) |
||||
fail("copying true failed"); |
||||
json_decref(value); |
||||
json_decref(copy); |
||||
|
||||
/* false */ |
||||
value = json_false(); |
||||
copy = json_copy(value); |
||||
if(value != copy) |
||||
fail("copying false failed"); |
||||
json_decref(value); |
||||
json_decref(copy); |
||||
|
||||
/* null */ |
||||
value = json_null(); |
||||
copy = json_copy(value); |
||||
if(value != copy) |
||||
fail("copying null failed"); |
||||
json_decref(value); |
||||
json_decref(copy); |
||||
|
||||
/* string */ |
||||
value = json_string("foo"); |
||||
if(!value) |
||||
fail("unable to create a string"); |
||||
copy = json_copy(value); |
||||
if(!copy) |
||||
fail("unable to copy a string"); |
||||
if(copy == value) |
||||
fail("copying a string doesn't copy"); |
||||
if(!json_equal(copy, value)) |
||||
fail("copying a string produces an inequal copy"); |
||||
if(value->refcount != 1 || copy->refcount != 1) |
||||
fail("invalid refcounts"); |
||||
json_decref(value); |
||||
json_decref(copy); |
||||
|
||||
/* integer */ |
||||
value = json_integer(543); |
||||
if(!value) |
||||
fail("unable to create an integer"); |
||||
copy = json_copy(value); |
||||
if(!copy) |
||||
fail("unable to copy an integer"); |
||||
if(copy == value) |
||||
fail("copying an integer doesn't copy"); |
||||
if(!json_equal(copy, value)) |
||||
fail("copying an integer produces an inequal copy"); |
||||
if(value->refcount != 1 || copy->refcount != 1) |
||||
fail("invalid refcounts"); |
||||
json_decref(value); |
||||
json_decref(copy); |
||||
|
||||
/* real */ |
||||
value = json_real(123e9); |
||||
if(!value) |
||||
fail("unable to create a real"); |
||||
copy = json_copy(value); |
||||
if(!copy) |
||||
fail("unable to copy a real"); |
||||
if(copy == value) |
||||
fail("copying a real doesn't copy"); |
||||
if(!json_equal(copy, value)) |
||||
fail("copying a real produces an inequal copy"); |
||||
if(value->refcount != 1 || copy->refcount != 1) |
||||
fail("invalid refcounts"); |
||||
json_decref(value); |
||||
json_decref(copy); |
||||
} |
||||
|
||||
static void test_deep_copy_simple(void) |
||||
{ |
||||
json_t *value, *copy; |
||||
|
||||
if(json_deep_copy(NULL)) |
||||
fail("deep copying NULL doesn't return NULL"); |
||||
|
||||
/* true */ |
||||
value = json_true(); |
||||
copy = json_deep_copy(value); |
||||
if(value != copy) |
||||
fail("deep copying true failed"); |
||||
json_decref(value); |
||||
json_decref(copy); |
||||
|
||||
/* false */ |
||||
value = json_false(); |
||||
copy = json_deep_copy(value); |
||||
if(value != copy) |
||||
fail("deep copying false failed"); |
||||
json_decref(value); |
||||
json_decref(copy); |
||||
|
||||
/* null */ |
||||
value = json_null(); |
||||
copy = json_deep_copy(value); |
||||
if(value != copy) |
||||
fail("deep copying null failed"); |
||||
json_decref(value); |
||||
json_decref(copy); |
||||
|
||||
/* string */ |
||||
value = json_string("foo"); |
||||
if(!value) |
||||
fail("unable to create a string"); |
||||
copy = json_deep_copy(value); |
||||
if(!copy) |
||||
fail("unable to deep copy a string"); |
||||
if(copy == value) |
||||
fail("deep copying a string doesn't copy"); |
||||
if(!json_equal(copy, value)) |
||||
fail("deep copying a string produces an inequal copy"); |
||||
if(value->refcount != 1 || copy->refcount != 1) |
||||
fail("invalid refcounts"); |
||||
json_decref(value); |
||||
json_decref(copy); |
||||
|
||||
/* integer */ |
||||
value = json_integer(543); |
||||
if(!value) |
||||
fail("unable to create an integer"); |
||||
copy = json_deep_copy(value); |
||||
if(!copy) |
||||
fail("unable to deep copy an integer"); |
||||
if(copy == value) |
||||
fail("deep copying an integer doesn't copy"); |
||||
if(!json_equal(copy, value)) |
||||
fail("deep copying an integer produces an inequal copy"); |
||||
if(value->refcount != 1 || copy->refcount != 1) |
||||
fail("invalid refcounts"); |
||||
json_decref(value); |
||||
json_decref(copy); |
||||
|
||||
/* real */ |
||||
value = json_real(123e9); |
||||
if(!value) |
||||
fail("unable to create a real"); |
||||
copy = json_deep_copy(value); |
||||
if(!copy) |
||||
fail("unable to deep copy a real"); |
||||
if(copy == value) |
||||
fail("deep copying a real doesn't copy"); |
||||
if(!json_equal(copy, value)) |
||||
fail("deep copying a real produces an inequal copy"); |
||||
if(value->refcount != 1 || copy->refcount != 1) |
||||
fail("invalid refcounts"); |
||||
json_decref(value); |
||||
json_decref(copy); |
||||
} |
||||
|
||||
static void test_copy_array(void) |
||||
{ |
||||
const char *json_array_text = "[1, \"foo\", 3.141592, {\"foo\": \"bar\"}]"; |
||||
|
||||
json_t *array, *copy; |
||||
size_t i; |
||||
|
||||
array = json_loads(json_array_text, 0, NULL); |
||||
if(!array) |
||||
fail("unable to parse an array"); |
||||
|
||||
copy = json_copy(array); |
||||
if(!copy) |
||||
fail("unable to copy an array"); |
||||
if(copy == array) |
||||
fail("copying an array doesn't copy"); |
||||
if(!json_equal(copy, array)) |
||||
fail("copying an array produces an inequal copy"); |
||||
|
||||
for(i = 0; i < json_array_size(copy); i++) |
||||
{ |
||||
if(json_array_get(array, i) != json_array_get(copy, i)) |
||||
fail("copying an array modifies its elements"); |
||||
} |
||||
|
||||
json_decref(array); |
||||
json_decref(copy); |
||||
} |
||||
|
||||
static void test_deep_copy_array(void) |
||||
{ |
||||
const char *json_array_text = "[1, \"foo\", 3.141592, {\"foo\": \"bar\"}]"; |
||||
|
||||
json_t *array, *copy; |
||||
size_t i; |
||||
|
||||
array = json_loads(json_array_text, 0, NULL); |
||||
if(!array) |
||||
fail("unable to parse an array"); |
||||
|
||||
copy = json_deep_copy(array); |
||||
if(!copy) |
||||
fail("unable to deep copy an array"); |
||||
if(copy == array) |
||||
fail("deep copying an array doesn't copy"); |
||||
if(!json_equal(copy, array)) |
||||
fail("deep copying an array produces an inequal copy"); |
||||
|
||||
for(i = 0; i < json_array_size(copy); i++) |
||||
{ |
||||
if(json_array_get(array, i) == json_array_get(copy, i)) |
||||
fail("deep copying an array doesn't copy its elements"); |
||||
} |
||||
|
||||
json_decref(array); |
||||
json_decref(copy); |
||||
} |
||||
|
||||
static void test_copy_object(void) |
||||
{ |
||||
const char *json_object_text = |
||||
"{\"foo\": \"bar\", \"a\": 1, \"b\": 3.141592, \"c\": [1,2,3,4]}"; |
||||
|
||||
json_t *object, *copy; |
||||
void *iter; |
||||
|
||||
object = json_loads(json_object_text, 0, NULL); |
||||
if(!object) |
||||
fail("unable to parse an object"); |
||||
|
||||
copy = json_copy(object); |
||||
if(!copy) |
||||
fail("unable to copy an object"); |
||||
if(copy == object) |
||||
fail("copying an object doesn't copy"); |
||||
if(!json_equal(copy, object)) |
||||
fail("copying an object produces an inequal copy"); |
||||
|
||||
iter = json_object_iter(object); |
||||
while(iter) |
||||
{ |
||||
const char *key; |
||||
json_t *value1, *value2; |
||||
|
||||
key = json_object_iter_key(iter); |
||||
value1 = json_object_iter_value(iter); |
||||
value2 = json_object_get(copy, key); |
||||
|
||||
if(value1 != value2) |
||||
fail("deep copying an object modifies its items"); |
||||
|
||||
iter = json_object_iter_next(object, iter); |
||||
} |
||||
|
||||
json_decref(object); |
||||
json_decref(copy); |
||||
} |
||||
|
||||
static void test_deep_copy_object(void) |
||||
{ |
||||
const char *json_object_text = |
||||
"{\"foo\": \"bar\", \"a\": 1, \"b\": 3.141592, \"c\": [1,2,3,4]}"; |
||||
|
||||
json_t *object, *copy; |
||||
void *iter; |
||||
|
||||
object = json_loads(json_object_text, 0, NULL); |
||||
if(!object) |
||||
fail("unable to parse an object"); |
||||
|
||||
copy = json_deep_copy(object); |
||||
if(!copy) |
||||
fail("unable to deep copy an object"); |
||||
if(copy == object) |
||||
fail("deep copying an object doesn't copy"); |
||||
if(!json_equal(copy, object)) |
||||
fail("deep copying an object produces an inequal copy"); |
||||
|
||||
iter = json_object_iter(object); |
||||
while(iter) |
||||
{ |
||||
const char *key; |
||||
json_t *value1, *value2; |
||||
|
||||
key = json_object_iter_key(iter); |
||||
value1 = json_object_iter_value(iter); |
||||
value2 = json_object_get(copy, key); |
||||
|
||||
if(value1 == value2) |
||||
fail("deep copying an object doesn't copy its items"); |
||||
|
||||
iter = json_object_iter_next(object, iter); |
||||
} |
||||
|
||||
json_decref(object); |
||||
json_decref(copy); |
||||
} |
||||
|
||||
static void run_tests() |
||||
{ |
||||
test_copy_simple(); |
||||
test_deep_copy_simple(); |
||||
test_copy_array(); |
||||
test_deep_copy_array(); |
||||
test_copy_object(); |
||||
test_deep_copy_object(); |
||||
} |
@ -0,0 +1,190 @@
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
* |
||||
* Jansson is free software; you can redistribute it and/or modify |
||||
* it under the terms of the MIT license. See LICENSE for details. |
||||
*/ |
||||
|
||||
#include <jansson.h> |
||||
#include <string.h> |
||||
#include "util.h" |
||||
|
||||
static int encode_null_callback(const char *buffer, size_t size, void *data) |
||||
{ |
||||
(void)buffer; |
||||
(void)size; |
||||
(void)data; |
||||
return 0; |
||||
} |
||||
|
||||
static void encode_null() |
||||
{ |
||||
if(json_dumps(NULL, JSON_ENCODE_ANY) != NULL) |
||||
fail("json_dumps didn't fail for NULL"); |
||||
|
||||
if(json_dumpf(NULL, stderr, JSON_ENCODE_ANY) != -1) |
||||
fail("json_dumpf didn't fail for NULL"); |
||||
|
||||
/* Don't test json_dump_file to avoid creating a file */ |
||||
|
||||
if(json_dump_callback(NULL, encode_null_callback, NULL, JSON_ENCODE_ANY) != -1) |
||||
fail("json_dump_callback didn't fail for NULL"); |
||||
} |
||||
|
||||
|
||||
static void encode_twice() |
||||
{ |
||||
/* Encode an empty object/array, add an item, encode again */ |
||||
|
||||
json_t *json; |
||||
char *result; |
||||
|
||||
json = json_object(); |
||||
result = json_dumps(json, 0); |
||||
if(!result || strcmp(result, "{}")) |
||||
fail("json_dumps failed"); |
||||
free(result); |
||||
|
||||
json_object_set_new(json, "foo", json_integer(5)); |
||||
result = json_dumps(json, 0); |
||||
if(!result || strcmp(result, "{\"foo\": 5}")) |
||||
fail("json_dumps failed"); |
||||
free(result); |
||||
|
||||
json_decref(json); |
||||
|
||||
json = json_array(); |
||||
result = json_dumps(json, 0); |
||||
if(!result || strcmp(result, "[]")) |
||||
fail("json_dumps failed"); |
||||
free(result); |
||||
|
||||
json_array_append_new(json, json_integer(5)); |
||||
result = json_dumps(json, 0); |
||||
if(!result || strcmp(result, "[5]")) |
||||
fail("json_dumps failed"); |
||||
free(result); |
||||
|
||||
json_decref(json); |
||||
} |
||||
|
||||
static void circular_references() |
||||
{ |
||||
/* Construct a JSON object/array with a circular reference:
|
||||
|
||||
object: {"a": {"b": {"c": <circular reference to $.a>}}} |
||||
array: [[[<circular reference to the $[0] array>]]] |
||||
|
||||
Encode it, remove the circular reference and encode again. |
||||
*/ |
||||
|
||||
json_t *json; |
||||
char *result; |
||||
|
||||
json = json_object(); |
||||
json_object_set_new(json, "a", json_object()); |
||||
json_object_set_new(json_object_get(json, "a"), "b", json_object()); |
||||
json_object_set(json_object_get(json_object_get(json, "a"), "b"), "c", |
||||
json_object_get(json, "a")); |
||||
|
||||
if(json_dumps(json, 0)) |
||||
fail("json_dumps encoded a circular reference!"); |
||||
|
||||
json_object_del(json_object_get(json_object_get(json, "a"), "b"), "c"); |
||||
|
||||
result = json_dumps(json, 0); |
||||
if(!result || strcmp(result, "{\"a\": {\"b\": {}}}")) |
||||
fail("json_dumps failed!"); |
||||
free(result); |
||||
|
||||
json_decref(json); |
||||
|
||||
json = json_array(); |
||||
json_array_append_new(json, json_array()); |
||||
json_array_append_new(json_array_get(json, 0), json_array()); |
||||
json_array_append(json_array_get(json_array_get(json, 0), 0), |
||||
json_array_get(json, 0)); |
||||
|
||||
if(json_dumps(json, 0)) |
||||
fail("json_dumps encoded a circular reference!"); |
||||
|
||||
json_array_remove(json_array_get(json_array_get(json, 0), 0), 0); |
||||
|
||||
result = json_dumps(json, 0); |
||||
if(!result || strcmp(result, "[[[]]]")) |
||||
fail("json_dumps failed!"); |
||||
free(result); |
||||
|
||||
json_decref(json); |
||||
} |
||||
|
||||
static void encode_other_than_array_or_object() |
||||
{ |
||||
/* Encoding anything other than array or object should only
|
||||
* succeed if the JSON_ENCODE_ANY flag is used */ |
||||
|
||||
json_t *json; |
||||
FILE *fp = NULL; |
||||
char *result; |
||||
|
||||
json = json_string("foo"); |
||||
if(json_dumps(json, 0) != NULL) |
||||
fail("json_dumps encoded a string!"); |
||||
if(json_dumpf(json, fp, 0) == 0) |
||||
fail("json_dumpf encoded a string!"); |
||||
|
||||
result = json_dumps(json, JSON_ENCODE_ANY); |
||||
if(!result || strcmp(result, "\"foo\"") != 0) |
||||
fail("json_dumps failed to encode a string with JSON_ENCODE_ANY"); |
||||
|
||||
free(result); |
||||
json_decref(json); |
||||
|
||||
json = json_integer(42); |
||||
if(json_dumps(json, 0) != NULL) |
||||
fail("json_dumps encoded an integer!"); |
||||
if(json_dumpf(json, fp, 0) == 0) |
||||
fail("json_dumpf encoded an integer!"); |
||||
|
||||
result = json_dumps(json, JSON_ENCODE_ANY); |
||||
if(!result || strcmp(result, "42") != 0) |
||||
fail("json_dumps failed to encode an integer with JSON_ENCODE_ANY"); |
||||
|
||||
free(result); |
||||
json_decref(json); |
||||
|
||||
|
||||
} |
||||
|
||||
static void escape_slashes() |
||||
{ |
||||
/* Test dump escaping slashes */ |
||||
|
||||
json_t *json; |
||||
char *result; |
||||
|
||||
json = json_object(); |
||||
json_object_set_new(json, "url", json_string("https://github.com/akheron/jansson")); |
||||
|
||||
result = json_dumps(json, 0); |
||||
if(!result || strcmp(result, "{\"url\": \"https://github.com/akheron/jansson\"}")) |
||||
fail("json_dumps failed to not escape slashes"); |
||||
|
||||
free(result); |
||||
|
||||
result = json_dumps(json, JSON_ESCAPE_SLASH); |
||||
if(!result || strcmp(result, "{\"url\": \"https:\\/\\/github.com\\/akheron\\/jansson\"}")) |
||||
fail("json_dumps failed to escape slashes"); |
||||
|
||||
free(result); |
||||
json_decref(json); |
||||
} |
||||
|
||||
static void run_tests() |
||||
{ |
||||
encode_null(); |
||||
encode_twice(); |
||||
circular_references(); |
||||
encode_other_than_array_or_object(); |
||||
escape_slashes(); |
||||
} |
@ -0,0 +1,81 @@
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
* |
||||
* Jansson is free software; you can redistribute it and/or modify |
||||
* it under the terms of the MIT license. See LICENSE for details. |
||||
*/ |
||||
|
||||
#include <jansson.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include "util.h" |
||||
|
||||
struct my_sink { |
||||
char *buf; |
||||
size_t off; |
||||
size_t cap; |
||||
}; |
||||
|
||||
static int my_writer(const char *buffer, size_t len, void *data) { |
||||
struct my_sink *s = data; |
||||
if (len > s->cap - s->off) { |
||||
return -1; |
||||
} |
||||
memcpy(s->buf + s->off, buffer, len); |
||||
s->off += len; |
||||
return 0; |
||||
} |
||||
|
||||
static void run_tests() |
||||
{ |
||||
struct my_sink s; |
||||
json_t *json; |
||||
const char str[] = "[\"A\", {\"B\": \"C\", \"e\": false}, 1, null, \"foo\"]"; |
||||
char *dumped_to_string; |
||||
|
||||
json = json_loads(str, 0, NULL); |
||||
if(!json) { |
||||
fail("json_loads failed"); |
||||
} |
||||
|
||||
dumped_to_string = json_dumps(json, 0); |
||||
if (!dumped_to_string) { |
||||
json_decref(json); |
||||
fail("json_dumps failed"); |
||||
} |
||||
|
||||
s.off = 0; |
||||
s.cap = strlen(dumped_to_string); |
||||
s.buf = malloc(s.cap); |
||||
if (!s.buf) { |
||||
json_decref(json); |
||||
free(dumped_to_string); |
||||
fail("malloc failed"); |
||||
} |
||||
|
||||
if (json_dump_callback(json, my_writer, &s, 0) == -1) { |
||||
json_decref(json); |
||||
free(dumped_to_string); |
||||
free(s.buf); |
||||
fail("json_dump_callback failed on an exact-length sink buffer"); |
||||
} |
||||
|
||||
if (strncmp(dumped_to_string, s.buf, s.off) != 0) { |
||||
json_decref(json); |
||||
free(dumped_to_string); |
||||
free(s.buf); |
||||
fail("json_dump_callback and json_dumps did not produce identical output"); |
||||
} |
||||
|
||||
s.off = 1; |
||||
if (json_dump_callback(json, my_writer, &s, 0) != -1) { |
||||
json_decref(json); |
||||
free(dumped_to_string); |
||||
free(s.buf); |
||||
fail("json_dump_callback succeeded on a short buffer when it should have failed"); |
||||
} |
||||
|
||||
json_decref(json); |
||||
free(dumped_to_string); |
||||
free(s.buf); |
||||
} |
@ -0,0 +1,189 @@
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
* |
||||
* Jansson is free software; you can redistribute it and/or modify |
||||
* it under the terms of the MIT license. See LICENSE for details. |
||||
*/ |
||||
|
||||
#include <jansson.h> |
||||
#include "util.h" |
||||
|
||||
static void test_equal_simple() |
||||
{ |
||||
json_t *value1, *value2; |
||||
|
||||
if(json_equal(NULL, NULL)) |
||||
fail("json_equal fails for two NULLs"); |
||||
|
||||
value1 = json_true(); |
||||
if(json_equal(value1, NULL) || json_equal(NULL, value1)) |
||||
fail("json_equal fails for NULL"); |
||||
|
||||
/* this covers true, false and null as they are singletons */ |
||||
if(!json_equal(value1, value1)) |
||||
fail("identical objects are not equal"); |
||||
json_decref(value1); |
||||
|
||||
/* integer */ |
||||
value1 = json_integer(1); |
||||
value2 = json_integer(1); |
||||
if(!value1 || !value2) |
||||
fail("unable to create integers"); |
||||
if(!json_equal(value1, value2)) |
||||
fail("json_equal fails for two equal integers"); |
||||
json_decref(value2); |
||||
|
||||
value2 = json_integer(2); |
||||
if(!value2) |
||||
fail("unable to create an integer"); |
||||
if(json_equal(value1, value2)) |
||||
fail("json_equal fails for two inequal integers"); |
||||
|
||||
json_decref(value1); |
||||
json_decref(value2); |
||||
|
||||
/* real */ |
||||
value1 = json_real(1.2); |
||||
value2 = json_real(1.2); |
||||
if(!value1 || !value2) |
||||
fail("unable to create reals"); |
||||
if(!json_equal(value1, value2)) |
||||
fail("json_equal fails for two equal reals"); |
||||
json_decref(value2); |
||||
|
||||
value2 = json_real(3.141592); |
||||
if(!value2) |
||||
fail("unable to create an real"); |
||||
if(json_equal(value1, value2)) |
||||
fail("json_equal fails for two inequal reals"); |
||||
|
||||
json_decref(value1); |
||||
json_decref(value2); |
||||
|
||||
/* string */ |
||||
value1 = json_string("foo"); |
||||
value2 = json_string("foo"); |
||||
if(!value1 || !value2) |
||||
fail("unable to create strings"); |
||||
if(!json_equal(value1, value2)) |
||||
fail("json_equal fails for two equal strings"); |
||||
json_decref(value2); |
||||
|
||||
value2 = json_string("bar"); |
||||
if(!value2) |
||||
fail("unable to create an string"); |
||||
if(json_equal(value1, value2)) |
||||
fail("json_equal fails for two inequal strings"); |
||||
|
||||
json_decref(value1); |
||||
json_decref(value2); |
||||
} |
||||
|
||||
static void test_equal_array() |
||||
{ |
||||
json_t *array1, *array2; |
||||
|
||||
array1 = json_array(); |
||||
array2 = json_array(); |
||||
if(!array1 || !array2) |
||||
fail("unable to create arrays"); |
||||
|
||||
if(!json_equal(array1, array2)) |
||||
fail("json_equal fails for two empty arrays"); |
||||
|
||||
json_array_append_new(array1, json_integer(1)); |
||||
json_array_append_new(array2, json_integer(1)); |
||||
json_array_append_new(array1, json_string("foo")); |
||||
json_array_append_new(array2, json_string("foo")); |
||||
json_array_append_new(array1, json_integer(2)); |
||||
json_array_append_new(array2, json_integer(2)); |
||||
if(!json_equal(array1, array2)) |
||||
fail("json_equal fails for two equal arrays"); |
||||
|
||||
json_array_remove(array2, 2); |
||||
if(json_equal(array1, array2)) |
||||
fail("json_equal fails for two inequal arrays"); |
||||
|
||||
json_array_append_new(array2, json_integer(3)); |
||||
if(json_equal(array1, array2)) |
||||
fail("json_equal fails for two inequal arrays"); |
||||
|
||||
json_decref(array1); |
||||
json_decref(array2); |
||||
} |
||||
|
||||
static void test_equal_object() |
||||
{ |
||||
json_t *object1, *object2; |
||||
|
||||
object1 = json_object(); |
||||
object2 = json_object(); |
||||
if(!object1 || !object2) |
||||
fail("unable to create objects"); |
||||
|
||||
if(!json_equal(object1, object2)) |
||||
fail("json_equal fails for two empty objects"); |
||||
|
||||
json_object_set_new(object1, "a", json_integer(1)); |
||||
json_object_set_new(object2, "a", json_integer(1)); |
||||
json_object_set_new(object1, "b", json_string("foo")); |
||||
json_object_set_new(object2, "b", json_string("foo")); |
||||
json_object_set_new(object1, "c", json_integer(2)); |
||||
json_object_set_new(object2, "c", json_integer(2)); |
||||
if(!json_equal(object1, object2)) |
||||
fail("json_equal fails for two equal objects"); |
||||
|
||||
json_object_del(object2, "c"); |
||||
if(json_equal(object1, object2)) |
||||
fail("json_equal fails for two inequal objects"); |
||||
|
||||
json_object_set_new(object2, "c", json_integer(3)); |
||||
if(json_equal(object1, object2)) |
||||
fail("json_equal fails for two inequal objects"); |
||||
|
||||
json_object_del(object2, "c"); |
||||
json_object_set_new(object2, "d", json_integer(2)); |
||||
if(json_equal(object1, object2)) |
||||
fail("json_equal fails for two inequal objects"); |
||||
|
||||
json_decref(object1); |
||||
json_decref(object2); |
||||
} |
||||
|
||||
static void test_equal_complex() |
||||
{ |
||||
json_t *value1, *value2; |
||||
|
||||
const char *complex_json = |
||||
"{" |
||||
" \"integer\": 1, " |
||||
" \"real\": 3.141592, " |
||||
" \"string\": \"foobar\", " |
||||
" \"true\": true, " |
||||
" \"object\": {" |
||||
" \"array-in-object\": [1,true,\"foo\",{}]," |
||||
" \"object-in-object\": {\"foo\": \"bar\"}" |
||||
" }," |
||||
" \"array\": [\"foo\", false, null, 1.234]" |
||||
"}"; |
||||
|
||||
value1 = json_loads(complex_json, 0, NULL); |
||||
value2 = 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"); |
||||
|
||||
json_decref(value1); |
||||
json_decref(value2); |
||||
|
||||
/* TODO: There's no negative test case here */ |
||||
} |
||||
|
||||
static void run_tests() |
||||
{ |
||||
test_equal_simple(); |
||||
test_equal_array(); |
||||
test_equal_object(); |
||||
test_equal_complex(); |
||||
} |
@ -0,0 +1,166 @@
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
* |
||||
* Jansson is free software; you can redistribute it and/or modify |
||||
* it under the terms of the MIT license. See LICENSE for details. |
||||
*/ |
||||
|
||||
#include <jansson.h> |
||||
#include <string.h> |
||||
#include "util.h" |
||||
|
||||
static void file_not_found() |
||||
{ |
||||
json_t *json; |
||||
json_error_t error; |
||||
char *pos; |
||||
|
||||
json = json_load_file("/path/to/nonexistent/file.json", 0, &error); |
||||
if(json) |
||||
fail("json_load_file returned non-NULL for a nonexistent file"); |
||||
if(error.line != -1) |
||||
fail("json_load_file returned an invalid line number"); |
||||
|
||||
/* The error message is locale specific, only check the beginning
|
||||
of the error message. */ |
||||
|
||||
pos = strchr(error.text, ':'); |
||||
if(!pos) |
||||
fail("json_load_file returne an invalid error message"); |
||||
|
||||
*pos = '\0'; |
||||
|
||||
if(strcmp(error.text, "unable to open /path/to/nonexistent/file.json") != 0) |
||||
fail("json_load_file returned an invalid error message"); |
||||
} |
||||
|
||||
static void reject_duplicates() |
||||
{ |
||||
json_error_t error; |
||||
|
||||
if(json_loads("{\"foo\": 1, \"foo\": 2}", JSON_REJECT_DUPLICATES, &error)) |
||||
fail("json_loads did not detect a duplicate key"); |
||||
check_error("duplicate object key near '\"foo\"'", "<string>", 1, 16, 16); |
||||
} |
||||
|
||||
static void disable_eof_check() |
||||
{ |
||||
json_error_t error; |
||||
json_t *json; |
||||
|
||||
const char *text = "{\"foo\": 1} garbage"; |
||||
|
||||
if(json_loads(text, 0, &error)) |
||||
fail("json_loads did not detect garbage after JSON text"); |
||||
check_error("end of file expected near 'garbage'", "<string>", 1, 18, 18); |
||||
|
||||
json = json_loads(text, JSON_DISABLE_EOF_CHECK, &error); |
||||
if(!json) |
||||
fail("json_loads failed with JSON_DISABLE_EOF_CHECK"); |
||||
|
||||
json_decref(json); |
||||
} |
||||
|
||||
static void decode_any() |
||||
{ |
||||
json_t *json; |
||||
json_error_t error; |
||||
|
||||
json = json_loads("\"foo\"", JSON_DECODE_ANY, &error); |
||||
if (!json || !json_is_string(json)) |
||||
fail("json_load decoded any failed - string"); |
||||
json_decref(json); |
||||
|
||||
json = json_loads("42", JSON_DECODE_ANY, &error); |
||||
if (!json || !json_is_integer(json)) |
||||
fail("json_load decoded any failed - integer"); |
||||
json_decref(json); |
||||
|
||||
json = json_loads("true", JSON_DECODE_ANY, &error); |
||||
if (!json || !json_is_true(json)) |
||||
fail("json_load decoded any failed - boolean"); |
||||
json_decref(json); |
||||
|
||||
json = json_loads("null", JSON_DECODE_ANY, &error); |
||||
if (!json || !json_is_null(json)) |
||||
fail("json_load decoded any failed - null"); |
||||
json_decref(json); |
||||
} |
||||
|
||||
static void decode_int_as_real() |
||||
{ |
||||
json_t *json; |
||||
json_error_t error; |
||||
|
||||
#if JSON_INTEGER_IS_LONG_LONG |
||||
const char *imprecise; |
||||
json_int_t expected; |
||||
#endif |
||||
|
||||
json = json_loads("42", JSON_DECODE_INT_AS_REAL | JSON_DECODE_ANY, &error); |
||||
if (!json || !json_is_real(json) || json_real_value(json) != 42.0) |
||||
fail("json_load decode int as real failed - int"); |
||||
json_decref(json); |
||||
|
||||
#if JSON_INTEGER_IS_LONG_LONG |
||||
/* This number cannot be represented exactly by a double */ |
||||
imprecise = "9007199254740993"; |
||||
expected = 9007199254740992ll; |
||||
|
||||
json = json_loads(imprecise, JSON_DECODE_INT_AS_REAL | JSON_DECODE_ANY, |
||||
&error); |
||||
if (!json || !json_is_real(json) || expected != (json_int_t)json_real_value(json)) |
||||
fail("json_load decode int as real failed - expected imprecision"); |
||||
json_decref(json); |
||||
#endif |
||||
} |
||||
|
||||
static void load_wrong_args() |
||||
{ |
||||
json_t *json; |
||||
json_error_t error; |
||||
|
||||
json = json_loads(NULL, 0, &error); |
||||
if (json) |
||||
fail("json_loads should return NULL if the first argument is NULL"); |
||||
|
||||
json = json_loadb(NULL, 0, 0, &error); |
||||
if (json) |
||||
fail("json_loadb should return NULL if the first argument is NULL"); |
||||
|
||||
json = json_loadf(NULL, 0, &error); |
||||
if (json) |
||||
fail("json_loadf should return NULL if the first argument is NULL"); |
||||
|
||||
json = json_load_file(NULL, 0, &error); |
||||
if (json) |
||||
fail("json_loadf should return NULL if the first argument is NULL"); |
||||
} |
||||
|
||||
static void position() |
||||
{ |
||||
json_t *json; |
||||
size_t flags = JSON_DISABLE_EOF_CHECK; |
||||
json_error_t error; |
||||
|
||||
json = json_loads("{\"foo\": \"bar\"}", 0, &error); |
||||
if(error.position != 14) |
||||
fail("json_loads returned a wrong position"); |
||||
json_decref(json); |
||||
|
||||
json = json_loads("{\"foo\": \"bar\"} baz quux", flags, &error); |
||||
if(error.position != 14) |
||||
fail("json_loads returned a wrong position"); |
||||
json_decref(json); |
||||
} |
||||
|
||||
static void run_tests() |
||||
{ |
||||
file_not_found(); |
||||
reject_duplicates(); |
||||
disable_eof_check(); |
||||
decode_any(); |
||||
decode_int_as_real(); |
||||
load_wrong_args(); |
||||
position(); |
||||
} |
@ -0,0 +1,75 @@
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org> |
||||
* |
||||
* Jansson is free software; you can redistribute it and/or modify |
||||
* it under the terms of the MIT license. See LICENSE for details. |
||||
*/ |
||||
|
||||
#include <jansson.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include "util.h" |
||||
|
||||
struct my_source { |
||||
const char *buf; |
||||
size_t off; |
||||
size_t cap; |
||||
}; |
||||
|
||||
static const char my_str[] = "[\"A\", {\"B\": \"C\", \"e\": false}, 1, null, \"foo\"]"; |
||||
|
||||
static size_t greedy_reader(void *buf, size_t buflen, void *arg) |
||||
{ |
||||
struct my_source *s = arg; |
||||
if (buflen > s->cap - s->off) |
||||
buflen = s->cap - s->off; |
||||
if (buflen > 0) { |
||||
memcpy(buf, s->buf + s->off, buflen); |
||||
s->off += buflen; |
||||
return buflen; |
||||
} else { |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
static void run_tests() |
||||
{ |
||||
struct my_source s; |
||||
json_t *json; |
||||
json_error_t error; |
||||
|
||||
s.off = 0; |
||||
s.cap = strlen(my_str); |
||||
s.buf = my_str; |
||||
|
||||
json = json_load_callback(greedy_reader, &s, 0, &error); |
||||
|
||||
if (!json) |
||||
fail("json_load_callback failed on a valid callback"); |
||||
json_decref(json); |
||||
|
||||
s.off = 0; |
||||
s.cap = strlen(my_str) - 1; |
||||
s.buf = my_str; |
||||
|
||||
json = json_load_callback(greedy_reader, &s, 0, &error); |
||||
if (json) { |
||||
json_decref(json); |
||||
fail("json_load_callback should have failed on an incomplete stream, but it didn't"); |
||||
} |
||||
if (strcmp(error.source, "<callback>") != 0) { |
||||
fail("json_load_callback returned an invalid error source"); |
||||
} |
||||
if (strcmp(error.text, "']' expected near end of file") != 0) { |
||||
fail("json_load_callback returned an invalid error message for an unclosed top-level array"); |
||||
} |
||||
|
||||
json = json_load_callback(NULL, NULL, 0, &error); |
||||
if (json) { |
||||
json_decref(json); |
||||
fail("json_load_callback should have failed on NULL load callback, but it didn't"); |
||||
} |
||||
if (strcmp(error.text, "wrong arguments") != 0) { |
||||
fail("json_load_callback returned an invalid error message for a NULL load callback"); |
||||
} |
||||
} |
@ -0,0 +1,36 @@
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
* |
||||
* Jansson is free software; you can redistribute it and/or modify |
||||
* it under the terms of the MIT license. See LICENSE for details. |
||||
*/ |
||||
|
||||
#include <jansson.h> |
||||
#include <string.h> |
||||
#include "util.h" |
||||
|
||||
static void run_tests() |
||||
{ |
||||
json_t *json; |
||||
json_error_t error; |
||||
const char str[] = "[\"A\", {\"B\": \"C\"}, 1, 2, 3]garbage"; |
||||
size_t len = strlen(str) - strlen("garbage"); |
||||
|
||||
json = json_loadb(str, len, 0, &error); |
||||
if(!json) { |
||||
fail("json_loadb failed on a valid JSON buffer"); |
||||
} |
||||
json_decref(json); |
||||
|
||||
json = json_loadb(str, len - 1, 0, &error); |
||||
if (json) { |
||||
json_decref(json); |
||||
fail("json_loadb should have failed on an incomplete buffer, but it didn't"); |
||||
} |
||||
if(error.line != 1) { |
||||
fail("json_loadb returned an invalid line number on fail"); |
||||
} |
||||
if(strcmp(error.text, "']' expected near end of file") != 0) { |
||||
fail("json_loadb returned an invalid error message for an unclosed top-level array"); |
||||
} |
||||
} |
@ -0,0 +1,82 @@
@@ -0,0 +1,82 @@
|
||||
#include <string.h> |
||||
#include <jansson.h> |
||||
|
||||
#include "util.h" |
||||
|
||||
static int malloc_called = 0; |
||||
static int free_called = 0; |
||||
|
||||
/* helper */ |
||||
static void create_and_free_complex_object() |
||||
{ |
||||
json_t *obj; |
||||
|
||||
obj = json_pack("{s:i,s:n,s:b,s:b,s:{s:s},s:[i,i,i]", |
||||
"foo", 42, |
||||
"bar", |
||||
"baz", 1, |
||||
"qux", 0, |
||||
"alice", "bar", "baz", |
||||
"bob", 9, 8, 7); |
||||
|
||||
json_decref(obj); |
||||
} |
||||
|
||||
static void *my_malloc(size_t size) |
||||
{ |
||||
malloc_called += 1; |
||||
return malloc(size); |
||||
} |
||||
|
||||
static void my_free(void *ptr) |
||||
{ |
||||
free_called += 1; |
||||
free(ptr); |
||||
} |
||||
|
||||
static void test_simple() |
||||
{ |
||||
json_set_alloc_funcs(my_malloc, my_free); |
||||
create_and_free_complex_object(); |
||||
|
||||
if(malloc_called != 20 || free_called != 20) |
||||
fail("Custom allocation failed"); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
Test the secure memory functions code given in the API reference |
||||
documentation, but by using plain memset instead of |
||||
guaranteed_memset(). |
||||
*/ |
||||
|
||||
static void *secure_malloc(size_t size) |
||||
{ |
||||
/* Store the memory area size in the beginning of the block */ |
||||
void *ptr = malloc(size + 8); |
||||
*((size_t *)ptr) = size; |
||||
return (char *)ptr + 8; |
||||
} |
||||
|
||||
static void secure_free(void *ptr) |
||||
{ |
||||
size_t size; |
||||
|
||||
ptr = (char *)ptr - 8; |
||||
size = *((size_t *)ptr); |
||||
|
||||
/*guaranteed_*/memset(ptr, 0, size); |
||||
free(ptr); |
||||
} |
||||
|
||||
static void test_secure_funcs(void) |
||||
{ |
||||
json_set_alloc_funcs(secure_malloc, secure_free); |
||||
create_and_free_complex_object(); |
||||
} |
||||
|
||||
static void run_tests() |
||||
{ |
||||
test_simple(); |
||||
test_secure_funcs(); |
||||
} |
@ -0,0 +1,73 @@
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
* |
||||
* Jansson is free software; you can redistribute it and/or modify |
||||
* it under the terms of the MIT license. See LICENSE for details. |
||||
*/ |
||||
|
||||
#include <math.h> |
||||
#include <jansson.h> |
||||
#include "util.h" |
||||
|
||||
static void run_tests() |
||||
{ |
||||
json_t *integer, *real; |
||||
json_int_t i; |
||||
double d; |
||||
|
||||
integer = json_integer(5); |
||||
real = json_real(100.1); |
||||
|
||||
if(!integer) |
||||
fail("unable to create integer"); |
||||
if(!real) |
||||
fail("unable to create real"); |
||||
|
||||
i = json_integer_value(integer); |
||||
if(i != 5) |
||||
fail("wrong integer value"); |
||||
|
||||
d = json_real_value(real); |
||||
if(d != 100.1) |
||||
fail("wrong real value"); |
||||
|
||||
d = json_number_value(integer); |
||||
if(d != 5.0) |
||||
fail("wrong number value"); |
||||
d = json_number_value(real); |
||||
if(d != 100.1) |
||||
fail("wrong number value"); |
||||
|
||||
json_decref(integer); |
||||
json_decref(real); |
||||
|
||||
#ifdef NAN |
||||
real = json_real(NAN); |
||||
if(real != NULL) |
||||
fail("could construct a real from NaN"); |
||||
|
||||
real = json_real(1.0); |
||||
if(json_real_set(real, NAN) != -1) |
||||
fail("could set a real to NaN"); |
||||
|
||||
if(json_real_value(real) != 1.0) |
||||
fail("real value changed unexpectedly"); |
||||
|
||||
json_decref(real); |
||||
#endif |
||||
|
||||
#ifdef INFINITY |
||||
real = json_real(INFINITY); |
||||
if(real != NULL) |
||||
fail("could construct a real from Inf"); |
||||
|
||||
real = json_real(1.0); |
||||
if(json_real_set(real, INFINITY) != -1) |
||||
fail("could set a real to Inf"); |
||||
|
||||
if(json_real_value(real) != 1.0) |
||||
fail("real value changed unexpectedly"); |
||||
|
||||
json_decref(real); |
||||
#endif |
||||
} |
@ -0,0 +1,511 @@
@@ -0,0 +1,511 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
* |
||||
* Jansson is free software; you can redistribute it and/or modify |
||||
* it under the terms of the MIT license. See LICENSE for details. |
||||
*/ |
||||
|
||||
#include <jansson.h> |
||||
#include <string.h> |
||||
#include "util.h" |
||||
|
||||
static void test_clear() |
||||
{ |
||||
json_t *object, *ten; |
||||
|
||||
object = json_object(); |
||||
ten = json_integer(10); |
||||
|
||||
if(!object) |
||||
fail("unable to create object"); |
||||
if(!ten) |
||||
fail("unable to create integer"); |
||||
|
||||
if(json_object_set(object, "a", ten) || |
||||
json_object_set(object, "b", ten) || |
||||
json_object_set(object, "c", ten) || |
||||
json_object_set(object, "d", ten) || |
||||
json_object_set(object, "e", ten)) |
||||
fail("unable to set value"); |
||||
|
||||
if(json_object_size(object) != 5) |
||||
fail("invalid size"); |
||||
|
||||
json_object_clear(object); |
||||
|
||||
if(json_object_size(object) != 0) |
||||
fail("invalid size after clear"); |
||||
|
||||
json_decref(ten); |
||||
json_decref(object); |
||||
} |
||||
|
||||
static void test_update() |
||||
{ |
||||
json_t *object, *other, *nine, *ten; |
||||
|
||||
object = json_object(); |
||||
other = json_object(); |
||||
|
||||
nine = json_integer(9); |
||||
ten = json_integer(10); |
||||
|
||||
if(!object || !other) |
||||
fail("unable to create object"); |
||||
if(!nine || !ten) |
||||
fail("unable to create integer"); |
||||
|
||||
|
||||
/* 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"); |
||||
|
||||
if(json_object_size(object) != 0) |
||||
fail("invalid size after update"); |
||||
|
||||
if(json_object_size(other) != 0) |
||||
fail("invalid size for updater after update"); |
||||
|
||||
|
||||
/* update an empty object with a nonempty object */ |
||||
|
||||
if(json_object_set(other, "a", ten) || |
||||
json_object_set(other, "b", ten) || |
||||
json_object_set(other, "c", ten) || |
||||
json_object_set(other, "d", ten) || |
||||
json_object_set(other, "e", ten)) |
||||
fail("unable to set value"); |
||||
|
||||
if(json_object_update(object, other)) |
||||
fail("unable to update an empty object"); |
||||
|
||||
if(json_object_size(object) != 5) |
||||
fail("invalid size after update"); |
||||
|
||||
if(json_object_get(object, "a") != ten || |
||||
json_object_get(object, "b") != ten || |
||||
json_object_get(object, "c") != ten || |
||||
json_object_get(object, "d") != ten || |
||||
json_object_get(object, "e") != ten) |
||||
fail("update works incorrectly"); |
||||
|
||||
|
||||
/* perform the same update again */ |
||||
|
||||
if(json_object_update(object, other)) |
||||
fail("unable to update a non-empty object"); |
||||
|
||||
if(json_object_size(object) != 5) |
||||
fail("invalid size after update"); |
||||
|
||||
if(json_object_get(object, "a") != ten || |
||||
json_object_get(object, "b") != ten || |
||||
json_object_get(object, "c") != ten || |
||||
json_object_get(object, "d") != ten || |
||||
json_object_get(object, "e") != ten) |
||||
fail("update works incorrectly"); |
||||
|
||||
|
||||
/* update a nonempty object with a nonempty object with both old
|
||||
and new keys */ |
||||
|
||||
if(json_object_clear(other)) |
||||
fail("clear failed"); |
||||
|
||||
if(json_object_set(other, "a", nine) || |
||||
json_object_set(other, "b", nine) || |
||||
json_object_set(other, "f", nine) || |
||||
json_object_set(other, "g", nine) || |
||||
json_object_set(other, "h", nine)) |
||||
fail("unable to set value"); |
||||
|
||||
if(json_object_update(object, other)) |
||||
fail("unable to update a nonempty object"); |
||||
|
||||
if(json_object_size(object) != 8) |
||||
fail("invalid size after update"); |
||||
|
||||
if(json_object_get(object, "a") != nine || |
||||
json_object_get(object, "b") != nine || |
||||
json_object_get(object, "f") != nine || |
||||
json_object_get(object, "g") != nine || |
||||
json_object_get(object, "h") != nine) |
||||
fail("update works incorrectly"); |
||||
|
||||
json_decref(nine); |
||||
json_decref(ten); |
||||
json_decref(other); |
||||
json_decref(object); |
||||
} |
||||
|
||||
static void test_conditional_updates() |
||||
{ |
||||
json_t *object, *other; |
||||
|
||||
object = json_pack("{sisi}", "foo", 1, "bar", 2); |
||||
other = json_pack("{sisi}", "foo", 3, "baz", 4); |
||||
|
||||
if(json_object_update_existing(object, other)) |
||||
fail("json_object_update_existing failed"); |
||||
|
||||
if(json_object_size(object) != 2) |
||||
fail("json_object_update_existing added new items"); |
||||
|
||||
if(json_integer_value(json_object_get(object, "foo")) != 3) |
||||
fail("json_object_update_existing failed to update existing key"); |
||||
|
||||
if(json_integer_value(json_object_get(object, "bar")) != 2) |
||||
fail("json_object_update_existing updated wrong key"); |
||||
|
||||
json_decref(object); |
||||
|
||||
object = json_pack("{sisi}", "foo", 1, "bar", 2); |
||||
|
||||
if(json_object_update_missing(object, other)) |
||||
fail("json_object_update_missing failed"); |
||||
|
||||
if(json_object_size(object) != 3) |
||||
fail("json_object_update_missing didn't add new items"); |
||||
|
||||
if(json_integer_value(json_object_get(object, "foo")) != 1) |
||||
fail("json_object_update_missing updated existing key"); |
||||
|
||||
if(json_integer_value(json_object_get(object, "bar")) != 2) |
||||
fail("json_object_update_missing updated wrong key"); |
||||
|
||||
if(json_integer_value(json_object_get(object, "baz")) != 4) |
||||
fail("json_object_update_missing didn't add new items"); |
||||
|
||||
json_decref(object); |
||||
json_decref(other); |
||||
} |
||||
|
||||
static void test_circular() |
||||
{ |
||||
json_t *object1, *object2; |
||||
|
||||
object1 = json_object(); |
||||
object2 = json_object(); |
||||
if(!object1 || !object2) |
||||
fail("unable to create object"); |
||||
|
||||
/* the simple case is checked */ |
||||
if(json_object_set(object1, "a", object1) == 0) |
||||
fail("able to set self"); |
||||
|
||||
/* create circular references */ |
||||
if(json_object_set(object1, "a", object2) || |
||||
json_object_set(object2, "a", object1)) |
||||
fail("unable to set value"); |
||||
|
||||
/* circularity is detected when dumping */ |
||||
if(json_dumps(object1, 0) != NULL) |
||||
fail("able to dump circulars"); |
||||
|
||||
/* decref twice to deal with the circular references */ |
||||
json_decref(object1); |
||||
json_decref(object2); |
||||
json_decref(object1); |
||||
} |
||||
|
||||
static void test_set_nocheck() |
||||
{ |
||||
json_t *object, *string; |
||||
|
||||
object = json_object(); |
||||
string = json_string("bar"); |
||||
|
||||
if(!object) |
||||
fail("unable to create object"); |
||||
if(!string) |
||||
fail("unable to create string"); |
||||
|
||||
if(json_object_set_nocheck(object, "foo", string)) |
||||
fail("json_object_set_nocheck failed"); |
||||
if(json_object_get(object, "foo") != string) |
||||
fail("json_object_get after json_object_set_nocheck failed"); |
||||
|
||||
/* invalid UTF-8 in key */ |
||||
if(json_object_set_nocheck(object, "a\xefz", string)) |
||||
fail("json_object_set_nocheck failed for invalid UTF-8"); |
||||
if(json_object_get(object, "a\xefz") != string) |
||||
fail("json_object_get after json_object_set_nocheck failed"); |
||||
|
||||
if(json_object_set_new_nocheck(object, "bax", json_integer(123))) |
||||
fail("json_object_set_new_nocheck failed"); |
||||
if(json_integer_value(json_object_get(object, "bax")) != 123) |
||||
fail("json_object_get after json_object_set_new_nocheck failed"); |
||||
|
||||
/* invalid UTF-8 in key */ |
||||
if(json_object_set_new_nocheck(object, "asdf\xfe", json_integer(321))) |
||||
fail("json_object_set_new_nocheck failed for invalid UTF-8"); |
||||
if(json_integer_value(json_object_get(object, "asdf\xfe")) != 321) |
||||
fail("json_object_get after json_object_set_new_nocheck failed"); |
||||
|
||||
json_decref(string); |
||||
json_decref(object); |
||||
} |
||||
|
||||
static void test_iterators() |
||||
{ |
||||
json_t *object, *foo, *bar, *baz; |
||||
void *iter; |
||||
|
||||
if(json_object_iter(NULL)) |
||||
fail("able to iterate over NULL"); |
||||
|
||||
if(json_object_iter_next(NULL, NULL)) |
||||
fail("able to increment an iterator on a NULL object"); |
||||
|
||||
object = json_object(); |
||||
foo = json_string("foo"); |
||||
bar = json_string("bar"); |
||||
baz = json_string("baz"); |
||||
if(!object || !foo || !bar || !bar) |
||||
fail("unable to create values"); |
||||
|
||||
if(json_object_iter_next(object, NULL)) |
||||
fail("able to increment a NULL iterator"); |
||||
|
||||
if(json_object_set(object, "a", foo) || |
||||
json_object_set(object, "b", bar) || |
||||
json_object_set(object, "c", baz)) |
||||
fail("unable to populate object"); |
||||
|
||||
iter = json_object_iter(object); |
||||
if(!iter) |
||||
fail("unable to get iterator"); |
||||
if(strcmp(json_object_iter_key(iter), "a")) |
||||
fail("iterating failed: wrong key"); |
||||
if(json_object_iter_value(iter) != foo) |
||||
fail("iterating failed: wrong value"); |
||||
|
||||
iter = json_object_iter_next(object, iter); |
||||
if(!iter) |
||||
fail("unable to increment iterator"); |
||||
if(strcmp(json_object_iter_key(iter), "b")) |
||||
fail("iterating failed: wrong key"); |
||||
if(json_object_iter_value(iter) != bar) |
||||
fail("iterating failed: wrong value"); |
||||
|
||||
iter = json_object_iter_next(object, iter); |
||||
if(!iter) |
||||
fail("unable to increment iterator"); |
||||
if(strcmp(json_object_iter_key(iter), "c")) |
||||
fail("iterating failed: wrong key"); |
||||
if(json_object_iter_value(iter) != baz) |
||||
fail("iterating failed: wrong value"); |
||||
|
||||
if(json_object_iter_next(object, iter) != NULL) |
||||
fail("able to iterate over the end"); |
||||
|
||||
if(json_object_iter_at(object, "foo")) |
||||
fail("json_object_iter_at() succeeds for non-existent key"); |
||||
|
||||
iter = json_object_iter_at(object, "b"); |
||||
if(!iter) |
||||
fail("json_object_iter_at() fails for an existing key"); |
||||
|
||||
if(strcmp(json_object_iter_key(iter), "b")) |
||||
fail("iterating failed: wrong key"); |
||||
if(json_object_iter_value(iter) != bar) |
||||
fail("iterating failed: wrong value"); |
||||
|
||||
iter = json_object_iter_next(object, iter); |
||||
if(!iter) |
||||
fail("unable to increment iterator"); |
||||
if(strcmp(json_object_iter_key(iter), "c")) |
||||
fail("iterating failed: wrong key"); |
||||
if(json_object_iter_value(iter) != baz) |
||||
fail("iterating failed: wrong value"); |
||||
|
||||
if(json_object_iter_set(object, iter, bar)) |
||||
fail("unable to set value at iterator"); |
||||
|
||||
if(strcmp(json_object_iter_key(iter), "c")) |
||||
fail("json_object_iter_key() fails after json_object_iter_set()"); |
||||
if(json_object_iter_value(iter) != bar) |
||||
fail("json_object_iter_value() fails after json_object_iter_set()"); |
||||
if(json_object_get(object, "c") != bar) |
||||
fail("json_object_get() fails after json_object_iter_set()"); |
||||
|
||||
json_decref(object); |
||||
json_decref(foo); |
||||
json_decref(bar); |
||||
json_decref(baz); |
||||
} |
||||
|
||||
static void test_misc() |
||||
{ |
||||
json_t *object, *string, *other_string, *value; |
||||
|
||||
object = json_object(); |
||||
string = json_string("test"); |
||||
other_string = json_string("other"); |
||||
|
||||
if(!object) |
||||
fail("unable to create object"); |
||||
if(!string || !other_string) |
||||
fail("unable to create string"); |
||||
|
||||
if(json_object_get(object, "a")) |
||||
fail("value for nonexisting key"); |
||||
|
||||
if(json_object_set(object, "a", string)) |
||||
fail("unable to set value"); |
||||
|
||||
if(!json_object_set(object, NULL, string)) |
||||
fail("able to set NULL key"); |
||||
|
||||
if(!json_object_set(object, "a", NULL)) |
||||
fail("able to set NULL value"); |
||||
|
||||
/* invalid UTF-8 in key */ |
||||
if(!json_object_set(object, "a\xefz", string)) |
||||
fail("able to set invalid unicode key"); |
||||
|
||||
value = json_object_get(object, "a"); |
||||
if(!value) |
||||
fail("no value for existing key"); |
||||
if(value != string) |
||||
fail("got different value than what was added"); |
||||
|
||||
/* "a", "lp" and "px" collide in a five-bucket hashtable */ |
||||
if(json_object_set(object, "b", string) || |
||||
json_object_set(object, "lp", string) || |
||||
json_object_set(object, "px", string)) |
||||
fail("unable to set value"); |
||||
|
||||
value = json_object_get(object, "a"); |
||||
if(!value) |
||||
fail("no value for existing key"); |
||||
if(value != string) |
||||
fail("got different value than what was added"); |
||||
|
||||
if(json_object_set(object, "a", other_string)) |
||||
fail("unable to replace an existing key"); |
||||
|
||||
value = json_object_get(object, "a"); |
||||
if(!value) |
||||
fail("no value for existing key"); |
||||
if(value != other_string) |
||||
fail("got different value than what was set"); |
||||
|
||||
if(!json_object_del(object, "nonexisting")) |
||||
fail("able to delete a nonexisting key"); |
||||
|
||||
if(json_object_del(object, "px")) |
||||
fail("unable to delete an existing key"); |
||||
|
||||
if(json_object_del(object, "a")) |
||||
fail("unable to delete an existing key"); |
||||
|
||||
if(json_object_del(object, "lp")) |
||||
fail("unable to delete an existing key"); |
||||
|
||||
|
||||
/* add many keys to initiate rehashing */ |
||||
|
||||
if(json_object_set(object, "a", string)) |
||||
fail("unable to set value"); |
||||
|
||||
if(json_object_set(object, "lp", string)) |
||||
fail("unable to set value"); |
||||
|
||||
if(json_object_set(object, "px", string)) |
||||
fail("unable to set value"); |
||||
|
||||
if(json_object_set(object, "c", string)) |
||||
fail("unable to set value"); |
||||
|
||||
if(json_object_set(object, "d", string)) |
||||
fail("unable to set value"); |
||||
|
||||
if(json_object_set(object, "e", string)) |
||||
fail("unable to set value"); |
||||
|
||||
|
||||
if(json_object_set_new(object, "foo", json_integer(123))) |
||||
fail("unable to set new value"); |
||||
|
||||
value = json_object_get(object, "foo"); |
||||
if(!json_is_integer(value) || json_integer_value(value) != 123) |
||||
fail("json_object_set_new works incorrectly"); |
||||
|
||||
if(!json_object_set_new(object, NULL, json_integer(432))) |
||||
fail("able to set_new NULL key"); |
||||
|
||||
if(!json_object_set_new(object, "foo", NULL)) |
||||
fail("able to set_new NULL value"); |
||||
|
||||
json_decref(string); |
||||
json_decref(other_string); |
||||
json_decref(object); |
||||
} |
||||
|
||||
static void test_preserve_order() |
||||
{ |
||||
json_t *object; |
||||
char *result; |
||||
|
||||
const char *expected = "{\"foobar\": 1, \"bazquux\": 6, \"lorem ipsum\": 3, \"sit amet\": 5, \"helicopter\": 7}"; |
||||
|
||||
object = json_object(); |
||||
|
||||
json_object_set_new(object, "foobar", json_integer(1)); |
||||
json_object_set_new(object, "bazquux", json_integer(2)); |
||||
json_object_set_new(object, "lorem ipsum", json_integer(3)); |
||||
json_object_set_new(object, "dolor", json_integer(4)); |
||||
json_object_set_new(object, "sit amet", json_integer(5)); |
||||
|
||||
/* changing a value should preserve the order */ |
||||
json_object_set_new(object, "bazquux", json_integer(6)); |
||||
|
||||
/* deletion shouldn't change the order of others */ |
||||
json_object_del(object, "dolor"); |
||||
|
||||
/* add a new item just to make sure */ |
||||
json_object_set_new(object, "helicopter", json_integer(7)); |
||||
|
||||
result = json_dumps(object, JSON_PRESERVE_ORDER); |
||||
|
||||
if(strcmp(expected, result) != 0) { |
||||
fprintf(stderr, "%s != %s", expected, result); |
||||
fail("JSON_PRESERVE_ORDER doesn't work"); |
||||
} |
||||
|
||||
free(result); |
||||
json_decref(object); |
||||
} |
||||
|
||||
static void test_object_foreach() |
||||
{ |
||||
const char *key; |
||||
json_t *object1, *object2, *value; |
||||
|
||||
object1 = json_pack("{sisisi}", "foo", 1, "bar", 2, "baz", 3); |
||||
object2 = json_object(); |
||||
|
||||
json_object_foreach(object1, key, value) |
||||
json_object_set(object2, key, value); |
||||
|
||||
if(!json_equal(object1, object2)) |
||||
fail("json_object_foreach failed to iterate all key-value pairs"); |
||||
|
||||
json_decref(object1); |
||||
json_decref(object2); |
||||
} |
||||
|
||||
static void run_tests() |
||||
{ |
||||
test_misc(); |
||||
test_clear(); |
||||
test_update(); |
||||
test_conditional_updates(); |
||||
test_circular(); |
||||
test_set_nocheck(); |
||||
test_iterators(); |
||||
test_preserve_order(); |
||||
test_object_foreach(); |
||||
} |
@ -0,0 +1,283 @@
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
* Copyright (c) 2010-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca> |
||||
* |
||||
* Jansson is free software; you can redistribute it and/or modify |
||||
* it under the terms of the MIT license. See LICENSE for details. |
||||
*/ |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include <config.h> |
||||
#endif |
||||
|
||||
#include <jansson_config.h> |
||||
|
||||
#include <string.h> |
||||
#include <jansson.h> |
||||
#include <stdio.h> |
||||
#include "util.h" |
||||
|
||||
static void run_tests() |
||||
{ |
||||
json_t *value; |
||||
int i; |
||||
char buffer[4] = {'t', 'e', 's', 't'}; |
||||
json_error_t error; |
||||
|
||||
/*
|
||||
* Simple, valid json_pack cases |
||||
*/ |
||||
/* true */ |
||||
value = json_pack("b", 1); |
||||
if(!json_is_true(value)) |
||||
fail("json_pack boolean failed"); |
||||
if(value->refcount != (size_t)-1) |
||||
fail("json_pack boolean refcount failed"); |
||||
json_decref(value); |
||||
|
||||
/* false */ |
||||
value = json_pack("b", 0); |
||||
if(!json_is_false(value)) |
||||
fail("json_pack boolean failed"); |
||||
if(value->refcount != (size_t)-1) |
||||
fail("json_pack boolean refcount failed"); |
||||
json_decref(value); |
||||
|
||||
/* null */ |
||||
value = json_pack("n"); |
||||
if(!json_is_null(value)) |
||||
fail("json_pack null failed"); |
||||
if(value->refcount != (size_t)-1) |
||||
fail("json_pack null refcount failed"); |
||||
json_decref(value); |
||||
|
||||
/* integer */ |
||||
value = json_pack("i", 1); |
||||
if(!json_is_integer(value) || json_integer_value(value) != 1) |
||||
fail("json_pack integer failed"); |
||||
if(value->refcount != (size_t)1) |
||||
fail("json_pack integer refcount failed"); |
||||
json_decref(value); |
||||
|
||||
/* integer from json_int_t */ |
||||
value = json_pack("I", (json_int_t)555555); |
||||
if(!json_is_integer(value) || json_integer_value(value) != 555555) |
||||
fail("json_pack json_int_t failed"); |
||||
if(value->refcount != (size_t)1) |
||||
fail("json_pack integer refcount failed"); |
||||
json_decref(value); |
||||
|
||||
/* real */ |
||||
value = json_pack("f", 1.0); |
||||
if(!json_is_real(value) || json_real_value(value) != 1.0) |
||||
fail("json_pack real failed"); |
||||
if(value->refcount != (size_t)1) |
||||
fail("json_pack real refcount failed"); |
||||
json_decref(value); |
||||
|
||||
/* string */ |
||||
value = json_pack("s", "test"); |
||||
if(!json_is_string(value) || strcmp("test", json_string_value(value))) |
||||
fail("json_pack string failed"); |
||||
if(value->refcount != (size_t)1) |
||||
fail("json_pack string refcount failed"); |
||||
json_decref(value); |
||||
|
||||
/* string and length */ |
||||
value = json_pack("s#", "test asdf", 4); |
||||
if(!json_is_string(value) || strcmp("test", json_string_value(value))) |
||||
fail("json_pack string and length failed"); |
||||
if(value->refcount != (size_t)1) |
||||
fail("json_pack string and length refcount failed"); |
||||
json_decref(value); |
||||
|
||||
/* string and length, non-NUL terminated string */ |
||||
value = json_pack("s#", buffer, 4); |
||||
if(!json_is_string(value) || strcmp("test", json_string_value(value))) |
||||
fail("json_pack string and length failed"); |
||||
if(value->refcount != (size_t)1) |
||||
fail("json_pack string and length refcount failed"); |
||||
json_decref(value); |
||||
|
||||
/* string concatenation */ |
||||
value = json_pack("s++", "te", "st", "ing"); |
||||
if(!json_is_string(value) || strcmp("testing", json_string_value(value))) |
||||
fail("json_pack string concatenation failed"); |
||||
if(value->refcount != (size_t)1) |
||||
fail("json_pack string concatenation refcount failed"); |
||||
json_decref(value); |
||||
|
||||
/* string concatenation and length */ |
||||
value = json_pack("s#+#+", "test", 1, "test", 2, "test"); |
||||
if(!json_is_string(value) || strcmp("ttetest", json_string_value(value))) |
||||
fail("json_pack string concatenation and length failed"); |
||||
if(value->refcount != (size_t)1) |
||||
fail("json_pack string concatenation and length refcount failed"); |
||||
json_decref(value); |
||||
|
||||
/* empty object */ |
||||
value = json_pack("{}", 1.0); |
||||
if(!json_is_object(value) || json_object_size(value) != 0) |
||||
fail("json_pack empty object failed"); |
||||
if(value->refcount != (size_t)1) |
||||
fail("json_pack empty object refcount failed"); |
||||
json_decref(value); |
||||
|
||||
/* empty list */ |
||||
value = json_pack("[]", 1.0); |
||||
if(!json_is_array(value) || json_array_size(value) != 0) |
||||
fail("json_pack empty list failed"); |
||||
if(value->refcount != (size_t)1) |
||||
fail("json_pack empty list failed"); |
||||
json_decref(value); |
||||
|
||||
/* non-incref'd object */ |
||||
value = json_pack("o", json_integer(1)); |
||||
if(!json_is_integer(value) || json_integer_value(value) != 1) |
||||
fail("json_pack object failed"); |
||||
if(value->refcount != (size_t)1) |
||||
fail("json_pack integer refcount failed"); |
||||
json_decref(value); |
||||
|
||||
/* incref'd object */ |
||||
value = json_pack("O", json_integer(1)); |
||||
if(!json_is_integer(value) || json_integer_value(value) != 1) |
||||
fail("json_pack object failed"); |
||||
if(value->refcount != (size_t)2) |
||||
fail("json_pack integer refcount failed"); |
||||
json_decref(value); |
||||
json_decref(value); |
||||
|
||||
/* simple object */ |
||||
value = json_pack("{s:[]}", "foo"); |
||||
if(!json_is_object(value) || json_object_size(value) != 1) |
||||
fail("json_pack array failed"); |
||||
if(!json_is_array(json_object_get(value, "foo"))) |
||||
fail("json_pack array failed"); |
||||
if(json_object_get(value, "foo")->refcount != (size_t)1) |
||||
fail("json_pack object refcount failed"); |
||||
json_decref(value); |
||||
|
||||
/* object with complex key */ |
||||
value = json_pack("{s+#+: []}", "foo", "barbar", 3, "baz"); |
||||
if(!json_is_object(value) || json_object_size(value) != 1) |
||||
fail("json_pack array failed"); |
||||
if(!json_is_array(json_object_get(value, "foobarbaz"))) |
||||
fail("json_pack array failed"); |
||||
if(json_object_get(value, "foobarbaz")->refcount != (size_t)1) |
||||
fail("json_pack object refcount failed"); |
||||
json_decref(value); |
||||
|
||||
/* simple array */ |
||||
value = json_pack("[i,i,i]", 0, 1, 2); |
||||
if(!json_is_array(value) || json_array_size(value) != 3) |
||||
fail("json_pack object failed"); |
||||
for(i=0; i<3; i++) |
||||
{ |
||||
if(!json_is_integer(json_array_get(value, i)) || |
||||
json_integer_value(json_array_get(value, i)) != i) |
||||
|
||||
fail("json_pack integer array failed"); |
||||
} |
||||
json_decref(value); |
||||
|
||||
/* Whitespace; regular string */ |
||||
value = json_pack(" s ", "test"); |
||||
if(!json_is_string(value) || strcmp("test", json_string_value(value))) |
||||
fail("json_pack string (with whitespace) failed"); |
||||
json_decref(value); |
||||
|
||||
/* Whitespace; empty array */ |
||||
value = json_pack("[ ]"); |
||||
if(!json_is_array(value) || json_array_size(value) != 0) |
||||
fail("json_pack empty array (with whitespace) failed"); |
||||
json_decref(value); |
||||
|
||||
/* Whitespace; array */ |
||||
value = json_pack("[ i , i, i ] ", 1, 2, 3); |
||||
if(!json_is_array(value) || json_array_size(value) != 3) |
||||
fail("json_pack array (with whitespace) failed"); |
||||
json_decref(value); |
||||
|
||||
/*
|
||||
* Invalid cases |
||||
*/ |
||||
|
||||
/* newline in format string */ |
||||
if(json_pack_ex(&error, 0, "{\n\n1")) |
||||
fail("json_pack failed to catch invalid format '1'"); |
||||
check_error("Expected format 's', got '1'", "<format>", 3, 1, 4); |
||||
|
||||
/* mismatched open/close array/object */ |
||||
if(json_pack_ex(&error, 0, "[}")) |
||||
fail("json_pack failed to catch mismatched '}'"); |
||||
check_error("Unexpected format character '}'", "<format>", 1, 2, 2); |
||||
|
||||
if(json_pack_ex(&error, 0, "{]")) |
||||
fail("json_pack failed to catch mismatched ']'"); |
||||
check_error("Expected format 's', got ']'", "<format>", 1, 2, 2); |
||||
|
||||
/* missing close array */ |
||||
if(json_pack_ex(&error, 0, "[")) |
||||
fail("json_pack failed to catch missing ']'"); |
||||
check_error("Unexpected end of format string", "<format>", 1, 2, 2); |
||||
|
||||
/* missing close object */ |
||||
if(json_pack_ex(&error, 0, "{")) |
||||
fail("json_pack failed to catch missing '}'"); |
||||
check_error("Unexpected end of format string", "<format>", 1, 2, 2); |
||||
|
||||
/* garbage after format string */ |
||||
if(json_pack_ex(&error, 0, "[i]a", 42)) |
||||
fail("json_pack failed to catch garbage after format string"); |
||||
check_error("Garbage after format string", "<format>", 1, 4, 4); |
||||
|
||||
if(json_pack_ex(&error, 0, "ia", 42)) |
||||
fail("json_pack failed to catch garbage after format string"); |
||||
check_error("Garbage after format string", "<format>", 1, 2, 2); |
||||
|
||||
/* NULL string */ |
||||
if(json_pack_ex(&error, 0, "s", NULL)) |
||||
fail("json_pack failed to catch null argument string"); |
||||
check_error("NULL string argument", "<args>", 1, 1, 1); |
||||
|
||||
/* + on its own */ |
||||
if(json_pack_ex(&error, 0, "+", NULL)) |
||||
fail("json_pack failed to a lone +"); |
||||
check_error("Unexpected format character '+'", "<format>", 1, 1, 1); |
||||
|
||||
/* NULL format */ |
||||
if(json_pack_ex(&error, 0, NULL)) |
||||
fail("json_pack failed to catch NULL format string"); |
||||
check_error("NULL or empty format string", "<format>", -1, -1, 0); |
||||
|
||||
/* NULL key */ |
||||
if(json_pack_ex(&error, 0, "{s:i}", NULL, 1)) |
||||
fail("json_pack failed to catch NULL key"); |
||||
check_error("NULL string argument", "<args>", 1, 2, 2); |
||||
|
||||
/* More complicated checks for row/columns */ |
||||
if(json_pack_ex(&error, 0, "{ {}: s }", "foo")) |
||||
fail("json_pack failed to catch object as key"); |
||||
check_error("Expected format 's', got '{'", "<format>", 1, 3, 3); |
||||
|
||||
/* Complex object */ |
||||
if(json_pack_ex(&error, 0, "{ s: {}, s:[ii{} }", "foo", "bar", 12, 13)) |
||||
fail("json_pack failed to catch missing ]"); |
||||
check_error("Unexpected format character '}'", "<format>", 1, 19, 19); |
||||
|
||||
/* Complex array */ |
||||
if(json_pack_ex(&error, 0, "[[[[[ [[[[[ [[[[ }]]]] ]]]] ]]]]]")) |
||||
fail("json_pack failed to catch extra }"); |
||||
check_error("Unexpected format character '}'", "<format>", 1, 21, 21); |
||||
|
||||
/* Invalid UTF-8 in object key */ |
||||
if(json_pack_ex(&error, 0, "{s:i}", "\xff\xff", 42)) |
||||
fail("json_pack failed to catch invalid UTF-8 in an object key"); |
||||
check_error("Invalid UTF-8 object key", "<args>", 1, 2, 2); |
||||
|
||||
/* Invalid UTF-8 in a string */ |
||||
if(json_pack_ex(&error, 0, "{s:s}", "foo", "\xff\xff")) |
||||
fail("json_pack failed to catch invalid UTF-8 in a string"); |
||||
check_error("Invalid UTF-8 string", "<args>", 1, 4, 4); |
||||
} |
@ -0,0 +1,199 @@
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
* |
||||
* Jansson is free software; you can redistribute it and/or modify |
||||
* it under the terms of the MIT license. See LICENSE for details. |
||||
*/ |
||||
|
||||
#include <string.h> |
||||
#include <jansson.h> |
||||
#include "util.h" |
||||
|
||||
/* Call the simple functions not covered by other tests of the public API */ |
||||
static void run_tests() |
||||
{ |
||||
json_t *value; |
||||
|
||||
value = json_boolean(1); |
||||
if(!json_is_true(value)) |
||||
fail("json_boolean(1) failed"); |
||||
json_decref(value); |
||||
|
||||
value = json_boolean(-123); |
||||
if(!json_is_true(value)) |
||||
fail("json_boolean(-123) failed"); |
||||
json_decref(value); |
||||
|
||||
value = json_boolean(0); |
||||
if(!json_is_false(value)) |
||||
fail("json_boolean(0) failed"); |
||||
json_decref(value); |
||||
|
||||
|
||||
value = json_integer(1); |
||||
if(json_typeof(value) != JSON_INTEGER) |
||||
fail("json_typeof failed"); |
||||
|
||||
if(json_is_object(value)) |
||||
fail("json_is_object failed"); |
||||
|
||||
if(json_is_array(value)) |
||||
fail("json_is_array failed"); |
||||
|
||||
if(json_is_string(value)) |
||||
fail("json_is_string failed"); |
||||
|
||||
if(!json_is_integer(value)) |
||||
fail("json_is_integer failed"); |
||||
|
||||
if(json_is_real(value)) |
||||
fail("json_is_real failed"); |
||||
|
||||
if(!json_is_number(value)) |
||||
fail("json_is_number failed"); |
||||
|
||||
if(json_is_true(value)) |
||||
fail("json_is_true failed"); |
||||
|
||||
if(json_is_false(value)) |
||||
fail("json_is_false failed"); |
||||
|
||||
if(json_is_boolean(value)) |
||||
fail("json_is_boolean failed"); |
||||
|
||||
if(json_is_null(value)) |
||||
fail("json_is_null failed"); |
||||
|
||||
json_decref(value); |
||||
|
||||
|
||||
value = json_string("foo"); |
||||
if(!value) |
||||
fail("json_string failed"); |
||||
if(strcmp(json_string_value(value), "foo")) |
||||
fail("invalid string value"); |
||||
|
||||
if(json_string_set(value, "bar")) |
||||
fail("json_string_set failed"); |
||||
if(strcmp(json_string_value(value), "bar")) |
||||
fail("invalid string value"); |
||||
|
||||
json_decref(value); |
||||
|
||||
value = json_string(NULL); |
||||
if(value) |
||||
fail("json_string(NULL) failed"); |
||||
|
||||
/* invalid UTF-8 */ |
||||
value = json_string("a\xefz"); |
||||
if(value) |
||||
fail("json_string(<invalid utf-8>) failed"); |
||||
|
||||
value = json_string_nocheck("foo"); |
||||
if(!value) |
||||
fail("json_string_nocheck failed"); |
||||
if(strcmp(json_string_value(value), "foo")) |
||||
fail("invalid string value"); |
||||
|
||||
if(json_string_set_nocheck(value, "bar")) |
||||
fail("json_string_set_nocheck failed"); |
||||
if(strcmp(json_string_value(value), "bar")) |
||||
fail("invalid string value"); |
||||
|
||||
json_decref(value); |
||||
|
||||
/* invalid UTF-8 */ |
||||
value = json_string_nocheck("qu\xff"); |
||||
if(!value) |
||||
fail("json_string_nocheck failed"); |
||||
if(strcmp(json_string_value(value), "qu\xff")) |
||||
fail("invalid string value"); |
||||
|
||||
if(json_string_set_nocheck(value, "\xfd\xfe\xff")) |
||||
fail("json_string_set_nocheck failed"); |
||||
if(strcmp(json_string_value(value), "\xfd\xfe\xff")) |
||||
fail("invalid string value"); |
||||
|
||||
json_decref(value); |
||||
|
||||
|
||||
value = json_integer(123); |
||||
if(!value) |
||||
fail("json_integer failed"); |
||||
if(json_integer_value(value) != 123) |
||||
fail("invalid integer value"); |
||||
if(json_number_value(value) != 123.0) |
||||
fail("invalid number value"); |
||||
|
||||
if(json_integer_set(value, 321)) |
||||
fail("json_integer_set failed"); |
||||
if(json_integer_value(value) != 321) |
||||
fail("invalid integer value"); |
||||
if(json_number_value(value) != 321.0) |
||||
fail("invalid number value"); |
||||
|
||||
json_decref(value); |
||||
|
||||
value = json_real(123.123); |
||||
if(!value) |
||||
fail("json_real failed"); |
||||
if(json_real_value(value) != 123.123) |
||||
fail("invalid integer value"); |
||||
if(json_number_value(value) != 123.123) |
||||
fail("invalid number value"); |
||||
|
||||
if(json_real_set(value, 321.321)) |
||||
fail("json_real_set failed"); |
||||
if(json_real_value(value) != 321.321) |
||||
fail("invalid real value"); |
||||
if(json_number_value(value) != 321.321) |
||||
fail("invalid number value"); |
||||
|
||||
json_decref(value); |
||||
|
||||
value = json_true(); |
||||
if(!value) |
||||
fail("json_true failed"); |
||||
json_decref(value); |
||||
|
||||
value = json_false(); |
||||
if(!value) |
||||
fail("json_false failed"); |
||||
json_decref(value); |
||||
|
||||
value = json_null(); |
||||
if(!value) |
||||
fail("json_null failed"); |
||||
json_decref(value); |
||||
|
||||
/* Test reference counting on singletons (true, false, null) */ |
||||
value = json_true(); |
||||
if(value->refcount != (size_t)-1) |
||||
fail("refcounting true works incorrectly"); |
||||
json_decref(value); |
||||
if(value->refcount != (size_t)-1) |
||||
fail("refcounting true works incorrectly"); |
||||
json_incref(value); |
||||
if(value->refcount != (size_t)-1) |
||||
fail("refcounting true works incorrectly"); |
||||
|
||||
value = json_false(); |
||||
if(value->refcount != (size_t)-1) |
||||
fail("refcounting false works incorrectly"); |
||||
json_decref(value); |
||||
if(value->refcount != (size_t)-1) |
||||
fail("refcounting false works incorrectly"); |
||||
json_incref(value); |
||||
if(value->refcount != (size_t)-1) |
||||
fail("refcounting false works incorrectly"); |
||||
|
||||
value = json_null(); |
||||
if(value->refcount != (size_t)-1) |
||||
fail("refcounting null works incorrectly"); |
||||
json_decref(value); |
||||
if(value->refcount != (size_t)-1) |
||||
fail("refcounting null works incorrectly"); |
||||
json_incref(value); |
||||
if(value->refcount != (size_t)-1) |
||||
fail("refcounting null works incorrectly"); |
||||
} |
@ -0,0 +1,373 @@
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
* Copyright (c) 2010-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca> |
||||
* |
||||
* Jansson is free software; you can redistribute it and/or modify |
||||
* it under the terms of the MIT license. See LICENSE for details. |
||||
*/ |
||||
|
||||
#include <string.h> |
||||
#include <jansson.h> |
||||
#include <stdio.h> |
||||
#include "util.h" |
||||
|
||||
static void run_tests() |
||||
{ |
||||
json_t *j, *j2; |
||||
int i1, i2, i3; |
||||
json_int_t I1; |
||||
int rv; |
||||
double f; |
||||
char *s; |
||||
|
||||
json_error_t error; |
||||
|
||||
/*
|
||||
* Simple, valid json_pack cases |
||||
*/ |
||||
|
||||
/* true */ |
||||
rv = json_unpack(json_true(), "b", &i1); |
||||
if(rv || !i1) |
||||
fail("json_unpack boolean failed"); |
||||
|
||||
/* false */ |
||||
rv = json_unpack(json_false(), "b", &i1); |
||||
if(rv || i1) |
||||
fail("json_unpack boolean failed"); |
||||
|
||||
/* null */ |
||||
if(json_unpack(json_null(), "n")) |
||||
fail("json_unpack null failed"); |
||||
|
||||
/* integer */ |
||||
j = json_integer(42); |
||||
rv = json_unpack(j, "i", &i1); |
||||
if(rv || i1 != 42) |
||||
fail("json_unpack integer failed"); |
||||
json_decref(j); |
||||
|
||||
/* json_int_t */ |
||||
j = json_integer(5555555); |
||||
rv = json_unpack(j, "I", &I1); |
||||
if(rv || I1 != 5555555) |
||||
fail("json_unpack json_int_t failed"); |
||||
json_decref(j); |
||||
|
||||
/* real */ |
||||
j = json_real(1.7); |
||||
rv = json_unpack(j, "f", &f); |
||||
if(rv || f != 1.7) |
||||
fail("json_unpack real failed"); |
||||
json_decref(j); |
||||
|
||||
/* number */ |
||||
j = json_integer(12345); |
||||
rv = json_unpack(j, "F", &f); |
||||
if(rv || f != 12345.0) |
||||
fail("json_unpack (real or) integer failed"); |
||||
json_decref(j); |
||||
|
||||
j = json_real(1.7); |
||||
rv = json_unpack(j, "F", &f); |
||||
if(rv || f != 1.7) |
||||
fail("json_unpack real (or integer) failed"); |
||||
json_decref(j); |
||||
|
||||
/* string */ |
||||
j = json_string("foo"); |
||||
rv = json_unpack(j, "s", &s); |
||||
if(rv || strcmp(s, "foo")) |
||||
fail("json_unpack string failed"); |
||||
json_decref(j); |
||||
|
||||
/* empty object */ |
||||
j = json_object(); |
||||
if(json_unpack(j, "{}")) |
||||
fail("json_unpack empty object failed"); |
||||
json_decref(j); |
||||
|
||||
/* empty list */ |
||||
j = json_array(); |
||||
if(json_unpack(j, "[]")) |
||||
fail("json_unpack empty list failed"); |
||||
json_decref(j); |
||||
|
||||
/* non-incref'd object */ |
||||
j = json_object(); |
||||
rv = json_unpack(j, "o", &j2); |
||||
if(rv || j2 != j || j->refcount != 1) |
||||
fail("json_unpack object failed"); |
||||
json_decref(j); |
||||
|
||||
/* incref'd object */ |
||||
j = json_object(); |
||||
rv = json_unpack(j, "O", &j2); |
||||
if(rv || j2 != j || j->refcount != 2) |
||||
fail("json_unpack object failed"); |
||||
json_decref(j); |
||||
json_decref(j); |
||||
|
||||
/* simple object */ |
||||
j = json_pack("{s:i}", "foo", 42); |
||||
rv = json_unpack(j, "{s:i}", "foo", &i1); |
||||
if(rv || i1 != 42) |
||||
fail("json_unpack simple object failed"); |
||||
json_decref(j); |
||||
|
||||
/* simple array */ |
||||
j = json_pack("[iii]", 1, 2, 3); |
||||
rv = json_unpack(j, "[i,i,i]", &i1, &i2, &i3); |
||||
if(rv || i1 != 1 || i2 != 2 || i3 != 3) |
||||
fail("json_unpack simple array failed"); |
||||
json_decref(j); |
||||
|
||||
/* object with many items & strict checking */ |
||||
j = json_pack("{s:i, s:i, s:i}", "a", 1, "b", 2, "c", 3); |
||||
rv = json_unpack(j, "{s:i, s:i, s:i}", "a", &i1, "b", &i2, "c", &i3); |
||||
if(rv || i1 != 1 || i2 != 2 || i3 != 3) |
||||
fail("json_unpack object with many items failed"); |
||||
json_decref(j); |
||||
|
||||
/*
|
||||
* Invalid cases |
||||
*/ |
||||
|
||||
j = json_integer(42); |
||||
if(!json_unpack_ex(j, &error, 0, "z")) |
||||
fail("json_unpack succeeded with invalid format character"); |
||||
check_error("Unexpected format character 'z'", "<format>", 1, 1, 1); |
||||
|
||||
if(!json_unpack_ex(NULL, &error, 0, "[i]")) |
||||
fail("json_unpack succeeded with NULL root"); |
||||
check_error("NULL root value", "<root>", -1, -1, 0); |
||||
json_decref(j); |
||||
|
||||
/* mismatched open/close array/object */ |
||||
j = json_pack("[]"); |
||||
if(!json_unpack_ex(j, &error, 0, "[}")) |
||||
fail("json_unpack failed to catch mismatched ']'"); |
||||
check_error("Unexpected format character '}'", "<format>", 1, 2, 2); |
||||
json_decref(j); |
||||
|
||||
j = json_pack("{}"); |
||||
if(!json_unpack_ex(j, &error, 0, "{]")) |
||||
fail("json_unpack failed to catch mismatched '}'"); |
||||
check_error("Expected format 's', got ']'", "<format>", 1, 2, 2); |
||||
json_decref(j); |
||||
|
||||
/* missing close array */ |
||||
j = json_pack("[]"); |
||||
if(!json_unpack_ex(j, &error, 0, "[")) |
||||
fail("json_unpack failed to catch missing ']'"); |
||||
check_error("Unexpected end of format string", "<format>", 1, 2, 2); |
||||
json_decref(j); |
||||
|
||||
/* missing close object */ |
||||
j = json_pack("{}"); |
||||
if(!json_unpack_ex(j, &error, 0, "{")) |
||||
fail("json_unpack failed to catch missing '}'"); |
||||
check_error("Unexpected end of format string", "<format>", 1, 2, 2); |
||||
json_decref(j); |
||||
|
||||
/* garbage after format string */ |
||||
j = json_pack("[i]", 42); |
||||
if(!json_unpack_ex(j, &error, 0, "[i]a", &i1)) |
||||
fail("json_unpack failed to catch garbage after format string"); |
||||
check_error("Garbage after format string", "<format>", 1, 4, 4); |
||||
json_decref(j); |
||||
|
||||
j = json_integer(12345); |
||||
if(!json_unpack_ex(j, &error, 0, "ia", &i1)) |
||||
fail("json_unpack failed to catch garbage after format string"); |
||||
check_error("Garbage after format string", "<format>", 1, 2, 2); |
||||
json_decref(j); |
||||
|
||||
/* NULL format string */ |
||||
j = json_pack("[]"); |
||||
if(!json_unpack_ex(j, &error, 0, NULL)) |
||||
fail("json_unpack failed to catch null format string"); |
||||
check_error("NULL or empty format string", "<format>", -1, -1, 0); |
||||
json_decref(j); |
||||
|
||||
/* NULL string pointer */ |
||||
j = json_string("foobie"); |
||||
if(!json_unpack_ex(j, &error, 0, "s", NULL)) |
||||
fail("json_unpack failed to catch null string pointer"); |
||||
check_error("NULL string argument", "<args>", 1, 1, 1); |
||||
json_decref(j); |
||||
|
||||
/* invalid types */ |
||||
j = json_integer(42); |
||||
j2 = json_string("foo"); |
||||
if(!json_unpack_ex(j, &error, 0, "s")) |
||||
fail("json_unpack failed to catch invalid type"); |
||||
check_error("Expected string, got integer", "<validation>", 1, 1, 1); |
||||
|
||||
if(!json_unpack_ex(j, &error, 0, "n")) |
||||
fail("json_unpack failed to catch invalid type"); |
||||
check_error("Expected null, got integer", "<validation>", 1, 1, 1); |
||||
|
||||
if(!json_unpack_ex(j, &error, 0, "b")) |
||||
fail("json_unpack failed to catch invalid type"); |
||||
check_error("Expected true or false, got integer", "<validation>", 1, 1, 1); |
||||
|
||||
if(!json_unpack_ex(j2, &error, 0, "i")) |
||||
fail("json_unpack failed to catch invalid type"); |
||||
check_error("Expected integer, got string", "<validation>", 1, 1, 1); |
||||
|
||||
if(!json_unpack_ex(j2, &error, 0, "I")) |
||||
fail("json_unpack failed to catch invalid type"); |
||||
check_error("Expected integer, got string", "<validation>", 1, 1, 1); |
||||
|
||||
if(!json_unpack_ex(j, &error, 0, "f")) |
||||
fail("json_unpack failed to catch invalid type"); |
||||
check_error("Expected real, got integer", "<validation>", 1, 1, 1); |
||||
|
||||
if(!json_unpack_ex(j2, &error, 0, "F")) |
||||
fail("json_unpack failed to catch invalid type"); |
||||
check_error("Expected real or integer, got string", "<validation>", 1, 1, 1); |
||||
|
||||
if(!json_unpack_ex(j, &error, 0, "[i]")) |
||||
fail("json_unpack failed to catch invalid type"); |
||||
check_error("Expected array, got integer", "<validation>", 1, 1, 1); |
||||
|
||||
if(!json_unpack_ex(j, &error, 0, "{si}", "foo")) |
||||
fail("json_unpack failed to catch invalid type"); |
||||
check_error("Expected object, got integer", "<validation>", 1, 1, 1); |
||||
|
||||
json_decref(j); |
||||
json_decref(j2); |
||||
|
||||
/* Array index out of range */ |
||||
j = json_pack("[i]", 1); |
||||
if(!json_unpack_ex(j, &error, 0, "[ii]", &i1, &i2)) |
||||
fail("json_unpack failed to catch index out of array bounds"); |
||||
check_error("Array index 1 out of range", "<validation>", 1, 3, 3); |
||||
json_decref(j); |
||||
|
||||
/* NULL object key */ |
||||
j = json_pack("{si}", "foo", 42); |
||||
if(!json_unpack_ex(j, &error, 0, "{si}", NULL, &i1)) |
||||
fail("json_unpack failed to catch null string pointer"); |
||||
check_error("NULL object key", "<args>", 1, 2, 2); |
||||
json_decref(j); |
||||
|
||||
/* Object key not found */ |
||||
j = json_pack("{si}", "foo", 42); |
||||
if(!json_unpack_ex(j, &error, 0, "{si}", "baz", &i1)) |
||||
fail("json_unpack failed to catch null string pointer"); |
||||
check_error("Object item not found: baz", "<validation>", 1, 3, 3); |
||||
json_decref(j); |
||||
|
||||
/*
|
||||
* Strict validation |
||||
*/ |
||||
|
||||
j = json_pack("[iii]", 1, 2, 3); |
||||
rv = json_unpack(j, "[iii!]", &i1, &i2, &i3); |
||||
if(rv || i1 != 1 || i2 != 2 || i3 != 3) |
||||
fail("json_unpack array with strict validation failed"); |
||||
json_decref(j); |
||||
|
||||
j = json_pack("[iii]", 1, 2, 3); |
||||
if(!json_unpack_ex(j, &error, 0, "[ii!]", &i1, &i2)) |
||||
fail("json_unpack array with strict validation failed"); |
||||
check_error("1 array item(s) left unpacked", "<validation>", 1, 5, 5); |
||||
json_decref(j); |
||||
|
||||
/* Like above, but with JSON_STRICT instead of '!' format */ |
||||
j = json_pack("[iii]", 1, 2, 3); |
||||
if(!json_unpack_ex(j, &error, JSON_STRICT, "[ii]", &i1, &i2)) |
||||
fail("json_unpack array with strict validation failed"); |
||||
check_error("1 array item(s) left unpacked", "<validation>", 1, 4, 4); |
||||
json_decref(j); |
||||
|
||||
j = json_pack("{s:s, s:i}", "foo", "bar", "baz", 42); |
||||
rv = json_unpack(j, "{sssi!}", "foo", &s, "baz", &i1); |
||||
if(rv || strcmp(s, "bar") != 0 || i1 != 42) |
||||
fail("json_unpack object with strict validation failed"); |
||||
json_decref(j); |
||||
|
||||
/* Unpack the same item twice */ |
||||
j = json_pack("{s:s, s:i}", "foo", "bar", "baz", 42); |
||||
if(!json_unpack_ex(j, &error, 0, "{s:s,s:s!}", "foo", &s, "foo", &s)) |
||||
fail("json_unpack object with strict validation failed"); |
||||
check_error("1 object item(s) left unpacked", "<validation>", 1, 10, 10); |
||||
json_decref(j); |
||||
|
||||
j = json_pack("[i,{s:i,s:n},[i,i]]", 1, "foo", 2, "bar", 3, 4); |
||||
if(json_unpack_ex(j, NULL, JSON_STRICT | JSON_VALIDATE_ONLY, |
||||
"[i{sisn}[ii]]", "foo", "bar")) |
||||
fail("json_unpack complex value with strict validation failed"); |
||||
json_decref(j); |
||||
|
||||
/* ! and * must be last */ |
||||
j = json_pack("[ii]", 1, 2); |
||||
if(!json_unpack_ex(j, &error, 0, "[i!i]", &i1, &i2)) |
||||
fail("json_unpack failed to catch ! in the middle of an array"); |
||||
check_error("Expected ']' after '!', got 'i'", "<format>", 1, 4, 4); |
||||
|
||||
if(!json_unpack_ex(j, &error, 0, "[i*i]", &i1, &i2)) |
||||
fail("json_unpack failed to catch * in the middle of an array"); |
||||
check_error("Expected ']' after '*', got 'i'", "<format>", 1, 4, 4); |
||||
json_decref(j); |
||||
|
||||
j = json_pack("{sssi}", "foo", "bar", "baz", 42); |
||||
if(!json_unpack_ex(j, &error, 0, "{ss!si}", "foo", &s, "baz", &i1)) |
||||
fail("json_unpack failed to catch ! in the middle of an object"); |
||||
check_error("Expected '}' after '!', got 's'", "<format>", 1, 5, 5); |
||||
|
||||
if(!json_unpack_ex(j, &error, 0, "{ss*si}", "foo", &s, "baz", &i1)) |
||||
fail("json_unpack failed to catch ! in the middle of an object"); |
||||
check_error("Expected '}' after '*', got 's'", "<format>", 1, 5, 5); |
||||
json_decref(j); |
||||
|
||||
/* Error in nested object */ |
||||
j = json_pack("{s{snsn}}", "foo", "bar", "baz"); |
||||
if(!json_unpack_ex(j, &error, 0, "{s{sn!}}", "foo", "bar")) |
||||
fail("json_unpack nested object with strict validation failed"); |
||||
check_error("1 object item(s) left unpacked", "<validation>", 1, 7, 7); |
||||
json_decref(j); |
||||
|
||||
/* Error in nested array */ |
||||
j = json_pack("[[ii]]", 1, 2); |
||||
if(!json_unpack_ex(j, &error, 0, "[[i!]]", &i1)) |
||||
fail("json_unpack nested array with strict validation failed"); |
||||
check_error("1 array item(s) left unpacked", "<validation>", 1, 5, 5); |
||||
json_decref(j); |
||||
|
||||
/* Optional values */ |
||||
j = json_object(); |
||||
i1 = 0; |
||||
if(json_unpack(j, "{s?i}", "foo", &i1)) |
||||
fail("json_unpack failed for optional key"); |
||||
if(i1 != 0) |
||||
fail("json_unpack unpacked an optional key"); |
||||
json_decref(j); |
||||
|
||||
i1 = 0; |
||||
j = json_pack("{si}", "foo", 42); |
||||
if(json_unpack(j, "{s?i}", "foo", &i1)) |
||||
fail("json_unpack failed for an optional value"); |
||||
if(i1 != 42) |
||||
fail("json_unpack failed to unpack an optional value"); |
||||
json_decref(j); |
||||
|
||||
j = json_object(); |
||||
i1 = i2 = i3 = 0; |
||||
if(json_unpack(j, "{s?[ii]s?{s{si}}}", |
||||
"foo", &i1, &i2, |
||||
"bar", "baz", "quux", &i3)) |
||||
fail("json_unpack failed for complex optional values"); |
||||
if(i1 != 0 || i2 != 0 || i3 != 0) |
||||
fail("json_unpack unexpectedly unpacked something"); |
||||
json_decref(j); |
||||
|
||||
j = json_pack("{s{si}}", "foo", "bar", 42); |
||||
if(json_unpack(j, "{s?{s?i}}", "foo", "bar", &i1)) |
||||
fail("json_unpack failed for complex optional values"); |
||||
if(i1 != 42) |
||||
fail("json_unpack failed to unpack"); |
||||
json_decref(j); |
||||
} |
@ -0,0 +1,74 @@
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org> |
||||
* |
||||
* Jansson is free software; you can redistribute it and/or modify |
||||
* it under the terms of the MIT license. See LICENSE for details. |
||||
*/ |
||||
|
||||
#ifndef UTIL_H |
||||
#define UTIL_H |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include <config.h> |
||||
#endif |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#if HAVE_LOCALE_H |
||||
#include <locale.h> |
||||
#endif |
||||
|
||||
#include <jansson.h> |
||||
|
||||
#define failhdr fprintf(stderr, "%s:%s:%d: ", __FILE__, __FUNCTION__, __LINE__) |
||||
|
||||
#define fail(msg) \ |
||||
do { \ |
||||
failhdr; \ |
||||
fprintf(stderr, "%s\n", msg); \ |
||||
exit(1); \ |
||||
} while(0) |
||||
|
||||
/* Assumes json_error_t error */ |
||||
#define check_error(text_, source_, line_, column_, position_) \ |
||||
do { \ |
||||
if(strcmp(error.text, text_) != 0) { \ |
||||
failhdr; \ |
||||
fprintf(stderr, "text: \"%s\" != \"%s\"\n", error.text, text_); \ |
||||
exit(1); \ |
||||
} \ |
||||
if(strcmp(error.source, source_) != 0) { \ |
||||
failhdr; \ |
||||
\ |
||||
fprintf(stderr, "source: \"%s\" != \"%s\"\n", error.source, source_); \ |
||||
exit(1); \ |
||||
} \ |
||||
if(error.line != line_) { \ |
||||
failhdr; \ |
||||
fprintf(stderr, "line: %d != %d\n", error.line, line_); \ |
||||
exit(1); \ |
||||
} \ |
||||
if(error.column != column_) { \ |
||||
failhdr; \ |
||||
fprintf(stderr, "column: %d != %d\n", error.column, column_); \ |
||||
exit(1); \ |
||||
} \ |
||||
if(error.position != position_) { \ |
||||
failhdr; \ |
||||
fprintf(stderr, "position: %d != %d\n", error.position, position_); \ |
||||
exit(1); \ |
||||
} \ |
||||
} while(0) |
||||
|
||||
|
||||
static void run_tests(); |
||||
|
||||
int main() { |
||||
#ifdef HAVE_SETLOCALE |
||||
setlocale(LC_ALL, ""); |
||||
#endif |
||||
run_tests(); |
||||
return 0; |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
1 2 2 |
||||
unable to decode byte 0xed near '"' |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
1 3 3 |
||||
unable to decode byte 0xe5 near '"\' |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
["\å"] |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
1 1 1 |
||||
unable to decode byte 0xe5 |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
[å] |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
1 4 4 |
||||
unable to decode byte 0xe5 near '123' |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
[123å] |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
1 4 4 |
||||
unable to decode byte 0xe5 near '"\u' |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
1 4 4 |
||||
unable to decode byte 0xe5 near '1e1' |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
[1e1å] |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
1 2 2 |
||||
unable to decode byte 0xe5 near 'a' |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
[a蘊 |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
1 2 2 |
||||
unable to decode byte 0xe5 near '0' |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
[0å] |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
1 3 3 |
||||
unable to decode byte 0xe5 near '1e' |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
[1e蘊 |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
1 2 2 |
||||
unable to decode byte 0xe5 near '"' |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
["å <-- invalid UTF-8"] |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
1 0 0 |
||||
unable to decode byte 0xe5 |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
1 2 2 |
||||
unable to decode byte 0x81 near '"' |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
1 2 2 |
||||
unable to decode byte 0xf4 near '"' |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
1 2 2 |
||||
unable to decode byte 0xe0 near '"' |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
1 2 2 |
||||
unable to decode byte 0xf0 near '"' |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
1 2 2 |
||||
unable to decode byte 0xc1 near '"' |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
1 2 2 |
||||
unable to decode byte 0xfd near '"' |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue