Compare commits

...

86 Commits

Author SHA1 Message Date
Max Bruckner
030d0c14cc Merge branch 'develop' (Release 1.4.0) 2017-03-03 23:26:52 +01:00
Max Bruckner
02cd3eec37 Update version number to 1.4.0 2017-03-03 23:21:53 +01:00
Max Bruckner
bdb59f09de Add contributing guideline 2017-03-03 22:14:11 +01:00
Max Bruckner
5f783fff11 cJSON_Utils: Add gcc pragma to use default visibility for system headers 2017-03-03 00:45:50 +01:00
Max Bruckner
7969af6434 Merge pull request #124 from DaveGamble/print-bool-return
Print functions: Return boolean values instead of pointers
2017-03-03 00:42:01 +01:00
Max Bruckner
0bb1843925 print_value: return as soon as possible 2017-03-03 00:40:02 +01:00
Max Bruckner
5ea4fad263 print_string: return boolean instead of pointer 2017-03-03 00:33:11 +01:00
Max Bruckner
1749de02f8 print_number: return boolean instead of pointer 2017-03-03 00:26:58 +01:00
Max Bruckner
748f4bfd4f print_object: return boolean instead of pointer 2017-03-03 00:21:34 +01:00
Max Bruckner
bea1d102fd print_array: return boolean instead of pointer 2017-03-03 00:16:54 +01:00
Max Bruckner
d441fa05b3 print_value: return boolean instead of pointer 2017-03-03 00:11:43 +01:00
Max Bruckner
3fe72cf2b8 fuzzing: afl.c: Fix printing usage 2017-03-02 23:57:05 +01:00
Max Bruckner
d8d0ae66d3 print_number: Fix incorrect output pointer 2017-03-02 23:57:01 +01:00
Max Bruckner
9d07917feb utf16_literal_to_utf8: Eliminate Duff's Device
This fixes -Wimplicit-fallthrough warnings with GCC7.
2017-03-02 13:46:31 +01:00
Max Bruckner
ad5abf4c5b Update unity with fixes for compiler warnings 2017-03-01 23:20:30 +01:00
Max Bruckner
2c45ad7816 Squashed 'tests/unity/' changes from 2988e98..1f52255
1f52255 Merge pull request #267 from FSMaxB/fix-wconversion
7bce0b4 Fix warning with ubsan and -Wconversion
b5da224 Merge pull request #266 from FSMaxB/fix-double-promotion
1bf22d3 Fix warnings with -Wdouble-promotion

git-subtree-dir: tests/unity
git-subtree-split: 1f522558a6c4577aa937341bf856ba3b1436768a
2017-03-01 23:20:30 +01:00
Max Bruckner
6405fd15e3 CMake: Set default visibility to hidden and dllexport on windows 2017-03-01 23:19:35 +01:00
Max Bruckner
b44c917be9 tests/common: use CJSON_PUBLIC 2017-03-01 23:16:19 +01:00
Max Bruckner
2d3520e0b9 Use own cJSON_bool boolean type in the header 2017-03-01 22:50:12 +01:00
Max Bruckner
2e118df0cd tests/common.h: Remove unused prototype 2017-03-01 22:47:45 +01:00
Max Bruckner
412f4f7d62 Use CJSON_PUBLIC for typecheck functions 2017-03-01 22:47:45 +01:00
Max Bruckner
0aea75fbda Merge pull request #123 from DaveGamble/trim-numbers
Remove traling zeroes when printing floating point numbers
2017-03-01 18:38:48 +01:00
Max Bruckner
0c0dd4a5b0 tests: test trim_trailing_zeroes 2017-03-01 18:29:01 +01:00
Max Bruckner
dd4cb5400f print_number: Remove unnecessary integer handling 2017-03-01 13:28:27 +01:00
Max Bruckner
1ea72f8260 print_number: Remove trailing zeroes (for doubles) 2017-03-01 13:22:32 +01:00
Max Bruckner
e78bc42362 print_number: Return buffer + offset instead of beginning of the number 2017-03-01 13:00:52 +01:00
Max Bruckner
6f271e511f print_number: Use sprintf's return value
This is used to update the buffer offset and determine success
2017-03-01 12:56:32 +01:00
Max Bruckner
bee069b4e7 Merge pull request #122 from DaveGamble/more-compiler-flags
Add more compiler flags
2017-03-01 12:30:12 +01:00
Max Bruckner
1e0bd24f2c Revert "unity: make it work with -Wconversion"
This reverts commit 12acc57967.
2017-03-01 11:57:07 +01:00
Max Bruckner
5cf56fa4fa Add -Wparentheses compile option 2017-03-01 11:57:07 +01:00
Max Bruckner
3f349a4258 Add -Wdouble-promotion compiler flag 2017-03-01 11:57:07 +01:00
Max Bruckner
40e3781e9b CMake: Disable -Werror for Unity 2017-03-01 11:57:07 +01:00
Max Bruckner
b056d7cb74 Add -Wcomma compiler flag 2017-03-01 11:57:06 +01:00
Max Bruckner
1f422b586a Squashed 'tests/unity/' changes from 1782bab..2988e98
2988e98 Merge pull request #262 from codehearts/patch-2
1732698 Fixed incorrect TEST_PROTECT explanation in readme
3817375 Merge pull request #260 from jeremyhannon/parseUnityFixtureOutputToJUnitFormat
9d5159f Merge pull request #261 from codehearts/patch-1
65ce727 Fixed typo for TEST_PROTECT in readme
4dc04d3 Enhance parseOutput.rb to support Unity fixture output

git-subtree-dir: tests/unity
git-subtree-split: 2988e980fbc2252fa4290b608517d4ae25cd9a46
2017-03-01 09:23:18 +01:00
Max Bruckner
899529e866 Update unity 2017-03-01 09:23:18 +01:00
Max Bruckner
2837aac23e Contributors: Add Mike Jerris 2017-02-28 23:04:29 +01:00
Max Bruckner
024f690289 Merge pull request #116 from mjerris/fschanges
add CJSON_DECLARE macros to support gcc visibility and windows dllexport
2017-02-27 21:51:55 +01:00
Mike Jerris
039b1cc653 add CJSON_PUBLIC macro to public functions to support visibility and dllimport/dllexport 2017-02-27 13:47:06 -06:00
Max Bruckner
2302f4f0b2 Merge pull request #120 from DaveGamble/typecheck-functions
Typecheck functions
2017-02-26 22:00:28 +01:00
Max Bruckner
c45dc12fd7 Tests for typecheck functions 2017-02-26 21:54:01 +01:00
Max Bruckner
ed8dc53699 cJSON_Utils: Use new typecheck functions 2017-02-26 21:26:34 +01:00
Max Bruckner
c26d53f0d7 Helper function to check the type of an item
This is necessary, because you can get it wrong if you do it manually.
(when you forget the & 0xFF in the comparison)
2017-02-26 14:30:50 +01:00
Max Bruckner
501046247d fix clang-sanitizer warnings 2017-02-21 15:08:36 +01:00
Max Bruckner
68cd0d4a11 cJSON.c: Pass allocation functions through internal functions
This is the first step in removing the global allocator functions. Every
internal function now only accesses its locally available set of
allocators.
2017-02-21 14:50:49 +01:00
Max Bruckner
56b819bfbc tests: test cJSON_GetObjectItem and cJSON_GetObjectItemCaseSensitive 2017-02-21 11:17:08 +01:00
Max Bruckner
605422c60a cJSON: New function cJSON_GetObjectItemCaseSensitive 2017-02-21 11:17:08 +01:00
Max Bruckner
cbbcc91498 tests: cJSON_ArrayForEach 2017-02-21 09:17:49 +01:00
Max Bruckner
b47d0e34ca cJSON_ArrayForEach: Fix handling of NULL pointers 2017-02-21 09:17:34 +01:00
Max Bruckner
bc12c69b54 Merge pull request #114 from DaveGamble/simplify-print
Simplify print functions
2017-02-20 23:09:06 +01:00
Max Bruckner
1d42c9bc60 print_object: simplify code 2017-02-20 23:07:24 +01:00
Max Bruckner
b71db93e03 print_object: rename variables 2017-02-20 23:07:24 +01:00
Max Bruckner
6d5a7c8c40 print_array: simplify code 2017-02-20 23:07:24 +01:00
Max Bruckner
8c1ed3ab82 update: rename to update_offset and change offset directly 2017-02-20 23:07:24 +01:00
Max Bruckner
f16dd7e028 print_array: rename variables 2017-02-20 23:07:24 +01:00
Max Bruckner
08770fc246 print_value: rename variables 2017-02-20 23:07:23 +01:00
Max Bruckner
0ca8587acc print_string_ptr: simplify code 2017-02-20 23:07:23 +01:00
Max Bruckner
88e38d042f tests: print_string: test if NULL is printed as empty string 2017-02-20 23:07:23 +01:00
Max Bruckner
6a746a230a print_string: Add more const 2017-02-20 23:07:23 +01:00
Max Bruckner
1e999352d3 print_string_ptr: rename variables 2017-02-20 23:07:23 +01:00
Max Bruckner
6815d96617 print_number: rename variables 2017-02-20 23:07:22 +01:00
Max Bruckner
61921498d0 print_number: remove special case for 0
Now that printbuffer is used for everything, it's not needed anymore.
2017-02-20 23:07:22 +01:00
Max Bruckner
4758d62fd4 Merge pull request #113 from DaveGamble/printbuffer-only
Always print with printbuffer
2017-02-20 23:06:58 +01:00
Max Bruckner
1bc1a9748a Merge pull request #112 from DaveGamble/print-tests
Add tests for print functions
2017-02-20 11:15:53 +01:00
Max Bruckner
de36476092 tests: print_value 2017-02-20 11:11:02 +01:00
Max Bruckner
983a4cd286 tests: parse_objects: Fix name of test 2017-02-20 11:11:01 +01:00
Max Bruckner
b6abef94ff tests: print_object 2017-02-20 11:11:01 +01:00
Max Bruckner
3d66766231 tests: print_array 2017-02-20 11:11:01 +01:00
Max Bruckner
924122904e tests: print_number 2017-02-20 11:11:01 +01:00
Max Bruckner
87691a86e5 cJSON_SetNumberValue: Fix compiler warning with -Waddress 2017-02-20 11:11:01 +01:00
Max Bruckner
8aa324fdc8 tests: print_string 2017-02-20 11:11:01 +01:00
Max Bruckner
3c4d309f62 ensure: Don't accept empty printbuffers anymore 2017-02-19 04:20:21 +01:00
Max Bruckner
9bf531ca05 Remove printing without buffer 2017-02-19 04:16:57 +01:00
Max Bruckner
80354bdb06 cJSON_Print: Use printbuffer 2017-02-19 04:03:02 +01:00
Max Bruckner
fe2e0956ad Merge pull request #111 from DaveGamble/fuzzing
partial build system integration of the afl fuzzing tool
2017-02-19 02:44:28 +01:00
Max Bruckner
cf71f3d627 fuzzing: script to prepare linux kernel for afl 2017-02-18 13:18:09 +01:00
Max Bruckner
da551c753f fuzzing: Speed up afl using persistent mode (in proccess fuzzing) 2017-02-18 13:18:09 +01:00
Max Bruckner
ae4681b787 fuzzing: use llvm source code instrumentation 2017-02-18 13:18:08 +01:00
Max Bruckner
c5a09a32a9 fuzzing: Fuzz different print methods
This is achieved by encoding the type of function used in the first two
bytes.

