Compare commits
487 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae80f5ef57 | ||
|
|
b26e71f960 | ||
|
|
7a2615c231 | ||
|
|
e174831819 | ||
|
|
ac368e9dfb | ||
|
|
d1c2e2df4a | ||
|
|
04e27dc8c5 | ||
|
|
0d675cb048 | ||
|
|
45e1278acb | ||
|
|
217ab02612 | ||
|
|
e872d40223 | ||
|
|
21733eb02e | ||
|
|
a9ce4e6bbc | ||
|
|
eb8c0baa3b | ||
|
|
4e0c119391 | ||
|
|
38b2f40a9a | ||
|
|
d3bc571a38 | ||
|
|
48eaecd172 | ||
|
|
18ad8a8770 | ||
|
|
93227319f0 | ||
|
|
f0c1b896ba | ||
|
|
2d252ae595 | ||
|
|
c46c4d1559 | ||
|
|
1af74c8cc1 | ||
|
|
9bdf19fde1 | ||
|
|
bdd5ff7ad6 | ||
|
|
24ea388dcf | ||
|
|
39745c9c75 | ||
|
|
9585c38d5a | ||
|
|
c268e77b21 | ||
|
|
9f745a2251 | ||
|
|
010e31f2f2 | ||
|
|
8ea37fce01 | ||
|
|
b2fe02712d | ||
|
|
c179509b31 | ||
|
|
46c4f55c94 | ||
|
|
90ff72c8bb | ||
|
|
e9d1de24cf | ||
|
|
56f2bc6f3e | ||
|
|
cdc35ebf88 | ||
|
|
90a46eaccd | ||
|
|
2a3a313f83 | ||
|
|
a2a2411b12 | ||
|
|
03ba72faec | ||
|
|
569aa060c6 | ||
|
|
b9cc911831 | ||
|
|
9abe75e072 | ||
|
|
9189b3322a | ||
|
|
bfbd8fe0d8 | ||
|
|
82295f9e4f | ||
|
|
38b44a298d | ||
|
|
00d5e225a6 | ||
|
|
9ecc96878f | ||
|
|
3efee9fda8 | ||
|
|
71a7b64860 | ||
|
|
ddf268b074 | ||
|
|
de5df3e56f | ||
|
|
a167d9e381 | ||
|
|
b537ca70a3 | ||
|
|
186cce3ece | ||
|
|
6c9f76c100 | ||
|
|
2c9947eec9 | ||
|
|
9a85c26161 | ||
|
|
c0088e1ebe | ||
|
|
8738160e16 | ||
|
|
eb6dd6ef6b | ||
|
|
98fb2c9437 | ||
|
|
1217ca9e9f | ||
|
|
6e9c6edd91 | ||
|
|
2d6a2e0133 | ||
|
|
d9b23039b8 | ||
|
|
a01267c0a4 | ||
|
|
ffb877c94a | ||
|
|
e1f6470dae | ||
|
|
1d277eb99d | ||
|
|
9857ab9835 | ||
|
|
66f75619d9 | ||
|
|
7f22948eec | ||
|
|
b674519695 | ||
|
|
94057fb069 | ||
|
|
3bf2913634 | ||
|
|
cd4d7b9b6e | ||
|
|
73823c4b6d | ||
|
|
0aaef1a8fa | ||
|
|
e88be8681d | ||
|
|
222686513e | ||
|
|
62b08f1336 | ||
|
|
7de847eeea | ||
|
|
af9c76e37e | ||
|
|
2f33e8ec9b | ||
|
|
30906a01c0 | ||
|
|
eb017abe72 | ||
|
|
487a8b76a1 | ||
|
|
1d85450883 | ||
|
|
2616db9e92 | ||
|
|
23cbb173d4 | ||
|
|
a29c468b68 | ||
|
|
1d65f33d3d | ||
|
|
997ca129a2 | ||
|
|
cf1770b0ea | ||
|
|
aefe2f85ab | ||
|
|
7f645de322 | ||
|
|
e6c239db2b | ||
|
|
f4d9e2e1a1 | ||
|
|
e3ed64d56e | ||
|
|
6b01dee7ca | ||
|
|
b73881a388 | ||
|
|
bb2f868126 | ||
|
|
11b8a8cd76 | ||
|
|
01d656bebc | ||
|
|
7bf62ff4dc | ||
|
|
f030058183 | ||
|
|
a67c24c451 | ||
|
|
512c313111 | ||
|
|
e591d4173a | ||
|
|
bde341edd8 | ||
|
|
48c97985d6 | ||
|
|
63db67bfeb | ||
|
|
2040ce9004 | ||
|
|
4ba6bafe34 | ||
|
|
378a333ee2 | ||
|
|
4642d6575f | ||
|
|
4932c80f26 | ||
|
|
674a678819 | ||
|
|
b8e3673d0f | ||
|
|
b16bcc3c19 | ||
|
|
44d313212b | ||
|
|
055c7007e5 | ||
|
|
a1a860cd31 | ||
|
|
bc622fcc15 | ||
|
|
dede4e3246 | ||
|
|
8b953d1202 | ||
|
|
2d07bbc9b2 | ||
|
|
8816a568ab | ||
|
|
33193ea557 | ||
|
|
acb0ca88df | ||
|
|
c24c3e0285 | ||
|
|
cc3a75dd39 | ||
|
|
204c7ee43f | ||
|
|
48b3909946 | ||
|
|
b00ecfd311 | ||
|
|
87fad25c2b | ||
|
|
a69ad22639 | ||
|
|
28570ad095 | ||
|
|
303660ae04 | ||
|
|
18a7828940 | ||
|
|
7fe8d53c19 | ||
|
|
ee3c3bc80e | ||
|
|
18b4e2f941 | ||
|
|
ab77a80e9b | ||
|
|
949c083315 | ||
|
|
c4c217f2ce | ||
|
|
79f30800ec | ||
|
|
e0d3a8a265 | ||
|
|
5aa152fa83 | ||
|
|
a400888c1f | ||
|
|
3fc9bc0648 | ||
|
|
05f75e360b | ||
|
|
32626cc251 | ||
|
|
24cf9308de | ||
|
|
51d3df6c9f | ||
|
|
6ccfd5d603 | ||
|
|
49ebc85e7a | ||
|
|
8fd46d51b1 | ||
|
|
609bb75421 | ||
|
|
cea3fe4165 | ||
|
|
b759ff38b8 | ||
|
|
ba7b48b3f3 | ||
|
|
134ebf5e89 | ||
|
|
02a05eea4e | ||
|
|
d67b008d4b | ||
|
|
c66342d871 | ||
|
|
c960b2b853 | ||
|
|
3056d85f01 | ||
|
|
b470d918f3 | ||
|
|
8efb287ae2 | ||
|
|
a1602f484b | ||
|
|
d058a9cd8f | ||
|
|
f11b5eadc8 | ||
|
|
075a06f40b | ||
|
|
62ba68fc7d | ||
|
|
7276f4df05 | ||
|
|
8c900b9e07 | ||
|
|
e0a3c2370d | ||
|
|
3c18c83513 | ||
|
|
6ac896d8d2 | ||
|
|
2a25abbf2a | ||
|
|
e9803341d5 | ||
|
|
31400affab | ||
|
|
6c3df7eb59 | ||
|
|
a99d254e4f | ||
|
|
f0230a584f | ||
|
|
2148e3277a | ||
|
|
c786cd9714 | ||
|
|
238ceec175 | ||
|
|
6702037b68 | ||
|
|
eb5000ba61 | ||
|
|
655c26ada1 | ||
|
|
218b0c8dcf | ||
|
|
281df6997c | ||
|
|
bc0bb7c224 | ||
|
|
56a32f9ecc | ||
|
|
770e8263a5 | ||
|
|
2683589d93 | ||
|
|
c837177a56 | ||
|
|
80bc7652ae | ||
|
|
87a204ed0b | ||
|
|
c9739c59fd | ||
|
|
778a0c146f | ||
|
|
f69b109c9f | ||
|
|
fef1c45b92 | ||
|
|
033a542532 | ||
|
|
fd0320cf54 | ||
|
|
0f98214e71 | ||
|
|
06a2326e3b | ||
|
|
11131b9ced | ||
|
|
99db5db9a4 | ||
|
|
bb5ab5916f | ||
|
|
411c50f671 | ||
|
|
ec2db50b6f | ||
|
|
74d0525201 | ||
|
|
3efef58c32 | ||
|
|
65541b900c | ||
|
|
c08f7e1d29 | ||
|
|
71b96afc27 | ||
|
|
749fefc0c4 | ||
|
|
50b3c30dfa | ||
|
|
c784f76c77 | ||
|
|
84237ff48e | ||
|
|
ab8489a851 | ||
|
|
795c3acabe | ||
|
|
2683d4d987 | ||
|
|
3c1bfe125c | ||
|
|
5916f70640 | ||
|
|
29cfc7a767 | ||
|
|
b1e9a6c0da | ||
|
|
3a20692c18 | ||
|
|
2f65e80a34 | ||
|
|
ef34500693 | ||
|
|
b0dfcde04c | ||
|
|
1934059554 | ||
|
|
cc84a446be | ||
|
|
e58f7ec027 | ||
|
|
4bfb880093 | ||
|
|
b7ce06224b | ||
|
|
227d3398d6 | ||
|
|
466eb8e3f8 | ||
|
|
4ec6e76ea2 | ||
|
|
a1b37d0abe | ||
|
|
3d971db426 | ||
|
|
30e1e7af7c | ||
|
|
76e5296d0d | ||
|
|
c597601cf1 | ||
|
|
e3d5798896 | ||
|
|
cf1842dc6f | ||
|
|
030d0c14cc | ||
|
|
02cd3eec37 | ||
|
|
bdb59f09de | ||
|
|
5f783fff11 | ||
|
|
7969af6434 | ||
|
|
0bb1843925 | ||
|
|
5ea4fad263 | ||
|
|
1749de02f8 | ||
|
|
748f4bfd4f | ||
|
|
bea1d102fd | ||
|
|
d441fa05b3 | ||
|
|
3fe72cf2b8 | ||
|
|
d8d0ae66d3 | ||
|
|
9d07917feb | ||
|
|
2c45ad7816 | ||
|
|
ad5abf4c5b | ||
|
|
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 | ||
|
|
de8eaaba89 | ||
|
|
b2da44d6cb | ||
|
|
f6998a6a34 | ||
|
|
e3e0b5150b | ||
|
|
1df987a170 | ||
|
|
ddadb44a67 | ||
|
|
9ef44fc0b6 | ||
|
|
8c58e62597 | ||
|
|
8893e39712 | ||
|
|
3d6ae11340 | ||
|
|
a1f2600883 | ||
|
|
fcc85bdfbc | ||
|
|
7d08a3518a | ||
|
|
cc486a0354 | ||
|
|
fcc89c4bb2 | ||
|
|
a0431e226f | ||
|
|
89edfb6741 | ||
|
|
e69db83de5 | ||
|
|
5310da351d | ||
|
|
68196f5b14 | ||
|
|
d992cd46e6 | ||
|
|
84b48121bb | ||
|
|
f10e2f884a | ||
|
|
eeb6d237b6 | ||
|
|
5b4420298f | ||
|
|
e1eb06fae0 | ||
|
|
6aefa45056 | ||
|
|
345d57e9e5 | ||
|
|
3da18a2df9 | ||
|
|
bf17703012 | ||
|
|
6622c54f18 | ||
|
|
8df4cd46eb | ||
|
|
3917fb5255 | ||
|
|
99896d879c | ||
|
|
4d1dcaa160 | ||
|
|
de93d76d0b | ||
|
|
602c241a0b | ||
|
|
23dafa4739 | ||
|
|
59cf4112d2 | ||
|
|
5cfda2292f | ||
|
|
038b04d80a | ||
|
|
624bc85143 | ||
|
|
1f0ad823c9 | ||
|
|
29b6643bab | ||
|
|
a8e1368697 | ||
|
|
bea0be48b6 | ||
|
|
91d11cd050 | ||
|
|
9591ecddbe | ||
|
|
1568015de6 | ||
|
|
7ed067e680 | ||
|
|
4703f01cf4 | ||
|
|
d0a9f46888 | ||
|
|
23b269d5f9 | ||
|
|
11fd27ade7 | ||
|
|
65ac0a1a2b | ||
|
|
679004914f | ||
|
|
b88da9b0de | ||
|
|
a5ff796c20 | ||
|
|
d47339e274 | ||
|
|
06008b0444 |
54
.github/CONTRIBUTING.md
vendored
Normal file
54
.github/CONTRIBUTING.md
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
Contribution Guidelines
|
||||
=======================
|
||||
|
||||
Contributions to cJSON are welcome. If you find a bug or want to improve cJSON in another way, pull requests are appreciated.
|
||||
|
||||
For bigger changes, in order to avoid wasted effort, please open an issue to discuss the technical details before creating a pull request.
|
||||
|
||||
The further sections explain the process in more detail and provides some guidelines on how contributions should look like.
|
||||
|
||||
Branches
|
||||
--------
|
||||
There are two branches to be aware of, the `master` and the `develop` branch. The `master` branch is reserved for the latest release, so only make pull requests to the `master` branch for small bug- or security fixes (these are usually just a few lines). In all other cases, please make a pull request to the `develop` branch.
|
||||
|
||||
Coding Style
|
||||
------------
|
||||
The coding style has been discussed in [#24](https://github.com/DaveGamble/cJSON/issues/24). The basics are:
|
||||
|
||||
* Use 4 tabs for indentation
|
||||
* No oneliners (conditions, loops, variable declarations ...)
|
||||
* Always use parenthesis for control structures
|
||||
* Don't implicitly rely on operator precedence, use round brackets in expressions. e.g. `(a > b) && (c < d)` instead of `a>b && c<d`
|
||||
* opening curly braces start in the next line
|
||||
* use spaces around operators
|
||||
* lines should not have trailing whitespace
|
||||
* use spaces between function parameters
|
||||
* use pronouncable variable names, not just a combination of letters
|
||||
|
||||
Example:
|
||||
|
||||
```c
|
||||
/* calculate the new length of the string in a printbuffer and update the offset */
|
||||
static void update_offset(printbuffer * const buffer)
|
||||
{
|
||||
const unsigned char *buffer_pointer = NULL;
|
||||
if ((buffer == NULL) || (buffer->buffer == NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
buffer_pointer = buffer->buffer + buffer->offset;
|
||||
|
||||
buffer->offset += strlen((const char*)buffer_pointer);
|
||||
}
|
||||
```
|
||||
|
||||
Unit Tests
|
||||
----------
|
||||
cJSON uses the [Unity](https://github.com/ThrowTheSwitch/Unity) library for unit tests. The tests are located in the `tests` directory. In order to add a new test, either add it to one of the existing files (if it fits) or add a new C file for the test. That new file has to be added to the list of tests in `tests/CMakeLists.txt`.
|
||||
|
||||
All new features have to be covered by unit tests.
|
||||
|
||||
Other Notes
|
||||
-----------
|
||||
* Internal functions are to be declared static.
|
||||
* Wrap the return type of external function in the `CJSON_PUBLIC` macro.
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -8,3 +8,8 @@ test
|
||||
tags
|
||||
*.dylib
|
||||
build/
|
||||
cJSON_test
|
||||
cJSON_test_utils
|
||||
libcjson.so.*
|
||||
libcjson_utils.so.*
|
||||
*.orig
|
||||
|
||||
28
.travis.yml
Normal file
28
.travis.yml
Normal file
@@ -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
|
||||
252
CHANGELOG.md
Normal file
252
CHANGELOG.md
Normal file
@@ -0,0 +1,252 @@
|
||||
1.5.6
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Make cJSON a lot more tolerant about passing NULL pointers to its functions, it should now fail safely instead of dereferencing the pointer. (#183) Thanks @msichal for reporting #182
|
||||
|
||||
1.5.5
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix pointers to nested arrays in cJSON_Utils (9abe75e072050f34732a7169740989a082b65134)
|
||||
* Fix an error with case sensitivity handling in cJSON_Utils (b9cc911831b0b3e1bb72f142389428e59f882b38)
|
||||
* Fix cJSON_Compare for arrays that are prefixes of the other and objects that are a subset of the other (03ba72faec115160d1f3aea5582d9b6af5d3e473) See #180, thanks @zhengqb for reporting
|
||||
|
||||
1.5.4
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix build with GCC 7.1.1 and optimization level `-O2` (bfbd8fe0d85f1dd21e508748fc10fc4c27cc51be)
|
||||
|
||||
Other Changes:
|
||||
--------------
|
||||
* Update [Unity](https://github.com/ThrowTheSwitch/Unity) to 3b69beaa58efc41bbbef70a32a46893cae02719d
|
||||
|
||||
1.5.3
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix `cJSON_ReplaceItemInObject` not keeping the name of an item (#174)
|
||||
|
||||
1.5.2
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix a reading buffer overflow in `parse_string` (a167d9e381e5c84bc03de4e261757b031c0c690d)
|
||||
* Fix compiling with -Wcomma (186cce3ece6ce6dfcb58ac8b2a63f7846c3493ad)
|
||||
* Remove leftover attribute from tests (b537ca70a35680db66f1f5b8b437f7114daa699a)
|
||||
|
||||
1.5.1
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Add gcc version guard to the Makefile (#164), thanks @juvasquezg
|
||||
* Fix incorrect free in `cJSON_Utils` if custom memory allocator is used (#166), thanks @prefetchnta
|
||||
|
||||
1.5.0
|
||||
=====
|
||||
Features:
|
||||
---------
|
||||
* cJSON finally prints numbers without losing precision (#153) thanks @DeboraG
|
||||
* `cJSON_Compare` recursively checks if two cJSON items contain the same values (#148)
|
||||
* Provide case sensitive versions of every function where it matters (#158, #159)
|
||||
* Added `cJSON_ReplaceItemViaPointer` and `cJSON_DetachItemViaPointer`
|
||||
* Added `cJSON_free` and `cJSON_malloc` that expose the internal configured memory allocators. (02a05eea4e6ba41811f130b322660bea8918e1a0)
|
||||
|
||||
|
||||
Enhancements:
|
||||
-------------
|
||||
* Parse into a buffer, this will allow parsing `\u0000` in the future (not quite yet though)
|
||||
* General simplifications and readability improvements
|
||||
* More unit tests
|
||||
* Update [unity](https://github.com/ThrowTheSwitch/Unity) testing library to 2.4.1
|
||||
* Add the [json-patch-tests](https://github.com/json-patch/json-patch-tests) test suite to test cJSON_Utils.
|
||||
* Move all tests from `test_utils.c` to unit tests with unity.
|
||||
|
||||
Fixes:
|
||||
------
|
||||
* Fix some warnings with the Microsoft compiler (#139) thanks @PawelWMS
|
||||
* Fix several bugs in cJSON_Utils, mostly found with [json-patch-tests](https://github.com/json-patch/json-patch-tests)
|
||||
* Prevent a stack overflow by specifying a maximum nesting depth `CJSON_NESTING_LIMIT`
|
||||
|
||||
Other Changes:
|
||||
--------------
|
||||
* Move generated files in the `library_config` subdirectory.
|
||||
|
||||
1.4.7
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix `cJSONUtils_ApplyPatches`, it was completely broken and apparently nobody noticed (or at least reported it) (075a06f40bdc4f836c7dd7cad690d253a57cfc50)
|
||||
* Fix inconsistent prototype for `cJSON_GetObjectItemCaseSensitive` (51d3df6c9f7b56b860c8fb24abe7bab255cd4fa9) thanks @PawelWMS
|
||||
|
||||
1.4.6
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Several corrections in the README
|
||||
* Making clear that `valueint` should not be written to
|
||||
* Fix overflow detection in `ensure` (2683d4d9873df87c4bdccc523903ddd78d1ad250)
|
||||
* Fix a potential null pointer dereference in cJSON_Utils (795c3acabed25c9672006b2c0f40be8845064827)
|
||||
* Replace incorrect `sizeof('\0')` with `sizeof("")` (84237ff48e69825c94261c624eb0376d0c328139)
|
||||
* Add caveats section to the README (50b3c30dfa89830f8f477ce33713500740ac3b79)
|
||||
* Make cJSON locale independent (#146) Thanks @peterh for reporting
|
||||
* Fix compiling without CMake with MSVC (#147) Thanks @dertuxmalwieder for reporting
|
||||
|
||||
1.4.5
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix bug in `cJSON_SetNumberHelper`, thanks @mmkeeper (#138 ef34500693e8c4a2849d41a4bd66fd19c9ec46c2)
|
||||
* Workaround for internal compiler error in GCC 5.4.0 and 6.3.1 on x86 (2f65e80a3471d053fdc3f8aed23d01dd1782a5cb [GCC bugreport](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80097))
|
||||
|
||||
1.4.4
|
||||
=====
|
||||
Fixes:
|
||||
--------
|
||||
* Fix a theoretical integer overflow, (not sure if it is possible on actual hardware) e58f7ec027d00b7cdcbf63e518c1b5268b29b3da
|
||||
* Fix an off by one error (cc84a446be20cc283bafdc4d94c050ba1111ac02), thanks @gatzka
|
||||
* Double check the offset of the print buffer in `ensure` (1934059554b9a0971e00f79e96900f422cfdd114)
|
||||
|
||||
Improvements:
|
||||
-------------
|
||||
* Add a note in the header about required buffer size when using `cJSON_PrintPreallocated` (4bfb88009342fb568295a7f6dc4b7fee74fbf022)
|
||||
|
||||
1.4.3
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix compilation of the tests on 32 bit PowerPC and potentially other systems (4ec6e76ea2eec16f54b58e8c95b4c734e59481e4)
|
||||
* Fix compilation with old GCC compilers (4.3+ were tested) (227d3398d6b967879761ebe02c1b63dbd6ea6e0d, 466eb8e3f8a65080f2b3ca4a79ab7b72bd539dba), see also #126
|
||||
|
||||
1.4.2
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix minimum required cmake version (30e1e7af7c63db9b55f5a3cda977a6c032f0b132)
|
||||
* Fix detection of supported compiler flags (76e5296d0d05ceb3018a9901639e0e171b44a557)
|
||||
* Run `cJSON_test` and `cJSON_test_utils` along with unity tests (c597601cf151a757dcf800548f18034d4ddfe2cb)
|
||||
|
||||
1.4.1
|
||||
=====
|
||||
Fix: Make `print_number` abort with a failure in out of memory situations (cf1842dc6f64c49451a022308b4415e4d468be0a)
|
||||
|
||||
1.4.0
|
||||
=====
|
||||
Features
|
||||
--------
|
||||
* Functions to check the type of an item (#120)
|
||||
* Use dllexport on windows and fvisibility on Unix systems for public functions (#116), thanks @mjerris
|
||||
* Remove trailing zeroes from printed numbers (#123)
|
||||
* Expose the internal boolean type `cJSON_bool` in the header (2d3520e0b9d0eb870e8886e8a21c571eeddbb310)
|
||||
|
||||
Fixes
|
||||
-----
|
||||
* Fix handling of NULL pointers in `cJSON_ArrayForEach` (b47d0e34caaef298edfb7bd09a72cfff21d231ff)
|
||||
* Make it compile with GCC 7 (fix -Wimplicit-fallthrough warning) (9d07917feb1b613544a7513d19233d4c851ad7ad)
|
||||
|
||||
Other Improvements
|
||||
------------------
|
||||
* internally use realloc if available (#110)
|
||||
* builtin support for fuzzing with [afl](http://lcamtuf.coredump.cx/afl/) (#111)
|
||||
* unit tests for the print functions (#112)
|
||||
* Always use buffered printing (#113)
|
||||
* simplify the print functions (#114)
|
||||
* Add the compiler flags `-Wdouble-conversion`, `-Wparentheses` and `-Wcomma` (#122)
|
||||
|
||||
1.3.2
|
||||
=====
|
||||
Fix:
|
||||
----
|
||||
- Don't build the unity library if testing is disabled ( #121 ). Thanks @ffontaine
|
||||
|
||||
1.3.1
|
||||
=====
|
||||
Bugfix release that fixes an out of bounds read #118. This shouldn't have any security implications.
|
||||
|
||||
1.3.0
|
||||
=====
|
||||
This release includes a lot of rework in the parser and includes the Cunity unit testing framework, as well as some fixes. I increased the minor version number because there were quite a lot of internal changes.
|
||||
|
||||
Features:
|
||||
---------
|
||||
- New type for cJSON structs: `cJSON_Invalid` (#108)
|
||||
|
||||
Fixes:
|
||||
------
|
||||
- runtime checks for a lot of potential integer overflows
|
||||
- fix incorrect return in cJSON_PrintBuffered (cf9d57d56cac21fc59465b8d26cf29bf6d2a87b3)
|
||||
- fix several potential issues found by [Coverity](https://scan.coverity.com/projects/cjson)
|
||||
- fix potentially undefined behavior when assigning big numbers to `valueint` (41e2837df1b1091643aff073f2313f6ff3cc10f4)
|
||||
- Numbers exceeding `INT_MAX` or lower than `INT_MIN` will be explicitly assigned to `valueint` as `INT_MAX` and `INT_MIN` respectively (saturation on overflow).
|
||||
- fix the `cJSON_SetNumberValue` macro (87f77274de6b3af00fb9b9a7f3b900ef382296c2), this slightly changes the behavior, see commit message
|
||||
|
||||
Introduce unit tests
|
||||
--------------------
|
||||
|
||||
Started writing unit tests with the [Cunity](https://github.com/ThrowTheSwitch/Unity) testing framework. Currently this covers the parser functions.
|
||||
|
||||
Also:
|
||||
- Support for running the tests with [Valgrind](http://valgrind.org)
|
||||
- Support for compiling the tests with [AddressSanitizer](https://github.com/google/sanitizers) and [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html).
|
||||
- `travis.yml` file for running unit tests on travis. (not enabled for the repository yet though #102)
|
||||
|
||||
Simplifications
|
||||
---------------
|
||||
|
||||
After having unit tests for the parser function in place, I started refactoring the parser functions (as well as others) and making them easier to read and maintain.
|
||||
- Use `strtod` from the standard library for parsing numbers (074766997246481dfc72bfa78f07898a2716473f)
|
||||
- Use goto-fail in several parser functions (#100)
|
||||
- Rewrite/restructure all of the parsing functions to be easier to understand and have less code paths doing the same as another. (#109)
|
||||
- Simplify the buffer allocation strategy to always doubling the needed amount (9f6fa94c91a87b71e4c6868dbf2ce431a48517b0)
|
||||
- Combined `cJSON_AddItemToObject` and `cJSON_AddItemToObjectCS` to one function (cf862d0fed7f9407e4b046d78d3d8050d2080d12)
|
||||
|
||||
Other changes
|
||||
-------------
|
||||
- Prevent the usage of incompatible C and header versions via preprocessor directive (123bb1af7bfae41d805337fef4b41045ef6c7d25)
|
||||
- Let CMake automatically detect compiler flags
|
||||
- Add new compiler flags (`-Wundef`, `-Wswitch-default`, `-Wconversion`, `-fstack-protector-strong`) (#98)
|
||||
- Change internal sizes from `int` to `size_t` (ecd5678527a6bc422da694e5be9e9979878fe6a0)
|
||||
- Change internal strings from `char*` to `unsigned char*` (28b9ba4334e0f7309e867e874a31f395c0ac2474)
|
||||
- Add `const` in more places
|
||||
|
||||
1.2.1
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
- Fixes a potential null pointer dereference in cJSON_Utils, discovered using clang's static analyzer by @bnason-nf (#96)
|
||||
|
||||
1.2.0
|
||||
=====
|
||||
Features:
|
||||
---------
|
||||
- Add a new type of cJSON item for raw JSON and support printing it. Thanks @loigu (#65, #90)
|
||||
|
||||
Fixes:
|
||||
------
|
||||
- Compiler warning if const is casted away, Thanks @gatzka (#83)
|
||||
- Fix compile error with strict-overflow on PowerPC, (#85)
|
||||
- Fix typo in the README, thanks @MicroJoe (#88)
|
||||
- Add compile flag for compatibility with C++ compilers
|
||||
|
||||
1.1.0
|
||||
=====
|
||||
- Add a function `cJSON_PrintPreallocated` to print to a preallocated buffer, thanks @ChisholmKyle (#72)
|
||||
- More compiler warnings when using Clang or GCC, thanks @gatzka (#75, #78)
|
||||
- fixed a memory leak in `cJSON_Duplicate`, thanks @alperakcan (#81)
|
||||
- fix the `ENABLE_CUSTOM_COMPILER_FLAGS` cmake option
|
||||
|
||||
1.0.2
|
||||
=====
|
||||
Rename internal boolean type, see #71.
|
||||
|
||||
1.0.1
|
||||
=====
|
||||
Small bugfix release.
|
||||
- Fixes a bug with the use of the cJSON structs type in cJSON_Utils, see d47339e2740360e6e0994527d5e4752007480f3a
|
||||
- improve code readability
|
||||
- initialize all variables
|
||||
|
||||
1.0.0
|
||||
=====
|
||||
This is the first official versioned release of cJSON. It provides an API version for the shared library and improved Makefile and CMake build files.
|
||||
152
CMakeLists.txt
152
CMakeLists.txt
@@ -1,24 +1,102 @@
|
||||
set(CMAKE_LEGACY_CYGWIN_WIN32 0)
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
cmake_minimum_required(VERSION 2.8.5)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
project(cJSON C)
|
||||
|
||||
set(PROJECT_VERSION_MAJOR 1)
|
||||
set(PROJECT_VERSION_MINOR 0)
|
||||
set(PROJECT_VERSION_PATCH 0)
|
||||
set(PROJECT_VERSION_MINOR 5)
|
||||
set(PROJECT_VERSION_PATCH 6)
|
||||
set(CJSON_VERSION_SO 1)
|
||||
set(CJSON_UTILS_VERSION_SO 1)
|
||||
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
||||
|
||||
option(ENABLE_CUSTOM_COMPILER_FLAGS ON)
|
||||
|
||||
set(custom_compiler_flags)
|
||||
|
||||
include(CheckCCompilerFlag)
|
||||
option(ENABLE_CUSTOM_COMPILER_FLAGS "Enables custom compiler flags" ON)
|
||||
if (ENABLE_CUSTOM_COMPILER_FLAGS)
|
||||
if(("${CMAKE_C_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_C_COMPILER_ID}" MATCHES "Clang"))
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c89 -pedantic -Wall -Wextra -Werror -Wstrict-prototypes -Wwrite-strings")
|
||||
if (("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") OR ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU"))
|
||||
list(APPEND custom_compiler_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
|
||||
-Wundef
|
||||
-Wswitch-default
|
||||
-Wconversion
|
||||
-Wc++-compat
|
||||
-fstack-protector-strong
|
||||
-Wcomma
|
||||
-Wdouble-promotion
|
||||
-Wparentheses
|
||||
-Wformat-overflow
|
||||
-Wunused-macros
|
||||
-Wmissing-variable-declarations
|
||||
-Wused-but-marked-unused
|
||||
-Wswitch-enum
|
||||
)
|
||||
elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC")
|
||||
list(APPEND custom_compiler_flags
|
||||
/GS
|
||||
/Za
|
||||
/sdl
|
||||
/W4
|
||||
)
|
||||
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})
|
||||
list(APPEND supported_compiler_flags)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${compiler_flag}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${supported_compiler_flags}")
|
||||
|
||||
#variables for pkg-config
|
||||
set(prefix "${CMAKE_INSTALL_PREFIX}")
|
||||
set(libdir "${CMAKE_INSTALL_LIBDIR}")
|
||||
@@ -34,17 +112,30 @@ set(CJSON_LIB cjson)
|
||||
file(GLOB HEADERS cJSON.h)
|
||||
set(SOURCES cJSON.c)
|
||||
|
||||
add_library("${CJSON_LIB}" "${HEADERS}" "${SOURCES}")
|
||||
option(BUILD_SHARED_AND_STATIC_LIBS "Build both shared and static libraries" Off)
|
||||
|
||||
if (NOT BUILD_SHARED_AND_STATIC_LIBS)
|
||||
add_library("${CJSON_LIB}" "${HEADERS}" "${SOURCES}")
|
||||
else()
|
||||
# See https://cmake.org/Wiki/CMake_FAQ#How_do_I_make_my_shared_and_static_libraries_have_the_same_root_name.2C_but_different_suffixes.3F
|
||||
add_library("${CJSON_LIB}" SHARED "${HEADERS}" "${SOURCES}")
|
||||
add_library("${CJSON_LIB}-static" STATIC "${HEADERS}" "${SOURCES}")
|
||||
set_target_properties("${CJSON_LIB}-static" PROPERTIES OUTPUT_NAME "${CJSON_LIB}")
|
||||
set_target_properties("${CJSON_LIB}-static" PROPERTIES PREFIX "lib")
|
||||
endif()
|
||||
if (NOT WIN32)
|
||||
target_link_libraries("${CJSON_LIB}" m)
|
||||
endif()
|
||||
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/libcjson.pc.in"
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/library_config/libcjson.pc.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/libcjson.pc" @ONLY)
|
||||
|
||||
install(FILES cJSON.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/cjson")
|
||||
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
install(TARGETS "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}" EXPORT "${CJSON_LIB}")
|
||||
if (BUILD_SHARED_AND_STATIC_LIBS)
|
||||
install(TARGETS "${CJSON_LIB}-static" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||
endif()
|
||||
if(ENABLE_TARGET_EXPORT)
|
||||
# export library information for CMake projects
|
||||
install(EXPORT "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cJSON")
|
||||
@@ -63,13 +154,25 @@ if(ENABLE_CJSON_UTILS)
|
||||
file(GLOB HEADERS_UTILS cJSON_Utils.h)
|
||||
set(SOURCES_UTILS cJSON_Utils.c)
|
||||
|
||||
add_library("${CJSON_UTILS_LIB}" "${HEADERS_UTILS}" "${SOURCES_UTILS}")
|
||||
target_link_libraries("${CJSON_UTILS_LIB}" "${CJSON_LIB}")
|
||||
if (NOT BUILD_SHARED_AND_STATIC_LIBS)
|
||||
add_library("${CJSON_UTILS_LIB}" "${HEADERS_UTILS}" "${SOURCES_UTILS}")
|
||||
target_link_libraries("${CJSON_UTILS_LIB}" "${CJSON_LIB}")
|
||||
else()
|
||||
add_library("${CJSON_UTILS_LIB}" SHARED "${HEADERS_UTILS}" "${SOURCES_UTILS}")
|
||||
target_link_libraries("${CJSON_UTILS_LIB}" "${CJSON_LIB}")
|
||||
add_library("${CJSON_UTILS_LIB}-static" STATIC "${HEADERS_UTILS}" "${SOURCES_UTILS}")
|
||||
target_link_libraries("${CJSON_UTILS_LIB}-static" "${CJSON_LIB}-static")
|
||||
set_target_properties("${CJSON_UTILS_LIB}-static" PROPERTIES OUTPUT_NAME "${CJSON_UTILS_LIB}")
|
||||
set_target_properties("${CJSON_UTILS_LIB}-static" PROPERTIES PREFIX "lib")
|
||||
endif()
|
||||
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/libcjson_utils.pc.in"
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/library_config/libcjson_utils.pc.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/libcjson_utils.pc" @ONLY)
|
||||
|
||||
install(TARGETS "${CJSON_UTILS_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}" EXPORT "${CJSON_UTILS_LIB}")
|
||||
if (BUILD_SHARED_AND_STATIC_LIBS)
|
||||
install(TARGETS "${CJSON_UTILS_LIB}-static" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||
endif()
|
||||
install(FILES cJSON_Utils.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/cjson")
|
||||
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson_utils.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
if(ENABLE_TARGET_EXPORT)
|
||||
@@ -85,10 +188,10 @@ endif()
|
||||
|
||||
# create the other package config files
|
||||
configure_file(
|
||||
cJSONConfig.cmake.in
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/library_config/cJSONConfig.cmake.in"
|
||||
${PROJECT_BINARY_DIR}/cJSONConfig.cmake @ONLY)
|
||||
configure_file(
|
||||
cJSONConfigVersion.cmake.in
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/library_config/cJSONConfigVersion.cmake.in"
|
||||
${PROJECT_BINARY_DIR}/cJSONConfigVersion.cmake @ONLY)
|
||||
|
||||
# Install package config files
|
||||
@@ -98,13 +201,28 @@ install(FILES ${PROJECT_BINARY_DIR}/cJSONConfig.cmake
|
||||
|
||||
option(ENABLE_CJSON_TEST "Enable building cJSON test" ON)
|
||||
if(ENABLE_CJSON_TEST)
|
||||
enable_testing()
|
||||
|
||||
set(TEST_CJSON cJSON_test)
|
||||
add_executable("${TEST_CJSON}" test.c)
|
||||
target_link_libraries("${TEST_CJSON}" "${CJSON_LIB}")
|
||||
|
||||
if(ENABLE_CJSON_UTILS)
|
||||
set(TEST_CJSON_UTILS cJSON_test_utils)
|
||||
add_executable("${TEST_CJSON_UTILS}" test_utils.c)
|
||||
target_link_libraries("${TEST_CJSON_UTILS}" "${CJSON_UTILS_LIB}")
|
||||
add_test(NAME ${TEST_CJSON} COMMAND "${CMAKE_CURRENT_BINARY_DIR}/${TEST_CJSON}")
|
||||
|
||||
# Disable -fsanitize=float-divide-by-zero for cJSON_test
|
||||
if (FLAG_SUPPORTED_fsanitizefloatdividebyzero)
|
||||
if ("${CMAKE_VERSION}" VERSION_LESS "2.8.12")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-sanitize=float-divide-by-zero")
|
||||
else()
|
||||
target_compile_options(${TEST_CJSON} PRIVATE "-fno-sanitize=float-divide-by-zero")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#"check" target that automatically builds everything and runs the tests
|
||||
add_custom_target(check
|
||||
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
|
||||
DEPENDS ${TEST_CJSON})
|
||||
endif()
|
||||
|
||||
add_subdirectory(tests)
|
||||
add_subdirectory(fuzzing)
|
||||
|
||||
@@ -2,26 +2,37 @@ Contributors
|
||||
============
|
||||
|
||||
* [Ajay Bhargav](https://github.com/ajaybhargav)
|
||||
* [Alper Akcan](https://github.com/alperakcan)
|
||||
* [Anton Sergeev](https://github.com/anton-sergeev)
|
||||
* [Christian Schulze](https://github.com/ChristianSch)
|
||||
* [Dave Gamble](https://github.com/DaveGamble)
|
||||
* [Debora Grosse](https://github.com/DeboraG)
|
||||
* [dieyushi](https://github.com/dieyushi)
|
||||
* [Dongwen Huang (黄东文)](https://github.com/DongwenHuang)
|
||||
* [Dōngwén Huáng (黄东文)](https://github.com/DongwenHuang)
|
||||
* Eswar Yaganti
|
||||
* [Evan Todd](https://github.com/etodd)
|
||||
* [Fabrice Fontaine](https://github.com/ffontaine)
|
||||
* Ian Mobley
|
||||
* Irwan Djadjadi
|
||||
* [IvanVoid](https://github.com/npi3pak)
|
||||
* [Jiri Zouhar](https://github.com/loigu)
|
||||
* [Jonathan Fether](https://github.com/jfether)
|
||||
* [Julián Vásquez](https://github.com/juvasquezg)
|
||||
* [Kevin Branigan](https://github.com/kbranigan)
|
||||
* [Kyle Chisholm](https://github.com/ChisholmKyle)
|
||||
* [Linus Wallgren](https://github.com/ecksun)
|
||||
* [Max Bruckner](https://github.com/FSMaxB)
|
||||
* Mike Pontillo
|
||||
* [Mike Jerris](https://github.com/mjerris)
|
||||
* [Mike Robinson](https://github.com/mhrobinson)
|
||||
* Paulo Antonio Alvarez
|
||||
* [Pawel Winogrodzki](https://github.com/PawelWMS)
|
||||
* [prefetchnta](https://github.com/prefetchnta)
|
||||
* [Rafael Leal Dias](https://github.com/rafaeldias)
|
||||
* [Rod Vagg](https://github.com/rvagg)
|
||||
* [Roland Meertens](https://github.com/rmeertens)
|
||||
* [Romain Porte](https://github.com/MicroJoe)
|
||||
* [Stephan Gatzka](https://github.com/gatzka)
|
||||
* [Weston Schmidt](https://github.com/schmidtw)
|
||||
|
||||
And probably more people on [SourceForge](https://sourceforge.net/p/cjson/bugs/search/?q=status%3Aclosed-rejected+or+status%3Aclosed-out-of-date+or+status%3Awont-fix+or+status%3Aclosed-fixed+or+status%3Aclosed&page=0)
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
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
|
||||
|
||||
26
Makefile
26
Makefile
@@ -3,11 +3,12 @@ UTILS_OBJ = cJSON_Utils.o
|
||||
CJSON_LIBNAME = libcjson
|
||||
UTILS_LIBNAME = libcjson_utils
|
||||
CJSON_TEST = cJSON_test
|
||||
UTILS_TEST = cJSON_test_utils
|
||||
|
||||
CJSON_TEST_SRC = cJSON.c test.c
|
||||
|
||||
LDLIBS = -lm
|
||||
|
||||
LIBVERSION = 1.0.0
|
||||
LIBVERSION = 1.5.6
|
||||
CJSON_SOVERSION = 1
|
||||
UTILS_SOVERSION = 1
|
||||
|
||||
@@ -20,7 +21,17 @@ INSTALL_LIBRARY_PATH = $(DESTDIR)$(PREFIX)/$(LIBRARY_PATH)
|
||||
|
||||
INSTALL ?= cp -a
|
||||
|
||||
R_CFLAGS = -fPIC -std=c89 -pedantic -Wall -Werror -Wstrict-prototypes -Wwrite-strings $(CFLAGS)
|
||||
# validate gcc version for use fstack-protector-strong
|
||||
MIN_GCC_VERSION = "4.9"
|
||||
GCC_VERSION := "`gcc -dumpversion`"
|
||||
IS_GCC_ABOVE_MIN_VERSION := $(shell expr "$(GCC_VERSION)" ">=" "$(MIN_GCC_VERSION)")
|
||||
ifeq "$(IS_GCC_ABOVE_MIN_VERSION)" "1"
|
||||
CFLAGS += -fstack-protector-strong
|
||||
else
|
||||
CFLAGS += -fstack-protector
|
||||
endif
|
||||
|
||||
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 $(CFLAGS)
|
||||
|
||||
uname := $(shell sh -c 'uname -s 2>/dev/null || echo false')
|
||||
|
||||
@@ -62,15 +73,12 @@ test: tests
|
||||
./$(UTILS_TEST)
|
||||
|
||||
.c.o:
|
||||
$(CC) -ansi -pedantic -c $(R_CFLAGS) $<
|
||||
$(CC) -c $(R_CFLAGS) $<
|
||||
|
||||
#tests
|
||||
#cJSON
|
||||
$(CJSON_TEST): cJSON.c cJSON.h test.c
|
||||
$(CC) $^ -o $@ $(LDLIBS) -I.
|
||||
#cJSON_Utils
|
||||
$(UTILS_TEST): cJSON.c cJSON.h test.c
|
||||
$(CC) $^ -o $@ $(LDLIBS) -I.
|
||||
$(CJSON_TEST): $(CJSON_TEST_SRC) cJSON.h
|
||||
$(CC) $(R_CFLAGS) $(CJSON_TEST_SRC) -o $@ $(LDLIBS) -I.
|
||||
|
||||
#static libraries
|
||||
#cJSON
|
||||
|
||||
91
README.md
91
README.md
@@ -9,11 +9,14 @@ Ultralightweight JSON parser in ANSI C.
|
||||
* [Building](#building)
|
||||
* [Some JSON](#some-json)
|
||||
* [Here's the structure](#heres-the-structure)
|
||||
* [Caveats](#caveats)
|
||||
* [Enjoy cJSON!](#enjoy-cjson)
|
||||
|
||||
## License
|
||||
|
||||
> Copyright (c) 2009-2016 Dave Gamble
|
||||
MIT License
|
||||
|
||||
> 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
|
||||
@@ -62,7 +65,7 @@ Because the entire library is only one C file and one header file, you can just
|
||||
cJSON is written in ANSI C (C89) in order to support as many platforms and compilers as possible.
|
||||
|
||||
#### CMake
|
||||
With CMake, cJSON supports a full blown build system. This way you get the most features. With CMake it is recommended to do an out of tree build, meaning the compiled files are put in a directory separate from the source files. So in order to build cJSON with CMake on a Unix platform, make a `build` directory and run CMake inside it.
|
||||
With CMake, cJSON supports a full blown build system. This way you get the most features. CMake with an equal or higher version than 2.8.5 is supported. With CMake it is recommended to do an out of tree build, meaning the compiled files are put in a directory separate from the source files. So in order to build cJSON with CMake on a Unix platform, make a `build` directory and run CMake inside it.
|
||||
|
||||
```
|
||||
mkdir build
|
||||
@@ -79,26 +82,27 @@ make
|
||||
And install it with `make install` if you want. By default it installs the headers `/usr/local/include/cjson` and the libraries to `/usr/local/lib`. It also installs files for pkg-config to make it easier to detect and use an existing installation of CMake. And it installs CMake config files, that can be used by other CMake based projects to discover the library.
|
||||
|
||||
You can change the build process with a list of different options that you can pass to CMake. Turn them on with `On` and off with `Off`:
|
||||
* `-DENABLE_CJSON_TESTS=On`: Enable building the tests. (on by default)
|
||||
* `-DENABLE_CJSON_TEST=On`: Enable building the tests. (on 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_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, GCC and MSVC). 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_AND_STATIC_LIBS=On`: Build both shared and static libraries. (off by default)
|
||||
* `-DCMAKE_INSTALL_PREFIX=/usr`: Set a prefix for the installation.
|
||||
|
||||
If you are packaging cJSON for a distribution of Linux, you would probably take these steps for example:
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DENABLE_CJSON_UTILS=On -DENABLE_CJSON_TESTS=Off -DCMAKE_INSTALL_PREFIX=/usr
|
||||
cmake .. -DENABLE_CJSON_UTILS=On -DENABLE_CJSON_TEST=Off -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make
|
||||
make DESTDIR=$pkgdir install
|
||||
```
|
||||
|
||||
CMake supports a lot of different platforms, not only UNIX Makefiles, but only UNIX Makefiles have been tested. It works on GNU/Linux and has been confirmed to compile on some versions of macOS, Cygwin, FreeBSD, Solaris and OpenIndiana.
|
||||
|
||||
#### Makefile
|
||||
If you don't have CMake available, but still have make. You can use the makefile to build cJSON:
|
||||
If you don't have CMake available, but still have GNU make. You can use the makefile to build cJSON:
|
||||
|
||||
Run this command in the directory with the source code and it will automatically compile static and shared libraries and a little test program.
|
||||
|
||||
@@ -135,14 +139,20 @@ This is an object. We're in C. We don't have objects. But we do have structs.
|
||||
What's the framerate?
|
||||
|
||||
```c
|
||||
cJSON *format = cJSON_GetObjectItem(root, "format");
|
||||
int framerate = cJSON_GetObjectItem(format, "frame rate")->valueint;
|
||||
cJSON *format = cJSON_GetObjectItemCaseSensitive(root, "format");
|
||||
cJSON *framerate_item = cJSON_GetObjectItemCaseSensitive(format, "frame rate");
|
||||
double framerate = 0;
|
||||
if (cJSON_IsNumber(framerate_item))
|
||||
{
|
||||
framerate = framerate_item->valuedouble;
|
||||
}
|
||||
```
|
||||
|
||||
Want to change the framerate?
|
||||
|
||||
```c
|
||||
cJSON_GetObjectItem(format, "frame rate")->valueint = 25;
|
||||
cJSON *framerate_item = cJSON_GetObjectItemCaseSensitive(format, "frame rate");
|
||||
cJSON_SetNumberValue(framerate_item, 25);
|
||||
```
|
||||
|
||||
Back to disk?
|
||||
@@ -201,7 +211,7 @@ typedef struct cJSON {
|
||||
int type;
|
||||
|
||||
char *valuestring;
|
||||
int valueint;
|
||||
int valueint; /* writing to valueint is DEPRECATED, please use cJSON_SetNumberValue instead */
|
||||
double valuedouble;
|
||||
|
||||
char *string;
|
||||
@@ -217,8 +227,7 @@ A `child` entry will have `prev == 0`, but next potentially points on. The last
|
||||
The type expresses *Null*/*True*/*False*/*Number*/*String*/*Array*/*Object*, all of which are `#defined` in
|
||||
`cJSON.h`.
|
||||
|
||||
A *Number* has `valueint` and `valuedouble`. If you're expecting an `int`, read `valueint`, if not read
|
||||
`valuedouble`.
|
||||
A *Number* has `valueint` and `valuedouble`. `valueint` is a relict of the past, so always use `valuedouble`.
|
||||
|
||||
Any entry which is in the linked list which is the child of an object will have a `string`
|
||||
which is the "name" of the entry. When I said "name" in the above example, that's `string`.
|
||||
@@ -235,8 +244,8 @@ void parse_and_callback(cJSON *item, const char *prefix)
|
||||
{
|
||||
while (item)
|
||||
{
|
||||
char *newprefix = malloc(strlen(prefix) + strlen(item->name) + 2);
|
||||
sprintf(newprefix, "%s/%s", prefix, item->name);
|
||||
char *newprefix = malloc(strlen(prefix) + strlen(item->string) + 2);
|
||||
sprintf(newprefix, "%s/%s", prefix, item->string);
|
||||
int dorecurse = callback(newprefix, item->type, item);
|
||||
if (item->child && dorecurse)
|
||||
{
|
||||
@@ -259,22 +268,22 @@ int callback(const char *name, int type, cJSON *item)
|
||||
{
|
||||
/* populate name */
|
||||
}
|
||||
else if (!strcmp(name, "format/type")
|
||||
else if (!strcmp(name, "format/type"))
|
||||
{
|
||||
/* handle "rect" */ }
|
||||
else if (!strcmp(name, "format/width")
|
||||
else if (!strcmp(name, "format/width"))
|
||||
{
|
||||
/* 800 */
|
||||
}
|
||||
else if (!strcmp(name, "format/height")
|
||||
else if (!strcmp(name, "format/height"))
|
||||
{
|
||||
/* 600 */
|
||||
}
|
||||
else if (!strcmp(name, "format/interlace")
|
||||
else if (!strcmp(name, "format/interlace"))
|
||||
{
|
||||
/* false */
|
||||
}
|
||||
else if (!strcmp(name, "format/frame rate")
|
||||
else if (!strcmp(name, "format/frame rate"))
|
||||
{
|
||||
/* 24 */
|
||||
}
|
||||
@@ -367,6 +376,46 @@ The `test.c` code shows how to handle a bunch of typical cases. If you uncomment
|
||||
the code, it'll load, parse and print a bunch of test files, also from [json.org](http://json.org),
|
||||
which are more complex than I'd care to try and stash into a `const char array[]`.
|
||||
|
||||
### Caveats
|
||||
|
||||
#### Zero Character
|
||||
|
||||
cJSON doesn't support strings that contain the zero character `'\0'` or `\u0000`. This is impossible with the current API because strings are zero terminated.
|
||||
|
||||
#### Character Encoding
|
||||
|
||||
cJSON only supports UTF-8 encoded input. In most cases it doesn't reject invalid UTF-8 as input though, it just propagates it through as is. As long as the input doesn't contain invalid UTF-8, the output will always be valid UTF-8.
|
||||
|
||||
#### C Standard
|
||||
|
||||
cJSON is written in ANSI C (or C89, C90). If your compiler or C library doesn't follow this standard, correct behavior is not guaranteed.
|
||||
|
||||
NOTE: ANSI C is not C++ therefore it shouldn't be compiled with a C++ compiler. You can compile it with a C compiler and link it with your C++ code however. Although compiling with a C++ compiler might work, correct behavior is not guaranteed.
|
||||
|
||||
#### Floating Point Numbers
|
||||
|
||||
cJSON does not officially support any `double` implementations other than IEEE754 double precision floating point numbers. It might still work with other implementations but bugs with these will be considered invalid.
|
||||
|
||||
The maximum length of a floating point literal that cJSON supports is currently 63 characters.
|
||||
|
||||
#### Deep Nesting Of Arrays And Objects
|
||||
|
||||
cJSON doesn't support arrays and objects that are nested too deeply because this would result in a stack overflow. To prevent this cJSON limits the depth to `CJSON_NESTING_LIMIT` which is 1000 by default but can be changed at compile time.
|
||||
|
||||
#### Thread Safety
|
||||
|
||||
In general cJSON is **not thread safe**.
|
||||
|
||||
However it is thread safe under the following conditions:
|
||||
* `cJSON_GetErrorPtr` is never used (the `return_parse_end` parameter of `cJSON_ParseWithOpts` can be used instead)
|
||||
* `cJSON_InitHooks` is only ever called before using cJSON in any threads.
|
||||
* `setlocale` is never called before all calls to cJSON functions have returned.
|
||||
|
||||
#### Case Sensitivity
|
||||
|
||||
When cJSON was originally created, it didn't follow the JSON standard and didn't make a distinction between uppercase and lowercase letters. If you want the correct, standard compliant, behavior, you need to use the `CaseSensitive` functions where available.
|
||||
|
||||
# Enjoy cJSON!
|
||||
|
||||
- Dave Gamble, Aug 2009
|
||||
- [cJSON contributors](CONTRIBUTORS.md)
|
||||
|
||||
198
cJSON.h
198
cJSON.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
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
|
||||
@@ -28,9 +28,15 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 5
|
||||
#define CJSON_VERSION_PATCH 6
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_Invalid (0)
|
||||
#define cJSON_False (1 << 0)
|
||||
#define cJSON_True (1 << 1)
|
||||
#define cJSON_NULL (1 << 2)
|
||||
@@ -38,6 +44,7 @@ extern "C"
|
||||
#define cJSON_String (1 << 4)
|
||||
#define cJSON_Array (1 << 5)
|
||||
#define cJSON_Object (1 << 6)
|
||||
#define cJSON_Raw (1 << 7) /* raw json */
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
#define cJSON_StringIsConst 512
|
||||
@@ -54,9 +61,9 @@ typedef struct cJSON
|
||||
/* The type of the item, as above. */
|
||||
int type;
|
||||
|
||||
/* The item's string, if type==cJSON_String */
|
||||
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
|
||||
char *valuestring;
|
||||
/* The item's number, if type==cJSON_Number */
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
/* The item's number, if type==cJSON_Number */
|
||||
double valuedouble;
|
||||
@@ -71,77 +78,161 @@ typedef struct cJSON_Hooks
|
||||
void (*free_fn)(void *ptr);
|
||||
} 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 (default)
|
||||
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
/* export symbols by default, this is necessary for copy pasting the C and header file */
|
||||
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_EXPORT_SYMBOLS
|
||||
#endif
|
||||
|
||||
#if defined(CJSON_HIDE_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) type __stdcall
|
||||
#elif defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall
|
||||
#elif defined(CJSON_IMPORT_SYMBOLS)
|
||||
#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
|
||||
|
||||
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_NESTING_LIMIT
|
||||
#define CJSON_NESTING_LIMIT 1000
|
||||
#endif
|
||||
|
||||
/* returns the version of cJSON as a string */
|
||||
CJSON_PUBLIC(const char*) cJSON_Version(void);
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||
/* 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. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
|
||||
/* 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);
|
||||
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
|
||||
extern char *cJSON_Print(const cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
|
||||
extern char *cJSON_PrintUnformatted(const cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage. */
|
||||
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. */
|
||||
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 */
|
||||
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 given length. Returns 1 on success and 0 on failure. */
|
||||
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
|
||||
/* 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). */
|
||||
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. */
|
||||
extern cJSON *cJSON_GetArrayItem(const cJSON *array, int item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
extern cJSON *cJSON_GetObjectItem(const cJSON *object, const char *string);
|
||||
extern int cJSON_HasObjectItem(const cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const 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. */
|
||||
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. */
|
||||
extern cJSON *cJSON_CreateNull(void);
|
||||
extern cJSON *cJSON_CreateTrue(void);
|
||||
extern cJSON *cJSON_CreateFalse(void);
|
||||
extern cJSON *cJSON_CreateBool(int b);
|
||||
extern cJSON *cJSON_CreateNumber(double num);
|
||||
extern cJSON *cJSON_CreateString(const char *string);
|
||||
extern cJSON *cJSON_CreateArray(void);
|
||||
extern cJSON *cJSON_CreateObject(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||
/* raw json */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||
|
||||
/* These utilities create an Array of count items. */
|
||||
extern cJSON *cJSON_CreateIntArray(const int *numbers, int count);
|
||||
extern cJSON *cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
extern cJSON *cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
extern cJSON *cJSON_CreateStringArray(const char **strings, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
extern void cJSON_AddItemToObjectCS(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 */
|
||||
CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, 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.
|
||||
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
|
||||
* writing to `item->string` */
|
||||
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. */
|
||||
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
|
||||
/* Remove/Detatch items from Arrays/Objects. */
|
||||
extern cJSON *cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
extern void cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
extern cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
extern void cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
extern 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);
|
||||
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
|
||||
CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* 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
|
||||
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. */
|
||||
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
|
||||
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
|
||||
|
||||
/* 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. */
|
||||
extern cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated);
|
||||
|
||||
extern void cJSON_Minify(char *json);
|
||||
CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||
|
||||
/* Macros for creating things quickly. */
|
||||
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
|
||||
@@ -150,13 +241,20 @@ extern void cJSON_Minify(char *json);
|
||||
#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
|
||||
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
|
||||
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(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. */
|
||||
#define cJSON_SetIntValue(object,val) ((object) ? (object)->valueint = (object)->valuedouble = (val) : (val))
|
||||
#define cJSON_SetNumberValue(object,val) ((object) ? (object)->valueint = (object)->valuedouble = (val) : (val))
|
||||
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
|
||||
/* 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 */
|
||||
#define cJSON_ArrayForEach(pos, head) for(pos = (head)->child; pos != NULL; pos = pos->next)
|
||||
/* Macro for iterating over an array or object */
|
||||
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
|
||||
|
||||
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
|
||||
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
||||
CJSON_PUBLIC(void) cJSON_free(void *object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
1627
cJSON_Utils.c
1627
cJSON_Utils.c
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,40 @@
|
||||
/*
|
||||
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 "cJSON.h"
|
||||
|
||||
/* 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 * const object, const char *pointer);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointerCaseSensitive(cJSON * const object, const char *pointer);
|
||||
|
||||
/* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */
|
||||
cJSON* cJSONUtils_GeneratePatches(cJSON *from, cJSON *to);
|
||||
/* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * const to);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from, cJSON * const to);
|
||||
/* 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 * const array, const char * const operation, const char * const path, const cJSON * const value);
|
||||
/* Returns 0 for success. */
|
||||
int cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches);
|
||||
CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * const patches);
|
||||
CJSON_PUBLIC(int) cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object, const cJSON * const patches);
|
||||
|
||||
/*
|
||||
// Note that ApplyPatches is NOT atomic on failure. To implement an atomic ApplyPatches, use:
|
||||
@@ -33,12 +59,16 @@ int cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches);
|
||||
|
||||
/* 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. */
|
||||
cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatchCaseSensitive(cJSON *target, const cJSON * const patch);
|
||||
/* generates a patch to move from -> to */
|
||||
cJSON *cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to);
|
||||
/* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatchCaseSensitive(cJSON * const from, cJSON * const to);
|
||||
|
||||
/* 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(const cJSON * const object, const cJSON * const target);
|
||||
|
||||
/* Sorts the members of the object into alphabetical order. */
|
||||
void cJSONUtils_SortObject(cJSON *object);
|
||||
CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object);
|
||||
CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object);
|
||||
|
||||
1
fuzzing/.gitignore
vendored
Normal file
1
fuzzing/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
afl-build
|
||||
28
fuzzing/CMakeLists.txt
Normal file
28
fuzzing/CMakeLists.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
option(ENABLE_FUZZING "Create executables and targets for fuzzing cJSON with afl." Off)
|
||||
if (ENABLE_FUZZING)
|
||||
find_program(AFL_FUZZ afl-fuzz)
|
||||
if ("${AFL_FUZZ}" MATCHES "AFL_FUZZ-NOTFOUND")
|
||||
message(FATAL_ERROR "Couldn't find afl-fuzz.")
|
||||
endif()
|
||||
|
||||
add_executable(afl-main afl.c)
|
||||
target_link_libraries(afl-main "${CJSON_LIB}")
|
||||
|
||||
if (NOT ENABLE_SANITIZERS)
|
||||
message(FATAL_ERROR "Enable sanitizers with -DENABLE_SANITIZERS=On to do fuzzing.")
|
||||
endif()
|
||||
|
||||
option(ENABLE_FUZZING_PRINT "Fuzz printing functions together with parser." On)
|
||||
set(fuzz_print_parameter "no")
|
||||
if (ENABLE_FUZZING_PRINT)
|
||||
set(fuzz_print_parameter "yes")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error")
|
||||
|
||||
add_custom_target(afl
|
||||
COMMAND "${AFL_FUZZ}" -i "${CMAKE_CURRENT_SOURCE_DIR}/inputs" -o "${CMAKE_CURRENT_BINARY_DIR}/findings" -x "${CMAKE_CURRENT_SOURCE_DIR}/json.dict" -- "${CMAKE_CURRENT_BINARY_DIR}/afl-main" "@@" "${fuzz_print_parameter}"
|
||||
DEPENDS afl-main)
|
||||
|
||||
|
||||
endif()
|
||||
5
fuzzing/afl-prepare-linux.sh
Executable file
5
fuzzing/afl-prepare-linux.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -x
|
||||
echo core | sudo tee /proc/sys/kernel/core_pattern
|
||||
echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
|
||||
176
fuzzing/afl.c
Normal file
176
fuzzing/afl.c
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../cJSON.h"
|
||||
|
||||
static char *read_file(const char *filename)
|
||||
{
|
||||
FILE *file = NULL;
|
||||
long length = 0;
|
||||
char *content = NULL;
|
||||
size_t read_chars = 0;
|
||||
|
||||
/* open in read binary mode */
|
||||
file = fopen(filename, "rb");
|
||||
if (file == NULL)
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* get the length */
|
||||
if (fseek(file, 0, SEEK_END) != 0)
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
length = ftell(file);
|
||||
if (length < 0)
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
if (fseek(file, 0, SEEK_SET) != 0)
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* allocate content buffer */
|
||||
content = (char*)malloc((size_t)length + sizeof(""));
|
||||
if (content == NULL)
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* read the file into memory */
|
||||
read_chars = fread(content, sizeof(char), (size_t)length, file);
|
||||
if ((long)read_chars != length)
|
||||
{
|
||||
free(content);
|
||||
content = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
content[read_chars] = '\0';
|
||||
|
||||
|
||||
cleanup:
|
||||
if (file != NULL)
|
||||
{
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char *filename = NULL;
|
||||
cJSON *item = NULL;
|
||||
char *json = NULL;
|
||||
int status = EXIT_FAILURE;
|
||||
char *printed_json = NULL;
|
||||
|
||||
if ((argc < 2) || (argc > 3))
|
||||
{
|
||||
printf("Usage:\n");
|
||||
printf("%s input_file [enable_printing]\n", argv[0]);
|
||||
printf("\t input_file: file containing the test data\n");
|
||||
printf("\t enable_printing: print after parsing, 'yes' or 'no', defaults to 'no'\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
filename = argv[1];
|
||||
|
||||
#if __AFL_HAVE_MANUAL_CONTROL
|
||||
while (__AFL_LOOP(1000))
|
||||
{
|
||||
#endif
|
||||
status = EXIT_SUCCESS;
|
||||
|
||||
json = read_file(filename);
|
||||
if ((json == NULL) || (json[0] == '\0') || (json[1] == '\0'))
|
||||
{
|
||||
status = EXIT_FAILURE;
|
||||
goto cleanup;
|
||||
}
|
||||
item = cJSON_Parse(json + 2);
|
||||
if (item == NULL)
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((argc == 3) && (strncmp(argv[2], "yes", 3) == 0))
|
||||
{
|
||||
int do_format = 0;
|
||||
if (json[1] == 'f')
|
||||
{
|
||||
do_format = 1;
|
||||
}
|
||||
|
||||
if (json[0] == 'b')
|
||||
{
|
||||
/* buffered printing */
|
||||
printed_json = cJSON_PrintBuffered(item, 1, do_format);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unbuffered printing */
|
||||
if (do_format)
|
||||
{
|
||||
printed_json = cJSON_Print(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
printed_json = cJSON_PrintUnformatted(item);
|
||||
}
|
||||
}
|
||||
if (printed_json == NULL)
|
||||
{
|
||||
status = EXIT_FAILURE;
|
||||
goto cleanup;
|
||||
}
|
||||
printf("%s\n", printed_json);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (item != NULL)
|
||||
{
|
||||
cJSON_Delete(item);
|
||||
item = NULL;
|
||||
}
|
||||
if (json != NULL)
|
||||
{
|
||||
free(json);
|
||||
json = NULL;
|
||||
}
|
||||
if (printed_json != NULL)
|
||||
{
|
||||
free(printed_json);
|
||||
printed_json = NULL;
|
||||
}
|
||||
#if __AFL_HAVE_MANUAL_CONTROL
|
||||
}
|
||||
#endif
|
||||
|
||||
return status;
|
||||
}
|
||||
9
fuzzing/afl.sh
Executable file
9
fuzzing/afl.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
mkdir -p afl-build || exit 1
|
||||
cd afl-build || exit 1
|
||||
#cleanup
|
||||
rm -r -- *
|
||||
|
||||
CC=afl-clang-fast cmake ../.. -DENABLE_FUZZING=On -DENABLE_SANITIZERS=On -DBUILD_SHARED_LIBS=Off
|
||||
make afl
|
||||
22
fuzzing/inputs/test1
Normal file
22
fuzzing/inputs/test1
Normal file
@@ -0,0 +1,22 @@
|
||||
bf{
|
||||
"glossary": {
|
||||
"title": "example glossary",
|
||||
"GlossDiv": {
|
||||
"title": "S",
|
||||
"GlossList": {
|
||||
"GlossEntry": {
|
||||
"ID": "SGML",
|
||||
"SortAs": "SGML",
|
||||
"GlossTerm": "Standard Generalized Markup Language",
|
||||
"Acronym": "SGML",
|
||||
"Abbrev": "ISO 8879:1986",
|
||||
"GlossDef": {
|
||||
"para": "A meta-markup language, used to create markup languages such as DocBook.",
|
||||
"GlossSeeAlso": ["GML", "XML"]
|
||||
},
|
||||
"GlossSee": "markup"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1
fuzzing/inputs/test10
Normal file
1
fuzzing/inputs/test10
Normal file
@@ -0,0 +1 @@
|
||||
bf["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
|
||||
8
fuzzing/inputs/test11
Normal file
8
fuzzing/inputs/test11
Normal file
@@ -0,0 +1,8 @@
|
||||
bf{
|
||||
"name": "Jack (\"Bee\") Nimble",
|
||||
"format": {"type": "rect",
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"interlace": false,"frame rate": 24
|
||||
}
|
||||
}
|
||||
11
fuzzing/inputs/test2
Normal file
11
fuzzing/inputs/test2
Normal file
@@ -0,0 +1,11 @@
|
||||
bf{"menu": {
|
||||
"id": "file",
|
||||
"value": "File",
|
||||
"popup": {
|
||||
"menuitem": [
|
||||
{"value": "New", "onclick": "CreateNewDoc()"},
|
||||
{"value": "Open", "onclick": "OpenDoc()"},
|
||||
{"value": "Close", "onclick": "CloseDoc()"}
|
||||
]
|
||||
}
|
||||
}}
|
||||
26
fuzzing/inputs/test3
Normal file
26
fuzzing/inputs/test3
Normal file
@@ -0,0 +1,26 @@
|
||||
bf{"widget": {
|
||||
"debug": "on",
|
||||
"window": {
|
||||
"title": "Sample Konfabulator Widget",
|
||||
"name": "main_window",
|
||||
"width": 500,
|
||||
"height": 500
|
||||
},
|
||||
"image": {
|
||||
"src": "Images/Sun.png",
|
||||
"name": "sun1",
|
||||
"hOffset": 250,
|
||||
"vOffset": 250,
|
||||
"alignment": "center"
|
||||
},
|
||||
"text": {
|
||||
"data": "Click Here",
|
||||
"size": 36,
|
||||
"style": "bold",
|
||||
"name": "text1",
|
||||
"hOffset": 250,
|
||||
"vOffset": 100,
|
||||
"alignment": "center",
|
||||
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
|
||||
}
|
||||
}}
|
||||
26
fuzzing/inputs/test3.bu
Normal file
26
fuzzing/inputs/test3.bu
Normal file
@@ -0,0 +1,26 @@
|
||||
bu{"widget": {
|
||||
"debug": "on",
|
||||
"window": {
|
||||
"title": "Sample Konfabulator Widget",
|
||||
"name": "main_window",
|
||||
"width": 500,
|
||||
"height": 500
|
||||
},
|
||||
"image": {
|
||||
"src": "Images/Sun.png",
|
||||
"name": "sun1",
|
||||
"hOffset": 250,
|
||||
"vOffset": 250,
|
||||
"alignment": "center"
|
||||
},
|
||||
"text": {
|
||||
"data": "Click Here",
|
||||
"size": 36,
|
||||
"style": "bold",
|
||||
"name": "text1",
|
||||
"hOffset": 250,
|
||||
"vOffset": 100,
|
||||
"alignment": "center",
|
||||
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
|
||||
}
|
||||
}}
|
||||
26
fuzzing/inputs/test3.uf
Normal file
26
fuzzing/inputs/test3.uf
Normal file
@@ -0,0 +1,26 @@
|
||||
uf{"widget": {
|
||||
"debug": "on",
|
||||
"window": {
|
||||
"title": "Sample Konfabulator Widget",
|
||||
"name": "main_window",
|
||||
"width": 500,
|
||||
"height": 500
|
||||
},
|
||||
"image": {
|
||||
"src": "Images/Sun.png",
|
||||
"name": "sun1",
|
||||
"hOffset": 250,
|
||||
"vOffset": 250,
|
||||
"alignment": "center"
|
||||
},
|
||||
"text": {
|
||||
"data": "Click Here",
|
||||
"size": 36,
|
||||
"style": "bold",
|
||||
"name": "text1",
|
||||
"hOffset": 250,
|
||||
"vOffset": 100,
|
||||
"alignment": "center",
|
||||
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
|
||||
}
|
||||
}}
|
||||
26
fuzzing/inputs/test3.uu
Normal file
26
fuzzing/inputs/test3.uu
Normal file
@@ -0,0 +1,26 @@
|
||||
uu{"widget": {
|
||||
"debug": "on",
|
||||
"window": {
|
||||
"title": "Sample Konfabulator Widget",
|
||||
"name": "main_window",
|
||||
"width": 500,
|
||||
"height": 500
|
||||
},
|
||||
"image": {
|
||||
"src": "Images/Sun.png",
|
||||
"name": "sun1",
|
||||
"hOffset": 250,
|
||||
"vOffset": 250,
|
||||
"alignment": "center"
|
||||
},
|
||||
"text": {
|
||||
"data": "Click Here",
|
||||
"size": 36,
|
||||
"style": "bold",
|
||||
"name": "text1",
|
||||
"hOffset": 250,
|
||||
"vOffset": 100,
|
||||
"alignment": "center",
|
||||
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
|
||||
}
|
||||
}}
|
||||
88
fuzzing/inputs/test4
Normal file
88
fuzzing/inputs/test4
Normal file
@@ -0,0 +1,88 @@
|
||||
bf{"web-app": {
|
||||
"servlet": [
|
||||
{
|
||||
"servlet-name": "cofaxCDS",
|
||||
"servlet-class": "org.cofax.cds.CDSServlet",
|
||||
"init-param": {
|
||||
"configGlossary:installationAt": "Philadelphia, PA",
|
||||
"configGlossary:adminEmail": "ksm@pobox.com",
|
||||
"configGlossary:poweredBy": "Cofax",
|
||||
"configGlossary:poweredByIcon": "/images/cofax.gif",
|
||||
"configGlossary:staticPath": "/content/static",
|
||||
"templateProcessorClass": "org.cofax.WysiwygTemplate",
|
||||
"templateLoaderClass": "org.cofax.FilesTemplateLoader",
|
||||
"templatePath": "templates",
|
||||
"templateOverridePath": "",
|
||||
"defaultListTemplate": "listTemplate.htm",
|
||||
"defaultFileTemplate": "articleTemplate.htm",
|
||||
"useJSP": false,
|
||||
"jspListTemplate": "listTemplate.jsp",
|
||||
"jspFileTemplate": "articleTemplate.jsp",
|
||||
"cachePackageTagsTrack": 200,
|
||||
"cachePackageTagsStore": 200,
|
||||
"cachePackageTagsRefresh": 60,
|
||||
"cacheTemplatesTrack": 100,
|
||||
"cacheTemplatesStore": 50,
|
||||
"cacheTemplatesRefresh": 15,
|
||||
"cachePagesTrack": 200,
|
||||
"cachePagesStore": 100,
|
||||
"cachePagesRefresh": 10,
|
||||
"cachePagesDirtyRead": 10,
|
||||
"searchEngineListTemplate": "forSearchEnginesList.htm",
|
||||
"searchEngineFileTemplate": "forSearchEngines.htm",
|
||||
"searchEngineRobotsDb": "WEB-INF/robots.db",
|
||||
"useDataStore": true,
|
||||
"dataStoreClass": "org.cofax.SqlDataStore",
|
||||
"redirectionClass": "org.cofax.SqlRedirection",
|
||||
"dataStoreName": "cofax",
|
||||
"dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
|
||||
"dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
|
||||
"dataStoreUser": "sa",
|
||||
"dataStorePassword": "dataStoreTestQuery",
|
||||
"dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",
|
||||
"dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
|
||||
"dataStoreInitConns": 10,
|
||||
"dataStoreMaxConns": 100,
|
||||
"dataStoreConnUsageLimit": 100,
|
||||
"dataStoreLogLevel": "debug",
|
||||
"maxUrlLength": 500}},
|
||||
{
|
||||
"servlet-name": "cofaxEmail",
|
||||
"servlet-class": "org.cofax.cds.EmailServlet",
|
||||
"init-param": {
|
||||
"mailHost": "mail1",
|
||||
"mailHostOverride": "mail2"}},
|
||||
{
|
||||
"servlet-name": "cofaxAdmin",
|
||||
"servlet-class": "org.cofax.cds.AdminServlet"},
|
||||
|
||||
{
|
||||
"servlet-name": "fileServlet",
|
||||
"servlet-class": "org.cofax.cds.FileServlet"},
|
||||
{
|
||||
"servlet-name": "cofaxTools",
|
||||
"servlet-class": "org.cofax.cms.CofaxToolsServlet",
|
||||
"init-param": {
|
||||
"templatePath": "toolstemplates/",
|
||||
"log": 1,
|
||||
"logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
|
||||
"logMaxSize": "",
|
||||
"dataLog": 1,
|
||||
"dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
|
||||
"dataLogMaxSize": "",
|
||||
"removePageCache": "/content/admin/remove?cache=pages&id=",
|
||||
"removeTemplateCache": "/content/admin/remove?cache=templates&id=",
|
||||
"fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
|
||||
"lookInContext": 1,
|
||||
"adminGroupID": 4,
|
||||
"betaServer": true}}],
|
||||
"servlet-mapping": {
|
||||
"cofaxCDS": "/",
|
||||
"cofaxEmail": "/cofaxutil/aemail/*",
|
||||
"cofaxAdmin": "/admin/*",
|
||||
"fileServlet": "/static/*",
|
||||
"cofaxTools": "/tools/*"},
|
||||
|
||||
"taglib": {
|
||||
"taglib-uri": "cofax.tld",
|
||||
"taglib-location": "/WEB-INF/tlds/cofax.tld"}}}
|
||||
27
fuzzing/inputs/test5
Normal file
27
fuzzing/inputs/test5
Normal file
@@ -0,0 +1,27 @@
|
||||
bf{"menu": {
|
||||
"header": "SVG Viewer",
|
||||
"items": [
|
||||
{"id": "Open"},
|
||||
{"id": "OpenNew", "label": "Open New"},
|
||||
null,
|
||||
{"id": "ZoomIn", "label": "Zoom In"},
|
||||
{"id": "ZoomOut", "label": "Zoom Out"},
|
||||
{"id": "OriginalView", "label": "Original View"},
|
||||
null,
|
||||
{"id": "Quality"},
|
||||
{"id": "Pause"},
|
||||
{"id": "Mute"},
|
||||
null,
|
||||
{"id": "Find", "label": "Find..."},
|
||||
{"id": "FindAgain", "label": "Find Again"},
|
||||
{"id": "Copy"},
|
||||
{"id": "CopyAgain", "label": "Copy Again"},
|
||||
{"id": "CopySVG", "label": "Copy SVG"},
|
||||
{"id": "ViewSVG", "label": "View SVG"},
|
||||
{"id": "ViewSource", "label": "View Source"},
|
||||
{"id": "SaveAs", "label": "Save As"},
|
||||
null,
|
||||
{"id": "Help"},
|
||||
{"id": "About", "label": "About Adobe CVG Viewer..."}
|
||||
]
|
||||
}}
|
||||
16
fuzzing/inputs/test6
Normal file
16
fuzzing/inputs/test6
Normal file
@@ -0,0 +1,16 @@
|
||||
bf<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style type="text/css">
|
||||
html, body, iframe { margin: 0; padding: 0; height: 100%; }
|
||||
iframe { display: block; width: 100%; border: none; }
|
||||
</style>
|
||||
<title>Application Error</title>
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="//s3.amazonaws.com/heroku_pages/error.html">
|
||||
<p>Application Error</p>
|
||||
</iframe>
|
||||
</body>
|
||||
</html>
|
||||
22
fuzzing/inputs/test7
Normal file
22
fuzzing/inputs/test7
Normal file
@@ -0,0 +1,22 @@
|
||||
bf[
|
||||
{
|
||||
"precision": "zip",
|
||||
"Latitude": 37.7668,
|
||||
"Longitude": -122.3959,
|
||||
"Address": "",
|
||||
"City": "SAN FRANCISCO",
|
||||
"State": "CA",
|
||||
"Zip": "94107",
|
||||
"Country": "US"
|
||||
},
|
||||
{
|
||||
"precision": "zip",
|
||||
"Latitude": 37.371991,
|
||||
"Longitude": -122.026020,
|
||||
"Address": "",
|
||||
"City": "SUNNYVALE",
|
||||
"State": "CA",
|
||||
"Zip": "94085",
|
||||
"Country": "US"
|
||||
}
|
||||
]
|
||||
13
fuzzing/inputs/test8
Normal file
13
fuzzing/inputs/test8
Normal file
@@ -0,0 +1,13 @@
|
||||
bf{
|
||||
"Image": {
|
||||
"Width": 800,
|
||||
"Height": 600,
|
||||
"Title": "View from 15th Floor",
|
||||
"Thumbnail": {
|
||||
"Url": "http:/*www.example.com/image/481989943",
|
||||
"Height": 125,
|
||||
"Width": "100"
|
||||
},
|
||||
"IDs": [116, 943, 234, 38793]
|
||||
}
|
||||
}
|
||||
5
fuzzing/inputs/test9
Normal file
5
fuzzing/inputs/test9
Normal file
@@ -0,0 +1,5 @@
|
||||
bf[
|
||||
[0, -1, 0],
|
||||
[1, 0, 0],
|
||||
[0, 0, 1]
|
||||
]
|
||||
47
fuzzing/json.dict
Normal file
47
fuzzing/json.dict
Normal file
@@ -0,0 +1,47 @@
|
||||
#
|
||||
# AFL dictionary for JSON
|
||||
# -----------------------------
|
||||
#
|
||||
|
||||
object_start="{"
|
||||
object_end="}"
|
||||
object_empty="{}"
|
||||
object_one_element="{\"one\":1}"
|
||||
object_two_elements="{\"1\":1,\"2\":2}"
|
||||
object_separator=":"
|
||||
|
||||
array_start="["
|
||||
array_end="]"
|
||||
array_empty="[]"
|
||||
array_one_element="[1]"
|
||||
array_two_elements="[1,2]"
|
||||
|
||||
separator=","
|
||||
|
||||
escape_sequence_b="\\b"
|
||||
escape_sequence_f="\\f"
|
||||
escape_sequence_n="\\n"
|
||||
escape_sequence_r="\\r"
|
||||
escape_sequence_t="\\t"
|
||||
escape_sequence_quote="\\\""
|
||||
escape_sequence_backslash="\\\\"
|
||||
escapce_sequence_slash="\\/"
|
||||
escpae_sequence_utf16_base="\\u"
|
||||
escape_sequence_utf16="\\u12ab"
|
||||
|
||||
number_integer="1"
|
||||
number_double="1.0"
|
||||
number_negative_integer="-1"
|
||||
number_negative_double="-1.0"
|
||||
number_engineering1="1e1"
|
||||
number_engineering2="1e-1"
|
||||
number_positive_integer="+1"
|
||||
number_positive_double="+1.0"
|
||||
number_e="e"
|
||||
number_plus="+"
|
||||
number_minus="-"
|
||||
number_separator="."
|
||||
|
||||
null="null"
|
||||
true="true"
|
||||
false="false"
|
||||
58
meson.build
Normal file
58
meson.build
Normal file
@@ -0,0 +1,58 @@
|
||||
project('cJSON', 'c', default_options: ['c_std=c89'])
|
||||
version = '1.6.0'
|
||||
soversion = '0'
|
||||
|
||||
compiler = meson.get_compiler('c')
|
||||
|
||||
compiler_flags = []
|
||||
|
||||
if (compiler.get_id() == 'clang') or (compiler.get_id() == 'gcc')
|
||||
compiler_flags += [
|
||||
'-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',
|
||||
'-Wformat-overflow',
|
||||
'-Wunused-macros',
|
||||
'-Wmissing-variable-declarations',
|
||||
'-Wused-but-marked-unused',
|
||||
'-Wswitch-enum'
|
||||
]
|
||||
endif
|
||||
|
||||
foreach flag : compiler_flags
|
||||
if compiler.has_argument(flag)
|
||||
add_project_arguments(flag, language: 'c')
|
||||
endif
|
||||
endforeach
|
||||
|
||||
math = compiler.find_library('m', required: false)
|
||||
|
||||
cjson = shared_library('cjson', 'cJSON.c', dependencies: math, version: version, soversion: soversion, install: true)
|
||||
if get_option('enable_cjson_utils')
|
||||
cjson_utils = shared_library('cjson_utils', 'cJSON_Utils.c', link_with: cjson, version: version, soversion: soversion, install: true)
|
||||
endif
|
||||
|
||||
if get_option('enable_cjson_tests')
|
||||
cjson_test = executable('cjson_test', 'test.c', link_with: cjson)
|
||||
test('cjson_test', cjson_test)
|
||||
endif
|
||||
|
||||
subdir('tests')
|
||||
2
meson_options.txt
Normal file
2
meson_options.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
option('enable_cjson_utils', type: 'boolean', value: true)
|
||||
option('enable_cjson_tests', type: 'boolean', value: true)
|
||||
267
test.c
267
test.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
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
|
||||
@@ -22,52 +22,9 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "cJSON.h"
|
||||
|
||||
/* Parse text to JSON, then render back to text, and print! */
|
||||
void doit(char *text)
|
||||
{
|
||||
char *out;
|
||||
cJSON *json;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* Read a file, parse, render back, etc. */
|
||||
void dofile(char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
long len;
|
||||
char *data;
|
||||
|
||||
/* 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);
|
||||
|
||||
fread(data, 1, len, f);
|
||||
data[len] = '\0';
|
||||
fclose(f);
|
||||
|
||||
doit(data);
|
||||
free(data);
|
||||
}
|
||||
|
||||
/* Used by some code below as an example datatype. */
|
||||
struct record
|
||||
{
|
||||
@@ -81,17 +38,83 @@ struct record
|
||||
const char *country;
|
||||
};
|
||||
|
||||
|
||||
/* Create a bunch of objects as demonstration. */
|
||||
void create_objects(void)
|
||||
static int print_preallocated(cJSON *root)
|
||||
{
|
||||
/* declarations */
|
||||
char *out = NULL;
|
||||
char *buf = NULL;
|
||||
char *buf_fail = NULL;
|
||||
size_t len = 0;
|
||||
size_t len_fail = 0;
|
||||
|
||||
/* formatted print */
|
||||
out = cJSON_Print(root);
|
||||
|
||||
/* create buffer to succeed */
|
||||
/* the extra 5 bytes are because of inaccuracies when reserving memory */
|
||||
len = strlen(out) + 5;
|
||||
buf = (char*)malloc(len);
|
||||
if (buf == NULL)
|
||||
{
|
||||
printf("Failed to allocate memory.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* create buffer to fail */
|
||||
len_fail = strlen(out);
|
||||
buf_fail = (char*)malloc(len_fail);
|
||||
if (buf_fail == NULL)
|
||||
{
|
||||
printf("Failed to allocate memory.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Print to buffer */
|
||||
if (!cJSON_PrintPreallocated(root, buf, (int)len, 1)) {
|
||||
printf("cJSON_PrintPreallocated failed!\n");
|
||||
if (strcmp(out, buf) != 0) {
|
||||
printf("cJSON_PrintPreallocated not the same as cJSON_Print!\n");
|
||||
printf("cJSON_Print result:\n%s\n", out);
|
||||
printf("cJSON_PrintPreallocated result:\n%s\n", buf);
|
||||
}
|
||||
free(out);
|
||||
free(buf_fail);
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* success */
|
||||
printf("%s\n", buf);
|
||||
|
||||
/* force it to fail */
|
||||
if (cJSON_PrintPreallocated(root, buf_fail, (int)len_fail, 1)) {
|
||||
printf("cJSON_PrintPreallocated failed to show error with insufficient memory!\n");
|
||||
printf("cJSON_Print result:\n%s\n", out);
|
||||
printf("cJSON_PrintPreallocated result:\n%s\n", buf_fail);
|
||||
free(out);
|
||||
free(buf_fail);
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(out);
|
||||
free(buf_fail);
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create a bunch of objects as demonstration. */
|
||||
static void create_objects(void)
|
||||
{
|
||||
/* declare a few. */
|
||||
cJSON *root;
|
||||
cJSON *fmt;
|
||||
cJSON *img;
|
||||
cJSON *thm;
|
||||
cJSON *fld;
|
||||
char *out;
|
||||
int i;
|
||||
cJSON *root = NULL;
|
||||
cJSON *fmt = NULL;
|
||||
cJSON *img = NULL;
|
||||
cJSON *thm = NULL;
|
||||
cJSON *fld = NULL;
|
||||
int i = 0;
|
||||
|
||||
/* Our "days of the week" array: */
|
||||
const char *strings[7] =
|
||||
@@ -152,21 +175,20 @@ void create_objects(void)
|
||||
cJSON_AddNumberToObject(fmt, "frame rate", 24);
|
||||
|
||||
/* Print to text */
|
||||
out = cJSON_Print(root);
|
||||
/* Delete the cJSON */
|
||||
if (print_preallocated(root) != 0) {
|
||||
cJSON_Delete(root);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
/* print it */
|
||||
printf("%s\n",out);
|
||||
/* release the string */
|
||||
free(out);
|
||||
|
||||
/* Our "days of the week" array: */
|
||||
root = cJSON_CreateStringArray(strings, 7);
|
||||
|
||||
out = cJSON_Print(root);
|
||||
if (print_preallocated(root) != 0) {
|
||||
cJSON_Delete(root);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
printf("%s\n", out);
|
||||
free(out);
|
||||
|
||||
/* Our matrix: */
|
||||
root = cJSON_CreateArray();
|
||||
@@ -177,11 +199,11 @@ void create_objects(void)
|
||||
|
||||
/* cJSON_ReplaceItemInArray(root, 1, cJSON_CreateString("Replacement")); */
|
||||
|
||||
out = cJSON_Print(root);
|
||||
if (print_preallocated(root) != 0) {
|
||||
cJSON_Delete(root);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
printf("%s\n", out);
|
||||
free(out);
|
||||
|
||||
|
||||
/* Our "gallery" item: */
|
||||
root = cJSON_CreateObject();
|
||||
@@ -195,13 +217,13 @@ void create_objects(void)
|
||||
cJSON_AddStringToObject(thm, "Width", "100");
|
||||
cJSON_AddItemToObject(img, "IDs", cJSON_CreateIntArray(ids, 4));
|
||||
|
||||
out = cJSON_Print(root);
|
||||
if (print_preallocated(root) != 0) {
|
||||
cJSON_Delete(root);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
printf("%s\n", out);
|
||||
free(out);
|
||||
|
||||
/* Our array of "records": */
|
||||
|
||||
root = cJSON_CreateArray();
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
@@ -218,109 +240,26 @@ void create_objects(void)
|
||||
|
||||
/* cJSON_ReplaceItemInObject(cJSON_GetArrayItem(root, 1), "City", cJSON_CreateIntArray(ids, 4)); */
|
||||
|
||||
out = cJSON_Print(root);
|
||||
if (print_preallocated(root) != 0) {
|
||||
cJSON_Delete(root);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
printf("%s\n", out);
|
||||
free(out);
|
||||
|
||||
root = cJSON_CreateObject();
|
||||
cJSON_AddNumberToObject(root, "number", 1.0 / zero);
|
||||
out = cJSON_Print(root);
|
||||
|
||||
if (print_preallocated(root) != 0) {
|
||||
cJSON_Delete(root);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
printf("%s\n", out);
|
||||
free(out);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* a bunch of json: */
|
||||
char text1[] =
|
||||
"{\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"); */
|
||||
/* print the version */
|
||||
printf("Version: %s\n", cJSON_Version());
|
||||
|
||||
/* Now some samplecode for building objects concisely: */
|
||||
create_objects();
|
||||
|
||||
171
test_utils.c
171
test_utils.c
@@ -1,171 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "cJSON_Utils.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* Some variables */
|
||||
char *temp = NULL;
|
||||
char *patchtext = NULL;
|
||||
char *patchedtext = NULL;
|
||||
|
||||
int i;
|
||||
/* JSON Pointer tests: */
|
||||
cJSON *root;
|
||||
const char *json="{"
|
||||
"\"foo\": [\"bar\", \"baz\"],"
|
||||
"\"\": 0,"
|
||||
"\"a/b\": 1,"
|
||||
"\"c%d\": 2,"
|
||||
"\"e^f\": 3,"
|
||||
"\"g|h\": 4,"
|
||||
"\"i\\\\j\": 5,"
|
||||
"\"k\\\"l\": 6,"
|
||||
"\" \": 7,"
|
||||
"\"m~n\": 8"
|
||||
"}";
|
||||
|
||||
const char *tests[12]={"","/foo","/foo/0","/","/a~1b","/c%d","/e^f","/g|h","/i\\j","/k\"l","/ ","/m~0n"};
|
||||
|
||||
/* JSON Apply Patch tests: */
|
||||
const char *patches[15][3]={
|
||||
{"{ \"foo\": \"bar\"}", "[{ \"op\": \"add\", \"path\": \"/baz\", \"value\": \"qux\" }]","{\"baz\": \"qux\",\"foo\": \"bar\"}"},
|
||||
{"{ \"foo\": [ \"bar\", \"baz\" ] }", "[{ \"op\": \"add\", \"path\": \"/foo/1\", \"value\": \"qux\" }]","{\"foo\": [ \"bar\", \"qux\", \"baz\" ] }"},
|
||||
{"{\"baz\": \"qux\",\"foo\": \"bar\"}"," [{ \"op\": \"remove\", \"path\": \"/baz\" }]","{\"foo\": \"bar\" }"},
|
||||
{"{ \"foo\": [ \"bar\", \"qux\", \"baz\" ] }","[{ \"op\": \"remove\", \"path\": \"/foo/1\" }]","{\"foo\": [ \"bar\", \"baz\" ] }"},
|
||||
{"{ \"baz\": \"qux\",\"foo\": \"bar\"}","[{ \"op\": \"replace\", \"path\": \"/baz\", \"value\": \"boo\" }]","{\"baz\": \"boo\",\"foo\": \"bar\"}"},
|
||||
{"{\"foo\": {\"bar\": \"baz\",\"waldo\": \"fred\"},\"qux\": {\"corge\": \"grault\"}}","[{ \"op\": \"move\", \"from\": \"/foo/waldo\", \"path\": \"/qux/thud\" }]","{\"foo\": {\"bar\": \"baz\"},\"qux\": {\"corge\": \"grault\",\"thud\": \"fred\"}}"},
|
||||
{"{ \"foo\": [ \"all\", \"grass\", \"cows\", \"eat\" ] }","[ { \"op\": \"move\", \"from\": \"/foo/1\", \"path\": \"/foo/3\" }]","{ \"foo\": [ \"all\", \"cows\", \"eat\", \"grass\" ] }"},
|
||||
{"{\"baz\": \"qux\",\"foo\": [ \"a\", 2, \"c\" ]}","[{ \"op\": \"test\", \"path\": \"/baz\", \"value\": \"qux\" },{ \"op\": \"test\", \"path\": \"/foo/1\", \"value\": 2 }]",""},
|
||||
{"{ \"baz\": \"qux\" }","[ { \"op\": \"test\", \"path\": \"/baz\", \"value\": \"bar\" }]",""},
|
||||
{"{ \"foo\": \"bar\" }","[{ \"op\": \"add\", \"path\": \"/child\", \"value\": { \"grandchild\": { } } }]","{\"foo\": \"bar\",\"child\": {\"grandchild\": {}}}"},
|
||||
{"{ \"foo\": \"bar\" }","[{ \"op\": \"add\", \"path\": \"/baz\", \"value\": \"qux\", \"xyz\": 123 }]","{\"foo\": \"bar\",\"baz\": \"qux\"}"},
|
||||
{"{ \"foo\": \"bar\" }","[{ \"op\": \"add\", \"path\": \"/baz/bat\", \"value\": \"qux\" }]",""},
|
||||
{"{\"/\": 9,\"~1\": 10}","[{\"op\": \"test\", \"path\": \"/~01\", \"value\": 10}]",""},
|
||||
{"{\"/\": 9,\"~1\": 10}","[{\"op\": \"test\", \"path\": \"/~01\", \"value\": \"10\"}]",""},
|
||||
{"{ \"foo\": [\"bar\"] }","[ { \"op\": \"add\", \"path\": \"/foo/-\", \"value\": [\"abc\", \"def\"] }]","{\"foo\": [\"bar\", [\"abc\", \"def\"]] }"}};
|
||||
|
||||
/* JSON Apply Merge tests: */
|
||||
const char *merges[15][3]={
|
||||
{"{\"a\":\"b\"}", "{\"a\":\"c\"}", "{\"a\":\"c\"}"},
|
||||
{"{\"a\":\"b\"}", "{\"b\":\"c\"}", "{\"a\":\"b\",\"b\":\"c\"}"},
|
||||
{"{\"a\":\"b\"}", "{\"a\":null}", "{}"},
|
||||
{"{\"a\":\"b\",\"b\":\"c\"}", "{\"a\":null}", "{\"b\":\"c\"}"},
|
||||
{"{\"a\":[\"b\"]}", "{\"a\":\"c\"}", "{\"a\":\"c\"}"},
|
||||
{"{\"a\":\"c\"}", "{\"a\":[\"b\"]}", "{\"a\":[\"b\"]}"},
|
||||
{"{\"a\":{\"b\":\"c\"}}", "{\"a\":{\"b\":\"d\",\"c\":null}}", "{\"a\":{\"b\":\"d\"}}"},
|
||||
{"{\"a\":[{\"b\":\"c\"}]}", "{\"a\":[1]}", "{\"a\":[1]}"},
|
||||
{"[\"a\",\"b\"]", "[\"c\",\"d\"]", "[\"c\",\"d\"]"},
|
||||
{"{\"a\":\"b\"}", "[\"c\"]", "[\"c\"]"},
|
||||
{"{\"a\":\"foo\"}", "null", "null"},
|
||||
{"{\"a\":\"foo\"}", "\"bar\"", "\"bar\""},
|
||||
{"{\"e\":null}", "{\"a\":1}", "{\"e\":null,\"a\":1}"},
|
||||
{"[1,2]", "{\"a\":\"b\",\"c\":null}", "{\"a\":\"b\"}"},
|
||||
{"{}","{\"a\":{\"bb\":{\"ccc\":null}}}", "{\"a\":{\"bb\":{}}}"}};
|
||||
|
||||
|
||||
/* Misc tests */
|
||||
int numbers[10]={0,1,2,3,4,5,6,7,8,9};
|
||||
const char *random="QWERTYUIOPASDFGHJKLZXCVBNM";
|
||||
char buf[2]={0,0},*before,*after;
|
||||
cJSON *object,*nums,*num6,*sortme;
|
||||
|
||||
|
||||
|
||||
printf("JSON Pointer Tests\n");
|
||||
root=cJSON_Parse(json);
|
||||
for (i=0;i<12;i++)
|
||||
{
|
||||
char *output=cJSON_Print(cJSONUtils_GetPointer(root,tests[i]));
|
||||
printf("Test %d:\n%s\n\n",i+1,output);
|
||||
free(output);
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
|
||||
|
||||
printf("JSON Apply Patch Tests\n");
|
||||
for (i=0;i<15;i++)
|
||||
{
|
||||
cJSON *object=cJSON_Parse(patches[i][0]);
|
||||
cJSON *patch=cJSON_Parse(patches[i][1]);
|
||||
int err=cJSONUtils_ApplyPatches(object,patch);
|
||||
char *output=cJSON_Print(object);
|
||||
printf("Test %d (err %d):\n%s\n\n",i+1,err,output);
|
||||
free(output);cJSON_Delete(object);cJSON_Delete(patch);
|
||||
}
|
||||
|
||||
/* JSON Generate Patch tests: */
|
||||
printf("JSON Generate Patch Tests\n");
|
||||
for (i=0;i<15;i++)
|
||||
{
|
||||
cJSON *from,*to,*patch;char *out;
|
||||
if (!strlen(patches[i][2])) continue;
|
||||
from=cJSON_Parse(patches[i][0]);
|
||||
to=cJSON_Parse(patches[i][2]);
|
||||
patch=cJSONUtils_GeneratePatches(from,to);
|
||||
out=cJSON_Print(patch);
|
||||
printf("Test %d: (patch: %s):\n%s\n\n",i+1,patches[i][1],out);
|
||||
free(out);cJSON_Delete(from);cJSON_Delete(to);cJSON_Delete(patch);
|
||||
}
|
||||
|
||||
/* Misc tests: */
|
||||
printf("JSON Pointer construct\n");
|
||||
object=cJSON_CreateObject();
|
||||
nums=cJSON_CreateIntArray(numbers,10);
|
||||
num6=cJSON_GetArrayItem(nums,6);
|
||||
cJSON_AddItemToObject(object,"numbers",nums);
|
||||
temp=cJSONUtils_FindPointerFromObjectTo(object,num6);
|
||||
printf("Pointer: [%s]\n",temp);
|
||||
free(temp);
|
||||
temp=cJSONUtils_FindPointerFromObjectTo(object,nums);
|
||||
printf("Pointer: [%s]\n",temp);
|
||||
free(temp);
|
||||
temp=cJSONUtils_FindPointerFromObjectTo(object,object);
|
||||
printf("Pointer: [%s]\n",temp);
|
||||
free(temp);
|
||||
cJSON_Delete(object);
|
||||
|
||||
/* JSON Sort test: */
|
||||
sortme=cJSON_CreateObject();
|
||||
for (i=0;i<26;i++)
|
||||
{
|
||||
buf[0]=random[i];cJSON_AddItemToObject(sortme,buf,cJSON_CreateNumber(1));
|
||||
}
|
||||
before=cJSON_PrintUnformatted(sortme);
|
||||
cJSONUtils_SortObject(sortme);
|
||||
after=cJSON_PrintUnformatted(sortme);
|
||||
printf("Before: [%s]\nAfter: [%s]\n\n",before,after);
|
||||
free(before);free(after);cJSON_Delete(sortme);
|
||||
|
||||
/* Merge tests: */
|
||||
printf("JSON Merge Patch tests\n");
|
||||
for (i=0;i<15;i++)
|
||||
{
|
||||
cJSON *object=cJSON_Parse(merges[i][0]);
|
||||
cJSON *patch=cJSON_Parse(merges[i][1]);
|
||||
char *before=cJSON_PrintUnformatted(object);
|
||||
patchtext=cJSON_PrintUnformatted(patch);
|
||||
printf("Before: [%s] -> [%s] = ",before,patchtext);
|
||||
object=cJSONUtils_MergePatch(object,patch);
|
||||
after=cJSON_PrintUnformatted(object);
|
||||
printf("[%s] vs [%s] (%s)\n",after,merges[i][2],strcmp(after,merges[i][2])?"FAIL":"OK");
|
||||
|
||||
free(before);free(patchtext);free(after);cJSON_Delete(object);cJSON_Delete(patch);
|
||||
}
|
||||
|
||||
/* Generate Merge tests: */
|
||||
for (i=0;i<15;i++)
|
||||
{
|
||||
cJSON *from=cJSON_Parse(merges[i][0]);
|
||||
cJSON *to=cJSON_Parse(merges[i][2]);
|
||||
cJSON *patch=cJSONUtils_GenerateMergePatch(from,to);
|
||||
from=cJSONUtils_MergePatch(from,patch);
|
||||
patchtext=cJSON_PrintUnformatted(patch);
|
||||
patchedtext=cJSON_PrintUnformatted(from);
|
||||
printf("Patch [%s] vs [%s] = [%s] vs [%s] (%s)\n",patchtext,merges[i][1],patchedtext,merges[i][2],strcmp(patchedtext,merges[i][2])?"FAIL":"OK");
|
||||
cJSON_Delete(from);cJSON_Delete(to);cJSON_Delete(patch);free(patchtext);free(patchedtext);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
112
tests/CMakeLists.txt
Normal file
112
tests/CMakeLists.txt
Normal file
@@ -0,0 +1,112 @@
|
||||
if(ENABLE_CJSON_TEST)
|
||||
add_library(unity unity/src/unity.c)
|
||||
|
||||
# Disable -Werror for Unity
|
||||
if (FLAG_SUPPORTED_Werror)
|
||||
if ("${CMAKE_VERSION}" VERSION_LESS "2.8.12")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error")
|
||||
else()
|
||||
target_compile_options(unity PRIVATE "-Wno-error")
|
||||
endif()
|
||||
endif()
|
||||
# Disable -fvisibility=hidden for Unity
|
||||
if (FLAG_SUPPORTED_fvisibilityhidden)
|
||||
if ("${CMAKE_VERSION}" VERSION_LESS "2.8.12")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=default")
|
||||
else()
|
||||
target_compile_options(unity PRIVATE "-fvisibility=default")
|
||||
endif()
|
||||
endif()
|
||||
# Disable -fsanitize=float-divide-by-zero for Unity (GCC bug on x86 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80097)
|
||||
if (FLAG_SUPPORTED_fsanitizefloatdividebyzero AND (CMAKE_C_COMPILER_ID STREQUAL "GNU"))
|
||||
if ("${CMAKE_VERSION}" VERSION_LESS "2.8.12")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-sanitize=float-divide-by-zero")
|
||||
else()
|
||||
target_compile_options(unity PRIVATE "-fno-sanitize=float-divide-by-zero")
|
||||
endif()
|
||||
endif()
|
||||
# Disable -Wswitch-enum for Unity
|
||||
if (FLAG_SUPPORTED_Wswitchenum)
|
||||
if ("${CMAKE_VERSION}" VERSION_LESS "2.8.12")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-switch-enum")
|
||||
else()
|
||||
target_compile_options(unity PRIVATE "-Wno-switch-enum")
|
||||
endif()
|
||||
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
|
||||
parse_with_opts
|
||||
compare_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()
|
||||
|
||||
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} "${CMAKE_CURRENT_BINARY_DIR}/${unity_test}")
|
||||
else()
|
||||
add_test(NAME "${unity_test}"
|
||||
COMMAND "./${unity_test}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
add_dependencies(check ${unity_tests})
|
||||
|
||||
if (ENABLE_CJSON_UTILS)
|
||||
#copy test files
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/json-patch-tests")
|
||||
file(GLOB test_files "json-patch-tests/*")
|
||||
file(COPY ${test_files} DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/json-patch-tests/")
|
||||
|
||||
set (cjson_utils_tests
|
||||
json_patch_tests
|
||||
old_utils_tests
|
||||
misc_utils_tests)
|
||||
|
||||
foreach (cjson_utils_test ${cjson_utils_tests})
|
||||
add_executable("${cjson_utils_test}" "${cjson_utils_test}.c")
|
||||
target_link_libraries("${cjson_utils_test}" "${CJSON_LIB}" "${CJSON_UTILS_LIB}" unity test-common)
|
||||
if(MEMORYCHECK_COMMAND)
|
||||
add_test(NAME "${cjson_utils_test}"
|
||||
COMMAND "${MEMORYCHECK_COMMAND}" ${MEMORYCHECK_COMMAND_OPTIONS} "${CMAKE_CURRENT_BINARY_DIR}/${cjson_utils_test}")
|
||||
else()
|
||||
add_test(NAME "${cjson_utils_test}"
|
||||
COMMAND "./${cjson_utils_test}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
add_dependencies(check ${cjson_utils_tests})
|
||||
endif()
|
||||
endif()
|
||||
97
tests/common.c
Normal file
97
tests/common.c
Normal file
@@ -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(""));
|
||||
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;
|
||||
}
|
||||
51
tests/common.h
Normal file
51
tests/common.h
Normal file
@@ -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
|
||||
205
tests/compare_tests.c
Normal file
205
tests/compare_tests.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
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 cJSON_bool compare_from_string(const char * const a, const char * const b, const cJSON_bool case_sensitive)
|
||||
{
|
||||
cJSON *a_json = NULL;
|
||||
cJSON *b_json = NULL;
|
||||
cJSON_bool result = false;
|
||||
|
||||
a_json = cJSON_Parse(a);
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(a_json, "Failed to parse a.");
|
||||
b_json = cJSON_Parse(b);
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(b_json, "Failed to parse b.");
|
||||
|
||||
result = cJSON_Compare(a_json, b_json, case_sensitive);
|
||||
|
||||
cJSON_Delete(a_json);
|
||||
cJSON_Delete(b_json);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void cjson_compare_should_compare_null_pointer_as_not_equal(void)
|
||||
{
|
||||
TEST_ASSERT_FALSE(cJSON_Compare(NULL, NULL, true));
|
||||
TEST_ASSERT_FALSE(cJSON_Compare(NULL, NULL, false));
|
||||
}
|
||||
|
||||
static void cjson_compare_should_compare_invalid_as_not_equal(void)
|
||||
{
|
||||
cJSON invalid[1];
|
||||
memset(invalid, '\0', sizeof(invalid));
|
||||
|
||||
TEST_ASSERT_FALSE(cJSON_Compare(invalid, invalid, false));
|
||||
TEST_ASSERT_FALSE(cJSON_Compare(invalid, invalid, true));
|
||||
}
|
||||
|
||||
static void cjson_compare_should_compare_numbers(void)
|
||||
{
|
||||
TEST_ASSERT_TRUE(compare_from_string("1", "1", true));
|
||||
TEST_ASSERT_TRUE(compare_from_string("1", "1", false));
|
||||
TEST_ASSERT_TRUE(compare_from_string("0.0001", "0.0001", true));
|
||||
TEST_ASSERT_TRUE(compare_from_string("0.0001", "0.0001", false));
|
||||
|
||||
TEST_ASSERT_FALSE(compare_from_string("1", "2", true));
|
||||
TEST_ASSERT_FALSE(compare_from_string("1", "2", false));
|
||||
}
|
||||
|
||||
static void cjson_compare_should_compare_booleans(void)
|
||||
{
|
||||
/* true */
|
||||
TEST_ASSERT_TRUE(compare_from_string("true", "true", true));
|
||||
TEST_ASSERT_TRUE(compare_from_string("true", "true", false));
|
||||
|
||||
/* false */
|
||||
TEST_ASSERT_TRUE(compare_from_string("false", "false", true));
|
||||
TEST_ASSERT_TRUE(compare_from_string("false", "false", false));
|
||||
|
||||
/* mixed */
|
||||
TEST_ASSERT_FALSE(compare_from_string("true", "false", true));
|
||||
TEST_ASSERT_FALSE(compare_from_string("true", "false", false));
|
||||
TEST_ASSERT_FALSE(compare_from_string("false", "true", true));
|
||||
TEST_ASSERT_FALSE(compare_from_string("false", "true", false));
|
||||
}
|
||||
|
||||
static void cjson_compare_should_compare_null(void)
|
||||
{
|
||||
TEST_ASSERT_TRUE(compare_from_string("null", "null", true));
|
||||
TEST_ASSERT_TRUE(compare_from_string("null", "null", false));
|
||||
|
||||
TEST_ASSERT_FALSE(compare_from_string("null", "true", true));
|
||||
TEST_ASSERT_FALSE(compare_from_string("null", "true", false));
|
||||
}
|
||||
|
||||
static void cjson_compare_should_not_accept_invalid_types(void)
|
||||
{
|
||||
cJSON invalid[1];
|
||||
memset(invalid, '\0', sizeof(invalid));
|
||||
|
||||
invalid->type = cJSON_Number | cJSON_String;
|
||||
|
||||
TEST_ASSERT_FALSE(cJSON_Compare(invalid, invalid, true));
|
||||
TEST_ASSERT_FALSE(cJSON_Compare(invalid, invalid, false));
|
||||
}
|
||||
|
||||
static void cjson_compare_should_compare_strings(void)
|
||||
{
|
||||
TEST_ASSERT_TRUE(compare_from_string("\"abcdefg\"", "\"abcdefg\"", true));
|
||||
TEST_ASSERT_TRUE(compare_from_string("\"abcdefg\"", "\"abcdefg\"", false));
|
||||
|
||||
TEST_ASSERT_FALSE(compare_from_string("\"ABCDEFG\"", "\"abcdefg\"", true));
|
||||
TEST_ASSERT_FALSE(compare_from_string("\"ABCDEFG\"", "\"abcdefg\"", false));
|
||||
}
|
||||
|
||||
static void cjson_compare_should_compare_raw(void)
|
||||
{
|
||||
cJSON *raw1 = NULL;
|
||||
cJSON *raw2 = NULL;
|
||||
|
||||
raw1 = cJSON_Parse("\"[true, false]\"");
|
||||
TEST_ASSERT_NOT_NULL(raw1);
|
||||
raw2 = cJSON_Parse("\"[true, false]\"");
|
||||
TEST_ASSERT_NOT_NULL(raw2);
|
||||
|
||||
raw1->type = cJSON_Raw;
|
||||
raw2->type = cJSON_Raw;
|
||||
|
||||
TEST_ASSERT_TRUE(cJSON_Compare(raw1, raw2, true));
|
||||
TEST_ASSERT_TRUE(cJSON_Compare(raw1, raw2, false));
|
||||
|
||||
cJSON_Delete(raw1);
|
||||
cJSON_Delete(raw2);
|
||||
}
|
||||
|
||||
static void cjson_compare_should_compare_arrays(void)
|
||||
{
|
||||
TEST_ASSERT_TRUE(compare_from_string("[]", "[]", true));
|
||||
TEST_ASSERT_TRUE(compare_from_string("[]", "[]", false));
|
||||
|
||||
TEST_ASSERT_TRUE(compare_from_string("[false,true,null,42,\"string\",[],{}]", "[false, true, null, 42, \"string\", [], {}]", true));
|
||||
TEST_ASSERT_TRUE(compare_from_string("[false,true,null,42,\"string\",[],{}]", "[false, true, null, 42, \"string\", [], {}]", false));
|
||||
|
||||
TEST_ASSERT_TRUE(compare_from_string("[[[1], 2]]", "[[[1], 2]]", true));
|
||||
TEST_ASSERT_TRUE(compare_from_string("[[[1], 2]]", "[[[1], 2]]", false));
|
||||
|
||||
TEST_ASSERT_FALSE(compare_from_string("[true,null,42,\"string\",[],{}]", "[false, true, null, 42, \"string\", [], {}]", true));
|
||||
TEST_ASSERT_FALSE(compare_from_string("[true,null,42,\"string\",[],{}]", "[false, true, null, 42, \"string\", [], {}]", false));
|
||||
|
||||
/* Arrays that are a prefix of another array */
|
||||
TEST_ASSERT_FALSE(compare_from_string("[1,2,3]", "[1,2]", true));
|
||||
TEST_ASSERT_FALSE(compare_from_string("[1,2,3]", "[1,2]", false));
|
||||
}
|
||||
|
||||
static void cjson_compare_should_compare_objects(void)
|
||||
{
|
||||
TEST_ASSERT_TRUE(compare_from_string("{}", "{}", true));
|
||||
TEST_ASSERT_TRUE(compare_from_string("{}", "{}", false));
|
||||
|
||||
TEST_ASSERT_TRUE(compare_from_string(
|
||||
"{\"false\": false, \"true\": true, \"null\": null, \"number\": 42, \"string\": \"string\", \"array\": [], \"object\": {}}",
|
||||
"{\"true\": true, \"false\": false, \"null\": null, \"number\": 42, \"string\": \"string\", \"array\": [], \"object\": {}}",
|
||||
true));
|
||||
TEST_ASSERT_FALSE(compare_from_string(
|
||||
"{\"False\": false, \"true\": true, \"null\": null, \"number\": 42, \"string\": \"string\", \"array\": [], \"object\": {}}",
|
||||
"{\"true\": true, \"false\": false, \"null\": null, \"number\": 42, \"string\": \"string\", \"array\": [], \"object\": {}}",
|
||||
true));
|
||||
TEST_ASSERT_TRUE(compare_from_string(
|
||||
"{\"False\": false, \"true\": true, \"null\": null, \"number\": 42, \"string\": \"string\", \"array\": [], \"object\": {}}",
|
||||
"{\"true\": true, \"false\": false, \"null\": null, \"number\": 42, \"string\": \"string\", \"array\": [], \"object\": {}}",
|
||||
false));
|
||||
TEST_ASSERT_FALSE(compare_from_string(
|
||||
"{\"Flse\": false, \"true\": true, \"null\": null, \"number\": 42, \"string\": \"string\", \"array\": [], \"object\": {}}",
|
||||
"{\"true\": true, \"false\": false, \"null\": null, \"number\": 42, \"string\": \"string\", \"array\": [], \"object\": {}}",
|
||||
false));
|
||||
/* test objects that are a subset of each other */
|
||||
TEST_ASSERT_FALSE(compare_from_string(
|
||||
"{\"one\": 1, \"two\": 2}",
|
||||
"{\"one\": 1, \"two\": 2, \"three\": 3}",
|
||||
true))
|
||||
TEST_ASSERT_FALSE(compare_from_string(
|
||||
"{\"one\": 1, \"two\": 2}",
|
||||
"{\"one\": 1, \"two\": 2, \"three\": 3}",
|
||||
false))
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
|
||||
RUN_TEST(cjson_compare_should_compare_null_pointer_as_not_equal);
|
||||
RUN_TEST(cjson_compare_should_compare_invalid_as_not_equal);
|
||||
RUN_TEST(cjson_compare_should_compare_numbers);
|
||||
RUN_TEST(cjson_compare_should_compare_booleans);
|
||||
RUN_TEST(cjson_compare_should_compare_null);
|
||||
RUN_TEST(cjson_compare_should_not_accept_invalid_types);
|
||||
RUN_TEST(cjson_compare_should_compare_strings);
|
||||
RUN_TEST(cjson_compare_should_compare_raw);
|
||||
RUN_TEST(cjson_compare_should_compare_arrays);
|
||||
RUN_TEST(cjson_compare_should_compare_objects);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
22
tests/inputs/test1.expected
Normal file
22
tests/inputs/test1.expected
Normal file
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1
tests/inputs/test10
Normal file
1
tests/inputs/test10
Normal file
@@ -0,0 +1 @@
|
||||
["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
|
||||
1
tests/inputs/test10.expected
Normal file
1
tests/inputs/test10.expected
Normal file
@@ -0,0 +1 @@
|
||||
["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
|
||||
8
tests/inputs/test11
Normal file
8
tests/inputs/test11
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "Jack (\"Bee\") Nimble",
|
||||
"format": {"type": "rect",
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"interlace": false,"frame rate": 24
|
||||
}
|
||||
}
|
||||
10
tests/inputs/test11.expected
Normal file
10
tests/inputs/test11.expected
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "Jack (\"Bee\") Nimble",
|
||||
"format": {
|
||||
"type": "rect",
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"interlace": false,
|
||||
"frame rate": 24
|
||||
}
|
||||
}
|
||||
18
tests/inputs/test2.expected
Normal file
18
tests/inputs/test2.expected
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"menu": {
|
||||
"id": "file",
|
||||
"value": "File",
|
||||
"popup": {
|
||||
"menuitem": [{
|
||||
"value": "New",
|
||||
"onclick": "CreateNewDoc()"
|
||||
}, {
|
||||
"value": "Open",
|
||||
"onclick": "OpenDoc()"
|
||||
}, {
|
||||
"value": "Close",
|
||||
"onclick": "CloseDoc()"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
28
tests/inputs/test3.expected
Normal file
28
tests/inputs/test3.expected
Normal file
@@ -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;"
|
||||
}
|
||||
}
|
||||
}
|
||||
94
tests/inputs/test4.expected
Normal file
94
tests/inputs/test4.expected
Normal file
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
54
tests/inputs/test5.expected
Normal file
54
tests/inputs/test5.expected
Normal file
@@ -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..."
|
||||
}]
|
||||
}
|
||||
}
|
||||
22
tests/inputs/test7
Normal file
22
tests/inputs/test7
Normal file
@@ -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"
|
||||
}
|
||||
]
|
||||
19
tests/inputs/test7.expected
Normal file
19
tests/inputs/test7.expected
Normal file
@@ -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"
|
||||
}]
|
||||
13
tests/inputs/test8
Normal file
13
tests/inputs/test8
Normal file
@@ -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]
|
||||
}
|
||||
}
|
||||
13
tests/inputs/test8.expected
Normal file
13
tests/inputs/test8.expected
Normal file
@@ -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]
|
||||
}
|
||||
}
|
||||
5
tests/inputs/test9
Normal file
5
tests/inputs/test9
Normal file
@@ -0,0 +1,5 @@
|
||||
[
|
||||
[0, -1, 0],
|
||||
[1, 0, 0],
|
||||
[0, 0, 1]
|
||||
]
|
||||
1
tests/inputs/test9.expected
Normal file
1
tests/inputs/test9.expected
Normal file
@@ -0,0 +1 @@
|
||||
[[0, -1, 0], [1, 0, 0], [0, 0, 1]]
|
||||
10
tests/json-patch-tests/.editorconfig
Normal file
10
tests/json-patch-tests/.editorconfig
Normal file
@@ -0,0 +1,10 @@
|
||||
# EditorConfig is awesome: http://EditorConfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
indent_style = space
|
||||
4
tests/json-patch-tests/.gitignore
vendored
Normal file
4
tests/json-patch-tests/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*~
|
||||
\#*
|
||||
!.editorconfig
|
||||
!.gitignore
|
||||
2
tests/json-patch-tests/.npmignore
Normal file
2
tests/json-patch-tests/.npmignore
Normal file
@@ -0,0 +1,2 @@
|
||||
.editorconfig
|
||||
.gitignore
|
||||
75
tests/json-patch-tests/README.md
Normal file
75
tests/json-patch-tests/README.md
Normal file
@@ -0,0 +1,75 @@
|
||||
JSON Patch Tests
|
||||
================
|
||||
|
||||
These are test cases for implementations of [IETF JSON Patch (RFC6902)](http://tools.ietf.org/html/rfc6902).
|
||||
|
||||
Some implementations can be found at [jsonpatch.com](http://jsonpatch.com).
|
||||
|
||||
|
||||
Test Format
|
||||
-----------
|
||||
|
||||
Each test file is a JSON document that contains an array of test records. A
|
||||
test record is an object with the following members:
|
||||
|
||||
- doc: The JSON document to test against
|
||||
- patch: The patch(es) to apply
|
||||
- expected: The expected resulting document, OR
|
||||
- error: A string describing an expected error
|
||||
- comment: A string describing the test
|
||||
- disabled: True if the test should be skipped
|
||||
|
||||
All fields except 'doc' and 'patch' are optional. Test records consisting only
|
||||
of a comment are also OK.
|
||||
|
||||
|
||||
Files
|
||||
-----
|
||||
|
||||
- tests.json: the main test file
|
||||
- spec_tests.json: tests from the RFC6902 spec
|
||||
|
||||
|
||||
Writing Tests
|
||||
-------------
|
||||
|
||||
All tests should have a descriptive comment. Tests should be as
|
||||
simple as possible - just what's required to test a specific piece of
|
||||
behavior. If you want to test interacting behaviors, create tests for
|
||||
each behavior as well as the interaction.
|
||||
|
||||
If an 'error' member is specified, the error text should describe the
|
||||
error the implementation should raise - *not* what's being tested.
|
||||
Implementation error strings will vary, but the suggested error should
|
||||
be easily matched to the implementation error string. Try to avoid
|
||||
creating error tests that might pass because an incorrect error was
|
||||
reported.
|
||||
|
||||
Please feel free to contribute!
|
||||
|
||||
|
||||
Credits
|
||||
-------
|
||||
|
||||
The seed test set was adapted from Byron Ruth's
|
||||
[jsonpatch-js](https://github.com/bruth/jsonpatch-js/blob/master/test.js) and
|
||||
extended by [Mike McCabe](https://github.com/mikemccabe).
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
Copyright 2014 The Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
84
tests/json-patch-tests/cjson-utils-tests.json
Normal file
84
tests/json-patch-tests/cjson-utils-tests.json
Normal file
@@ -0,0 +1,84 @@
|
||||
[
|
||||
{
|
||||
"comment": "1",
|
||||
"doc": { "foo": "bar"},
|
||||
"patch": [{ "op": "add", "path": "/baz", "value": "qux" }],
|
||||
"expected": {"baz": "qux", "foo": "bar"}
|
||||
},
|
||||
{
|
||||
"comment": "2",
|
||||
"doc": { "foo": [ "bar", "baz" ] },
|
||||
"patch": [{ "op": "add", "path": "/foo/1", "value": "qux" }],
|
||||
"expected": {"foo": [ "bar", "qux", "baz" ] }
|
||||
},
|
||||
{
|
||||
"comment": "3",
|
||||
"doc": {"baz": "qux","foo": "bar"},
|
||||
"patch": [{ "op": "remove", "path": "/baz" }],
|
||||
"expected": {"foo": "bar" }
|
||||
},
|
||||
{
|
||||
"comment": "4",
|
||||
"doc": { "foo": [ "bar", "qux", "baz" ] },
|
||||
"patch": [{ "op": "remove", "path": "/foo/1" }],
|
||||
"expected": {"foo": [ "bar", "baz" ] }
|
||||
},
|
||||
{
|
||||
"comment": "5",
|
||||
"doc": { "baz": "qux","foo": "bar"},
|
||||
"patch": [{ "op": "replace", "path": "/baz", "value": "boo" }],
|
||||
"expected": {"baz": "boo","foo": "bar"}
|
||||
},
|
||||
{
|
||||
"comment": "6",
|
||||
"doc": {"foo": {"bar": "baz","waldo": "fred"},"qux": {"corge": "grault"}},
|
||||
"patch": [{ "op": "move", "from": "/foo/waldo", "path": "/qux/thud" }],
|
||||
"expected": {"foo": {"bar": "baz"},"qux": {"corge": "grault","thud": "fred"}}
|
||||
},
|
||||
{
|
||||
"comment": "7",
|
||||
"doc": { "foo": [ "all", "grass", "cows", "eat" ] },
|
||||
"patch": [ { "op": "move", "from": "/foo/1", "path": "/foo/3" }],
|
||||
"expected": { "foo": [ "all", "cows", "eat", "grass" ] }
|
||||
},
|
||||
{
|
||||
"comment": "8",
|
||||
"doc": {"baz": "qux","foo": [ "a", 2, "c" ]},
|
||||
"patch": [{ "op": "test", "path": "/baz", "value": "qux" },{ "op": "test", "path": "/foo/1", "value": 2 }]
|
||||
},
|
||||
{
|
||||
"comment": "9",
|
||||
"doc": { "baz": "qux" },
|
||||
"patch": [ { "op": "test", "path": "/baz", "value": "bar" }],
|
||||
"error": "\"bar\" doesn't exist"
|
||||
},
|
||||
{
|
||||
"comment": "10",
|
||||
"doc": { "foo": "bar" },
|
||||
"patch": [{ "op": "add", "path": "/child", "value": { "grandchild": { } } }],
|
||||
"expected": {"foo": "bar","child": {"grandchild": {}}}
|
||||
},
|
||||
{
|
||||
"comment": "11",
|
||||
"doc": { "foo": "bar" },
|
||||
"patch": [{ "op": "add", "path": "/baz", "value": "qux", "xyz": 123 }],
|
||||
"expected": {"foo": "bar","baz": "qux"}
|
||||
},
|
||||
{
|
||||
"comment": "12",
|
||||
"doc": { "foo": "bar" },
|
||||
"patch": [{ "op": "add", "path": "/baz/bat", "value": "qux" }],
|
||||
"error": "Can't add to nonexistent object"
|
||||
},
|
||||
{
|
||||
"comment": "13",
|
||||
"doc": {"/": 9,"~1": 10},
|
||||
"patch": [{"op": "test", "path": "/~01", "value": 10}]
|
||||
},
|
||||
{
|
||||
"comment": "14",
|
||||
"doc": { "foo": ["bar"] },
|
||||
"patch": [ { "op": "add", "path": "/foo/-", "value": ["abc", "def"] }],
|
||||
"expected": {"foo": ["bar", ["abc", "def"]] }
|
||||
}
|
||||
]
|
||||
15
tests/json-patch-tests/package.json
Normal file
15
tests/json-patch-tests/package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "json-patch-test-suite",
|
||||
"version": "1.1.0",
|
||||
"description": "JSON Patch RFC 6902 test suite",
|
||||
"repository": "github:json-patch/json-patch-tests",
|
||||
"homepage": "https://github.com/json-patch/json-patch-tests",
|
||||
"bugs": "https://github.com/json-patch/json-patch-tests/issues",
|
||||
"keywords": [
|
||||
"JSON",
|
||||
"Patch",
|
||||
"test",
|
||||
"suite"
|
||||
],
|
||||
"license": "Apache-2.0"
|
||||
}
|
||||
233
tests/json-patch-tests/spec_tests.json
Normal file
233
tests/json-patch-tests/spec_tests.json
Normal file
@@ -0,0 +1,233 @@
|
||||
[
|
||||
{
|
||||
"comment": "4.1. add with missing object",
|
||||
"doc": { "q": { "bar": 2 } },
|
||||
"patch": [ {"op": "add", "path": "/a/b", "value": 1} ],
|
||||
"error":
|
||||
"path /a does not exist -- missing objects are not created recursively"
|
||||
},
|
||||
|
||||
{
|
||||
"comment": "A.1. Adding an Object Member",
|
||||
"doc": {
|
||||
"foo": "bar"
|
||||
},
|
||||
"patch": [
|
||||
{ "op": "add", "path": "/baz", "value": "qux" }
|
||||
],
|
||||
"expected": {
|
||||
"baz": "qux",
|
||||
"foo": "bar"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"comment": "A.2. Adding an Array Element",
|
||||
"doc": {
|
||||
"foo": [ "bar", "baz" ]
|
||||
},
|
||||
"patch": [
|
||||
{ "op": "add", "path": "/foo/1", "value": "qux" }
|
||||
],
|
||||
"expected": {
|
||||
"foo": [ "bar", "qux", "baz" ]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"comment": "A.3. Removing an Object Member",
|
||||
"doc": {
|
||||
"baz": "qux",
|
||||
"foo": "bar"
|
||||
},
|
||||
"patch": [
|
||||
{ "op": "remove", "path": "/baz" }
|
||||
],
|
||||
"expected": {
|
||||
"foo": "bar"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"comment": "A.4. Removing an Array Element",
|
||||
"doc": {
|
||||
"foo": [ "bar", "qux", "baz" ]
|
||||
},
|
||||
"patch": [
|
||||
{ "op": "remove", "path": "/foo/1" }
|
||||
],
|
||||
"expected": {
|
||||
"foo": [ "bar", "baz" ]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"comment": "A.5. Replacing a Value",
|
||||
"doc": {
|
||||
"baz": "qux",
|
||||
"foo": "bar"
|
||||
},
|
||||
"patch": [
|
||||
{ "op": "replace", "path": "/baz", "value": "boo" }
|
||||
],
|
||||
"expected": {
|
||||
"baz": "boo",
|
||||
"foo": "bar"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"comment": "A.6. Moving a Value",
|
||||
"doc": {
|
||||
"foo": {
|
||||
"bar": "baz",
|
||||
"waldo": "fred"
|
||||
},
|
||||
"qux": {
|
||||
"corge": "grault"
|
||||
}
|
||||
},
|
||||
"patch": [
|
||||
{ "op": "move", "from": "/foo/waldo", "path": "/qux/thud" }
|
||||
],
|
||||
"expected": {
|
||||
"foo": {
|
||||
"bar": "baz"
|
||||
},
|
||||
"qux": {
|
||||
"corge": "grault",
|
||||
"thud": "fred"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"comment": "A.7. Moving an Array Element",
|
||||
"doc": {
|
||||
"foo": [ "all", "grass", "cows", "eat" ]
|
||||
},
|
||||
"patch": [
|
||||
{ "op": "move", "from": "/foo/1", "path": "/foo/3" }
|
||||
],
|
||||
"expected": {
|
||||
"foo": [ "all", "cows", "eat", "grass" ]
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
"comment": "A.8. Testing a Value: Success",
|
||||
"doc": {
|
||||
"baz": "qux",
|
||||
"foo": [ "a", 2, "c" ]
|
||||
},
|
||||
"patch": [
|
||||
{ "op": "test", "path": "/baz", "value": "qux" },
|
||||
{ "op": "test", "path": "/foo/1", "value": 2 }
|
||||
],
|
||||
"expected": {
|
||||
"baz": "qux",
|
||||
"foo": [ "a", 2, "c" ]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"comment": "A.9. Testing a Value: Error",
|
||||
"doc": {
|
||||
"baz": "qux"
|
||||
},
|
||||
"patch": [
|
||||
{ "op": "test", "path": "/baz", "value": "bar" }
|
||||
],
|
||||
"error": "string not equivalent"
|
||||
},
|
||||
|
||||
{
|
||||
"comment": "A.10. Adding a nested Member Object",
|
||||
"doc": {
|
||||
"foo": "bar"
|
||||
},
|
||||
"patch": [
|
||||
{ "op": "add", "path": "/child", "value": { "grandchild": { } } }
|
||||
],
|
||||
"expected": {
|
||||
"foo": "bar",
|
||||
"child": {
|
||||
"grandchild": {
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"comment": "A.11. Ignoring Unrecognized Elements",
|
||||
"doc": {
|
||||
"foo":"bar"
|
||||
},
|
||||
"patch": [
|
||||
{ "op": "add", "path": "/baz", "value": "qux", "xyz": 123 }
|
||||
],
|
||||
"expected": {
|
||||
"foo":"bar",
|
||||
"baz":"qux"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"comment": "A.12. Adding to a Non-existent Target",
|
||||
"doc": {
|
||||
"foo": "bar"
|
||||
},
|
||||
"patch": [
|
||||
{ "op": "add", "path": "/baz/bat", "value": "qux" }
|
||||
],
|
||||
"error": "add to a non-existent target"
|
||||
},
|
||||
|
||||
{
|
||||
"comment": "A.13 Invalid JSON Patch Document",
|
||||
"doc": {
|
||||
"foo": "bar"
|
||||
},
|
||||
"patch": [
|
||||
{ "op": "add", "path": "/baz", "value": "qux", "op": "remove" }
|
||||
],
|
||||
"error": "operation has two 'op' members",
|
||||
"disabled": true
|
||||
},
|
||||
|
||||
{
|
||||
"comment": "A.14. ~ Escape Ordering",
|
||||
"doc": {
|
||||
"/": 9,
|
||||
"~1": 10
|
||||
},
|
||||
"patch": [{"op": "test", "path": "/~01", "value": 10}],
|
||||
"expected": {
|
||||
"/": 9,
|
||||
"~1": 10
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"comment": "A.15. Comparing Strings and Numbers",
|
||||
"doc": {
|
||||
"/": 9,
|
||||
"~1": 10
|
||||
},
|
||||
"patch": [{"op": "test", "path": "/~01", "value": "10"}],
|
||||
"error": "number is not equal to string"
|
||||
},
|
||||
|
||||
{
|
||||
"comment": "A.16. Adding an Array Value",
|
||||
"doc": {
|
||||
"foo": ["bar"]
|
||||
},
|
||||
"patch": [{ "op": "add", "path": "/foo/-", "value": ["abc", "def"] }],
|
||||
"expected": {
|
||||
"foo": ["bar", ["abc", "def"]]
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
429
tests/json-patch-tests/tests.json
Normal file
429
tests/json-patch-tests/tests.json
Normal file
@@ -0,0 +1,429 @@
|
||||
[
|
||||
{ "comment": "empty list, empty docs",
|
||||
"doc": {},
|
||||
"patch": [],
|
||||
"expected": {} },
|
||||
|
||||
{ "comment": "empty patch list",
|
||||
"doc": {"foo": 1},
|
||||
"patch": [],
|
||||
"expected": {"foo": 1} },
|
||||
|
||||
{ "comment": "rearrangements OK?",
|
||||
"doc": {"foo": 1, "bar": 2},
|
||||
"patch": [],
|
||||
"expected": {"bar":2, "foo": 1} },
|
||||
|
||||
{ "comment": "rearrangements OK? How about one level down ... array",
|
||||
"doc": [{"foo": 1, "bar": 2}],
|
||||
"patch": [],
|
||||
"expected": [{"bar":2, "foo": 1}] },
|
||||
|
||||
{ "comment": "rearrangements OK? How about one level down...",
|
||||
"doc": {"foo":{"foo": 1, "bar": 2}},
|
||||
"patch": [],
|
||||
"expected": {"foo":{"bar":2, "foo": 1}} },
|
||||
|
||||
{ "comment": "add replaces any existing field",
|
||||
"doc": {"foo": null},
|
||||
"patch": [{"op": "add", "path": "/foo", "value":1}],
|
||||
"expected": {"foo": 1} },
|
||||
|
||||
{ "comment": "toplevel array",
|
||||
"doc": [],
|
||||
"patch": [{"op": "add", "path": "/0", "value": "foo"}],
|
||||
"expected": ["foo"] },
|
||||
|
||||
{ "comment": "toplevel array, no change",
|
||||
"doc": ["foo"],
|
||||
"patch": [],
|
||||
"expected": ["foo"] },
|
||||
|
||||
{ "comment": "toplevel object, numeric string",
|
||||
"doc": {},
|
||||
"patch": [{"op": "add", "path": "/foo", "value": "1"}],
|
||||
"expected": {"foo":"1"} },
|
||||
|
||||
{ "comment": "toplevel object, integer",
|
||||
"doc": {},
|
||||
"patch": [{"op": "add", "path": "/foo", "value": 1}],
|
||||
"expected": {"foo":1} },
|
||||
|
||||
{ "comment": "Toplevel scalar values OK?",
|
||||
"doc": "foo",
|
||||
"patch": [{"op": "replace", "path": "", "value": "bar"}],
|
||||
"expected": "bar",
|
||||
"disabled": true },
|
||||
|
||||
{ "comment": "replace object document with array document?",
|
||||
"doc": {},
|
||||
"patch": [{"op": "add", "path": "", "value": []}],
|
||||
"expected": [] },
|
||||
|
||||
{ "comment": "replace array document with object document?",
|
||||
"doc": [],
|
||||
"patch": [{"op": "add", "path": "", "value": {}}],
|
||||
"expected": {} },
|
||||
|
||||
{ "comment": "append to root array document?",
|
||||
"doc": [],
|
||||
"patch": [{"op": "add", "path": "/-", "value": "hi"}],
|
||||
"expected": ["hi"] },
|
||||
|
||||
{ "comment": "Add, / target",
|
||||
"doc": {},
|
||||
"patch": [ {"op": "add", "path": "/", "value":1 } ],
|
||||
"expected": {"":1} },
|
||||
|
||||
{ "comment": "Add, /foo/ deep target (trailing slash)",
|
||||
"doc": {"foo": {}},
|
||||
"patch": [ {"op": "add", "path": "/foo/", "value":1 } ],
|
||||
"expected": {"foo":{"": 1}} },
|
||||
|
||||
{ "comment": "Add composite value at top level",
|
||||
"doc": {"foo": 1},
|
||||
"patch": [{"op": "add", "path": "/bar", "value": [1, 2]}],
|
||||
"expected": {"foo": 1, "bar": [1, 2]} },
|
||||
|
||||
{ "comment": "Add into composite value",
|
||||
"doc": {"foo": 1, "baz": [{"qux": "hello"}]},
|
||||
"patch": [{"op": "add", "path": "/baz/0/foo", "value": "world"}],
|
||||
"expected": {"foo": 1, "baz": [{"qux": "hello", "foo": "world"}]} },
|
||||
|
||||
{ "doc": {"bar": [1, 2]},
|
||||
"patch": [{"op": "add", "path": "/bar/8", "value": "5"}],
|
||||
"error": "Out of bounds (upper)" },
|
||||
|
||||
{ "doc": {"bar": [1, 2]},
|
||||
"patch": [{"op": "add", "path": "/bar/-1", "value": "5"}],
|
||||
"error": "Out of bounds (lower)" },
|
||||
|
||||
{ "doc": {"foo": 1},
|
||||
"patch": [{"op": "add", "path": "/bar", "value": true}],
|
||||
"expected": {"foo": 1, "bar": true} },
|
||||
|
||||
{ "doc": {"foo": 1},
|
||||
"patch": [{"op": "add", "path": "/bar", "value": false}],
|
||||
"expected": {"foo": 1, "bar": false} },
|
||||
|
||||
{ "doc": {"foo": 1},
|
||||
"patch": [{"op": "add", "path": "/bar", "value": null}],
|
||||
"expected": {"foo": 1, "bar": null} },
|
||||
|
||||
{ "comment": "0 can be an array index or object element name",
|
||||
"doc": {"foo": 1},
|
||||
"patch": [{"op": "add", "path": "/0", "value": "bar"}],
|
||||
"expected": {"foo": 1, "0": "bar" } },
|
||||
|
||||
{ "doc": ["foo"],
|
||||
"patch": [{"op": "add", "path": "/1", "value": "bar"}],
|
||||
"expected": ["foo", "bar"] },
|
||||
|
||||
{ "doc": ["foo", "sil"],
|
||||
"patch": [{"op": "add", "path": "/1", "value": "bar"}],
|
||||
"expected": ["foo", "bar", "sil"] },
|
||||
|
||||
{ "doc": ["foo", "sil"],
|
||||
"patch": [{"op": "add", "path": "/0", "value": "bar"}],
|
||||
"expected": ["bar", "foo", "sil"] },
|
||||
|
||||
{ "comment": "push item to array via last index + 1",
|
||||
"doc": ["foo", "sil"],
|
||||
"patch": [{"op":"add", "path": "/2", "value": "bar"}],
|
||||
"expected": ["foo", "sil", "bar"] },
|
||||
|
||||
{ "comment": "add item to array at index > length should fail",
|
||||
"doc": ["foo", "sil"],
|
||||
"patch": [{"op":"add", "path": "/3", "value": "bar"}],
|
||||
"error": "index is greater than number of items in array" },
|
||||
|
||||
{ "comment": "test against implementation-specific numeric parsing",
|
||||
"doc": {"1e0": "foo"},
|
||||
"patch": [{"op": "test", "path": "/1e0", "value": "foo"}],
|
||||
"expected": {"1e0": "foo"} },
|
||||
|
||||
{ "comment": "test with bad number should fail",
|
||||
"doc": ["foo", "bar"],
|
||||
"patch": [{"op": "test", "path": "/1e0", "value": "bar"}],
|
||||
"error": "test op shouldn't get array element 1" },
|
||||
|
||||
{ "doc": ["foo", "sil"],
|
||||
"patch": [{"op": "add", "path": "/bar", "value": 42}],
|
||||
"error": "Object operation on array target" },
|
||||
|
||||
{ "doc": ["foo", "sil"],
|
||||
"patch": [{"op": "add", "path": "/1", "value": ["bar", "baz"]}],
|
||||
"expected": ["foo", ["bar", "baz"], "sil"],
|
||||
"comment": "value in array add not flattened" },
|
||||
|
||||
{ "doc": {"foo": 1, "bar": [1, 2, 3, 4]},
|
||||
"patch": [{"op": "remove", "path": "/bar"}],
|
||||
"expected": {"foo": 1} },
|
||||
|
||||
{ "doc": {"foo": 1, "baz": [{"qux": "hello"}]},
|
||||
"patch": [{"op": "remove", "path": "/baz/0/qux"}],
|
||||
"expected": {"foo": 1, "baz": [{}]} },
|
||||
|
||||
{ "doc": {"foo": 1, "baz": [{"qux": "hello"}]},
|
||||
"patch": [{"op": "replace", "path": "/foo", "value": [1, 2, 3, 4]}],
|
||||
"expected": {"foo": [1, 2, 3, 4], "baz": [{"qux": "hello"}]} },
|
||||
|
||||
{ "doc": {"foo": [1, 2, 3, 4], "baz": [{"qux": "hello"}]},
|
||||
"patch": [{"op": "replace", "path": "/baz/0/qux", "value": "world"}],
|
||||
"expected": {"foo": [1, 2, 3, 4], "baz": [{"qux": "world"}]} },
|
||||
|
||||
{ "doc": ["foo"],
|
||||
"patch": [{"op": "replace", "path": "/0", "value": "bar"}],
|
||||
"expected": ["bar"] },
|
||||
|
||||
{ "doc": [""],
|
||||
"patch": [{"op": "replace", "path": "/0", "value": 0}],
|
||||
"expected": [0] },
|
||||
|
||||
{ "doc": [""],
|
||||
"patch": [{"op": "replace", "path": "/0", "value": true}],
|
||||
"expected": [true] },
|
||||
|
||||
{ "doc": [""],
|
||||
"patch": [{"op": "replace", "path": "/0", "value": false}],
|
||||
"expected": [false] },
|
||||
|
||||
{ "doc": [""],
|
||||
"patch": [{"op": "replace", "path": "/0", "value": null}],
|
||||
"expected": [null] },
|
||||
|
||||
{ "doc": ["foo", "sil"],
|
||||
"patch": [{"op": "replace", "path": "/1", "value": ["bar", "baz"]}],
|
||||
"expected": ["foo", ["bar", "baz"]],
|
||||
"comment": "value in array replace not flattened" },
|
||||
|
||||
{ "comment": "replace whole document",
|
||||
"doc": {"foo": "bar"},
|
||||
"patch": [{"op": "replace", "path": "", "value": {"baz": "qux"}}],
|
||||
"expected": {"baz": "qux"} },
|
||||
|
||||
{ "comment": "spurious patch properties",
|
||||
"doc": {"foo": 1},
|
||||
"patch": [{"op": "test", "path": "/foo", "value": 1, "spurious": 1}],
|
||||
"expected": {"foo": 1} },
|
||||
|
||||
{ "doc": {"foo": null},
|
||||
"patch": [{"op": "test", "path": "/foo", "value": null}],
|
||||
"comment": "null value should be valid obj property" },
|
||||
|
||||
{ "doc": {"foo": null},
|
||||
"patch": [{"op": "replace", "path": "/foo", "value": "truthy"}],
|
||||
"expected": {"foo": "truthy"},
|
||||
"comment": "null value should be valid obj property to be replaced with something truthy" },
|
||||
|
||||
{ "doc": {"foo": null},
|
||||
"patch": [{"op": "move", "from": "/foo", "path": "/bar"}],
|
||||
"expected": {"bar": null},
|
||||
"comment": "null value should be valid obj property to be moved" },
|
||||
|
||||
{ "doc": {"foo": null},
|
||||
"patch": [{"op": "copy", "from": "/foo", "path": "/bar"}],
|
||||
"expected": {"foo": null, "bar": null},
|
||||
"comment": "null value should be valid obj property to be copied" },
|
||||
|
||||
{ "doc": {"foo": null},
|
||||
"patch": [{"op": "remove", "path": "/foo"}],
|
||||
"expected": {},
|
||||
"comment": "null value should be valid obj property to be removed" },
|
||||
|
||||
{ "doc": {"foo": "bar"},
|
||||
"patch": [{"op": "replace", "path": "/foo", "value": null}],
|
||||
"expected": {"foo": null},
|
||||
"comment": "null value should still be valid obj property replace other value" },
|
||||
|
||||
{ "doc": {"foo": {"foo": 1, "bar": 2}},
|
||||
"patch": [{"op": "test", "path": "/foo", "value": {"bar": 2, "foo": 1}}],
|
||||
"comment": "test should pass despite rearrangement" },
|
||||
|
||||
{ "doc": {"foo": [{"foo": 1, "bar": 2}]},
|
||||
"patch": [{"op": "test", "path": "/foo", "value": [{"bar": 2, "foo": 1}]}],
|
||||
"comment": "test should pass despite (nested) rearrangement" },
|
||||
|
||||
{ "doc": {"foo": {"bar": [1, 2, 5, 4]}},
|
||||
"patch": [{"op": "test", "path": "/foo", "value": {"bar": [1, 2, 5, 4]}}],
|
||||
"comment": "test should pass - no error" },
|
||||
|
||||
{ "doc": {"foo": {"bar": [1, 2, 5, 4]}},
|
||||
"patch": [{"op": "test", "path": "/foo", "value": [1, 2]}],
|
||||
"error": "test op should fail" },
|
||||
|
||||
{ "comment": "Whole document",
|
||||
"doc": { "foo": 1 },
|
||||
"patch": [{"op": "test", "path": "", "value": {"foo": 1}}],
|
||||
"disabled": true },
|
||||
|
||||
{ "comment": "Empty-string element",
|
||||
"doc": { "": 1 },
|
||||
"patch": [{"op": "test", "path": "/", "value": 1}] },
|
||||
|
||||
{ "doc": {
|
||||
"foo": ["bar", "baz"],
|
||||
"": 0,
|
||||
"a/b": 1,
|
||||
"c%d": 2,
|
||||
"e^f": 3,
|
||||
"g|h": 4,
|
||||
"i\\j": 5,
|
||||
"k\"l": 6,
|
||||
" ": 7,
|
||||
"m~n": 8
|
||||
},
|
||||
"patch": [{"op": "test", "path": "/foo", "value": ["bar", "baz"]},
|
||||
{"op": "test", "path": "/foo/0", "value": "bar"},
|
||||
{"op": "test", "path": "/", "value": 0},
|
||||
{"op": "test", "path": "/a~1b", "value": 1},
|
||||
{"op": "test", "path": "/c%d", "value": 2},
|
||||
{"op": "test", "path": "/e^f", "value": 3},
|
||||
{"op": "test", "path": "/g|h", "value": 4},
|
||||
{"op": "test", "path": "/i\\j", "value": 5},
|
||||
{"op": "test", "path": "/k\"l", "value": 6},
|
||||
{"op": "test", "path": "/ ", "value": 7},
|
||||
{"op": "test", "path": "/m~0n", "value": 8}] },
|
||||
|
||||
{ "comment": "Move to same location has no effect",
|
||||
"doc": {"foo": 1},
|
||||
"patch": [{"op": "move", "from": "/foo", "path": "/foo"}],
|
||||
"expected": {"foo": 1} },
|
||||
|
||||
{ "doc": {"foo": 1, "baz": [{"qux": "hello"}]},
|
||||
"patch": [{"op": "move", "from": "/foo", "path": "/bar"}],
|
||||
"expected": {"baz": [{"qux": "hello"}], "bar": 1} },
|
||||
|
||||
{ "doc": {"baz": [{"qux": "hello"}], "bar": 1},
|
||||
"patch": [{"op": "move", "from": "/baz/0/qux", "path": "/baz/1"}],
|
||||
"expected": {"baz": [{}, "hello"], "bar": 1} },
|
||||
|
||||
{ "doc": {"baz": [{"qux": "hello"}], "bar": 1},
|
||||
"patch": [{"op": "copy", "from": "/baz/0", "path": "/boo"}],
|
||||
"expected": {"baz":[{"qux":"hello"}],"bar":1,"boo":{"qux":"hello"}} },
|
||||
|
||||
{ "comment": "replacing the root of the document is possible with add",
|
||||
"doc": {"foo": "bar"},
|
||||
"patch": [{"op": "add", "path": "", "value": {"baz": "qux"}}],
|
||||
"expected": {"baz":"qux"}},
|
||||
|
||||
{ "comment": "Adding to \"/-\" adds to the end of the array",
|
||||
"doc": [ 1, 2 ],
|
||||
"patch": [ { "op": "add", "path": "/-", "value": { "foo": [ "bar", "baz" ] } } ],
|
||||
"expected": [ 1, 2, { "foo": [ "bar", "baz" ] } ]},
|
||||
|
||||
{ "comment": "Adding to \"/-\" adds to the end of the array, even n levels down",
|
||||
"doc": [ 1, 2, [ 3, [ 4, 5 ] ] ],
|
||||
"patch": [ { "op": "add", "path": "/2/1/-", "value": { "foo": [ "bar", "baz" ] } } ],
|
||||
"expected": [ 1, 2, [ 3, [ 4, 5, { "foo": [ "bar", "baz" ] } ] ] ]},
|
||||
|
||||
{ "comment": "test remove with bad number should fail",
|
||||
"doc": {"foo": 1, "baz": [{"qux": "hello"}]},
|
||||
"patch": [{"op": "remove", "path": "/baz/1e0/qux"}],
|
||||
"error": "remove op shouldn't remove from array with bad number" },
|
||||
|
||||
{ "comment": "test remove on array",
|
||||
"doc": [1, 2, 3, 4],
|
||||
"patch": [{"op": "remove", "path": "/0"}],
|
||||
"expected": [2, 3, 4] },
|
||||
|
||||
{ "comment": "test repeated removes",
|
||||
"doc": [1, 2, 3, 4],
|
||||
"patch": [{ "op": "remove", "path": "/1" },
|
||||
{ "op": "remove", "path": "/2" }],
|
||||
"expected": [1, 3] },
|
||||
|
||||
{ "comment": "test remove with bad index should fail",
|
||||
"doc": [1, 2, 3, 4],
|
||||
"patch": [{"op": "remove", "path": "/1e0"}],
|
||||
"error": "remove op shouldn't remove from array with bad number" },
|
||||
|
||||
{ "comment": "test replace with bad number should fail",
|
||||
"doc": [""],
|
||||
"patch": [{"op": "replace", "path": "/1e0", "value": false}],
|
||||
"error": "replace op shouldn't replace in array with bad number" },
|
||||
|
||||
{ "comment": "test copy with bad number should fail",
|
||||
"doc": {"baz": [1,2,3], "bar": 1},
|
||||
"patch": [{"op": "copy", "from": "/baz/1e0", "path": "/boo"}],
|
||||
"error": "copy op shouldn't work with bad number" },
|
||||
|
||||
{ "comment": "test move with bad number should fail",
|
||||
"doc": {"foo": 1, "baz": [1,2,3,4]},
|
||||
"patch": [{"op": "move", "from": "/baz/1e0", "path": "/foo"}],
|
||||
"error": "move op shouldn't work with bad number" },
|
||||
|
||||
{ "comment": "test add with bad number should fail",
|
||||
"doc": ["foo", "sil"],
|
||||
"patch": [{"op": "add", "path": "/1e0", "value": "bar"}],
|
||||
"error": "add op shouldn't add to array with bad number" },
|
||||
|
||||
{ "comment": "missing 'value' parameter to add",
|
||||
"doc": [ 1 ],
|
||||
"patch": [ { "op": "add", "path": "/-" } ],
|
||||
"error": "missing 'value' parameter" },
|
||||
|
||||
{ "comment": "missing 'value' parameter to replace",
|
||||
"doc": [ 1 ],
|
||||
"patch": [ { "op": "replace", "path": "/0" } ],
|
||||
"error": "missing 'value' parameter" },
|
||||
|
||||
{ "comment": "missing 'value' parameter to test",
|
||||
"doc": [ null ],
|
||||
"patch": [ { "op": "test", "path": "/0" } ],
|
||||
"error": "missing 'value' parameter" },
|
||||
|
||||
{ "comment": "missing value parameter to test - where undef is falsy",
|
||||
"doc": [ false ],
|
||||
"patch": [ { "op": "test", "path": "/0" } ],
|
||||
"error": "missing 'value' parameter" },
|
||||
|
||||
{ "comment": "missing from parameter to copy",
|
||||
"doc": [ 1 ],
|
||||
"patch": [ { "op": "copy", "path": "/-" } ],
|
||||
"error": "missing 'from' parameter" },
|
||||
|
||||
{ "comment": "missing from parameter to move",
|
||||
"doc": { "foo": 1 },
|
||||
"patch": [ { "op": "move", "path": "" } ],
|
||||
"error": "missing 'from' parameter" },
|
||||
|
||||
{ "comment": "duplicate ops",
|
||||
"doc": { "foo": "bar" },
|
||||
"patch": [ { "op": "add", "path": "/baz", "value": "qux",
|
||||
"op": "move", "from":"/foo" } ],
|
||||
"error": "patch has two 'op' members",
|
||||
"disabled": true },
|
||||
|
||||
{ "comment": "unrecognized op should fail",
|
||||
"doc": {"foo": 1},
|
||||
"patch": [{"op": "spam", "path": "/foo", "value": 1}],
|
||||
"error": "Unrecognized op 'spam'" },
|
||||
|
||||
{ "comment": "test with bad array number that has leading zeros",
|
||||
"doc": ["foo", "bar"],
|
||||
"patch": [{"op": "test", "path": "/00", "value": "foo"}],
|
||||
"error": "test op should reject the array value, it has leading zeros" },
|
||||
|
||||
{ "comment": "test with bad array number that has leading zeros",
|
||||
"doc": ["foo", "bar"],
|
||||
"patch": [{"op": "test", "path": "/01", "value": "bar"}],
|
||||
"error": "test op should reject the array value, it has leading zeros" },
|
||||
|
||||
{ "comment": "Removing nonexistent field",
|
||||
"doc": {"foo" : "bar"},
|
||||
"patch": [{"op": "remove", "path": "/baz"}],
|
||||
"error": "removing a nonexistent field should fail" },
|
||||
|
||||
{ "comment": "Removing nonexistent index",
|
||||
"doc": ["foo", "bar"],
|
||||
"patch": [{"op": "remove", "path": "/2"}],
|
||||
"error": "removing a nonexistent index should fail" },
|
||||
|
||||
{ "comment": "Patch with different capitalisation than doc",
|
||||
"doc": {"foo":"bar"},
|
||||
"patch": [{"op": "add", "path": "/FOO", "value": "BAR"}],
|
||||
"expected": {"foo": "bar", "FOO": "BAR"}
|
||||
}
|
||||
|
||||
]
|
||||
243
tests/json_patch_tests.c
Normal file
243
tests/json_patch_tests.c
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
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"
|
||||
#include "../cJSON_Utils.h"
|
||||
|
||||
static cJSON *parse_test_file(const char * const filename)
|
||||
{
|
||||
char *file = NULL;
|
||||
cJSON *json = NULL;
|
||||
|
||||
file = read_file(filename);
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(file, "Failed to read file.");
|
||||
|
||||
json = cJSON_Parse(file);
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(json, "Failed to parse test json.");
|
||||
TEST_ASSERT_TRUE_MESSAGE(cJSON_IsArray(json), "Json is not an array.");
|
||||
|
||||
free(file);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
static cJSON_bool test_apply_patch(const cJSON * const test)
|
||||
{
|
||||
cJSON *doc = NULL;
|
||||
cJSON *patch = NULL;
|
||||
cJSON *expected = NULL;
|
||||
cJSON *error_element = NULL;
|
||||
cJSON *comment = NULL;
|
||||
cJSON *disabled = NULL;
|
||||
|
||||
cJSON *object = NULL;
|
||||
cJSON_bool successful = false;
|
||||
|
||||
/* extract all the data out of the test */
|
||||
comment = cJSON_GetObjectItemCaseSensitive(test, "comment");
|
||||
if (cJSON_IsString(comment))
|
||||
{
|
||||
printf("Testing \"%s\"\n", comment->valuestring);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Testing unkown\n");
|
||||
}
|
||||
|
||||
disabled = cJSON_GetObjectItemCaseSensitive(test, "disabled");
|
||||
if (cJSON_IsTrue(disabled))
|
||||
{
|
||||
printf("SKIPPED\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
doc = cJSON_GetObjectItemCaseSensitive(test, "doc");
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(doc, "No \"doc\" in the test.");
|
||||
patch = cJSON_GetObjectItemCaseSensitive(test, "patch");
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(patch, "No \"patch\"in the test.");
|
||||
/* Make a working copy of 'doc' */
|
||||
object = cJSON_Duplicate(doc, true);
|
||||
TEST_ASSERT_NOT_NULL(object);
|
||||
|
||||
expected = cJSON_GetObjectItemCaseSensitive(test, "expected");
|
||||
error_element = cJSON_GetObjectItemCaseSensitive(test, "error");
|
||||
if (error_element != NULL)
|
||||
{
|
||||
/* excepting an error */
|
||||
TEST_ASSERT_TRUE_MESSAGE(0 != cJSONUtils_ApplyPatchesCaseSensitive(object, patch), "Test didn't fail as it's supposed to.");
|
||||
|
||||
successful = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* apply the patch */
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(0, cJSONUtils_ApplyPatchesCaseSensitive(object, patch), "Failed to apply patches.");
|
||||
successful = true;
|
||||
|
||||
if (expected != NULL)
|
||||
{
|
||||
successful = cJSON_Compare(object, expected, true);
|
||||
}
|
||||
}
|
||||
|
||||
cJSON_Delete(object);
|
||||
|
||||
if (successful)
|
||||
{
|
||||
printf("OK\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("FAILED\n");
|
||||
}
|
||||
|
||||
return successful;
|
||||
}
|
||||
|
||||
static cJSON_bool test_generate_test(cJSON *test)
|
||||
{
|
||||
cJSON *doc = NULL;
|
||||
cJSON *patch = NULL;
|
||||
cJSON *expected = NULL;
|
||||
cJSON *disabled = NULL;
|
||||
|
||||
cJSON *object = NULL;
|
||||
cJSON_bool successful = false;
|
||||
|
||||
char *printed_patch = NULL;
|
||||
|
||||
disabled = cJSON_GetObjectItemCaseSensitive(test, "disabled");
|
||||
if (cJSON_IsTrue(disabled))
|
||||
{
|
||||
printf("SKIPPED\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
doc = cJSON_GetObjectItemCaseSensitive(test, "doc");
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(doc, "No \"doc\" in the test.");
|
||||
|
||||
/* Make a working copy of 'doc' */
|
||||
object = cJSON_Duplicate(doc, true);
|
||||
TEST_ASSERT_NOT_NULL(object);
|
||||
|
||||
expected = cJSON_GetObjectItemCaseSensitive(test, "expected");
|
||||
if (expected == NULL)
|
||||
{
|
||||
cJSON_Delete(object);
|
||||
/* if there is no expected output, this test doesn't make sense */
|
||||
return true;
|
||||
}
|
||||
|
||||
patch = cJSONUtils_GeneratePatchesCaseSensitive(doc, expected);
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(patch, "Failed to generate patches.");
|
||||
|
||||
printed_patch = cJSON_Print(patch);
|
||||
printf("%s\n", printed_patch);
|
||||
free(printed_patch);
|
||||
|
||||
/* apply the generated patch */
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(0, cJSONUtils_ApplyPatchesCaseSensitive(object, patch), "Failed to apply generated patch.");
|
||||
|
||||
successful = cJSON_Compare(object, expected, true);
|
||||
|
||||
cJSON_Delete(patch);
|
||||
cJSON_Delete(object);
|
||||
|
||||
if (successful)
|
||||
{
|
||||
printf("generated patch: OK\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("generated patch: FAILED\n");
|
||||
}
|
||||
|
||||
return successful;
|
||||
}
|
||||
|
||||
static void cjson_utils_should_pass_json_patch_test_tests(void)
|
||||
{
|
||||
cJSON *tests = parse_test_file("json-patch-tests/tests.json");
|
||||
cJSON *test = NULL;
|
||||
|
||||
cJSON_bool failed = false;
|
||||
cJSON_ArrayForEach(test, tests)
|
||||
{
|
||||
failed |= !test_apply_patch(test);
|
||||
failed |= !test_generate_test(test);
|
||||
}
|
||||
|
||||
cJSON_Delete(tests);
|
||||
|
||||
TEST_ASSERT_FALSE_MESSAGE(failed, "Some tests failed.");
|
||||
}
|
||||
|
||||
static void cjson_utils_should_pass_json_patch_test_spec_tests(void)
|
||||
{
|
||||
cJSON *tests = parse_test_file("json-patch-tests/spec_tests.json");
|
||||
cJSON *test = NULL;
|
||||
|
||||
cJSON_bool failed = false;
|
||||
cJSON_ArrayForEach(test, tests)
|
||||
{
|
||||
failed |= !test_apply_patch(test);
|
||||
failed |= !test_generate_test(test);
|
||||
}
|
||||
|
||||
cJSON_Delete(tests);
|
||||
|
||||
TEST_ASSERT_FALSE_MESSAGE(failed, "Some tests failed.");
|
||||
}
|
||||
|
||||
static void cjson_utils_should_pass_json_patch_test_cjson_utils_tests(void)
|
||||
{
|
||||
cJSON *tests = parse_test_file("json-patch-tests/cjson-utils-tests.json");
|
||||
cJSON *test = NULL;
|
||||
|
||||
cJSON_bool failed = false;
|
||||
cJSON_ArrayForEach(test, tests)
|
||||
{
|
||||
failed |= !test_apply_patch(test);
|
||||
failed |= !test_generate_test(test);
|
||||
}
|
||||
|
||||
cJSON_Delete(tests);
|
||||
|
||||
TEST_ASSERT_FALSE_MESSAGE(failed, "Some tests failed.");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
|
||||
RUN_TEST(cjson_utils_should_pass_json_patch_test_tests);
|
||||
RUN_TEST(cjson_utils_should_pass_json_patch_test_spec_tests);
|
||||
RUN_TEST(cjson_utils_should_pass_json_patch_test_cjson_utils_tests);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
58
tests/meson.build
Normal file
58
tests/meson.build
Normal file
@@ -0,0 +1,58 @@
|
||||
if get_option('enable_cjson_tests')
|
||||
unity_flags = []
|
||||
|
||||
if (compiler.get_id() == 'clang') or (compiler.get_id() == 'gcc')
|
||||
unity_flags += [
|
||||
'-Wno-switch-enum',
|
||||
'-Wno-error',
|
||||
'-fvisibility=default',
|
||||
'-fno-sanitize=float-divide-by-zero'
|
||||
]
|
||||
endif
|
||||
|
||||
unity_c_args = []
|
||||
foreach flag : unity_flags
|
||||
if compiler.has_argument(flag)
|
||||
unity_c_args += flag
|
||||
endif
|
||||
endforeach
|
||||
|
||||
unity = library('unity', 'unity/src/unity.c', c_args: unity_c_args)
|
||||
common = library('test_common', 'common.c')
|
||||
|
||||
cjson_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',
|
||||
'parse_with_opts',
|
||||
'compare_tests'
|
||||
]
|
||||
|
||||
foreach cjson_test : cjson_tests
|
||||
exe = executable(cjson_test, cjson_test + '.c', link_with: [common, cjson, unity])
|
||||
test(cjson_test, exe, workdir: meson.current_source_dir())
|
||||
endforeach
|
||||
|
||||
if get_option('enable_cjson_utils')
|
||||
cjson_utils_tests = [
|
||||
'json_patch_tests',
|
||||
'old_utils_tests',
|
||||
'misc_utils_tests'
|
||||
]
|
||||
|
||||
foreach cjson_utils_test : cjson_utils_tests
|
||||
exe = executable(cjson_utils_test, cjson_utils_test + '.c', link_with: [common, cjson_utils, unity, cjson])
|
||||
test(cjson_utils_test, exe, workdir: meson.current_source_dir())
|
||||
endforeach
|
||||
endif
|
||||
endif
|
||||
430
tests/misc_tests.c
Normal file
430
tests/misc_tests.c
Normal file
@@ -0,0 +1,430 @@
|
||||
/*
|
||||
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));
|
||||
}
|
||||
|
||||
static void cjson_should_not_parse_to_deeply_nested_jsons(void)
|
||||
{
|
||||
char deep_json[CJSON_NESTING_LIMIT + 1];
|
||||
size_t position = 0;
|
||||
|
||||
for (position = 0; position < sizeof(deep_json); position++)
|
||||
{
|
||||
deep_json[position] = '[';
|
||||
}
|
||||
deep_json[sizeof(deep_json) - 1] = '\0';
|
||||
|
||||
TEST_ASSERT_NULL_MESSAGE(cJSON_Parse(deep_json), "To deep JSONs should not be parsed.");
|
||||
}
|
||||
|
||||
static void cjson_set_number_value_should_set_numbers(void)
|
||||
{
|
||||
cJSON number[1] = {{NULL, NULL, NULL, cJSON_Number, NULL, 0, 0, NULL}};
|
||||
|
||||
cJSON_SetNumberValue(number, 1.5);
|
||||
TEST_ASSERT_EQUAL(1, number->valueint);
|
||||
TEST_ASSERT_EQUAL_DOUBLE(1.5, number->valuedouble);
|
||||
|
||||
cJSON_SetNumberValue(number, -1.5);
|
||||
TEST_ASSERT_EQUAL(-1, number->valueint);
|
||||
TEST_ASSERT_EQUAL_DOUBLE(-1.5, number->valuedouble);
|
||||
|
||||
cJSON_SetNumberValue(number, 1 + (double)INT_MAX);
|
||||
TEST_ASSERT_EQUAL(INT_MAX, number->valueint);
|
||||
TEST_ASSERT_EQUAL_DOUBLE(1 + (double)INT_MAX, number->valuedouble);
|
||||
|
||||
cJSON_SetNumberValue(number, -1 + (double)INT_MIN);
|
||||
TEST_ASSERT_EQUAL(INT_MIN, number->valueint);
|
||||
TEST_ASSERT_EQUAL_DOUBLE(-1 + (double)INT_MIN, number->valuedouble);
|
||||
}
|
||||
|
||||
static void cjson_detach_item_via_pointer_should_detach_items(void)
|
||||
{
|
||||
cJSON list[4];
|
||||
cJSON parent[1];
|
||||
|
||||
memset(list, '\0', sizeof(list));
|
||||
|
||||
/* link the list */
|
||||
list[0].next = &(list[1]);
|
||||
list[1].next = &(list[2]);
|
||||
list[2].next = &(list[3]);
|
||||
|
||||
list[3].prev = &(list[2]);
|
||||
list[2].prev = &(list[1]);
|
||||
list[1].prev = &(list[0]);
|
||||
|
||||
parent->child = &list[0];
|
||||
|
||||
/* detach in the middle (list[1]) */
|
||||
TEST_ASSERT_TRUE_MESSAGE(cJSON_DetachItemViaPointer(parent, &(list[1])) == &(list[1]), "Failed to detach in the middle.");
|
||||
TEST_ASSERT_TRUE_MESSAGE((list[1].prev == NULL) && (list[1].next == NULL), "Didn't set pointers of detached item to NULL.");
|
||||
TEST_ASSERT_TRUE((list[0].next == &(list[2])) && (list[2].prev == &(list[0])));
|
||||
|
||||
/* detach beginning (list[0]) */
|
||||
TEST_ASSERT_TRUE_MESSAGE(cJSON_DetachItemViaPointer(parent, &(list[0])) == &(list[0]), "Failed to detach beginning.");
|
||||
TEST_ASSERT_TRUE_MESSAGE((list[0].prev == NULL) && (list[0].next == NULL), "Didn't set pointers of detached item to NULL.");
|
||||
TEST_ASSERT_TRUE_MESSAGE((list[2].prev == NULL) && (parent->child == &(list[2])), "Didn't set the new beginning.");
|
||||
|
||||
/* detach end (list[3])*/
|
||||
TEST_ASSERT_TRUE_MESSAGE(cJSON_DetachItemViaPointer(parent, &(list[3])) == &(list[3]), "Failed to detach end.");
|
||||
TEST_ASSERT_TRUE_MESSAGE((list[3].prev == NULL) && (list[3].next == NULL), "Didn't set pointers of detached item to NULL.");
|
||||
TEST_ASSERT_TRUE_MESSAGE((list[2].next == NULL) && (parent->child == &(list[2])), "Didn't set the new end");
|
||||
|
||||
/* detach single item (list[2]) */
|
||||
TEST_ASSERT_TRUE_MESSAGE(cJSON_DetachItemViaPointer(parent, &list[2]) == &list[2], "Failed to detach single item.");
|
||||
TEST_ASSERT_TRUE_MESSAGE((list[2].prev == NULL) && (list[2].next == NULL), "Didn't set pointers of detached item to NULL.");
|
||||
TEST_ASSERT_NULL_MESSAGE(parent->child, "Child of the parent wasn't set to NULL.");
|
||||
}
|
||||
|
||||
static void cjson_replace_item_via_pointer_should_replace_items(void)
|
||||
{
|
||||
cJSON replacements[3];
|
||||
cJSON *beginning = NULL;
|
||||
cJSON *middle = NULL;
|
||||
cJSON *end = NULL;
|
||||
cJSON *array = NULL;
|
||||
|
||||
beginning = cJSON_CreateNull();
|
||||
TEST_ASSERT_NOT_NULL(beginning);
|
||||
middle = cJSON_CreateNull();
|
||||
TEST_ASSERT_NOT_NULL(middle);
|
||||
end = cJSON_CreateNull();
|
||||
TEST_ASSERT_NOT_NULL(end);
|
||||
|
||||
array = cJSON_CreateArray();
|
||||
TEST_ASSERT_NOT_NULL(array);
|
||||
|
||||
cJSON_AddItemToArray(array, beginning);
|
||||
cJSON_AddItemToArray(array, middle);
|
||||
cJSON_AddItemToArray(array, end);
|
||||
|
||||
|
||||
memset(replacements, '\0', sizeof(replacements));
|
||||
|
||||
/* replace beginning */
|
||||
TEST_ASSERT_TRUE(cJSON_ReplaceItemViaPointer(array, beginning, &(replacements[0])));
|
||||
TEST_ASSERT_NULL(replacements[0].prev);
|
||||
TEST_ASSERT_TRUE(replacements[0].next == middle);
|
||||
TEST_ASSERT_TRUE(middle->prev == &(replacements[0]));
|
||||
TEST_ASSERT_TRUE(array->child == &(replacements[0]));
|
||||
|
||||
/* replace middle */
|
||||
TEST_ASSERT_TRUE(cJSON_ReplaceItemViaPointer(array, middle, &(replacements[1])));
|
||||
TEST_ASSERT_TRUE(replacements[1].prev == &(replacements[0]));
|
||||
TEST_ASSERT_TRUE(replacements[1].next == end);
|
||||
TEST_ASSERT_TRUE(end->prev == &(replacements[1]));
|
||||
|
||||
/* replace end */
|
||||
TEST_ASSERT_TRUE(cJSON_ReplaceItemViaPointer(array, end, &(replacements[2])));
|
||||
TEST_ASSERT_TRUE(replacements[2].prev == &(replacements[1]));
|
||||
TEST_ASSERT_NULL(replacements[2].next);
|
||||
TEST_ASSERT_TRUE(replacements[1].next == &(replacements[2]));
|
||||
|
||||
cJSON_free(array);
|
||||
}
|
||||
|
||||
static void cjson_replace_item_in_object_should_preserve_name(void)
|
||||
{
|
||||
cJSON root[1] = {{ NULL, NULL, NULL, 0, NULL, 0, 0, NULL }};
|
||||
cJSON *child = NULL;
|
||||
cJSON *replacement = NULL;
|
||||
|
||||
child = cJSON_CreateNumber(1);
|
||||
TEST_ASSERT_NOT_NULL(child);
|
||||
replacement = cJSON_CreateNumber(2);
|
||||
TEST_ASSERT_NOT_NULL(replacement);
|
||||
|
||||
cJSON_AddItemToObject(root, "child", child);
|
||||
cJSON_ReplaceItemInObject(root, "child", replacement);
|
||||
|
||||
TEST_ASSERT_TRUE(root->child == replacement);
|
||||
TEST_ASSERT_EQUAL_STRING("child", replacement->string);
|
||||
|
||||
cJSON_Delete(replacement);
|
||||
}
|
||||
|
||||
static void cjson_functions_shouldnt_crash_with_null_pointers(void)
|
||||
{
|
||||
char buffer[10];
|
||||
cJSON *item = cJSON_CreateString("item");
|
||||
|
||||
cJSON_InitHooks(NULL);
|
||||
TEST_ASSERT_NULL(cJSON_Parse(NULL));
|
||||
TEST_ASSERT_NULL(cJSON_ParseWithOpts(NULL, NULL, true));
|
||||
TEST_ASSERT_NULL(cJSON_Print(NULL));
|
||||
TEST_ASSERT_NULL(cJSON_PrintUnformatted(NULL));
|
||||
TEST_ASSERT_NULL(cJSON_PrintBuffered(NULL, 10, true));
|
||||
TEST_ASSERT_FALSE(cJSON_PrintPreallocated(NULL, buffer, sizeof(buffer), true));
|
||||
TEST_ASSERT_FALSE(cJSON_PrintPreallocated(item, NULL, 1, true));
|
||||
cJSON_Delete(NULL);
|
||||
cJSON_GetArraySize(NULL);
|
||||
TEST_ASSERT_NULL(cJSON_GetArrayItem(NULL, 0));
|
||||
TEST_ASSERT_NULL(cJSON_GetObjectItem(NULL, "item"));
|
||||
TEST_ASSERT_NULL(cJSON_GetObjectItem(item, NULL));
|
||||
TEST_ASSERT_NULL(cJSON_GetObjectItemCaseSensitive(NULL, "item"));
|
||||
TEST_ASSERT_NULL(cJSON_GetObjectItemCaseSensitive(item, NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_HasObjectItem(NULL, "item"));
|
||||
TEST_ASSERT_FALSE(cJSON_HasObjectItem(item, NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_IsInvalid(NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_IsFalse(NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_IsTrue(NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_IsBool(NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_IsNull(NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_IsNumber(NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_IsString(NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_IsArray(NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_IsObject(NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_IsRaw(NULL));
|
||||
TEST_ASSERT_NULL(cJSON_CreateString(NULL));
|
||||
TEST_ASSERT_NULL(cJSON_CreateRaw(NULL));
|
||||
TEST_ASSERT_NULL(cJSON_CreateIntArray(NULL, 10));
|
||||
TEST_ASSERT_NULL(cJSON_CreateFloatArray(NULL, 10));
|
||||
TEST_ASSERT_NULL(cJSON_CreateDoubleArray(NULL, 10));
|
||||
TEST_ASSERT_NULL(cJSON_CreateStringArray(NULL, 10));
|
||||
cJSON_AddItemToArray(NULL, item);
|
||||
cJSON_AddItemToArray(item, NULL);
|
||||
cJSON_AddItemToObject(item, "item", NULL);
|
||||
cJSON_AddItemToObject(item, NULL, item);
|
||||
cJSON_AddItemToObject(NULL, "item", item);
|
||||
cJSON_AddItemToObjectCS(item, "item", NULL);
|
||||
cJSON_AddItemToObjectCS(item, NULL, item);
|
||||
cJSON_AddItemToObjectCS(NULL, "item", item);
|
||||
cJSON_AddItemReferenceToArray(NULL, item);
|
||||
cJSON_AddItemReferenceToArray(item, NULL);
|
||||
cJSON_AddItemReferenceToObject(item, "item", NULL);
|
||||
cJSON_AddItemReferenceToObject(item, NULL, item);
|
||||
cJSON_AddItemReferenceToObject(NULL, "item", item);
|
||||
TEST_ASSERT_NULL(cJSON_DetachItemViaPointer(NULL, item));
|
||||
TEST_ASSERT_NULL(cJSON_DetachItemViaPointer(item, NULL));
|
||||
TEST_ASSERT_NULL(cJSON_DetachItemFromArray(NULL, 0));
|
||||
cJSON_DeleteItemFromArray(NULL, 0);
|
||||
TEST_ASSERT_NULL(cJSON_DetachItemFromObject(NULL, "item"));
|
||||
TEST_ASSERT_NULL(cJSON_DetachItemFromObject(item, NULL));
|
||||
TEST_ASSERT_NULL(cJSON_DetachItemFromObjectCaseSensitive(NULL, "item"));
|
||||
TEST_ASSERT_NULL(cJSON_DetachItemFromObjectCaseSensitive(item, NULL));
|
||||
cJSON_DeleteItemFromObject(NULL, "item");
|
||||
cJSON_DeleteItemFromObject(item, NULL);
|
||||
cJSON_DeleteItemFromObjectCaseSensitive(NULL, "item");
|
||||
cJSON_DeleteItemFromObjectCaseSensitive(item, NULL);
|
||||
cJSON_InsertItemInArray(NULL, 0, item);
|
||||
cJSON_InsertItemInArray(item, 0, NULL);
|
||||
TEST_ASSERT_FALSE(cJSON_ReplaceItemViaPointer(NULL, item, item));
|
||||
TEST_ASSERT_FALSE(cJSON_ReplaceItemViaPointer(item, NULL, item));
|
||||
TEST_ASSERT_FALSE(cJSON_ReplaceItemViaPointer(item, item, NULL));
|
||||
cJSON_ReplaceItemInArray(item, 0, NULL);
|
||||
cJSON_ReplaceItemInArray(NULL, 0, item);
|
||||
cJSON_ReplaceItemInObject(NULL, "item", item);
|
||||
cJSON_ReplaceItemInObject(item, NULL, item);
|
||||
cJSON_ReplaceItemInObject(item, "item", NULL);
|
||||
cJSON_ReplaceItemInObjectCaseSensitive(NULL, "item", item);
|
||||
cJSON_ReplaceItemInObjectCaseSensitive(item, NULL, item);
|
||||
cJSON_ReplaceItemInObjectCaseSensitive(item, "item", NULL);
|
||||
TEST_ASSERT_NULL(cJSON_Duplicate(NULL, true));
|
||||
TEST_ASSERT_FALSE(cJSON_Compare(item, NULL, false));
|
||||
TEST_ASSERT_FALSE(cJSON_Compare(NULL, item, false));
|
||||
cJSON_Minify(NULL);
|
||||
/* skipped because it is only used via a macro that checks for NULL */
|
||||
/* cJSON_SetNumberHelper(NULL, 0); */
|
||||
|
||||
cJSON_Delete(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);
|
||||
RUN_TEST(cjson_should_not_parse_to_deeply_nested_jsons);
|
||||
RUN_TEST(cjson_set_number_value_should_set_numbers);
|
||||
RUN_TEST(cjson_detach_item_via_pointer_should_detach_items);
|
||||
RUN_TEST(cjson_replace_item_via_pointer_should_replace_items);
|
||||
RUN_TEST(cjson_replace_item_in_object_should_preserve_name);
|
||||
RUN_TEST(cjson_functions_shouldnt_crash_with_null_pointers);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
80
tests/misc_utils_tests.c
Normal file
80
tests/misc_utils_tests.c
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
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"
|
||||
#include "../cJSON_Utils.h"
|
||||
|
||||
static void cjson_utils_functions_shouldnt_crash_with_null_pointers(void)
|
||||
{
|
||||
cJSON *item = cJSON_CreateString("item");
|
||||
TEST_ASSERT_NOT_NULL(item);
|
||||
|
||||
TEST_ASSERT_NULL(cJSONUtils_GetPointer(item, NULL));
|
||||
TEST_ASSERT_NULL(cJSONUtils_GetPointer(NULL, "pointer"));
|
||||
TEST_ASSERT_NULL(cJSONUtils_GetPointerCaseSensitive(NULL, "pointer"));
|
||||
TEST_ASSERT_NULL(cJSONUtils_GetPointerCaseSensitive(item, NULL));
|
||||
TEST_ASSERT_NULL(cJSONUtils_GeneratePatches(item, NULL));
|
||||
TEST_ASSERT_NULL(cJSONUtils_GeneratePatches(NULL, item));
|
||||
TEST_ASSERT_NULL(cJSONUtils_GeneratePatchesCaseSensitive(item, NULL));
|
||||
TEST_ASSERT_NULL(cJSONUtils_GeneratePatchesCaseSensitive(NULL, item));
|
||||
cJSONUtils_AddPatchToArray(item, "path", "add", NULL);
|
||||
cJSONUtils_AddPatchToArray(item, "path", NULL, item);
|
||||
cJSONUtils_AddPatchToArray(item, NULL, "add", item);
|
||||
cJSONUtils_AddPatchToArray(NULL, "path", "add", item);
|
||||
cJSONUtils_ApplyPatches(item, NULL);
|
||||
cJSONUtils_ApplyPatches(NULL, item);
|
||||
cJSONUtils_ApplyPatchesCaseSensitive(item, NULL);
|
||||
cJSONUtils_ApplyPatchesCaseSensitive(NULL, item);
|
||||
TEST_ASSERT_NULL(cJSONUtils_MergePatch(item, NULL));
|
||||
item = cJSON_CreateString("item");
|
||||
TEST_ASSERT_NULL(cJSONUtils_MergePatchCaseSensitive(item, NULL));
|
||||
item = cJSON_CreateString("item");
|
||||
/* these calls are actually valid */
|
||||
/* cJSONUtils_MergePatch(NULL, item); */
|
||||
/* cJSONUtils_MergePatchCaseSensitive(NULL, item);*/
|
||||
/* cJSONUtils_GenerateMergePatch(item, NULL); */
|
||||
/* cJSONUtils_GenerateMergePatch(NULL, item); */
|
||||
/* cJSONUtils_GenerateMergePatchCaseSensitive(item, NULL); */
|
||||
/* cJSONUtils_GenerateMergePatchCaseSensitive(NULL, item); */
|
||||
|
||||
TEST_ASSERT_NULL(cJSONUtils_FindPointerFromObjectTo(item, NULL));
|
||||
TEST_ASSERT_NULL(cJSONUtils_FindPointerFromObjectTo(NULL, item));
|
||||
cJSONUtils_SortObject(NULL);
|
||||
cJSONUtils_SortObjectCaseSensitive(NULL);
|
||||
|
||||
cJSON_Delete(item);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
|
||||
RUN_TEST(cjson_utils_functions_shouldnt_crash_with_null_pointers);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
205
tests/old_utils_tests.c
Normal file
205
tests/old_utils_tests.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
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"
|
||||
#include "../cJSON_Utils.h"
|
||||
|
||||
/* JSON Apply Merge tests: */
|
||||
static const char *merges[15][3] =
|
||||
{
|
||||
{"{\"a\":\"b\"}", "{\"a\":\"c\"}", "{\"a\":\"c\"}"},
|
||||
{"{\"a\":\"b\"}", "{\"b\":\"c\"}", "{\"a\":\"b\",\"b\":\"c\"}"},
|
||||
{"{\"a\":\"b\"}", "{\"a\":null}", "{}"},
|
||||
{"{\"a\":\"b\",\"b\":\"c\"}", "{\"a\":null}", "{\"b\":\"c\"}"},
|
||||
{"{\"a\":[\"b\"]}", "{\"a\":\"c\"}", "{\"a\":\"c\"}"},
|
||||
{"{\"a\":\"c\"}", "{\"a\":[\"b\"]}", "{\"a\":[\"b\"]}"},
|
||||
{"{\"a\":{\"b\":\"c\"}}", "{\"a\":{\"b\":\"d\",\"c\":null}}", "{\"a\":{\"b\":\"d\"}}"},
|
||||
{"{\"a\":[{\"b\":\"c\"}]}", "{\"a\":[1]}", "{\"a\":[1]}"},
|
||||
{"[\"a\",\"b\"]", "[\"c\",\"d\"]", "[\"c\",\"d\"]"},
|
||||
{"{\"a\":\"b\"}", "[\"c\"]", "[\"c\"]"},
|
||||
{"{\"a\":\"foo\"}", "null", "null"},
|
||||
{"{\"a\":\"foo\"}", "\"bar\"", "\"bar\""},
|
||||
{"{\"e\":null}", "{\"a\":1}", "{\"e\":null,\"a\":1}"},
|
||||
{"[1,2]", "{\"a\":\"b\",\"c\":null}", "{\"a\":\"b\"}"},
|
||||
{"{}","{\"a\":{\"bb\":{\"ccc\":null}}}", "{\"a\":{\"bb\":{}}}"}
|
||||
};
|
||||
|
||||
static void json_pointer_tests(void)
|
||||
{
|
||||
cJSON *root = NULL;
|
||||
const char *json=
|
||||
"{"
|
||||
"\"foo\": [\"bar\", \"baz\"],"
|
||||
"\"\": 0,"
|
||||
"\"a/b\": 1,"
|
||||
"\"c%d\": 2,"
|
||||
"\"e^f\": 3,"
|
||||
"\"g|h\": 4,"
|
||||
"\"i\\\\j\": 5,"
|
||||
"\"k\\\"l\": 6,"
|
||||
"\" \": 7,"
|
||||
"\"m~n\": 8"
|
||||
"}";
|
||||
|
||||
root = cJSON_Parse(json);
|
||||
|
||||
TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, ""), root);
|
||||
TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/foo"), cJSON_GetObjectItem(root, "foo"));
|
||||
TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/foo/0"), cJSON_GetObjectItem(root, "foo")->child);
|
||||
TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/foo/0"), cJSON_GetObjectItem(root, "foo")->child);
|
||||
TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/"), cJSON_GetObjectItem(root, ""));
|
||||
TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/a~1b"), cJSON_GetObjectItem(root, "a/b"));
|
||||
TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/c%d"), cJSON_GetObjectItem(root, "c%d"));
|
||||
TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/c^f"), cJSON_GetObjectItem(root, "c^f"));
|
||||
TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/c|f"), cJSON_GetObjectItem(root, "c|f"));
|
||||
TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/i\\j"), cJSON_GetObjectItem(root, "i\\j"));
|
||||
TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/k\"l"), cJSON_GetObjectItem(root, "k\"l"));
|
||||
TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/ "), cJSON_GetObjectItem(root, " "));
|
||||
TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/m~0n"), cJSON_GetObjectItem(root, "m~n"));
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void misc_tests(void)
|
||||
{
|
||||
/* Misc tests */
|
||||
int numbers[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
cJSON *object = NULL;
|
||||
cJSON *nums = NULL;
|
||||
cJSON *num6 = NULL;
|
||||
char *pointer = NULL;
|
||||
|
||||
printf("JSON Pointer construct\n");
|
||||
object = cJSON_CreateObject();
|
||||
nums = cJSON_CreateIntArray(numbers, 10);
|
||||
num6 = cJSON_GetArrayItem(nums, 6);
|
||||
cJSON_AddItemToObject(object, "numbers", nums);
|
||||
|
||||
pointer = cJSONUtils_FindPointerFromObjectTo(object, num6);
|
||||
TEST_ASSERT_EQUAL_STRING("/numbers/6", pointer);
|
||||
free(pointer);
|
||||
|
||||
pointer = cJSONUtils_FindPointerFromObjectTo(object, nums);
|
||||
TEST_ASSERT_EQUAL_STRING("/numbers", pointer);
|
||||
free(pointer);
|
||||
|
||||
pointer = cJSONUtils_FindPointerFromObjectTo(object, object);
|
||||
TEST_ASSERT_EQUAL_STRING("", pointer);
|
||||
free(pointer);
|
||||
|
||||
cJSON_Delete(object);
|
||||
}
|
||||
|
||||
static void sort_tests(void)
|
||||
{
|
||||
/* Misc tests */
|
||||
const char *random = "QWERTYUIOPASDFGHJKLZXCVBNM";
|
||||
char buf[2] = {'\0', '\0'};
|
||||
cJSON *sortme = NULL;
|
||||
size_t i = 0;
|
||||
cJSON *current_element = NULL;
|
||||
|
||||
/* JSON Sort test: */
|
||||
sortme = cJSON_CreateObject();
|
||||
for (i = 0; i < 26; i++)
|
||||
{
|
||||
buf[0] = random[i];
|
||||
cJSON_AddItemToObject(sortme, buf, cJSON_CreateNumber(1));
|
||||
}
|
||||
|
||||
cJSONUtils_SortObject(sortme);
|
||||
|
||||
/* check sorting */
|
||||
current_element = sortme->child->next;
|
||||
for (i = 1; (i < 26) && (current_element != NULL) && (current_element->prev != NULL); i++)
|
||||
{
|
||||
TEST_ASSERT_TRUE(current_element->string[0] >= current_element->prev->string[0]);
|
||||
current_element = current_element->next;
|
||||
}
|
||||
|
||||
cJSON_Delete(sortme);
|
||||
}
|
||||
|
||||
static void merge_tests(void)
|
||||
{
|
||||
size_t i = 0;
|
||||
char *patchtext = NULL;
|
||||
char *after = NULL;
|
||||
|
||||
/* Merge tests: */
|
||||
printf("JSON Merge Patch tests\n");
|
||||
for (i = 0; i < 15; i++)
|
||||
{
|
||||
cJSON *object_to_be_merged = cJSON_Parse(merges[i][0]);
|
||||
cJSON *patch = cJSON_Parse(merges[i][1]);
|
||||
patchtext = cJSON_PrintUnformatted(patch);
|
||||
object_to_be_merged = cJSONUtils_MergePatch(object_to_be_merged, patch);
|
||||
after = cJSON_PrintUnformatted(object_to_be_merged);
|
||||
TEST_ASSERT_EQUAL_STRING(merges[i][2], after);
|
||||
|
||||
free(patchtext);
|
||||
free(after);
|
||||
cJSON_Delete(object_to_be_merged);
|
||||
cJSON_Delete(patch);
|
||||
}
|
||||
}
|
||||
|
||||
static void generate_merge_tests(void)
|
||||
{
|
||||
size_t i = 0;
|
||||
char *patchedtext = NULL;
|
||||
|
||||
/* Generate Merge tests: */
|
||||
for (i = 0; i < 15; i++)
|
||||
{
|
||||
cJSON *from = cJSON_Parse(merges[i][0]);
|
||||
cJSON *to = cJSON_Parse(merges[i][2]);
|
||||
cJSON *patch = cJSONUtils_GenerateMergePatch(from,to);
|
||||
from = cJSONUtils_MergePatch(from,patch);
|
||||
patchedtext = cJSON_PrintUnformatted(from);
|
||||
TEST_ASSERT_EQUAL_STRING(merges[i][2], patchedtext);
|
||||
|
||||
cJSON_Delete(from);
|
||||
cJSON_Delete(to);
|
||||
cJSON_Delete(patch);
|
||||
free(patchedtext);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
|
||||
RUN_TEST(json_pointer_tests);
|
||||
RUN_TEST(misc_tests);
|
||||
RUN_TEST(sort_tests);
|
||||
RUN_TEST(merge_tests);
|
||||
RUN_TEST(generate_merge_tests);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
166
tests/parse_array.c
Normal file
166
tests/parse_array.c
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
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_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)
|
||||
{
|
||||
parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
buffer.content = (const unsigned char*)json;
|
||||
buffer.length = strlen(json) + sizeof("");
|
||||
buffer.hooks = global_hooks;
|
||||
|
||||
TEST_ASSERT_FALSE(parse_array(item, &buffer));
|
||||
assert_is_invalid(item);
|
||||
}
|
||||
|
||||
static void assert_parse_array(const char *json)
|
||||
{
|
||||
parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
buffer.content = (const unsigned char*)json;
|
||||
buffer.length = strlen(json) + sizeof("");
|
||||
buffer.hooks = global_hooks;
|
||||
|
||||
TEST_ASSERT_TRUE(parse_array(item, &buffer));
|
||||
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();
|
||||
}
|
||||
197
tests/parse_examples.c
Normal file
197
tests/parse_examples.c
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "unity/examples/unity_config.h"
|
||||
#include "unity/src/unity.h"
|
||||
#include "common.h"
|
||||
|
||||
static 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();
|
||||
}
|
||||
73
tests/parse_hex4.c
Normal file
73
tests/parse_hex4.c
Normal file
@@ -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[6];
|
||||
unsigned char digits_upper[6];
|
||||
/* 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();
|
||||
}
|
||||
110
tests/parse_number.c
Normal file
110
tests/parse_number.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
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)
|
||||
{
|
||||
parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
buffer.content = (const unsigned char*)string;
|
||||
buffer.length = strlen(string) + sizeof("");
|
||||
|
||||
TEST_ASSERT_TRUE(parse_number(item, &buffer));
|
||||
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();
|
||||
}
|
||||
176
tests/parse_object.c
Normal file
176
tests/parse_object.c
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "unity/examples/unity_config.h"
|
||||
#include "unity/src/unity.h"
|
||||
#include "common.h"
|
||||
|
||||
static cJSON item[1];
|
||||
|
||||
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)
|
||||
{
|
||||
parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
parsebuffer.content = (const unsigned char*)json;
|
||||
parsebuffer.length = strlen(json) + sizeof("");
|
||||
parsebuffer.hooks = global_hooks;
|
||||
|
||||
TEST_ASSERT_FALSE(parse_object(item, &parsebuffer));
|
||||
assert_is_invalid(item);
|
||||
reset(item);
|
||||
}
|
||||
|
||||
static void assert_parse_object(const char *json)
|
||||
{
|
||||
parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
parsebuffer.content = (const unsigned char*)json;
|
||||
parsebuffer.length = strlen(json) + sizeof("");
|
||||
parsebuffer.hooks = global_hooks;
|
||||
|
||||
TEST_ASSERT_TRUE(parse_object(item, &parsebuffer));
|
||||
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();
|
||||
}
|
||||
135
tests/parse_string.c
Normal file
135
tests/parse_string.c
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
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_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)
|
||||
{
|
||||
parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
buffer.content = (const unsigned char*)string;
|
||||
buffer.length = strlen(string) + sizeof("");
|
||||
buffer.hooks = global_hooks;
|
||||
|
||||
TEST_ASSERT_TRUE_MESSAGE(parse_string(item, &buffer), "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;
|
||||
}
|
||||
|
||||
static void assert_not_parse_string(const char * const string)
|
||||
{
|
||||
parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
buffer.content = (const unsigned char*)string;
|
||||
buffer.length = strlen(string) + sizeof("");
|
||||
buffer.hooks = global_hooks;
|
||||
|
||||
TEST_ASSERT_FALSE_MESSAGE(parse_string(item, &buffer), "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();
|
||||
}
|
||||
112
tests/parse_value.c
Normal file
112
tests/parse_value.c
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
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_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)
|
||||
{
|
||||
parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
buffer.content = (const unsigned char*) string;
|
||||
buffer.length = strlen(string) + sizeof("");
|
||||
buffer.hooks = global_hooks;
|
||||
|
||||
TEST_ASSERT_TRUE(parse_value(item, &buffer));
|
||||
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();
|
||||
}
|
||||
82
tests/parse_with_opts.c
Normal file
82
tests/parse_with_opts.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
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 parse_with_opts_should_handle_null(void)
|
||||
{
|
||||
const char *error_pointer = NULL;
|
||||
cJSON *item = NULL;
|
||||
TEST_ASSERT_NULL_MESSAGE(cJSON_ParseWithOpts(NULL, &error_pointer, false), "Failed to handle NULL input.");
|
||||
item = cJSON_ParseWithOpts("{}", NULL, false);
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(item, "Failed to handle NULL error pointer.");
|
||||
cJSON_Delete(item);
|
||||
TEST_ASSERT_NULL_MESSAGE(cJSON_ParseWithOpts(NULL, NULL, false), "Failed to handle both NULL.");
|
||||
TEST_ASSERT_NULL_MESSAGE(cJSON_ParseWithOpts("{", NULL, false), "Failed to handle NULL error pointer with parse error.");
|
||||
}
|
||||
|
||||
static void parse_with_opts_should_handle_empty_strings(void)
|
||||
{
|
||||
const char empty_string[] = "";
|
||||
const char *error_pointer = NULL;
|
||||
TEST_ASSERT_NULL(cJSON_ParseWithOpts(empty_string, NULL, false));
|
||||
error_pointer = cJSON_GetErrorPtr();
|
||||
TEST_ASSERT_EQUAL_INT(0, error_pointer - empty_string);
|
||||
TEST_ASSERT_NULL(cJSON_ParseWithOpts(empty_string, &error_pointer, false));
|
||||
TEST_ASSERT_EQUAL_INT(0, error_pointer - empty_string);
|
||||
}
|
||||
|
||||
static void parse_with_opts_should_require_null_if_requested(void)
|
||||
{
|
||||
cJSON *item = cJSON_ParseWithOpts("{}", NULL, true);
|
||||
TEST_ASSERT_NOT_NULL(item);
|
||||
cJSON_Delete(item);
|
||||
item = cJSON_ParseWithOpts("{} \n", NULL, true);
|
||||
TEST_ASSERT_NOT_NULL(item);
|
||||
cJSON_Delete(item);
|
||||
TEST_ASSERT_NULL(cJSON_ParseWithOpts("{}x", NULL, true));
|
||||
}
|
||||
|
||||
static void parse_with_opts_should_return_parse_end(void)
|
||||
{
|
||||
const char json[] = "[] empty array XD";
|
||||
const char *parse_end = NULL;
|
||||
|
||||
cJSON *item = cJSON_ParseWithOpts(json, &parse_end, false);
|
||||
TEST_ASSERT_NOT_NULL(item);
|
||||
TEST_ASSERT_EQUAL_INT(2, parse_end - json);
|
||||
cJSON_Delete(item);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
|
||||
RUN_TEST(parse_with_opts_should_handle_null);
|
||||
RUN_TEST(parse_with_opts_should_handle_empty_strings);
|
||||
RUN_TEST(parse_with_opts_should_require_null_if_requested);
|
||||
RUN_TEST(parse_with_opts_should_return_parse_end);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
100
tests/print_array.c
Normal file
100
tests/print_array.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
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];
|
||||
|
||||
cJSON item[1];
|
||||
|
||||
printbuffer formatted_buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
|
||||
parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
parsebuffer.content = (const unsigned char*)input;
|
||||
parsebuffer.length = strlen(input) + sizeof("");
|
||||
parsebuffer.hooks = global_hooks;
|
||||
|
||||
/* buffer for formatted printing */
|
||||
formatted_buffer.buffer = printed_formatted;
|
||||
formatted_buffer.length = sizeof(printed_formatted);
|
||||
formatted_buffer.offset = 0;
|
||||
formatted_buffer.noalloc = true;
|
||||
formatted_buffer.hooks = global_hooks;
|
||||
|
||||
/* buffer for unformatted printing */
|
||||
unformatted_buffer.buffer = printed_unformatted;
|
||||
unformatted_buffer.length = sizeof(printed_unformatted);
|
||||
unformatted_buffer.offset = 0;
|
||||
unformatted_buffer.noalloc = true;
|
||||
unformatted_buffer.hooks = global_hooks;
|
||||
|
||||
memset(item, 0, sizeof(item));
|
||||
TEST_ASSERT_TRUE_MESSAGE(parse_array(item, &parsebuffer), "Failed to parse array.");
|
||||
|
||||
unformatted_buffer.format = false;
|
||||
TEST_ASSERT_TRUE_MESSAGE(print_array(item, &unformatted_buffer), "Failed to print unformatted string.");
|
||||
TEST_ASSERT_EQUAL_STRING_MESSAGE(input, printed_unformatted, "Unformatted array is not correct.");
|
||||
|
||||
formatted_buffer.format = true;
|
||||
TEST_ASSERT_TRUE_MESSAGE(print_array(item, &formatted_buffer), "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();
|
||||
}
|
||||
105
tests/print_number.c
Normal file
105
tests/print_number.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
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 = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
buffer.buffer = printed;
|
||||
buffer.length = sizeof(printed);
|
||||
buffer.offset = 0;
|
||||
buffer.noalloc = true;
|
||||
buffer.hooks = global_hooks;
|
||||
|
||||
memset(item, 0, sizeof(item));
|
||||
cJSON_SetNumberValue(item, input);
|
||||
|
||||
TEST_ASSERT_TRUE_MESSAGE(print_number(item, &buffer), "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.0);
|
||||
assert_print_number("-32768", -32768.0);
|
||||
assert_print_number("-2147483648", -2147483648.0);
|
||||
}
|
||||
|
||||
static void print_number_should_print_positive_integers(void)
|
||||
{
|
||||
assert_print_number("1", 1.0);
|
||||
assert_print_number("32767", 32767.0);
|
||||
assert_print_number("2147483647", 2147483647.0);
|
||||
}
|
||||
|
||||
static void print_number_should_print_positive_reals(void)
|
||||
{
|
||||
assert_print_number("0.123", 0.123);
|
||||
assert_print_number("1e-09", 10e-10);
|
||||
assert_print_number("1000000000000", 10e11);
|
||||
assert_print_number("1.23e+129", 123e+127);
|
||||
assert_print_number("1.23e-126", 123e-128);
|
||||
assert_print_number("3.1415926535897931", 3.1415926535897931);
|
||||
}
|
||||
|
||||
static void print_number_should_print_negative_reals(void)
|
||||
{
|
||||
assert_print_number("-0.0123", -0.0123);
|
||||
assert_print_number("-1e-09", -10e-10);
|
||||
assert_print_number("-1e+21", -10e20);
|
||||
assert_print_number("-1.23e+129", -123e+127);
|
||||
assert_print_number("-1.23e-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); */
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
101
tests/print_object.c
Normal file
101
tests/print_object.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
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];
|
||||
|
||||
cJSON item[1];
|
||||
|
||||
printbuffer formatted_buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
|
||||
/* buffer for parsing */
|
||||
parsebuffer.content = (const unsigned char*)input;
|
||||
parsebuffer.length = strlen(input) + sizeof("");
|
||||
parsebuffer.hooks = global_hooks;
|
||||
|
||||
/* buffer for formatted printing */
|
||||
formatted_buffer.buffer = printed_formatted;
|
||||
formatted_buffer.length = sizeof(printed_formatted);
|
||||
formatted_buffer.offset = 0;
|
||||
formatted_buffer.noalloc = true;
|
||||
formatted_buffer.hooks = global_hooks;
|
||||
|
||||
/* buffer for unformatted printing */
|
||||
unformatted_buffer.buffer = printed_unformatted;
|
||||
unformatted_buffer.length = sizeof(printed_unformatted);
|
||||
unformatted_buffer.offset = 0;
|
||||
unformatted_buffer.noalloc = true;
|
||||
unformatted_buffer.hooks = global_hooks;
|
||||
|
||||
memset(item, 0, sizeof(item));
|
||||
TEST_ASSERT_TRUE_MESSAGE(parse_object(item, &parsebuffer), "Failed to parse object.");
|
||||
|
||||
unformatted_buffer.format = false;
|
||||
TEST_ASSERT_TRUE_MESSAGE(print_object(item, &unformatted_buffer), "Failed to print unformatted string.");
|
||||
TEST_ASSERT_EQUAL_STRING_MESSAGE(input, printed_unformatted, "Unformatted object is not correct.");
|
||||
|
||||
formatted_buffer.format = true;
|
||||
TEST_ASSERT_TRUE_MESSAGE(print_object(item, &formatted_buffer), "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();
|
||||
}
|
||||
78
tests/print_string.c
Normal file
78
tests/print_string.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
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 = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
buffer.buffer = printed;
|
||||
buffer.length = sizeof(printed);
|
||||
buffer.offset = 0;
|
||||
buffer.noalloc = true;
|
||||
buffer.hooks = global_hooks;
|
||||
|
||||
TEST_ASSERT_TRUE_MESSAGE(print_string_ptr((const unsigned char*)input, &buffer), "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();
|
||||
}
|
||||
107
tests/print_value.c
Normal file
107
tests/print_value.c
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
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];
|
||||
cJSON item[1];
|
||||
printbuffer buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
buffer.buffer = printed;
|
||||
buffer.length = sizeof(printed);
|
||||
buffer.offset = 0;
|
||||
buffer.noalloc = true;
|
||||
buffer.hooks = global_hooks;
|
||||
|
||||
parsebuffer.content = (const unsigned char*)input;
|
||||
parsebuffer.length = strlen(input) + sizeof("");
|
||||
parsebuffer.hooks = global_hooks;
|
||||
|
||||
memset(item, 0, sizeof(item));
|
||||
|
||||
TEST_ASSERT_TRUE_MESSAGE(parse_value(item, &parsebuffer), "Failed to parse value.");
|
||||
|
||||
TEST_ASSERT_TRUE_MESSAGE(print_value(item, &buffer), "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();
|
||||
}
|
||||
30
tests/unity/.gitattributes
vendored
Normal file
30
tests/unity/.gitattributes
vendored
Normal file
@@ -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
|
||||
9
tests/unity/.gitignore
vendored
Normal file
9
tests/unity/.gitignore
vendored
Normal file
@@ -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
|
||||
27
tests/unity/.travis.yml
Normal file
27
tests/unity/.travis.yml
Normal file
@@ -0,0 +1,27 @@
|
||||
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
|
||||
- gem install rubocop
|
||||
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
|
||||
220
tests/unity/README.md
Normal file
220
tests/unity/README.md
Normal file
@@ -0,0 +1,220 @@
|
||||
Unity Test API
|
||||
==============
|
||||
|
||||
[](https://travis-ci.org/ThrowTheSwitch/Unity)
|
||||
__Copyright (c) 2007 - 2017 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).
|
||||
|
||||
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.
|
||||
|
||||
Arrays
|
||||
------
|
||||
|
||||
_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)
|
||||
|
||||
_EACH_EQUAL
|
||||
|
||||
Another array comparison option is to check that EVERY element of an array is equal to a single expected
|
||||
value. You do this by specifying the EACH_EQUAL macro. For example:
|
||||
|
||||
TEST_ASSERT_EACH_EQUAL_INT32(expected, actual, elements)
|
||||
|
||||
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.
|
||||
|
||||
118
tests/unity/auto/colour_prompt.rb
Normal file
118
tests/unity/auto/colour_prompt.rb
Normal file
@@ -0,0 +1,118 @@
|
||||
# ==========================================
|
||||
# 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
|
||||
return unless RUBY_PLATFORM =~ /(win|w)32$/
|
||||
get_std_handle = Win32API.new('kernel32', 'GetStdHandle', ['L'], 'L')
|
||||
@set_console_txt_attrb =
|
||||
Win32API.new('kernel32', 'SetConsoleTextAttribute', %w(L N), 'I')
|
||||
@hout = get_std_handle.call(-11)
|
||||
end
|
||||
|
||||
def change_to(new_colour)
|
||||
if RUBY_PLATFORM =~ /(win|w)32$/
|
||||
@set_console_txt_attrb.call(@hout, 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
|
||||
39
tests/unity/auto/colour_reporter.rb
Normal file
39
tests/unity/auto/colour_reporter.rb
Normal file
@@ -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 !$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
|
||||
Regexp.last_match(1).to_i.zero? ? :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
|
||||
36
tests/unity/auto/generate_config.yml
Normal file
36
tests/unity/auto/generate_config.yml
Normal file
@@ -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
|
||||
//-------------------------------------------
|
||||
308
tests/unity/auto/generate_module.rb
Normal file
308
tests/unity/auto/generate_module.rb
Normal file
@@ -0,0 +1,308 @@
|
||||
# ==========================================
|
||||
# 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 ||= '#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");
|
||||
}
|
||||
'.freeze
|
||||
|
||||
# TEMPLATE_SRC
|
||||
TEMPLATE_SRC ||= '%2$s#include "%1$s.h"
|
||||
'.freeze
|
||||
|
||||
# TEMPLATE_INC
|
||||
TEMPLATE_INC ||= '#ifndef _%3$s_H
|
||||
#define _%3$s_H
|
||||
%2$s
|
||||
|
||||
#endif // _%3$s_H
|
||||
'.freeze
|
||||
|
||||
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 = default_options
|
||||
unless config_file.nil? || 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
|
||||
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
|
||||
triad.select! { |v| v[:inc] == :tst } if pattern == 'test'
|
||||
|
||||
# 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| format(f, module_name) })
|
||||
when :inc then (@options[:includes][:inc] || [])
|
||||
when :tst then (@options[:includes][:tst] || []) | (pattern_traits[:inc].map { |f| format("#{@options[:mock_prefix]}#{f}", module_name) })
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
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|
|
||||
all_files_exist = false unless File.exist?(file[:path])
|
||||
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 { |ff| "#include \"#{ff}\"\n" }.join,
|
||||
file[:name].upcase])
|
||||
end
|
||||
if @options[:update_svn]
|
||||
`svn add \"#{file[:path]}\"`
|
||||
if $!.exitstatus.zero?
|
||||
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] = Regexp.last_match(1)
|
||||
when /^-s\"?(.+)\"?/ then options[:path_src] = Regexp.last_match(1)
|
||||
when /^-i\"?(.+)\"?/ then options[:path_inc] = Regexp.last_match(1)
|
||||
when /^-t\"?(.+)\"?/ then options[:path_tst] = Regexp.last_match(1)
|
||||
when /^-n\"?(.+)\"?/ then options[:naming] = Regexp.last_match(1)
|
||||
when /^-y\"?(.+)\"?/ then options = UnityModuleGenerator.grab_config(Regexp.last_match(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 = [].freeze
|
||||
else
|
||||
raise "ERROR: Unknown option specified '#{arg}'"
|
||||
end
|
||||
end
|
||||
|
||||
unless 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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user