diff options
author | Michael Clark <michael@metaparadigm.com> | 2010-10-06 16:39:20 +0000 |
---|---|---|
committer | Michael Clark <michael@metaparadigm.com> | 2010-10-06 16:39:20 +0000 |
commit | c4dceae1c53bc37cacc46a806f8a02524d12a382 (patch) | |
tree | c10fe3348cc8ff3ddee17f4cae386cbe2e5421a6 | |
parent | 88ded9ceb8296eb6661c4d6f8f266ac74d81b9c4 (diff) | |
download | json-c-c4dceae1c53bc37cacc46a806f8a02524d12a382.tar.gz |
* Add int64 support. Two new functions json_object_net_int64 and
json_object_get_int64. Binary compatibility preserved.
Eric Haszlakiewicz, EHASZLA at transunion com
Rui Miguel Silva Seabra, rms at 1407 dot org
git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@56 327403b1-1117-474d-bef2-5cb71233fd97
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | Doxyfile | 2 | ||||
-rw-r--r-- | Makefile.am | 32 | ||||
-rw-r--r-- | config.h.in | 6 | ||||
-rw-r--r-- | json_inttypes.h | 21 | ||||
-rw-r--r-- | json_object.c | 72 | ||||
-rw-r--r-- | json_object.h | 28 | ||||
-rw-r--r-- | json_object_private.h | 3 | ||||
-rw-r--r-- | json_tokener.c | 24 | ||||
-rw-r--r-- | json_util.c | 65 | ||||
-rw-r--r-- | json_util.h | 1 | ||||
-rw-r--r-- | parse_int64.test | 12 | ||||
-rw-r--r-- | test-defs.sh | 114 | ||||
-rw-r--r-- | test1.c | 2 | ||||
-rw-r--r-- | test1.expected | 44 | ||||
-rw-r--r-- | test1.test | 12 | ||||
-rw-r--r-- | test2.expected | 1 | ||||
-rw-r--r-- | test2.test | 12 | ||||
-rw-r--r-- | test4.c | 17 | ||||
-rw-r--r-- | test4.expected | 3 | ||||
-rw-r--r-- | test4.test | 12 | ||||
-rw-r--r-- | test_parse_int64.c | 99 | ||||
-rw-r--r-- | test_parse_int64.expected | 23 |
23 files changed, 569 insertions, 40 deletions
@@ -1,4 +1,8 @@ 0.10 + * Add int64 support. Two new functions json_object_net_int64 and + json_object_get_int64. Binary compatibility preserved. + Eric Haszlakiewicz, EHASZLA at transunion com + Rui Miguel Silva Seabra, rms at 1407 dot org * Fix subtle bug in linkhash where lookup could hang after all slots were filled then successively freed. Spotted by Jean-Marc Naud, j dash m at newtraxtech dot com @@ -23,7 +23,7 @@ PROJECT_NAME = json-c # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 0.2 +PROJECT_NUMBER = 0.10 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. diff --git a/Makefile.am b/Makefile.am index 1c1a9ba..dc920f8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,16 +9,17 @@ pkgconfig_DATA = json.pc libjsonincludedir = $(includedir)/json libjsoninclude_HEADERS = \ - json.h \ + arraylist.h \ bits.h \ debug.h \ - linkhash.h \ - arraylist.h \ - printbuf.h \ - json_util.h \ + json.h \ + json_inttypes.h \ json_object.h \ - json_object_private.h \ - json_tokener.h + json_object_private.h \ + json_tokener.h \ + json_util.h \ + linkhash.h \ + printbuf.h libjson_la_LDFLAGS = -version-info 0:1:0 @@ -31,7 +32,7 @@ libjson_la_SOURCES = \ linkhash.c \ printbuf.c -check_PROGRAMS = test1 test2 test3 test4 +check_PROGRAMS = test1 test2 test4 test_parse_int64 test1_SOURCES = test1.c test1_LDADD = $(lib_LTLIBRARIES) @@ -39,8 +40,17 @@ test1_LDADD = $(lib_LTLIBRARIES) test2_SOURCES = test2.c test2_LDADD = $(lib_LTLIBRARIES) -test3_SOURCES = test3.c -test3_LDADD = $(lib_LTLIBRARIES) - test4_SOURCES = test4.c test4_LDADD = $(lib_LTLIBRARIES) + +test_parse_int64_SOURCES = test_parse_int64.c +test_parse_int64_LDADD = $(lib_LTLIBRARIES) + +TESTS = test1.test test2.test test4.test parse_int64.test +EXTRA_DIST += $(TESTS) +testsubdir=testSubDir +TESTS_ENVIRONMENT = top_builddir=$(top_builddir) + +distclean-local: + -rm -rf $(testsubdir) + diff --git a/config.h.in b/config.h.in index 5139ae8..83ab797 100644 --- a/config.h.in +++ b/config.h.in @@ -80,10 +80,6 @@ /* Define to 1 if you have the `vsyslog' function. */ #undef HAVE_VSYSLOG -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#undef LT_OBJDIR - /* Name of package */ #undef PACKAGE @@ -117,5 +113,5 @@ /* Define to rpl_realloc if the replacement function should be used. */ #undef realloc -/* Define to `unsigned int' if <sys/types.h> does not define. */ +/* Define to `unsigned' if <sys/types.h> does not define. */ #undef size_t diff --git a/json_inttypes.h b/json_inttypes.h new file mode 100644 index 0000000..1cbafc2 --- /dev/null +++ b/json_inttypes.h @@ -0,0 +1,21 @@ + +#ifndef _json_inttypes_h_ +#define _json_inttypes_h_ + +#if defined(_MSC_VER) && _MSC_VER < 1600 + +/* Anything less than Visual Studio C++ 10 is missing stdint.h and inttypes.h */ +typedef __int64 int64_t; +#define PRId64 "I64d" +#define SCNd64 "I64d" + +#else + +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#endif +/* inttypes.h includes stdint.h */ + +#endif + +#endif diff --git a/json_object.c b/json_object.c index f52445c..c2b6fe2 100644 --- a/json_object.c +++ b/json_object.c @@ -20,8 +20,10 @@ #include "printbuf.h" #include "linkhash.h" #include "arraylist.h" +#include "json_inttypes.h" #include "json_object.h" #include "json_object_private.h" +#include "json_util.h" #if !HAVE_STRNDUP char* strndup(const char* str, size_t n); @@ -41,6 +43,7 @@ static const char* json_type_name[] = { "object", "array", "string", + "int64", }; #endif /* REFCOUNT_DEBUG */ @@ -304,6 +307,8 @@ boolean json_object_get_boolean(struct json_object *jso) return jso->o.c_boolean; case json_type_int: return (jso->o.c_int != 0); + case json_type_int64: + return (jso->o.c_int64 != 0); case json_type_double: return (jso->o.c_double != 0); case json_type_string: @@ -322,7 +327,11 @@ static int json_object_int_to_json_string(struct json_object* jso, return sprintbuf(pb, "%d", jso->o.c_int); } -struct json_object* json_object_new_int(int i) +static int json_object_int64_to_json_string(struct json_object* jso, struct printbuf *pb) { + return sprintbuf(pb, "%"PRId64, jso->o.c_int64); +} + +struct json_object* json_object_new_int(int32_t i) { struct json_object *jso = json_object_new(json_type_int); if(!jso) return NULL; @@ -331,20 +340,69 @@ struct json_object* json_object_new_int(int i) return jso; } -int json_object_get_int(struct json_object *jso) +int32_t json_object_get_int(struct json_object *jso) { - int cint; - if(!jso) return 0; + + enum json_type o_type = jso->o_type; + int64_t cint64 = jso->o.c_int64; + + if (o_type == json_type_string) + { + /* + * Parse strings into 64-bit numbers, then use the + * 64-to-32-bit number handling below. + */ + if (json_parse_int64(jso->o.c_string, &cint64) != 0) + return 0; /* whoops, it didn't work. */ + o_type = json_type_int64; + } + switch(jso->o_type) { case json_type_int: return jso->o.c_int; + case json_type_int64: + /* Make sure we return the correct values for out of range numbers. */ + if (cint64 <= INT32_MIN) + return INT32_MIN; + else if (cint64 >= INT32_MAX) + return INT32_MAX; + else + return (int32_t)cint64; + case json_type_double: + return (int32_t)jso->o.c_double; + case json_type_boolean: + return jso->o.c_boolean; + default: + return 0; + } +} + +struct json_object* json_object_new_int64(int64_t i) +{ + struct json_object *jso = json_object_new(json_type_int64); + if(!jso) return NULL; + jso->_to_json_string = &json_object_int64_to_json_string; + jso->o.c_int64 = i; + return jso; +} + +int64_t json_object_get_int64(struct json_object *jso) +{ + int64_t cint; + + if(!jso) return 0; + switch(jso->o_type) { + case json_type_int: + return (int64_t)jso->o.c_int; + case json_type_int64: + return jso->o.c_int64; case json_type_double: - return (int)jso->o.c_double; + return (int64_t)jso->o.c_double; case json_type_boolean: return jso->o.c_boolean; case json_type_string: - if(sscanf(jso->o.c_string, "%d", &cint) == 1) return cint; + if (json_parse_int64(jso->o.c_string, &cint) == 0) return cint; default: return 0; } @@ -378,6 +436,8 @@ double json_object_get_double(struct json_object *jso) return jso->o.c_double; case json_type_int: return jso->o.c_int; + case json_type_int64: + return jso->o.c_int64; case json_type_boolean: return jso->o.c_boolean; case json_type_string: diff --git a/json_object.h b/json_object.h index 80d2313..cea4c81 100644 --- a/json_object.h +++ b/json_object.h @@ -46,7 +46,8 @@ typedef enum json_type { json_type_int, json_type_object, json_type_array, - json_type_string + json_type_string, + json_type_int64 } json_type; /* reference counting functions */ @@ -74,6 +75,7 @@ extern void json_object_put(struct json_object *obj); json_type_object, json_type_array, json_type_string, + json_type_int64, */ extern int json_object_is_type(struct json_object *obj, enum json_type type); @@ -87,6 +89,7 @@ extern int json_object_is_type(struct json_object *obj, enum json_type type); json_type_object, json_type_array, json_type_string, + json_type_int64, */ extern enum json_type json_object_get_type(struct json_object *obj); @@ -252,7 +255,15 @@ extern boolean json_object_get_boolean(struct json_object *obj); * @param i the integer * @returns a json_object of type json_type_int */ -extern struct json_object* json_object_new_int(int i); +extern struct json_object* json_object_new_int(int32_t i); + + +/** Create a new empty json_object of type json_type_int64 + * @param i the integer + * @returns a json_object of type json_type_int64 + */ +extern struct json_object* json_object_new_int64(int64_t i); + /** Get the int value of a json_object * @@ -263,7 +274,18 @@ extern struct json_object* json_object_new_int(int i); * @param obj the json_object instance * @returns an int */ -extern int json_object_get_int(struct json_object *obj); +extern int32_t json_object_get_int(struct json_object *obj); + +/** Get the int value of a json_object + * + * The type is coerced to a int64 if the passed object is not a int64. + * double objects will return their int64 conversion. Strings will be + * parsed as an int64. If no conversion exists then 0 is returned. + * + * @param obj the json_object instance + * @returns an int64 + */ +extern int64_t json_object_get_int64(struct json_object *obj); /* double type methods */ diff --git a/json_object_private.h b/json_object_private.h index 9fb4011..a0f9845 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -30,7 +30,8 @@ struct json_object union data { boolean c_boolean; double c_double; - int c_int; + int32_t c_int; + int64_t c_int64; struct lh_table *c_object; struct array_list *c_array; char *c_string; diff --git a/json_tokener.c b/json_tokener.c index 8d0b5dc..dbaacaa 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -20,14 +20,16 @@ #include <stddef.h> #include <ctype.h> #include <string.h> +#include <limits.h> #include "bits.h" #include "debug.h" #include "printbuf.h" #include "arraylist.h" +#include "json_inttypes.h" #include "json_object.h" #include "json_tokener.h" - +#include "json_util.h" #if !HAVE_STRNCASECMP && defined(_MSC_VER) /* MSC has the version as _strnicmp */ @@ -542,11 +544,21 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, printbuf_memappend_fast(tok->pb, case_start, case_len); } { - int numi; - double numd; - if(!tok->is_double && sscanf(tok->pb->buf, "%d", &numi) == 1) { - current = json_object_new_int(numi); - } else if(tok->is_double && sscanf(tok->pb->buf, "%lf", &numd) == 1) { + int64_t num64; + double numd; + if (!tok->is_double && json_parse_int64(tok->pb->buf, &num64) == 0) { + // Decode the type based on the value range to keep compatibilty + // with code that checks the type of objects. i.e. this: + // json_object_get_type(o) == json_type_int + // will continue to work. + // The other option would be to eliminate any distinction between + // int and int64 types, but that would change the ABI of + // json_object_get_int(). + if (num64 < INT32_MAX && num64 > INT32_MIN) + current = json_object_new_int(num64); + else + current = json_object_new_int64(num64); + } else if(tok->is_double && sscanf(tok->pb->buf, "%lf", &numd) == 1) { current = json_object_new_double(numd); } else { tok->err = json_tokener_error_parse_number; diff --git a/json_util.c b/json_util.c index 06e4a71..e5a9dc6 100644 --- a/json_util.c +++ b/json_util.c @@ -17,6 +17,7 @@ #include <limits.h> #include <string.h> #include <errno.h> +#include <ctype.h> #if HAVE_SYS_TYPES_H #include <sys/types.h> @@ -48,6 +49,7 @@ #include "bits.h" #include "debug.h" #include "printbuf.h" +#include "json_inttypes.h" #include "json_object.h" #include "json_tokener.h" #include "json_util.h" @@ -120,3 +122,66 @@ int json_object_to_file(char *filename, struct json_object *obj) close(fd); return 0; } + +int json_parse_int64(const char *buf, int64_t *retval) +{ + int64_t num64; + if (sscanf(buf, "%" SCNd64, &num64) != 1) + { + printf("Failed to parse, sscanf != 1\n"); + return 1; + } + const char *buf_skip_space = buf; + int orig_has_neg = 0; + // Skip leading spaces + while (isspace((int)*buf_skip_space) && *buf_skip_space) + buf_skip_space++; + if (*buf_skip_space == '-') + { + buf_skip_space++; + orig_has_neg = 1; + } + // Skip leading zeros + while (*buf_skip_space == '0' && *buf_skip_space) + buf_skip_space++; + + if (errno != ERANGE) + { + char buf_cmp[100]; + char *buf_cmp_start = buf_cmp; + int recheck_has_neg = 0; + snprintf(buf_cmp_start, sizeof(buf_cmp), "%" PRId64, num64); + if (*buf_cmp_start == '-') + { + recheck_has_neg = 1; + buf_cmp_start++; + } + // No need to skip leading spaces or zeros here. + + int buf_cmp_len = strlen(buf_cmp_start); + /** + * If the sign is different, or + * some of the digits are different, or + * there is another digit present in the original string + * then we NOT successfully parsed the value. + */ + if (orig_has_neg != recheck_has_neg || + strncmp(buf_skip_space, buf_cmp_start, strlen(buf_cmp_start)) != 0 || + (strlen(buf_skip_space) != buf_cmp_len && + isdigit(buf_skip_space[buf_cmp_len]) + ) + ) + { + errno = ERANGE; + } + } + if (errno == ERANGE) + { + if (orig_has_neg) + num64 = INT64_MIN; + else + num64 = INT64_MAX; + } + *retval = num64; + return 0; +} diff --git a/json_util.h b/json_util.h index 134390f..fbfcb14 100644 --- a/json_util.h +++ b/json_util.h @@ -23,6 +23,7 @@ extern "C" { /* utility functions */ extern struct json_object* json_object_from_file(const char *filename); extern int json_object_to_file(char *filename, struct json_object *obj); +extern int json_parse_int64(const char *buf, int64_t *retval); #ifdef __cplusplus } diff --git a/parse_int64.test b/parse_int64.test new file mode 100644 index 0000000..2b7fbfb --- /dev/null +++ b/parse_int64.test @@ -0,0 +1,12 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +run_output_test test_parse_int64 +exit $? diff --git a/test-defs.sh b/test-defs.sh new file mode 100644 index 0000000..2014b37 --- /dev/null +++ b/test-defs.sh @@ -0,0 +1,114 @@ + +#! /bin/sh + +# Make sure srcdir is an absolute path. Supply the variable +# if it does not exist. We want to be able to run the tests +# stand-alone!! +# +srcdir=${srcdir-.} +if test ! -d $srcdir ; then + echo "test-defs.sh: installation error" 1>&2 + exit 1 +fi + +# Use absolute paths +case "$srcdir" in + /* | [A-Za-z]:\\*) ;; + *) srcdir=`\cd $srcdir && pwd` ;; +esac + +case "$top_builddir" in + /* | [A-Za-z]:\\*) ;; + *) top_builddir=`\cd ${top_builddir-..} && pwd` ;; +esac + +progname=`echo "$0" | sed 's,^.*/,,'` +testname=`echo "$progname" | sed 's,-.*$,,'` +testsubdir=${testsubdir-testSubDir} + +# User can set VERBOSE to cause output redirection +case "$VERBOSE" in +[Nn]|[Nn][Oo]|0|"") + VERBOSE=0 + exec > /dev/null 2>&1 + ;; +[Yy]|[Yy][Ee][Ss]) + VERBOSE=1 + ;; +esac + +rm -rf "$testsubdir/$progname" > /dev/null 2>&1 +mkdir -p "$testsubdir/$progname" +cd "$testsubdir/$progname" \ + || { echo "Cannot make or change into $testsubdir/$progname"; exit 1; } + +echo "=== Running test $progname" + +CMP="${CMP-cmp}" + +use_valgrind=${USE_VALGRIND-1} +valgrind_path=$(which valgrind 2> /dev/null) +if [ -z "${valgrind_path}" -o ! -x "${valgrind_path}" ] ; then + use_valgrind=0 +fi + +# +# This is a common function to check the results of a test program +# that is intended to generate consistent output across runs. +# +# ${top_builddir} must be set to the top level build directory. +# +# Output will be written to the current directory. +# +# It must be passed the name of the test command to run, which must be present +# in the ${top_builddir} directory. +# +# It will compare the output of running that against <name of command>.expected +# +run_output_test() +{ + TEST_COMMAND="$1" + + REDIR_OUTPUT="> \"${TEST_COMMAND}.out\"" + if [ $VERBOSE -gt 1 ] ; then + REDIR_OUTPUT="| tee \"${TEST_COMMAND}.out\"" + fi + + if [ $use_valgrind -eq 1 ] ; then + eval valgrind --tool=memcheck \ + --trace-children=yes \ + --demangle=yes \ + --log-file=vg.out \ + --leak-check=full \ + --show-reachable=yes \ + --run-libc-freeres=yes \ + "\"${top_builddir}/${TEST_COMMAND}\"" ${REDIR_OUTPUT} + err=$? + + else + eval "\"${top_builddir}/${TEST_COMMAND}"\" ${REDIR_OUTPUT} + err=$? + fi + + if [ $err -ne 0 ] ; then + echo "ERROR: ${TEST_COMMAND} exited with non-zero exit status: $err" 1>&2 + fi + + if [ $use_valgrind -eq 1 ] ; then + if ! tail -1 "vg.out" | grep -q "ERROR SUMMARY: 0 errors" ; then + echo "ERROR: valgrind found errors during execution:" 1>&2 + cat vg.out + err=1 + fi + fi + + if ! "$CMP" -s "${top_builddir}/${TEST_COMMAND}.expected" "${TEST_COMMAND}.out" ; then + echo "ERROR: ${TEST_COMMAND} failed:" 1>&2 + diff "${top_builddir}/${TEST_COMMAND}.expected" "${TEST_COMMAND}.out" 1>&2 + err=1 + fi + + return $err +} + + @@ -158,7 +158,7 @@ int main(int argc, char **argv) json_object_put(my_string); json_object_put(my_int); json_object_put(my_object); - //json_object_put(my_array); + json_object_put(my_array); return 0; } diff --git a/test1.expected b/test1.expected new file mode 100644 index 0000000..e38ef50 --- /dev/null +++ b/test1.expected @@ -0,0 +1,44 @@ +my_string= +my_string.to_string()="\t" +my_string=\ +my_string.to_string()="\\" +my_string=foo +my_string.to_string()="foo" +my_int=9 +my_int.to_string()=9 +my_array= + [0]=1 + [1]=2 + [2]=3 + [3]=null + [4]=5 +my_array.to_string()=[ 1, 2, 3, null, 5 ] +my_object= + abc: 12 + foo: "bar" + bool0: false + bool1: true +my_object.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true } +new_obj.to_string()="\u0003" +new_obj.to_string()="foo" +new_obj.to_string()="foo" +new_obj.to_string()="ABC" +new_obj.to_string()=null +new_obj.to_string()=true +new_obj.to_string()=12 +new_obj.to_string()=12.300000 +new_obj.to_string()=[ "\n" ] +new_obj.to_string()=[ "\nabc\n" ] +new_obj.to_string()=[ null ] +new_obj.to_string()=[ ] +new_obj.to_string()=[ false ] +new_obj.to_string()=[ "abc", null, "def", 12 ] +new_obj.to_string()={ } +new_obj.to_string()={ "foo": "bar" } +new_obj.to_string()={ "foo": "bar", "baz": null, "bool0": true } +new_obj.to_string()={ "foo": [ null, "foo" ] } +new_obj.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true, "arr": [ 1, 2, 3, null, 5 ] } +got error as expected +got error as expected +got error as expected +new_obj.to_string()={ "foo": { "bar": 13 } } diff --git a/test1.test b/test1.test new file mode 100644 index 0000000..6074fac --- /dev/null +++ b/test1.test @@ -0,0 +1,12 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +run_output_test test1 +exit $? diff --git a/test2.expected b/test2.expected new file mode 100644 index 0000000..0b740a9 --- /dev/null +++ b/test2.expected @@ -0,0 +1 @@ +new_obj.to_string()={ "glossary": { "title": "example glossary", "GlossDiv": { "title": "S", "GlossList": [ { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": [ "GML", "XML", "markup" ] } ] } } } diff --git a/test2.test b/test2.test new file mode 100644 index 0000000..cbb3830 --- /dev/null +++ b/test2.test @@ -0,0 +1,12 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +run_output_test test2 +exit $? @@ -4,11 +4,14 @@ #include <stdio.h> #include <string.h> -#include <json/json_object.h> -#include <json/json_tokener.h> +#include "config.h" -void print_hex( const unsigned char* s) { - const unsigned char *iter = s; +#include "json_inttypes.h" +#include "json_object.h" +#include "json_tokener.h" + +void print_hex( const char* s) { + const char *iter = s; unsigned char ch; while ((ch = *iter++) != 0) { if( ',' != ch) @@ -28,10 +31,10 @@ int main() { printf("input: %s\n", input); int strings_match = !strcmp( expected, unjson); + int retval = 0; if (strings_match) { printf("JSON parse result is correct: %s\n", unjson); printf("PASS\n"); - return(0); } else { printf("JSON parse result doesn't match expected string\n"); printf("expected string bytes: "); @@ -39,6 +42,8 @@ int main() { printf("parsed string bytes: "); print_hex( unjson); printf("FAIL\n"); - return(1); + retval = 1; } + json_object_put(parse_result); + return retval; } diff --git a/test4.expected b/test4.expected new file mode 100644 index 0000000..68d4336 --- /dev/null +++ b/test4.expected @@ -0,0 +1,3 @@ +input: "\ud840\udd26,\ud840\udd27,\ud800\udd26,\ud800\udd27" +JSON parse result is correct: 𠄦,𠄧,𐄦,𐄧 +PASS diff --git a/test4.test b/test4.test new file mode 100644 index 0000000..8bcc460 --- /dev/null +++ b/test4.test @@ -0,0 +1,12 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +run_output_test test4 +exit $? diff --git a/test_parse_int64.c b/test_parse_int64.c new file mode 100644 index 0000000..42d4575 --- /dev/null +++ b/test_parse_int64.c @@ -0,0 +1,99 @@ + +#include <stdio.h> +#include <string.h> + +#include "config.h" + +#include "json_inttypes.h" +#include "json_util.h" + +void checkit(const char *buf) +{ + int64_t cint64 = -666; + + int retval = json_parse_int64(buf, &cint64); + printf("buf=%s parseit=%d, value=%" PRId64 " \n", buf, retval, cint64); +} + +/** + * This test calls json_parse_int64 with a variety of different strings. + * It's purpose is to ensure that the results are consistent across all + * different environments that it might be executed in. + * + * This always exits with a 0 exit value. The output should be compared + * against previously saved expected output. + */ +int main() +{ + char buf[100]; + + checkit("x"); + + checkit("1"); + + strcpy(buf, "2147483647"); // aka INT32_MAX + checkit(buf); + + strcpy(buf, "-1"); + checkit(buf); + + strcpy(buf, " -1"); + checkit(buf); + + strcpy(buf, "00001234"); + checkit(buf); + + strcpy(buf, "0001234x"); + checkit(buf); + + strcpy(buf, "-00001234"); + checkit(buf); + + strcpy(buf, "-00001234x"); + checkit(buf); + + strcpy(buf, "4294967295"); // aka UINT32_MAX + + sprintf(buf, "4294967296"); // aka UINT32_MAX + 1 + + strcpy(buf, "21474836470"); // INT32_MAX * 10 + checkit(buf); + + strcpy(buf, "31474836470"); // INT32_MAX * 10 + a bunch + checkit(buf); + + strcpy(buf, "-2147483647"); // INT32_MIN + 1 + checkit(buf); + + strcpy(buf, "-2147483648"); // INT32_MIN + checkit(buf); + + strcpy(buf, "-2147483649"); // INT32_MIN - 1 + checkit(buf); + + strcpy(buf, "-21474836480"); // INT32_MIN * 10 + checkit(buf); + + strcpy(buf, "9223372036854775807"); // INT64_MAX + checkit(buf); + + strcpy(buf, "9223372036854775808"); // INT64_MAX + 1 + checkit(buf); + + strcpy(buf, "-9223372036854775808"); // INT64_MIN + checkit(buf); + + strcpy(buf, "-9223372036854775809"); // INT64_MIN - 1 + checkit(buf); + + strcpy(buf, "18446744073709551615"); // UINT64_MAX + checkit(buf); + + strcpy(buf, "18446744073709551616"); // UINT64_MAX + 1 + checkit(buf); + + strcpy(buf, "-18446744073709551616"); // -UINT64_MAX + checkit(buf); + + return 0; +} diff --git a/test_parse_int64.expected b/test_parse_int64.expected new file mode 100644 index 0000000..2d01ca7 --- /dev/null +++ b/test_parse_int64.expected @@ -0,0 +1,23 @@ +Failed to parse, sscanf != 1 +buf=x parseit=1, value=-666 +buf=1 parseit=0, value=1 +buf=2147483647 parseit=0, value=2147483647 +buf=-1 parseit=0, value=-1 +buf= -1 parseit=0, value=-1 +buf=00001234 parseit=0, value=1234 +buf=0001234x parseit=0, value=1234 +buf=-00001234 parseit=0, value=-1234 +buf=-00001234x parseit=0, value=-1234 +buf=21474836470 parseit=0, value=21474836470 +buf=31474836470 parseit=0, value=31474836470 +buf=-2147483647 parseit=0, value=-2147483647 +buf=-2147483648 parseit=0, value=-2147483648 +buf=-2147483649 parseit=0, value=-2147483649 +buf=-21474836480 parseit=0, value=-21474836480 +buf=9223372036854775807 parseit=0, value=9223372036854775807 +buf=9223372036854775808 parseit=0, value=9223372036854775807 +buf=-9223372036854775808 parseit=0, value=-9223372036854775808 +buf=-9223372036854775809 parseit=0, value=-9223372036854775808 +buf=18446744073709551615 parseit=0, value=9223372036854775807 +buf=18446744073709551616 parseit=0, value=9223372036854775807 +buf=-18446744073709551616 parseit=0, value=-9223372036854775808 |