First byte:
b: buffered

Second byte:
f: formatted
2017-02-18 13:18:08 +01:00
Max Bruckner
4785070ad3 fuzzing: Fuzz printing as well.
With one big limitation: It can only be fuzzed with what has been
parsed by the library beforehand.
2017-02-18 12:52:16 +01:00
Max Bruckner
0e0cd5bae5 CMake: Add ENABLE_FUZZING and "afl" target 2017-02-18 12:52:16 +01:00
Max Bruckner
44512f643e Merge pull request #110 from DaveGamble/ensure-improvements
ensure improvements
2017-02-18 12:18:18 +01:00
Max Bruckner
331c18d09a ensure: only memcopy what's necessary
We don't need to copy the entire printbuffer, only the part that is
used.
2017-02-18 12:07:17 +01:00
Max Bruckner
4fff92140e ensure: use realloc if possible 2017-02-18 12:07:17 +01:00
Max Bruckner
fc1d4b07df ensure: if printbuffer is null: cJSON_malloc
This allowed for the removal of a lot of if (p) checks.
2017-02-18 11:35:59 +01:00
Max Bruckner
bd073343fa rename skip -> skip_whitespace 2017-02-17 19:37:31 +01:00
Max Bruckner
7c722dca5f CMake: Add target "check" that builds and runs tests 2017-02-17 13:59:26 +01:00
45 changed files with 2249 additions and 946 deletions

54
.github/CONTRIBUTING.md vendored Normal file
View File

@@ -0,0 +1,54 @@
Contribution Guidelines
=======================
Contributions to cJSON are welcome. If you find a bug or want to improve cJSON in another way, pull requests are appreciated.
For bigger changes, in order to avoid wasted effort, please open an issue to discuss the technical details before creating a pull request.
The further sections explain the process in more detail and provides some guidelines on how contributions should look like.
Branches
--------
There are two branches to be aware of, the `master` and the `develop` branch. The `master` branch is reserved for the latest release, so only make pull requests to the `master` branch for small bug- or security fixes (these are usually just a few lines). In all other cases, please make a pull request to the `develop` branch.
Coding Style
------------
The coding style has been discussed in [#24](https://github.com/DaveGamble/cJSON/issues/24). The basics are:
* Use 4 tabs for indentation
* No oneliners (conditions, loops, variable declarations ...)
* Always use parenthesis for control structures
* Don't implicitly rely on operator precedence, use round brackets in expressions. e.g. `(a > b) && (c < d)` instead of `a>b && c<d`
* opening curly braces start in the next line
* use spaces around operators
* lines should not have trailing whitespace
* use spaces between function parameters
* use pronouncable variable names, not just a combination of letters
Example:
```c
/* calculate the new length of the string in a printbuffer and update the offset */
static void update_offset(printbuffer * const buffer)
{
const unsigned char *buffer_pointer = NULL;
if ((buffer == NULL) || (buffer->buffer == NULL))
{
return;
}
buffer_pointer = buffer->buffer + buffer->offset;
buffer->offset += strlen((const char*)buffer_pointer);
}
```
Unit Tests
----------
cJSON uses the [Unity](https://github.com/ThrowTheSwitch/Unity) library for unit tests. The tests are located in the `tests` directory. In order to add a new test, either add it to one of the existing files (if it fits) or add a new C file for the test. That new file has to be added to the list of tests in `tests/CMakeLists.txt`.
All new features have to be covered by unit tests.
Other Notes
-----------
* Internal functions are to be declared static.
* Wrap the return type of external function in the `CJSON_PUBLIC` macro.

View File

@@ -1,15 +1,15 @@
set(CMAKE_LEGACY_CYGWIN_WIN32 0) set(CMAKE_LEGACY_CYGWIN_WIN32 0)
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 2.8)
subdirs(tests) subdirs(tests fuzzing)
include(GNUInstallDirs) include(GNUInstallDirs)
project(cJSON C) project(cJSON C)
set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MAJOR 1)
set(PROJECT_VERSION_MINOR 3) set(PROJECT_VERSION_MINOR 4)
set(PROJECT_VERSION_PATCH 2) set(PROJECT_VERSION_PATCH 0)
set(CJSON_VERSION_SO 1) set(CJSON_VERSION_SO 1)
set(CJSON_UTILS_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1)
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
@@ -40,6 +40,9 @@ if (ENABLE_CUSTOM_COMPILER_FLAGS)
-Wconversion -Wconversion
-Wc++-compat -Wc++-compat
-fstack-protector-strong -fstack-protector-strong
-Wcomma
-Wdouble-promotion
-Wparentheses
) )
endif() endif()
@@ -58,6 +61,16 @@ if (ENABLE_SANITIZERS)
) )
endif() endif()
option(ENABLE_PUBLIC_SYMBOLS "Export library symbols." On)
if (ENABLE_PUBLIC_SYMBOLS)
list(APPEND custom_compiler_flags -fvisibility=hidden)
add_definitions(-DCJSON_EXPORT_SYMBOLS -DCJSON_API_VISIBILITY)
endif()
option(ENABLE_HIDDEN_SYMBOLS "Hide library symbols." Off)
if (ENABLE_HIDDEN_SYMBOLS)
add_definitions(-DCJSON_HIDE_SYMBOLS -UCJSON_API_VISIBILITY)
endif()
# apply custom compiler flags # apply custom compiler flags
foreach(compiler_flag ${custom_compiler_flags}) foreach(compiler_flag ${custom_compiler_flags})
#remove problematic characters #remove problematic characters

View File

