Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c2ca3fae6 | ||
|
|
2ae279e0d4 | ||
|
|
4c6cb6afd1 | ||
|
|
78594e9bd3 | ||
|
|
e921e63b54 | ||
|
|
f9febb64c5 | ||
|
|
b76ee75aad | ||
|
|
b077d7988e | ||
|
|
7f8684828d | ||
|
|
93ac06c902 | ||
|
|
b21f07b35c | ||
|
|
508873de9b | ||
|
|
aeb5b481c9 | ||
|
|
9db34dc31a | ||
|
|
95a468cebb | ||
|
|
22173c1d8b | ||
|
|
dd2fe1ebe8 | ||
|
|
6637b976ed | ||
|
|
f5202bedef | ||
|
|
2db2f2cfb6 | ||
|
|
e7a5dc58e6 | ||
|
|
3889af476b | ||
|
|
19a606d736 | ||
|
|
3add1cf361 | ||
|
|
50031440a3 | ||
|
|
d67aeb9739 | ||
|
|
e0a88d19d1 | ||
|
|
17d913307e | ||
|
|
f236c14dc5 | ||
|
|
bf01067a8a | ||
|
|
d1b07171cc | ||
|
|
5ff8ae8052 | ||
|
|
8d53f447bf |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -22,3 +22,4 @@ missing
|
||||
*.la
|
||||
stamp-h1
|
||||
*.pyc
|
||||
*.pc
|
||||
|
||||
110
CHANGES
110
CHANGES
@@ -1,54 +1,117 @@
|
||||
Version 1.1.3, released 2009-12-18
|
||||
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
|
||||
* Don't export private symbols in ``libjansson.so``
|
||||
|
||||
|
||||
Version 1.1.2, released 2009-11-08
|
||||
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()
|
||||
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 for stdint.h in jansson.h
|
||||
* Remove an unneeded include of ``stdint.h`` in ``jansson.h``
|
||||
|
||||
|
||||
Version 1.1.1, released 2009-10-26
|
||||
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
|
||||
* Fix v1.1 release date in ``CHANGES``
|
||||
|
||||
|
||||
Version 1.1, released 2009-10-20
|
||||
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
|
||||
- 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)
|
||||
* 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
|
||||
* 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
|
||||
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
|
||||
* Make Jansson compile on platforms where plain ``char`` is unsigned
|
||||
* Fix API tests for object
|
||||
|
||||
|
||||
Version 1.0.3, released 2009-09-14
|
||||
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
|
||||
@@ -56,16 +119,25 @@ Version 1.0.3, released 2009-09-14
|
||||
* Distribute changelog (this file)
|
||||
|
||||
|
||||
Version 1.0.2, released 2009-09-08
|
||||
Version 1.0.2
|
||||
=============
|
||||
|
||||
Released 2009-09-08
|
||||
|
||||
* Handle EOF correctly in decoder
|
||||
|
||||
|
||||
Version 1.0.1, released 2009-09-04
|
||||
Version 1.0.1
|
||||
=============
|
||||
|
||||
* Fixed broken json_is_boolean()
|
||||
Released 2009-09-04
|
||||
|
||||
* Fixed broken `json_is_boolean()`
|
||||
|
||||
|
||||
Version 1.0, released 2009-08-25
|
||||
Version 1.0
|
||||
===========
|
||||
|
||||
Released 2009-08-25
|
||||
|
||||
* Initial release
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
EXTRA_DIST = CHANGES LICENSE README.rst
|
||||
SUBDIRS = doc src test
|
||||
|
||||
distcheck-hook:
|
||||
sphinx-build -b html -W \
|
||||
$(distdir)/doc \
|
||||
$(distdir)/_build/doc/.build/html
|
||||
check-local: html
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = jansson.pc
|
||||
|
||||
@@ -36,8 +36,6 @@ To run the test suite, invoke::
|
||||
|
||||
$ make check
|
||||
|
||||
Python_ is required to run the tests.
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
@@ -49,15 +47,13 @@ available at http://www.digip.org/jansson/doc/.
|
||||
|
||||
To generate HTML documentation yourself, invoke::
|
||||
|
||||
cd doc/
|
||||
sphinx-build . .build/html
|
||||
make html
|
||||
|
||||
... and point your browser to ``.build/html/index.html``. Sphinx_ is
|
||||
and point your browser to ``doc/_build/html/index.html``. Sphinx_ is
|
||||
required to generate the documentation.
|
||||
|
||||
|
||||
.. _Jansson: http://www.digip.org/jansson/
|
||||
.. _`MIT license`: http://www.opensource.org/licenses/mit-license.php
|
||||
.. _Python: http://www.python.org/
|
||||
.. _reStructuredText: http://docutils.sourceforge.net/rst.html
|
||||
.. _Sphinx: http://sphinx.pocoo.org/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
AC_PREREQ([2.59])
|
||||
AC_INIT([jansson], [1.1.3], [petri@digip.org])
|
||||
AC_INIT([jansson], [1.2], [petri@digip.org])
|
||||
|
||||
AM_INIT_AUTOMAKE([1.10 foreign])
|
||||
|
||||
@@ -19,11 +19,13 @@ AC_PROG_LIBTOOL
|
||||
# Checks for library functions.
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
jansson.pc
|
||||
Makefile
|
||||
doc/Makefile
|
||||
src/Makefile
|
||||
test/Makefile
|
||||
test/testdata/Makefile
|
||||
test/testprogs/Makefile
|
||||
test/bin/Makefile
|
||||
test/suites/Makefile
|
||||
test/suites/api/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
||||
2
doc/.gitignore
vendored
2
doc/.gitignore
vendored
@@ -1 +1 @@
|
||||
.build/
|
||||
_build/
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
EXTRA_DIST = \
|
||||
conf.py apiref.rst gettingstarted.rst github_commits.c index.rst \
|
||||
tutorial.rst ext/refcounting.py
|
||||
EXTRA_DIST = conf.py apiref.rst changes.rst gettingstarted.rst \
|
||||
github_commits.c index.rst tutorial.rst ext/refcounting.py
|
||||
|
||||
SPHINXBUILD = sphinx-build
|
||||
SPHINXOPTS = -d _build/doctrees -W
|
||||
|
||||
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
|
||||
rm -rf _build
|
||||
rm -f ext/refcounting.pyc changes.rst
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
To build the documentation, invoke
|
||||
|
||||
sphinx-build . .build/html
|
||||
make html
|
||||
|
||||
in this directory. Then point your browser to .build/html/index.html.
|
||||
Then point your browser to _build/html/index.html.
|
||||
|
||||
147
doc/apiref.rst
147
doc/apiref.rst
@@ -229,6 +229,16 @@ String
|
||||
Returns a new JSON string, or *NULL* on error. *value* must be a
|
||||
valid UTF-8 encoded Unicode string.
|
||||
|
||||
.. cfunction:: json_t *json_string_nocheck(const char *value)
|
||||
|
||||
.. refcounting:: new
|
||||
|
||||
Like :cfunc:`json_string`, but doesn't check that *value* is valid
|
||||
UTF-8. Use this function only if you are certain that this really
|
||||
is the case (e.g. you have already checked it by other means).
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
||||
.. cfunction:: const char *json_string_value(const json_t *string)
|
||||
|
||||
Returns the associated value of *string* as a null terminated UTF-8
|
||||
@@ -242,6 +252,15 @@ String
|
||||
|
||||
.. versionadded:: 1.1
|
||||
|
||||
.. cfunction:: int json_string_set_nocheck(const json_t *string, const char *value)
|
||||
|
||||
Like :cfunc:`json_string_set`, but doesn't check that *value* is
|
||||
valid UTF-8. Use this function only if you are certain that this
|
||||
really is the case (e.g. you have already checked it by other
|
||||
means).
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
||||
|
||||
Number
|
||||
======
|
||||
@@ -420,6 +439,15 @@ Unicode string and the value is any JSON value.
|
||||
already is a value for *key*, it is replaced by the new value.
|
||||
Returns 0 on success and -1 on error.
|
||||
|
||||
.. cfunction:: int json_object_set_nocheck(json_t *object, const char *key, json_t *value)
|
||||
|
||||
Like :cfunc:`json_object_set`, but doesn't check that *key* is
|
||||
valid UTF-8. Use this function only if you are certain that this
|
||||
really is the case (e.g. you have already checked it by other
|
||||
means).
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
||||
.. cfunction:: int json_object_set_new(json_t *object, const char *key, json_t *value)
|
||||
|
||||
Like :cfunc:`json_object_set()` but steals the reference to
|
||||
@@ -428,6 +456,15 @@ Unicode string and the value is any JSON value.
|
||||
|
||||
.. versionadded:: 1.1
|
||||
|
||||
.. cfunction:: int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value)
|
||||
|
||||
Like :cfunc:`json_object_set_new`, but doesn't check that *key* is
|
||||
valid UTF-8. Use this function only if you are certain that this
|
||||
really is the case (e.g. you have already checked it by other
|
||||
means).
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
||||
.. cfunction:: int json_object_del(json_t *object, const char *key)
|
||||
|
||||
Delete *key* from *object* if it exists. Returns 0 on success, or
|
||||
@@ -494,16 +531,44 @@ This sections describes the functions that can be used to encode
|
||||
values to JSON. Only objects and arrays can be encoded, since they are
|
||||
the only valid "root" values of a JSON text.
|
||||
|
||||
By default, the output has no newlines, and spaces are used between
|
||||
array and object elements for a readable output. This behavior can be
|
||||
altered by using the ``JSON_INDENT`` and ``JSON_COMPACT`` flags
|
||||
described below. A newline is never appended to the end of the encoded
|
||||
JSON data.
|
||||
|
||||
Each function takes a *flags* parameter that controls some aspects of
|
||||
how the data is encoded. Its default value is 0. The following macros
|
||||
can be ORed together to obtain *flags*.
|
||||
|
||||
``JSON_INDENT(n)``
|
||||
Pretty-print the result, indenting arrays and objects by *n*
|
||||
spaces. The valid range for *n* is between 0 and 255, other values
|
||||
result in an undefined output. If ``JSON_INDENT`` is not used or
|
||||
*n* is 0, no pretty-printing is done and the result is a compact
|
||||
representation.
|
||||
Pretty-print the result, using newlines between array and object
|
||||
items, and indenting with *n* spaces. The valid range for *n* is
|
||||
between 0 and 255, other values result in an undefined output. If
|
||||
``JSON_INDENT`` is not used or *n* is 0, no newlines are inserted
|
||||
between array and object items.
|
||||
|
||||
``JSON_COMPACT``
|
||||
This flag enables a compact representation, i.e. sets the separator
|
||||
between array and object items to ``","`` and between object keys
|
||||
and values to ``":"``. Without this flag, the corresponding
|
||||
separators are ``", "`` and ``": "`` for more readable output.
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
||||
``JSON_ENSURE_ASCII``
|
||||
If this flag is used, the output is guaranteed to consist only of
|
||||
ASCII characters. This is achived by escaping all Unicode
|
||||
characters outside the ASCII range.
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
||||
``JSON_SORT_KEYS``
|
||||
If this flag is used, all the objects in output are sorted by key.
|
||||
This is useful e.g. if two JSON texts are diffed or visually
|
||||
compared.
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
||||
The following functions perform the actual JSON encoding. The result
|
||||
is in UTF-8.
|
||||
@@ -608,3 +673,75 @@ The following functions perform the actual JSON decoding.
|
||||
object it contains, or *NULL* on error, in which case *error* is
|
||||
filled with information about the error. See above for discussion
|
||||
on the *error* parameter.
|
||||
|
||||
|
||||
Equality
|
||||
========
|
||||
|
||||
Testing for equality of two JSON values cannot, in general, be
|
||||
achieved using the ``==`` operator. Equality in the terms of the
|
||||
``==`` operator states that the two :ctype:`json_t` pointers point to
|
||||
exactly the same JSON value. However, two JSON values can be equal not
|
||||
only if they are exactly the same value, but also if they have equal
|
||||
"contents":
|
||||
|
||||
* Two integer or real values are equal if their contained numeric
|
||||
values are equal. An integer value is never equal to a real value,
|
||||
though.
|
||||
|
||||
* Two strings are equal if their contained UTF-8 strings are equal.
|
||||
|
||||
* Two arrays are equal if they have the same number of elements and
|
||||
each element in the first array is equal to the corresponding
|
||||
element in the second array.
|
||||
|
||||
* Two objects are equal if they have exactly the same keys and the
|
||||
value for each key in the first object is equal to the value of the
|
||||
corresponding key in the second object.
|
||||
|
||||
* Two true, false or null values have no "contents", so they are equal
|
||||
if their types are equal. (Because these values are singletons,
|
||||
their equality can actually be tested with ``==``.)
|
||||
|
||||
The following function can be used to test whether two JSON values are
|
||||
equal.
|
||||
|
||||
.. cfunction:: int json_equal(json_t *value1, json_t *value2)
|
||||
|
||||
Returns 1 if *value1* and *value2* are equal, as defined above.
|
||||
Returns 0 if they are inequal or one or both of the pointers are
|
||||
*NULL*.
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
||||
|
||||
Copying
|
||||
=======
|
||||
|
||||
Because of reference counting, passing JSON values around doesn't
|
||||
require copying them. But sometimes a fresh copy of a JSON value is
|
||||
needed. For example, if you need to modify an array, but still want to
|
||||
use the original afterwards, you should take a copy of it first.
|
||||
|
||||
Jansson supports two kinds of copying: shallow and deep. There is a
|
||||
difference between these methods only for arrays and objects. Shallow
|
||||
copying only copies the first level value (array or object) and uses
|
||||
the same child values in the copied value. Deep copying makes a fresh
|
||||
copy of the child values, too. Moreover, all the child values are deep
|
||||
copied in a recursive fashion.
|
||||
|
||||
.. cfunction:: json_t *json_copy(json_t *value)
|
||||
|
||||
.. refcounting:: new
|
||||
|
||||
Returns a shallow copy of *value*, or *NULL* on error.
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
||||
.. cfunction:: json_t *json_deep_copy(json_t *value)
|
||||
|
||||
.. refcounting:: new
|
||||
|
||||
Returns a deep copy of *value*, or *NULL* on error.
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
||||
5
doc/changes.rst
Normal file
5
doc/changes.rst
Normal file
@@ -0,0 +1,5 @@
|
||||
******************
|
||||
Changes in Jansson
|
||||
******************
|
||||
|
||||
.. include:: ../CHANGES
|
||||
@@ -50,9 +50,9 @@ copyright = u'2009, Petri Lehtinen'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '1.1'
|
||||
version = '1.2'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.1.3'
|
||||
release = '1.2'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
@@ -69,10 +69,10 @@ release = '1.1.3'
|
||||
|
||||
# List of directories, relative to source directory, that shouldn't be searched
|
||||
# for source files.
|
||||
exclude_trees = ['.build']
|
||||
exclude_trees = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
default_role = 'cfunc'
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
@@ -31,9 +31,9 @@ the ``--prefix=DIR`` argument to ``./configure``. See ``./configure
|
||||
no options to customize the resulting Jansson binary.)
|
||||
|
||||
The command ``make check`` runs the test suite distributed with
|
||||
Jansson. Python_ is required to run the tests. 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.
|
||||
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
|
||||
@@ -44,12 +44,11 @@ to use ``autoreconf``::
|
||||
autoreconf -vi
|
||||
|
||||
This command creates the ``./configure`` script, which can then be
|
||||
used as described in the previous section.
|
||||
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/
|
||||
.. _Python: http://www.python.org/
|
||||
|
||||
|
||||
Installing Prebuilt Binary Packages
|
||||
@@ -76,18 +75,17 @@ Documentation is in the ``doc/`` subdirectory. It's written in
|
||||
reStructuredText_ with Sphinx_ annotations. To generate the HTML
|
||||
documentation, invoke::
|
||||
|
||||
cd doc/
|
||||
sphinx-build . .build/html
|
||||
make html
|
||||
|
||||
... and point your browser to ``.build/html/index.html``. Sphinx_ is
|
||||
and point your browser to ``doc/_build/html/index.html``. Sphinx_ is
|
||||
required to generate the documentation.
|
||||
|
||||
.. _reStructuredText: http://docutils.sourceforge.net/rst.html
|
||||
.. _Sphinx: http://sphinx.pocoo.org/
|
||||
|
||||
|
||||
Compiling Programs Using Jansson
|
||||
================================
|
||||
Compiling Programs That Use Jansson
|
||||
===================================
|
||||
|
||||
Jansson involves one C header file, :file:`jansson.h`, so it's enough
|
||||
to put the line
|
||||
@@ -102,3 +100,9 @@ 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/
|
||||
|
||||
@@ -35,6 +35,7 @@ Contents
|
||||
gettingstarted
|
||||
tutorial
|
||||
apiref
|
||||
changes
|
||||
|
||||
|
||||
Indices and Tables
|
||||
|
||||
10
jansson.pc.in
Normal file
10
jansson.pc.in
Normal file
@@ -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}
|
||||
@@ -15,6 +15,6 @@ libjansson_la_SOURCES = \
|
||||
value.c
|
||||
libjansson_la_LDFLAGS = \
|
||||
-export-symbols-regex '^json_' \
|
||||
-version-info 1:2:1
|
||||
-version-info 2:0:2
|
||||
|
||||
AM_CFLAGS = -Wall -Wextra -Werror
|
||||
|
||||
199
src/dump.c
199
src/dump.c
@@ -9,10 +9,13 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <jansson.h>
|
||||
#include "jansson_private.h"
|
||||
#include "strbuffer.h"
|
||||
#include "utf.h"
|
||||
|
||||
#define MAX_INTEGER_STR_LENGTH 100
|
||||
#define MAX_REAL_STR_LENGTH 100
|
||||
@@ -42,7 +45,7 @@ static int dump_to_file(const char *buffer, int size, void *data)
|
||||
/* 256 spaces (the maximum indentation size) */
|
||||
static char whitespace[] = " ";
|
||||
|
||||
static int dump_indent(unsigned long flags, int depth, dump_func dump, void *data)
|
||||
static int dump_indent(unsigned long flags, int depth, int space, dump_func dump, void *data)
|
||||
{
|
||||
if(JSON_INDENT(flags) > 0)
|
||||
{
|
||||
@@ -57,37 +60,56 @@ static int dump_indent(unsigned long flags, int depth, dump_func dump, void *dat
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if(space && !(flags & JSON_COMPACT))
|
||||
{
|
||||
return dump(" ", 1, data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dump_string(const char *str, dump_func dump, void *data)
|
||||
static int dump_string(const char *str, int ascii, dump_func dump, void *data)
|
||||
{
|
||||
const char *end;
|
||||
const char *pos, *end;
|
||||
int32_t codepoint;
|
||||
|
||||
if(dump("\"", 1, data))
|
||||
return -1;
|
||||
|
||||
end = str;
|
||||
end = pos = str;
|
||||
while(1)
|
||||
{
|
||||
const char *text;
|
||||
char seq[7];
|
||||
char seq[13];
|
||||
int length;
|
||||
|
||||
while(*end && *end != '\\' && *end != '"' && (unsigned char)*end > 0x1F)
|
||||
end++;
|
||||
while(*end)
|
||||
{
|
||||
end = utf8_iterate(pos, &codepoint);
|
||||
if(!end)
|
||||
return -1;
|
||||
|
||||
if(end != str) {
|
||||
if(dump(str, end - str, data))
|
||||
/* mandatory escape or control char */
|
||||
if(codepoint == '\\' || codepoint == '"' || codepoint < 0x20)
|
||||
break;
|
||||
|
||||
/* non-ASCII */
|
||||
if(ascii && codepoint > 0x7F)
|
||||
break;
|
||||
|
||||
pos = end;
|
||||
}
|
||||
|
||||
if(pos != str) {
|
||||
if(dump(str, pos - str, data))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!*end)
|
||||
if(end == pos)
|
||||
break;
|
||||
|
||||
/* handle \, ", and control codes */
|
||||
length = 2;
|
||||
switch(*end)
|
||||
switch(codepoint)
|
||||
{
|
||||
case '\\': text = "\\\\"; break;
|
||||
case '\"': text = "\\\""; break;
|
||||
@@ -98,9 +120,27 @@ static int dump_string(const char *str, dump_func dump, void *data)
|
||||
case '\t': text = "\\t"; break;
|
||||
default:
|
||||
{
|
||||
sprintf(seq, "\\u00%02x", *end);
|
||||
/* codepoint is in BMP */
|
||||
if(codepoint < 0x10000)
|
||||
{
|
||||
sprintf(seq, "\\u%04x", codepoint);
|
||||
length = 6;
|
||||
}
|
||||
|
||||
/* not in BMP -> construct a UTF-16 surrogate pair */
|
||||
else
|
||||
{
|
||||
int32_t first, last;
|
||||
|
||||
codepoint -= 0x10000;
|
||||
first = 0xD800 | ((codepoint & 0xffc00) >> 10);
|
||||
last = 0xDC00 | (codepoint & 0x003ff);
|
||||
|
||||
sprintf(seq, "\\u%04x\\u%04x", first, last);
|
||||
length = 12;
|
||||
}
|
||||
|
||||
text = seq;
|
||||
length = 6;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -108,16 +148,22 @@ static int dump_string(const char *str, dump_func dump, void *data)
|
||||
if(dump(text, length, data))
|
||||
return -1;
|
||||
|
||||
end++;
|
||||
str = end;
|
||||
str = pos = end;
|
||||
}
|
||||
|
||||
return dump("\"", 1, data);
|
||||
}
|
||||
|
||||
static int object_key_cmp(const void *key1, const void *key2)
|
||||
{
|
||||
return strcmp(*(const char **)key1, *(const char **)key2);
|
||||
}
|
||||
|
||||
static int do_dump(const json_t *json, unsigned long flags, int depth,
|
||||
dump_func dump, void *data)
|
||||
{
|
||||
int ascii = flags & JSON_ENSURE_ASCII ? 1 : 0;
|
||||
|
||||
switch(json_typeof(json)) {
|
||||
case JSON_NULL:
|
||||
return dump("null", 4, data);
|
||||
@@ -168,7 +214,7 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
|
||||
}
|
||||
|
||||
case JSON_STRING:
|
||||
return dump_string(json_string_value(json), dump, data);
|
||||
return dump_string(json_string_value(json), ascii, dump, data);
|
||||
|
||||
case JSON_ARRAY:
|
||||
{
|
||||
@@ -188,7 +234,7 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
|
||||
return -1;
|
||||
if(n == 0)
|
||||
return dump("]", 1, data);
|
||||
if(dump_indent(flags, depth + 1, dump, data))
|
||||
if(dump_indent(flags, depth + 1, 0, dump, data))
|
||||
return -1;
|
||||
|
||||
for(i = 0; i < n; ++i) {
|
||||
@@ -199,12 +245,12 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
|
||||
if(i < n - 1)
|
||||
{
|
||||
if(dump(",", 1, data) ||
|
||||
dump_indent(flags, depth + 1, dump, data))
|
||||
dump_indent(flags, depth + 1, 1, dump, data))
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(dump_indent(flags, depth, dump, data))
|
||||
if(dump_indent(flags, depth, 0, dump, data))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -217,6 +263,17 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
|
||||
{
|
||||
json_object_t *object;
|
||||
void *iter;
|
||||
const char *separator;
|
||||
int separator_length;
|
||||
|
||||
if(flags & JSON_COMPACT) {
|
||||
separator = ":";
|
||||
separator_length = 1;
|
||||
}
|
||||
else {
|
||||
separator = ": ";
|
||||
separator_length = 2;
|
||||
}
|
||||
|
||||
/* detect circular references */
|
||||
object = json_to_object(json);
|
||||
@@ -230,32 +287,99 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
|
||||
return -1;
|
||||
if(!iter)
|
||||
return dump("}", 1, data);
|
||||
if(dump_indent(flags, depth + 1, dump, data))
|
||||
if(dump_indent(flags, depth + 1, 0, dump, data))
|
||||
return -1;
|
||||
|
||||
while(iter)
|
||||
if(flags & JSON_SORT_KEYS)
|
||||
{
|
||||
void *next = json_object_iter_next((json_t *)json, iter);
|
||||
/* Sort keys */
|
||||
|
||||
dump_string(json_object_iter_key(iter), dump, data);
|
||||
if(dump(": ", 2, data) ||
|
||||
do_dump(json_object_iter_value(iter), flags, depth + 1,
|
||||
dump, data))
|
||||
const char **keys;
|
||||
unsigned int size;
|
||||
unsigned int i;
|
||||
|
||||
size = json_object_size(json);
|
||||
keys = malloc(size * sizeof(const char *));
|
||||
if(!keys)
|
||||
return -1;
|
||||
|
||||
if(next)
|
||||
i = 0;
|
||||
while(iter)
|
||||
{
|
||||
if(dump(",", 1, data) ||
|
||||
dump_indent(flags, depth + 1, dump, data))
|
||||
return -1;
|
||||
keys[i] = json_object_iter_key(iter);
|
||||
iter = json_object_iter_next((json_t *)json, iter);
|
||||
i++;
|
||||
}
|
||||
else
|
||||
assert(i == size);
|
||||
|
||||
qsort(keys, size, sizeof(const char *), object_key_cmp);
|
||||
|
||||
for(i = 0; i < size; i++)
|
||||
{
|
||||
if(dump_indent(flags, depth, dump, data))
|
||||
const char *key;
|
||||
json_t *value;
|
||||
|
||||
key = keys[i];
|
||||
value = json_object_get(json, key);
|
||||
assert(value);
|
||||
|
||||
dump_string(key, ascii, dump, data);
|
||||
if(dump(separator, separator_length, data) ||
|
||||
do_dump(value, flags, depth + 1, dump, data))
|
||||
{
|
||||
free(keys);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(i < size - 1)
|
||||
{
|
||||
if(dump(",", 1, data) ||
|
||||
dump_indent(flags, depth + 1, 1, dump, data))
|
||||
{
|
||||
free(keys);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(dump_indent(flags, depth, 0, dump, data))
|
||||
{
|
||||
free(keys);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iter = next;
|
||||
free(keys);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Don't sort keys */
|
||||
|
||||
while(iter)
|
||||
{
|
||||
void *next = json_object_iter_next((json_t *)json, iter);
|
||||
|
||||
dump_string(json_object_iter_key(iter), ascii, dump, data);
|
||||
if(dump(separator, separator_length, data) ||
|
||||
do_dump(json_object_iter_value(iter), flags, depth + 1,
|
||||
dump, data))
|
||||
return -1;
|
||||
|
||||
if(next)
|
||||
{
|
||||
if(dump(",", 1, data) ||
|
||||
dump_indent(flags, depth + 1, 1, dump, data))
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(dump_indent(flags, depth, 0, dump, data))
|
||||
return -1;
|
||||
}
|
||||
|
||||
iter = next;
|
||||
}
|
||||
}
|
||||
|
||||
object->visited = 0;
|
||||
@@ -285,11 +409,6 @@ char *json_dumps(const json_t *json, unsigned long flags)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(dump_to_strbuffer("\n", 1, (void *)&strbuff)) {
|
||||
strbuffer_close(&strbuff);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = strdup(strbuffer_value(&strbuff));
|
||||
strbuffer_close(&strbuff);
|
||||
|
||||
@@ -301,9 +420,7 @@ int json_dumpf(const json_t *json, FILE *output, unsigned long flags)
|
||||
if(!json_is_array(json) && !json_is_object(json))
|
||||
return -1;
|
||||
|
||||
if(do_dump(json, flags, 0, dump_to_file, (void *)output))
|
||||
return -1;
|
||||
return dump_to_file("\n", 1, (void *)output);
|
||||
return do_dump(json, flags, 0, dump_to_file, (void *)output);
|
||||
}
|
||||
|
||||
int json_dump_file(const json_t *json, const char *path, unsigned long flags)
|
||||
|
||||
@@ -49,6 +49,7 @@ typedef struct {
|
||||
json_t *json_object(void);
|
||||
json_t *json_array(void);
|
||||
json_t *json_string(const char *value);
|
||||
json_t *json_string_nocheck(const char *value);
|
||||
json_t *json_integer(int value);
|
||||
json_t *json_real(double value);
|
||||
json_t *json_true(void);
|
||||
@@ -77,6 +78,7 @@ static inline void json_decref(json_t *json)
|
||||
unsigned int json_object_size(const json_t *object);
|
||||
json_t *json_object_get(const json_t *object, const char *key);
|
||||
int json_object_set_new(json_t *object, const char *key, json_t *value);
|
||||
int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value);
|
||||
int json_object_del(json_t *object, const char *key);
|
||||
int json_object_clear(json_t *object);
|
||||
int json_object_update(json_t *object, json_t *other);
|
||||
@@ -91,6 +93,12 @@ int json_object_set(json_t *object, const char *key, json_t *value)
|
||||
return json_object_set_new(object, key, json_incref(value));
|
||||
}
|
||||
|
||||
static inline
|
||||
int json_object_set_nocheck(json_t *object, const char *key, json_t *value)
|
||||
{
|
||||
return json_object_set_new_nocheck(object, key, json_incref(value));
|
||||
}
|
||||
|
||||
unsigned int json_array_size(const json_t *array);
|
||||
json_t *json_array_get(const json_t *array, unsigned int index);
|
||||
int json_array_set_new(json_t *array, unsigned int index, json_t *value);
|
||||
@@ -123,9 +131,21 @@ int json_integer_value(const json_t *integer);
|
||||
double json_real_value(const json_t *real);
|
||||
double json_number_value(const json_t *json);
|
||||
|
||||
int json_string_set(const json_t *string, const char *value);
|
||||
int json_integer_set(const json_t *integer, int value);
|
||||
int json_real_set(const json_t *real, double value);
|
||||
int json_string_set(json_t *string, const char *value);
|
||||
int json_string_set_nocheck(json_t *string, const char *value);
|
||||
int json_integer_set(json_t *integer, int value);
|
||||
int json_real_set(json_t *real, double value);
|
||||
|
||||
|
||||
/* equality */
|
||||
|
||||
int json_equal(json_t *value1, json_t *value2);
|
||||
|
||||
|
||||
/* copying */
|
||||
|
||||
json_t *json_copy(json_t *value);
|
||||
json_t *json_deep_copy(json_t *value);
|
||||
|
||||
|
||||
/* loading, printing */
|
||||
@@ -141,7 +161,10 @@ json_t *json_loads(const char *input, json_error_t *error);
|
||||
json_t *json_loadf(FILE *input, json_error_t *error);
|
||||
json_t *json_load_file(const char *path, json_error_t *error);
|
||||
|
||||
#define JSON_INDENT(n) (n & 0xFF)
|
||||
#define JSON_INDENT(n) (n & 0xFF)
|
||||
#define JSON_COMPACT 0x100
|
||||
#define JSON_ENSURE_ASCII 0x200
|
||||
#define JSON_SORT_KEYS 0x400
|
||||
|
||||
char *json_dumps(const json_t *json, unsigned long flags);
|
||||
int json_dumpf(const json_t *json, FILE *output, unsigned long flags);
|
||||
|
||||
@@ -49,7 +49,4 @@ typedef struct {
|
||||
#define json_to_real(json_) container_of(json_, json_real_t, json)
|
||||
#define json_to_integer(json_) container_of(json_, json_integer_t, json)
|
||||
|
||||
int json_object_set_nocheck(json_t *json, const char *key, json_t *value);
|
||||
json_t *json_string_nocheck(const char *value);
|
||||
|
||||
#endif
|
||||
|
||||
11
src/load.c
11
src/load.c
@@ -14,6 +14,7 @@
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <jansson.h>
|
||||
#include "jansson_private.h"
|
||||
@@ -148,7 +149,7 @@ static char stream_get(stream_t *stream, json_error_t *error)
|
||||
for(i = 1; i < count; i++)
|
||||
stream->buffer[i] = stream->get(stream->data);
|
||||
|
||||
if(!utf8_check_full(stream->buffer, count))
|
||||
if(!utf8_check_full(stream->buffer, count, NULL))
|
||||
goto out;
|
||||
|
||||
stream->stream_pos += count;
|
||||
@@ -221,10 +222,10 @@ static void lex_save_cached(lex_t *lex)
|
||||
}
|
||||
|
||||
/* assumes that str points to 'u' plus at least 4 valid hex digits */
|
||||
static int decode_unicode_escape(const char *str)
|
||||
static int32_t decode_unicode_escape(const char *str)
|
||||
{
|
||||
int i;
|
||||
int value = 0;
|
||||
int32_t value = 0;
|
||||
|
||||
assert(str[0] == 'u');
|
||||
|
||||
@@ -325,7 +326,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
|
||||
if(*p == 'u') {
|
||||
char buffer[4];
|
||||
int length;
|
||||
int value;
|
||||
int32_t value;
|
||||
|
||||
value = decode_unicode_escape(p);
|
||||
p += 5;
|
||||
@@ -333,7 +334,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
|
||||
if(0xD800 <= value && value <= 0xDBFF) {
|
||||
/* surrogate pair */
|
||||
if(*p == '\\' && *(p + 1) == 'u') {
|
||||
int value2 = decode_unicode_escape(++p);
|
||||
int32_t value2 = decode_unicode_escape(++p);
|
||||
p += 5;
|
||||
|
||||
if(0xDC00 <= value2 && value2 <= 0xDFFF) {
|
||||
|
||||
39
src/utf.c
39
src/utf.c
@@ -6,8 +6,9 @@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int utf8_encode(int codepoint, char *buffer, int *size)
|
||||
int utf8_encode(int32_t codepoint, char *buffer, int *size)
|
||||
{
|
||||
if(codepoint < 0)
|
||||
return -1;
|
||||
@@ -79,9 +80,10 @@ int utf8_check_first(char byte)
|
||||
}
|
||||
}
|
||||
|
||||
int utf8_check_full(const char *buffer, int size)
|
||||
int utf8_check_full(const char *buffer, int size, int32_t *codepoint)
|
||||
{
|
||||
int i, value = 0;
|
||||
int i;
|
||||
int32_t value = 0;
|
||||
unsigned char u = (unsigned char)buffer[0];
|
||||
|
||||
if(size == 2)
|
||||
@@ -128,9 +130,38 @@ int utf8_check_full(const char *buffer, int size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(codepoint)
|
||||
*codepoint = value;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *utf8_iterate(const char *buffer, int32_t *codepoint)
|
||||
{
|
||||
int count;
|
||||
int32_t value;
|
||||
|
||||
if(!*buffer)
|
||||
return buffer;
|
||||
|
||||
count = utf8_check_first(buffer[0]);
|
||||
if(count <= 0)
|
||||
return NULL;
|
||||
|
||||
if(count == 1)
|
||||
value = (unsigned char)buffer[0];
|
||||
else
|
||||
{
|
||||
if(!utf8_check_full(buffer, count, &value))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(codepoint)
|
||||
*codepoint = value;
|
||||
|
||||
return buffer + count;
|
||||
}
|
||||
|
||||
int utf8_check_string(const char *string, int length)
|
||||
{
|
||||
int i;
|
||||
@@ -148,7 +179,7 @@ int utf8_check_string(const char *string, int length)
|
||||
if(i + count > length)
|
||||
return 0;
|
||||
|
||||
if(!utf8_check_full(&string[i], count))
|
||||
if(!utf8_check_full(&string[i], count, NULL))
|
||||
return 0;
|
||||
|
||||
i += count - 1;
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
int utf8_encode(int codepoint, char *buffer, int *size);
|
||||
|
||||
int utf8_check_first(char byte);
|
||||
int utf8_check_full(const char *buffer, int size);
|
||||
int utf8_check_full(const char *buffer, int size, int32_t *codepoint);
|
||||
const char *utf8_iterate(const char *buffer, int32_t *codepoint);
|
||||
|
||||
int utf8_check_string(const char *string, int length);
|
||||
|
||||
|
||||
272
src/value.c
272
src/value.c
@@ -120,11 +120,6 @@ int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int json_object_set_nocheck(json_t *json, const char *key, json_t *value)
|
||||
{
|
||||
return json_object_set_new_nocheck(json, key, json_incref(value));
|
||||
}
|
||||
|
||||
int json_object_set_new(json_t *json, const char *key, json_t *value)
|
||||
{
|
||||
if(!key || !utf8_check_string(key, -1))
|
||||
@@ -175,7 +170,7 @@ int json_object_update(json_t *object, json_t *other)
|
||||
key = json_object_iter_key(iter);
|
||||
value = json_object_iter_value(iter);
|
||||
|
||||
if(json_object_set(object, key, value))
|
||||
if(json_object_set_nocheck(object, key, value))
|
||||
return -1;
|
||||
|
||||
iter = json_object_iter_next(other, iter);
|
||||
@@ -222,6 +217,82 @@ json_t *json_object_iter_value(void *iter)
|
||||
return (json_t *)hashtable_iter_value(iter);
|
||||
}
|
||||
|
||||
static int json_object_equal(json_t *object1, json_t *object2)
|
||||
{
|
||||
void *iter;
|
||||
|
||||
if(json_object_size(object1) != json_object_size(object2))
|
||||
return 0;
|
||||
|
||||
iter = json_object_iter(object1);
|
||||
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(object2, key);
|
||||
|
||||
if(!json_equal(value1, value2))
|
||||
return 0;
|
||||
|
||||
iter = json_object_iter_next(object1, iter);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static json_t *json_object_copy(json_t *object)
|
||||
{
|
||||
json_t *result;
|
||||
void *iter;
|
||||
|
||||
result = json_object();
|
||||
if(!result)
|
||||
return NULL;
|
||||
|
||||
iter = json_object_iter(object);
|
||||
while(iter)
|
||||
{
|
||||
const char *key;
|
||||
json_t *value;
|
||||
|
||||
key = json_object_iter_key(iter);
|
||||
value = json_object_iter_value(iter);
|
||||
json_object_set_nocheck(result, key, value);
|
||||
|
||||
iter = json_object_iter_next(object, iter);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static json_t *json_object_deep_copy(json_t *object)
|
||||
{
|
||||
json_t *result;
|
||||
void *iter;
|
||||
|
||||
result = json_object();
|
||||
if(!result)
|
||||
return NULL;
|
||||
|
||||
iter = json_object_iter(object);
|
||||
while(iter)
|
||||
{
|
||||
const char *key;
|
||||
json_t *value;
|
||||
|
||||
key = json_object_iter_key(iter);
|
||||
value = json_object_iter_value(iter);
|
||||
json_object_set_new_nocheck(result, key, json_deep_copy(value));
|
||||
|
||||
iter = json_object_iter_next(object, iter);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*** array ***/
|
||||
|
||||
@@ -468,6 +539,57 @@ int json_array_extend(json_t *json, json_t *other_json)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int json_array_equal(json_t *array1, json_t *array2)
|
||||
{
|
||||
unsigned int i, size;
|
||||
|
||||
size = json_array_size(array1);
|
||||
if(size != json_array_size(array2))
|
||||
return 0;
|
||||
|
||||
for(i = 0; i < size; i++)
|
||||
{
|
||||
json_t *value1, *value2;
|
||||
|
||||
value1 = json_array_get(array1, i);
|
||||
value2 = json_array_get(array2, i);
|
||||
|
||||
if(!json_equal(value1, value2))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static json_t *json_array_copy(json_t *array)
|
||||
{
|
||||
json_t *result;
|
||||
unsigned int i;
|
||||
|
||||
result = json_array();
|
||||
if(!result)
|
||||
return NULL;
|
||||
|
||||
for(i = 0; i < json_array_size(array); i++)
|
||||
json_array_append(result, json_array_get(array, i));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static json_t *json_array_deep_copy(json_t *array)
|
||||
{
|
||||
json_t *result;
|
||||
unsigned int i;
|
||||
|
||||
result = json_array();
|
||||
if(!result)
|
||||
return NULL;
|
||||
|
||||
for(i = 0; i < json_array_size(array); i++)
|
||||
json_array_append_new(result, json_deep_copy(json_array_get(array, i)));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*** string ***/
|
||||
|
||||
@@ -508,14 +630,11 @@ const char *json_string_value(const json_t *json)
|
||||
return json_to_string(json)->value;
|
||||
}
|
||||
|
||||
int json_string_set(const json_t *json, const char *value)
|
||||
int json_string_set_nocheck(json_t *json, const char *value)
|
||||
{
|
||||
char *dup;
|
||||
json_string_t *string;
|
||||
|
||||
if(!json_is_string(json) || !value || !utf8_check_string(value, -1))
|
||||
return -1;
|
||||
|
||||
dup = strdup(value);
|
||||
if(!dup)
|
||||
return -1;
|
||||
@@ -527,12 +646,30 @@ int json_string_set(const json_t *json, const char *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int json_string_set(json_t *json, const char *value)
|
||||
{
|
||||
if(!value || !utf8_check_string(value, -1))
|
||||
return -1;
|
||||
|
||||
return json_string_set_nocheck(json, value);
|
||||
}
|
||||
|
||||
static void json_delete_string(json_string_t *string)
|
||||
{
|
||||
free(string->value);
|
||||
free(string);
|
||||
}
|
||||
|
||||
static int json_string_equal(json_t *string1, json_t *string2)
|
||||
{
|
||||
return strcmp(json_string_value(string1), json_string_value(string2)) == 0;
|
||||
}
|
||||
|
||||
static json_t *json_string_copy(json_t *string)
|
||||
{
|
||||
return json_string_nocheck(json_string_value(string));
|
||||
}
|
||||
|
||||
|
||||
/*** integer ***/
|
||||
|
||||
@@ -555,7 +692,7 @@ int json_integer_value(const json_t *json)
|
||||
return json_to_integer(json)->value;
|
||||
}
|
||||
|
||||
int json_integer_set(const json_t *json, int value)
|
||||
int json_integer_set(json_t *json, int value)
|
||||
{
|
||||
if(!json_is_integer(json))
|
||||
return -1;
|
||||
@@ -570,6 +707,16 @@ static void json_delete_integer(json_integer_t *integer)
|
||||
free(integer);
|
||||
}
|
||||
|
||||
static int json_integer_equal(json_t *integer1, json_t *integer2)
|
||||
{
|
||||
return json_integer_value(integer1) == json_integer_value(integer2);
|
||||
}
|
||||
|
||||
static json_t *json_integer_copy(json_t *integer)
|
||||
{
|
||||
return json_integer(json_integer_value(integer));
|
||||
}
|
||||
|
||||
|
||||
/*** real ***/
|
||||
|
||||
@@ -592,7 +739,7 @@ double json_real_value(const json_t *json)
|
||||
return json_to_real(json)->value;
|
||||
}
|
||||
|
||||
int json_real_set(const json_t *json, double value)
|
||||
int json_real_set(json_t *json, double value)
|
||||
{
|
||||
if(!json_is_real(json))
|
||||
return 0;
|
||||
@@ -607,6 +754,16 @@ static void json_delete_real(json_real_t *real)
|
||||
free(real);
|
||||
}
|
||||
|
||||
static int json_real_equal(json_t *real1, json_t *real2)
|
||||
{
|
||||
return json_real_value(real1) == json_real_value(real2);
|
||||
}
|
||||
|
||||
static json_t *json_real_copy(json_t *real)
|
||||
{
|
||||
return json_real(json_real_value(real));
|
||||
}
|
||||
|
||||
|
||||
/*** number ***/
|
||||
|
||||
@@ -674,3 +831,94 @@ void json_delete(json_t *json)
|
||||
|
||||
/* json_delete is not called for true, false or null */
|
||||
}
|
||||
|
||||
|
||||
/*** equality ***/
|
||||
|
||||
int json_equal(json_t *json1, json_t *json2)
|
||||
{
|
||||
if(!json1 || !json2)
|
||||
return 0;
|
||||
|
||||
if(json_typeof(json1) != json_typeof(json2))
|
||||
return 0;
|
||||
|
||||
/* this covers true, false and null as they are singletons */
|
||||
if(json1 == json2)
|
||||
return 1;
|
||||
|
||||
if(json_is_object(json1))
|
||||
return json_object_equal(json1, json2);
|
||||
|
||||
if(json_is_array(json1))
|
||||
return json_array_equal(json1, json2);
|
||||
|
||||
if(json_is_string(json1))
|
||||
return json_string_equal(json1, json2);
|
||||
|
||||
if(json_is_integer(json1))
|
||||
return json_integer_equal(json1, json2);
|
||||
|
||||
if(json_is_real(json1))
|
||||
return json_real_equal(json1, json2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*** copying ***/
|
||||
|
||||
json_t *json_copy(json_t *json)
|
||||
{
|
||||
if(!json)
|
||||
return NULL;
|
||||
|
||||
if(json_is_object(json))
|
||||
return json_object_copy(json);
|
||||
|
||||
if(json_is_array(json))
|
||||
return json_array_copy(json);
|
||||
|
||||
if(json_is_string(json))
|
||||
return json_string_copy(json);
|
||||
|
||||
if(json_is_integer(json))
|
||||
return json_integer_copy(json);
|
||||
|
||||
if(json_is_real(json))
|
||||
return json_real_copy(json);
|
||||
|
||||
if(json_is_true(json) || json_is_false(json) || json_is_null(json))
|
||||
return json;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
json_t *json_deep_copy(json_t *json)
|
||||
{
|
||||
if(!json)
|
||||
return NULL;
|
||||
|
||||
if(json_is_object(json))
|
||||
return json_object_deep_copy(json);
|
||||
|
||||
if(json_is_array(json))
|
||||
return json_array_deep_copy(json);
|
||||
|
||||
/* for the rest of the types, deep copying doesn't differ from
|
||||
shallow copying */
|
||||
|
||||
if(json_is_string(json))
|
||||
return json_string_copy(json);
|
||||
|
||||
if(json_is_integer(json))
|
||||
return json_integer_copy(json);
|
||||
|
||||
if(json_is_real(json))
|
||||
return json_real_copy(json);
|
||||
|
||||
if(json_is_true(json) || json_is_false(json) || json_is_null(json))
|
||||
return json;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
18
test/.gitignore
vendored
18
test/.gitignore
vendored
@@ -1,9 +1,9 @@
|
||||
loadf_dumpf
|
||||
loads_dumps
|
||||
load_file_dump_file
|
||||
testlogs
|
||||
testprogs/test_array
|
||||
testprogs/test_load
|
||||
testprogs/test_number
|
||||
testprogs/test_object
|
||||
testprogs/test_simple
|
||||
logs
|
||||
bin/json_process
|
||||
suites/api/test_array
|
||||
suites/api/test_equal
|
||||
suites/api/test_copy
|
||||
suites/api/test_load
|
||||
suites/api/test_number
|
||||
suites/api/test_object
|
||||
suites/api/test_simple
|
||||
|
||||
@@ -1,22 +1,10 @@
|
||||
DIST_SUBDIRS = testprogs testdata
|
||||
SUBDIRS = testprogs
|
||||
SUBDIRS = bin suites
|
||||
EXTRA_DIST = scripts run-suites
|
||||
|
||||
check_PROGRAMS = loadf_dumpf loads_dumps load_file_dump_file
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src
|
||||
AM_CFLAGS = -Wall -Werror
|
||||
LDFLAGS = -static # for speed and Valgrind
|
||||
LDADD = ../src/libjansson.la
|
||||
|
||||
TESTS = test-api test-invalid test-valid
|
||||
|
||||
EXTRA_DIST = \
|
||||
test-api \
|
||||
test-invalid \
|
||||
test-valid \
|
||||
run-test \
|
||||
json-compare.py \
|
||||
split-testfile.py
|
||||
TESTS = run-suites
|
||||
TESTS_ENVIRONMENT = \
|
||||
top_srcdir=$(top_srcdir) \
|
||||
top_builddir=$(top_builddir)
|
||||
|
||||
clean-local:
|
||||
rm -rf testlogs
|
||||
rm -rf logs
|
||||
|
||||
6
test/bin/Makefile.am
Normal file
6
test/bin/Makefile.am
Normal file
@@ -0,0 +1,6 @@
|
||||
check_PROGRAMS = json_process
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src
|
||||
AM_CFLAGS = -Wall -Werror
|
||||
LDFLAGS = -static # for speed and Valgrind
|
||||
LDADD = $(top_builddir)/src/libjansson.la
|
||||
69
test/bin/json_process.c
Normal file
69
test/bin/json_process.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <jansson.h>
|
||||
|
||||
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 main(int argc, char *argv[])
|
||||
{
|
||||
int indent = 0;
|
||||
unsigned int flags = 0;
|
||||
|
||||
json_t *json;
|
||||
json_error_t error;
|
||||
|
||||
if(argc != 1) {
|
||||
fprintf(stderr, "usage: %s\n", argv[0]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
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_SORT_KEYS"))
|
||||
flags |= JSON_SORT_KEYS;
|
||||
|
||||
json = json_loadf(stdin, &error);
|
||||
if(!json) {
|
||||
fprintf(stderr, "%d\n%s\n", error.line, error.text);
|
||||
return 1;
|
||||
}
|
||||
|
||||
json_dumpf(json, stdout, flags);
|
||||
json_decref(json);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (c) 2009 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.
|
||||
|
||||
import sys
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
import simplejson as json
|
||||
|
||||
def load(filename):
|
||||
try:
|
||||
jsonfile = open(filename)
|
||||
except IOError, err:
|
||||
print >>sys.stderr, "unable to load %s: %s" % \
|
||||
(filename, err.strerror)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
jsondata = json.load(jsonfile)
|
||||
except ValueError, err:
|
||||
print "%s is malformed: %s" % (filename, err)
|
||||
sys.exit(1)
|
||||
finally:
|
||||
jsonfile.close()
|
||||
|
||||
return jsondata
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 3:
|
||||
print >>sys.stderr, "usage: %s json1 json2" % sys.argv[0]
|
||||
return 2
|
||||
|
||||
json1 = load(sys.argv[1])
|
||||
json2 = load(sys.argv[2])
|
||||
if json1 == json2:
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main() or 0)
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 <stdio.h>
|
||||
#include <jansson.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
json_t *json;
|
||||
json_error_t error;
|
||||
|
||||
if(argc != 3) {
|
||||
fprintf(stderr, "usage: %s infile outfile\n", argv[0]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
json = json_load_file(argv[1], &error);
|
||||
if(!json) {
|
||||
fprintf(stderr, "%d\n%s\n", error.line, error.text);
|
||||
return 1;
|
||||
}
|
||||
|
||||
json_dump_file(json, argv[2], 0);
|
||||
json_decref(json);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 <stdio.h>
|
||||
#include <jansson.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
json_t *json;
|
||||
json_error_t error;
|
||||
|
||||
if(argc != 1) {
|
||||
fprintf(stderr, "usage: %s\n", argv[0]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
json = json_loadf(stdin, &error);
|
||||
if(!json) {
|
||||
fprintf(stderr, "%d\n%s\n", error.line, error.text);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* loadf_dumpf indents, others don't, so dumping with and without
|
||||
indenting is tested */
|
||||
json_dumpf(json, stdout, JSON_INDENT(4));
|
||||
json_decref(json);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <jansson.h>
|
||||
|
||||
#define BUFFER_SIZE (256 * 1024)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
json_t *json;
|
||||
json_error_t error;
|
||||
int count;
|
||||
char buffer[BUFFER_SIZE];
|
||||
char *result;
|
||||
|
||||
if(argc != 1) {
|
||||
fprintf(stderr, "usage: %s\n", argv[0]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
count = fread(buffer, 1, BUFFER_SIZE, stdin);
|
||||
if(count < 0 || count >= BUFFER_SIZE) {
|
||||
fprintf(stderr, "unable to read input\n");
|
||||
return 1;
|
||||
}
|
||||
buffer[count] = '\0';
|
||||
|
||||
json = json_loads(buffer, &error);
|
||||
if(!json) {
|
||||
fprintf(stderr, "%d\n%s\n", error.line, error.text);
|
||||
return 1;
|
||||
}
|
||||
|
||||
result = json_dumps(json, 0);
|
||||
json_decref(json);
|
||||
|
||||
puts(result);
|
||||
free(result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
46
test/run-suites
Executable file
46
test/run-suites
Executable file
@@ -0,0 +1,46 @@
|
||||
#!/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
|
||||
|
||||
export suites_srcdir=$top_srcdir/test/suites
|
||||
export suites_builddir=suites
|
||||
export scriptdir=$top_srcdir/test/scripts
|
||||
export logdir=logs
|
||||
export bindir=bin
|
||||
|
||||
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))
|
||||
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
|
||||
@@ -1,57 +0,0 @@
|
||||
# Copyright (c) 2009 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.
|
||||
|
||||
VALGRIND_CMDLINE="valgrind --leak-check=full --show-reachable=yes --track-origins=yes -q"
|
||||
|
||||
run_testprog() {
|
||||
local prog=$1
|
||||
local prefix=$2
|
||||
if [ -n "$VALGRIND" ]; then
|
||||
local runner="$VALGRIND_CMDLINE "
|
||||
fi
|
||||
|
||||
case "$prog" in
|
||||
load_file_dump_file)
|
||||
$runner./$prog \
|
||||
$prefix.in \
|
||||
$prefix.$prog.stdout \
|
||||
2>$prefix.$prog.stderr
|
||||
;;
|
||||
*)
|
||||
$runner./$prog \
|
||||
<$prefix.in \
|
||||
>$prefix.$prog.stdout \
|
||||
2>$prefix.$prog.stderr
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -n "$VALGRIND" ]; 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]+== ' $prefix.$prog.stderr; then
|
||||
echo "### $prefix ($prog) failed:" >&2
|
||||
echo "valgrind detected an error" >&2
|
||||
echo "for details, see test/$prefix.$prog.stderr" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
for testfile in $TESTFILES; do
|
||||
tmpdir="testlogs/`basename $testfile`"
|
||||
rm -rf $tmpdir
|
||||
mkdir -p $tmpdir
|
||||
if echo "$testfile" | grep -q -E -e '-strip$'; then
|
||||
opts="--strip"
|
||||
fi
|
||||
${srcdir}/split-testfile.py $opts $testfile $tmpdir | while read name; do
|
||||
run_test loadf_dumpf $tmpdir/$name
|
||||
run_test loads_dumps $tmpdir/$name
|
||||
run_test load_file_dump_file $tmpdir/$name
|
||||
echo -n '.'
|
||||
done || exit 1
|
||||
echo
|
||||
done
|
||||
71
test/scripts/run-tests.sh
Normal file
71
test/scripts/run-tests.sh
Normal file
@@ -0,0 +1,71 @@
|
||||
# Copyright (c) 2009 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.
|
||||
|
||||
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
|
||||
|
||||
. $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
|
||||
echo -n "$name... "
|
||||
fi
|
||||
|
||||
if run_test; then
|
||||
# Success
|
||||
if [ $VERBOSE -eq 1 ]; then
|
||||
echo "ok"
|
||||
else
|
||||
echo -n "."
|
||||
fi
|
||||
rm -rf $test_log
|
||||
else
|
||||
# Failure
|
||||
if [ $VERBOSE -eq 1 ]; then
|
||||
echo "FAILED"
|
||||
else
|
||||
echo -n "F"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $VERBOSE -eq 0 ]; then
|
||||
echo
|
||||
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
|
||||
35
test/scripts/valgrind.sh
Normal file
35
test/scripts/valgrind.sh
Normal file
@@ -0,0 +1,35 @@
|
||||
# Copyright (c) 2009 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
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (c) 2009 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.
|
||||
|
||||
import os
|
||||
import sys
|
||||
from optparse import OptionParser
|
||||
|
||||
def strip_file(filename):
|
||||
with open(filename) as fobj:
|
||||
data = fobj.read()
|
||||
with open(filename, 'w') as fobj:
|
||||
fobj.write(data.strip())
|
||||
|
||||
def open_files(outdir, i, name):
|
||||
basename = '%02d_%s' % (i, name)
|
||||
print basename
|
||||
input_path = os.path.join(outdir, basename + '.in')
|
||||
output_path = os.path.join(outdir, basename + '.out')
|
||||
return open(input_path, 'w'), open(output_path, 'w')
|
||||
|
||||
def main():
|
||||
parser = OptionParser('usage: %prog [options] inputfile outputdir')
|
||||
parser.add_option('--strip', help='strip whitespace from input',
|
||||
action='store_true', default=False)
|
||||
options, args = parser.parse_args()
|
||||
|
||||
if len(args) != 2:
|
||||
parser.print_help()
|
||||
return 2
|
||||
|
||||
infile = os.path.normpath(args[0])
|
||||
outdir = os.path.normpath(args[1])
|
||||
|
||||
if not os.path.exists(outdir):
|
||||
print >>sys.stderr, 'output directory %r does not exist!' % outdir
|
||||
return 1
|
||||
|
||||
n = 0
|
||||
current = None
|
||||
input, output = None, None
|
||||
|
||||
for line in open(infile):
|
||||
if line.startswith('==== '):
|
||||
n += 1
|
||||
if input is not None and output is not None:
|
||||
input.close()
|
||||
output.close()
|
||||
if options.strip:
|
||||
strip_file(input.name)
|
||||
input, output = open_files(outdir, n, line[5:line.find(' ====\n')])
|
||||
current = input
|
||||
elif line == '====\n':
|
||||
current = output
|
||||
else:
|
||||
current.write(line)
|
||||
|
||||
if input is not None and output is not None:
|
||||
input.close()
|
||||
output.close()
|
||||
|
||||
print >>sys.stderr, "%s: %d test cases" % (infile, n)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main() or 0)
|
||||
@@ -1 +1,2 @@
|
||||
SUBDIRS = api
|
||||
EXTRA_DIST = invalid invalid-strip invalid-unicode valid valid-strip
|
||||
@@ -1,6 +1,16 @@
|
||||
check_PROGRAMS = test_array test_load test_simple test_number test_object
|
||||
EXTRA_DIST = run
|
||||
|
||||
check_PROGRAMS = \
|
||||
test_array \
|
||||
test_equal \
|
||||
test_copy \
|
||||
test_load \
|
||||
test_simple \
|
||||
test_number \
|
||||
test_object
|
||||
|
||||
test_array_SOURCES = test_array.c util.h
|
||||
test_copy_SOURCES = test_copy.c util.h
|
||||
test_load_SOURCES = test_load.c util.h
|
||||
test_simple_SOURCES = test_simple.c util.h
|
||||
test_number_SOURCES = test_number.c util.h
|
||||
@@ -9,4 +19,4 @@ test_object_SOURCES = test_object.c util.h
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src
|
||||
AM_CFLAGS = -Wall -Werror
|
||||
LDFLAGS = -static # for speed and Valgrind
|
||||
LDADD = ../../src/libjansson.la
|
||||
LDADD = $(top_builddir)/src/libjansson.la
|
||||
88
test/suites/api/check-exports
Executable file
88
test/suites/api/check-exports
Executable file
@@ -0,0 +1,88 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This tests checks that the libjansson.so exports the correct
|
||||
# symbols.
|
||||
|
||||
# The list of symbols that the shared object should export
|
||||
sort >$test_log/exports <<EOF
|
||||
json_delete
|
||||
json_true
|
||||
json_false
|
||||
json_null
|
||||
json_string
|
||||
json_string_nocheck
|
||||
json_string_value
|
||||
json_string_set
|
||||
json_string_set_nocheck
|
||||
json_integer
|
||||
json_integer_value
|
||||
json_integer_set
|
||||
json_real
|
||||
json_real_value
|
||||
json_real_set
|
||||
json_number_value
|
||||
json_array
|
||||
json_array_size
|
||||
json_array_get
|
||||
json_array_set_new
|
||||
json_array_append_new
|
||||
json_array_insert_new
|
||||
json_array_remove
|
||||
json_array_clear
|
||||
json_array_extend
|
||||
json_object
|
||||
json_object_size
|
||||
json_object_get
|
||||
json_object_set_new
|
||||
json_object_set_new_nocheck
|
||||
json_object_del
|
||||
json_object_clear
|
||||
json_object_update
|
||||
json_object_iter
|
||||
json_object_iter_next
|
||||
json_object_iter_key
|
||||
json_object_iter_value
|
||||
json_dumps
|
||||
json_dumpf
|
||||
json_dump_file
|
||||
json_loads
|
||||
json_loadf
|
||||
json_load_file
|
||||
json_equal
|
||||
json_copy
|
||||
json_deep_copy
|
||||
EOF
|
||||
|
||||
# The list of functions are not exported in the library because they
|
||||
# are macros or static inline functions. This is only the make the
|
||||
# list complete, there are not used by the test.
|
||||
sort >$test_log/macros_or_inline <<EOF
|
||||
json_typeof
|
||||
json_incref
|
||||
json_decref
|
||||
json_is_object
|
||||
json_is_object
|
||||
json_is_array
|
||||
json_is_string
|
||||
json_is_integer
|
||||
json_is_real
|
||||
json_is_true
|
||||
json_is_false
|
||||
json_is_null
|
||||
json_is_number
|
||||
json_is_boolean
|
||||
json_array_set
|
||||
json_array_append
|
||||
json_array_insert
|
||||
json_object_set
|
||||
json_object_set_nocheck
|
||||
EOF
|
||||
|
||||
SOFILE="../src/.libs/libjansson.so"
|
||||
|
||||
nm -D $SOFILE | grep ' T ' | cut -d' ' -f3 | 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
|
||||
30
test/suites/api/run
Executable file
30
test/suites/api/run
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2009 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() {
|
||||
[ "${test_name%.c}" != "$test_name" ] && return 0
|
||||
[ -x $test_path -a ! -f $test_path.c ] && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
run_test() {
|
||||
if [ -x $test_path ]; 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
|
||||
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
|
||||
319
test/suites/api/test_copy.c
Normal file
319
test/suites/api/test_copy.c
Normal file
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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;
|
||||
unsigned int i;
|
||||
|
||||
array = json_loads(json_array_text, 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;
|
||||
unsigned int i;
|
||||
|
||||
array = json_loads(json_array_text, 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, 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, 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);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_copy_simple();
|
||||
test_deep_copy_simple();
|
||||
test_copy_array();
|
||||
test_deep_copy_array();
|
||||
test_copy_object();
|
||||
test_deep_copy_object();
|
||||
return 0;
|
||||
}
|
||||
190
test/suites/api/test_equal.c
Normal file
190
test/suites/api/test_equal.c
Normal file
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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, NULL);
|
||||
value2 = json_loads(complex_json, 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 */
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_equal_simple();
|
||||
test_equal_array();
|
||||
test_equal_object();
|
||||
test_equal_complex();
|
||||
return 0;
|
||||
}
|
||||
@@ -167,6 +167,44 @@ static void test_circular()
|
||||
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_misc()
|
||||
{
|
||||
json_t *object, *string, *other_string, *value;
|
||||
@@ -293,6 +331,7 @@ int main()
|
||||
test_clear();
|
||||
test_update();
|
||||
test_circular();
|
||||
test_set_nocheck();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -73,6 +73,33 @@ int main()
|
||||
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)
|
||||
1
test/suites/encoding-flags/array/input
Normal file
1
test/suites/encoding-flags/array/input
Normal file
@@ -0,0 +1 @@
|
||||
[1, 2]
|
||||
1
test/suites/encoding-flags/array/output
Normal file
1
test/suites/encoding-flags/array/output
Normal file
@@ -0,0 +1 @@
|
||||
[1, 2]
|
||||
1
test/suites/encoding-flags/compact-array/env
Normal file
1
test/suites/encoding-flags/compact-array/env
Normal file
@@ -0,0 +1 @@
|
||||
export JSON_COMPACT=1
|
||||
1
test/suites/encoding-flags/compact-array/input
Normal file
1
test/suites/encoding-flags/compact-array/input
Normal file
@@ -0,0 +1 @@
|
||||
[1, 2]
|
||||
1
test/suites/encoding-flags/compact-array/output
Normal file
1
test/suites/encoding-flags/compact-array/output
Normal file
@@ -0,0 +1 @@
|
||||
[1,2]
|
||||
1
test/suites/encoding-flags/compact-object/env
Normal file
1
test/suites/encoding-flags/compact-object/env
Normal file
@@ -0,0 +1 @@
|
||||
export JSON_COMPACT=1
|
||||
1
test/suites/encoding-flags/compact-object/input
Normal file
1
test/suites/encoding-flags/compact-object/input
Normal file
@@ -0,0 +1 @@
|
||||
{"a": 1, "b": 2}
|
||||
1
test/suites/encoding-flags/compact-object/output
Normal file
1
test/suites/encoding-flags/compact-object/output
Normal file
@@ -0,0 +1 @@
|
||||
{"a":1,"b":2}
|
||||
1
test/suites/encoding-flags/ensure-ascii/env
Normal file
1
test/suites/encoding-flags/ensure-ascii/env
Normal file
@@ -0,0 +1 @@
|
||||
export JSON_ENSURE_ASCII=1
|
||||
8
test/suites/encoding-flags/ensure-ascii/input
Normal file
8
test/suites/encoding-flags/ensure-ascii/input
Normal file
@@ -0,0 +1,8 @@
|
||||
[
|
||||
"foo",
|
||||
"å ä ö",
|
||||
"foo åä",
|
||||
"åä foo",
|
||||
"å foo ä",
|
||||
"clef g: 𝄞"
|
||||
]
|
||||
1
test/suites/encoding-flags/ensure-ascii/output
Normal file
1
test/suites/encoding-flags/ensure-ascii/output
Normal file
@@ -0,0 +1 @@
|
||||
["foo", "\u00e5 \u00e4 \u00f6", "foo \u00e5\u00e4", "\u00e5\u00e4 foo", "\u00e5 foo \u00e4", "clef g: \ud834\udd1e"]
|
||||
1
test/suites/encoding-flags/indent-array/env
Normal file
1
test/suites/encoding-flags/indent-array/env
Normal file
@@ -0,0 +1 @@
|
||||
export JSON_INDENT=4
|
||||
1
test/suites/encoding-flags/indent-array/input
Normal file
1
test/suites/encoding-flags/indent-array/input
Normal file
@@ -0,0 +1 @@
|
||||
[1, 2]
|
||||
4
test/suites/encoding-flags/indent-array/output
Normal file
4
test/suites/encoding-flags/indent-array/output
Normal file
@@ -0,0 +1,4 @@
|
||||
[
|
||||
1,
|
||||
2
|
||||
]
|
||||
2
test/suites/encoding-flags/indent-compact-array/env
Normal file
2
test/suites/encoding-flags/indent-compact-array/env
Normal file
@@ -0,0 +1,2 @@
|
||||
export JSON_INDENT=4
|
||||
export JSON_COMPACT=1
|
||||
1
test/suites/encoding-flags/indent-compact-array/input
Normal file
1
test/suites/encoding-flags/indent-compact-array/input
Normal file
@@ -0,0 +1 @@
|
||||
[1, 2]
|
||||
4
test/suites/encoding-flags/indent-compact-array/output
Normal file
4
test/suites/encoding-flags/indent-compact-array/output
Normal file
@@ -0,0 +1,4 @@
|
||||
[
|
||||
1,
|
||||
2
|
||||
]
|
||||
2
test/suites/encoding-flags/indent-compact-object/env
Normal file
2
test/suites/encoding-flags/indent-compact-object/env
Normal file
@@ -0,0 +1,2 @@
|
||||
export JSON_INDENT=4
|
||||
export JSON_COMPACT=1
|
||||
1
test/suites/encoding-flags/indent-compact-object/input
Normal file
1
test/suites/encoding-flags/indent-compact-object/input
Normal file
@@ -0,0 +1 @@
|
||||
{"a": 1, "b": 2}
|
||||
4
test/suites/encoding-flags/indent-compact-object/output
Normal file
4
test/suites/encoding-flags/indent-compact-object/output
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"a":1,
|
||||
"b":2
|
||||
}
|
||||
1
test/suites/encoding-flags/indent-object/env
Normal file
1
test/suites/encoding-flags/indent-object/env
Normal file
@@ -0,0 +1 @@
|
||||
export JSON_INDENT=4
|
||||
1
test/suites/encoding-flags/indent-object/input
Normal file
1
test/suites/encoding-flags/indent-object/input
Normal file
@@ -0,0 +1 @@
|
||||
{"a": 1, "b": 2}
|
||||
4
test/suites/encoding-flags/indent-object/output
Normal file
4
test/suites/encoding-flags/indent-object/output
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"a": 1,
|
||||
"b": 2
|
||||
}
|
||||
1
test/suites/encoding-flags/object/input
Normal file
1
test/suites/encoding-flags/object/input
Normal file
@@ -0,0 +1 @@
|
||||
{"a": 1, "b": 2}
|
||||
1
test/suites/encoding-flags/object/output
Normal file
1
test/suites/encoding-flags/object/output
Normal file
@@ -0,0 +1 @@
|
||||
{"a": 1, "b": 2}
|
||||
32
test/suites/encoding-flags/run
Executable file
32
test/suites/encoding-flags/run
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2009 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() {
|
||||
test -d $test_path
|
||||
}
|
||||
|
||||
run_test() {
|
||||
(
|
||||
if [ -f $test_path/env ]; then
|
||||
. $test_path/env
|
||||
fi
|
||||
$json_process <$test_path/input >$test_log/stdout 2>$test_log/stderr
|
||||
)
|
||||
valgrind_check $test_log/stderr || return 1
|
||||
cmp -s $test_path/output $test_log/stdout
|
||||
}
|
||||
|
||||
show_error() {
|
||||
valgrind_show_error && return
|
||||
|
||||
echo "EXPECTED OUTPUT:"
|
||||
nl -bn $test_path/output
|
||||
echo "ACTUAL OUTPUT:"
|
||||
nl -bn $test_log/stdout
|
||||
}
|
||||
|
||||
. $top_srcdir/test/scripts/run-tests.sh
|
||||
1
test/suites/encoding-flags/sort-keys/env
Normal file
1
test/suites/encoding-flags/sort-keys/env
Normal file
@@ -0,0 +1 @@
|
||||
export JSON_SORT_KEYS=1
|
||||
1
test/suites/encoding-flags/sort-keys/input
Normal file
1
test/suites/encoding-flags/sort-keys/input
Normal file
@@ -0,0 +1 @@
|
||||
{"foo": 1, "bar": 2, "baz": 3, "quux": 4}
|
||||
1
test/suites/encoding-flags/sort-keys/output
Normal file
1
test/suites/encoding-flags/sort-keys/output
Normal file
@@ -0,0 +1 @@
|
||||
{"bar": 2, "baz": 3, "foo": 1, "quux": 4}
|
||||
2
test/suites/invalid-strip/apostrophe/error
Normal file
2
test/suites/invalid-strip/apostrophe/error
Normal file
@@ -0,0 +1,2 @@
|
||||
1
|
||||
invalid token near '''
|
||||
1
test/suites/invalid-strip/apostrophe/input
Normal file
1
test/suites/invalid-strip/apostrophe/input
Normal file
@@ -0,0 +1 @@
|
||||
['
|
||||
2
test/suites/invalid-strip/ascii-unicode-identifier/error
Normal file
2
test/suites/invalid-strip/ascii-unicode-identifier/error
Normal file
@@ -0,0 +1,2 @@
|
||||
1
|
||||
'[' or '{' expected near 'a'
|
||||
1
test/suites/invalid-strip/ascii-unicode-identifier/input
Normal file
1
test/suites/invalid-strip/ascii-unicode-identifier/input
Normal file
@@ -0,0 +1 @@
|
||||
aå
|
||||
2
test/suites/invalid-strip/brace-comma/error
Normal file
2
test/suites/invalid-strip/brace-comma/error
Normal file
@@ -0,0 +1,2 @@
|
||||
1
|
||||
string or '}' expected near ','
|
||||
1
test/suites/invalid-strip/brace-comma/input
Normal file
1
test/suites/invalid-strip/brace-comma/input
Normal file
@@ -0,0 +1 @@
|
||||
{,
|
||||
2
test/suites/invalid-strip/bracket-comma/error
Normal file
2
test/suites/invalid-strip/bracket-comma/error
Normal file
@@ -0,0 +1,2 @@
|
||||
1
|
||||
unexpected token near ','
|
||||
1
test/suites/invalid-strip/bracket-comma/input
Normal file
1
test/suites/invalid-strip/bracket-comma/input
Normal file
@@ -0,0 +1 @@
|
||||
[,
|
||||
2
test/suites/invalid-strip/bracket-one-comma/error
Normal file
2
test/suites/invalid-strip/bracket-one-comma/error
Normal file
@@ -0,0 +1,2 @@
|
||||
1
|
||||
']' expected near end of file
|
||||
1
test/suites/invalid-strip/bracket-one-comma/input
Normal file
1
test/suites/invalid-strip/bracket-one-comma/input
Normal file
@@ -0,0 +1 @@
|
||||
[1,
|
||||
2
test/suites/invalid-strip/empty/error
Normal file
2
test/suites/invalid-strip/empty/error
Normal file
@@ -0,0 +1,2 @@
|
||||
1
|
||||
'[' or '{' expected near end of file
|
||||
0
test/suites/invalid-strip/empty/input
Normal file
0
test/suites/invalid-strip/empty/input
Normal file
2
test/suites/invalid-strip/extra-comma-in-array/error
Normal file
2
test/suites/invalid-strip/extra-comma-in-array/error
Normal file
@@ -0,0 +1,2 @@
|
||||
1
|
||||
unexpected token near ']'
|
||||
1
test/suites/invalid-strip/extra-comma-in-array/input
Normal file
1
test/suites/invalid-strip/extra-comma-in-array/input
Normal file
@@ -0,0 +1 @@
|
||||
[1,]
|
||||
@@ -0,0 +1,2 @@
|
||||
6
|
||||
unexpected token near ']'
|
||||
@@ -0,0 +1,6 @@
|
||||
[1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
]
|
||||
2
test/suites/invalid-strip/garbage-after-newline/error
Normal file
2
test/suites/invalid-strip/garbage-after-newline/error
Normal file
@@ -0,0 +1,2 @@
|
||||
2
|
||||
end of file expected near 'foo'
|
||||
2
test/suites/invalid-strip/garbage-after-newline/input
Normal file
2
test/suites/invalid-strip/garbage-after-newline/input
Normal file
@@ -0,0 +1,2 @@
|
||||
[1,2,3]
|
||||
foo
|
||||
2
test/suites/invalid-strip/garbage-at-the-end/error
Normal file
2
test/suites/invalid-strip/garbage-at-the-end/error
Normal file
@@ -0,0 +1,2 @@
|
||||
1
|
||||
end of file expected near 'foo'
|
||||
1
test/suites/invalid-strip/garbage-at-the-end/input
Normal file
1
test/suites/invalid-strip/garbage-at-the-end/input
Normal file
@@ -0,0 +1 @@
|
||||
[1,2,3]foo
|
||||
@@ -0,0 +1,2 @@
|
||||
1
|
||||
invalid token near '0'
|
||||
@@ -0,0 +1 @@
|
||||
[012]
|
||||
2
test/suites/invalid-strip/invalid-escape/error
Normal file
2
test/suites/invalid-strip/invalid-escape/error
Normal file
@@ -0,0 +1,2 @@
|
||||
1
|
||||
invalid escape near '"\'
|
||||
1
test/suites/invalid-strip/invalid-escape/input
Normal file
1
test/suites/invalid-strip/invalid-escape/input
Normal file
@@ -0,0 +1 @@
|
||||
["\a <-- invalid escape"]
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user