AC_PREREQ([2.63])
-AC_INIT([jansson], [1.0.3], [petri@digip.org])
+AC_INIT([jansson], [1.0.3+], [petri@digip.org])
AM_INIT_AUTOMAKE([1.10 foreign])
are APIs for querying the type, manipulating the reference count, and
for constructing and manipulating values of different types.
+Unless noted otherwise, all API functions return an error value if an
+error occurs. Depending on the function's signature, the error value
+is either *NULL* or -1. Invalid arguments or invalid input are
+apparent sources for errors. Memory allocation and I/O operations may
+also cause errors.
+
Type
----
.. cfunction:: int json_typeof(const json_t *json)
Return the type of the JSON value (a :ctype:`json_type` cast to
- :ctype:`int`). This function is actually implemented as a macro for
- speed.
+ :ctype:`int`). *json* MUST NOT be *NULL*. This function is actually
+ implemented as a macro for speed.
.. cfunction:: json_is_object(const json_t *json)
json_is_array(const json_t *json)
json_is_null(const json_t *json)
These functions (actually macros) return true (non-zero) for values
- of the given type, and false (zero) for values of other types.
+ of the given type, and false (zero) for values of other types and
+ for *NULL*.
.. cfunction:: json_is_number(const json_t *json)
Returns true for values of types :const:`JSON_INTEGER` and
- :const:`JSON_REAL`, and false for other types.
+ :const:`JSON_REAL`, and false for other types and for *NULL*.
.. cfunction:: json_is_boolean(const json_t *json)
Returns true for types :const:`JSON_TRUE` and :const:`JSON_FALSE`,
- and false for values of other types.
+ and false for values of other types and for *NULL*.
Reference Count
.. cfunction:: json_t *json_incref(json_t *json)
- Increment the reference count of *json*.
+ Increment the reference count of *json* if it's not non-*NULL*.
+ Returns *json*.
.. cfunction:: void json_decref(json_t *json)
to release the reference.
Normally, all functions accepting a JSON value as an argument will
-manage the reference, i.e. increase and decrease the reference count
+nmanage the reference, i.e. increase and decrease the reference count
as needed. However, some functions **steal** the reference, i.e. they
have the same result as if the user called :cfunc:`json_decref()` on
the argument right after calling the function. These are usually
True, False and Null
====================
+These values are implemented as singletons, so each of these functions
+returns the same value each time.
+
.. cfunction:: json_t *json_true(void)
.. refcounting:: new
- Returns a value of the type :const:`JSON_TRUE`, or *NULL* on
- error.
+ Returns the JSON true value.
.. cfunction:: json_t *json_false(void)
.. refcounting:: new
- Returns a value of the type :const:`JSON_FALSE`, or *NULL* on
- error.
+ Returns the JSON false value.
.. cfunction:: json_t *json_null(void)
.. refcounting:: new
- Returns a value of the type :const:`JSON_NULL`, or *NULL* on
- error.
+ Returns the JSON null value.
String
.. refcounting:: new
- Returns a new value of the type :const:`JSON_STRING`, or *NULL* on
- error. *value* must be a valid UTF-8 encoded Unicode string.
+ Returns a new JSON string, or *NULL* on error. *value* must be a
+ valid UTF-8 encoded Unicode string.
.. cfunction:: const char *json_string_value(const json_t *json)
- Returns the associated value of a :const:`JSON_STRING` value as a
- null terminated UTF-8 encoded string.
+ Returns the associated value of the JSON string *json* as a null
+ terminated UTF-8 encoded string, or *NULL* if *json* is not a JSON
+ string.
Number
.. refcounting:: new
- Returns a new value of the type :const:`JSON_INTEGER`, or *NULL* on
- error.
+ Returns a new JSON integer, or *NULL* on error.
.. cfunction:: int json_integer_value(const json_t *json)
- Returns the associated integer value of values of the type
- :const:`JSON_INTEGER`, or 0 for values of other types.
+ Returns the associated value the JSON integer *json*. If *json* is
+ *NULL* or not a JSON integer, 0 is returned.
.. cfunction:: json_t *json_real(double value)
.. refcounting:: new
- Returns a new value of the type :const:`JSON_REAL`, or *NULL* on
- error.
+ Returns a new JSON real, or *NULL* on error.
.. cfunction:: double json_real_value(const json_t *json)
- Returns the associated real value of values of the type
- :const:`JSON_INTEGER`, or 0 for values of other types.
+ Returns the associated value of the JSON real *json*. If *json* is
+ *NULL* or not a JSON real, 0.0 is returned.
In addition to the functions above, there's a common query function
for integers and reals:
.. cfunction:: double json_number_value(const json_t *json)
- Returns the value of either ``JSON_INTEGER`` or ``JSON_REAL``, cast
- to double regardless of the actual type.
+ Returns the associated value of the JSON integer or JSON real
+ *json*, cast to double regardless of the actual type. If *json* is
+ neither JSON real nor JSON integer, 0.0 is returned.
Array
.. refcounting:: new
- Returns a new value of the type :const:`JSON_ARRAY`, or *NULL* on
- error. Initially, the array is empty.
+ Returns a new JSON array, or *NULL* on error. Initially, the array
+ is empty.
.. cfunction:: unsigned int json_array_size(const json_t *array)
- Returns the number of elements in *array*.
+ Returns the number of elements in *array*, or 0 if *array* is NULL
+ or not a JSON array.
.. cfunction:: json_t *json_array_get(const json_t *array, unsigned int index)
.. refcounting:: borrow
- Returns the element in *array* at position *index*, or *NULL* if
- *index* is out of range. The valid range for *index* is from 0 to
- the return value of :cfunc:`json_array_size()` minus 1.
+ Returns the element in *array* at position *index*. The valid range
+ for *index* is from 0 to the return value of
+ :cfunc:`json_array_size()` minus 1. If *array* is not a JSON array,
+ if *array* is *NULL*, or if *index* is out of range, *NULL* is
+ returned.
.. cfunction:: int json_array_set(json_t *array, unsigned int index, json_t *value)
Replaces the element in *array* at position *index* with *value*.
- Returns 0 on success, or -1 if *index* is out of range. The valid
- range for *index* is from 0 to the return value of
- :cfunc:`json_array_size()` minus 1.
+ The valid range for *index* is from 0 to the return value of
+ :cfunc:`json_array_size()` minus 1. Returns 0 on success and -1 on
+ error.
+
+.. cfunction:: int json_array_set_new(json_t *array, unsigned int index, json_t *value)
+
+ Like :cfunc:`json_array_set()` but steals the reference to *value*.
+ This is useful when *value* is newly created and not used after
+ the call.
+
+ .. versionadded:: 1.1
.. cfunction:: int json_array_append(json_t *array, json_t *value)
Appends *value* to the end of *array*, growing the size of *array*
by 1. Returns 0 on success and -1 on error.
+.. cfunction:: int json_array_append_new(json_t *array, json_t *value)
+
+ Like :cfunc:`json_array_append()` but steals the reference to
+ *value*. This is useful when *value* is newly created and not used
+ after the call.
+
+ .. versionadded:: 1.1
+
Object
======
.. refcounting:: new
- Returns a new value of the type :const:`JSON_OBJECT`, or *NULL* on
- error. Initially, the object is empty.
+ Returns a new JSON object, or *NULL* on error. Initially, the
+ object is empty.
.. cfunction:: json_t *json_object_get(const json_t *object, const char *key)
.. cfunction:: int json_object_set(json_t *object, const char *key, json_t *value)
Set the value of *key* to *value* in *object*. *key* must be a
- valid terminated UTF-8 encoded Unicode string. If there already is
- a value for *key*, it is replaced by the new value. Returns 0 on
- success and -1 on error.
+ valid null terminated UTF-8 encoded Unicode string. If there
+ 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_new(json_t *object, const char *key, json_t *value)
+
+ Like :cfunc:`json_object_set()` but steals the reference to
+ *value*. This is useful when *value* is newly created and not used
+ after the call.
+
+ .. versionadded:: 1.1
.. cfunction:: int json_object_del(json_t *object, const char *key)
Extract the associated value from *iter*.
+The iteration protocol can be used for example as follows::
+
+ /* obj is a JSON object */
+ const char *key;
+ json_t *value;
+ void *iter = json_object_iter(obj);
+ while(iter)
+ {
+ key = json_object_iter_key(iter);
+ value = json_object_iter_value(iter);
+ /* use key and value ... */
+ iter = json_object_iter_next(obj, iter);
+ }
+
Encoding
========
The following functions perform the actual JSON encoding. The result
is in UTF-8.
-.. cfunction:: char *json_dumps(const json_t *root, uint32_t flags)
+.. cfunction:: char *json_dumps(const json_t *root, unsigned long flags)
Returns the JSON representation of *root* as a string, or *NULL* on
error. *flags* is described above. The return value must be freed
by the caller using :cfunc:`free()`.
-.. cfunction:: int json_dumpf(const json_t *root, FILE *output, uint32_t flags)
+.. cfunction:: int json_dumpf(const json_t *root, FILE *output, unsigned long flags)
Write the JSON representation of *root* to the stream *output*.
*flags* is described above. Returns 0 on success and -1 on error.
-.. cfunction:: int json_dump_file(const json_t *json, const char *path, uint32_t flags)
+.. cfunction:: int json_dump_file(const json_t *json, const char *path, unsigned long flags)
Write the JSON representation of *root* to the file *path*. If
*path* already exists, it is overwritten. *flags* is described
# The short X.Y version.
version = '1.0'
# The full version, including alpha/beta/rc tags.
-release = '1.0.3'
+release = '1.0.3+'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
value.c
libjansson_la_LDFLAGS = -version-info 0:3:0
-AM_CFLAGS = -Wall -Wextra -Werror -std=c99
+AM_CFLAGS = -Wall -Wextra -Werror
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
#include <jansson.h>
#include "strbuffer.h"
return 0;
}
-static int dump_indent(uint32_t flags, int depth, dump_func dump, 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)
{
if(JSON_INDENT(flags) > 0)
{
- char *ws_buffer;
- int ws_count = JSON_INDENT(flags) * depth;
+ int i, ws_count = JSON_INDENT(flags);
if(dump("\n", 1, data))
return -1;
- if(ws_count == 0)
- return 0;
-
- ws_buffer = alloca(ws_count);
- memset(ws_buffer, ' ', ws_count);
- return dump(ws_buffer, ws_count, data);
+ for(i = 0; i < depth; i++)
+ {
+ if(dump(whitespace, ws_count, data))
+ return -1;
+ }
}
return 0;
}
return dump("\"", 1, data);
}
-static int do_dump(const json_t *json, uint32_t flags, int depth,
+static int do_dump(const json_t *json, unsigned long flags, int depth,
dump_func dump, void *data)
{
switch(json_typeof(json)) {
}
-char *json_dumps(const json_t *json, uint32_t flags)
+char *json_dumps(const json_t *json, unsigned long flags)
{
strbuffer_t strbuff;
char *result;
return result;
}
-int json_dumpf(const json_t *json, FILE *output, uint32_t flags)
+int json_dumpf(const json_t *json, FILE *output, unsigned long flags)
{
if(!json_is_array(json) && !json_is_object(json))
return -1;
return dump_to_file("\n", 1, (void *)output);
}
-int json_dump_file(const json_t *json, const char *path, uint32_t flags)
+int json_dump_file(const json_t *json, const char *path, unsigned long flags)
{
int result;
static inline json_t *json_incref(json_t *json)
{
- if(json)
+ if(json && json->refcount != (unsigned int)-1)
++json->refcount;
return json;
}
static inline void json_decref(json_t *json)
{
- if(json && --json->refcount == 0)
+ if(json && json->refcount != (unsigned int)-1 && --json->refcount == 0)
json_delete(json);
}
/* getters, setters, manipulation */
json_t *json_object_get(const json_t *object, const char *key);
-int json_object_set(json_t *object, const char *key, json_t *value);
+int json_object_set_new(json_t *object, const char *key, json_t *value);
int json_object_del(json_t *object, const char *key);
void *json_object_iter(json_t *object);
void *json_object_iter_next(json_t *object, void *iter);
const char *json_object_iter_key(void *iter);
json_t *json_object_iter_value(void *iter);
+static inline
+int json_object_set(json_t *object, const char *key, json_t *value)
+{
+ return json_object_set_new(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(json_t *array, unsigned int index, json_t *value);
-int json_array_append(json_t *array, json_t *value);
+int json_array_set_new(json_t *array, unsigned int index, json_t *value);
+int json_array_append_new(json_t *array, json_t *value);
+
+static inline
+int json_array_set(json_t *array, unsigned int index, json_t *value)
+{
+ return json_array_set_new(array, index, json_incref(value));
+}
+
+static inline
+int json_array_append(json_t *array, json_t *value)
+{
+ return json_array_append_new(array, json_incref(value));
+}
+
const char *json_string_value(const json_t *json);
int json_integer_value(const json_t *json);
#define JSON_INDENT(n) (n & 0xFF)
-char *json_dumps(const json_t *json, uint32_t flags);
-int json_dumpf(const json_t *json, FILE *output, uint32_t flags);
-int json_dump_file(const json_t *json, const char *path, uint32_t flags);
+char *json_dumps(const json_t *json, unsigned long flags);
+int json_dumpf(const json_t *json, FILE *output, unsigned long flags);
+int json_dump_file(const json_t *json, const char *path, unsigned long flags);
#endif
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
-#include <unistd.h>
#include <assert.h>
#include <jansson.h>
return lex->token;
}
+static char *lex_steal_string(lex_t *lex)
+{
+ char *result = NULL;
+ if(lex->token == TOKEN_STRING)
+ {
+ result = lex->value.string;
+ lex->value.string = NULL;
+ }
+ return result;
+}
+
static int lex_init(lex_t *lex, get_func get, eof_func eof, void *data)
{
stream_init(&lex->stream, get, eof, data);
goto error;
}
- key = strdup(lex->value.string);
+ key = lex_steal_string(lex);
if(!key)
return NULL;
return hashtable_get(&object->hashtable, key);
}
-int json_object_set_nocheck(json_t *json, const char *key, json_t *value)
+int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value)
{
json_object_t *object;
- if(!json_is_object(json))
+ if(!key || !value)
return -1;
+ if(!json_is_object(json))
+ {
+ json_decref(value);
+ return -1;
+ }
object = json_to_object(json);
- return hashtable_set(&object->hashtable, strdup(key), json_incref(value));
+
+ if(hashtable_set(&object->hashtable, strdup(key), value))
+ {
+ json_decref(value);
+ return -1;
+ }
+
+ return 0;
}
-int json_object_set(json_t *json, const char *key, json_t *value)
+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(!utf8_check_string(key, -1))
+ {
+ json_decref(value);
return -1;
+ }
- return json_object_set_nocheck(json, key, value);
+ return json_object_set_new_nocheck(json, key, value);
}
int json_object_del(json_t *json, const char *key)
return array->table[index];
}
-int json_array_set(json_t *json, unsigned int index, json_t *value)
+int json_array_set_new(json_t *json, unsigned int index, json_t *value)
{
json_array_t *array;
+
+ if(!value)
+ return -1;
+
if(!json_is_array(json))
+ {
+ json_decref(value);
return -1;
+ }
array = json_to_array(json);
if(index >= array->entries)
+ {
+ json_decref(value);
return -1;
+ }
json_decref(array->table[index]);
- array->table[index] = json_incref(value);
+ array->table[index] = value;
return 0;
}
-int json_array_append(json_t *json, json_t *value)
+int json_array_append_new(json_t *json, json_t *value)
{
json_array_t *array;
+
+ if(!value)
+ return -1;
+
if(!json_is_array(json))
+ {
+ json_decref(value);
return -1;
+ }
array = json_to_array(json);
if(array->entries == array->size) {
array->size = max(8, array->size * 2);
array->table = realloc(array->table, array->size * sizeof(json_t *));
if(!array->table)
+ {
+ json_decref(value);
return -1;
+ }
}
- array->table[array->entries] = json_incref(value);
+ array->table[array->entries] = value;
array->entries++;
return 0;
json_t *json_string_nocheck(const char *value)
{
- json_string_t *string = malloc(sizeof(json_string_t));
+ json_string_t *string;
+
+ if(!value)
+ return NULL;
+
+ string = malloc(sizeof(json_string_t));
if(!string)
return NULL;
json_init(&string->json, JSON_STRING);
string->value = strdup(value);
+ if(!string->value) {
+ free(string);
+ return NULL;
+ }
+
return &string->json;
}
json_t *json_string(const char *value)
{
- if(!utf8_check_string(value, -1))
+ if(!value || !utf8_check_string(value, -1))
return NULL;
return json_string_nocheck(value);
{
static json_t the_true = {
.type = JSON_TRUE,
- .refcount = 1
+ .refcount = (unsigned int)1
};
- return json_incref(&the_true);
+ return &the_true;
}
{
static json_t the_false = {
.type = JSON_FALSE,
- .refcount = 1
+ .refcount = (unsigned int)1
};
- return json_incref(&the_false);
+ return &the_false;
}
{
static json_t the_null = {
.type = JSON_NULL,
- .refcount = 1
+ .refcount = (unsigned int)1
};
- return json_incref(&the_null);
+ return &the_null;
}
testprogs/test_array
testprogs/test_number
testprogs/test_object
+testprogs/test_simple
tmpdir="testlogs/`basename $testfile`"
rm -rf $tmpdir
mkdir -p $tmpdir
- ${srcdir}/split-testfile.py $testfile $tmpdir | while read name; do
+ 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
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)
return open(input_path, 'w'), open(output_path, 'w')
def main():
- if len(sys.argv) != 3:
- print 'usage: %s input-file output-directory' % sys.argv[0]
+ 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(sys.argv[1])
- outdir = os.path.normpath(sys.argv[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
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':
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
-TESTFILES="${srcdir}/testdata/invalid ${srcdir}/testdata/invalid-unicode"
+TESTFILES="${srcdir}/testdata/invalid ${srcdir}/testdata/invalid-strip ${srcdir}/testdata/invalid-unicode"
run_test() {
local prog=$1
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
-TESTFILES="${srcdir}/testdata/valid"
+TESTFILES="${srcdir}/testdata/valid ${srcdir}/testdata/valid-strip"
run_test() {
local prog=$1
--- /dev/null
+==== empty ====
+====
+1
+'[' or '{' expected near end of file
+==== null ====
+null
+====
+1
+'[' or '{' expected near 'null'
+==== lone-open-brace ====
+{
+====
+1
+string or '}' expected near end of file
+==== lone-open-bracket ====
+[
+====
+1
+']' expected near end of file
+==== bracket-comma ====
+[,
+====
+1
+unexpected token near ','
+==== bracket-one-comma ====
+[1,
+====
+1
+']' expected near end of file
+==== unterminated-string ====
+["a
+====
+1
+premature end of input near '"a'
+==== unterminated-array ====
+["a"
+====
+1
+']' expected near end of file
+==== apostrophe ====
+['
+====
+1
+invalid token near '''
+==== brace-comma ====
+{,
+====
+1
+string or '}' expected near ','
+==== unterminated-empty-key ====
+{"
+====
+1
+premature end of input near '"'
+==== unterminated-key ====
+{"a
+====
+1
+premature end of input near '"a'
+==== object-no-colon ====
+{"a"
+====
+1
+':' expected near end of file
+==== object-apostrophes ====
+{'a'
+====
+1
+string or '}' expected near '''
+==== object-no-value ====
+{"a":
+====
+1
+unexpected token near end of file
+==== object-unterminated-value ====
+{"a":"a
+====
+1
+premature end of input near '"a'
+==== object-garbage-at-end ====
+{"a":"a" 123}
+====
+1
+'}' expected near '123'
+==== unterminated-object-and-array ====
+{[
+====
+1
+string or '}' expected near '['
+==== unterminated-array-and-object ====
+[{
+====
+1
+string or '}' expected near end of file
+==== object-in-unterminated-array ====
+[{}
+====
+1
+']' expected near end of file
+==== extra-comma-in-array ====
+[1,]
+====
+1
+unexpected token near ']'
+==== extra-command-in-multiline-array ====
+[1,
+2,
+3,
+4,
+5,
+]
+====
+6
+unexpected token near ']'
+==== real-truncated-at-point ====
+[1.]
+====
+1
+invalid token near '1.'
+==== real-truncated-at-e ====
+[1e]
+====
+1
+invalid token near '1e'
+==== real-garbage-after-e ====
+[1ea]
+====
+1
+invalid token near '1e'
+==== real-positive-overflow ====
+[123123e100000]
+====
+1
+real number overflow near '123123e100000'
+==== real-negative-overflow ====
+[-123123e100000]
+====
+1
+real number overflow near '-123123e100000'
+==== real-underflow ====
+[123e-10000000]
+====
+1
+real number underflow near '123e-10000000'
+==== integer-starting-with-zero ====
+[012]
+====
+1
+invalid token near '0'
+==== negative-integer-starting-with-zero ====
+[-012]
+====
+1
+invalid token near '-0'
+==== too-big-positive-integer ====
+[123123123123123]
+====
+1
+too big integer near '123123123123123'
+==== too-big-negative-integer ====
+[-123123123123123]
+====
+1
+too big negative integer near '-123123123123123'
+==== invalid-identifier ====
+[troo
+====
+1
+invalid token near 'troo'
+==== invalid-escap ====
+["\a <-- invalid escape"]
+====
+1
+invalid escape near '"\'
+==== tab-character-in-string ====
+[" <-- tab character"]
+====
+1
+control character 0x9 near '"'
+==== null-byte-in-string ====
+["\u0000 (null byte not allowed)"]
+====
+1
+\u0000 is not allowed
+==== truncated-unicode-surrogate ====
+["\uDADA (first surrogate without the second)"]
+====
+1
+invalid Unicode '\uDADA'
+==== invalid-second-surrogate ====
+["\uD888\u3210 (first surrogate and invalid second surrogate)"]
+====
+1
+invalid Unicode '\uD888\u3210'
+==== lone-second-surrogate ====
+["\uDFAA (second surrogate on it's own)"]
+====
+1
+invalid Unicode '\uDFAA'
+==== unicode-identifier ====
+å
+====
+1
+'[' or '{' expected near 'å'
+==== ascii-unicode-identifier ====
+aå
+====
+1
+'[' or '{' expected near 'a'
+==== garbage-at-the-end ====
+[1,2,3]foo
+====
+1
+end of file expected near 'foo'
+==== garbage-after-newline ====
+[1,2,3]
+foo
+====
+2
+end of file expected near 'foo'
--- /dev/null
+==== empty-string ====
+[""]
+==== short-string ====
+["a"]
+==== simple-ascii-string ====
+["abcdefghijklmnopqrstuvwxyz1234567890 "]
+==== utf-8-string ====
+["€þıœəßð some utf-8 ĸʒ×ŋµåäö𝄞"]
+==== string-escapes ====
+["\"\\\/\b\f\n\r\t"]
+==== one-byte-utf-8 ====
+["\u002c one-byte UTF-8"]
+==== two-byte-utf-8 ====
+["\u0123 two-byte UTF-8"]
+==== three-byte-utf-8 ====
+["\u0821 three-byte UTF-8"]
+==== utf-surrogate-four-byte-encoding ====
+["\uD834\uDD1E surrogate, four-byte UTF-8"]
+==== escaped-utf-control-char ====
+["\u0012 escaped control character"]
+==== simple-int-0 ====
+[0]
+==== simple-int-1 ====
+[1]
+==== simple-int-123 ====
+[123]
+==== negative-zero ====
+[-0]
+==== negative-one ====
+[-1]
+==== negative-int ====
+[-123]
+==== simple-real ====
+[123.456789]
+==== real-exponent ====
+[123e45]
+==== real-capital-e ====
+[1E22]
+==== real-positive-exponent ====
+[1e+2]
+==== real-negative-exponent ====
+[1e-2]
+==== real-capital-e-positive-exponent ====
+[1E+2]
+==== real-capital-e-negative-exponent ====
+[1E-2]
+==== real-fraction-exponent ====
+[123.456e78]
+==== true ====
+[true]
+==== false ====
+[false]
+==== null ====
+[null]
+==== empty-array ====
+[]
+==== empty-object-in-array ====
+[{}]
+==== complex-array ====
+[1,2,3,4,
+"a", "b", "c",
+{"foo": "bar", "core": "dump"},
+true, false, true, true, null, false
+]
+==== empty-object ====
+{}
+==== simple-object ====
+{"a":[]}
-check_PROGRAMS = test_array test_number test_object
+check_PROGRAMS = test_array test_simple test_number test_object
test_array_SOURCES = test_array.c util.h
+test_simple_SOURCES = test_simple.c util.h
test_number_SOURCES = test_number.c util.h
test_object_SOURCES = test_number.c util.h
if(json_array_size(array) != 0)
fail("empty array has nonzero size");
+ if(!json_array_append(array, NULL))
+ fail("able to append NULL");
+
if(json_array_append(array, five))
fail("unable to append");
if(json_array_set(array, 0, seven))
fail("unable to set value");
+ if(!json_array_set(array, 0, NULL))
+ fail("able to set NULL");
+
if(json_array_size(array) != 2)
fail("wrong array size");
fail("got wrong value");
}
+ if(json_array_set_new(array, 15, json_integer(123)))
+ fail("unable to set new value");
+
+ value = json_array_get(array, 15);
+ if(!json_is_integer(value) || json_integer_value(value) != 123)
+ fail("json_array_set_new works incorrectly");
+
+ if(!json_array_set_new(array, 15, NULL))
+ fail("able to set_new NULL value");
+
+ if(json_array_append_new(array, json_integer(321)))
+ fail("unable to append new value");
+
+ value = json_array_get(array, json_array_size(array) - 1);
+ if(!json_is_integer(value) || json_integer_value(value) != 321)
+ fail("json_array_append_new works incorrectly");
+
+ if(!json_array_append_new(array, NULL))
+ fail("able to append_new NULL value");
+
json_decref(five);
json_decref(seven);
json_decref(array);
if(json_object_set(object, "a", string))
fail("unable to set value");
+ if(!json_object_set(object, NULL, string))
+ fail("able to set NULL key");
+
+ if(!json_object_set(object, "a", NULL))
+ fail("able to set NULL value");
+
+ iter = json_object_iter(object);
+ if(!iter)
+ fail("unable to get iterator");
+
+ if(strcmp(json_object_iter_key(iter), "a"))
+ fail("iterating failed: wrong key");
+ if(json_object_iter_value(iter) != string)
+ fail("iterating failed: wrong value");
+ if(json_object_iter_next(object, iter) != NULL)
+ fail("able to iterate over the end");
+
/* invalid UTF-8 in key */
if(!json_object_set(object, "a\xefz", string))
fail("able to set invalid unicode key");
if(value != string)
fail("got different value than what was added");
- /* "a", "lp" and "px" collide with a five-bucket hashtable */
+ /* "a", "lp" and "px" collide in a five-bucket hashtable */
if(json_object_set(object, "b", string) ||
json_object_set(object, "lp", string) ||
json_object_set(object, "px", string))
fail("unable to delete an existing key");
- /* add many keys to rehashing */
+ /* add many keys to initiate rehashing */
if(json_object_set(object, "a", string))
fail("unable to set value");
if(json_object_set(object, "e", string))
fail("unable to set value");
+
+ if(json_object_set_new(object, "foo", json_integer(123)))
+ fail("unable to set new value");
+
+ value = json_object_get(object, "foo");
+ if(!json_is_integer(value) || json_integer_value(value) != 123)
+ fail("json_object_set_new works incorrectly");
+
+ if(!json_object_set_new(object, NULL, json_integer(432)))
+ fail("able to set_new NULL key");
+
+ if(!json_object_set_new(object, "foo", NULL))
+ fail("able to set_new NULL value");
+
json_decref(string);
json_decref(other_string);
json_decref(object);
--- /dev/null
+/*
+ * 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"
+
+/* Call the simple functions not covered by other tests of the public API */
+int main()
+{
+ json_t *value;
+
+ value = json_integer(1);
+ if(json_typeof(value) != JSON_INTEGER)
+ fail("json_typeof failed");
+
+ if(json_is_object(value))
+ fail("json_is_object failed");
+
+ if(json_is_array(value))
+ fail("json_is_array failed");
+
+ if(json_is_string(value))
+ fail("json_is_string failed");
+
+ if(!json_is_integer(value))
+ fail("json_is_integer failed");
+
+ if(json_is_real(value))
+ fail("json_is_real failed");
+
+ if(!json_is_number(value))
+ fail("json_is_number failed");
+
+ if(json_is_true(value))
+ fail("json_is_true failed");
+
+ if(json_is_false(value))
+ fail("json_is_false failed");
+
+ if(json_is_boolean(value))
+ fail("json_is_boolean failed");
+
+ if(json_is_null(value))
+ fail("json_is_null failed");
+
+ json_decref(value);
+
+
+ value = json_string("foo");
+ if(!value)
+ fail("json_string failed");
+ if(strcmp(json_string_value(value), "foo"))
+ fail("invalid string value");
+ json_decref(value);
+
+ value = json_string(NULL);
+ if(value)
+ fail("json_string(NULL) failed");
+
+ value = json_integer(123);
+ if(!value)
+ fail("json_integer failed");
+ if(json_integer_value(value) != 123)
+ fail("invalid integer value");
+ if(json_number_value(value) != 123.0)
+ fail("invalid number value");
+ json_decref(value);
+
+ value = json_real(123.123);
+ if(!value)
+ fail("json_real failed");
+ if(json_real_value(value) != 123.123)
+ fail("invalid integer value");
+ if(json_number_value(value) != 123.123)
+ fail("invalid number value");
+ json_decref(value);
+
+ value = json_true();
+ if(!value)
+ fail("json_true failed");
+ json_decref(value);
+
+ value = json_false();
+ if(!value)
+ fail("json_false failed");
+ json_decref(value);
+
+ value = json_null();
+ if(!value)
+ fail("json_null failed");
+ json_decref(value);
+
+ return 0;
+}