@@ -21,6 +21,7 @@ Contributors
* [Linus Wallgren](https://github.com/ecksun) * [Linus Wallgren](https://github.com/ecksun)
* [Max Bruckner](https://github.com/FSMaxB) * [Max Bruckner](https://github.com/FSMaxB)
* Mike Pontillo * Mike Pontillo
* [Mike Jerris](https://github.com/mjerris)
* Paulo Antonio Alvarez * Paulo Antonio Alvarez
* [Rafael Leal Dias](https://github.com/rafaeldias) * [Rafael Leal Dias](https://github.com/rafaeldias)
* [Rod Vagg](https://github.com/rvagg) * [Rod Vagg](https://github.com/rvagg)

View File

@@ -10,7 +10,7 @@ UTILS_TEST_SRC = cJSON.c cJSON_Utils.c test_utils.c
LDLIBS = -lm LDLIBS = -lm
LIBVERSION = 1.3.2 LIBVERSION = 1.4.0
CJSON_SOVERSION = 1 CJSON_SOVERSION = 1
UTILS_SOVERSION = 1 UTILS_SOVERSION = 1

1520
cJSON.c

File diff suppressed because it is too large Load Diff

148
cJSON.h
View File

@@ -30,11 +30,8 @@ extern "C"
/* project version */ /* project version */
#define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MAJOR 1
#define CJSON_VERSION_MINOR 3 #define CJSON_VERSION_MINOR 4
#define CJSON_VERSION_PATCH 2 #define CJSON_VERSION_PATCH 0
/* returns the version of cJSON as a string */
extern const char* cJSON_Version(void);
#include <stddef.h> #include <stddef.h>
@@ -81,84 +78,139 @@ typedef struct cJSON_Hooks
void (*free_fn)(void *ptr); void (*free_fn)(void *ptr);
} cJSON_Hooks; } cJSON_Hooks;
typedef int cJSON_bool;
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
#define __WINDOWS__
#endif
#ifdef __WINDOWS__
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options:
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols
For *nix builds that support visibility attribute, you can define similar behavior by
setting default visibility to hidden by adding
-fvisibility=hidden (for gcc)
or
-xldscope=hidden (for sun cc)
to CFLAGS
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
*/
#if defined(CJSON_HIDE_SYMBOLS)
#define CJSON_PUBLIC(type) type __stdcall
#elif defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall
#else
#define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall
#endif
#else /* !WIN32 */
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
#else
#define CJSON_PUBLIC(type) type
#endif
#endif
/* returns the version of cJSON as a string */
CJSON_PUBLIC(const char*) cJSON_Version(void);
/* Supply malloc, realloc and free functions to cJSON */ /* Supply malloc, realloc and free functions to cJSON */
extern void cJSON_InitHooks(cJSON_Hooks* hooks); CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ /* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
extern cJSON *cJSON_Parse(const char *value); CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
extern char *cJSON_Print(const cJSON *item); CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
extern char *cJSON_PrintUnformatted(const cJSON *item); CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
extern char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, int fmt); CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
/* Render a cJSON entity to text using a buffer already allocated in memory with length buf_len. Returns 1 on success and 0 on failure. */ /* Render a cJSON entity to text using a buffer already allocated in memory with length buf_len. Returns 1 on success and 0 on failure. */
extern int cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const int fmt); CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt);
/* Delete a cJSON entity and all subentities. */ /* Delete a cJSON entity and all subentities. */
extern void cJSON_Delete(cJSON *c); CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
/* Returns the number of items in an array (or object). */ /* Returns the number of items in an array (or object). */
extern int cJSON_GetArraySize(const cJSON *array); CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
extern cJSON *cJSON_GetArrayItem(const cJSON *array, int item); CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int item);
/* Get item "string" from object. Case insensitive. */ /* Get item "string" from object. Case insensitive. */
extern cJSON *cJSON_GetObjectItem(const cJSON *object, const char *string); CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON *object, const char *string);
extern int cJSON_HasObjectItem(const cJSON *object, const char *string); CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON *object, const char *string);
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
extern const char *cJSON_GetErrorPtr(void); CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
/* These functions check the type of an item */
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
/* These calls create a cJSON item of the appropriate type. */ /* These calls create a cJSON item of the appropriate type. */
extern cJSON *cJSON_CreateNull(void); CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
extern cJSON *cJSON_CreateTrue(void); CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
extern cJSON *cJSON_CreateFalse(void); CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
extern cJSON *cJSON_CreateBool(int b); CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
extern cJSON *cJSON_CreateNumber(double num); CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
extern cJSON *cJSON_CreateString(const char *string); CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
/* raw json */ /* raw json */
extern cJSON *cJSON_CreateRaw(const char *raw); CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
extern cJSON *cJSON_CreateArray(void); CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
extern cJSON *cJSON_CreateObject(void); CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
/* These utilities create an Array of count items. */ /* These utilities create an Array of count items. */
extern cJSON *cJSON_CreateIntArray(const int *numbers, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
extern cJSON *cJSON_CreateFloatArray(const float *numbers, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
extern cJSON *cJSON_CreateDoubleArray(const double *numbers, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
extern cJSON *cJSON_CreateStringArray(const char **strings, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count);
/* Append item to the specified array/object. */ /* Append item to the specified array/object. */
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item);
extern void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
* writing to `item->string` */ * writing to `item->string` */
extern void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
extern void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
/* Remove/Detatch items from Arrays/Objects. */ /* Remove/Detatch items from Arrays/Objects. */
extern cJSON *cJSON_DetachItemFromArray(cJSON *array, int which); CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
extern void cJSON_DeleteItemFromArray(cJSON *array, int which); CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
extern cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string); CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
extern void cJSON_DeleteItemFromObject(cJSON *object, const char *string); CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
/* Update array items. */ /* Update array items. */
extern void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
extern void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
/* Duplicate a cJSON item */ /* Duplicate a cJSON item */
extern cJSON *cJSON_Duplicate(const cJSON *item, int recurse); CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
need to be released. With recurse!=0, it will duplicate any children connected to the item. need to be released. With recurse!=0, it will duplicate any children connected to the item.
The item->next and ->prev pointers are always zero on return from Duplicate. */ The item->next and ->prev pointers are always zero on return from Duplicate. */
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error. If not, then cJSON_GetErrorPtr() does the job. */ /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error. If not, then cJSON_GetErrorPtr() does the job. */
extern cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated); CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
extern void cJSON_Minify(char *json); CJSON_PUBLIC(void) cJSON_Minify(char *json);
/* Macros for creating things quickly. */ /* Macros for creating things quickly. */
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
@@ -172,11 +224,11 @@ extern void cJSON_Minify(char *json);
/* When assigning an integer value, it needs to be propagated to valuedouble too. */ /* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) #define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
/* helper for the cJSON_SetNumberValue macro */ /* helper for the cJSON_SetNumberValue macro */
extern double cJSON_SetNumberHelper(cJSON *object, double number); CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
#define cJSON_SetNumberValue(object, number) ((object) ? cJSON_SetNumberHelper(object, (double)number) : (number)) #define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
/* Macro for iterating over an array */ /* Macro for iterating over an array */
#define cJSON_ArrayForEach(pos, head) for(pos = (head)->child; pos != NULL; pos = pos->next) #define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -1,8 +1,10 @@
#pragma GCC visibility push(default)
#include <ctype.h> #include <ctype.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <limits.h> #include <limits.h>
#pragma GCC visibility pop
#include "cJSON_Utils.h" #include "cJSON_Utils.h"
@@ -31,7 +33,7 @@ static int cJSONUtils_strcasecmp(const unsigned char *s1, const unsigned char *s
{ {
return 1; return 1;
} }
for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) for(; tolower(*s1) == tolower(*s2); (void)++s1, ++s2)
{ {
if(*s1 == 0) if(*s1 == 0)
{ {
@@ -49,7 +51,7 @@ static int cJSONUtils_Pstrcasecmp(const unsigned char *a, const unsigned char *e
{ {
return (a == e) ? 0 : 1; /* both NULL? */ return (a == e) ? 0 : 1; /* both NULL? */
} }
for (; *a && *e && (*e != '/'); a++, e++) /* compare until next '/' */ for (; *a && *e && (*e != '/'); (void)a++, e++) /* compare until next '/' */
{ {
if (*e == '~') if (*e == '~')
{ {
@@ -81,7 +83,7 @@ static int cJSONUtils_Pstrcasecmp(const unsigned char *a, const unsigned char *e
static size_t cJSONUtils_PointerEncodedstrlen(const unsigned char *s) static size_t cJSONUtils_PointerEncodedstrlen(const unsigned char *s)
{ {
size_t l = 0; size_t l = 0;
for (; *s; s++, l++) for (; *s; (void)s++, l++)
{ {
if ((*s == '~') || (*s == '/')) if ((*s == '~') || (*s == '/'))
{ {
@@ -115,9 +117,8 @@ static void cJSONUtils_PointerEncodedstrcpy(unsigned char *d, const unsigned cha
*d = '\0'; *d = '\0';
} }
char *cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target) CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target)
{ {
int type = object->type;
size_t c = 0; size_t c = 0;
cJSON *obj = 0; cJSON *obj = 0;
@@ -128,12 +129,12 @@ char *cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target)
} }
/* recursively search all children of the object */ /* recursively search all children of the object */
for (obj = object->child; obj; obj = obj->next, c++) for (obj = object->child; obj; (void)(obj = obj->next), c++)
{ {
unsigned char *found = (unsigned char*)cJSONUtils_FindPointerFromObjectTo(obj, target); unsigned char *found = (unsigned char*)cJSONUtils_FindPointerFromObjectTo(obj, target);
if (found) if (found)
{ {
if ((type & 0xFF) == cJSON_Array) if (cJSON_IsArray(object))
{ {
/* reserve enough memory for a 64 bit integer + '/' and '\0' */ /* reserve enough memory for a 64 bit integer + '/' and '\0' */
unsigned char *ret = (unsigned char*)malloc(strlen((char*)found) + 23); unsigned char *ret = (unsigned char*)malloc(strlen((char*)found) + 23);
@@ -150,7 +151,7 @@ char *cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target)
return (char*)ret; return (char*)ret;
} }
else if ((type & 0xFF) == cJSON_Object) else if (cJSON_IsObject(object))
{ {
unsigned char *ret = (unsigned char*)malloc(strlen((char*)found) + cJSONUtils_PointerEncodedstrlen((unsigned char*)obj->string) + 2); unsigned char *ret = (unsigned char*)malloc(strlen((char*)found) + cJSONUtils_PointerEncodedstrlen((unsigned char*)obj->string) + 2);
*ret = '/'; *ret = '/';
@@ -171,12 +172,12 @@ char *cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target)
return NULL; return NULL;
} }
cJSON *cJSONUtils_GetPointer(cJSON *object, const char *pointer) CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON *object, const char *pointer)
{ {
/* follow path of the pointer */ /* follow path of the pointer */
while ((*pointer++ == '/') && object) while ((*pointer++ == '/') && object)
{ {
if ((object->type & 0xFF) == cJSON_Array) if (cJSON_IsArray(object))
{ {
size_t which = 0; size_t which = 0;
/* parse array index */ /* parse array index */
@@ -195,7 +196,7 @@ cJSON *cJSONUtils_GetPointer(cJSON *object, const char *pointer)
} }
object = cJSON_GetArrayItem(object, (int)which); object = cJSON_GetArrayItem(object, (int)which);
} }
else if ((object->type & 0xFF) == cJSON_Object) else if (cJSON_IsObject(object))
{ {
object = object->child; object = object->child;
/* GetObjectItem. */ /* GetObjectItem. */
@@ -227,7 +228,7 @@ static void cJSONUtils_InplaceDecodePointerString(unsigned char *string)
return; return;
} }
for (; *string; s2++, string++) for (; *string; (void)s2++, string++)
{ {
*s2 = (*string != '~') *s2 = (*string != '~')
? (*string) ? (*string)
@@ -269,11 +270,11 @@ static cJSON *cJSONUtils_PatchDetach(cJSON *object, const unsigned char *path)
/* Couldn't find object to remove child from. */ /* Couldn't find object to remove child from. */
ret = NULL; ret = NULL;
} }
else if ((parent->type & 0xFF) == cJSON_Array) else if (cJSON_IsArray(parent))
{ {
ret = cJSON_DetachItemFromArray(parent, atoi((char*)childptr)); ret = cJSON_DetachItemFromArray(parent, atoi((char*)childptr));
} }
else if ((parent->type & 0xFF) == cJSON_Object) else if (cJSON_IsObject(parent))
{ {
ret = cJSON_DetachItemFromObject(parent, (char*)childptr); ret = cJSON_DetachItemFromObject(parent, (char*)childptr);
} }
@@ -299,7 +300,7 @@ static int cJSONUtils_Compare(cJSON *a, cJSON *b)
/* string mismatch. */ /* string mismatch. */
return (strcmp(a->valuestring, b->valuestring) != 0) ? -3 : 0; return (strcmp(a->valuestring, b->valuestring) != 0) ? -3 : 0;
case cJSON_Array: case cJSON_Array:
for (a = a->child, b = b->child; a && b; a = a->next, b = b->next) for ((void)(a = a->child), b = b->child; a && b; (void)(a = a->next), b = b->next)
{ {
int err = cJSONUtils_Compare(a, b); int err = cJSONUtils_Compare(a, b);
if (err) if (err)
@@ -474,7 +475,7 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch)
cJSON_Delete(value); cJSON_Delete(value);
return 9; return 9;
} }
else if ((parent->type & 0xFF) == cJSON_Array) else if (cJSON_IsArray(parent))
{ {
if (!strcmp((char*)childptr, "-")) if (!strcmp((char*)childptr, "-"))
{ {
@@ -485,7 +486,7 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch)
cJSON_InsertItemInArray(parent, atoi((char*)childptr), value); cJSON_InsertItemInArray(parent, atoi((char*)childptr), value);
} }
} }
else if ((parent->type & 0xFF) == cJSON_Object) else if (cJSON_IsObject(parent))
{ {
cJSON_DeleteItemFromObject(parent, (char*)childptr); cJSON_DeleteItemFromObject(parent, (char*)childptr);
cJSON_AddItemToObject(parent, (char*)childptr, value); cJSON_AddItemToObject(parent, (char*)childptr, value);
@@ -499,7 +500,7 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch)
return 0; return 0;
} }
int cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches) CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches)
{ {
int err = 0; int err = 0;
@@ -508,7 +509,7 @@ int cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches)
return 1; return 1;
} }
if ((patches->type & 0xFF) != cJSON_Array) if (cJSON_IsArray(patches))
{ {
/* malformed patches. */ /* malformed patches. */
return 1; return 1;
@@ -551,7 +552,7 @@ static void cJSONUtils_GeneratePatch(cJSON *patches, const unsigned char *op, co
cJSON_AddItemToArray(patches, patch); cJSON_AddItemToArray(patches, patch);
} }
void cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, cJSON *val) CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, cJSON *val)
{ {
cJSONUtils_GeneratePatch(array, (const unsigned char*)op, (const unsigned char*)path, 0, val); cJSONUtils_GeneratePatch(array, (const unsigned char*)op, (const unsigned char*)path, 0, val);
} }
@@ -590,7 +591,7 @@ static void cJSONUtils_CompareToPatch(cJSON *patches, const unsigned char *path,
size_t c = 0; size_t c = 0;
unsigned char *newpath = (unsigned char*)malloc(strlen((const char*)path) + 23); /* Allow space for 64bit int. */ unsigned char *newpath = (unsigned char*)malloc(strlen((const char*)path) + 23); /* Allow space for 64bit int. */
/* generate patches for all array elements that exist in "from" and "to" */ /* generate patches for all array elements that exist in "from" and "to" */
for (c = 0, from = from->child, to = to->child; from && to; from = from->next, to = to->next, c++) for ((void)(c = 0), (void)(from = from->child), to = to->child; from && to; (void)(from = from->next), (void)(to = to->next), c++)
{ {
/* check if conversion to unsigned long is valid /* check if conversion to unsigned long is valid
* This should be eliminated at compile time by dead code elimination * This should be eliminated at compile time by dead code elimination
@@ -604,7 +605,7 @@ static void cJSONUtils_CompareToPatch(cJSON *patches, const unsigned char *path,
cJSONUtils_CompareToPatch(patches, newpath, from, to); cJSONUtils_CompareToPatch(patches, newpath, from, to);
} }
/* remove leftover elements from 'from' that are not in 'to' */ /* remove leftover elements from 'from' that are not in 'to' */
for (; from; from = from->next, c++) for (; from; (void)(from = from->next), c++)
{ {
/* check if conversion to unsigned long is valid /* check if conversion to unsigned long is valid
* This should be eliminated at compile time by dead code elimination * This should be eliminated at compile time by dead code elimination
@@ -618,7 +619,7 @@ static void cJSONUtils_CompareToPatch(cJSON *patches, const unsigned char *path,
cJSONUtils_GeneratePatch(patches, (const unsigned char*)"remove", path, newpath, 0); cJSONUtils_GeneratePatch(patches, (const unsigned char*)"remove", path, newpath, 0);
} }
/* add new elements in 'to' that were not in 'from' */ /* add new elements in 'to' that were not in 'from' */
for (; to; to = to->next, c++) for (; to; (void)(to = to->next), c++)
{ {
cJSONUtils_GeneratePatch(patches, (const unsigned char*)"add", path, (const unsigned char*)"-", to); cJSONUtils_GeneratePatch(patches, (const unsigned char*)"add", path, (const unsigned char*)"-", to);
} }
@@ -671,7 +672,7 @@ static void cJSONUtils_CompareToPatch(cJSON *patches, const unsigned char *path,
} }
} }
cJSON* cJSONUtils_GeneratePatches(cJSON *from, cJSON *to) CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON *from, cJSON *to)
{ {
cJSON *patches = cJSON_CreateArray(); cJSON *patches = cJSON_CreateArray();
cJSONUtils_CompareToPatch(patches, (const unsigned char*)"", from, to); cJSONUtils_CompareToPatch(patches, (const unsigned char*)"", from, to);
@@ -786,21 +787,21 @@ static cJSON *cJSONUtils_SortList(cJSON *list)
return list; return list;
} }
void cJSONUtils_SortObject(cJSON *object) CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON *object)
{ {
object->child = cJSONUtils_SortList(object->child); object->child = cJSONUtils_SortList(object->child);
} }
cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch) CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, cJSON *patch)
{ {
if (!patch || ((patch->type & 0xFF) != cJSON_Object)) if (!cJSON_IsObject(patch))
{ {
/* scalar value, array or NULL, just duplicate */ /* scalar value, array or NULL, just duplicate */
cJSON_Delete(target); cJSON_Delete(target);
return cJSON_Duplicate(patch, 1); return cJSON_Duplicate(patch, 1);
} }
if (!target || ((target->type & 0xFF) != cJSON_Object)) if (!cJSON_IsObject(target))
{ {
cJSON_Delete(target); cJSON_Delete(target);
target = cJSON_CreateObject(); target = cJSON_CreateObject();
@@ -809,7 +810,7 @@ cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch)
patch = patch->child; patch = patch->child;
while (patch) while (patch)
{ {
if ((patch->type & 0xFF) == cJSON_NULL) if (cJSON_IsNull(patch))
{ {
/* NULL is the indicator to remove a value, see RFC7396 */ /* NULL is the indicator to remove a value, see RFC7396 */
cJSON_DeleteItemFromObject(target, patch->string); cJSON_DeleteItemFromObject(target, patch->string);
@@ -824,7 +825,7 @@ cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch)
return target; return target;
} }
cJSON *cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to) CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to)
{ {
cJSON *patch = NULL; cJSON *patch = NULL;
if (!to) if (!to)
@@ -832,7 +833,7 @@ cJSON *cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to)
/* patch to delete everything */ /* patch to delete everything */
return cJSON_CreateNull(); return cJSON_CreateNull();
} }
if (((to->type & 0xFF) != cJSON_Object) || !from || ((from->type & 0xFF) != cJSON_Object)) if (!cJSON_IsObject(to) || !cJSON_IsObject(from))
{ {
return cJSON_Duplicate(to, 1); return cJSON_Duplicate(to, 1);
} }

View File

@@ -1,14 +1,14 @@
#include "cJSON.h" #include "cJSON.h"
/* Implement RFC6901 (https://tools.ietf.org/html/rfc6901) JSON Pointer spec. */ /* Implement RFC6901 (https://tools.ietf.org/html/rfc6901) JSON Pointer spec. */
cJSON *cJSONUtils_GetPointer(cJSON *object, const char *pointer); CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON *object, const char *pointer);
/* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */ /* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */
cJSON* cJSONUtils_GeneratePatches(cJSON *from, cJSON *to); CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON *from, cJSON *to);
/* Utility for generating patch array entries. */ /* Utility for generating patch array entries. */
void cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, cJSON *val); CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, cJSON *val);
/* Returns 0 for success. */ /* Returns 0 for success. */
int cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches); CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches);
/* /*
// Note that ApplyPatches is NOT atomic on failure. To implement an atomic ApplyPatches, use: // Note that ApplyPatches is NOT atomic on failure. To implement an atomic ApplyPatches, use:
@@ -33,12 +33,12 @@ int cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches);
/* Implement RFC7386 (https://tools.ietf.org/html/rfc7396) JSON Merge Patch spec. */ /* Implement RFC7386 (https://tools.ietf.org/html/rfc7396) JSON Merge Patch spec. */
/* target will be modified by patch. return value is new ptr for target. */ /* target will be modified by patch. return value is new ptr for target. */
cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch); CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, cJSON *patch);
/* generates a patch to move from -> to */ /* generates a patch to move from -> to */
cJSON *cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to); CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to);
/* Given a root object and a target object, construct a pointer from one to the other. */ /* Given a root object and a target object, construct a pointer from one to the other. */
char *cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target); CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target);
/* Sorts the members of the object into alphabetical order. */ /* Sorts the members of the object into alphabetical order. */
void cJSONUtils_SortObject(cJSON *object); CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON *object);

