mirror of
https://github.com/DaveGamble/cJSON.git
synced 2026-11-14 19:03:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3d5798896 | ||
|
|
cf1842dc6f | ||
|
|
030d0c14cc | ||
|
|
02cd3eec37 | ||
|
|
bdb59f09de | ||
|
|
5f783fff11 | ||
|
|
7969af6434 | ||
|
|
0bb1843925 | ||
|
|
5ea4fad263 | ||
|
|
1749de02f8 | ||
|
|
748f4bfd4f | ||
|
|
bea1d102fd | ||
|
|
d441fa05b3 | ||
|
|
3fe72cf2b8 | ||
|
|
d8d0ae66d3 | ||
|
|
9d07917feb | ||
|
|
ad5abf4c5b | ||
|
|
2c45ad7816 | ||
|
|
6405fd15e3 | ||
|
|
b44c917be9 | ||
|
|
2d3520e0b9 | ||
|
|
2e118df0cd | ||
|
|
412f4f7d62 | ||
|
|
0aea75fbda | ||
|
|
0c0dd4a5b0 | ||
|
|
dd4cb5400f | ||
|
|
1ea72f8260 | ||
|
|
e78bc42362 | ||
|
|
6f271e511f | ||
|
|
bee069b4e7 | ||
|
|
1e0bd24f2c | ||
|
|
5cf56fa4fa | ||
|
|
3f349a4258 | ||
|
|
40e3781e9b | ||
|
|
b056d7cb74 | ||
|
|
1f422b586a | ||
|
|
899529e866 | ||
|
|
2837aac23e | ||
|
|
c66d95d116 | ||
|
|
cb6df3ffad | ||
|
|
695d8a01a9 | ||
|
|
024f690289 | ||
|
|
039b1cc653 | ||
|
|
c0ff1fef9b | ||
|
|
2302f4f0b2 | ||
|
|
c45dc12fd7 | ||
|
|
ed8dc53699 | ||
|
|
c26d53f0d7 | ||
|
|
29f312dd69 | ||
|
|
72e6e23523 | ||
|
|
501046247d | ||
|
|
68cd0d4a11 | ||
|
|
56b819bfbc | ||
|
|
605422c60a | ||
|
|
cbbcc91498 | ||
|
|
b47d0e34ca | ||
|
|
bc12c69b54 | ||
|
|
1d42c9bc60 | ||
|
|
b71db93e03 | ||
|
|
6d5a7c8c40 | ||
|
|
8c1ed3ab82 | ||
|
|
f16dd7e028 | ||
|
|
08770fc246 | ||
|
|
0ca8587acc | ||
|
|
88e38d042f | ||
|
|
6a746a230a | ||
|
|
1e999352d3 | ||
|
|
6815d96617 | ||
|
|
61921498d0 | ||
|
|
4758d62fd4 | ||
|
|
1bc1a9748a | ||
|
|
de36476092 | ||
|
|
983a4cd286 | ||
|
|
b6abef94ff | ||
|
|
3d66766231 | ||
|
|
924122904e | ||
|
|
87691a86e5 | ||
|
|
8aa324fdc8 | ||
|
|
3c4d309f62 | ||
|
|
9bf531ca05 | ||
|
|
80354bdb06 | ||
|
|
fe2e0956ad | ||
|
|
cf71f3d627 | ||
|
|
da551c753f | ||
|
|
ae4681b787 | ||
|
|
c5a09a32a9 | ||
|
|
4785070ad3 | ||
|
|
0e0cd5bae5 | ||
|
|
44512f643e | ||
|
|
331c18d09a | ||
|
|
4fff92140e | ||
|
|
fc1d4b07df | ||
|
|
bd073343fa | ||
|
|
7c722dca5f | ||
|
|
4fce9cce86 | ||
|
|
415962da34 | ||
|
|
b41264d164 | ||
|
|
0f271dcf63 | ||
|
|
ead389aba2 | ||
|
|
698dc528f4 | ||
|
|
3dc6339025 | ||
|
|
15592c50f6 | ||
|
|
efb5e1bc93 | ||
|
|
ace5047782 | ||
|
|
03f23738bb | ||
|
|
24dbf29360 | ||
|
|
b6974ecbc9 | ||
|
|
12b2daccf3 | ||
|
|
f8d0c47bdb | ||
|
|
9f6fa94c91 | ||
|
|
123bb1af7b | ||
|
|
cf862d0fed | ||
|
|
57d105d498 | ||
|
|
5986edba1d | ||
|
|
c6e1a281f9 | ||
|
|
4f58695ed3 | ||
|
|
3facca4792 | ||
|
|
cf48ea8175 | ||
|
|
702fd95af3 | ||
|
|
94117a5d23 | ||
|
|
c3bd4463be | ||
|
|
9d7e8f1175 | ||
|
|
4047de4f6e | ||
|
|
49b9336558 | ||
|
|
d04a2aeccf | ||
|
|
33e01ae087 | ||
|
|
a09defec4c | ||
|
|
21c02cd3e5 | ||
|
|
5a36b71a80 | ||
|
|
9041570eba | ||
|
|
71b05fd4c2 | ||
|
|
598b609c45 | ||
|
|
b0e5209bde | ||
|
|
7fd536d7e0 | ||
|
|
be0951dfa4 | ||
|
|
86be961bb5 | ||
|
|
bb60d6def5 | ||
|
|
896e52255b | ||
|
|
12acc57967 | ||
|
|
6b9b57be22 | ||
|
|
d19f3ae890 | ||
|
|
e65ea3a45b | ||
|
|
87f77274de | ||
|
|
dded751757 | ||
|
|
d7b5545748 | ||
|
|
0747669972 | ||
|
|
f09bdef15e | ||
|
|
7119a16b5f | ||
|
|
cc514583cc | ||
|
|
021b174ee1 | ||
|
|
99cd9af7d5 | ||
|
|
8656386c4f | ||
|
|
c866abd842 | ||
|
|
1f5538f79d | ||
|
|
9ed906758e | ||
|
|
2f712c7456 | ||
|
|
d00ca18ac2 | ||
|
|
6cdb6894d4 | ||
|
|
ee0c920dff | ||
|
|
af6d5d3d7c | ||
|
|
cf9d57d56c | ||
|
|
4d95639001 | ||
|
|
3d3bfc6a4d | ||
|
|
41e2837df1 | ||
|
|
ecd5678527 | ||
|
|
28b9ba4334 | ||
|
|
b182ced1d6 | ||
|
|
fe18403935 | ||
|
|
981f59b163 | ||
|
|
e4eadb9a81 | ||
|
|
ff0681e4fd | ||
|
|
a2309a509d | ||
|
|
c49ffbfba8 | ||
|
|
e7533aa6f0 |
No files matched your search
@@ -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.
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
dist: trusty
|
||||||
|
sudo: false
|
||||||
|
language: c
|
||||||
|
env:
|
||||||
|
matrix:
|
||||||
|
- VALGRIND=On SANITIZERS=Off
|
||||||
|
- VALGRIND=Off SANITIZERS=Off
|
||||||
|
- VALGRIND=Off SANITIZERS=On
|
||||||
|
compiler:
|
||||||
|
- gcc
|
||||||
|
- clang
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- valgrind
|
||||||
|
- libasan0
|
||||||
|
- lib32asan0
|
||||||
|
# currently not supported on travis:
|
||||||
|
# - libasan1
|
||||||
|
# - libasan2
|
||||||
|
# - libubsan0
|
||||||
|
- llvm
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- cmake .. -DENABLE_CJSON_UTILS=On -DENABLE_VALGRIND="${VALGRIND}" -DENABLE_SANITIZERS="${SANITIZERS}"
|
||||||
|
- make
|
||||||
|
- make test CTEST_OUTPUT_ON_FAILURE=On
|
||||||
+70
-5
@@ -1,24 +1,87 @@
|
|||||||
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 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 2)
|
set(PROJECT_VERSION_MINOR 4)
|
||||||
set(PROJECT_VERSION_PATCH 0)
|
set(PROJECT_VERSION_PATCH 1)
|
||||||
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}")
|
||||||
|
|
||||||
|
|
||||||
|
set(custom_compiler_flags)
|
||||||
|
|
||||||
|
include(CheckCCompilerFlag)
|
||||||
option(ENABLE_CUSTOM_COMPILER_FLAGS "Enables custom compiler flags for Clang and GCC" ON)
|
option(ENABLE_CUSTOM_COMPILER_FLAGS "Enables custom compiler flags for Clang and GCC" ON)
|
||||||
if (ENABLE_CUSTOM_COMPILER_FLAGS)
|
if (ENABLE_CUSTOM_COMPILER_FLAGS)
|
||||||
if(("${CMAKE_C_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_C_COMPILER_ID}" MATCHES "Clang"))
|
list(APPEND custom_compiler_flags
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c89 -pedantic -Wall -Wextra -Werror -Wstrict-prototypes -Wwrite-strings -Wshadow -Winit-self -Wcast-align -Wformat=2 -Wmissing-prototypes -Wstrict-overflow=2 -Wcast-qual -Wc++-compat")
|
-std=c89
|
||||||
endif()
|
-pedantic
|
||||||
|
-Wall
|
||||||
|
-Wextra
|
||||||
|
-Werror
|
||||||
|
-Wstrict-prototypes
|
||||||
|
-Wwrite-strings
|
||||||
|
-Wshadow
|
||||||
|
-Winit-self
|
||||||
|
-Wcast-align
|
||||||
|
-Wformat=2
|
||||||
|
-Wmissing-prototypes
|
||||||
|
-Wstrict-overflow=2
|
||||||
|
-Wcast-qual
|
||||||
|
-Wundef
|
||||||
|
-Wswitch-default
|
||||||
|
-Wconversion
|
||||||
|
-Wc++-compat
|
||||||
|
-fstack-protector-strong
|
||||||
|
-Wcomma
|
||||||
|
-Wdouble-promotion
|
||||||
|
-Wparentheses
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
option(ENABLE_SANITIZERS "Enables AddressSanitizer and UndefinedBehaviorSanitizer." OFF)
|
||||||
|
if (ENABLE_SANITIZERS)
|
||||||
|
list(APPEND custom_compiler_flags
|
||||||
|
-fno-omit-frame-pointer
|
||||||
|
-fsanitize=address
|
||||||
|
-fsanitize=undefined
|
||||||
|
-fsanitize=float-divide-by-zero
|
||||||
|
-fsanitize=float-cast-overflow
|
||||||
|
-fsanitize-address-use-after-scope
|
||||||
|
-fsanitize=integer
|
||||||
|
-01
|
||||||
|
-fno-sanitize-recover
|
||||||
|
)
|
||||||
|
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
|
||||||
|
foreach(compiler_flag ${custom_compiler_flags})
|
||||||
|
#remove problematic characters
|
||||||
|
string(REGEX REPLACE "[^a-zA-Z0-9]" "" current_variable ${compiler_flag})
|
||||||
|
|
||||||
|
CHECK_C_COMPILER_FLAG(${compiler_flag} "FLAG_SUPPORTED_${current_variable}")
|
||||||
|
if (FLAG_SUPPORTED_${current_variable})
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${compiler_flag}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
#variables for pkg-config
|
#variables for pkg-config
|
||||||
set(prefix "${CMAKE_INSTALL_PREFIX}")
|
set(prefix "${CMAKE_INSTALL_PREFIX}")
|
||||||
set(libdir "${CMAKE_INSTALL_LIBDIR}")
|
set(libdir "${CMAKE_INSTALL_LIBDIR}")
|
||||||
@@ -98,6 +161,8 @@ install(FILES ${PROJECT_BINARY_DIR}/cJSONConfig.cmake
|
|||||||
|
|
||||||
option(ENABLE_CJSON_TEST "Enable building cJSON test" ON)
|
option(ENABLE_CJSON_TEST "Enable building cJSON test" ON)
|
||||||
if(ENABLE_CJSON_TEST)
|
if(ENABLE_CJSON_TEST)
|
||||||
|
enable_testing()
|
||||||
|
|
||||||
set(TEST_CJSON cJSON_test)
|
set(TEST_CJSON cJSON_test)
|
||||||
add_executable("${TEST_CJSON}" test.c)
|
add_executable("${TEST_CJSON}" test.c)
|
||||||
target_link_libraries("${TEST_CJSON}" "${CJSON_LIB}")
|
target_link_libraries("${TEST_CJSON}" "${CJSON_LIB}")
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ UTILS_TEST_SRC = cJSON.c cJSON_Utils.c test_utils.c
|
|||||||
|
|
||||||
LDLIBS = -lm
|
LDLIBS = -lm
|
||||||
|
|
||||||
LIBVERSION = 1.2.0
|
LIBVERSION = 1.4.1
|
||||||
CJSON_SOVERSION = 1
|
CJSON_SOVERSION = 1
|
||||||
UTILS_SOVERSION = 1
|
UTILS_SOVERSION = 1
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ INSTALL_LIBRARY_PATH = $(DESTDIR)$(PREFIX)/$(LIBRARY_PATH)
|
|||||||
|
|
||||||
INSTALL ?= cp -a
|
INSTALL ?= cp -a
|
||||||
|
|
||||||
R_CFLAGS = -fPIC -std=c89 -pedantic -Wall -Werror -Wstrict-prototypes -Wwrite-strings -Wshadow -Winit-self -Wcast-align -Wformat=2 -Wmissing-prototypes -Wstrict-overflow=2 -Wcast-qual -Wc++-compat $(CFLAGS)
|
R_CFLAGS = -fPIC -std=c89 -pedantic -Wall -Werror -Wstrict-prototypes -Wwrite-strings -Wshadow -Winit-self -Wcast-align -Wformat=2 -Wmissing-prototypes -Wstrict-overflow=2 -Wcast-qual -Wc++-compat -Wundef -Wswitch-default -Wconversion -fstack-protector-strong $(CFLAGS)
|
||||||
|
|
||||||
uname := $(shell sh -c 'uname -s 2>/dev/null || echo false')
|
uname := $(shell sh -c 'uname -s 2>/dev/null || echo false')
|
||||||
|
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ You can change the build process with a list of different options that you can p
|
|||||||
* `-DENABLE_CJSON_UTILS=On`: Enable building cJSON_Utils. (off by default)
|
* `-DENABLE_CJSON_UTILS=On`: Enable building cJSON_Utils. (off by default)
|
||||||
* `-DENABLE_TARGET_EXPORT=On`: Enable the export of CMake targets. Turn off if it makes problems. (on by default)
|
* `-DENABLE_TARGET_EXPORT=On`: Enable the export of CMake targets. Turn off if it makes problems. (on by default)
|
||||||
* `-DENABLE_CUSTOM_COMPILER_FLAGS=On`: Enable custom compiler flags (currently for Clang and GCC). Turn off if it makes problems. (on by default)
|
* `-DENABLE_CUSTOM_COMPILER_FLAGS=On`: Enable custom compiler flags (currently for Clang and GCC). Turn off if it makes problems. (on by default)
|
||||||
|
* `-DENABLE_VALGRIND=On`: Run tests with [valgrind](http://valgrind.org). (off by default)
|
||||||
|
* `-DENABLE_SANITIZERS=On`: Compile cJSON with [AddressSanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer) and [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) enabled (if possible). (off by default)
|
||||||
* `-DBUILD_SHARED_LIBS=On`: Build the shared libraries. (on by default)
|
* `-DBUILD_SHARED_LIBS=On`: Build the shared libraries. (on by default)
|
||||||
* `-DCMAKE_INSTALL_PREFIX=/usr`: Set a prefix for the installation.
|
* `-DCMAKE_INSTALL_PREFIX=/usr`: Set a prefix for the installation.
|
||||||
|
|
||||||
|
|||||||
@@ -28,9 +28,15 @@ extern "C"
|
|||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* project version */
|
||||||
|
#define CJSON_VERSION_MAJOR 1
|
||||||
|
#define CJSON_VERSION_MINOR 4
|
||||||
|
#define CJSON_VERSION_PATCH 1
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
/* cJSON Types: */
|
/* cJSON Types: */
|
||||||
|
#define cJSON_Invalid (0)
|
||||||
#define cJSON_False (1 << 0)
|
#define cJSON_False (1 << 0)
|
||||||
#define cJSON_True (1 << 1)
|
#define cJSON_True (1 << 1)
|
||||||
#define cJSON_NULL (1 << 2)
|
#define cJSON_NULL (1 << 2)
|
||||||
@@ -72,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())
|
||||||
@@ -161,11 +222,13 @@ extern void cJSON_Minify(char *json);
|
|||||||
#define cJSON_AddRawToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateRaw(s))
|
#define cJSON_AddRawToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateRaw(s))
|
||||||
|
|
||||||
/* 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,val) ((object) ? (object)->valueint = (object)->valuedouble = (val) : (val))
|
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
|
||||||
#define cJSON_SetNumberValue(object,val) ((object) ? (object)->valueint = (object)->valuedouble = (val) : (val))
|
/* helper for the cJSON_SetNumberValue macro */
|
||||||
|
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double 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
|
||||||
}
|
}
|
||||||
|
|||||||
+160
-106
@@ -1,16 +1,20 @@
|
|||||||
|
#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>
|
||||||
|
#pragma GCC visibility pop
|
||||||
|
|
||||||
#include "cJSON_Utils.h"
|
#include "cJSON_Utils.h"
|
||||||
|
|
||||||
static char* cJSONUtils_strdup(const char* str)
|
static unsigned char* cJSONUtils_strdup(const unsigned char* str)
|
||||||
{
|
{
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
char *copy = NULL;
|
unsigned char *copy = NULL;
|
||||||
|
|
||||||
len = strlen(str) + 1;
|
len = strlen((const char*)str) + 1;
|
||||||
if (!(copy = (char*)malloc(len)))
|
if (!(copy = (unsigned char*)malloc(len)))
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -19,7 +23,7 @@ static char* cJSONUtils_strdup(const char* str)
|
|||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cJSONUtils_strcasecmp(const char *s1, const char *s2)
|
static int cJSONUtils_strcasecmp(const unsigned char *s1, const unsigned char *s2)
|
||||||
{
|
{
|
||||||
if (!s1)
|
if (!s1)
|
||||||
{
|
{
|
||||||
@@ -29,7 +33,7 @@ static int cJSONUtils_strcasecmp(const char *s1, const char *s2)
|
|||||||
{
|
{
|
||||||
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)
|
||||||
{
|
{
|
||||||
@@ -37,17 +41,17 @@ static int cJSONUtils_strcasecmp(const char *s1, const char *s2)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
|
return tolower(*s1) - tolower(*s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* JSON Pointer implementation: */
|
/* JSON Pointer implementation: */
|
||||||
static int cJSONUtils_Pstrcasecmp(const char *a, const char *e)
|
static int cJSONUtils_Pstrcasecmp(const unsigned char *a, const unsigned char *e)
|
||||||
{
|
{
|
||||||
if (!a || !e)
|
if (!a || !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 == '~')
|
||||||
{
|
{
|
||||||
@@ -76,10 +80,10 @@ static int cJSONUtils_Pstrcasecmp(const char *a, const char *e)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cJSONUtils_PointerEncodedstrlen(const char *s)
|
static size_t cJSONUtils_PointerEncodedstrlen(const unsigned char *s)
|
||||||
{
|
{
|
||||||
int l = 0;
|
size_t l = 0;
|
||||||
for (; *s; s++, l++)
|
for (; *s; (void)s++, l++)
|
||||||
{
|
{
|
||||||
if ((*s == '~') || (*s == '/'))
|
if ((*s == '~') || (*s == '/'))
|
||||||
{
|
{
|
||||||
@@ -90,7 +94,7 @@ static int cJSONUtils_PointerEncodedstrlen(const char *s)
|
|||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cJSONUtils_PointerEncodedstrcpy(char *d, const char *s)
|
static void cJSONUtils_PointerEncodedstrcpy(unsigned char *d, const unsigned char *s)
|
||||||
{
|
{
|
||||||
for (; *s; s++)
|
for (; *s; s++)
|
||||||
{
|
{
|
||||||
@@ -113,42 +117,49 @@ static void cJSONUtils_PointerEncodedstrcpy(char *d, const char *s)
|
|||||||
*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;
|
||||||
int c = 0;
|
|
||||||
cJSON *obj = 0;
|
cJSON *obj = 0;
|
||||||
|
|
||||||
if (object == target)
|
if (object == target)
|
||||||
{
|
{
|
||||||
/* found */
|
/* found */
|
||||||
return cJSONUtils_strdup("");
|
return (char*)cJSONUtils_strdup((const unsigned char*)"");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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++)
|
||||||
{
|
{
|
||||||
char *found = 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' */
|
||||||
char *ret = (char*)malloc(strlen(found) + 23);
|
unsigned char *ret = (unsigned char*)malloc(strlen((char*)found) + 23);
|
||||||
sprintf(ret, "/%d%s", c, found); /* /<array_index><path> */
|
/* check if conversion to unsigned long is valid
|
||||||
|
* This should be eliminated at compile time by dead code elimination
|
||||||
|
* if size_t is an alias of unsigned long, or if it is bigger */
|
||||||
|
if (c > ULONG_MAX)
|
||||||
|
{
|
||||||
|
free(found);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
sprintf((char*)ret, "/%lu%s", (unsigned long)c, found); /* /<array_index><path> */
|
||||||
free(found);
|
free(found);
|
||||||
|
|
||||||
return ret;
|
return (char*)ret;
|
||||||
}
|
}
|
||||||
else if ((type & 0xFF) == cJSON_Object)
|
else if (cJSON_IsObject(object))
|
||||||
{
|
{
|
||||||
char *ret = (char*)malloc(strlen(found) + cJSONUtils_PointerEncodedstrlen(obj->string) + 2);
|
unsigned char *ret = (unsigned char*)malloc(strlen((char*)found) + cJSONUtils_PointerEncodedstrlen((unsigned char*)obj->string) + 2);
|
||||||
*ret = '/';
|
*ret = '/';
|
||||||
cJSONUtils_PointerEncodedstrcpy(ret + 1, obj->string);
|
cJSONUtils_PointerEncodedstrcpy(ret + 1, (unsigned char*)obj->string);
|
||||||
strcat(ret, found);
|
strcat((char*)ret, (char*)found);
|
||||||
free(found);
|
free(found);
|
||||||
|
|
||||||
return ret;
|
return (char*)ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reached leaf of the tree, found nothing */
|
/* reached leaf of the tree, found nothing */
|
||||||
@@ -161,31 +172,35 @@ 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))
|
||||||
{
|
{
|
||||||
int which = 0;
|
size_t which = 0;
|
||||||
/* parse array index */
|
/* parse array index */
|
||||||
while ((*pointer >= '0') && (*pointer <= '9'))
|
while ((*pointer >= '0') && (*pointer <= '9'))
|
||||||
{
|
{
|
||||||
which = (10 * which) + (*pointer++ - '0');
|
which = (10 * which) + (size_t)(*pointer++ - '0');
|
||||||
}
|
}
|
||||||
if (*pointer && (*pointer != '/'))
|
if (*pointer && (*pointer != '/'))
|
||||||
{
|
{
|
||||||
/* not end of string or new path token */
|
/* not end of string or new path token */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
object = cJSON_GetArrayItem(object, which);
|
if (which > INT_MAX)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
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. */
|
||||||
while (object && cJSONUtils_Pstrcasecmp(object->string, pointer))
|
while (object && cJSONUtils_Pstrcasecmp((unsigned char*)object->string, (const unsigned char*)pointer))
|
||||||
{
|
{
|
||||||
object = object->next;
|
object = object->next;
|
||||||
}
|
}
|
||||||
@@ -205,10 +220,15 @@ cJSON *cJSONUtils_GetPointer(cJSON *object, const char *pointer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* JSON Patch implementation. */
|
/* JSON Patch implementation. */
|
||||||
static void cJSONUtils_InplaceDecodePointerString(char *string)
|
static void cJSONUtils_InplaceDecodePointerString(unsigned char *string)
|
||||||
{
|
{
|
||||||
char *s2 = string;
|
unsigned char *s2 = string;
|
||||||
for (; *string; s2++, string++)
|
|
||||||
|
if (string == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; *string; (void)s2++, string++)
|
||||||
{
|
{
|
||||||
*s2 = (*string != '~')
|
*s2 = (*string != '~')
|
||||||
? (*string)
|
? (*string)
|
||||||
@@ -220,22 +240,29 @@ static void cJSONUtils_InplaceDecodePointerString(char *string)
|
|||||||
*s2 = '\0';
|
*s2 = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
static cJSON *cJSONUtils_PatchDetach(cJSON *object, const char *path)
|
static cJSON *cJSONUtils_PatchDetach(cJSON *object, const unsigned char *path)
|
||||||
{
|
{
|
||||||
char *parentptr = NULL;
|
unsigned char *parentptr = NULL;
|
||||||
char *childptr = NULL;
|
unsigned char *childptr = NULL;
|
||||||
cJSON *parent = NULL;
|
cJSON *parent = NULL;
|
||||||
cJSON *ret = NULL;
|
cJSON *ret = NULL;
|
||||||
|
|
||||||
/* copy path and split it in parent and child */
|
/* copy path and split it in parent and child */
|
||||||
parentptr = cJSONUtils_strdup(path);
|
parentptr = cJSONUtils_strdup(path);
|
||||||
childptr = strrchr(parentptr, '/'); /* last '/' */
|
if (parentptr == NULL) {
|
||||||
if (childptr)
|
return NULL;
|
||||||
{
|
|
||||||
/* split strings */
|
|
||||||
*childptr++ = '\0';
|
|
||||||
}
|
}
|
||||||
parent = cJSONUtils_GetPointer(object, parentptr);
|
|
||||||
|
childptr = (unsigned char*)strrchr((char*)parentptr, '/'); /* last '/' */
|
||||||
|
if (childptr == NULL)
|
||||||
|
{
|
||||||
|
free(parentptr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* split strings */
|
||||||
|
*childptr++ = '\0';
|
||||||
|
|
||||||
|
parent = cJSONUtils_GetPointer(object, (char*)parentptr);
|
||||||
cJSONUtils_InplaceDecodePointerString(childptr);
|
cJSONUtils_InplaceDecodePointerString(childptr);
|
||||||
|
|
||||||
if (!parent)
|
if (!parent)
|
||||||
@@ -243,13 +270,13 @@ static cJSON *cJSONUtils_PatchDetach(cJSON *object, const 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(childptr));
|
ret = cJSON_DetachItemFromArray(parent, atoi((char*)childptr));
|
||||||
}
|
}
|
||||||
else if ((parent->type & 0xFF) == cJSON_Object)
|
else if (cJSON_IsObject(parent))
|
||||||
{
|
{
|
||||||
ret = cJSON_DetachItemFromObject(parent, childptr);
|
ret = cJSON_DetachItemFromObject(parent, (char*)childptr);
|
||||||
}
|
}
|
||||||
free(parentptr);
|
free(parentptr);
|
||||||
|
|
||||||
@@ -259,7 +286,7 @@ static cJSON *cJSONUtils_PatchDetach(cJSON *object, const char *path)
|
|||||||
|
|
||||||
static int cJSONUtils_Compare(cJSON *a, cJSON *b)
|
static int cJSONUtils_Compare(cJSON *a, cJSON *b)
|
||||||
{
|
{
|
||||||
if ((a->type & 0xFF) != (b->type & 0xFF))
|
if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)))
|
||||||
{
|
{
|
||||||
/* mismatched type. */
|
/* mismatched type. */
|
||||||
return -1;
|
return -1;
|
||||||
@@ -273,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)
|
||||||
@@ -292,7 +319,7 @@ static int cJSONUtils_Compare(cJSON *a, cJSON *b)
|
|||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
/* compare object keys */
|
/* compare object keys */
|
||||||
if (cJSONUtils_strcasecmp(a->string, b->string))
|
if (cJSONUtils_strcasecmp((unsigned char*)a->string, (unsigned char*)b->string))
|
||||||
{
|
{
|
||||||
/* missing member */
|
/* missing member */
|
||||||
return -6;
|
return -6;
|
||||||
@@ -322,8 +349,8 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch)
|
|||||||
cJSON *value = NULL;
|
cJSON *value = NULL;
|
||||||
cJSON *parent = NULL;
|
cJSON *parent = NULL;
|
||||||
int opcode = 0;
|
int opcode = 0;
|
||||||
char *parentptr = NULL;
|
unsigned char *parentptr = NULL;
|
||||||
char *childptr = NULL;
|
unsigned char *childptr = NULL;
|
||||||
|
|
||||||
op = cJSON_GetObjectItem(patch, "op");
|
op = cJSON_GetObjectItem(patch, "op");
|
||||||
path = cJSON_GetObjectItem(patch, "path");
|
path = cJSON_GetObjectItem(patch, "path");
|
||||||
@@ -369,7 +396,7 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch)
|
|||||||
if ((opcode == 1) || (opcode == 2))
|
if ((opcode == 1) || (opcode == 2))
|
||||||
{
|
{
|
||||||
/* Get rid of old. */
|
/* Get rid of old. */
|
||||||
cJSON_Delete(cJSONUtils_PatchDetach(object, path->valuestring));
|
cJSON_Delete(cJSONUtils_PatchDetach(object, (unsigned char*)path->valuestring));
|
||||||
if (opcode == 1)
|
if (opcode == 1)
|
||||||
{
|
{
|
||||||
/* For Remove, this is job done. */
|
/* For Remove, this is job done. */
|
||||||
@@ -390,7 +417,7 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch)
|
|||||||
if (opcode == 3)
|
if (opcode == 3)
|
||||||
{
|
{
|
||||||
/* move */
|
/* move */
|
||||||
value = cJSONUtils_PatchDetach(object, from->valuestring);
|
value = cJSONUtils_PatchDetach(object, (unsigned char*)from->valuestring);
|
||||||
}
|
}
|
||||||
if (opcode == 4)
|
if (opcode == 4)
|
||||||
{
|
{
|
||||||
@@ -431,13 +458,13 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch)
|
|||||||
/* Now, just add "value" to "path". */
|
/* Now, just add "value" to "path". */
|
||||||
|
|
||||||
/* split pointer in parent and child */
|
/* split pointer in parent and child */
|
||||||
parentptr = cJSONUtils_strdup(path->valuestring);
|
parentptr = cJSONUtils_strdup((unsigned char*)path->valuestring);
|
||||||
childptr = strrchr(parentptr, '/');
|
childptr = (unsigned char*)strrchr((char*)parentptr, '/');
|
||||||
if (childptr)
|
if (childptr)
|
||||||
{
|
{
|
||||||
*childptr++ = '\0';
|
*childptr++ = '\0';
|
||||||
}
|
}
|
||||||
parent = cJSONUtils_GetPointer(object, parentptr);
|
parent = cJSONUtils_GetPointer(object, (char*)parentptr);
|
||||||
cJSONUtils_InplaceDecodePointerString(childptr);
|
cJSONUtils_InplaceDecodePointerString(childptr);
|
||||||
|
|
||||||
/* add, remove, replace, move, copy, test. */
|
/* add, remove, replace, move, copy, test. */
|
||||||
@@ -448,21 +475,21 @@ 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(childptr, "-"))
|
if (!strcmp((char*)childptr, "-"))
|
||||||
{
|
{
|
||||||
cJSON_AddItemToArray(parent, value);
|
cJSON_AddItemToArray(parent, value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cJSON_InsertItemInArray(parent, atoi(childptr), value);
|
cJSON_InsertItemInArray(parent, atoi((char*)childptr), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((parent->type & 0xFF) == cJSON_Object)
|
else if (cJSON_IsObject(parent))
|
||||||
{
|
{
|
||||||
cJSON_DeleteItemFromObject(parent, childptr);
|
cJSON_DeleteItemFromObject(parent, (char*)childptr);
|
||||||
cJSON_AddItemToObject(parent, childptr, value);
|
cJSON_AddItemToObject(parent, (char*)childptr, value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -473,10 +500,16 @@ 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;
|
||||||
if ((patches->type & 0xFF) != cJSON_Array)
|
|
||||||
|
if (patches == NULL)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cJSON_IsArray(patches))
|
||||||
{
|
{
|
||||||
/* malformed patches. */
|
/* malformed patches. */
|
||||||
return 1;
|
return 1;
|
||||||
@@ -497,20 +530,20 @@ int cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cJSONUtils_GeneratePatch(cJSON *patches, const char *op, const char *path, const char *suffix, cJSON *val)
|
static void cJSONUtils_GeneratePatch(cJSON *patches, const unsigned char *op, const unsigned char *path, const unsigned char *suffix, cJSON *val)
|
||||||
{
|
{
|
||||||
cJSON *patch = cJSON_CreateObject();
|
cJSON *patch = cJSON_CreateObject();
|
||||||
cJSON_AddItemToObject(patch, "op", cJSON_CreateString(op));
|
cJSON_AddItemToObject(patch, "op", cJSON_CreateString((const char*)op));
|
||||||
if (suffix)
|
if (suffix)
|
||||||
{
|
{
|
||||||
char *newpath = (char*)malloc(strlen(path) + cJSONUtils_PointerEncodedstrlen(suffix) + 2);
|
unsigned char *newpath = (unsigned char*)malloc(strlen((const char*)path) + cJSONUtils_PointerEncodedstrlen(suffix) + 2);
|
||||||
cJSONUtils_PointerEncodedstrcpy(newpath + sprintf(newpath, "%s/", path), suffix);
|
cJSONUtils_PointerEncodedstrcpy(newpath + sprintf((char*)newpath, "%s/", (const char*)path), suffix);
|
||||||
cJSON_AddItemToObject(patch, "path", cJSON_CreateString(newpath));
|
cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)newpath));
|
||||||
free(newpath);
|
free(newpath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cJSON_AddItemToObject(patch, "path", cJSON_CreateString(path));
|
cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)path));
|
||||||
}
|
}
|
||||||
if (val)
|
if (val)
|
||||||
{
|
{
|
||||||
@@ -519,16 +552,21 @@ static void cJSONUtils_GeneratePatch(cJSON *patches, const char *op, const char
|
|||||||
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, op, path, 0, val);
|
cJSONUtils_GeneratePatch(array, (const unsigned char*)op, (const unsigned char*)path, 0, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cJSONUtils_CompareToPatch(cJSON *patches, const char *path, cJSON *from, cJSON *to)
|
static void cJSONUtils_CompareToPatch(cJSON *patches, const unsigned char *path, cJSON *from, cJSON *to)
|
||||||
{
|
{
|
||||||
|
if ((from == NULL) || (to == NULL))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ((from->type & 0xFF) != (to->type & 0xFF))
|
if ((from->type & 0xFF) != (to->type & 0xFF))
|
||||||
{
|
{
|
||||||
cJSONUtils_GeneratePatch(patches, "replace", path, 0, to);
|
cJSONUtils_GeneratePatch(patches, (const unsigned char*)"replace", path, 0, to);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -537,37 +575,53 @@ static void cJSONUtils_CompareToPatch(cJSON *patches, const char *path, cJSON *f
|
|||||||
case cJSON_Number:
|
case cJSON_Number:
|
||||||
if ((from->valueint != to->valueint) || (from->valuedouble != to->valuedouble))
|
if ((from->valueint != to->valueint) || (from->valuedouble != to->valuedouble))
|
||||||
{
|
{
|
||||||
cJSONUtils_GeneratePatch(patches, "replace", path, 0, to);
|
cJSONUtils_GeneratePatch(patches, (const unsigned char*)"replace", path, 0, to);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case cJSON_String:
|
case cJSON_String:
|
||||||
if (strcmp(from->valuestring, to->valuestring) != 0)
|
if (strcmp(from->valuestring, to->valuestring) != 0)
|
||||||
{
|
{
|
||||||
cJSONUtils_GeneratePatch(patches, "replace", path, 0, to);
|
cJSONUtils_GeneratePatch(patches, (const unsigned char*)"replace", path, 0, to);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case cJSON_Array:
|
case cJSON_Array:
|
||||||
{
|
{
|
||||||
int c = 0;
|
size_t c = 0;
|
||||||
char *newpath = (char*)malloc(strlen(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++)
|
||||||
{
|
{
|
||||||
sprintf(newpath, "%s/%d", path, c); /* path of the current array element */
|
/* check if conversion to unsigned long is valid
|
||||||
|
* This should be eliminated at compile time by dead code elimination
|
||||||
|
* if size_t is an alias of unsigned long, or if it is bigger */
|
||||||
|
if (c > ULONG_MAX)
|
||||||
|
{
|
||||||
|
free(newpath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sprintf((char*)newpath, "%s/%lu", path, (unsigned long)c); /* path of the current array element */
|
||||||
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++)
|
||||||
{
|
{
|
||||||
sprintf(newpath, "%d", c);
|
/* check if conversion to unsigned long is valid
|
||||||
cJSONUtils_GeneratePatch(patches, "remove", path, newpath, 0);
|
* This should be eliminated at compile time by dead code elimination
|
||||||
|
* if size_t is an alias of unsigned long, or if it is bigger */
|
||||||
|
if (c > ULONG_MAX)
|
||||||
|
{
|
||||||
|
free(newpath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sprintf((char*)newpath, "%lu", (unsigned long)c);
|
||||||
|
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, "add", path, "-", to);
|
cJSONUtils_GeneratePatch(patches, (const unsigned char*)"add", path, (const unsigned char*)"-", to);
|
||||||
}
|
}
|
||||||
free(newpath);
|
free(newpath);
|
||||||
return;
|
return;
|
||||||
@@ -585,12 +639,12 @@ static void cJSONUtils_CompareToPatch(cJSON *patches, const char *path, cJSON *f
|
|||||||
/* for all object values in the object with more of them */
|
/* for all object values in the object with more of them */
|
||||||
while (a || b)
|
while (a || b)
|
||||||
{
|
{
|
||||||
int diff = (!a) ? 1 : ((!b) ? -1 : cJSONUtils_strcasecmp(a->string, b->string));
|
int diff = (!a) ? 1 : ((!b) ? -1 : cJSONUtils_strcasecmp((unsigned char*)a->string, (unsigned char*)b->string));
|
||||||
if (!diff)
|
if (!diff)
|
||||||
{
|
{
|
||||||
/* both object keys are the same */
|
/* both object keys are the same */
|
||||||
char *newpath = (char*)malloc(strlen(path) + cJSONUtils_PointerEncodedstrlen(a->string) + 2);
|
unsigned char *newpath = (unsigned char*)malloc(strlen((const char*)path) + cJSONUtils_PointerEncodedstrlen((unsigned char*)a->string) + 2);
|
||||||
cJSONUtils_PointerEncodedstrcpy(newpath + sprintf(newpath, "%s/", path), a->string);
|
cJSONUtils_PointerEncodedstrcpy(newpath + sprintf((char*)newpath, "%s/", path), (unsigned char*)a->string);
|
||||||
/* create a patch for the element */
|
/* create a patch for the element */
|
||||||
cJSONUtils_CompareToPatch(patches, newpath, a, b);
|
cJSONUtils_CompareToPatch(patches, newpath, a, b);
|
||||||
free(newpath);
|
free(newpath);
|
||||||
@@ -600,13 +654,13 @@ static void cJSONUtils_CompareToPatch(cJSON *patches, const char *path, cJSON *f
|
|||||||
else if (diff < 0)
|
else if (diff < 0)
|
||||||
{
|
{
|
||||||
/* object element doesn't exist in 'to' --> remove it */
|
/* object element doesn't exist in 'to' --> remove it */
|
||||||
cJSONUtils_GeneratePatch(patches, "remove", path, a->string, 0);
|
cJSONUtils_GeneratePatch(patches, (const unsigned char*)"remove", path, (unsigned char*)a->string, 0);
|
||||||
a = a->next;
|
a = a->next;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* object element doesn't exist in 'from' --> add it */
|
/* object element doesn't exist in 'from' --> add it */
|
||||||
cJSONUtils_GeneratePatch(patches, "add", path, b->string, b);
|
cJSONUtils_GeneratePatch(patches, (const unsigned char*)"add", path, (unsigned char*)b->string, b);
|
||||||
b = b->next;
|
b = b->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -618,10 +672,10 @@ static void cJSONUtils_CompareToPatch(cJSON *patches, const char *path, cJSON *f
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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, "", from, to);
|
cJSONUtils_CompareToPatch(patches, (const unsigned char*)"", from, to);
|
||||||
|
|
||||||
return patches;
|
return patches;
|
||||||
}
|
}
|
||||||
@@ -639,7 +693,7 @@ static cJSON *cJSONUtils_SortList(cJSON *list)
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (ptr && ptr->next && (cJSONUtils_strcasecmp(ptr->string, ptr->next->string) < 0))
|
while (ptr && ptr->next && (cJSONUtils_strcasecmp((unsigned char*)ptr->string, (unsigned char*)ptr->next->string) < 0))
|
||||||
{
|
{
|
||||||
/* Test for list sorted. */
|
/* Test for list sorted. */
|
||||||
ptr = ptr->next;
|
ptr = ptr->next;
|
||||||
@@ -676,7 +730,7 @@ static cJSON *cJSONUtils_SortList(cJSON *list)
|
|||||||
|
|
||||||
while (first && second) /* Merge the sub-lists */
|
while (first && second) /* Merge the sub-lists */
|
||||||
{
|
{
|
||||||
if (cJSONUtils_strcasecmp(first->string, second->string) < 0)
|
if (cJSONUtils_strcasecmp((unsigned char*)first->string, (unsigned char*)second->string) < 0)
|
||||||
{
|
{
|
||||||
if (!list)
|
if (!list)
|
||||||
{
|
{
|
||||||
@@ -733,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();
|
||||||
@@ -756,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);
|
||||||
@@ -771,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)
|
||||||
@@ -779,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);
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-8
@@ -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);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
afl-build
|
||||||
@@ -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()
|
||||||
Executable
+5
@@ -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
@@ -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;
|
||||||
|
}
|
||||||
Executable
+9
@@ -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
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
bf["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
bf{
|
||||||
|
"name": "Jack (\"Bee\") Nimble",
|
||||||
|
"format": {"type": "rect",
|
||||||
|
"width": 1920,
|
||||||
|
"height": 1080,
|
||||||
|
"interlace": false,"frame rate": 24
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
bf{"menu": {
|
||||||
|
"id": "file",
|
||||||
|
"value": "File",
|
||||||
|
"popup": {
|
||||||
|
"menuitem": [
|
||||||
|
{"value": "New", "onclick": "CreateNewDoc()"},
|
||||||
|
{"value": "Open", "onclick": "OpenDoc()"},
|
||||||
|
{"value": "Close", "onclick": "CloseDoc()"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}
|
||||||
@@ -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;"
|
||||||
|
}
|
||||||
|
}}
|
||||||
@@ -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;"
|
||||||
|
}
|
||||||
|
}}
|
||||||
@@ -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;"
|
||||||
|
}
|
||||||
|
}}
|
||||||
@@ -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;"
|
||||||
|
}
|
||||||
|
}}
|
||||||
@@ -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"}}}
|
||||||
@@ -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..."}
|
||||||
|
]
|
||||||
|
}}
|
||||||
@@ -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>
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -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]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
bf[
|
||||||
|
[0, -1, 0],
|
||||||
|
[1, 0, 0],
|
||||||
|
[0, 0, 1]
|
||||||
|
]
|
||||||
@@ -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"
|
||||||
@@ -25,57 +25,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "cJSON.h"
|
#include "cJSON.h"
|
||||||
|
|
||||||
/* Parse text to JSON, then render back to text, and print! */
|
|
||||||
static void doit(char *text)
|
|
||||||
{
|
|
||||||
char *out = NULL;
|
|
||||||
cJSON *json = NULL;
|
|
||||||
|
|
||||||
json = cJSON_Parse(text);
|
|
||||||
if (!json)
|
|
||||||
{
|
|
||||||
printf("Error before: [%s]\n", cJSON_GetErrorPtr());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
out = cJSON_Print(json);
|
|
||||||
cJSON_Delete(json);
|
|
||||||
printf("%s\n", out);
|
|
||||||
free(out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* Read a file, parse, render back, etc. */
|
|
||||||
static void dofile(char *filename)
|
|
||||||
{
|
|
||||||
FILE *f = NULL;
|
|
||||||
long len = 0;
|
|
||||||
char *data = NULL;
|
|
||||||
|
|
||||||
/* open in read binary mode */
|
|
||||||
f = fopen(filename,"rb");
|
|
||||||
/* get the length */
|
|
||||||
fseek(f, 0, SEEK_END);
|
|
||||||
len = ftell(f);
|
|
||||||
fseek(f, 0, SEEK_SET);
|
|
||||||
|
|
||||||
data = (char*)malloc(len + 1);
|
|
||||||
if (data == NULL)
|
|
||||||
{
|
|
||||||
printf("Failed to allocate memory.\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fread(data, 1, len, f);
|
|
||||||
data[len] = '\0';
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
doit(data);
|
|
||||||
free(data);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Used by some code below as an example datatype. */
|
/* Used by some code below as an example datatype. */
|
||||||
struct record
|
struct record
|
||||||
{
|
{
|
||||||
@@ -97,8 +46,8 @@ static int print_preallocated(cJSON *root)
|
|||||||
char *out = NULL;
|
char *out = NULL;
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
char *buf_fail = NULL;
|
char *buf_fail = NULL;
|
||||||
int len = 0;
|
size_t len = 0;
|
||||||
int len_fail = 0;
|
size_t len_fail = 0;
|
||||||
|
|
||||||
/* formatted print */
|
/* formatted print */
|
||||||
out = cJSON_Print(root);
|
out = cJSON_Print(root);
|
||||||
@@ -123,7 +72,7 @@ static int print_preallocated(cJSON *root)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Print to buffer */
|
/* Print to buffer */
|
||||||
if (!cJSON_PrintPreallocated(root, buf, len, 1)) {
|
if (!cJSON_PrintPreallocated(root, buf, (int)len, 1)) {
|
||||||
printf("cJSON_PrintPreallocated failed!\n");
|
printf("cJSON_PrintPreallocated failed!\n");
|
||||||
if (strcmp(out, buf) != 0) {
|
if (strcmp(out, buf) != 0) {
|
||||||
printf("cJSON_PrintPreallocated not the same as cJSON_Print!\n");
|
printf("cJSON_PrintPreallocated not the same as cJSON_Print!\n");
|
||||||
@@ -140,7 +89,7 @@ static int print_preallocated(cJSON *root)
|
|||||||
printf("%s\n", buf);
|
printf("%s\n", buf);
|
||||||
|
|
||||||
/* force it to fail */
|
/* force it to fail */
|
||||||
if (cJSON_PrintPreallocated(root, buf_fail, len_fail, 1)) {
|
if (cJSON_PrintPreallocated(root, buf_fail, (int)len_fail, 1)) {
|
||||||
printf("cJSON_PrintPreallocated failed to show error with insufficient memory!\n");
|
printf("cJSON_PrintPreallocated failed to show error with insufficient memory!\n");
|
||||||
printf("cJSON_Print result:\n%s\n", out);
|
printf("cJSON_Print result:\n%s\n", out);
|
||||||
printf("cJSON_PrintPreallocated result:\n%s\n", buf_fail);
|
printf("cJSON_PrintPreallocated result:\n%s\n", buf_fail);
|
||||||
@@ -309,94 +258,8 @@ static void create_objects(void)
|
|||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
/* a bunch of json: */
|
/* print the version */
|
||||||
char text1[] =
|
printf("Version: %s\n", cJSON_Version());
|
||||||
"{\n"
|
|
||||||
"\"name\": \"Jack (\\\"Bee\\\") Nimble\", \n"
|
|
||||||
"\"format\": {\"type\": \"rect\", \n"
|
|
||||||
"\"width\": 1920, \n"
|
|
||||||
"\"height\": 1080, \n"
|
|
||||||
"\"interlace\": false,\"frame rate\": 24\n"
|
|
||||||
"}\n"
|
|
||||||
"}";
|
|
||||||
char text2[] = "[\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"]";
|
|
||||||
char text3[] =
|
|
||||||
"[\n"
|
|
||||||
" [0, -1, 0],\n"
|
|
||||||
" [1, 0, 0],\n"
|
|
||||||
" [0, 0, 1]\n"
|
|
||||||
"\t]\n";
|
|
||||||
char text4[] =
|
|
||||||
"{\n"
|
|
||||||
"\t\t\"Image\": {\n"
|
|
||||||
"\t\t\t\"Width\": 800,\n"
|
|
||||||
"\t\t\t\"Height\": 600,\n"
|
|
||||||
"\t\t\t\"Title\": \"View from 15th Floor\",\n"
|
|
||||||
"\t\t\t\"Thumbnail\": {\n"
|
|
||||||
"\t\t\t\t\"Url\": \"http:/*www.example.com/image/481989943\",\n"
|
|
||||||
"\t\t\t\t\"Height\": 125,\n"
|
|
||||||
"\t\t\t\t\"Width\": \"100\"\n"
|
|
||||||
"\t\t\t},\n"
|
|
||||||
"\t\t\t\"IDs\": [116, 943, 234, 38793]\n"
|
|
||||||
"\t\t}\n"
|
|
||||||
"\t}";
|
|
||||||
char text5[] =
|
|
||||||
"[\n"
|
|
||||||
"\t {\n"
|
|
||||||
"\t \"precision\": \"zip\",\n"
|
|
||||||
"\t \"Latitude\": 37.7668,\n"
|
|
||||||
"\t \"Longitude\": -122.3959,\n"
|
|
||||||
"\t \"Address\": \"\",\n"
|
|
||||||
"\t \"City\": \"SAN FRANCISCO\",\n"
|
|
||||||
"\t \"State\": \"CA\",\n"
|
|
||||||
"\t \"Zip\": \"94107\",\n"
|
|
||||||
"\t \"Country\": \"US\"\n"
|
|
||||||
"\t },\n"
|
|
||||||
"\t {\n"
|
|
||||||
"\t \"precision\": \"zip\",\n"
|
|
||||||
"\t \"Latitude\": 37.371991,\n"
|
|
||||||
"\t \"Longitude\": -122.026020,\n"
|
|
||||||
"\t \"Address\": \"\",\n"
|
|
||||||
"\t \"City\": \"SUNNYVALE\",\n"
|
|
||||||
"\t \"State\": \"CA\",\n"
|
|
||||||
"\t \"Zip\": \"94085\",\n"
|
|
||||||
"\t \"Country\": \"US\"\n"
|
|
||||||
"\t }\n"
|
|
||||||
"\t ]";
|
|
||||||
|
|
||||||
char text6[] =
|
|
||||||
"<!DOCTYPE html>"
|
|
||||||
"<html>\n"
|
|
||||||
"<head>\n"
|
|
||||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n"
|
|
||||||
" <style type=\"text/css\">\n"
|
|
||||||
" html, body, iframe { margin: 0; padding: 0; height: 100%; }\n"
|
|
||||||
" iframe { display: block; width: 100%; border: none; }\n"
|
|
||||||
" </style>\n"
|
|
||||||
"<title>Application Error</title>\n"
|
|
||||||
"</head>\n"
|
|
||||||
"<body>\n"
|
|
||||||
" <iframe src=\"//s3.amazonaws.com/heroku_pages/error.html\">\n"
|
|
||||||
" <p>Application Error</p>\n"
|
|
||||||
" </iframe>\n"
|
|
||||||
"</body>\n"
|
|
||||||
"</html>\n";
|
|
||||||
|
|
||||||
/* Process each json textblock by parsing, then rebuilding: */
|
|
||||||
doit(text1);
|
|
||||||
doit(text2);
|
|
||||||
doit(text3);
|
|
||||||
doit(text4);
|
|
||||||
doit(text5);
|
|
||||||
doit(text6);
|
|
||||||
|
|
||||||
/* Parse standard testfiles: */
|
|
||||||
/* dofile("../../tests/test1"); */
|
|
||||||
/* dofile("../../tests/test2"); */
|
|
||||||
/* dofile("../../tests/test3"); */
|
|
||||||
/* dofile("../../tests/test4"); */
|
|
||||||
/* dofile("../../tests/test5"); */
|
|
||||||
/* dofile("../../tests/test6"); */
|
|
||||||
|
|
||||||
/* Now some samplecode for building objects concisely: */
|
/* Now some samplecode for building objects concisely: */
|
||||||
create_objects();
|
create_objects();
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
if(ENABLE_CJSON_TEST)
|
||||||
|
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
|
||||||
|
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/inputs")
|
||||||
|
file(GLOB test_files "inputs/*")
|
||||||
|
file(COPY ${test_files} DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/inputs/")
|
||||||
|
|
||||||
|
set(unity_tests
|
||||||
|
parse_examples
|
||||||
|
parse_number
|
||||||
|
parse_hex4
|
||||||
|
parse_string
|
||||||
|
parse_array
|
||||||
|
parse_object
|
||||||
|
parse_value
|
||||||
|
print_string
|
||||||
|
print_number
|
||||||
|
print_array
|
||||||
|
print_object
|
||||||
|
print_value
|
||||||
|
misc_tests
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(test-common common.c)
|
||||||
|
|
||||||
|
option(ENABLE_VALGRIND OFF "Enable the valgrind memory checker for the tests.")
|
||||||
|
if (ENABLE_VALGRIND)
|
||||||
|
find_program(MEMORYCHECK_COMMAND valgrind)
|
||||||
|
if ("${MEMORYCHECK_COMMAND}" MATCHES "MEMORYCHECK_COMMAND-NOTFOUND")
|
||||||
|
message(WARNING "Valgrind couldn't be found.")
|
||||||
|
unset(MEMORYCHECK_COMMAND)
|
||||||
|
else()
|
||||||
|
set(MEMORYCHECK_COMMAND_OPTIONS --trace-children=yes --leak-check=full --error-exitcode=1)
|
||||||
|
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})
|
||||||
|
add_executable("${unity_test}" "${unity_test}.c")
|
||||||
|
target_link_libraries("${unity_test}" "${CJSON_LIB}" unity test-common)
|
||||||
|
if(MEMORYCHECK_COMMAND)
|
||||||
|
add_test(NAME "${unity_test}"
|
||||||
|
COMMAND "${MEMORYCHECK_COMMAND}" ${MEMORYCHECK_COMMAND_OPTIONS} "./${unity_test}")
|
||||||
|
else()
|
||||||
|
add_test(NAME "${unity_test}"
|
||||||
|
COMMAND "./${unity_test}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
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 "common.h"
|
||||||
|
|
||||||
|
CJSON_PUBLIC(void) reset(cJSON *item)
|
||||||
|
{
|
||||||
|
if ((item != NULL) && (item->child != NULL))
|
||||||
|
{
|
||||||
|
cJSON_Delete(item->child);
|
||||||
|
}
|
||||||
|
if ((item->valuestring != NULL) && !(item->type & cJSON_IsReference))
|
||||||
|
{
|
||||||
|
global_hooks.deallocate(item->valuestring);
|
||||||
|
}
|
||||||
|
if ((item->string != NULL) && !(item->type & cJSON_StringIsConst))
|
||||||
|
{
|
||||||
|
global_hooks.deallocate(item->string);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(item, 0, sizeof(cJSON));
|
||||||
|
}
|
||||||
|
|
||||||
|
CJSON_PUBLIC(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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CJSON_TESTS_COMMON_H
|
||||||
|
#define CJSON_TESTS_COMMON_H
|
||||||
|
|
||||||
|
#include "../cJSON.c"
|
||||||
|
|
||||||
|
CJSON_PUBLIC(void) reset(cJSON *item);
|
||||||
|
CJSON_PUBLIC(char*) read_file(const char *filename);
|
||||||
|
|
||||||
|
/* 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_no_reference(item) TEST_ASSERT_BITS_MESSAGE(cJSON_IsReference, 0, item->type, "Item should not have a string as reference.")
|
||||||
|
#define assert_has_no_const_string(item) TEST_ASSERT_BITS_MESSAGE(cJSON_StringIsConst, 0, item->type, "Item should not have a const string.")
|
||||||
|
#define assert_has_valuestring(item) TEST_ASSERT_NOT_NULL_MESSAGE(item->valuestring, "Valuestring is NULL.")
|
||||||
|
#define assert_has_no_valuestring(item) TEST_ASSERT_NULL_MESSAGE(item->valuestring, "Valuestring is not NULL.")
|
||||||
|
#define assert_has_string(item) TEST_ASSERT_NOT_NULL_MESSAGE(item->string, "String is NULL")
|
||||||
|
#define assert_has_no_string(item) TEST_ASSERT_NULL_MESSAGE(item->string, "String is not NULL.")
|
||||||
|
#define assert_not_in_list(item) \
|
||||||
|
TEST_ASSERT_NULL_MESSAGE(item->next, "Linked list next pointer is not NULL.");\
|
||||||
|
TEST_ASSERT_NULL_MESSAGE(item->prev, "Linked list previous pointer is not NULL.")
|
||||||
|
#define assert_has_child(item) TEST_ASSERT_NOT_NULL_MESSAGE(item->child, "Item doesn't have a child.")
|
||||||
|
#define assert_has_no_child(item) TEST_ASSERT_NULL_MESSAGE(item->child, "Item has a child.")
|
||||||
|
#define assert_is_invalid(item) \
|
||||||
|
assert_has_type(item, cJSON_Invalid);\
|
||||||
|
assert_not_in_list(item);\
|
||||||
|
assert_has_no_child(item);\
|
||||||
|
assert_has_no_string(item);\
|
||||||
|
assert_has_no_valuestring(item)
|
||||||
|
|
||||||
|
#endif
|
||||||
File renamed without changes.
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"name": "Jack (\"Bee\") Nimble",
|
||||||
|
"format": {"type": "rect",
|
||||||
|
"width": 1920,
|
||||||
|
"height": 1080,
|
||||||
|
"interlace": false,"frame rate": 24
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Jack (\"Bee\") Nimble",
|
||||||
|
"format": {
|
||||||
|
"type": "rect",
|
||||||
|
"width": 1920,
|
||||||
|
"height": 1080,
|
||||||
|
"interlace": false,
|
||||||
|
"frame rate": 24
|
||||||
|
}
|
||||||
|
}
|
||||||
File renamed without changes.
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"menu": {
|
||||||
|
"id": "file",
|
||||||
|
"value": "File",
|
||||||
|
"popup": {
|
||||||
|
"menuitem": [{
|
||||||
|
"value": "New",
|
||||||
|
"onclick": "CreateNewDoc()"
|
||||||
|
}, {
|
||||||
|
"value": "Open",
|
||||||
|
"onclick": "OpenDoc()"
|
||||||
|
}, {
|
||||||
|
"value": "Close",
|
||||||
|
"onclick": "CloseDoc()"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File renamed without changes.
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"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;"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File renamed without changes.
@@ -0,0 +1,94 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File renamed without changes.
@@ -0,0 +1,54 @@
|
|||||||
|
{
|
||||||
|
"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..."
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
File renamed without changes.
@@ -0,0 +1,22 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
[{
|
||||||
|
"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.02602,
|
||||||
|
"Address": "",
|
||||||
|
"City": "SUNNYVALE",
|
||||||
|
"State": "CA",
|
||||||
|
"Zip": "94085",
|
||||||
|
"Country": "US"
|
||||||
|
}]
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"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]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"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]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
[0, -1, 0],
|
||||||
|
[1, 0, 0],
|
||||||
|
[0, 0, 1]
|
||||||
|
]
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
[[0, -1, 0], [1, 0, 0], [0, 0, 1]]
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
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 cJSON item[1];
|
||||||
|
|
||||||
|
static const unsigned char *error_pointer = NULL;
|
||||||
|
|
||||||
|
static void assert_is_array(cJSON *array_item)
|
||||||
|
{
|
||||||
|
TEST_ASSERT_NOT_NULL_MESSAGE(array_item, "Item is NULL.");
|
||||||
|
|
||||||
|
assert_not_in_list(array_item);
|
||||||
|
assert_has_type(array_item, cJSON_Array);
|
||||||
|
assert_has_no_reference(array_item);
|
||||||
|
assert_has_no_const_string(array_item);
|
||||||
|
assert_has_no_valuestring(array_item);
|
||||||
|
assert_has_no_string(array_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assert_not_array(const char *json)
|
||||||
|
{
|
||||||
|
TEST_ASSERT_NULL(parse_array(item, (const unsigned char*)json, &error_pointer, &global_hooks));
|
||||||
|
assert_is_invalid(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assert_parse_array(const char *json)
|
||||||
|
{
|
||||||
|
TEST_ASSERT_NOT_NULL(parse_array(item, (const unsigned char*)json, &error_pointer, &global_hooks));
|
||||||
|
assert_is_array(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_array_should_parse_empty_arrays(void)
|
||||||
|
{
|
||||||
|
assert_parse_array("[]");
|
||||||
|
assert_has_no_child(item);
|
||||||
|
|
||||||
|
assert_parse_array("[\n\t]");
|
||||||
|
assert_has_no_child(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void parse_array_should_parse_arrays_with_one_element(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
assert_parse_array("[1]");
|
||||||
|
assert_has_child(item);
|
||||||
|
assert_has_type(item->child, cJSON_Number);
|
||||||
|
reset(item);
|
||||||
|
|
||||||
|
assert_parse_array("[\"hello!\"]");
|
||||||
|
assert_has_child(item);
|
||||||
|
assert_has_type(item->child, cJSON_String);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("hello!", item->child->valuestring);
|
||||||
|
reset(item);
|
||||||
|
|
||||||
|
assert_parse_array("[[]]");
|
||||||
|
assert_has_child(item);
|
||||||
|
assert_is_array(item->child);
|
||||||
|
assert_has_no_child(item->child);
|
||||||
|
reset(item);
|
||||||
|
|
||||||
|
assert_parse_array("[null]");
|
||||||
|
assert_has_child(item);
|
||||||
|
assert_has_type(item->child, cJSON_NULL);
|
||||||
|
reset(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_array_should_parse_arrays_with_multiple_elements(void)
|
||||||
|
{
|
||||||
|
assert_parse_array("[1\t,\n2, 3]");
|
||||||
|
assert_has_child(item);
|
||||||
|
TEST_ASSERT_NOT_NULL(item->child->next);
|
||||||
|
TEST_ASSERT_NOT_NULL(item->child->next->next);
|
||||||
|
TEST_ASSERT_NULL(item->child->next->next->next);
|
||||||
|
assert_has_type(item->child, cJSON_Number);
|
||||||
|
assert_has_type(item->child->next, cJSON_Number);
|
||||||
|
assert_has_type(item->child->next->next, cJSON_Number);
|
||||||
|
reset(item);
|
||||||
|
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
cJSON *node = NULL;
|
||||||
|
int expected_types[7] =
|
||||||
|
{
|
||||||
|
cJSON_Number,
|
||||||
|
cJSON_NULL,
|
||||||
|
cJSON_True,
|
||||||
|
cJSON_False,
|
||||||
|
cJSON_Array,
|
||||||
|
cJSON_String,
|
||||||
|
cJSON_Object
|
||||||
|
};
|
||||||
|
assert_parse_array("[1, null, true, false, [], \"hello\", {}]");
|
||||||
|
|
||||||
|
node = item->child;
|
||||||
|
for (
|
||||||
|
i = 0;
|
||||||
|
(i < (sizeof(expected_types)/sizeof(int)))
|
||||||
|
&& (node != NULL);
|
||||||
|
(void)i++, node = node->next)
|
||||||
|
{
|
||||||
|
TEST_ASSERT_BITS(0xFF, expected_types[i], node->type);
|
||||||
|
}
|
||||||
|
TEST_ASSERT_EQUAL_INT(i, 7);
|
||||||
|
reset(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_array_should_not_parse_non_arrays(void)
|
||||||
|
{
|
||||||
|
assert_not_array("");
|
||||||
|
assert_not_array("[");
|
||||||
|
assert_not_array("]");
|
||||||
|
assert_not_array("{\"hello\":[]}");
|
||||||
|
assert_not_array("42");
|
||||||
|
assert_not_array("3.14");
|
||||||
|
assert_not_array("\"[]hello world!\n\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
/* initialize cJSON item */
|
||||||
|
memset(item, 0, sizeof(cJSON));
|
||||||
|
|
||||||
|
UNITY_BEGIN();
|
||||||
|
RUN_TEST(parse_array_should_parse_empty_arrays);
|
||||||
|
RUN_TEST(parse_array_should_parse_arrays_with_one_element);
|
||||||
|
RUN_TEST(parse_array_should_parse_arrays_with_multiple_elements);
|
||||||
|
RUN_TEST(parse_array_should_not_parse_non_arrays);
|
||||||
|
return UNITY_END();
|
||||||
|
}
|
||||||
@@ -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 cJSON *parse_file(const char *filename)
|
||||||
|
{
|
||||||
|
cJSON *parsed = NULL;
|
||||||
|
char *content = read_file(filename);
|
||||||
|
|
||||||
|
parsed = cJSON_Parse(content);
|
||||||
|
|
||||||
|
if (content != NULL)
|
||||||
|
{
|
||||||
|
free(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_test(const char *test_name)
|
||||||
|
{
|
||||||
|
char *expected = NULL;
|
||||||
|
char *actual = NULL;
|
||||||
|
cJSON *tree = NULL;
|
||||||
|
|
||||||
|
size_t test_name_length = 0;
|
||||||
|
/* path of the test input */
|
||||||
|
char *test_path = NULL;
|
||||||
|
/* path of the expected output */
|
||||||
|
char *expected_path = NULL;
|
||||||
|
|
||||||
|
test_name_length = strlen(test_name);
|
||||||
|
|
||||||
|
/* allocate file paths */
|
||||||
|
#define TEST_DIR_PATH "inputs/"
|
||||||
|
test_path = (char*)malloc(sizeof(TEST_DIR_PATH) + test_name_length);
|
||||||
|
TEST_ASSERT_NOT_NULL_MESSAGE(test_path, "Failed to allocate test_path buffer.");
|
||||||
|
expected_path = (char*)malloc(sizeof(TEST_DIR_PATH) + test_name_length + sizeof(".expected"));
|
||||||
|
TEST_ASSERT_NOT_NULL_MESSAGE(expected_path, "Failed to allocate expected_path buffer.");
|
||||||
|
|
||||||
|
/* create file paths */
|
||||||
|
sprintf(test_path, TEST_DIR_PATH"%s", test_name);
|
||||||
|
sprintf(expected_path, TEST_DIR_PATH"%s.expected", test_name);
|
||||||
|
|
||||||
|
/* read expected output */
|
||||||
|
expected = read_file(expected_path);
|
||||||
|
TEST_ASSERT_NOT_NULL_MESSAGE(expected, "Failed to read expected output.");
|
||||||
|
|
||||||
|
/* read and parse test */
|
||||||
|
tree = parse_file(test_path);
|
||||||
|
TEST_ASSERT_NOT_NULL_MESSAGE(tree, "Failed to read of parse test.");
|
||||||
|
|
||||||
|
/* print the parsed tree */
|
||||||
|
actual = cJSON_Print(tree);
|
||||||
|
TEST_ASSERT_NOT_NULL_MESSAGE(actual, "Failed to print tree back to JSON.");
|
||||||
|
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING(expected, actual);
|
||||||
|
|
||||||
|
/* cleanup resources */
|
||||||
|
if (expected != NULL)
|
||||||
|
{
|
||||||
|
free(expected);
|
||||||
|
}
|
||||||
|
if (tree != NULL)
|
||||||
|
{
|
||||||
|
cJSON_Delete(tree);
|
||||||
|
}
|
||||||
|
if (actual != NULL)
|
||||||
|
{
|
||||||
|
free(actual);
|
||||||
|
}
|
||||||
|
if (test_path != NULL)
|
||||||
|
{
|
||||||
|
free(test_path);
|
||||||
|
}
|
||||||
|
if (expected_path != NULL)
|
||||||
|
{
|
||||||
|
free(expected_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void file_test1_should_be_parsed_and_printed(void)
|
||||||
|
{
|
||||||
|
do_test("test1");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void file_test2_should_be_parsed_and_printed(void)
|
||||||
|
{
|
||||||
|
do_test("test2");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void file_test3_should_be_parsed_and_printed(void)
|
||||||
|
{
|
||||||
|
do_test("test3");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void file_test4_should_be_parsed_and_printed(void)
|
||||||
|
{
|
||||||
|
do_test("test4");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void file_test5_should_be_parsed_and_printed(void)
|
||||||
|
{
|
||||||
|
do_test("test5");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void file_test6_should_not_be_parsed(void)
|
||||||
|
{
|
||||||
|
char *test6 = NULL;
|
||||||
|
cJSON *tree = NULL;
|
||||||
|
|
||||||
|
test6 = read_file("inputs/test6");
|
||||||
|
TEST_ASSERT_NOT_NULL_MESSAGE(test6, "Failed to read test6 data.");
|
||||||
|
|
||||||
|
tree = cJSON_Parse(test6);
|
||||||
|
TEST_ASSERT_NULL_MESSAGE(tree, "Should fail to parse what is not JSON.");
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING_MESSAGE(test6, cJSON_GetErrorPtr(), "Error pointer is incorrect.");
|
||||||
|
|
||||||
|
if (test6 != NULL)
|
||||||
|
{
|
||||||
|
free(test6);
|
||||||
|
}
|
||||||
|
if (tree != NULL)
|
||||||
|
{
|
||||||
|
cJSON_Delete(tree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void file_test7_should_be_parsed_and_printed(void)
|
||||||
|
{
|
||||||
|
do_test("test7");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void file_test8_should_be_parsed_and_printed(void)
|
||||||
|
{
|
||||||
|
do_test("test8");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void file_test9_should_be_parsed_and_printed(void)
|
||||||
|
{
|
||||||
|
do_test("test9");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void file_test10_should_be_parsed_and_printed(void)
|
||||||
|
{
|
||||||
|
do_test("test10");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void file_test11_should_be_parsed_and_printed(void)
|
||||||
|
{
|
||||||
|
do_test("test11");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
UNITY_BEGIN();
|
||||||
|
RUN_TEST(file_test1_should_be_parsed_and_printed);
|
||||||
|
RUN_TEST(file_test2_should_be_parsed_and_printed);
|
||||||
|
RUN_TEST(file_test3_should_be_parsed_and_printed);
|
||||||
|
RUN_TEST(file_test4_should_be_parsed_and_printed);
|
||||||
|
RUN_TEST(file_test5_should_be_parsed_and_printed);
|
||||||
|
RUN_TEST(file_test6_should_not_be_parsed);
|
||||||
|
RUN_TEST(file_test7_should_be_parsed_and_printed);
|
||||||
|
RUN_TEST(file_test8_should_be_parsed_and_printed);
|
||||||
|
RUN_TEST(file_test9_should_be_parsed_and_printed);
|
||||||
|
RUN_TEST(file_test10_should_be_parsed_and_printed);
|
||||||
|
RUN_TEST(file_test11_should_be_parsed_and_printed);
|
||||||
|
return UNITY_END();
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
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 parse_hex4_should_parse_all_combinations(void)
|
||||||
|
{
|
||||||
|
unsigned int number = 0;
|
||||||
|
unsigned char digits_lower[5];
|
||||||
|
unsigned char digits_upper[5];
|
||||||
|
/* test all combinations */
|
||||||
|
for (number = 0; number <= 0xFFFF; number++)
|
||||||
|
{
|
||||||
|
TEST_ASSERT_EQUAL_INT_MESSAGE(4, sprintf((char*)digits_lower, "%.4x", number), "sprintf failed.");
|
||||||
|
TEST_ASSERT_EQUAL_INT_MESSAGE(4, sprintf((char*)digits_upper, "%.4X", number), "sprintf failed.");
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_INT_MESSAGE(number, parse_hex4(digits_lower), "Failed to parse lowercase digits.");
|
||||||
|
TEST_ASSERT_EQUAL_INT_MESSAGE(number, parse_hex4(digits_upper), "Failed to parse uppercase digits.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_hex4_should_parse_mixed_case(void)
|
||||||
|
{
|
||||||
|
TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"beef"));
|
||||||
|
TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"beeF"));
|
||||||
|
TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"beEf"));
|
||||||
|
TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"beEF"));
|
||||||
|
TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"bEef"));
|
||||||
|
TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"bEeF"));
|
||||||
|
TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"bEEf"));
|
||||||
|
TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"bEEF"));
|
||||||
|
TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"Beef"));
|
||||||
|
TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"BeeF"));
|
||||||
|
TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"BeEf"));
|
||||||
|
TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"BeEF"));
|
||||||
|
TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"BEef"));
|
||||||
|
TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"BEeF"));
|
||||||
|
TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"BEEf"));
|
||||||
|
TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"BEEF"));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
UNITY_BEGIN();
|
||||||
|
RUN_TEST(parse_hex4_should_parse_all_combinations);
|
||||||
|
RUN_TEST(parse_hex4_should_parse_mixed_case);
|
||||||
|
return UNITY_END();
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
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 cJSON item[1];
|
||||||
|
|
||||||
|
static void assert_is_number(cJSON *number_item)
|
||||||
|
{
|
||||||
|
TEST_ASSERT_NOT_NULL_MESSAGE(number_item, "Item is NULL.");
|
||||||
|
|
||||||
|
assert_not_in_list(number_item);
|
||||||
|
assert_has_no_child(number_item);
|
||||||
|
assert_has_type(number_item, cJSON_Number);
|
||||||
|
assert_has_no_reference(number_item);
|
||||||
|
assert_has_no_const_string(number_item);
|
||||||
|
assert_has_no_valuestring(number_item);
|
||||||
|
assert_has_no_string(number_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assert_parse_number(const char *string, int integer, double real)
|
||||||
|
{
|
||||||
|
TEST_ASSERT_NOT_NULL(parse_number(item, (const unsigned char*)string));
|
||||||
|
assert_is_number(item);
|
||||||
|
TEST_ASSERT_EQUAL_INT(integer, item->valueint);
|
||||||
|
TEST_ASSERT_EQUAL_DOUBLE(real, item->valuedouble);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_number_should_parse_zero(void)
|
||||||
|
{
|
||||||
|
assert_parse_number("0", 0, 0);
|
||||||
|
assert_parse_number("0.0", 0, 0.0);
|
||||||
|
assert_parse_number("-0", 0, -0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_number_should_parse_negative_integers(void)
|
||||||
|
{
|
||||||
|
assert_parse_number("-1", -1, -1);
|
||||||
|
assert_parse_number("-32768", -32768, -32768.0);
|
||||||
|
assert_parse_number("-2147483648", (int)-2147483648.0, -2147483648.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_number_should_parse_positive_integers(void)
|
||||||
|
{
|
||||||
|
assert_parse_number("1", 1, 1);
|
||||||
|
assert_parse_number("32767", 32767, 32767.0);
|
||||||
|
assert_parse_number("2147483647", (int)2147483647.0, 2147483647.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_number_should_parse_positive_reals(void)
|
||||||
|
{
|
||||||
|
assert_parse_number("0.001", 0, 0.001);
|
||||||
|
assert_parse_number("10e-10", 0, 10e-10);
|
||||||
|
assert_parse_number("10E-10", 0, 10e-10);
|
||||||
|
assert_parse_number("10e10", INT_MAX, 10e10);
|
||||||
|
assert_parse_number("123e+127", INT_MAX, 123e127);
|
||||||
|
assert_parse_number("123e-128", 0, 123e-128);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_number_should_parse_negative_reals(void)
|
||||||
|
{
|
||||||
|
assert_parse_number("-0.001", 0, -0.001);
|
||||||
|
assert_parse_number("-10e-10", 0, -10e-10);
|
||||||
|
assert_parse_number("-10E-10", 0, -10e-10);
|
||||||
|
assert_parse_number("-10e20", INT_MIN, -10e20);
|
||||||
|
assert_parse_number("-123e+127", INT_MIN, -123e127);
|
||||||
|
assert_parse_number("-123e-128", 0, -123e-128);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
/* initialize cJSON item */
|
||||||
|
memset(item, 0, sizeof(cJSON));
|
||||||
|
UNITY_BEGIN();
|
||||||
|
RUN_TEST(parse_number_should_parse_zero);
|
||||||
|
RUN_TEST(parse_number_should_parse_negative_integers);
|
||||||
|
RUN_TEST(parse_number_should_parse_positive_integers);
|
||||||
|
RUN_TEST(parse_number_should_parse_positive_reals);
|
||||||
|
RUN_TEST(parse_number_should_parse_negative_reals);
|
||||||
|
return UNITY_END();
|
||||||
|
}
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
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 cJSON item[1];
|
||||||
|
|
||||||
|
static const unsigned char *error_pointer = NULL;
|
||||||
|
|
||||||
|
static void assert_is_object(cJSON *object_item)
|
||||||
|
{
|
||||||
|
TEST_ASSERT_NOT_NULL_MESSAGE(object_item, "Item is NULL.");
|
||||||
|
|
||||||
|
assert_not_in_list(object_item);
|
||||||
|
assert_has_type(object_item, cJSON_Object);
|
||||||
|
assert_has_no_reference(object_item);
|
||||||
|
assert_has_no_const_string(object_item);
|
||||||
|
assert_has_no_valuestring(object_item);
|
||||||
|
assert_has_no_string(object_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assert_is_child(cJSON *child_item, const char *name, int type)
|
||||||
|
{
|
||||||
|
TEST_ASSERT_NOT_NULL_MESSAGE(child_item, "Child item is NULL.");
|
||||||
|
TEST_ASSERT_NOT_NULL_MESSAGE(child_item->string, "Child item doesn't have a name.");
|
||||||
|
TEST_ASSERT_EQUAL_STRING_MESSAGE(name, child_item->string, "Child item has the wrong name.");
|
||||||
|
TEST_ASSERT_BITS(0xFF, type, child_item->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assert_not_object(const char *json)
|
||||||
|
{
|
||||||
|
TEST_ASSERT_NULL(parse_object(item, (const unsigned char*)json, &error_pointer, &global_hooks));
|
||||||
|
assert_is_invalid(item);
|
||||||
|
reset(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assert_parse_object(const char *json)
|
||||||
|
{
|
||||||
|
TEST_ASSERT_NOT_NULL(parse_object(item, (const unsigned char*)json, &error_pointer, &global_hooks));
|
||||||
|
assert_is_object(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_object_should_parse_empty_objects(void)
|
||||||
|
{
|
||||||
|
assert_parse_object("{}");
|
||||||
|
assert_has_no_child(item);
|
||||||
|
reset(item);
|
||||||
|
|
||||||
|
assert_parse_object("{\n\t}");
|
||||||
|
assert_has_no_child(item);
|
||||||
|
reset(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_object_should_parse_objects_with_one_element(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
assert_parse_object("{\"one\":1}");
|
||||||
|
assert_is_child(item->child, "one", cJSON_Number);
|
||||||
|
reset(item);
|
||||||
|
|
||||||
|
assert_parse_object("{\"hello\":\"world!\"}");
|
||||||
|
assert_is_child(item->child, "hello", cJSON_String);
|
||||||
|
reset(item);
|
||||||
|
|
||||||
|
assert_parse_object("{\"array\":[]}");
|
||||||
|
assert_is_child(item->child, "array", cJSON_Array);
|
||||||
|
reset(item);
|
||||||
|
|
||||||
|
assert_parse_object("{\"null\":null}");
|
||||||
|
assert_is_child(item->child, "null", cJSON_NULL);
|
||||||
|
reset(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_object_should_parse_objects_with_multiple_elements(void)
|
||||||
|
{
|
||||||
|
assert_parse_object("{\"one\":1\t,\t\"two\"\n:2, \"three\":3}");
|
||||||
|
assert_is_child(item->child, "one", cJSON_Number);
|
||||||
|
assert_is_child(item->child->next, "two", cJSON_Number);
|
||||||
|
assert_is_child(item->child->next->next, "three", cJSON_Number);
|
||||||
|
reset(item);
|
||||||
|
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
cJSON *node = NULL;
|
||||||
|
int expected_types[7] =
|
||||||
|
{
|
||||||
|
cJSON_Number,
|
||||||
|
cJSON_NULL,
|
||||||
|
cJSON_True,
|
||||||
|
cJSON_False,
|
||||||
|
cJSON_Array,
|
||||||
|
cJSON_String,
|
||||||
|
cJSON_Object
|
||||||
|
};
|
||||||
|
const char *expected_names[7] =
|
||||||
|
{
|
||||||
|
"one",
|
||||||
|
"NULL",
|
||||||
|
"TRUE",
|
||||||
|
"FALSE",
|
||||||
|
"array",
|
||||||
|
"world",
|
||||||
|
"object"
|
||||||
|
};
|
||||||
|
assert_parse_object("{\"one\":1, \"NULL\":null, \"TRUE\":true, \"FALSE\":false, \"array\":[], \"world\":\"hello\", \"object\":{}}");
|
||||||
|
|
||||||
|
node = item->child;
|
||||||
|
for (
|
||||||
|
i = 0;
|
||||||
|
(i < (sizeof(expected_types)/sizeof(int)))
|
||||||
|
&& (node != NULL);
|
||||||
|
(void)i++, node = node->next)
|
||||||
|
{
|
||||||
|
assert_is_child(node, expected_names[i], expected_types[i]);
|
||||||
|
}
|
||||||
|
TEST_ASSERT_EQUAL_INT(i, 7);
|
||||||
|
reset(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_object_should_not_parse_non_objects(void)
|
||||||
|
{
|
||||||
|
assert_not_object("");
|
||||||
|
assert_not_object("{");
|
||||||
|
assert_not_object("}");
|
||||||
|
assert_not_object("[\"hello\",{}]");
|
||||||
|
assert_not_object("42");
|
||||||
|
assert_not_object("3.14");
|
||||||
|
assert_not_object("\"{}hello world!\n\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
/* initialize cJSON item */
|
||||||
|
memset(item, 0, sizeof(cJSON));
|
||||||
|
|
||||||
|
UNITY_BEGIN();
|
||||||
|
RUN_TEST(parse_object_should_parse_empty_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_one_element);
|
||||||
|
return UNITY_END();
|
||||||
|
}
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
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 cJSON item[1];
|
||||||
|
|
||||||
|
static const unsigned char *error_pointer = NULL;
|
||||||
|
|
||||||
|
static void assert_is_string(cJSON *string_item)
|
||||||
|
{
|
||||||
|
TEST_ASSERT_NOT_NULL_MESSAGE(string_item, "Item is NULL.");
|
||||||
|
|
||||||
|
assert_not_in_list(string_item);
|
||||||
|
assert_has_no_child(string_item);
|
||||||
|
assert_has_type(string_item, cJSON_String);
|
||||||
|
assert_has_no_reference(string_item);
|
||||||
|
assert_has_no_const_string(string_item);
|
||||||
|
assert_has_valuestring(string_item);
|
||||||
|
assert_has_no_string(string_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
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, &global_hooks), "Couldn't parse string.");
|
||||||
|
assert_is_string(item);
|
||||||
|
TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, item->valuestring, "The parsed result isn't as expected.");
|
||||||
|
global_hooks.deallocate(item->valuestring);
|
||||||
|
item->valuestring = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define assert_not_parse_string(string) \
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void parse_string_should_parse_strings(void)
|
||||||
|
{
|
||||||
|
assert_parse_string("\"\"", "");
|
||||||
|
assert_parse_string(
|
||||||
|
"\" !\\\"#$%&'()*+,-./\\/0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_'abcdefghijklmnopqrstuvwxyz{|}~\"",
|
||||||
|
" !\"#$%&'()*+,-.//0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_'abcdefghijklmnopqrstuvwxyz{|}~");
|
||||||
|
assert_parse_string(
|
||||||
|
"\"\\\"\\\\\\/\\b\\f\\n\\r\\t\\u20AC\\u732b\"",
|
||||||
|
"\"\\/\b\f\n\r\t€猫");
|
||||||
|
reset(item);
|
||||||
|
assert_parse_string("\"\b\f\n\r\t\"", "\b\f\n\r\t");
|
||||||
|
reset(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_string_should_parse_utf16_surrogate_pairs(void)
|
||||||
|
{
|
||||||
|
assert_parse_string("\"\\uD83D\\udc31\"", "🐱");
|
||||||
|
reset(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_string_should_not_parse_non_strings(void)
|
||||||
|
{
|
||||||
|
assert_not_parse_string("this\" is not a string\"");
|
||||||
|
reset(item);
|
||||||
|
assert_not_parse_string("");
|
||||||
|
reset(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_string_should_not_parse_invalid_backslash(void)
|
||||||
|
{
|
||||||
|
assert_not_parse_string("Abcdef\\123");
|
||||||
|
reset(item);
|
||||||
|
assert_not_parse_string("Abcdef\\e23");
|
||||||
|
reset(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_string_should_not_overflow_with_closing_backslash(void)
|
||||||
|
{
|
||||||
|
assert_not_parse_string("\"000000000000000000\\");
|
||||||
|
reset(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_string_should_parse_bug_94(void)
|
||||||
|
{
|
||||||
|
const char string[] = "\"~!@\\\\#$%^&*()\\\\\\\\-\\\\+{}[]:\\\\;\\\\\\\"\\\\<\\\\>?/.,DC=ad,DC=com\"";
|
||||||
|
assert_parse_string(string, "~!@\\#$%^&*()\\\\-\\+{}[]:\\;\\\"\\<\\>?/.,DC=ad,DC=com");
|
||||||
|
reset(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
/* initialize cJSON item and error pointer */
|
||||||
|
memset(item, 0, sizeof(cJSON));
|
||||||
|
|
||||||
|
UNITY_BEGIN();
|
||||||
|
RUN_TEST(parse_string_should_parse_strings);
|
||||||
|
RUN_TEST(parse_string_should_parse_utf16_surrogate_pairs);
|
||||||
|
RUN_TEST(parse_string_should_not_parse_non_strings);
|
||||||
|
RUN_TEST(parse_string_should_not_parse_invalid_backslash);
|
||||||
|
RUN_TEST(parse_string_should_parse_bug_94);
|
||||||
|
RUN_TEST(parse_string_should_not_overflow_with_closing_backslash);
|
||||||
|
return UNITY_END();
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
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 cJSON item[1];
|
||||||
|
const unsigned char *error_pointer = NULL;
|
||||||
|
|
||||||
|
static void assert_is_value(cJSON *value_item, int type)
|
||||||
|
{
|
||||||
|
TEST_ASSERT_NOT_NULL_MESSAGE(value_item, "Item is NULL.");
|
||||||
|
|
||||||
|
assert_not_in_list(value_item);
|
||||||
|
assert_has_type(value_item, type);
|
||||||
|
assert_has_no_reference(value_item);
|
||||||
|
assert_has_no_const_string(value_item);
|
||||||
|
assert_has_no_string(value_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assert_parse_value(const char *string, int type)
|
||||||
|
{
|
||||||
|
TEST_ASSERT_NOT_NULL(parse_value(item, (const unsigned char*)string, &error_pointer, &global_hooks));
|
||||||
|
assert_is_value(item, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_value_should_parse_null(void)
|
||||||
|
{
|
||||||
|
assert_parse_value("null", cJSON_NULL);
|
||||||
|
reset(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_value_should_parse_true(void)
|
||||||
|
{
|
||||||
|
assert_parse_value("true", cJSON_True);
|
||||||
|
reset(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_value_should_parse_false(void)
|
||||||
|
{
|
||||||
|
assert_parse_value("false", cJSON_False);
|
||||||
|
reset(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_value_should_parse_number(void)
|
||||||
|
{
|
||||||
|
assert_parse_value("1.5", cJSON_Number);
|
||||||
|
reset(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_value_should_parse_string(void)
|
||||||
|
{
|
||||||
|
assert_parse_value("\"\"", cJSON_String);
|
||||||
|
reset(item);
|
||||||
|
assert_parse_value("\"hello\"", cJSON_String);
|
||||||
|
reset(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_value_should_parse_array(void)
|
||||||
|
{
|
||||||
|
assert_parse_value("[]", cJSON_Array);
|
||||||
|
reset(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_value_should_parse_object(void)
|
||||||
|
{
|
||||||
|
assert_parse_value("{}", cJSON_Object);
|
||||||
|
reset(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
/* initialize cJSON item */
|
||||||
|
memset(item, 0, sizeof(cJSON));
|
||||||
|
UNITY_BEGIN();
|
||||||
|
RUN_TEST(parse_value_should_parse_null);
|
||||||
|
RUN_TEST(parse_value_should_parse_true);
|
||||||
|
RUN_TEST(parse_value_should_parse_false);
|
||||||
|
RUN_TEST(parse_value_should_parse_number);
|
||||||
|
RUN_TEST(parse_value_should_parse_string);
|
||||||
|
RUN_TEST(parse_value_should_parse_array);
|
||||||
|
RUN_TEST(parse_value_should_parse_object);
|
||||||
|
return UNITY_END();
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
* text=auto
|
||||||
|
|
||||||
|
# These files are text and should be normalized (convert crlf to lf)
|
||||||
|
*.rb text
|
||||||
|
*.test text
|
||||||
|
*.c text
|
||||||
|
*.cpp text
|
||||||
|
*.h text
|
||||||
|
*.txt text
|
||||||
|
*.yml text
|
||||||
|
*.s79 text
|
||||||
|
*.bat text
|
||||||
|
*.xcl text
|
||||||
|
*.inc text
|
||||||
|
*.info text
|
||||||
|
*.md text
|
||||||
|
makefile text
|
||||||
|
rakefile text
|
||||||
|
|
||||||
|
|
||||||
|
#These files are binary and should not be normalized
|
||||||
|
*.doc binary
|
||||||
|
*.odt binary
|
||||||
|
*.pdf binary
|
||||||
|
*.ewd binary
|
||||||
|
*.eww binary
|
||||||
|
*.dni binary
|
||||||
|
*.wsdt binary
|
||||||
|
*.dbgdt binary
|
||||||
|
*.mac binary
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
build/
|
||||||
|
test/sandbox
|
||||||
|
.DS_Store
|
||||||
|
examples/example_1/test1.exe
|
||||||
|
examples/example_1/test2.exe
|
||||||
|
examples/example_2/all_tests.exe
|
||||||
|
examples/example_1/test1.out
|
||||||
|
examples/example_1/test2.out
|
||||||
|
examples/example_2/all_tests.out
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
language: c
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: osx
|
||||||
|
compiler: clang
|
||||||
|
osx_image: xcode7.3
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
compiler: gcc
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then rvm install 2.1 && rvm use 2.1 && ruby -v; fi
|
||||||
|
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install --assume-yes --quiet gcc-multilib; fi
|
||||||
|
install: gem install rspec
|
||||||
|
script:
|
||||||
|
- cd test && rake ci
|
||||||
|
- make -s
|
||||||
|
- make -s DEBUG=-m32
|
||||||
|
- cd ../extras/fixture/test && rake ci
|
||||||
|
- make -s default noStdlibMalloc
|
||||||
|
- make -s C89
|
||||||
|
- cd ../../../examples/example_1 && make -s ci
|
||||||
|
- cd ../example_2 && make -s ci
|
||||||
|
- cd ../example_3 && rake
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
Unity Test API
|
||||||
|
==============
|
||||||
|
|
||||||
|
[](https://travis-ci.org/ThrowTheSwitch/Unity)
|
||||||
|
__Copyright (c) 2007 - 2014 Unity Project by Mike Karlesky, Mark VanderVoord, and Greg Williams__
|
||||||
|
|
||||||
|
Running Tests
|
||||||
|
-------------
|
||||||
|
|
||||||
|
RUN_TEST(func, linenum)
|
||||||
|
|
||||||
|
Each Test is run within the macro `RUN_TEST`. This macro performs necessary setup before the test is called and handles cleanup and result tabulation afterwards.
|
||||||
|
|
||||||
|
Ignoring Tests
|
||||||
|
--------------
|
||||||
|
|
||||||
|
There are times when a test is incomplete or not valid for some reason. At these times, TEST_IGNORE can be called. Control will immediately be returned to the caller of the test, and no failures will be returned.
|
||||||
|
|
||||||
|
TEST_IGNORE()
|
||||||
|
|
||||||
|
Ignore this test and return immediately
|
||||||
|
|
||||||
|
TEST_IGNORE_MESSAGE (message)
|
||||||
|
|
||||||
|
Ignore this test and return immediately. Output a message stating why the test was ignored.
|
||||||
|
|
||||||
|
Aborting Tests
|
||||||
|
--------------
|
||||||
|
|
||||||
|
There are times when a test will contain an infinite loop on error conditions, or there may be reason to escape from the test early without executing the rest of the test. A pair of macros support this functionality in Unity. The first `TEST_PROTECT` sets up the feature, and handles emergency abort cases. `TEST_ABORT` can then be used at any time within the tests to return to the last `TEST_PROTECT` call.
|
||||||
|
|
||||||
|
TEST_PROTECT()
|
||||||
|
|
||||||
|
Setup and Catch macro
|
||||||
|
|
||||||
|
TEST_ABORT()
|
||||||
|
|
||||||
|
Abort Test macro
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
if (TEST_PROTECT())
|
||||||
|
{
|
||||||
|
MyTest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
If MyTest calls `TEST_ABORT`, program control will immediately return to `TEST_PROTECT` with a return value of zero.
|
||||||
|
|
||||||
|
|
||||||
|
Unity Assertion Summary
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Basic Validity Tests
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
TEST_ASSERT_TRUE(condition)
|
||||||
|
|
||||||
|
Evaluates whatever code is in condition and fails if it evaluates to false
|
||||||
|
|
||||||
|
TEST_ASSERT_FALSE(condition)
|
||||||
|
|
||||||
|
Evaluates whatever code is in condition and fails if it evaluates to true
|
||||||
|
|
||||||
|
TEST_ASSERT(condition)
|
||||||
|
|
||||||
|
Another way of calling `TEST_ASSERT_TRUE`
|
||||||
|
|
||||||
|
TEST_ASSERT_UNLESS(condition)
|
||||||
|
|
||||||
|
Another way of calling `TEST_ASSERT_FALSE`
|
||||||
|
|
||||||
|
TEST_FAIL()
|
||||||
|
TEST_FAIL_MESSAGE(message)
|
||||||
|
|
||||||
|
This test is automatically marked as a failure. The message is output stating why.
|
||||||
|
|
||||||
|
Numerical Assertions: Integers
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_INT(expected, actual)
|
||||||
|
TEST_ASSERT_EQUAL_INT8(expected, actual)
|
||||||
|
TEST_ASSERT_EQUAL_INT16(expected, actual)
|
||||||
|
TEST_ASSERT_EQUAL_INT32(expected, actual)
|
||||||
|
TEST_ASSERT_EQUAL_INT64(expected, actual)
|
||||||
|
|
||||||
|
Compare two integers for equality and display errors as signed integers. A cast will be performed
|
||||||
|
to your natural integer size so often this can just be used. When you need to specify the exact size,
|
||||||
|
like when comparing arrays, you can use a specific version:
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_UINT(expected, actual)
|
||||||
|
TEST_ASSERT_EQUAL_UINT8(expected, actual)
|
||||||
|
TEST_ASSERT_EQUAL_UINT16(expected, actual)
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(expected, actual)
|
||||||
|
TEST_ASSERT_EQUAL_UINT64(expected, actual)
|
||||||
|
|
||||||
|
Compare two integers for equality and display errors as unsigned integers. Like INT, there are
|
||||||
|
variants for different sizes also.
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_HEX(expected, actual)
|
||||||
|
TEST_ASSERT_EQUAL_HEX8(expected, actual)
|
||||||
|
TEST_ASSERT_EQUAL_HEX16(expected, actual)
|
||||||
|
TEST_ASSERT_EQUAL_HEX32(expected, actual)
|
||||||
|
TEST_ASSERT_EQUAL_HEX64(expected, actual)
|
||||||
|
|
||||||
|
Compares two integers for equality and display errors as hexadecimal. Like the other integer comparisons,
|
||||||
|
you can specify the size... here the size will also effect how many nibbles are shown (for example, `HEX16`
|
||||||
|
will show 4 nibbles).
|
||||||
|
|
||||||
|
_ARRAY
|
||||||
|
|
||||||
|
You can append `_ARRAY` to any of these macros to make an array comparison of that type. Here you will
|
||||||
|
need to care a bit more about the actual size of the value being checked. You will also specify an
|
||||||
|
additional argument which is the number of elements to compare. For example:
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, elements)
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(expected, actual)
|
||||||
|
|
||||||
|
Another way of calling TEST_ASSERT_EQUAL_INT
|
||||||
|
|
||||||
|
TEST_ASSERT_INT_WITHIN(delta, expected, actual)
|
||||||
|
|
||||||
|
Asserts that the actual value is within plus or minus delta of the expected value. This also comes in
|
||||||
|
size specific variants.
|
||||||
|
|
||||||
|
|
||||||
|
Numerical Assertions: Bitwise
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
TEST_ASSERT_BITS(mask, expected, actual)
|
||||||
|
|
||||||
|
Use an integer mask to specify which bits should be compared between two other integers. High bits in the mask are compared, low bits ignored.
|
||||||
|
|
||||||
|
TEST_ASSERT_BITS_HIGH(mask, actual)
|
||||||
|
|
||||||
|
Use an integer mask to specify which bits should be inspected to determine if they are all set high. High bits in the mask are compared, low bits ignored.
|
||||||
|
|
||||||
|
TEST_ASSERT_BITS_LOW(mask, actual)
|
||||||
|
|
||||||
|
Use an integer mask to specify which bits should be inspected to determine if they are all set low. High bits in the mask are compared, low bits ignored.
|
||||||
|
|
||||||
|
TEST_ASSERT_BIT_HIGH(bit, actual)
|
||||||
|
|
||||||
|
Test a single bit and verify that it is high. The bit is specified 0-31 for a 32-bit integer.
|
||||||
|
|
||||||
|
TEST_ASSERT_BIT_LOW(bit, actual)
|
||||||
|
|
||||||
|
Test a single bit and verify that it is low. The bit is specified 0-31 for a 32-bit integer.
|
||||||
|
|
||||||
|
Numerical Assertions: Floats
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual)
|
||||||
|
|
||||||
|
Asserts that the actual value is within plus or minus delta of the expected value.
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_FLOAT(expected, actual)
|
||||||
|
TEST_ASSERT_EQUAL_DOUBLE(expected, actual)
|
||||||
|
|
||||||
|
Asserts that two floating point values are "equal" within a small % delta of the expected value.
|
||||||
|
|
||||||
|
String Assertions
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING(expected, actual)
|
||||||
|
|
||||||
|
Compare two null-terminate strings. Fail if any character is different or if the lengths are different.
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING_LEN(expected, actual, len)
|
||||||
|
|
||||||
|
Compare two strings. Fail if any character is different, stop comparing after len characters.
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, actual, message)
|
||||||
|
|
||||||
|
Compare two null-terminate strings. Fail if any character is different or if the lengths are different. Output a custom message on failure.
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING_LEN_MESSAGE(expected, actual, len, message)
|
||||||
|
|
||||||
|
Compare two strings. Fail if any character is different, stop comparing after len characters. Output a custom message on failure.
|
||||||
|
|
||||||
|
Pointer Assertions
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Most pointer operations can be performed by simply using the integer comparisons above. However, a couple of special cases are added for clarity.
|
||||||
|
|
||||||
|
TEST_ASSERT_NULL(pointer)
|
||||||
|
|
||||||
|
Fails if the pointer is not equal to NULL
|
||||||
|
|
||||||
|
TEST_ASSERT_NOT_NULL(pointer)
|
||||||
|
|
||||||
|
Fails if the pointer is equal to NULL
|
||||||
|
|
||||||
|
Memory Assertions
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_MEMORY(expected, actual, len)
|
||||||
|
|
||||||
|
Compare two blocks of memory. This is a good generic assertion for types that can't be coerced into acting like
|
||||||
|
standard types... but since it's a memory compare, you have to be careful that your data types are packed.
|
||||||
|
|
||||||
|
_MESSAGE
|
||||||
|
--------
|
||||||
|
|
||||||
|
you can append _MESSAGE to any of the macros to make them take an additional argument. This argument
|
||||||
|
is a string that will be printed at the end of the failure strings. This is useful for specifying more
|
||||||
|
information about the problem.
|
||||||
|
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
# ==========================================
|
||||||
|
# Unity Project - A Test Framework for C
|
||||||
|
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||||
|
# [Released under MIT License. Please refer to license.txt for details]
|
||||||
|
# ==========================================
|
||||||
|
|
||||||
|
if RUBY_PLATFORM =~/(win|w)32$/
|
||||||
|
begin
|
||||||
|
require 'Win32API'
|
||||||
|
rescue LoadError
|
||||||
|
puts "ERROR! \"Win32API\" library not found"
|
||||||
|
puts "\"Win32API\" is required for colour on a windows machine"
|
||||||
|
puts " try => \"gem install Win32API\" on the command line"
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
# puts
|
||||||
|
# puts 'Windows Environment Detected...'
|
||||||
|
# puts 'Win32API Library Found.'
|
||||||
|
# puts
|
||||||
|
end
|
||||||
|
|
||||||
|
class ColourCommandLine
|
||||||
|
def initialize
|
||||||
|
if RUBY_PLATFORM =~/(win|w)32$/
|
||||||
|
get_std_handle = Win32API.new("kernel32", "GetStdHandle", ['L'], 'L')
|
||||||
|
@set_console_txt_attrb =
|
||||||
|
Win32API.new("kernel32","SetConsoleTextAttribute",['L','N'], 'I')
|
||||||
|
@hout = get_std_handle.call(-11)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def change_to(new_colour)
|
||||||
|
if RUBY_PLATFORM =~/(win|w)32$/
|
||||||
|
@set_console_txt_attrb.call(@hout,self.win32_colour(new_colour))
|
||||||
|
else
|
||||||
|
"\033[30;#{posix_colour(new_colour)};22m"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def win32_colour(colour)
|
||||||
|
case colour
|
||||||
|
when :black then 0
|
||||||
|
when :dark_blue then 1
|
||||||
|
when :dark_green then 2
|
||||||
|
when :dark_cyan then 3
|
||||||
|
when :dark_red then 4
|
||||||
|
when :dark_purple then 5
|
||||||
|
when :dark_yellow, :narrative then 6
|
||||||
|
when :default_white, :default, :dark_white then 7
|
||||||
|
when :silver then 8
|
||||||
|
when :blue then 9
|
||||||
|
when :green, :success then 10
|
||||||
|
when :cyan, :output then 11
|
||||||
|
when :red, :failure then 12
|
||||||
|
when :purple then 13
|
||||||
|
when :yellow then 14
|
||||||
|
when :white then 15
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def posix_colour(colour)
|
||||||
|
# ANSI Escape Codes - Foreground colors
|
||||||
|
# | Code | Color |
|
||||||
|
# | 39 | Default foreground color |
|
||||||
|
# | 30 | Black |
|
||||||
|
# | 31 | Red |
|
||||||
|
# | 32 | Green |
|
||||||
|
# | 33 | Yellow |
|
||||||
|
# | 34 | Blue |
|
||||||
|
# | 35 | Magenta |
|
||||||
|
# | 36 | Cyan |
|
||||||
|
# | 37 | Light gray |
|
||||||
|
# | 90 | Dark gray |
|
||||||
|
# | 91 | Light red |
|
||||||
|
# | 92 | Light green |
|
||||||
|
# | 93 | Light yellow |
|
||||||
|
# | 94 | Light blue |
|
||||||
|
# | 95 | Light magenta |
|
||||||
|
# | 96 | Light cyan |
|
||||||
|
# | 97 | White |
|
||||||
|
|
||||||
|
case colour
|
||||||
|
when :black then 30
|
||||||
|
when :red, :failure then 31
|
||||||
|
when :green, :success then 32
|
||||||
|
when :yellow then 33
|
||||||
|
when :blue, :narrative then 34
|
||||||
|
when :purple, :magenta then 35
|
||||||
|
when :cyan, :output then 36
|
||||||
|
when :white, :default_white then 37
|
||||||
|
when :default then 39
|
||||||
|
else
|
||||||
|
39
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def out_c(mode, colour, str)
|
||||||
|
case RUBY_PLATFORM
|
||||||
|
when /(win|w)32$/
|
||||||
|
change_to(colour)
|
||||||
|
$stdout.puts str if mode == :puts
|
||||||
|
$stdout.print str if mode == :print
|
||||||
|
change_to(:default_white)
|
||||||
|
else
|
||||||
|
$stdout.puts("#{change_to(colour)}#{str}\033[0m") if mode == :puts
|
||||||
|
$stdout.print("#{change_to(colour)}#{str}\033[0m") if mode == :print
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end # ColourCommandLine
|
||||||
|
|
||||||
|
def colour_puts(role,str) ColourCommandLine.new.out_c(:puts, role, str) end
|
||||||
|
def colour_print(role,str) ColourCommandLine.new.out_c(:print, role, str) end
|
||||||
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# ==========================================
|
||||||
|
# Unity Project - A Test Framework for C
|
||||||
|
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||||
|
# [Released under MIT License. Please refer to license.txt for details]
|
||||||
|
# ==========================================
|
||||||
|
|
||||||
|
require "#{File.expand_path(File.dirname(__FILE__))}/colour_prompt"
|
||||||
|
|
||||||
|
$colour_output = true
|
||||||
|
|
||||||
|
def report(message)
|
||||||
|
if not $colour_output
|
||||||
|
$stdout.puts(message)
|
||||||
|
else
|
||||||
|
message = message.join('\n') if (message.class == Array)
|
||||||
|
message.each_line do |line|
|
||||||
|
line.chomp!
|
||||||
|
colour = case(line)
|
||||||
|
when /(?:total\s+)?tests:?\s+(\d+)\s+(?:total\s+)?failures:?\s+\d+\s+Ignored:?/i
|
||||||
|
($1.to_i == 0) ? :green : :red
|
||||||
|
when /PASS/
|
||||||
|
:green
|
||||||
|
when /^OK$/
|
||||||
|
:green
|
||||||
|
when /(?:FAIL|ERROR)/
|
||||||
|
:red
|
||||||
|
when /IGNORE/
|
||||||
|
:yellow
|
||||||
|
when /^(?:Creating|Compiling|Linking)/
|
||||||
|
:white
|
||||||
|
else
|
||||||
|
:silver
|
||||||
|
end
|
||||||
|
colour_puts(colour, line)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
$stdout.flush
|
||||||
|
$stderr.flush
|
||||||
|
end
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#this is a sample configuration file for generate_module
|
||||||
|
#you would use it by calling generate_module with the -ygenerate_config.yml option
|
||||||
|
#files like this are useful for customizing generate_module to your environment
|
||||||
|
:generate_module:
|
||||||
|
:defaults:
|
||||||
|
#these defaults are used in place of any missing options at the command line
|
||||||
|
:path_src: ../src/
|
||||||
|
:path_inc: ../src/
|
||||||
|
:path_tst: ../test/
|
||||||
|
:update_svn: true
|
||||||
|
:includes:
|
||||||
|
#use [] for no additional includes, otherwise list the includes on separate lines
|
||||||
|
:src:
|
||||||
|
- Defs.h
|
||||||
|
- Board.h
|
||||||
|
:inc: []
|
||||||
|
:tst:
|
||||||
|
- Defs.h
|
||||||
|
- Board.h
|
||||||
|
- Exception.h
|
||||||
|
:boilerplates:
|
||||||
|
#these are inserted at the top of generated files.
|
||||||
|
#just comment out or remove if not desired.
|
||||||
|
#use %1$s where you would like the file name to appear (path/extension not included)
|
||||||
|
:src: |
|
||||||
|
//-------------------------------------------
|
||||||
|
// %1$s.c
|
||||||
|
//-------------------------------------------
|
||||||
|
:inc: |
|
||||||
|
//-------------------------------------------
|
||||||
|
// %1$s.h
|
||||||
|
//-------------------------------------------
|
||||||
|
:tst: |
|
||||||
|
//-------------------------------------------
|
||||||
|
// Test%1$s.c : Units tests for %1$s.c
|
||||||
|
//-------------------------------------------
|
||||||
@@ -0,0 +1,311 @@
|
|||||||
|
# ==========================================
|
||||||
|
# Unity Project - A Test Framework for C
|
||||||
|
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||||
|
# [Released under MIT License. Please refer to license.txt for details]
|
||||||
|
# ==========================================
|
||||||
|
|
||||||
|
# This script creates all the files with start code necessary for a new module.
|
||||||
|
# A simple module only requires a source file, header file, and test file.
|
||||||
|
# Triad modules require a source, header, and test file for each triad type (like model, conductor, and hardware).
|
||||||
|
|
||||||
|
require 'rubygems'
|
||||||
|
require 'fileutils'
|
||||||
|
require 'pathname'
|
||||||
|
|
||||||
|
#TEMPLATE_TST
|
||||||
|
TEMPLATE_TST ||= %q[#include "unity.h"
|
||||||
|
%2$s#include "%1$s.h"
|
||||||
|
|
||||||
|
void setUp(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void tearDown(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_%1$s_NeedToImplement(void)
|
||||||
|
{
|
||||||
|
TEST_IGNORE_MESSAGE("Need to Implement %1$s");
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
#TEMPLATE_SRC
|
||||||
|
TEMPLATE_SRC ||= %q[%2$s#include "%1$s.h"
|
||||||
|
]
|
||||||
|
|
||||||
|
#TEMPLATE_INC
|
||||||
|
TEMPLATE_INC ||= %q[#ifndef _%3$s_H
|
||||||
|
#define _%3$s_H
|
||||||
|
%2$s
|
||||||
|
|
||||||
|
#endif // _%3$s_H
|
||||||
|
]
|
||||||
|
|
||||||
|
class UnityModuleGenerator
|
||||||
|
|
||||||
|
############################
|
||||||
|
def initialize(options=nil)
|
||||||
|
|
||||||
|
here = File.expand_path(File.dirname(__FILE__)) + '/'
|
||||||
|
|
||||||
|
@options = UnityModuleGenerator.default_options
|
||||||
|
case(options)
|
||||||
|
when NilClass then @options
|
||||||
|
when String then @options.merge!(UnityModuleGenerator.grab_config(options))
|
||||||
|
when Hash then @options.merge!(options)
|
||||||
|
else raise "If you specify arguments, it should be a filename or a hash of options"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Create default file paths if none were provided
|
||||||
|
@options[:path_src] = here + "../src/" if @options[:path_src].nil?
|
||||||
|
@options[:path_inc] = @options[:path_src] if @options[:path_inc].nil?
|
||||||
|
@options[:path_tst] = here + "../test/" if @options[:path_tst].nil?
|
||||||
|
@options[:path_src] += '/' unless (@options[:path_src][-1] == 47)
|
||||||
|
@options[:path_inc] += '/' unless (@options[:path_inc][-1] == 47)
|
||||||
|
@options[:path_tst] += '/' unless (@options[:path_tst][-1] == 47)
|
||||||
|
|
||||||
|
#Built in patterns
|
||||||
|
@patterns = { 'src' => {'' => { :inc => [] } },
|
||||||
|
'test'=> {'' => { :inc => [] } },
|
||||||
|
'dh' => {'Driver' => { :inc => [create_filename('%1$s','Hardware.h')] },
|
||||||
|
'Hardware' => { :inc => [] }
|
||||||
|
},
|
||||||
|
'dih' => {'Driver' => { :inc => [create_filename('%1$s','Hardware.h'), create_filename('%1$s','Interrupt.h')] },
|
||||||
|
'Interrupt'=> { :inc => [create_filename('%1$s','Hardware.h')] },
|
||||||
|
'Hardware' => { :inc => [] }
|
||||||
|
},
|
||||||
|
'mch' => {'Model' => { :inc => [] },
|
||||||
|
'Conductor'=> { :inc => [create_filename('%1$s','Model.h'), create_filename('%1$s','Hardware.h')] },
|
||||||
|
'Hardware' => { :inc => [] }
|
||||||
|
},
|
||||||
|
'mvp' => {'Model' => { :inc => [] },
|
||||||
|
'Presenter'=> { :inc => [create_filename('%1$s','Model.h'), create_filename('%1$s','View.h')] },
|
||||||
|
'View' => { :inc => [] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
############################
|
||||||
|
def self.default_options
|
||||||
|
{
|
||||||
|
:pattern => "src",
|
||||||
|
:includes =>
|
||||||
|
{
|
||||||
|
:src => [],
|
||||||
|
:inc => [],
|
||||||
|
:tst => [],
|
||||||
|
},
|
||||||
|
:update_svn => false,
|
||||||
|
:boilerplates => {},
|
||||||
|
:test_prefix => 'Test',
|
||||||
|
:mock_prefix => 'Mock',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
############################
|
||||||
|
def self.grab_config(config_file)
|
||||||
|
options = self.default_options
|
||||||
|
unless (config_file.nil? or config_file.empty?)
|
||||||
|
require 'yaml'
|
||||||
|
yaml_guts = YAML.load_file(config_file)
|
||||||
|
options.merge!(yaml_guts[:unity] || yaml_guts[:cmock])
|
||||||
|
raise "No :unity or :cmock section found in #{config_file}" unless options
|
||||||
|
end
|
||||||
|
return(options)
|
||||||
|
end
|
||||||
|
|
||||||
|
############################
|
||||||
|
def files_to_operate_on(module_name, pattern=nil)
|
||||||
|
#strip any leading path information from the module name and save for later
|
||||||
|
subfolder = File.dirname(module_name)
|
||||||
|
module_name = File.basename(module_name)
|
||||||
|
|
||||||
|
#create triad definition
|
||||||
|
prefix = @options[:test_prefix] || 'Test'
|
||||||
|
triad = [ { :ext => '.c', :path => @options[:path_src], :prefix => "", :template => TEMPLATE_SRC, :inc => :src, :boilerplate => @options[:boilerplates][:src] },
|
||||||
|
{ :ext => '.h', :path => @options[:path_inc], :prefix => "", :template => TEMPLATE_INC, :inc => :inc, :boilerplate => @options[:boilerplates][:inc] },
|
||||||
|
{ :ext => '.c', :path => @options[:path_tst], :prefix => prefix, :template => TEMPLATE_TST, :inc => :tst, :boilerplate => @options[:boilerplates][:tst] },
|
||||||
|
]
|
||||||
|
|
||||||
|
#prepare the pattern for use
|
||||||
|
pattern = (pattern || @options[:pattern] || 'src').downcase
|
||||||
|
patterns = @patterns[pattern]
|
||||||
|
raise "ERROR: The design pattern '#{pattern}' specified isn't one that I recognize!" if patterns.nil?
|
||||||
|
|
||||||
|
#single file patterns (currently just 'test') can reject the other parts of the triad
|
||||||
|
if (pattern == 'test')
|
||||||
|
triad.reject!{|v| v[:inc] != :tst }
|
||||||
|
end
|
||||||
|
|
||||||
|
# Assemble the path/names of the files we need to work with.
|
||||||
|
files = []
|
||||||
|
triad.each do |cfg|
|
||||||
|
patterns.each_pair do |pattern_file, pattern_traits|
|
||||||
|
submodule_name = create_filename(module_name, pattern_file)
|
||||||
|
filename = cfg[:prefix] + submodule_name + cfg[:ext]
|
||||||
|
files << {
|
||||||
|
:path => (Pathname.new("#{cfg[:path]}#{subfolder}") + filename).cleanpath,
|
||||||
|
:name => submodule_name,
|
||||||
|
:template => cfg[:template],
|
||||||
|
:boilerplate => cfg[:boilerplate],
|
||||||
|
:includes => case(cfg[:inc])
|
||||||
|
when :src then (@options[:includes][:src] || []) | pattern_traits[:inc].map{|f| f % [module_name]}
|
||||||
|
when :inc then (@options[:includes][:inc] || [])
|
||||||
|
when :tst then (@options[:includes][:tst] || []) | pattern_traits[:inc].map{|f| "#{@options[:mock_prefix]}#{f}" % [module_name]}
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return files
|
||||||
|
end
|
||||||
|
|
||||||
|
############################
|
||||||
|
def create_filename(part1, part2="")
|
||||||
|
if part2.empty?
|
||||||
|
case(@options[:naming])
|
||||||
|
when 'bumpy' then part1
|
||||||
|
when 'camel' then part1
|
||||||
|
when 'snake' then part1.downcase
|
||||||
|
when 'caps' then part1.upcase
|
||||||
|
else part1.downcase
|
||||||
|
end
|
||||||
|
else
|
||||||
|
case(@options[:naming])
|
||||||
|
when 'bumpy' then part1 + part2
|
||||||
|
when 'camel' then part1 + part2
|
||||||
|
when 'snake' then part1.downcase + "_" + part2.downcase
|
||||||
|
when 'caps' then part1.upcase + "_" + part2.upcase
|
||||||
|
else part1.downcase + "_" + part2.downcase
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
############################
|
||||||
|
def generate(module_name, pattern=nil)
|
||||||
|
|
||||||
|
files = files_to_operate_on(module_name, pattern)
|
||||||
|
|
||||||
|
#Abort if all of the module files already exist
|
||||||
|
all_files_exist = true
|
||||||
|
files.each do |file|
|
||||||
|
if not File.exist?(file[:path])
|
||||||
|
all_files_exist = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
raise "ERROR: File #{files[0][:name]} already exists. Exiting." if all_files_exist
|
||||||
|
|
||||||
|
# Create Source Modules
|
||||||
|
files.each_with_index do |file, i|
|
||||||
|
# If this file already exists, don't overwrite it.
|
||||||
|
if File.exist?(file[:path])
|
||||||
|
puts "File #{file[:path]} already exists!"
|
||||||
|
next
|
||||||
|
end
|
||||||
|
# Create the path first if necessary.
|
||||||
|
FileUtils.mkdir_p(File.dirname(file[:path]), :verbose => false)
|
||||||
|
File.open(file[:path], 'w') do |f|
|
||||||
|
f.write("#{file[:boilerplate]}\n" % [file[:name]]) unless file[:boilerplate].nil?
|
||||||
|
f.write(file[:template] % [ file[:name],
|
||||||
|
file[:includes].map{|f| "#include \"#{f}\"\n"}.join,
|
||||||
|
file[:name].upcase ]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
if (@options[:update_svn])
|
||||||
|
`svn add \"#{file[:path]}\"`
|
||||||
|
if $?.exitstatus == 0
|
||||||
|
puts "File #{file[:path]} created and added to source control"
|
||||||
|
else
|
||||||
|
puts "File #{file[:path]} created but FAILED adding to source control!"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
puts "File #{file[:path]} created"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
puts 'Generate Complete'
|
||||||
|
end
|
||||||
|
|
||||||
|
############################
|
||||||
|
def destroy(module_name, pattern=nil)
|
||||||
|
|
||||||
|
files_to_operate_on(module_name, pattern).each do |filespec|
|
||||||
|
file = filespec[:path]
|
||||||
|
if File.exist?(file)
|
||||||
|
if @options[:update_svn]
|
||||||
|
`svn delete \"#{file}\" --force`
|
||||||
|
puts "File #{file} deleted and removed from source control"
|
||||||
|
else
|
||||||
|
FileUtils.remove(file)
|
||||||
|
puts "File #{file} deleted"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
puts "File #{file} does not exist so cannot be removed."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
puts "Destroy Complete"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
############################
|
||||||
|
#Handle As Command Line If Called That Way
|
||||||
|
if ($0 == __FILE__)
|
||||||
|
destroy = false
|
||||||
|
options = { }
|
||||||
|
module_name = nil
|
||||||
|
|
||||||
|
# Parse the command line parameters.
|
||||||
|
ARGV.each do |arg|
|
||||||
|
case(arg)
|
||||||
|
when /^-d/ then destroy = true
|
||||||
|
when /^-u/ then options[:update_svn] = true
|
||||||
|
when /^-p\"?(\w+)\"?/ then options[:pattern] = $1
|
||||||
|
when /^-s\"?(.+)\"?/ then options[:path_src] = $1
|
||||||
|
when /^-i\"?(.+)\"?/ then options[:path_inc] = $1
|
||||||
|
when /^-t\"?(.+)\"?/ then options[:path_tst] = $1
|
||||||
|
when /^-n\"?(.+)\"?/ then options[:naming] = $1
|
||||||
|
when /^-y\"?(.+)\"?/ then options = UnityModuleGenerator.grab_config($1)
|
||||||
|
when /^(\w+)/
|
||||||
|
raise "ERROR: You can't have more than one Module name specified!" unless module_name.nil?
|
||||||
|
module_name = arg
|
||||||
|
when /^-(h|-help)/
|
||||||
|
ARGV = []
|
||||||
|
else
|
||||||
|
raise "ERROR: Unknown option specified '#{arg}'"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (!ARGV[0])
|
||||||
|
puts [ "\nGENERATE MODULE\n-------- ------",
|
||||||
|
"\nUsage: ruby generate_module [options] module_name",
|
||||||
|
" -i\"include\" sets the path to output headers to 'include' (DEFAULT ../src)",
|
||||||
|
" -s\"../src\" sets the path to output source to '../src' (DEFAULT ../src)",
|
||||||
|
" -t\"C:/test\" sets the path to output source to 'C:/test' (DEFAULT ../test)",
|
||||||
|
" -p\"MCH\" sets the output pattern to MCH.",
|
||||||
|
" dh - driver hardware.",
|
||||||
|
" dih - driver interrupt hardware.",
|
||||||
|
" mch - model conductor hardware.",
|
||||||
|
" mvp - model view presenter.",
|
||||||
|
" src - just a source module, header and test. (DEFAULT)",
|
||||||
|
" test - just a test file.",
|
||||||
|
" -d destroy module instead of creating it.",
|
||||||
|
" -n\"camel\" sets the file naming convention.",
|
||||||
|
" bumpy - BumpyCaseFilenames.",
|
||||||
|
" camel - camelCaseFilenames.",
|
||||||
|
" snake - snake_case_filenames. (DEFAULT)",
|
||||||
|
" caps - CAPS_CASE_FILENAMES.",
|
||||||
|
" -u update subversion too (requires subversion command line)",
|
||||||
|
" -y\"my.yml\" selects a different yaml config file for module generation",
|
||||||
|
"" ].join("\n")
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
|
||||||
|
raise "ERROR: You must have a Module name specified! (use option -h for help)" if module_name.nil?
|
||||||
|
if (destroy)
|
||||||
|
UnityModuleGenerator.new(options).destroy(module_name)
|
||||||
|
else
|
||||||
|
UnityModuleGenerator.new(options).generate(module_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,435 @@
|
|||||||
|
# ==========================================
|
||||||
|
# Unity Project - A Test Framework for C
|
||||||
|
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||||
|
# [Released under MIT License. Please refer to license.txt for details]
|
||||||
|
# ==========================================
|
||||||
|
|
||||||
|
$QUICK_RUBY_VERSION = RUBY_VERSION.split('.').inject(0){|vv,v| vv * 100 + v.to_i }
|
||||||
|
File.expand_path(File.join(File.dirname(__FILE__),'colour_prompt'))
|
||||||
|
|
||||||
|
class UnityTestRunnerGenerator
|
||||||
|
|
||||||
|
def initialize(options = nil)
|
||||||
|
@options = UnityTestRunnerGenerator.default_options
|
||||||
|
case(options)
|
||||||
|
when NilClass then @options
|
||||||
|
when String then @options.merge!(UnityTestRunnerGenerator.grab_config(options))
|
||||||
|
when Hash then @options.merge!(options)
|
||||||
|
else raise "If you specify arguments, it should be a filename or a hash of options"
|
||||||
|
end
|
||||||
|
require "#{File.expand_path(File.dirname(__FILE__))}/type_sanitizer"
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.default_options
|
||||||
|
{
|
||||||
|
:includes => [],
|
||||||
|
:defines => [],
|
||||||
|
:plugins => [],
|
||||||
|
:framework => :unity,
|
||||||
|
:test_prefix => "test|spec|should",
|
||||||
|
:setup_name => "setUp",
|
||||||
|
:teardown_name => "tearDown",
|
||||||
|
:main_name => "main", #set to :auto to automatically generate each time
|
||||||
|
:main_export_decl => "",
|
||||||
|
:cmdline_args => false,
|
||||||
|
:use_param_tests => false,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.grab_config(config_file)
|
||||||
|
options = self.default_options
|
||||||
|
unless (config_file.nil? or config_file.empty?)
|
||||||
|
require 'yaml'
|
||||||
|
yaml_guts = YAML.load_file(config_file)
|
||||||
|
options.merge!(yaml_guts[:unity] || yaml_guts[:cmock])
|
||||||
|
raise "No :unity or :cmock section found in #{config_file}" unless options
|
||||||
|
end
|
||||||
|
return(options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def run(input_file, output_file, options=nil)
|
||||||
|
tests = []
|
||||||
|
testfile_includes = []
|
||||||
|
used_mocks = []
|
||||||
|
|
||||||
|
@options.merge!(options) unless options.nil?
|
||||||
|
module_name = File.basename(input_file)
|
||||||
|
|
||||||
|
#pull required data from source file
|
||||||
|
source = File.read(input_file)
|
||||||
|
source = source.force_encoding("ISO-8859-1").encode("utf-8", :replace => nil) if ($QUICK_RUBY_VERSION > 10900)
|
||||||
|
tests = find_tests(source)
|
||||||
|
headers = find_includes(source)
|
||||||
|
testfile_includes = (headers[:local] + headers[:system])
|
||||||
|
used_mocks = find_mocks(testfile_includes)
|
||||||
|
testfile_includes = (testfile_includes - used_mocks)
|
||||||
|
testfile_includes.delete_if{|inc| inc =~ /(unity|cmock)/}
|
||||||
|
|
||||||
|
#build runner file
|
||||||
|
generate(input_file, output_file, tests, used_mocks, testfile_includes)
|
||||||
|
|
||||||
|
#determine which files were used to return them
|
||||||
|
all_files_used = [input_file, output_file]
|
||||||
|
all_files_used += testfile_includes.map {|filename| filename + '.c'} unless testfile_includes.empty?
|
||||||
|
all_files_used += @options[:includes] unless @options[:includes].empty?
|
||||||
|
return all_files_used.uniq
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate(input_file, output_file, tests, used_mocks, testfile_includes)
|
||||||
|
File.open(output_file, 'w') do |output|
|
||||||
|
create_header(output, used_mocks, testfile_includes)
|
||||||
|
create_externs(output, tests, used_mocks)
|
||||||
|
create_mock_management(output, used_mocks)
|
||||||
|
create_suite_setup_and_teardown(output)
|
||||||
|
create_reset(output, used_mocks)
|
||||||
|
create_main(output, input_file, tests, used_mocks)
|
||||||
|
end
|
||||||
|
|
||||||
|
if (@options[:header_file] && !@options[:header_file].empty?)
|
||||||
|
File.open(@options[:header_file], 'w') do |output|
|
||||||
|
create_h_file(output, @options[:header_file], tests, testfile_includes, used_mocks)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_tests(source)
|
||||||
|
tests_and_line_numbers = []
|
||||||
|
|
||||||
|
source_scrubbed = source.clone
|
||||||
|
source_scrubbed = source_scrubbed.gsub(/"[^"\n]*"/, '') # remove things in strings
|
||||||
|
source_scrubbed = source_scrubbed.gsub(/\/\/.*$/, '') # remove line comments
|
||||||
|
source_scrubbed = source_scrubbed.gsub(/\/\*.*?\*\//m, '') # remove block comments
|
||||||
|
lines = source_scrubbed.split(/(^\s*\#.*$) # Treat preprocessor directives as a logical line
|
||||||
|
| (;|\{|\}) /x) # Match ;, {, and } as end of lines
|
||||||
|
|
||||||
|
lines.each_with_index do |line, index|
|
||||||
|
#find tests
|
||||||
|
if line =~ /^((?:\s*TEST_CASE\s*\(.*?\)\s*)*)\s*void\s+((?:#{@options[:test_prefix]}).*)\s*\(\s*(.*)\s*\)/
|
||||||
|
arguments = $1
|
||||||
|
name = $2
|
||||||
|
call = $3
|
||||||
|
params = $4
|
||||||
|
args = nil
|
||||||
|
if (@options[:use_param_tests] and !arguments.empty?)
|
||||||
|
args = []
|
||||||
|
arguments.scan(/\s*TEST_CASE\s*\((.*)\)\s*$/) {|a| args << a[0]}
|
||||||
|
end
|
||||||
|
tests_and_line_numbers << { :test => name, :args => args, :call => call, :params => params, :line_number => 0 }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
tests_and_line_numbers.uniq! {|v| v[:test] }
|
||||||
|
|
||||||
|
#determine line numbers and create tests to run
|
||||||
|
source_lines = source.split("\n")
|
||||||
|
source_index = 0;
|
||||||
|
tests_and_line_numbers.size.times do |i|
|
||||||
|
source_lines[source_index..-1].each_with_index do |line, index|
|
||||||
|
if (line =~ /#{tests_and_line_numbers[i][:test]}/)
|
||||||
|
source_index += index
|
||||||
|
tests_and_line_numbers[i][:line_number] = source_index + 1
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return tests_and_line_numbers
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_includes(source)
|
||||||
|
|
||||||
|
#remove comments (block and line, in three steps to ensure correct precedence)
|
||||||
|
source.gsub!(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks
|
||||||
|
source.gsub!(/\/\*.*?\*\//m, '') # remove block comments
|
||||||
|
source.gsub!(/\/\/.*$/, '') # remove line comments (all that remain)
|
||||||
|
|
||||||
|
#parse out includes
|
||||||
|
includes = {
|
||||||
|
:local => source.scan(/^\s*#include\s+\"\s*(.+)\.[hH]\s*\"/).flatten,
|
||||||
|
:system => source.scan(/^\s*#include\s+<\s*(.+)\s*>/).flatten.map { |inc| "<#{inc}>" }
|
||||||
|
}
|
||||||
|
return includes
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_mocks(includes)
|
||||||
|
mock_headers = []
|
||||||
|
includes.each do |include_path|
|
||||||
|
include_file = File.basename(include_path)
|
||||||
|
mock_headers << include_path if (include_file =~ /^mock/i)
|
||||||
|
end
|
||||||
|
return mock_headers
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_header(output, mocks, testfile_includes=[])
|
||||||
|
output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */')
|
||||||
|
create_runtest(output, mocks)
|
||||||
|
output.puts("\n/*=======Automagically Detected Files To Include=====*/")
|
||||||
|
output.puts("#include \"#{@options[:framework].to_s}.h\"")
|
||||||
|
output.puts('#include "cmock.h"') unless (mocks.empty?)
|
||||||
|
output.puts('#include <setjmp.h>')
|
||||||
|
output.puts('#include <stdio.h>')
|
||||||
|
output.puts('#include "CException.h"') if @options[:plugins].include?(:cexception)
|
||||||
|
if (@options[:defines] && !@options[:defines].empty?)
|
||||||
|
@options[:defines].each {|d| output.puts("#define #{d}")}
|
||||||
|
end
|
||||||
|
if (@options[:header_file] && !@options[:header_file].empty?)
|
||||||
|
output.puts("#include \"#{File.basename(@options[:header_file])}\"")
|
||||||
|
else
|
||||||
|
@options[:includes].flatten.uniq.compact.each do |inc|
|
||||||
|
output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h','')}.h\""}")
|
||||||
|
end
|
||||||
|
testfile_includes.each do |inc|
|
||||||
|
output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h','')}.h\""}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
mocks.each do |mock|
|
||||||
|
output.puts("#include \"#{mock.gsub('.h','')}.h\"")
|
||||||
|
end
|
||||||
|
if @options[:enforce_strict_ordering]
|
||||||
|
output.puts('')
|
||||||
|
output.puts('int GlobalExpectCount;')
|
||||||
|
output.puts('int GlobalVerifyOrder;')
|
||||||
|
output.puts('char* GlobalOrderError;')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_externs(output, tests, mocks)
|
||||||
|
output.puts("\n/*=======External Functions This Runner Calls=====*/")
|
||||||
|
output.puts("extern void #{@options[:setup_name]}(void);")
|
||||||
|
output.puts("extern void #{@options[:teardown_name]}(void);")
|
||||||
|
tests.each do |test|
|
||||||
|
output.puts("extern void #{test[:test]}(#{test[:call] || 'void'});")
|
||||||
|
end
|
||||||
|
output.puts('')
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_mock_management(output, mock_headers)
|
||||||
|
unless (mock_headers.empty?)
|
||||||
|
output.puts("\n/*=======Mock Management=====*/")
|
||||||
|
output.puts("static void CMock_Init(void)")
|
||||||
|
output.puts("{")
|
||||||
|
if @options[:enforce_strict_ordering]
|
||||||
|
output.puts(" GlobalExpectCount = 0;")
|
||||||
|
output.puts(" GlobalVerifyOrder = 0;")
|
||||||
|
output.puts(" GlobalOrderError = NULL;")
|
||||||
|
end
|
||||||
|
mocks = mock_headers.map {|mock| File.basename(mock)}
|
||||||
|
mocks.each do |mock|
|
||||||
|
mock_clean = TypeSanitizer.sanitize_c_identifier(mock)
|
||||||
|
output.puts(" #{mock_clean}_Init();")
|
||||||
|
end
|
||||||
|
output.puts("}\n")
|
||||||
|
|
||||||
|
output.puts("static void CMock_Verify(void)")
|
||||||
|
output.puts("{")
|
||||||
|
mocks.each do |mock|
|
||||||
|
mock_clean = TypeSanitizer.sanitize_c_identifier(mock)
|
||||||
|
output.puts(" #{mock_clean}_Verify();")
|
||||||
|
end
|
||||||
|
output.puts("}\n")
|
||||||
|
|
||||||
|
output.puts("static void CMock_Destroy(void)")
|
||||||
|
output.puts("{")
|
||||||
|
mocks.each do |mock|
|
||||||
|
mock_clean = TypeSanitizer.sanitize_c_identifier(mock)
|
||||||
|
output.puts(" #{mock_clean}_Destroy();")
|
||||||
|
end
|
||||||
|
output.puts("}\n")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_suite_setup_and_teardown(output)
|
||||||
|
unless (@options[:suite_setup].nil?)
|
||||||
|
output.puts("\n/*=======Suite Setup=====*/")
|
||||||
|
output.puts("static void suite_setup(void)")
|
||||||
|
output.puts("{")
|
||||||
|
output.puts(@options[:suite_setup])
|
||||||
|
output.puts("}")
|
||||||
|
end
|
||||||
|
unless (@options[:suite_teardown].nil?)
|
||||||
|
output.puts("\n/*=======Suite Teardown=====*/")
|
||||||
|
output.puts("static int suite_teardown(int num_failures)")
|
||||||
|
output.puts("{")
|
||||||
|
output.puts(@options[:suite_teardown])
|
||||||
|
output.puts("}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_runtest(output, used_mocks)
|
||||||
|
cexception = @options[:plugins].include? :cexception
|
||||||
|
va_args1 = @options[:use_param_tests] ? ', ...' : ''
|
||||||
|
va_args2 = @options[:use_param_tests] ? '__VA_ARGS__' : ''
|
||||||
|
output.puts("\n/*=======Test Runner Used To Run Each Test Below=====*/")
|
||||||
|
output.puts("#define RUN_TEST_NO_ARGS") if @options[:use_param_tests]
|
||||||
|
output.puts("#define RUN_TEST(TestFunc, TestLineNum#{va_args1}) \\")
|
||||||
|
output.puts("{ \\")
|
||||||
|
output.puts(" Unity.CurrentTestName = #TestFunc#{va_args2.empty? ? '' : " \"(\" ##{va_args2} \")\""}; \\")
|
||||||
|
output.puts(" Unity.CurrentTestLineNumber = TestLineNum; \\")
|
||||||
|
output.puts(" if (UnityTestMatches()) { \\") if (@options[:cmdline_args])
|
||||||
|
output.puts(" Unity.NumberOfTests++; \\")
|
||||||
|
output.puts(" CMock_Init(); \\") unless (used_mocks.empty?)
|
||||||
|
output.puts(" UNITY_CLR_DETAILS(); \\") unless (used_mocks.empty?)
|
||||||
|
output.puts(" if (TEST_PROTECT()) \\")
|
||||||
|
output.puts(" { \\")
|
||||||
|
output.puts(" CEXCEPTION_T e; \\") if cexception
|
||||||
|
output.puts(" Try { \\") if cexception
|
||||||
|
output.puts(" #{@options[:setup_name]}(); \\")
|
||||||
|
output.puts(" TestFunc(#{va_args2}); \\")
|
||||||
|
output.puts(" } Catch(e) { TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, \"Unhandled Exception!\"); } \\") if cexception
|
||||||
|
output.puts(" } \\")
|
||||||
|
output.puts(" if (TEST_PROTECT()) \\")
|
||||||
|
output.puts(" { \\")
|
||||||
|
output.puts(" #{@options[:teardown_name]}(); \\")
|
||||||
|
output.puts(" CMock_Verify(); \\") unless (used_mocks.empty?)
|
||||||
|
output.puts(" } \\")
|
||||||
|
output.puts(" CMock_Destroy(); \\") unless (used_mocks.empty?)
|
||||||
|
output.puts(" UnityConcludeTest(); \\")
|
||||||
|
output.puts(" } \\") if (@options[:cmdline_args])
|
||||||
|
output.puts("}\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_reset(output, used_mocks)
|
||||||
|
output.puts("\n/*=======Test Reset Option=====*/")
|
||||||
|
output.puts("void resetTest(void);")
|
||||||
|
output.puts("void resetTest(void)")
|
||||||
|
output.puts("{")
|
||||||
|
output.puts(" CMock_Verify();") unless (used_mocks.empty?)
|
||||||
|
output.puts(" CMock_Destroy();") unless (used_mocks.empty?)
|
||||||
|
output.puts(" #{@options[:teardown_name]}();")
|
||||||
|
output.puts(" CMock_Init();") unless (used_mocks.empty?)
|
||||||
|
output.puts(" #{@options[:setup_name]}();")
|
||||||
|
output.puts("}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_main(output, filename, tests, used_mocks)
|
||||||
|
output.puts("\n\n/*=======MAIN=====*/")
|
||||||
|
main_name = (@options[:main_name].to_sym == :auto) ? "main_#{filename.gsub('.c','')}" : "#{@options[:main_name]}"
|
||||||
|
if (@options[:cmdline_args])
|
||||||
|
if (main_name != "main")
|
||||||
|
output.puts("#{@options[:main_export_decl]} int #{main_name}(int argc, char** argv);")
|
||||||
|
end
|
||||||
|
output.puts("#{@options[:main_export_decl]} int #{main_name}(int argc, char** argv)")
|
||||||
|
output.puts("{")
|
||||||
|
output.puts(" int parse_status = UnityParseOptions(argc, argv);")
|
||||||
|
output.puts(" if (parse_status != 0)")
|
||||||
|
output.puts(" {")
|
||||||
|
output.puts(" if (parse_status < 0)")
|
||||||
|
output.puts(" {")
|
||||||
|
output.puts(" UnityPrint(\"#{filename.gsub('.c','')}.\");")
|
||||||
|
output.puts(" UNITY_PRINT_EOL();")
|
||||||
|
if (@options[:use_param_tests])
|
||||||
|
tests.each do |test|
|
||||||
|
if ((test[:args].nil?) or (test[:args].empty?))
|
||||||
|
output.puts(" UnityPrint(\" #{test[:test]}(RUN_TEST_NO_ARGS)\");")
|
||||||
|
output.puts(" UNITY_PRINT_EOL();")
|
||||||
|
else
|
||||||
|
test[:args].each do |args|
|
||||||
|
output.puts(" UnityPrint(\" #{test[:test]}(#{args})\");")
|
||||||
|
output.puts(" UNITY_PRINT_EOL();")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
tests.each { |test| output.puts(" UnityPrint(\" #{test[:test]}\");\n UNITY_PRINT_EOL();")}
|
||||||
|
end
|
||||||
|
output.puts(" return 0;")
|
||||||
|
output.puts(" }")
|
||||||
|
output.puts(" return parse_status;")
|
||||||
|
output.puts(" }")
|
||||||
|
else
|
||||||
|
if (main_name != "main")
|
||||||
|
output.puts("#{@options[:main_export_decl]} int #{main_name}(void);")
|
||||||
|
end
|
||||||
|
output.puts("int #{main_name}(void)")
|
||||||
|
output.puts("{")
|
||||||
|
end
|
||||||
|
output.puts(" suite_setup();") unless @options[:suite_setup].nil?
|
||||||
|
output.puts(" UnityBegin(\"#{filename.gsub(/\\/,'\\\\\\')}\");")
|
||||||
|
if (@options[:use_param_tests])
|
||||||
|
tests.each do |test|
|
||||||
|
if ((test[:args].nil?) or (test[:args].empty?))
|
||||||
|
output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]}, RUN_TEST_NO_ARGS);")
|
||||||
|
else
|
||||||
|
test[:args].each {|args| output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]}, #{args});")}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
tests.each { |test| output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]});") }
|
||||||
|
end
|
||||||
|
output.puts()
|
||||||
|
output.puts(" CMock_Guts_MemFreeFinal();") unless used_mocks.empty?
|
||||||
|
output.puts(" return #{@options[:suite_teardown].nil? ? "" : "suite_teardown"}(UnityEnd());")
|
||||||
|
output.puts("}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_h_file(output, filename, tests, testfile_includes, used_mocks)
|
||||||
|
filename = File.basename(filename).gsub(/[-\/\\\.\,\s]/, "_").upcase
|
||||||
|
output.puts("/* AUTOGENERATED FILE. DO NOT EDIT. */")
|
||||||
|
output.puts("#ifndef _#{filename}")
|
||||||
|
output.puts("#define _#{filename}\n\n")
|
||||||
|
output.puts("#include \"#{@options[:framework].to_s}.h\"")
|
||||||
|
output.puts('#include "cmock.h"') unless (used_mocks.empty?)
|
||||||
|
@options[:includes].flatten.uniq.compact.each do |inc|
|
||||||
|
output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h','')}.h\""}")
|
||||||
|
end
|
||||||
|
testfile_includes.each do |inc|
|
||||||
|
output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h','')}.h\""}")
|
||||||
|
end
|
||||||
|
output.puts "\n"
|
||||||
|
tests.each do |test|
|
||||||
|
if ((test[:params].nil?) or (test[:params].empty?))
|
||||||
|
output.puts("void #{test[:test]}(void);")
|
||||||
|
else
|
||||||
|
output.puts("void #{test[:test]}(#{test[:params]});")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
output.puts("#endif\n\n")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if ($0 == __FILE__)
|
||||||
|
options = { :includes => [] }
|
||||||
|
yaml_file = nil
|
||||||
|
|
||||||
|
#parse out all the options first (these will all be removed as we go)
|
||||||
|
ARGV.reject! do |arg|
|
||||||
|
case(arg)
|
||||||
|
when '-cexception'
|
||||||
|
options[:plugins] = [:cexception]; true
|
||||||
|
when /\.*\.ya?ml/
|
||||||
|
options = UnityTestRunnerGenerator.grab_config(arg); true
|
||||||
|
when /--(\w+)=\"?(.*)\"?/
|
||||||
|
options[$1.to_sym] = $2; true
|
||||||
|
when /\.*\.h/
|
||||||
|
options[:includes] << arg; true
|
||||||
|
else false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#make sure there is at least one parameter left (the input file)
|
||||||
|
if !ARGV[0]
|
||||||
|
puts ["\nusage: ruby #{__FILE__} (files) (options) input_test_file (output)",
|
||||||
|
"\n input_test_file - this is the C file you want to create a runner for",
|
||||||
|
" output - this is the name of the runner file to generate",
|
||||||
|
" defaults to (input_test_file)_Runner",
|
||||||
|
" files:",
|
||||||
|
" *.yml / *.yaml - loads configuration from here in :unity or :cmock",
|
||||||
|
" *.h - header files are added as #includes in runner",
|
||||||
|
" options:",
|
||||||
|
" -cexception - include cexception support",
|
||||||
|
" --setup_name=\"\" - redefine setUp func name to something else",
|
||||||
|
" --teardown_name=\"\" - redefine tearDown func name to something else",
|
||||||
|
" --main_name=\"\" - redefine main func name to something else",
|
||||||
|
" --test_prefix=\"\" - redefine test prefix from default test|spec|should",
|
||||||
|
" --suite_setup=\"\" - code to execute for setup of entire suite",
|
||||||
|
" --suite_teardown=\"\" - code to execute for teardown of entire suite",
|
||||||
|
" --use_param_tests=1 - enable parameterized tests (disabled by default)",
|
||||||
|
" --header_file=\"\" - path/name of test header file to generate too"
|
||||||
|
].join("\n")
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
|
||||||
|
#create the default test runner name if not specified
|
||||||
|
ARGV[1] = ARGV[0].gsub(".c","_Runner.c") if (!ARGV[1])
|
||||||
|
|
||||||
|
UnityTestRunnerGenerator.new(options).run(ARGV[0], ARGV[1])
|
||||||
|
end
|
||||||
@@ -0,0 +1,224 @@
|
|||||||
|
#============================================================
|
||||||
|
# Author: John Theofanopoulos
|
||||||
|
# A simple parser. Takes the output files generated during the build process and
|
||||||
|
# extracts information relating to the tests.
|
||||||
|
#
|
||||||
|
# Notes:
|
||||||
|
# To capture an output file under VS builds use the following:
|
||||||
|
# devenv [build instructions] > Output.txt & type Output.txt
|
||||||
|
#
|
||||||
|
# To capture an output file under GCC/Linux builds use the following:
|
||||||
|
# make | tee Output.txt
|
||||||
|
#
|
||||||
|
# To use this parser use the following command
|
||||||
|
# ruby parseOutput.rb [options] [file]
|
||||||
|
# options: -xml : produce a JUnit compatible XML file
|
||||||
|
# file : file to scan for results
|
||||||
|
#============================================================
|
||||||
|
|
||||||
|
|
||||||
|
class ParseOutput
|
||||||
|
# The following flag is set to true when a test is found or false otherwise.
|
||||||
|
@testFlag
|
||||||
|
@xmlOut
|
||||||
|
@arrayList
|
||||||
|
@totalTests
|
||||||
|
@classIndex
|
||||||
|
|
||||||
|
# Set the flag to indicate if there will be an XML output file or not
|
||||||
|
def setXmlOutput()
|
||||||
|
@xmlOut = true
|
||||||
|
end
|
||||||
|
|
||||||
|
# if write our output to XML
|
||||||
|
def writeXmlOuput()
|
||||||
|
output = File.open("report.xml", "w")
|
||||||
|
output << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||||
|
@arrayList.each do |item|
|
||||||
|
output << item << "\n"
|
||||||
|
end
|
||||||
|
output << "</testsuite>\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
# This function will try and determine when the suite is changed. This is
|
||||||
|
# is the name that gets added to the classname parameter.
|
||||||
|
def testSuiteVerify(testSuiteName)
|
||||||
|
if @testFlag == false
|
||||||
|
@testFlag = true;
|
||||||
|
# Split the path name
|
||||||
|
testName = testSuiteName.split("/")
|
||||||
|
# Remove the extension
|
||||||
|
baseName = testName[testName.size - 1].split(".")
|
||||||
|
@testSuite = "test." + baseName[0]
|
||||||
|
printf "New Test: %s\n", @testSuite
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Test was flagged as having passed so format the output
|
||||||
|
def testPassed(array)
|
||||||
|
lastItem = array.length - 1
|
||||||
|
testName = array[lastItem - 1]
|
||||||
|
testSuiteVerify(array[@className])
|
||||||
|
printf "%-40s PASS\n", testName
|
||||||
|
if @xmlOut == true
|
||||||
|
@arrayList.push " <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\"/>"
|
||||||
|
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
|
||||||
|
def testIgnored(array)
|
||||||
|
lastItem = array.length - 1
|
||||||
|
testName = array[lastItem - 2]
|
||||||
|
reason = array[lastItem].chomp
|
||||||
|
testSuiteVerify(array[@className])
|
||||||
|
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
|
||||||
|
@arrayList.push " <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\">"
|
||||||
|
@arrayList.push " <skipped type=\"TEST IGNORED\"> " + reason + " </skipped>"
|
||||||
|
@arrayList.push " </testcase>"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Test was flagged as having failed so format the line
|
||||||
|
def testFailed(array)
|
||||||
|
lastItem = array.length - 1
|
||||||
|
testName = array[lastItem - 2]
|
||||||
|
reason = array[lastItem].chomp + " at line: " + array[lastItem - 3]
|
||||||
|
testSuiteVerify(array[@className])
|
||||||
|
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
|
||||||
|
@arrayList.push " <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\">"
|
||||||
|
@arrayList.push " <failure type=\"ASSERT FAILED\"> " + reason + " </failure>"
|
||||||
|
@arrayList.push " </testcase>"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Figure out what OS we are running on. For now we are assuming if it's not Windows it must
|
||||||
|
# be Unix based.
|
||||||
|
def detectOS()
|
||||||
|
myOS = RUBY_PLATFORM.split("-")
|
||||||
|
if myOS.size == 2
|
||||||
|
if myOS[1] == "mingw32"
|
||||||
|
@className = 1
|
||||||
|
else
|
||||||
|
@className = 0
|
||||||
|
end
|
||||||
|
else
|
||||||
|
@className = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
# Main function used to parse the file that was captured.
|
||||||
|
def process(name)
|
||||||
|
@testFlag = false
|
||||||
|
@arrayList = Array.new
|
||||||
|
|
||||||
|
detectOS()
|
||||||
|
|
||||||
|
puts "Parsing file: " + name
|
||||||
|
|
||||||
|
|
||||||
|
testPass = 0
|
||||||
|
testFail = 0
|
||||||
|
testIgnore = 0
|
||||||
|
puts ""
|
||||||
|
puts "=================== RESULTS ====================="
|
||||||
|
puts ""
|
||||||
|
File.open(name).each do |line|
|
||||||
|
# Typical test lines look like this:
|
||||||
|
# <path>/<test_file>.c:36:test_tc1000_opsys:FAIL: Expected 1 Was 0
|
||||||
|
# <path>/<test_file>.c:112:test_tc5004_initCanChannel:IGNORE: Not Yet Implemented
|
||||||
|
# <path>/<test_file>.c:115:test_tc5100_initCanVoidPtrs:PASS
|
||||||
|
#
|
||||||
|
# where path is different on Unix vs Windows devices (Windows leads with a drive letter)
|
||||||
|
lineArray = line.split(":")
|
||||||
|
lineSize = lineArray.size
|
||||||
|
# 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.
|
||||||
|
if ((lineSize >= 4) || (line.start_with? "TEST("))
|
||||||
|
# Determine if this test passed
|
||||||
|
if line.include? ":PASS"
|
||||||
|
testPassed(lineArray)
|
||||||
|
testPass += 1
|
||||||
|
elsif line.include? ":FAIL:"
|
||||||
|
testFailed(lineArray)
|
||||||
|
testFail += 1
|
||||||
|
elsif line.include? ":IGNORE:"
|
||||||
|
testIgnored(lineArray)
|
||||||
|
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
|
||||||
|
# the test flag
|
||||||
|
else
|
||||||
|
@testFlag = false
|
||||||
|
end
|
||||||
|
else
|
||||||
|
@testFlag = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
puts ""
|
||||||
|
puts "=================== SUMMARY ====================="
|
||||||
|
puts ""
|
||||||
|
puts "Tests Passed : " + testPass.to_s
|
||||||
|
puts "Tests Failed : " + testFail.to_s
|
||||||
|
puts "Tests Ignored : " + testIgnore.to_s
|
||||||
|
@totalTests = testPass + testFail + testIgnore
|
||||||
|
if @xmlOut == true
|
||||||
|
heading = "<testsuite tests=\"" + @totalTests.to_s + "\" failures=\"" + testFail.to_s + "\"" + " skips=\"" + testIgnore.to_s + "\">"
|
||||||
|
@arrayList.insert(0, heading)
|
||||||
|
writeXmlOuput()
|
||||||
|
end
|
||||||
|
|
||||||
|
# return result
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
# If the command line has no values in, used a default value of Output.txt
|
||||||
|
parseMyFile = ParseOutput.new
|
||||||
|
|
||||||
|
if ARGV.size >= 1
|
||||||
|
ARGV.each do |a|
|
||||||
|
if a == "-xml"
|
||||||
|
parseMyFile.setXmlOutput();
|
||||||
|
else
|
||||||
|
parseMyFile.process(a)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,264 @@
|
|||||||
|
#!/usr/bin/ruby
|
||||||
|
#
|
||||||
|
# unity_to_junit.rb
|
||||||
|
#
|
||||||
|
require 'fileutils'
|
||||||
|
require 'optparse'
|
||||||
|
require 'ostruct'
|
||||||
|
require 'set'
|
||||||
|
|
||||||
|
require 'pp'
|
||||||
|
|
||||||
|
VERSION = 1.0
|
||||||
|
|
||||||
|
class ArgvParser
|
||||||
|
|
||||||
|
#
|
||||||
|
# Return a structure describing the options.
|
||||||
|
#
|
||||||
|
def self.parse(args)
|
||||||
|
# The options specified on the command line will be collected in *options*.
|
||||||
|
# We set default values here.
|
||||||
|
options = OpenStruct.new
|
||||||
|
options.results_dir = "."
|
||||||
|
options.root_path = "."
|
||||||
|
options.out_file = "results.xml"
|
||||||
|
|
||||||
|
opts = OptionParser.new do |opts|
|
||||||
|
opts.banner = "Usage: unity_to_junit.rb [options]"
|
||||||
|
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "Specific options:"
|
||||||
|
|
||||||
|
opts.on("-r", "--results <dir>", "Look for Unity Results files here.") do |results|
|
||||||
|
#puts "results #{results}"
|
||||||
|
options.results_dir = results
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on("-p", "--root_path <path>", "Prepend this path to files in results.") do |root_path|
|
||||||
|
options.root_path = root_path
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on("-o", "--output <filename>", "XML file to generate.") do |out_file|
|
||||||
|
#puts "out_file: #{out_file}"
|
||||||
|
options.out_file = out_file
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "Common options:"
|
||||||
|
|
||||||
|
# No argument, shows at tail. This will print an options summary.
|
||||||
|
opts.on_tail("-h", "--help", "Show this message") do
|
||||||
|
puts opts
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
|
||||||
|
# Another typical switch to print the version.
|
||||||
|
opts.on_tail("--version", "Show version") do
|
||||||
|
puts "unity_to_junit.rb version #{VERSION}"
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.parse!(args)
|
||||||
|
options
|
||||||
|
end # parse()
|
||||||
|
|
||||||
|
end # class OptparseExample
|
||||||
|
|
||||||
|
class UnityToJUnit
|
||||||
|
include FileUtils::Verbose
|
||||||
|
attr_reader :report, :total_tests, :failures, :ignored
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@report = ''
|
||||||
|
@unit_name = ''
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
# Clean up result file names
|
||||||
|
results = @targets.map {|target| target.gsub(/\\/,"/")}
|
||||||
|
#puts "Output File: #{@out_file}"
|
||||||
|
f = File.new(@out_file, "w")
|
||||||
|
write_xml_header(f)
|
||||||
|
write_suites_header( f )
|
||||||
|
results.each do |result_file|
|
||||||
|
lines = File.readlines(result_file).map { |line| line.chomp }
|
||||||
|
if lines.length == 0
|
||||||
|
raise "Empty test result file: #{result_file}"
|
||||||
|
else
|
||||||
|
result_output = get_details(result_file, lines)
|
||||||
|
tests,failures,ignored = parse_test_summary(lines)
|
||||||
|
result_output[:counts][:total] = tests
|
||||||
|
result_output[:counts][:failed] = failures
|
||||||
|
result_output[:counts][:ignored] = ignored
|
||||||
|
result_output[:counts][:passed] = (result_output[:counts][:total] - result_output[:counts][:failed] - result_output[:counts][:ignored])
|
||||||
|
end
|
||||||
|
#use line[0] from the test output to get the test_file path and name
|
||||||
|
test_file_str = lines[0].gsub("\\","/")
|
||||||
|
test_file_str = test_file_str.split(":")
|
||||||
|
test_file = if (test_file_str.length < 2)
|
||||||
|
result_file
|
||||||
|
else
|
||||||
|
test_file_str[0] + ':' + test_file_str[1]
|
||||||
|
end
|
||||||
|
result_output[:source][:path] = File.dirname(test_file)
|
||||||
|
result_output[:source][:file] = File.basename(test_file)
|
||||||
|
|
||||||
|
# save result_output
|
||||||
|
@unit_name = File.basename(test_file, ".*")
|
||||||
|
|
||||||
|
write_suite_header( result_output[:counts], f)
|
||||||
|
write_failures( result_output, f )
|
||||||
|
write_tests( result_output, f )
|
||||||
|
write_ignored( result_output, f )
|
||||||
|
write_suite_footer( f )
|
||||||
|
end
|
||||||
|
write_suites_footer( f )
|
||||||
|
f.close
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_targets(target_array)
|
||||||
|
@targets = target_array
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_root_path(path)
|
||||||
|
@root = path
|
||||||
|
end
|
||||||
|
def set_out_file(filename)
|
||||||
|
@out_file = filename
|
||||||
|
end
|
||||||
|
def usage(err_msg=nil)
|
||||||
|
puts "\nERROR: "
|
||||||
|
puts err_msg if err_msg
|
||||||
|
puts "Usage: unity_to_junit.rb [options]"
|
||||||
|
puts ""
|
||||||
|
puts "Specific options:"
|
||||||
|
puts " -r, --results <dir> Look for Unity Results files here."
|
||||||
|
puts " -p, --root_path <path> Prepend this path to files in results."
|
||||||
|
puts " -o, --output <filename> XML file to generate."
|
||||||
|
puts ""
|
||||||
|
puts "Common options:"
|
||||||
|
puts " -h, --help Show this message"
|
||||||
|
puts " --version Show version"
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
def get_details(result_file, lines)
|
||||||
|
results = get_results_structure
|
||||||
|
lines.each do |line|
|
||||||
|
line = line.gsub("\\","/")
|
||||||
|
src_file,src_line,test_name,status,msg = line.split(/:/)
|
||||||
|
line_out = ((@root and (@root != 0)) ? "#{@root}#{line}" : line ).gsub(/\//, "\\")
|
||||||
|
case(status)
|
||||||
|
when 'IGNORE' then results[:ignores] << {:test => test_name, :line => src_line, :message => msg}
|
||||||
|
when 'FAIL' then results[:failures] << {:test => test_name, :line => src_line, :message => msg}
|
||||||
|
when 'PASS' then results[:successes] << {:test => test_name, :line => src_line, :message => msg}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return results
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_test_summary(summary)
|
||||||
|
if summary.find { |v| v =~ /(\d+) Tests (\d+) Failures (\d+) Ignored/ }
|
||||||
|
[$1.to_i,$2.to_i,$3.to_i]
|
||||||
|
else
|
||||||
|
raise "Couldn't parse test results: #{summary}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
def here; File.expand_path(File.dirname(__FILE__)); end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def get_results_structure
|
||||||
|
return {
|
||||||
|
:source => {:path => '', :file => ''},
|
||||||
|
:successes => [],
|
||||||
|
:failures => [],
|
||||||
|
:ignores => [],
|
||||||
|
:counts => {:total => 0, :passed => 0, :failed => 0, :ignored => 0},
|
||||||
|
:stdout => [],
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def write_xml_header( stream )
|
||||||
|
stream.puts "<?xml version='1.0' encoding='utf-8' ?>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def write_suites_header( stream )
|
||||||
|
stream.puts "<testsuites>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def write_suite_header( counts, stream )
|
||||||
|
stream.puts "\t<testsuite errors=\"0\" skipped=\"#{counts[:ignored]}\" failures=\"#{counts[:failed]}\" tests=\"#{counts[:total]}\" name=\"unity\">"
|
||||||
|
end
|
||||||
|
|
||||||
|
def write_failures( results, stream )
|
||||||
|
result = results[:failures]
|
||||||
|
result.each do |item|
|
||||||
|
filename = File.join(results[:source][:path], File.basename(results[:source][:file], '.*'))
|
||||||
|
stream.puts "\t\t<testcase classname=\"#{@unit_name}\" name=\"#{item[:test]}\" time=\"0\">"
|
||||||
|
stream.puts "\t\t\t<failure message=\"#{item[:message]}\" type=\"Assertion\"/>"
|
||||||
|
stream.puts "\t\t\t<system-err>
[File] #{filename}
[Line] #{item[:line]}
</system-err>"
|
||||||
|
stream.puts "\t\t</testcase>"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def write_tests( results, stream )
|
||||||
|
result = results[:successes]
|
||||||
|
result.each do |item|
|
||||||
|
filename = File.join(results[:source][:path], File.basename(results[:source][:file], '.*'))
|
||||||
|
stream.puts "\t\t<testcase classname=\"#{@unit_name}\" name=\"#{item[:test]}\" time=\"0\" />"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def write_ignored( results, stream )
|
||||||
|
result = results[:ignores]
|
||||||
|
result.each do |item|
|
||||||
|
filename = File.join(results[:source][:path], File.basename(results[:source][:file], '.*'))
|
||||||
|
puts "Writing ignored tests for test harness: #{filename}"
|
||||||
|
stream.puts "\t\t<testcase classname=\"#{@unit_name}\" name=\"#{item[:test]}\" time=\"0\">"
|
||||||
|
stream.puts "\t\t\t<skipped message=\"#{item[:message]}\" type=\"Assertion\"/>"
|
||||||
|
stream.puts "\t\t\t<system-err>
[File] #{filename}
[Line] #{item[:line]}
</system-err>"
|
||||||
|
stream.puts "\t\t</testcase>"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def write_suite_footer( stream )
|
||||||
|
stream.puts "\t</testsuite>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def write_suites_footer( stream )
|
||||||
|
stream.puts "</testsuites>"
|
||||||
|
end
|
||||||
|
end #UnityToJUnit
|
||||||
|
|
||||||
|
if __FILE__ == $0
|
||||||
|
#parse out the command options
|
||||||
|
options = ArgvParser.parse(ARGV)
|
||||||
|
|
||||||
|
#create an instance to work with
|
||||||
|
utj = UnityToJUnit.new
|
||||||
|
begin
|
||||||
|
#look in the specified or current directory for result files
|
||||||
|
targets = "#{options.results_dir.gsub(/\\/, '/')}**/*.test*"
|
||||||
|
|
||||||
|
results = Dir[targets]
|
||||||
|
raise "No *.testpass, *.testfail, or *.testresults files found in '#{targets}'" if results.empty?
|
||||||
|
utj.set_targets(results)
|
||||||
|
|
||||||
|
#set the root path
|
||||||
|
utj.set_root_path(options.root_path)
|
||||||
|
|
||||||
|
#set the output XML file name
|
||||||
|
#puts "Output File from options: #{options.out_file}"
|
||||||
|
utj.set_out_file(options.out_file)
|
||||||
|
|
||||||
|
#run the summarizer
|
||||||
|
puts utj.run
|
||||||
|
rescue Exception => e
|
||||||
|
utj.usage e.message
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# ==========================================
|
||||||
|
# Unity Project - A Test Framework for C
|
||||||
|
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||||
|
# [Released under MIT License. Please refer to license.txt for details]
|
||||||
|
# ==========================================
|
||||||
|
|
||||||
|
require'yaml'
|
||||||
|
|
||||||
|
module RakefileHelpers
|
||||||
|
class TestFileFilter
|
||||||
|
def initialize(all_files = false)
|
||||||
|
@all_files = all_files
|
||||||
|
if not @all_files == true
|
||||||
|
if File.exist?('test_file_filter.yml')
|
||||||
|
filters = YAML.load_file( 'test_file_filter.yml' )
|
||||||
|
@all_files, @only_files, @exclude_files =
|
||||||
|
filters[:all_files], filters[:only_files], filters[:exclude_files]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
attr_accessor :all_files, :only_files, :exclude_files
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
module TypeSanitizer
|
||||||
|
|
||||||
|
def self.sanitize_c_identifier(unsanitized)
|
||||||
|
# convert filename to valid C identifier by replacing invalid chars with '_'
|
||||||
|
return unsanitized.gsub(/[-\/\\\.\,\s]/, "_")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
#! python3
|
||||||
|
# ==========================================
|
||||||
|
# Unity Project - A Test Framework for C
|
||||||
|
# Copyright (c) 2015 Alexander Mueller / XelaRellum@web.de
|
||||||
|
# [Released under MIT License. Please refer to license.txt for details]
|
||||||
|
# Based on the ruby script by Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||||
|
# ==========================================
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
from glob import glob
|
||||||
|
|
||||||
|
class UnityTestSummary:
|
||||||
|
def __init__(self):
|
||||||
|
self.report = ''
|
||||||
|
self.total_tests = 0
|
||||||
|
self.failures = 0
|
||||||
|
self.ignored = 0
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
# Clean up result file names
|
||||||
|
results = []
|
||||||
|
for target in self.targets:
|
||||||
|
results.append(target.replace('\\', '/'))
|
||||||
|
|
||||||
|
# Dig through each result file, looking for details on pass/fail:
|
||||||
|
failure_output = []
|
||||||
|
ignore_output = []
|
||||||
|
|
||||||
|
for result_file in results:
|
||||||
|
lines = list(map(lambda line: line.rstrip(), open(result_file, "r").read().split('\n')))
|
||||||
|
if len(lines) == 0:
|
||||||
|
raise Exception("Empty test result file: %s" % result_file)
|
||||||
|
|
||||||
|
details = self.get_details(result_file, lines)
|
||||||
|
failures = details['failures']
|
||||||
|
ignores = details['ignores']
|
||||||
|
if len(failures) > 0: failure_output.append('\n'.join(failures))
|
||||||
|
if len(ignores) > 0: ignore_output.append('n'.join(ignores))
|
||||||
|
tests,failures,ignored = self.parse_test_summary('\n'.join(lines))
|
||||||
|
self.total_tests += tests
|
||||||
|
self.failures += failures
|
||||||
|
self.ignored += ignored
|
||||||
|
|
||||||
|
if self.ignored > 0:
|
||||||
|
self.report += "\n"
|
||||||
|
self.report += "--------------------------\n"
|
||||||
|
self.report += "UNITY IGNORED TEST SUMMARY\n"
|
||||||
|
self.report += "--------------------------\n"
|
||||||
|
self.report += "\n".join(ignore_output)
|
||||||
|
|
||||||
|
if self.failures > 0:
|
||||||
|
self.report += "\n"
|
||||||
|
self.report += "--------------------------\n"
|
||||||
|
self.report += "UNITY FAILED TEST SUMMARY\n"
|
||||||
|
self.report += "--------------------------\n"
|
||||||
|
self.report += '\n'.join(failure_output)
|
||||||
|
|
||||||
|
self.report += "\n"
|
||||||
|
self.report += "--------------------------\n"
|
||||||
|
self.report += "OVERALL UNITY TEST SUMMARY\n"
|
||||||
|
self.report += "--------------------------\n"
|
||||||
|
self.report += "{total_tests} TOTAL TESTS {failures} TOTAL FAILURES {ignored} IGNORED\n".format(total_tests = self.total_tests, failures=self.failures, ignored=self.ignored)
|
||||||
|
self.report += "\n"
|
||||||
|
|
||||||
|
return self.report
|
||||||
|
|
||||||
|
def set_targets(self, target_array):
|
||||||
|
self.targets = target_array
|
||||||
|
|
||||||
|
def set_root_path(self, path):
|
||||||
|
self.root = path
|
||||||
|
|
||||||
|
def usage(self, err_msg=None):
|
||||||
|
print("\nERROR: ")
|
||||||
|
if err_msg:
|
||||||
|
print(err_msg)
|
||||||
|
print("\nUsage: unity_test_summary.py result_file_directory/ root_path/")
|
||||||
|
print(" result_file_directory - The location of your results files.")
|
||||||
|
print(" Defaults to current directory if not specified.")
|
||||||
|
print(" Should end in / if specified.")
|
||||||
|
print(" root_path - Helpful for producing more verbose output if using relative paths.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def get_details(self, result_file, lines):
|
||||||
|
results = { 'failures': [], 'ignores': [], 'successes': [] }
|
||||||
|
for line in lines:
|
||||||
|
parts = line.split(':')
|
||||||
|
if len(parts) == 5:
|
||||||
|
src_file,src_line,test_name,status,msg = parts
|
||||||
|
elif len(parts) == 4:
|
||||||
|
src_file,src_line,test_name,status = parts
|
||||||
|
msg = ''
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
if len(self.root) > 0:
|
||||||
|
line_out = "%s%s" % (self.root, line)
|
||||||
|
else:
|
||||||
|
line_out = line
|
||||||
|
if status == 'IGNORE':
|
||||||
|
results['ignores'].append(line_out)
|
||||||
|
elif status == 'FAIL':
|
||||||
|
results['failures'].append(line_out)
|
||||||
|
elif status == 'PASS':
|
||||||
|
results['successes'].append(line_out)
|
||||||
|
return results
|
||||||
|
|
||||||
|
def parse_test_summary(self, summary):
|
||||||
|
m = re.search(r"([0-9]+) Tests ([0-9]+) Failures ([0-9]+) Ignored", summary)
|
||||||
|
if not m:
|
||||||
|
raise Exception("Couldn't parse test results: %s" % summary)
|
||||||
|
|
||||||
|
return int(m.group(1)), int(m.group(2)), int(m.group(3))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
uts = UnityTestSummary()
|
||||||
|
try:
|
||||||
|
#look in the specified or current directory for result files
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
targets_dir = sys.argv[1]
|
||||||
|
else:
|
||||||
|
targets_dir = './'
|
||||||
|
targets = list(map(lambda x: x.replace('\\', '/'), glob(targets_dir + '*.test*')))
|
||||||
|
if len(targets) == 0:
|
||||||
|
raise Exception("No *.testpass or *.testfail files found in '%s'" % targets_dir)
|
||||||
|
uts.set_targets(targets)
|
||||||
|
|
||||||
|
#set the root path
|
||||||
|
if len(sys.argv) > 2:
|
||||||
|
root_path = sys.argv[2]
|
||||||
|
else:
|
||||||
|
root_path = os.path.split(__file__)[0]
|
||||||
|
uts.set_root_path(root_path)
|
||||||
|
|
||||||
|
#run the summarizer
|
||||||
|
print(uts.run())
|
||||||
|
except Exception as e:
|
||||||
|
uts.usage(e)
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
# ==========================================
|
||||||
|
# Unity Project - A Test Framework for C
|
||||||
|
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||||
|
# [Released under MIT License. Please refer to license.txt for details]
|
||||||
|
# ==========================================
|
||||||
|
|
||||||
|
#!/usr/bin/ruby
|
||||||
|
#
|
||||||
|
# unity_test_summary.rb
|
||||||
|
#
|
||||||
|
require 'fileutils'
|
||||||
|
require 'set'
|
||||||
|
|
||||||
|
class UnityTestSummary
|
||||||
|
include FileUtils::Verbose
|
||||||
|
|
||||||
|
attr_reader :report, :total_tests, :failures, :ignored
|
||||||
|
|
||||||
|
def initialize(opts = {})
|
||||||
|
@report = ''
|
||||||
|
@total_tests = 0
|
||||||
|
@failures = 0
|
||||||
|
@ignored = 0
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
# Clean up result file names
|
||||||
|
results = @targets.map {|target| target.gsub(/\\/,'/')}
|
||||||
|
|
||||||
|
# Dig through each result file, looking for details on pass/fail:
|
||||||
|
failure_output = []
|
||||||
|
ignore_output = []
|
||||||
|
|
||||||
|
results.each do |result_file|
|
||||||
|
lines = File.readlines(result_file).map { |line| line.chomp }
|
||||||
|
if lines.length == 0
|
||||||
|
raise "Empty test result file: #{result_file}"
|
||||||
|
else
|
||||||
|
output = get_details(result_file, lines)
|
||||||
|
failure_output << output[:failures] unless output[:failures].empty?
|
||||||
|
ignore_output << output[:ignores] unless output[:ignores].empty?
|
||||||
|
tests,failures,ignored = parse_test_summary(lines)
|
||||||
|
@total_tests += tests
|
||||||
|
@failures += failures
|
||||||
|
@ignored += ignored
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if @ignored > 0
|
||||||
|
@report += "\n"
|
||||||
|
@report += "--------------------------\n"
|
||||||
|
@report += "UNITY IGNORED TEST SUMMARY\n"
|
||||||
|
@report += "--------------------------\n"
|
||||||
|
@report += ignore_output.flatten.join("\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
if @failures > 0
|
||||||
|
@report += "\n"
|
||||||
|
@report += "--------------------------\n"
|
||||||
|
@report += "UNITY FAILED TEST SUMMARY\n"
|
||||||
|
@report += "--------------------------\n"
|
||||||
|
@report += failure_output.flatten.join("\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
@report += "\n"
|
||||||
|
@report += "--------------------------\n"
|
||||||
|
@report += "OVERALL UNITY TEST SUMMARY\n"
|
||||||
|
@report += "--------------------------\n"
|
||||||
|
@report += "#{@total_tests} TOTAL TESTS #{@failures} TOTAL FAILURES #{@ignored} IGNORED\n"
|
||||||
|
@report += "\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_targets(target_array)
|
||||||
|
@targets = target_array
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_root_path(path)
|
||||||
|
@root = path
|
||||||
|
end
|
||||||
|
|
||||||
|
def usage(err_msg=nil)
|
||||||
|
puts "\nERROR: "
|
||||||
|
puts err_msg if err_msg
|
||||||
|
puts "\nUsage: unity_test_summary.rb result_file_directory/ root_path/"
|
||||||
|
puts " result_file_directory - The location of your results files."
|
||||||
|
puts " Defaults to current directory if not specified."
|
||||||
|
puts " Should end in / if specified."
|
||||||
|
puts " root_path - Helpful for producing more verbose output if using relative paths."
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def get_details(result_file, lines)
|
||||||
|
results = { :failures => [], :ignores => [], :successes => [] }
|
||||||
|
lines.each do |line|
|
||||||
|
src_file,src_line,test_name,status,msg = line.split(/:/)
|
||||||
|
line_out = ((@root && (@root != 0)) ? "#{@root}#{line}" : line ).gsub(/\//, "\\")
|
||||||
|
case(status)
|
||||||
|
when 'IGNORE' then results[:ignores] << line_out
|
||||||
|
when 'FAIL' then results[:failures] << line_out
|
||||||
|
when 'PASS' then results[:successes] << line_out
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return results
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_test_summary(summary)
|
||||||
|
if summary.find { |v| v =~ /(\d+) Tests (\d+) Failures (\d+) Ignored/ }
|
||||||
|
[$1.to_i,$2.to_i,$3.to_i]
|
||||||
|
else
|
||||||
|
raise "Couldn't parse test results: #{summary}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def here; File.expand_path(File.dirname(__FILE__)); end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if $0 == __FILE__
|
||||||
|
|
||||||
|
#parse out the command options
|
||||||
|
opts, args = ARGV.partition {|v| v =~ /^--\w+/}
|
||||||
|
opts.map! {|v| v[2..-1].to_sym }
|
||||||
|
|
||||||
|
#create an instance to work with
|
||||||
|
uts = UnityTestSummary.new(opts)
|
||||||
|
|
||||||
|
begin
|
||||||
|
#look in the specified or current directory for result files
|
||||||
|
args[0] ||= './'
|
||||||
|
targets = "#{ARGV[0].gsub(/\\/, '/')}**/*.test*"
|
||||||
|
results = Dir[targets]
|
||||||
|
raise "No *.testpass, *.testfail, or *.testresults files found in '#{targets}'" if results.empty?
|
||||||
|
uts.set_targets(results)
|
||||||
|
|
||||||
|
#set the root path
|
||||||
|
args[1] ||= Dir.pwd + '/'
|
||||||
|
uts.set_root_path(ARGV[1])
|
||||||
|
|
||||||
|
#run the summarizer
|
||||||
|
puts uts.run
|
||||||
|
rescue Exception => e
|
||||||
|
uts.usage e.message
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
import sys
|
||||||
|
import os
|
||||||
|
from glob import glob
|
||||||
|
|
||||||
|
from pyparsing import *
|
||||||
|
from junit_xml import TestSuite, TestCase
|
||||||
|
|
||||||
|
|
||||||
|
class UnityTestSummary:
|
||||||
|
def __init__(self):
|
||||||
|
self.report = ''
|
||||||
|
self.total_tests = 0
|
||||||
|
self.failures = 0
|
||||||
|
self.ignored = 0
|
||||||
|
self.targets = 0
|
||||||
|
self.root = None
|
||||||
|
self.test_suites = dict()
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
# Clean up result file names
|
||||||
|
results = []
|
||||||
|
for target in self.targets:
|
||||||
|
results.append(target.replace('\\', '/'))
|
||||||
|
|
||||||
|
# Dig through each result file, looking for details on pass/fail:
|
||||||
|
for result_file in results:
|
||||||
|
lines = list(map(lambda line: line.rstrip(), open(result_file, "r").read().split('\n')))
|
||||||
|
if len(lines) == 0:
|
||||||
|
raise Exception("Empty test result file: %s" % result_file)
|
||||||
|
|
||||||
|
# define an expression for your file reference
|
||||||
|
entry_one = Combine(
|
||||||
|
oneOf(list(alphas)) + ':/' +
|
||||||
|
Word(alphanums + '_-./'))
|
||||||
|
|
||||||
|
entry_two = Word(printables + ' ', excludeChars=':')
|
||||||
|
entry = entry_one | entry_two
|
||||||
|
|
||||||
|
delimiter = Literal(':').suppress()
|
||||||
|
tc_result_line = Group(entry.setResultsName('tc_file_name') + delimiter + entry.setResultsName(
|
||||||
|
'tc_line_nr') + delimiter + entry.setResultsName('tc_name') + delimiter + entry.setResultsName(
|
||||||
|
'tc_status') + Optional(
|
||||||
|
delimiter + entry.setResultsName('tc_msg'))).setResultsName("tc_line")
|
||||||
|
|
||||||
|
eol = LineEnd().suppress()
|
||||||
|
sol = LineStart().suppress()
|
||||||
|
blank_line = sol + eol
|
||||||
|
|
||||||
|
tc_summary_line = Group(Word(nums).setResultsName("num_of_tests") + "Tests" + Word(nums).setResultsName(
|
||||||
|
"num_of_fail") + "Failures" + Word(nums).setResultsName("num_of_ignore") + "Ignored").setResultsName(
|
||||||
|
"tc_summary")
|
||||||
|
tc_end_line = Or(Literal("FAIL"), Literal('Ok')).setResultsName("tc_result")
|
||||||
|
|
||||||
|
# run it and see...
|
||||||
|
pp1 = tc_result_line | Optional(tc_summary_line | tc_end_line)
|
||||||
|
pp1.ignore(blank_line | OneOrMore("-"))
|
||||||
|
|
||||||
|
result = list()
|
||||||
|
for l in lines:
|
||||||
|
result.append((pp1.parseString(l)).asDict())
|
||||||
|
# delete empty results
|
||||||
|
result = filter(None, result)
|
||||||
|
|
||||||
|
tc_list = list()
|
||||||
|
for r in result:
|
||||||
|
if 'tc_line' in r:
|
||||||
|
tmp_tc_line = r['tc_line']
|
||||||
|
|
||||||
|
# get only the file name which will be used as the classname
|
||||||
|
file_name = tmp_tc_line['tc_file_name'].split('\\').pop().split('/').pop().rsplit('.', 1)[0]
|
||||||
|
tmp_tc = TestCase(name=tmp_tc_line['tc_name'], classname=file_name)
|
||||||
|
if 'tc_status' in tmp_tc_line:
|
||||||
|
if str(tmp_tc_line['tc_status']) == 'IGNORE':
|
||||||
|
if 'tc_msg' in tmp_tc_line:
|
||||||
|
tmp_tc.add_skipped_info(message=tmp_tc_line['tc_msg'],
|
||||||
|
output=r'[File]={0}, [Line]={1}'.format(
|
||||||
|
tmp_tc_line['tc_file_name'], tmp_tc_line['tc_line_nr']))
|
||||||
|
else:
|
||||||
|
tmp_tc.add_skipped_info(message=" ")
|
||||||
|
elif str(tmp_tc_line['tc_status']) == 'FAIL':
|
||||||
|
if 'tc_msg' in tmp_tc_line:
|
||||||
|
tmp_tc.add_failure_info(message=tmp_tc_line['tc_msg'],
|
||||||
|
output=r'[File]={0}, [Line]={1}'.format(
|
||||||
|
tmp_tc_line['tc_file_name'], tmp_tc_line['tc_line_nr']))
|
||||||
|
else:
|
||||||
|
tmp_tc.add_failure_info(message=" ")
|
||||||
|
|
||||||
|
tc_list.append((str(result_file), tmp_tc))
|
||||||
|
|
||||||
|
for k, v in tc_list:
|
||||||
|
try:
|
||||||
|
self.test_suites[k].append(v)
|
||||||
|
except KeyError:
|
||||||
|
self.test_suites[k] = [v]
|
||||||
|
ts = []
|
||||||
|
for suite_name in self.test_suites:
|
||||||
|
ts.append(TestSuite(suite_name, self.test_suites[suite_name]))
|
||||||
|
|
||||||
|
with open('result.xml', 'w') as f:
|
||||||
|
TestSuite.to_file(f, ts, prettyprint='True', encoding='utf-8')
|
||||||
|
|
||||||
|
return self.report
|
||||||
|
|
||||||
|
def set_targets(self, target_array):
|
||||||
|
self.targets = target_array
|
||||||
|
|
||||||
|
def set_root_path(self, path):
|
||||||
|
self.root = path
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def usage(err_msg=None):
|
||||||
|
print("\nERROR: ")
|
||||||
|
if err_msg:
|
||||||
|
print(err_msg)
|
||||||
|
print("\nUsage: unity_test_summary.py result_file_directory/ root_path/")
|
||||||
|
print(" result_file_directory - The location of your results files.")
|
||||||
|
print(" Defaults to current directory if not specified.")
|
||||||
|
print(" Should end in / if specified.")
|
||||||
|
print(" root_path - Helpful for producing more verbose output if using relative paths.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
uts = UnityTestSummary()
|
||||||
|
try:
|
||||||
|
# look in the specified or current directory for result files
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
targets_dir = sys.argv[1]
|
||||||
|
else:
|
||||||
|
targets_dir = './'
|
||||||
|
targets = list(map(lambda x: x.replace('\\', '/'), glob(targets_dir + '*.test*')))
|
||||||
|
if len(targets) == 0:
|
||||||
|
raise Exception("No *.testpass or *.testfail files found in '%s'" % targets_dir)
|
||||||
|
uts.set_targets(targets)
|
||||||
|
|
||||||
|
# set the root path
|
||||||
|
if len(sys.argv) > 2:
|
||||||
|
root_path = sys.argv[2]
|
||||||
|
else:
|
||||||
|
root_path = os.path.split(__file__)[0]
|
||||||
|
uts.set_root_path(root_path)
|
||||||
|
|
||||||
|
# run the summarizer
|
||||||
|
print(uts.run())
|
||||||
|
except Exception as e:
|
||||||
|
UnityTestSummary.usage(e)
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) <year> 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||||
|
|
||||||
|
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.
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
# ==========================================
|
||||||
|
# Unity Project - A Test Framework for C
|
||||||
|
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||||
|
# [Released under MIT License. Please refer to license.txt for details]
|
||||||
|
# ==========================================
|
||||||
|
|
||||||
|
#We try to detect the OS we are running on, and adjust commands as needed
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
ifeq ($(shell uname -s),) # not in a bash-like shell
|
||||||
|
CLEANUP = del /F /Q
|
||||||
|
MKDIR = mkdir
|
||||||
|
else # in a bash-like shell, like msys
|
||||||
|
CLEANUP = rm -f
|
||||||
|
MKDIR = mkdir -p
|
||||||
|
endif
|
||||||
|
TARGET_EXTENSION=.exe
|
||||||
|
else
|
||||||
|
CLEANUP = rm -f
|
||||||
|
MKDIR = mkdir -p
|
||||||
|
TARGET_EXTENSION=.out
|
||||||
|
endif
|
||||||
|
|
||||||
|
C_COMPILER=gcc
|
||||||
|
ifeq ($(shell uname -s), Darwin)
|
||||||
|
C_COMPILER=clang
|
||||||
|
endif
|
||||||
|
|
||||||
|
UNITY_ROOT=../..
|
||||||
|
|
||||||
|
CFLAGS=-std=c89
|
||||||
|
CFLAGS += -Wall
|
||||||
|
CFLAGS += -Wextra
|
||||||
|
CFLAGS += -Wpointer-arith
|
||||||
|
CFLAGS += -Wcast-align
|
||||||
|
CFLAGS += -Wwrite-strings
|
||||||
|
CFLAGS += -Wswitch-default
|
||||||
|
CFLAGS += -Wunreachable-code
|
||||||
|
CFLAGS += -Winit-self
|
||||||
|
CFLAGS += -Wmissing-field-initializers
|
||||||
|
CFLAGS += -Wno-unknown-pragmas
|
||||||
|
CFLAGS += -Wstrict-prototypes
|
||||||
|
CFLAGS += -Wundef
|
||||||
|
CFLAGS += -Wold-style-definition
|
||||||
|
|
||||||
|
TARGET_BASE1=test1
|
||||||
|
TARGET_BASE2=test2
|
||||||
|
TARGET1 = $(TARGET_BASE1)$(TARGET_EXTENSION)
|
||||||
|
TARGET2 = $(TARGET_BASE2)$(TARGET_EXTENSION)
|
||||||
|
SRC_FILES1=$(UNITY_ROOT)/src/unity.c src/ProductionCode.c test/TestProductionCode.c test/test_runners/TestProductionCode_Runner.c
|
||||||
|
SRC_FILES2=$(UNITY_ROOT)/src/unity.c src/ProductionCode2.c test/TestProductionCode2.c test/test_runners/TestProductionCode2_Runner.c
|
||||||
|
INC_DIRS=-Isrc -I$(UNITY_ROOT)/src
|
||||||
|
SYMBOLS=
|
||||||
|
|
||||||
|
all: clean default
|
||||||
|
|
||||||
|
default: $(SRC_FILES1) $(SRC_FILES2)
|
||||||
|
$(C_COMPILER) $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $(SRC_FILES1) -o $(TARGET1)
|
||||||
|
$(C_COMPILER) $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $(SRC_FILES2) -o $(TARGET2)
|
||||||
|
- ./$(TARGET1)
|
||||||
|
./$(TARGET2)
|
||||||
|
|
||||||
|
test/test_runners/TestProductionCode_Runner.c: test/TestProductionCode.c
|
||||||
|
ruby $(UNITY_ROOT)/auto/generate_test_runner.rb test/TestProductionCode.c test/test_runners/TestProductionCode_Runner.c
|
||||||
|
test/test_runners/TestProductionCode2_Runner.c: test/TestProductionCode2.c
|
||||||
|
ruby $(UNITY_ROOT)/auto/generate_test_runner.rb test/TestProductionCode2.c test/test_runners/TestProductionCode2_Runner.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(CLEANUP) $(TARGET1) $(TARGET2)
|
||||||
|
|
||||||
|
ci: CFLAGS += -Werror
|
||||||
|
ci: default
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
Example 1
|
||||||
|
=========
|
||||||
|
|
||||||
|
Close to the simplest possible example of Unity, using only basic features.
|
||||||
|
Run make to build & run the example tests.
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
#include "ProductionCode.h"
|
||||||
|
|
||||||
|
int Counter = 0;
|
||||||
|
int NumbersToFind[9] = { 0, 34, 55, 66, 32, 11, 1, 77, 888 }; /* some obnoxious array to search that is 1-based indexing instead of 0. */
|
||||||
|
|
||||||
|
/* This function is supposed to search through NumbersToFind and find a particular number.
|
||||||
|
* If it finds it, the index is returned. Otherwise 0 is returned which sorta makes sense since
|
||||||
|
* NumbersToFind is indexed from 1. Unfortunately it's broken
|
||||||
|
* (and should therefore be caught by our tests) */
|
||||||
|
int FindFunction_WhichIsBroken(int NumberToFind)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while (i <= 8) /* Notice I should have been in braces */
|
||||||
|
i++;
|
||||||
|
if (NumbersToFind[i] == NumberToFind) /* Yikes! I'm getting run after the loop finishes instead of during it! */
|
||||||
|
return i;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FunctionWhichReturnsLocalVariable(void)
|
||||||
|
{
|
||||||
|
return Counter;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
int FindFunction_WhichIsBroken(int NumberToFind);
|
||||||
|
int FunctionWhichReturnsLocalVariable(void);
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
#include "ProductionCode2.h"
|
||||||
|
|
||||||
|
char* ThisFunctionHasNotBeenTested(int Poor, char* LittleFunction)
|
||||||
|
{
|
||||||
|
(void)Poor;
|
||||||
|
(void)LittleFunction;
|
||||||
|
/* Since There Are No Tests Yet, This Function Could Be Empty For All We Know.
|
||||||
|
* Which isn't terribly useful... but at least we put in a TEST_IGNORE so we won't forget */
|
||||||
|
return (char*)0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
char* ThisFunctionHasNotBeenTested(int Poor, char* LittleFunction);
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
|
||||||
|
#include "ProductionCode.h"
|
||||||
|
#include "unity.h"
|
||||||
|
|
||||||
|
/* sometimes you may want to get at local data in a module.
|
||||||
|
* for example: If you plan to pass by reference, this could be useful
|
||||||
|
* however, it should often be avoided */
|
||||||
|
extern int Counter;
|
||||||
|
|
||||||
|
void setUp(void)
|
||||||
|
{
|
||||||
|
/* This is run before EACH TEST */
|
||||||
|
Counter = 0x5a5a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tearDown(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode(void)
|
||||||
|
{
|
||||||
|
/* All of these should pass */
|
||||||
|
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(78));
|
||||||
|
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(1));
|
||||||
|
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(33));
|
||||||
|
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(999));
|
||||||
|
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken(void)
|
||||||
|
{
|
||||||
|
/* You should see this line fail in your test summary */
|
||||||
|
TEST_ASSERT_EQUAL(1, FindFunction_WhichIsBroken(34));
|
||||||
|
|
||||||
|
/* Notice the rest of these didn't get a chance to run because the line above failed.
|
||||||
|
* Unit tests abort each test function on the first sign of trouble.
|
||||||
|
* Then NEXT test function runs as normal. */
|
||||||
|
TEST_ASSERT_EQUAL(8, FindFunction_WhichIsBroken(8888));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue(void)
|
||||||
|
{
|
||||||
|
/* This should be true because setUp set this up for us before this test */
|
||||||
|
TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable());
|
||||||
|
|
||||||
|
/* This should be true because we can still change our answer */
|
||||||
|
Counter = 0x1234;
|
||||||
|
TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable());
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain(void)
|
||||||
|
{
|
||||||
|
/* This should be true again because setup was rerun before this test (and after we changed it to 0x1234) */
|
||||||
|
TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable());
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed(void)
|
||||||
|
{
|
||||||
|
/* Sometimes you get the test wrong. When that happens, you get a failure too... and a quick look should tell
|
||||||
|
* you what actually happened...which in this case was a failure to setup the initial condition. */
|
||||||
|
TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable());
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
#include "ProductionCode2.h"
|
||||||
|
#include "unity.h"
|
||||||
|
|
||||||
|
/* These should be ignored because they are commented out in various ways:
|
||||||
|
#include "whatever.h"
|
||||||
|
#include "somethingelse.h"
|
||||||
|
*/
|
||||||
|
|
||||||
|
void setUp(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void tearDown(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_IgnoredTest(void)
|
||||||
|
{
|
||||||
|
TEST_IGNORE_MESSAGE("This Test Was Ignored On Purpose");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_AnotherIgnoredTest(void)
|
||||||
|
{
|
||||||
|
TEST_IGNORE_MESSAGE("These Can Be Useful For Leaving Yourself Notes On What You Need To Do Yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_ThisFunctionHasNotBeenTested_NeedsToBeImplemented(void)
|
||||||
|
{
|
||||||
|
TEST_IGNORE(); /* Like This */
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/* AUTOGENERATED FILE. DO NOT EDIT. */
|
||||||
|
|
||||||
|
/*=======Test Runner Used To Run Each Test Below=====*/
|
||||||
|
#define RUN_TEST(TestFunc, TestLineNum) \
|
||||||
|
{ \
|
||||||
|
Unity.CurrentTestName = #TestFunc; \
|
||||||
|
Unity.CurrentTestLineNumber = TestLineNum; \
|
||||||
|
Unity.NumberOfTests++; \
|
||||||
|
if (TEST_PROTECT()) \
|
||||||
|
{ \
|
||||||
|
setUp(); \
|
||||||
|
TestFunc(); \
|
||||||
|
} \
|
||||||
|
if (TEST_PROTECT()) \
|
||||||
|
{ \
|
||||||
|
tearDown(); \
|
||||||
|
} \
|
||||||
|
UnityConcludeTest(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*=======Automagically Detected Files To Include=====*/
|
||||||
|
#include "unity.h"
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "ProductionCode2.h"
|
||||||
|
|
||||||
|
/*=======External Functions This Runner Calls=====*/
|
||||||
|
extern void setUp(void);
|
||||||
|
extern void tearDown(void);
|
||||||
|
extern void test_IgnoredTest(void);
|
||||||
|
extern void test_AnotherIgnoredTest(void);
|
||||||
|
extern void test_ThisFunctionHasNotBeenTested_NeedsToBeImplemented(void);
|
||||||
|
|
||||||
|
|
||||||
|
/*=======Test Reset Option=====*/
|
||||||
|
void resetTest(void);
|
||||||
|
void resetTest(void)
|
||||||
|
{
|
||||||
|
tearDown();
|
||||||
|
setUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*=======MAIN=====*/
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
UnityBegin("test/TestProductionCode2.c");
|
||||||
|
RUN_TEST(test_IgnoredTest, 18);
|
||||||
|
RUN_TEST(test_AnotherIgnoredTest, 23);
|
||||||
|
RUN_TEST(test_ThisFunctionHasNotBeenTested_NeedsToBeImplemented, 28);
|
||||||
|
|
||||||
|
return (UnityEnd());
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/* AUTOGENERATED FILE. DO NOT EDIT. */
|
||||||
|
|
||||||
|
/*=======Test Runner Used To Run Each Test Below=====*/
|
||||||
|
#define RUN_TEST(TestFunc, TestLineNum) \
|
||||||
|
{ \
|
||||||
|
Unity.CurrentTestName = #TestFunc; \
|
||||||
|
Unity.CurrentTestLineNumber = TestLineNum; \
|
||||||
|
Unity.NumberOfTests++; \
|
||||||
|
if (TEST_PROTECT()) \
|
||||||
|
{ \
|
||||||
|
setUp(); \
|
||||||
|
TestFunc(); \
|
||||||
|
} \
|
||||||
|
if (TEST_PROTECT()) \
|
||||||
|
{ \
|
||||||
|
tearDown(); \
|
||||||
|
} \
|
||||||
|
UnityConcludeTest(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*=======Automagically Detected Files To Include=====*/
|
||||||
|
#include "unity.h"
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "ProductionCode.h"
|
||||||
|
|
||||||
|
/*=======External Functions This Runner Calls=====*/
|
||||||
|
extern void setUp(void);
|
||||||
|
extern void tearDown(void);
|
||||||
|
extern void test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode(void);
|
||||||
|
extern void test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken(void);
|
||||||
|
extern void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue(void);
|
||||||
|
extern void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain(void);
|
||||||
|
extern void test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed(void);
|
||||||
|
|
||||||
|
|
||||||
|
/*=======Test Reset Option=====*/
|
||||||
|
void resetTest(void);
|
||||||
|
void resetTest(void)
|
||||||
|
{
|
||||||
|
tearDown();
|
||||||
|
setUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*=======MAIN=====*/
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
UnityBegin("test/TestProductionCode.c");
|
||||||
|
RUN_TEST(test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode, 20);
|
||||||
|
RUN_TEST(test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken, 30);
|
||||||
|
RUN_TEST(test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue, 41);
|
||||||
|
RUN_TEST(test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain, 51);
|
||||||
|
RUN_TEST(test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed, 57);
|
||||||
|
|
||||||
|
return (UnityEnd());
|
||||||
|
}
|
||||||
Loaded 100 of 193 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user