1
fuzzing/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
afl-build

28
fuzzing/CMakeLists.txt Normal file
View File

@@ -0,0 +1,28 @@
option(ENABLE_FUZZING "Create executables and targets for fuzzing cJSON with afl." Off)
if (ENABLE_FUZZING)
find_program(AFL_FUZZ afl-fuzz)
if ("${AFL_FUZZ}" MATCHES "AFL_FUZZ-NOTFOUND")
message(FATAL_ERROR "Couldn't find afl-fuzz.")
endif()
add_executable(afl-main afl.c)
target_link_libraries(afl-main "${CJSON_LIB}")
if (NOT ENABLE_SANITIZERS)
message(FATAL_ERROR "Enable sanitizers with -DENABLE_SANITIZERS=On to do fuzzing.")
endif()
option(ENABLE_FUZZING_PRINT "Fuzz printing functions together with parser." On)
set(fuzz_print_parameter "no")
if (ENABLE_FUZZING_PRINT)
set(fuzz_print_parameter "yes")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error")
add_custom_target(afl
COMMAND "${AFL_FUZZ}" -i "${CMAKE_CURRENT_SOURCE_DIR}/inputs" -o "${CMAKE_CURRENT_BINARY_DIR}/findings" -x "${CMAKE_CURRENT_SOURCE_DIR}/json.dict" -- "${CMAKE_CURRENT_BINARY_DIR}/afl-main" "@@" "${fuzz_print_parameter}"
DEPENDS afl-main)
endif()

5
fuzzing/afl-prepare-linux.sh Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
set -x
echo core | sudo tee /proc/sys/kernel/core_pattern
echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

176
fuzzing/afl.c Normal file
View File

@@ -0,0 +1,176 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../cJSON.h"
static char *read_file(const char *filename)
{
FILE *file = NULL;
long length = 0;
char *content = NULL;
size_t read_chars = 0;
/* open in read binary mode */
file = fopen(filename, "rb");
if (file == NULL)
{
goto cleanup;
}
/* get the length */
if (fseek(file, 0, SEEK_END) != 0)
{
goto cleanup;
}
length = ftell(file);
if (length < 0)
{
goto cleanup;
}
if (fseek(file, 0, SEEK_SET) != 0)
{
goto cleanup;
}
/* allocate content buffer */
content = (char*)malloc((size_t)length + sizeof('\0'));
if (content == NULL)
{
goto cleanup;
}
/* read the file into memory */
read_chars = fread(content, sizeof(char), (size_t)length, file);
if ((long)read_chars != length)
{
free(content);
content = NULL;
goto cleanup;
}
content[read_chars] = '\0';
cleanup:
if (file != NULL)
{
fclose(file);
}
return content;
}
int main(int argc, char** argv)
{
const char *filename = NULL;
cJSON *item = NULL;
char *json = NULL;
int status = EXIT_FAILURE;
char *printed_json = NULL;
if ((argc < 2) || (argc > 3))
{
printf("Usage:\n");
printf("%s input_file [enable_printing]\n", argv[0]);
printf("\t input_file: file containing the test data\n");
printf("\t enable_printing: print after parsing, 'yes' or 'no', defaults to 'no'\n");
goto cleanup;
}
filename = argv[1];
#if __AFL_HAVE_MANUAL_CONTROL
while (__AFL_LOOP(1000))
{
#endif
status = EXIT_SUCCESS;
json = read_file(filename);
if ((json == NULL) || (json[0] == '\0') || (json[1] == '\0'))
{
status = EXIT_FAILURE;
goto cleanup;
}
item = cJSON_Parse(json + 2);
if (item == NULL)
{
goto cleanup;
}
if ((argc == 3) && (strncmp(argv[2], "yes", 3) == 0))
{
int do_format = 0;
if (json[1] == 'f')
{
do_format = 1;
}
if (json[0] == 'b')
{
/* buffered printing */
printed_json = cJSON_PrintBuffered(item, 1, do_format);
}
else
{
/* unbuffered printing */
if (do_format)
{
printed_json = cJSON_Print(item);
}
else
{
printed_json = cJSON_PrintUnformatted(item);
}
}
if (printed_json == NULL)
{
status = EXIT_FAILURE;
goto cleanup;
}
printf("%s\n", printed_json);
}
cleanup:
if (item != NULL)
{
cJSON_Delete(item);
item = NULL;
}
if (json != NULL)
{
free(json);
json = NULL;
}
if (printed_json != NULL)
{
free(printed_json);
printed_json = NULL;
}
#if __AFL_HAVE_MANUAL_CONTROL
}
#endif
return status;
}

9
fuzzing/afl.sh Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/bash
mkdir -p afl-build || exit 1
cd afl-build || exit 1
#cleanup
rm -r -- *
CC=afl-clang-fast cmake ../.. -DENABLE_FUZZING=On -DENABLE_SANITIZERS=On -DBUILD_SHARED_LIBS=Off
make afl

22
fuzzing/inputs/test1 Normal file
View File

@@ -0,0 +1,22 @@
bf{
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
}

1
fuzzing/inputs/test10 Normal file
View File

@@ -0,0 +1 @@
bf["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]

8
fuzzing/inputs/test11 Normal file
View File

@@ -0,0 +1,8 @@
bf{
"name": "Jack (\"Bee\") Nimble",
"format": {"type": "rect",
"width": 1920,
"height": 1080,
"interlace": false,"frame rate": 24
}
}

11
fuzzing/inputs/test2 Normal file
View File

@@ -0,0 +1,11 @@
bf{"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{"value": "New", "onclick": "CreateNewDoc()"},
{"value": "Open", "onclick": "OpenDoc()"},
{"value": "Close", "onclick": "CloseDoc()"}
]
}
}}

26
fuzzing/inputs/test3 Normal file
View File

@@ -0,0 +1,26 @@
bf{"widget": {
"debug": "on",
"window": {
"title": "Sample Konfabulator Widget",
"name": "main_window",
"width": 500,
"height": 500
},
"image": {
"src": "Images/Sun.png",
"name": "sun1",
"hOffset": 250,
"vOffset": 250,
"alignment": "center"
},
"text": {
"data": "Click Here",
"size": 36,
"style": "bold",
"name": "text1",
"hOffset": 250,
"vOffset": 100,
"alignment": "center",
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
}
}}

26
fuzzing/inputs/test3.bu Normal file
View File

@@ -0,0 +1,26 @@
bu{"widget": {
"debug": "on",
"window": {
"title": "Sample Konfabulator Widget",
"name": "main_window",
"width": 500,
"height": 500
},
"image": {
"src": "Images/Sun.png",
"name": "sun1",
"hOffset": 250,
"vOffset": 250,
"alignment": "center"
},
"text": {
"data": "Click Here",
"size": 36,
"style": "bold",
"name": "text1",
"hOffset": 250,
"vOffset": 100,
"alignment": "center",
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
}
}}

26
fuzzing/inputs/test3.uf Normal file
View File

@@ -0,0 +1,26 @@
uf{"widget": {
"debug": "on",
"window": {
"title": "Sample Konfabulator Widget",
"name": "main_window",
"width": 500,
"height": 500
},
"image": {
"src": "Images/Sun.png",
"name": "sun1",
"hOffset": 250,
"vOffset": 250,
"alignment": "center"
},
"text": {
"data": "Click Here",
"size": 36,
"style": "bold",
"name": "text1",
"hOffset": 250,
"vOffset": 100,
"alignment": "center",
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
}
}}

26
fuzzing/inputs/test3.uu Normal file
View File

@@ -0,0 +1,26 @@
uu{"widget": {
"debug": "on",
"window": {
"title": "Sample Konfabulator Widget",
"name": "main_window",
"width": 500,
"height": 500
},
"image": {
"src": "Images/Sun.png",
"name": "sun1",
"hOffset": 250,
"vOffset": 250,
"alignment": "center"
},
"text": {
"data": "Click Here",
"size": 36,
"style": "bold",
"name": "text1",
"hOffset": 250,
"vOffset": 100,
"alignment": "center",
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
}
}}

88
fuzzing/inputs/test4 Normal file
View File

@@ -0,0 +1,88 @@
bf{"web-app": {
"servlet": [
{
"servlet-name": "cofaxCDS",
"servlet-class": "org.cofax.cds.CDSServlet",
"init-param": {
"configGlossary:installationAt": "Philadelphia, PA",
"configGlossary:adminEmail": "ksm@pobox.com",
"configGlossary:poweredBy": "Cofax",
"configGlossary:poweredByIcon": "/images/cofax.gif",
"configGlossary:staticPath": "/content/static",
"templateProcessorClass": "org.cofax.WysiwygTemplate",
"templateLoaderClass": "org.cofax.FilesTemplateLoader",
"templatePath": "templates",
"templateOverridePath": "",
"defaultListTemplate": "listTemplate.htm",
"defaultFileTemplate": "articleTemplate.htm",
"useJSP": false,
"jspListTemplate": "listTemplate.jsp",
"jspFileTemplate": "articleTemplate.jsp",
"cachePackageTagsTrack": 200,
"cachePackageTagsStore": 200,
"cachePackageTagsRefresh": 60,
"cacheTemplatesTrack": 100,
"cacheTemplatesStore": 50,
"cacheTemplatesRefresh": 15,
"cachePagesTrack": 200,
"cachePagesStore": 100,
"cachePagesRefresh": 10,
"cachePagesDirtyRead": 10,
"searchEngineListTemplate": "forSearchEnginesList.htm",
"searchEngineFileTemplate": "forSearchEngines.htm",
"searchEngineRobotsDb": "WEB-INF/robots.db",
"useDataStore": true,
"dataStoreClass": "org.cofax.SqlDataStore",
"redirectionClass": "org.cofax.SqlRedirection",
"dataStoreName": "cofax",
"dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
"dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
"dataStoreUser": "sa",
"dataStorePassword": "dataStoreTestQuery",
"dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",
"dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
"dataStoreInitConns": 10,
"dataStoreMaxConns": 100,
"dataStoreConnUsageLimit": 100,
"dataStoreLogLevel": "debug",
"maxUrlLength": 500}},
{
"servlet-name": "cofaxEmail",
"servlet-class": "org.cofax.cds.EmailServlet",
"init-param": {
"mailHost": "mail1",
"mailHostOverride": "mail2"}},
{
"servlet-name": "cofaxAdmin",
"servlet-class": "org.cofax.cds.AdminServlet"},
{
"servlet-name": "fileServlet",
"servlet-class": "org.cofax.cds.FileServlet"},
{
"servlet-name": "cofaxTools",
"servlet-class": "org.cofax.cms.CofaxToolsServlet",
"init-param": {
"templatePath": "toolstemplates/",
"log": 1,
"logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
"logMaxSize": "",
"dataLog": 1,
"dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
"dataLogMaxSize": "",
"removePageCache": "/content/admin/remove?cache=pages&id=",
"removeTemplateCache": "/content/admin/remove?cache=templates&id=",
"fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
"lookInContext": 1,
"adminGroupID": 4,
"betaServer": true}}],
"servlet-mapping": {
"cofaxCDS": "/",
"cofaxEmail": "/cofaxutil/aemail/*",
"cofaxAdmin": "/admin/*",
"fileServlet": "/static/*",
"cofaxTools": "/tools/*"},
"taglib": {
"taglib-uri": "cofax.tld",
"taglib-location": "/WEB-INF/tlds/cofax.tld"}}}

27
fuzzing/inputs/test5 Normal file
View File

@@ -0,0 +1,27 @@
bf{"menu": {
"header": "SVG Viewer",
"items": [
{"id": "Open"},
{"id": "OpenNew", "label": "Open New"},
null,
{"id": "ZoomIn", "label": "Zoom In"},
{"id": "ZoomOut", "label": "Zoom Out"},
{"id": "OriginalView", "label": "Original View"},
null,
{"id": "Quality"},
{"id": "Pause"},
{"id": "Mute"},
null,
{"id": "Find", "label": "Find..."},
{"id": "FindAgain", "label": "Find Again"},
{"id": "Copy"},
{"id": "CopyAgain", "label": "Copy Again"},
{"id": "CopySVG", "label": "Copy SVG"},
{"id": "ViewSVG", "label": "View SVG"},
{"id": "ViewSource", "label": "View Source"},
{"id": "SaveAs", "label": "Save As"},
null,
{"id": "Help"},
{"id": "About", "label": "About Adobe CVG Viewer..."}
]
}}

16
fuzzing/inputs/test6 Normal file
View File

@@ -0,0 +1,16 @@
bf<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
html, body, iframe { margin: 0; padding: 0; height: 100%; }
iframe { display: block; width: 100%; border: none; }
</style>
<title>Application Error</title>
</head>
<body>
<iframe src="//s3.amazonaws.com/heroku_pages/error.html">
<p>Application Error</p>
</iframe>
</body>
</html>

22
fuzzing/inputs/test7 Normal file
View File

@@ -0,0 +1,22 @@
bf[
{
"precision": "zip",
"Latitude": 37.7668,
"Longitude": -122.3959,
"Address": "",
"City": "SAN FRANCISCO",
"State": "CA",
"Zip": "94107",
"Country": "US"
},
{
"precision": "zip",
"Latitude": 37.371991,
"Longitude": -122.026020,
"Address": "",
"City": "SUNNYVALE",
"State": "CA",
"Zip": "94085",
"Country": "US"
}
]

13
fuzzing/inputs/test8 Normal file
View File

@@ -0,0 +1,13 @@
bf{
"Image": {
"Width": 800,
"Height": 600,
"Title": "View from 15th Floor",
"Thumbnail": {
"Url": "http:/*www.example.com/image/481989943",
"Height": 125,
"Width": "100"
},
"IDs": [116, 943, 234, 38793]
}
}

5
fuzzing/inputs/test9 Normal file
View File

@@ -0,0 +1,5 @@
bf[
[0, -1, 0],
[1, 0, 0],
[0, 0, 1]
]

47
fuzzing/json.dict Normal file
View File

@@ -0,0 +1,47 @@
#
# AFL dictionary for JSON
# -----------------------------
#
object_start="{"
object_end="}"
object_empty="{}"
object_one_element="{\"one\":1}"
object_two_elements="{\"1\":1,\"2\":2}"
object_separator=":"
array_start="["
array_end="]"
array_empty="[]"
array_one_element="[1]"
array_two_elements="[1,2]"
separator=","
escape_sequence_b="\\b"
escape_sequence_f="\\f"
escape_sequence_n="\\n"
escape_sequence_r="\\r"
escape_sequence_t="\\t"
escape_sequence_quote="\\\""
escape_sequence_backslash="\\\\"
escapce_sequence_slash="\\/"
escpae_sequence_utf16_base="\\u"
escape_sequence_utf16="\\u12ab"
number_integer="1"
number_double="1.0"
number_negative_integer="-1"
number_negative_double="-1.0"
number_engineering1="1e1"
number_engineering2="1e-1"
number_positive_integer="+1"
number_positive_double="+1.0"
number_e="e"
number_plus="+"
number_minus="-"
number_separator="."
null="null"
true="true"
false="false"

View File

@@ -1,6 +1,17 @@
if(ENABLE_CJSON_TEST) if(ENABLE_CJSON_TEST)
add_library(unity unity/src/unity.c) add_library(unity unity/src/unity.c)
# Disable -Werror for Unity
list(FIND custom_compiler_flags "-Werror" werror_found)
if (werror_found)
target_compile_options(unity PRIVATE "-Wno-error")
endif()
# Disable -fvisibility=hidden for Unity
list(FIND custom_compiler_flags "-fvisibility=hidden" visibility_found)
if (visibility_found)
target_compile_options(unity PRIVATE "-fvisibility=default")
endif()
#copy test files #copy test files
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/inputs") file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/inputs")
file(GLOB test_files "inputs/*") file(GLOB test_files "inputs/*")
@@ -14,6 +25,12 @@ if(ENABLE_CJSON_TEST)
parse_array parse_array
parse_object parse_object
parse_value parse_value
print_string
print_number
print_array
print_object
print_value
misc_tests
) )
add_library(test-common common.c) add_library(test-common common.c)
@@ -29,6 +46,11 @@ if(ENABLE_CJSON_TEST)
endif() endif()
endif() endif()
#"check" target that automatically builds everything and runs the tests
add_custom_target(check
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
DEPENDS ${unity_tests})
foreach(unity_test ${unity_tests}) foreach(unity_test ${unity_tests})
add_executable("${unity_test}" "${unity_test}.c") add_executable("${unity_test}" "${unity_test}.c")
target_link_libraries("${unity_test}" "${CJSON_LIB}" unity test-common) target_link_libraries("${unity_test}" "${CJSON_LIB}" unity test-common)

View File

@@ -22,7 +22,7 @@
#include "common.h" #include "common.h"
extern void reset(cJSON *item) CJSON_PUBLIC(void) reset(cJSON *item)
{ {
if ((item != NULL) && (item->child != NULL)) if ((item != NULL) && (item->child != NULL))
{ {
@@ -30,17 +30,17 @@ extern void reset(cJSON *item)
} }
if ((item->valuestring != NULL) && !(item->type & cJSON_IsReference)) if ((item->valuestring != NULL) && !(item->type & cJSON_IsReference))
{ {
cJSON_free(item->valuestring); global_hooks.deallocate(item->valuestring);
} }
if ((item->string != NULL) && !(item->type & cJSON_StringIsConst)) if ((item->string != NULL) && !(item->type & cJSON_StringIsConst))
{ {
cJSON_free(item->string); global_hooks.deallocate(item->string);
} }
memset(item, 0, sizeof(cJSON)); memset(item, 0, sizeof(cJSON));
} }
extern char *read_file(const char *filename) CJSON_PUBLIC(char*) read_file(const char *filename)
{ {
FILE *file = NULL; FILE *file = NULL;
long length = 0; long length = 0;

View File

@@ -25,9 +25,8 @@
#include "../cJSON.c" #include "../cJSON.c"
extern void reset(cJSON *item); CJSON_PUBLIC(void) reset(cJSON *item);
extern char *read_file(const char *filename); CJSON_PUBLIC(char*) read_file(const char *filename);
extern cjbool assert_is_invalid(cJSON *item);
/* assertion helper macros */ /* assertion helper macros */
#define assert_has_type(item, item_type) TEST_ASSERT_BITS_MESSAGE(0xFF, item_type, item->type, "Item doesn't have expected type.") #define assert_has_type(item, item_type) TEST_ASSERT_BITS_MESSAGE(0xFF, item_type, item->type, "Item doesn't have expected type.")

View File

@@ -1,7 +1,7 @@
[{ [{
"precision": "zip", "precision": "zip",
"Latitude": 37.766800, "Latitude": 37.7668,
"Longitude": -122.395900, "Longitude": -122.3959,
"Address": "", "Address": "",
"City": "SAN FRANCISCO", "City": "SAN FRANCISCO",
"State": "CA", "State": "CA",
@@ -10,7 +10,7 @@
}, { }, {
"precision": "zip", "precision": "zip",
"Latitude": 37.371991, "Latitude": 37.371991,
"Longitude": -122.026020, "Longitude": -122.02602,
"Address": "", "Address": "",
"City": "SUNNYVALE", "City": "SUNNYVALE",
"State": "CA", "State": "CA",

197
tests/misc_tests.c Normal file
View File

@@ -0,0 +1,197 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "unity/examples/unity_config.h"
#include "unity/src/unity.h"
#include "common.h"
static void cjson_array_foreach_should_loop_over_arrays(void)
{
cJSON array[1];
cJSON elements[10];
cJSON *element_pointer = NULL;
size_t i = 0;
memset(array, 0, sizeof(array));
memset(elements, 0, sizeof(elements));
/* create array */
array[0].child = &elements[0];
elements[0].prev = NULL;
elements[9].next = NULL;
for (i = 0; i < 9; i++)
{
elements[i].next = &elements[i + 1];
elements[i + 1].prev = &elements[i];
}
i = 0;
cJSON_ArrayForEach(element_pointer, array)
{
TEST_ASSERT_TRUE_MESSAGE(element_pointer == &elements[i], "Not iterating over array properly");
i++;
}
}
static void cjson_array_foreach_should_not_dereference_null_pointer(void)
{
cJSON *array = NULL;
cJSON *element = NULL;
cJSON_ArrayForEach(element, array);
}
static void cjson_get_object_item_should_get_object_items(void)
{
cJSON *item = NULL;
cJSON *found = NULL;
item = cJSON_Parse("{\"one\":1, \"Two\":2, \"tHree\":3}");
found = cJSON_GetObjectItem(NULL, "test");
TEST_ASSERT_NULL_MESSAGE(found, "Failed to fail on NULL pointer.");
found = cJSON_GetObjectItem(item, NULL);
TEST_ASSERT_NULL_MESSAGE(found, "Failed to fail on NULL string.");
found = cJSON_GetObjectItem(item, "one");
TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find first item.");
TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 1);
found = cJSON_GetObjectItem(item, "tWo");
TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find first item.");
TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 2);
found = cJSON_GetObjectItem(item, "three");
TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find item.");
TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 3);
found = cJSON_GetObjectItem(item, "four");
TEST_ASSERT_NULL_MESSAGE(found, "Should not find something that isn't there.");
cJSON_Delete(item);
}
static void cjson_get_object_item_case_sensitive_should_get_object_items(void)
{
cJSON *item = NULL;
cJSON *found = NULL;
item = cJSON_Parse("{\"one\":1, \"Two\":2, \"tHree\":3}");
found = cJSON_GetObjectItemCaseSensitive(NULL, "test");
TEST_ASSERT_NULL_MESSAGE(found, "Failed to fail on NULL pointer.");
found = cJSON_GetObjectItemCaseSensitive(item, NULL);
TEST_ASSERT_NULL_MESSAGE(found, "Failed to fail on NULL string.");
found = cJSON_GetObjectItemCaseSensitive(item, "one");
TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find first item.");
TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 1);
found = cJSON_GetObjectItemCaseSensitive(item, "Two");
TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find first item.");
TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 2);
found = cJSON_GetObjectItemCaseSensitive(item, "tHree");
TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find item.");
TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 3);
found = cJSON_GetObjectItemCaseSensitive(item, "One");
TEST_ASSERT_NULL_MESSAGE(found, "Should not find something that isn't there.");
cJSON_Delete(item);
}
static void typecheck_functions_should_check_type(void)
{
cJSON invalid[1];
cJSON item[1];
invalid->type = cJSON_Invalid;
invalid->type |= cJSON_StringIsConst;
item->type = cJSON_False;
item->type |= cJSON_StringIsConst;
TEST_ASSERT_FALSE(cJSON_IsInvalid(NULL));
TEST_ASSERT_FALSE(cJSON_IsInvalid(item));
TEST_ASSERT_TRUE(cJSON_IsInvalid(invalid));
item->type = cJSON_False | cJSON_StringIsConst;
TEST_ASSERT_FALSE(cJSON_IsFalse(NULL));
TEST_ASSERT_FALSE(cJSON_IsFalse(invalid));
TEST_ASSERT_TRUE(cJSON_IsFalse(item));
TEST_ASSERT_TRUE(cJSON_IsBool(item));
item->type = cJSON_True | cJSON_StringIsConst;
TEST_ASSERT_FALSE(cJSON_IsTrue(NULL));
TEST_ASSERT_FALSE(cJSON_IsTrue(invalid));
TEST_ASSERT_TRUE(cJSON_IsTrue(item));
TEST_ASSERT_TRUE(cJSON_IsBool(item));
item->type = cJSON_NULL | cJSON_StringIsConst;
TEST_ASSERT_FALSE(cJSON_IsNull(NULL));
TEST_ASSERT_FALSE(cJSON_IsNull(invalid));
TEST_ASSERT_TRUE(cJSON_IsNull(item));
item->type = cJSON_Number | cJSON_StringIsConst;
TEST_ASSERT_FALSE(cJSON_IsNumber(NULL));
TEST_ASSERT_FALSE(cJSON_IsNumber(invalid));
TEST_ASSERT_TRUE(cJSON_IsNumber(item));
item->type = cJSON_String | cJSON_StringIsConst;
TEST_ASSERT_FALSE(cJSON_IsString(NULL));
TEST_ASSERT_FALSE(cJSON_IsString(invalid));
TEST_ASSERT_TRUE(cJSON_IsString(item));
item->type = cJSON_Array | cJSON_StringIsConst;
TEST_ASSERT_FALSE(cJSON_IsArray(NULL));
TEST_ASSERT_FALSE(cJSON_IsArray(invalid));
TEST_ASSERT_TRUE(cJSON_IsArray(item));
item->type = cJSON_Object | cJSON_StringIsConst;
TEST_ASSERT_FALSE(cJSON_IsObject(NULL));
TEST_ASSERT_FALSE(cJSON_IsObject(invalid));
TEST_ASSERT_TRUE(cJSON_IsObject(item));
item->type = cJSON_Raw | cJSON_StringIsConst;
TEST_ASSERT_FALSE(cJSON_IsRaw(NULL));
TEST_ASSERT_FALSE(cJSON_IsRaw(invalid));
TEST_ASSERT_TRUE(cJSON_IsRaw(item));
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(cjson_array_foreach_should_loop_over_arrays);
RUN_TEST(cjson_array_foreach_should_not_dereference_null_pointer);
RUN_TEST(cjson_get_object_item_should_get_object_items);
RUN_TEST(cjson_get_object_item_case_sensitive_should_get_object_items);
RUN_TEST(typecheck_functions_should_check_type);
return UNITY_END();
}

View File

@@ -46,13 +46,13 @@ static void assert_is_array(cJSON *array_item)
static void assert_not_array(const char *json) static void assert_not_array(const char *json)
{ {
TEST_ASSERT_NULL(parse_array(item, (const unsigned char*)json, &error_pointer)); TEST_ASSERT_NULL(parse_array(item, (const unsigned char*)json, &error_pointer, &global_hooks));
assert_is_invalid(item); assert_is_invalid(item);
} }
static void assert_parse_array(const char *json) static void assert_parse_array(const char *json)
{ {
TEST_ASSERT_NOT_NULL(parse_array(item, (const unsigned char*)json, &error_pointer)); TEST_ASSERT_NOT_NULL(parse_array(item, (const unsigned char*)json, &error_pointer, &global_hooks));
assert_is_array(item); assert_is_array(item);
} }
@@ -124,7 +124,7 @@ static void parse_array_should_parse_arrays_with_multiple_elements(void)
i = 0; i = 0;
(i < (sizeof(expected_types)/sizeof(int))) (i < (sizeof(expected_types)/sizeof(int)))
&& (node != NULL); && (node != NULL);
i++, node = node->next) (void)i++, node = node->next)
{ {
TEST_ASSERT_BITS(0xFF, expected_types[i], node->type); TEST_ASSERT_BITS(0xFF, expected_types[i], node->type);
} }

View File

@@ -54,14 +54,14 @@ static void assert_is_child(cJSON *child_item, const char *name, int type)
static void assert_not_object(const char *json) static void assert_not_object(const char *json)
{ {
TEST_ASSERT_NULL(parse_object(item, (const unsigned char*)json, &error_pointer)); TEST_ASSERT_NULL(parse_object(item, (const unsigned char*)json, &error_pointer, &global_hooks));
assert_is_invalid(item); assert_is_invalid(item);
reset(item); reset(item);
} }
static void assert_parse_object(const char *json) static void assert_parse_object(const char *json)
{ {
TEST_ASSERT_NOT_NULL(parse_object(item, (const unsigned char*)json, &error_pointer)); TEST_ASSERT_NOT_NULL(parse_object(item, (const unsigned char*)json, &error_pointer, &global_hooks));
assert_is_object(item); assert_is_object(item);
} }
@@ -76,7 +76,7 @@ static void parse_object_should_parse_empty_objects(void)
reset(item); reset(item);
} }
static void parse_array_should_parse_arrays_with_one_element(void) static void parse_object_should_parse_objects_with_one_element(void)
{ {
assert_parse_object("{\"one\":1}"); assert_parse_object("{\"one\":1}");
@@ -134,7 +134,7 @@ static void parse_object_should_parse_objects_with_multiple_elements(void)
i = 0; i = 0;
(i < (sizeof(expected_types)/sizeof(int))) (i < (sizeof(expected_types)/sizeof(int)))
&& (node != NULL); && (node != NULL);
i++, node = node->next) (void)i++, node = node->next)
{ {
assert_is_child(node, expected_names[i], expected_types[i]); assert_is_child(node, expected_names[i], expected_types[i]);
} }
@@ -163,6 +163,6 @@ int main(void)
RUN_TEST(parse_object_should_parse_empty_objects); RUN_TEST(parse_object_should_parse_empty_objects);
RUN_TEST(parse_object_should_not_parse_non_objects); RUN_TEST(parse_object_should_not_parse_non_objects);
RUN_TEST(parse_object_should_parse_objects_with_multiple_elements); RUN_TEST(parse_object_should_parse_objects_with_multiple_elements);
RUN_TEST(parse_array_should_parse_arrays_with_one_element); RUN_TEST(parse_object_should_parse_objects_with_one_element);
return UNITY_END(); return UNITY_END();
} }

View File

@@ -47,15 +47,15 @@ static void assert_is_string(cJSON *string_item)
static void assert_parse_string(const char *string, const char *expected) static void assert_parse_string(const char *string, const char *expected)
{ {
TEST_ASSERT_NOT_NULL_MESSAGE(parse_string(item, (const unsigned char*)string, &error_pointer), "Couldn't parse string."); TEST_ASSERT_NOT_NULL_MESSAGE(parse_string(item, (const unsigned char*)string, &error_pointer, &global_hooks), "Couldn't parse string.");
assert_is_string(item); assert_is_string(item);
TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, item->valuestring, "The parsed result isn't as expected."); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, item->valuestring, "The parsed result isn't as expected.");
cJSON_free(item->valuestring); global_hooks.deallocate(item->valuestring);
item->valuestring = NULL; item->valuestring = NULL;
} }
#define assert_not_parse_string(string) \ #define assert_not_parse_string(string) \
TEST_ASSERT_NULL_MESSAGE(parse_string(item, (const unsigned char*)string, &error_pointer), "Malformed string should not be accepted");\ TEST_ASSERT_NULL_MESSAGE(parse_string(item, (const unsigned char*)string, &error_pointer, &global_hooks), "Malformed string should not be accepted");\
assert_is_invalid(item) assert_is_invalid(item)

View File

@@ -44,7 +44,7 @@ static void assert_is_value(cJSON *value_item, int type)
static void assert_parse_value(const char *string, int type) static void assert_parse_value(const char *string, int type)
{ {
TEST_ASSERT_NOT_NULL(parse_value(item, (const unsigned char*)string, &error_pointer)); TEST_ASSERT_NOT_NULL(parse_value(item, (const unsigned char*)string, &error_pointer, &global_hooks));
assert_is_value(item, type); assert_is_value(item, type);
} }

92
tests/print_array.c Normal file
View File

@@ -0,0 +1,92 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "unity/examples/unity_config.h"
#include "unity/src/unity.h"
#include "common.h"
static void assert_print_array(const char * const expected, const char * const input)
{
unsigned char printed_unformatted[1024];
unsigned char printed_formatted[1024];
const unsigned char *error_pointer;
cJSON item[1];
printbuffer formatted_buffer;
printbuffer unformatted_buffer;
/* buffer for formatted printing */
formatted_buffer.buffer = printed_formatted;
formatted_buffer.length = sizeof(printed_formatted);
formatted_buffer.offset = 0;
formatted_buffer.noalloc = true;
/* buffer for unformatted printing */
unformatted_buffer.buffer = printed_unformatted;
unformatted_buffer.length = sizeof(printed_unformatted);
unformatted_buffer.offset = 0;
unformatted_buffer.noalloc = true;
memset(item, 0, sizeof(item));
TEST_ASSERT_NOT_NULL_MESSAGE(parse_array(item, (const unsigned char*)input, &error_pointer, &global_hooks), "Failed to parse array.");
TEST_ASSERT_TRUE_MESSAGE(print_array(item, 0, false, &unformatted_buffer, &global_hooks), "Failed to print unformatted string.");
TEST_ASSERT_EQUAL_STRING_MESSAGE(input, printed_unformatted, "Unformatted array is not correct.");
TEST_ASSERT_TRUE_MESSAGE(print_array(item, 0, true, &formatted_buffer, &global_hooks), "Failed to print formatted string.");
TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed_formatted, "Formatted array is not correct.");
reset(item);
}
static void print_array_should_print_empty_arrays(void)
{
assert_print_array("[]", "[]");
}
static void print_array_should_print_arrays_with_one_element(void)
{
assert_print_array("[1]", "[1]");
assert_print_array("[\"hello!\"]", "[\"hello!\"]");
assert_print_array("[[]]", "[[]]");
assert_print_array("[null]", "[null]");
}
static void print_array_should_print_arrays_with_multiple_elements(void)
{
assert_print_array("[1, 2, 3]", "[1,2,3]");
assert_print_array("[1, null, true, false, [], \"hello\", {\n\t}]", "[1,null,true,false,[],\"hello\",{}]");
}
int main(void)
{
/* initialize cJSON item */
UNITY_BEGIN();
RUN_TEST(print_array_should_print_empty_arrays);
RUN_TEST(print_array_should_print_arrays_with_one_element);
RUN_TEST(print_array_should_print_arrays_with_multiple_elements);
return UNITY_END();
}

119
tests/print_number.c Normal file
View File

@@ -0,0 +1,119 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "unity/examples/unity_config.h"
#include "unity/src/unity.h"
#include "common.h"
static void assert_print_number(const char *expected, double input)
{
unsigned char printed[1024];
cJSON item[1];
printbuffer buffer;
buffer.buffer = printed;
buffer.length = sizeof(printed);
buffer.offset = 0;
buffer.noalloc = true;
memset(item, 0, sizeof(item));
cJSON_SetNumberValue(item, input);
TEST_ASSERT_TRUE_MESSAGE(print_number(item, &buffer, &global_hooks), "Failed to print number.");
TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, buffer.buffer, "Printed number is not as expected.");
}
static void print_number_should_print_zero(void)
{
assert_print_number("0", 0);
}
static void print_number_should_print_negative_integers(void)
{
assert_print_number("-1", -1);
assert_print_number("-32768", -32768);
assert_print_number("-2147483648", -2147483648);
}
static void print_number_should_print_positive_integers(void)
{
assert_print_number("1", 1);
assert_print_number("32767", 32767);
assert_print_number("2147483647", 2147483647);
}
static void print_number_should_print_positive_reals(void)
{
assert_print_number("0.123", 0.123);
assert_print_number("1.000000e-09", 10e-10);
assert_print_number("1000000000000", 10e11);
assert_print_number("1.230000e+129", 123e+127);
assert_print_number("0", 123e-128); /* TODO: Maybe this shouldn't be 0 */
}
static void print_number_should_print_negative_reals(void)
{
assert_print_number("-0.0123", -0.0123);
assert_print_number("-1.000000e-09", -10e-10);
assert_print_number("-1000000000000000000000", -10e20);
assert_print_number("-1.230000e+129", -123e+127);
assert_print_number("-1.230000e-126", -123e-128);
}
static void print_number_should_print_non_number(void)
{
TEST_IGNORE();
/* FIXME: Cannot test this easily in C89! */
/* assert_print_number("null", NaN); */
/* assert_print_number("null", INFTY); */
/* assert_print_number("null", -INFTY); */
}
static void trim_trailing_zeroes_should_trim_trailing_zeroes(void)
{
printbuffer buffer;
unsigned char number[100];
buffer.length = sizeof(number);
buffer.buffer = number;
strcpy((char*)number, "10.00");
buffer.offset = sizeof("10.00") - 1;
TEST_ASSERT_TRUE(trim_trailing_zeroes(&buffer));
TEST_ASSERT_EQUAL_UINT8('\0', buffer.buffer[buffer.offset]);
TEST_ASSERT_EQUAL_STRING("10", number);
TEST_ASSERT_EQUAL_UINT(sizeof("10") - 1, buffer.offset);
}
int main(void)
{
/* initialize cJSON item */
UNITY_BEGIN();
RUN_TEST(print_number_should_print_zero);
RUN_TEST(print_number_should_print_negative_integers);
RUN_TEST(print_number_should_print_positive_integers);
RUN_TEST(print_number_should_print_positive_reals);
RUN_TEST(print_number_should_print_negative_reals);
RUN_TEST(print_number_should_print_non_number);
RUN_TEST(trim_trailing_zeroes_should_trim_trailing_zeroes);
return UNITY_END();
}

92
tests/print_object.c Normal file
View File

@@ -0,0 +1,92 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "unity/examples/unity_config.h"
#include "unity/src/unity.h"
#include "common.h"
static void assert_print_object(const char * const expected, const char * const input)
{
unsigned char printed_unformatted[1024];
unsigned char printed_formatted[1024];
const unsigned char *error_pointer;
cJSON item[1];
printbuffer formatted_buffer;
printbuffer unformatted_buffer;
/* buffer for formatted printing */
formatted_buffer.buffer = printed_formatted;
formatted_buffer.length = sizeof(printed_formatted);
formatted_buffer.offset = 0;
formatted_buffer.noalloc = true;
/* buffer for unformatted printing */
unformatted_buffer.buffer = printed_unformatted;
unformatted_buffer.length = sizeof(printed_unformatted);
unformatted_buffer.offset = 0;
unformatted_buffer.noalloc = true;
memset(item, 0, sizeof(item));
TEST_ASSERT_NOT_NULL_MESSAGE(parse_object(item, (const unsigned char*)input, &error_pointer, &global_hooks), "Failed to parse object.");
TEST_ASSERT_TRUE_MESSAGE(print_object(item, 0, false, &unformatted_buffer, &global_hooks), "Failed to print unformatted string.");
TEST_ASSERT_EQUAL_STRING_MESSAGE(input, printed_unformatted, "Unformatted object is not correct.");
TEST_ASSERT_TRUE_MESSAGE(print_object(item, 0, true, &formatted_buffer, &global_hooks), "Failed to print formatted string.");
TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed_formatted, "Formatted ojbect is not correct.");
reset(item);
}
static void print_object_should_print_empty_objects(void)
{
assert_print_object("{\n}", "{}");
}
static void print_object_should_print_objects_with_one_element(void)
{
assert_print_object("{\n\t\"one\":\t1\n}", "{\"one\":1}");
assert_print_object("{\n\t\"hello\":\t\"world!\"\n}", "{\"hello\":\"world!\"}");
assert_print_object("{\n\t\"array\":\t[]\n}", "{\"array\":[]}");
assert_print_object("{\n\t\"null\":\tnull\n}", "{\"null\":null}");
}
static void print_object_should_print_objects_with_multiple_elements(void)
{
assert_print_object("{\n\t\"one\":\t1,\n\t\"two\":\t2,\n\t\"three\":\t3\n}", "{\"one\":1,\"two\":2,\"three\":3}");
assert_print_object("{\n\t\"one\":\t1,\n\t\"NULL\":\tnull,\n\t\"TRUE\":\ttrue,\n\t\"FALSE\":\tfalse,\n\t\"array\":\t[],\n\t\"world\":\t\"hello\",\n\t\"object\":\t{\n\t}\n}", "{\"one\":1,\"NULL\":null,\"TRUE\":true,\"FALSE\":false,\"array\":[],\"world\":\"hello\",\"object\":{}}");
}
int main(void)
{
/* initialize cJSON item */
UNITY_BEGIN();
RUN_TEST(print_object_should_print_empty_objects);
RUN_TEST(print_object_should_print_objects_with_one_element);
RUN_TEST(print_object_should_print_objects_with_multiple_elements);
return UNITY_END();
}

77
tests/print_string.c Normal file
View File

@@ -0,0 +1,77 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "unity/examples/unity_config.h"
#include "unity/src/unity.h"
#include "common.h"
static void assert_print_string(const char *expected, const char *input)
{
unsigned char printed[1024];
printbuffer buffer;
buffer.buffer = printed;
buffer.length = sizeof(printed);
buffer.offset = 0;
buffer.noalloc = true;
TEST_ASSERT_TRUE_MESSAGE(print_string_ptr((const unsigned char*)input, &buffer, &global_hooks), "Failed to print string.");
TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed, "The printed string isn't as expected.");
}
static void print_string_should_print_empty_strings(void)
{
assert_print_string("\"\"", "");
assert_print_string("\"\"", NULL);
}
static void print_string_should_print_ascii(void)
{
char ascii[0x7F];
size_t i = 1;
/* create ascii table */
for (i = 1; i < 0x7F; i++)
{
ascii[i-1] = (char)i;
}
ascii[0x7F-1] = '\0';
assert_print_string("\"\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"",
ascii);
}
static void print_string_should_print_utf8(void)
{
assert_print_string("\"ü猫慕\"", "ü猫慕");
}
int main(void)
{
/* initialize cJSON item */
UNITY_BEGIN();
RUN_TEST(print_string_should_print_empty_strings);
RUN_TEST(print_string_should_print_ascii);
RUN_TEST(print_string_should_print_utf8);
return UNITY_END();
}

102
tests/print_value.c Normal file
View File

@@ -0,0 +1,102 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "unity/examples/unity_config.h"
#include "unity/src/unity.h"
#include "common.h"
static void assert_print_value(const char *input)
{
unsigned char printed[1024];
const unsigned char *error_pointer = NULL;
cJSON item[1];
printbuffer buffer;
buffer.buffer = printed;
buffer.length = sizeof(printed);
buffer.offset = 0;
buffer.noalloc = true;
memset(item, 0, sizeof(item));
TEST_ASSERT_NOT_NULL_MESSAGE(parse_value(item, (const unsigned char*)input, &error_pointer, &global_hooks), "Failed to parse value.");
TEST_ASSERT_TRUE_MESSAGE(print_value(item, 0, false, &buffer, &global_hooks), "Failed to print value.");
TEST_ASSERT_EQUAL_STRING_MESSAGE(input, buffer.buffer, "Printed value is not as expected.");
reset(item);
}
static void print_value_should_print_null(void)
{
assert_print_value("null");
}
static void print_value_should_print_true(void)
{
assert_print_value("true");
}
static void print_value_should_print_false(void)
{
assert_print_value("false");
}
static void print_value_should_print_number(void)
{
assert_print_value("1.5");
}
static void print_value_should_print_string(void)
{
assert_print_value("\"\"");
assert_print_value("\"hello\"");
}
static void print_value_should_print_array(void)
{
assert_print_value("[]");
}
static void print_value_should_print_object(void)
{
assert_print_value("{}");
}
int main(void)
{
/* initialize cJSON item */
UNITY_BEGIN();
RUN_TEST(print_value_should_print_null);
RUN_TEST(print_value_should_print_true);
RUN_TEST(print_value_should_print_false);
RUN_TEST(print_value_should_print_number);
RUN_TEST(print_value_should_print_string);
RUN_TEST(print_value_should_print_array);
RUN_TEST(print_value_should_print_object);
return UNITY_END();
}

View File

@@ -41,13 +41,13 @@ Example:
main() main()
{ {
if (TEST_PROTECT() == 0) if (TEST_PROTECT())
{ {
MyTest(); MyTest();
} }
} }
If MyTest calls `TEST_ABORT`, program control will immediately return to `TEST_PROTECT` with a non-zero return value. If MyTest calls `TEST_ABORT`, program control will immediately return to `TEST_PROTECT` with a return value of zero.
Unity Assertion Summary Unity Assertion Summary

View File

@@ -65,6 +65,17 @@ class ParseOutput
@arrayList.push " <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\"/>" @arrayList.push " <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\"/>"
end end
end end
# Test was flagged as having passed so format the output.
# This is using the Unity fixture output and not the original Unity output.
def testPassedUnityFixture(array)
testSuite = array[0].sub("TEST(", "")
testSuite = testSuite.sub(",", "")
testName = array[1].sub(")", "")
if @xmlOut == true
@arrayList.push " <testcase classname=\"" + testSuite + "\" name=\"" + testName + "\"/>"
end
end
# Test was flagged as being ingored so format the output # Test was flagged as being ingored so format the output
def testIgnored(array) def testIgnored(array)
@@ -73,6 +84,14 @@ class ParseOutput
reason = array[lastItem].chomp reason = array[lastItem].chomp
testSuiteVerify(array[@className]) testSuiteVerify(array[@className])
printf "%-40s IGNORED\n", testName printf "%-40s IGNORED\n", testName
if testName.start_with? "TEST("
array2 = testName.split(" ")
@testSuite = array2[0].sub("TEST(", "")
@testSuite = @testSuite.sub(",", "")
testName = array2[1].sub(")", "")
end
if @xmlOut == true if @xmlOut == true
@arrayList.push " <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\">" @arrayList.push " <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\">"
@arrayList.push " <skipped type=\"TEST IGNORED\"> " + reason + " </skipped>" @arrayList.push " <skipped type=\"TEST IGNORED\"> " + reason + " </skipped>"
@@ -87,6 +106,14 @@ class ParseOutput
reason = array[lastItem].chomp + " at line: " + array[lastItem - 3] reason = array[lastItem].chomp + " at line: " + array[lastItem - 3]
testSuiteVerify(array[@className]) testSuiteVerify(array[@className])
printf "%-40s FAILED\n", testName printf "%-40s FAILED\n", testName
if testName.start_with? "TEST("
array2 = testName.split(" ")
@testSuite = array2[0].sub("TEST(", "")
@testSuite = @testSuite.sub(",", "")
testName = array2[1].sub(")", "")
end
if @xmlOut == true if @xmlOut == true
@arrayList.push " <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\">" @arrayList.push " <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\">"
@arrayList.push " <failure type=\"ASSERT FAILED\"> " + reason + " </failure>" @arrayList.push " <failure type=\"ASSERT FAILED\"> " + reason + " </failure>"
@@ -138,7 +165,7 @@ class ParseOutput
lineSize = lineArray.size lineSize = lineArray.size
# If we were able to split the line then we can look to see if any of our target words # If we were able to split the line then we can look to see if any of our target words
# were found. Case is important. # were found. Case is important.
if lineSize >= 4 if ((lineSize >= 4) || (line.start_with? "TEST("))
# Determine if this test passed # Determine if this test passed
if line.include? ":PASS" if line.include? ":PASS"
testPassed(lineArray) testPassed(lineArray)
@@ -149,6 +176,12 @@ class ParseOutput
elsif line.include? ":IGNORE:" elsif line.include? ":IGNORE:"
testIgnored(lineArray) testIgnored(lineArray)
testIgnore += 1 testIgnore += 1
elsif line.start_with? "TEST("
if line.include? " PASS"
lineArray = line.split(" ")
testPassedUnityFixture(lineArray)
testPass += 1
end
# If none of the keywords are found there are no more tests for this suite so clear # If none of the keywords are found there are no more tests for this suite so clear
# the test flag # the test flag
else else

View File

@@ -669,7 +669,7 @@ void UnityAssertEqualFloatArray(UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* expected,
UnityTestResultsFailBegin(lineNumber); UnityTestResultsFailBegin(lineNumber);
UnityPrint(UnityStrElement); UnityPrint(UnityStrElement);
UnityPrintNumberUnsigned(num_elements - elements - 1); UnityPrintNumberUnsigned(num_elements - elements - 1);
UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(*ptr_expected, *ptr_actual); UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT((UNITY_DOUBLE)*ptr_expected, (UNITY_DOUBLE)*ptr_actual);
UnityAddMsgIfSpecified(msg); UnityAddMsgIfSpecified(msg);
UNITY_FAIL_AND_BAIL; UNITY_FAIL_AND_BAIL;
} }
@@ -691,7 +691,7 @@ void UnityAssertFloatsWithin(const UNITY_FLOAT delta,
if (!UnityFloatsWithin(delta, expected, actual)) if (!UnityFloatsWithin(delta, expected, actual))
{ {
UnityTestResultsFailBegin(lineNumber); UnityTestResultsFailBegin(lineNumber);
UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(expected, actual); UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT((UNITY_DOUBLE)expected, (UNITY_DOUBLE)actual);
UnityAddMsgIfSpecified(msg); UnityAddMsgIfSpecified(msg);
UNITY_FAIL_AND_BAIL; UNITY_FAIL_AND_BAIL;
} }
@@ -746,7 +746,7 @@ void UnityAssertFloatSpecial(const UNITY_FLOAT actual,
UnityPrint(trait_names[trait_index]); UnityPrint(trait_names[trait_index]);
UnityPrint(UnityStrWas); UnityPrint(UnityStrWas);
#ifndef UNITY_EXCLUDE_FLOAT_PRINT #ifndef UNITY_EXCLUDE_FLOAT_PRINT
UnityPrintFloat(actual); UnityPrintFloat((UNITY_DOUBLE)actual);
#else #else
if (should_be_trait) if (should_be_trait)
UnityPrint(UnityStrNot); UnityPrint(UnityStrNot);