mirror of
https://github.com/DaveGamble/cJSON.git
synced 2023-08-10 21:13:26 +03:00
Compare commits
743 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
cb8693b058 | ||
![]() |
545710e3bf | ||
![]() |
543c28869e | ||
![]() |
766dd9d590 | ||
![]() |
b45f48e600 | ||
![]() |
a6424b85dd | ||
![]() |
3cecc40466 | ||
![]() |
2fc55f6793 | ||
![]() |
c7025b093a | ||
![]() |
e7ebe77ebf | ||
![]() |
61eb84d991 | ||
![]() |
d321fa9e6e | ||
![]() |
203a0dec6f | ||
![]() |
c77a688927 | ||
![]() |
e5dbaee131 | ||
![]() |
189dcde644 | ||
![]() |
b9eff8b02a | ||
![]() |
f50dafc7d0 | ||
![]() |
d348621ca9 | ||
![]() |
744e47353a | ||
![]() |
7795249dd4 | ||
![]() |
324a6ac9a9 | ||
![]() |
6ea4c01e4e | ||
![]() |
9226e4ed8c | ||
![]() |
7b6645794d | ||
![]() |
4100379a04 | ||
![]() |
2f6fc7f0f2 | ||
![]() |
a1e1c208ff | ||
![]() |
9bf4960cd5 | ||
![]() |
488169faca | ||
![]() |
9931900768 | ||
![]() |
d2735278ed | ||
![]() |
8e84db4c4e | ||
![]() |
8e357f825b | ||
![]() |
2e5171d8d6 | ||
![]() |
c8ca78a3cc | ||
![]() |
0b13220419 | ||
![]() |
23f027139e | ||
![]() |
60c3b0a571 | ||
![]() |
857c037ccc | ||
![]() |
3fb9d929e1 | ||
![]() |
cf97c6f066 | ||
![]() |
1ef4deec06 | ||
![]() |
4578d3a9e1 | ||
![]() |
b95a4c56b0 | ||
![]() |
7db005e028 | ||
![]() |
1fc755ac09 | ||
![]() |
a82449fa3e | ||
![]() |
2a6299d904 | ||
![]() |
43f471bff1 | ||
![]() |
7103844037 | ||
![]() |
3442b36672 | ||
![]() |
cb4661cd91 | ||
![]() |
a65abf2f4f | ||
![]() |
3999b12848 | ||
![]() |
39853e5148 | ||
![]() |
ff0dabc72e | ||
![]() |
5d55c6c2ee | ||
![]() |
23e4fbc639 | ||
![]() |
65578af8cc | ||
![]() |
f12cd7b701 | ||
![]() |
97cf1d84e4 | ||
![]() |
983bb2b4d6 | ||
![]() |
4e114c1f31 | ||
![]() |
8943c73345 | ||
![]() |
af56a146fd | ||
![]() |
131966f748 | ||
![]() |
bd7cbe9776 | ||
![]() |
54d6b8016e | ||
![]() |
31c7880fab | ||
![]() |
34e102d0dc | ||
![]() |
4790c3c8f5 | ||
![]() |
6b35f1c5bc | ||
![]() |
3ece4c893c | ||
![]() |
fa28d82f2e | ||
![]() |
1be85ff26d | ||
![]() |
d92c0de7e8 | ||
![]() |
ae7a7a1d0c | ||
![]() |
0586a6c437 | ||
![]() |
9034a9cd0b | ||
![]() |
b0e7195a74 | ||
![]() |
e8077d0150 | ||
![]() |
2955fe5ec4 | ||
![]() |
895b9ad344 | ||
![]() |
f790e17b6c | ||
![]() |
2c97086b97 | ||
![]() |
ada2169183 | ||
![]() |
cc78050ff4 | ||
![]() |
74b2f03837 | ||
![]() |
fa8b454552 | ||
![]() |
2d4ad84192 | ||
![]() |
ea532cdd61 | ||
![]() |
4e3335618f | ||
![]() |
69bc9ccc20 | ||
![]() |
ea3a6dcd69 | ||
![]() |
c06d8264d0 | ||
![]() |
1f970e7db3 | ||
![]() |
98ecc0245a | ||
![]() |
6434d8643e | ||
![]() |
51f6b4c07e | ||
![]() |
d31fdefa38 | ||
![]() |
8badd19b64 | ||
![]() |
500a9db81b | ||
![]() |
95368da1a1 | ||
![]() |
f3b6ad15f0 | ||
![]() |
446ff0d6cc | ||
![]() |
6a848fce32 | ||
![]() |
c64854b26e | ||
![]() |
533ff8a783 | ||
![]() |
4755aea837 | ||
![]() |
4454731775 | ||
![]() |
326f1f5ed5 | ||
![]() |
bb059dc2e1 | ||
![]() |
de99175cd0 | ||
![]() |
a417b183c6 | ||
![]() |
f589f81a42 | ||
![]() |
49a0ede475 | ||
![]() |
73b0e739d0 | ||
![]() |
a0fdf115be | ||
![]() |
6b728982f2 | ||
![]() |
f00060af44 | ||
![]() |
ec8d2f9c2e | ||
![]() |
18b7113b49 | ||
![]() |
18dad60035 | ||
![]() |
66d0a1793f | ||
![]() |
a8dbf6d878 | ||
![]() |
60fb788aa5 | ||
![]() |
bcc91ecbc3 | ||
![]() |
26772a8ef7 | ||
![]() |
dc56e24f7f | ||
![]() |
f31ff795bd | ||
![]() |
e52b212dbf | ||
![]() |
2de7d04aaf | ||
![]() |
ae49da2b61 | ||
![]() |
a3154a36f1 | ||
![]() |
189b51c5da | ||
![]() |
709c3dcf32 | ||
![]() |
c61573f1af | ||
![]() |
20cffa37a8 | ||
![]() |
cf0d87a095 | ||
![]() |
e750194cb1 | ||
![]() |
e13f11ba79 | ||
![]() |
8872b1429a | ||
![]() |
bd1a375028 | ||
![]() |
b6da0d6565 | ||
![]() |
166c814cda | ||
![]() |
c680faea56 | ||
![]() |
2d6db59c7b | ||
![]() |
e6bc5d16e6 | ||
![]() |
2691e142f4 | ||
![]() |
f7f175fdf2 | ||
![]() |
9d766f07a7 | ||
![]() |
85ceadb4b4 | ||
![]() |
110f184d18 | ||
![]() |
c9e8a68b00 | ||
![]() |
16f56300e4 | ||
![]() |
5fe80a94b6 | ||
![]() |
3c8935676a | ||
![]() |
b93fd34044 | ||
![]() |
687b1a2fe1 | ||
![]() |
08d2bc766a | ||
![]() |
465352fb99 | ||
![]() |
19ff92da79 | ||
![]() |
3a4cfa84c3 | ||
![]() |
62bc2e3432 | ||
![]() |
359567fdde | ||
![]() |
0b5a7abf48 | ||
![]() |
93688cbe72 | ||
![]() |
6b249213dd | ||
![]() |
09ebae8149 | ||
![]() |
a43fa56a63 | ||
![]() |
9a970b9ff6 | ||
![]() |
5a52eaddfd | ||
![]() |
add86a6be8 | ||
![]() |
c69134d017 | ||
![]() |
563d861f92 | ||
![]() |
6820448db5 | ||
![]() |
d44b594ab3 | ||
![]() |
f110bd2e58 | ||
![]() |
5cd1dabb30 | ||
![]() |
d606cbbc64 | ||
![]() |
be749d7efa | ||
![]() |
eaec82c3c5 | ||
![]() |
cb1df2f88c | ||
![]() |
2c914c073d | ||
![]() |
4917024741 | ||
![]() |
a3fadd44d1 | ||
![]() |
feb05fb2fd | ||
![]() |
26f38f4782 | ||
![]() |
8e742e4869 | ||
![]() |
543ab5d08a | ||
![]() |
e2162adeed | ||
![]() |
08103f048e | ||
![]() |
ace800e444 | ||
![]() |
00544a4a74 | ||
![]() |
3550a5553d | ||
![]() |
d9fe34bade | ||
![]() |
f25b8448e4 | ||
![]() |
ad2cb5b7ea | ||
![]() |
f32703a7a1 | ||
![]() |
86234db095 | ||
![]() |
af5b4911de | ||
![]() |
787d651e81 | ||
![]() |
1571a3ebe4 | ||
![]() |
0d5ecc11b6 | ||
![]() |
529ec06abb | ||
![]() |
3349978268 | ||
![]() |
cbc05de76f | ||
![]() |
7996a4a2ee | ||
![]() |
ed8fefc9ca | ||
![]() |
e6869c2e03 | ||
![]() |
0e0c463491 | ||
![]() |
2336a0348d | ||
![]() |
5d50f4efe1 | ||
![]() |
8abf110750 | ||
![]() |
d26a42af8d | ||
![]() |
6f264b5d0c | ||
![]() |
5da9edc8b1 | ||
![]() |
22a7d04fa0 | ||
![]() |
a559eac472 | ||
![]() |
d514bb866e | ||
![]() |
27caa364b0 | ||
![]() |
f47271f455 | ||
![]() |
7cc52f6035 | ||
![]() |
b60b5d3744 | ||
![]() |
4d84acf926 | ||
![]() |
28d4410f42 | ||
![]() |
f33fa95f3d | ||
![]() |
984dc85a5f | ||
![]() |
13a2d337a8 | ||
![]() |
17b83e76e9 | ||
![]() |
43754e7833 | ||
![]() |
1e95363638 | ||
![]() |
d7e711c0de | ||
![]() |
f26d8f3175 | ||
![]() |
e7d0c1dc37 | ||
![]() |
5605fa4ad5 | ||
![]() |
cdcd553769 | ||
![]() |
61dd7f1e41 | ||
![]() |
1285e6ac68 | ||
![]() |
b54b81251e | ||
![]() |
c31ee79ad1 | ||
![]() |
a1a1e60cb0 | ||
![]() |
1b21bcd150 | ||
![]() |
77931e7fc0 | ||
![]() |
5865faffa3 | ||
![]() |
f966409b33 | ||
![]() |
de729a1635 | ||
![]() |
55c597c719 | ||
![]() |
2a087843e4 | ||
![]() |
eb7c681a4b | ||
![]() |
0476590a0c | ||
![]() |
da8c48668d | ||
![]() |
11844dd5a6 | ||
![]() |
1f543f0e28 | ||
![]() |
eaa90a6b74 | ||
![]() |
440390a9a5 | ||
![]() |
2718d30a3d | ||
![]() |
043507872e | ||
![]() |
b2afbd3c9f | ||
![]() |
27a4303f87 | ||
![]() |
b5f2e5c540 | ||
![]() |
fa00278f66 | ||
![]() |
8412b1e2cd | ||
![]() |
35907223e1 | ||
![]() |
8a11f8ce17 | ||
![]() |
df1c49dba1 | ||
![]() |
c083421f40 | ||
![]() |
96c33e5abb | ||
![]() |
f437767fa9 | ||
![]() |
c51a19be51 | ||
![]() |
97d7347a6e | ||
![]() |
28328a0b34 | ||
![]() |
9b960fa870 | ||
![]() |
4f9e9dfc30 | ||
![]() |
b7bfe1e91a | ||
![]() |
acf80470f8 | ||
![]() |
afd5d186b7 | ||
![]() |
7456637793 | ||
![]() |
d92754cd30 | ||
![]() |
e4980b65b9 | ||
![]() |
629c354390 | ||
![]() |
1b2236a9a6 | ||
![]() |
1925d1bbe5 | ||
![]() |
76b705576f | ||
![]() |
469a437e2a | ||
![]() |
7e2781a734 | ||
![]() |
f0f3e55d48 | ||
![]() |
2caa884f6a | ||
![]() |
88d66c5da9 | ||
![]() |
954d61e5e7 | ||
![]() |
c6f7f78cbb | ||
![]() |
824e1b2a99 | ||
![]() |
dd980008f7 | ||
![]() |
ecdff7837c | ||
![]() |
a3c2eba991 | ||
![]() |
bf0bc22a11 | ||
![]() |
5baa77f86c | ||
![]() |
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 | ||
![]() |
38b44a298d | ||
![]() |
82295f9e4f | ||
![]() |
00d5e225a6 | ||
![]() |
9ecc96878f | ||
![]() |
3efee9fda8 | ||
![]() |
71a7b64860 | ||
![]() |
ddf268b074 | ||
![]() |
de5df3e56f | ||
![]() |
a167d9e381 | ||
![]() |
b537ca70a3 | ||
![]() |
186cce3ece | ||
![]() |
6c9f76c100 | ||
![]() |
2c9947eec9 | ||
![]() |
9a85c26161 | ||
![]() |
c0088e1ebe | ||
![]() |
8738160e16 | ||
![]() |
eb6dd6ef6b | ||
![]() |
98fb2c9437 | ||
![]() |
1217ca9e9f | ||
![]() |
6e9c6edd91 | ||
![]() |
2d6a2e0133 | ||
![]() |
d9b23039b8 | ||
![]() |
ffb877c94a | ||
![]() |
a01267c0a4 | ||
![]() |
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 | ||
![]() |
06008b0444 |
23
.editorconfig
Normal file
23
.editorconfig
Normal file
@ -0,0 +1,23 @@
|
||||
root = true
|
||||
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
indent_size = unset
|
||||
|
||||
# ignore external repositories and test inputs
|
||||
[tests/{unity,json-patch-tests,inputs}/*]
|
||||
indent_style = unset
|
||||
indent_size = unset
|
||||
end_of_line = unset
|
||||
charset = unset
|
||||
trim_trailing_whitespace = unset
|
||||
insert_final_newline = unset
|
11
.gitattributes
vendored
Normal file
11
.gitattributes
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
* text=auto
|
||||
/tests/inputs/* text eol=lf
|
||||
|
||||
.gitattributes export-ignore
|
||||
.gitignore export-ignore
|
||||
.github export-ignore
|
||||
.editorconfig export-ignore
|
||||
.travis.yml export-ignore
|
||||
|
||||
# Linguist incorrectly identified the headers as C++, manually override this.
|
||||
*.h linguist-language=C
|
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 spaces 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.
|
102
.github/workflows/CI.yml
vendored
Normal file
102
.github/workflows/CI.yml
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'LICENSE'
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'LICENSE'
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
runs-on: ubuntu-latest
|
||||
if: "!contains(github.event.head_commit.message, 'ci skip')"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
mem_check:
|
||||
- ENABLE_VALGRIND
|
||||
- ENABLE_SANITIZERS
|
||||
- NONE_MEM_CHECK
|
||||
compiler:
|
||||
- GCC
|
||||
- CLANG
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: install build dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install clang-14 valgrind
|
||||
- name: build and test
|
||||
shell: bash
|
||||
run: |
|
||||
if [ "${{ matrix.mem_check }}" == "ENABLE_VALGRIND" ]; then
|
||||
EVENT_CMAKE_OPTIONS="-DENABLE_CJSON_UTILS=ON -DENABLE_VALGRIND=ON -DENABLE_SAFE_STACK=ON -DENABLE_SANITIZERS=OFF"
|
||||
elif [ "${{ matrix.mem_check }}" == "ENABLE_SANITIZERS" ]; then
|
||||
EVENT_CMAKE_OPTIONS="-DENABLE_CJSON_UTILS=ON -DENABLE_VALGRIND=OFF -DENABLE_SAFE_STACK=OFF -DENABLE_SANITIZERS=ON"
|
||||
else
|
||||
EVENT_CMAKE_OPTIONS="-DENABLE_CJSON_UTILS=ON -DENABLE_VALGRIND=OFF -DENABLE_SAFE_STACK=OFF -DENABLE_SANITIZERS=OFF"
|
||||
fi
|
||||
if [ "${{ matrix.compiler }}" == "GCC" ]; then
|
||||
export CC=gcc
|
||||
else
|
||||
export CC=clang
|
||||
fi
|
||||
#run build and test
|
||||
JOBS=20
|
||||
export CTEST_PARALLEL_LEVEL=$JOBS
|
||||
export CTEST_OUTPUT_ON_FAILURE=1
|
||||
mkdir -p build
|
||||
cd build
|
||||
echo [cmake]: cmake .. $EVENT_CMAKE_OPTIONS
|
||||
cmake .. $EVENT_CMAKE_OPTIONS || (rm -rf * && cmake .. $EVENT_CMAKE_OPTIONS)
|
||||
cmake --build .
|
||||
make
|
||||
make test
|
||||
|
||||
macos:
|
||||
runs-on: macos-latest
|
||||
if: "!contains(github.event.head_commit.message, 'ci skip')"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
mem_check:
|
||||
- ENABLE_VALGRIND
|
||||
- ENABLE_SANITIZERS
|
||||
- NONE_MEM_CHECK
|
||||
compiler:
|
||||
- GCC
|
||||
- CLANG
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: build and test
|
||||
shell: bash
|
||||
run: |
|
||||
if [ "${{ matrix.mem_check }}" == "ENABLE_VALGRIND" ]; then
|
||||
EVENT_CMAKE_OPTIONS="-DENABLE_CJSON_UTILS=ON -DENABLE_VALGRIND=ON -DENABLE_SAFE_STACK=ON -DENABLE_SANITIZERS=OFF"
|
||||
elif [ "${{ matrix.mem_check }}" == "ENABLE_SANITIZERS" ]; then
|
||||
EVENT_CMAKE_OPTIONS="-DENABLE_CJSON_UTILS=ON -DENABLE_VALGRIND=OFF -DENABLE_SAFE_STACK=OFF -DENABLE_SANITIZERS=ON"
|
||||
else
|
||||
EVENT_CMAKE_OPTIONS="-DENABLE_CJSON_UTILS=ON -DENABLE_VALGRIND=OFF -DENABLE_SAFE_STACK=OFF -DENABLE_SANITIZERS=OFF"
|
||||
fi
|
||||
if [ "${{ matrix.compiler }}" == "GCC" ]; then
|
||||
export CC=gcc
|
||||
else
|
||||
export CC=clang
|
||||
fi
|
||||
#run build and test
|
||||
JOBS=20
|
||||
export CTEST_PARALLEL_LEVEL=$JOBS
|
||||
export CTEST_OUTPUT_ON_FAILURE=1
|
||||
mkdir -p build
|
||||
cd build
|
||||
echo [cmake]: cmake .. $EVENT_CMAKE_OPTIONS
|
||||
cmake .. $EVENT_CMAKE_OPTIONS || (rm -rf * && cmake .. $EVENT_CMAKE_OPTIONS)
|
||||
cmake --build .
|
||||
make
|
||||
make test
|
23
.github/workflows/ci-fuzz.yml
vendored
Normal file
23
.github/workflows/ci-fuzz.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
name: CIFuzz
|
||||
on: [pull_request]
|
||||
jobs:
|
||||
Fuzzing:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Build Fuzzers
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
|
||||
with:
|
||||
oss-fuzz-project-name: 'cjson'
|
||||
dry-run: false
|
||||
- name: Run Fuzzers
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
|
||||
with:
|
||||
oss-fuzz-project-name: 'cjson'
|
||||
fuzz-seconds: 600
|
||||
dry-run: false
|
||||
- name: Upload Crash
|
||||
uses: actions/upload-artifact@v1
|
||||
if: failure()
|
||||
with:
|
||||
name: artifacts
|
||||
path: ./out/artifacts
|
12
.gitignore
vendored
12
.gitignore
vendored
@ -6,5 +6,15 @@ test
|
||||
*.swp
|
||||
*.patch
|
||||
tags
|
||||
*.dylib
|
||||
*.dylib*
|
||||
build/
|
||||
cJSON_test
|
||||
cJSON_test_utils
|
||||
libcjson.so.*
|
||||
libcjson_utils.so.*
|
||||
*.orig
|
||||
.vscode
|
||||
.idea
|
||||
cmake-build-debug
|
||||
*.lst
|
||||
*.lss
|
||||
|
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_SAFE_STACK="${VALGRIND}" -DENABLE_SANITIZERS="${SANITIZERS}"
|
||||
- make
|
||||
- make test CTEST_OUTPUT_ON_FAILURE=On
|
447
CHANGELOG.md
Normal file
447
CHANGELOG.md
Normal file
@ -0,0 +1,447 @@
|
||||
1.7.16 (Jul 5, 2023)
|
||||
======
|
||||
Features:
|
||||
------
|
||||
* Add an option for ENABLE_CJSON_VERSION_SO in CMakeLists.txt, see #534
|
||||
* Add cmake_policy to CMakeLists.txt, see #163
|
||||
* Add cJSON_SetBoolValue, see #639
|
||||
* Add meson documentation, see #761
|
||||
|
||||
Fixes:
|
||||
------
|
||||
* Fix memory leak in merge_patch, see #611
|
||||
* Fix conflicting target names 'uninstall', see #617
|
||||
* Bump cmake version to 3.0 and use new version syntax, see #587
|
||||
* Print int without decimal places, see #630
|
||||
* Fix 'cjson_utils-static' target not exist, see #625
|
||||
* Add allocate check for replace_item_in_object, see #675
|
||||
* Fix a null pointer crash in cJSON_ReplaceItemViaPointer, see #726
|
||||
|
||||
1.7.15 (Aug 25, 2021)
|
||||
======
|
||||
Fixes:
|
||||
------
|
||||
* Fix potential core dumped for strrchr, see [#546](https://github.com/DaveGamble/cJSON/pull/546)
|
||||
* Fix null pointer crash in cJSON_CreateXxArray, see [#538](https://github.com/DaveGamble/cJSON/pull/538)
|
||||
* Fix several null pointer problems on allocation failure, see [#526](https://github.com/DaveGamble/cJSON/pull/526)
|
||||
* Fix a possible dereference of null pointer, see [#519](https://github.com/DaveGamble/cJSON/pull/519)
|
||||
* Fix windows build failure about defining nan, see [#518](https://github.com/DaveGamble/cJSON/pull/518)
|
||||
|
||||
1.7.14 (Sep 3, 2020)
|
||||
======
|
||||
Fixes:
|
||||
------
|
||||
* optimize the way to find tail node, see [#503](https://github.com/DaveGamble/cJSON/pull/503)
|
||||
* Fix WError error on macosx because NAN is a float. Thanks @sappo, see [#484](https://github.com/DaveGamble/cJSON/pull/484)
|
||||
* Fix some bugs in detach and replace. Thanks @miaoerduo, see [#456](https://github.com/DaveGamble/cJSON/pull/456)
|
||||
|
||||
1.7.13 (Apr 2, 2020)
|
||||
======
|
||||
Features:
|
||||
---------
|
||||
* add new API of cJSON_ParseWithLength without breaking changes. Thanks @caglarivriz, see [#358](https://github.com/DaveGamble/cJSON/pull/358)
|
||||
* add new API of cJSON_GetNumberValue. Thanks @Intuition, see[#385](https://github.com/DaveGamble/cJSON/pull/385)
|
||||
* add uninstall target function for CMake. See [#402](https://github.com/DaveGamble/cJSON/pull/402)
|
||||
* Improve performance of adding item to array. Thanks @xiaomianhehe, see [#430](https://github.com/DaveGamble/cJSON/pull/430), [#448](https://github.com/DaveGamble/cJSON/pull/448)
|
||||
* add new API of cJSON_SetValuestring, for changing the valuestring safely. See [#451](https://github.com/DaveGamble/cJSON/pull/451)
|
||||
* add return value for cJSON_AddItemTo... and cJSON_ReplaceItem... (check if the operation successful). See [#453](https://github.com/DaveGamble/cJSON/pull/453)
|
||||
|
||||
Fixes:
|
||||
------
|
||||
* Fix clang -Wfloat-equal warning. Thanks @paulmalovanyi, see [#368](https://github.com/DaveGamble/cJSON/pull/368)
|
||||
* Fix make failed in mac os. See [#405](https://github.com/DaveGamble/cJSON/pull/405)
|
||||
* Fix memory leak in cJSONUtils_FindPointerFromObjectTo. Thanks @andywolk for reporting, see [#414](https://github.com/DaveGamble/cJSON/issues/414)
|
||||
* Fix bug in encode_string_as_pointer. Thanks @AIChangJiang for reporting, see [#439](https://github.com/DaveGamble/cJSON/issues/439)
|
||||
|
||||
1.7.12 (May 17, 2019)
|
||||
======
|
||||
Fixes:
|
||||
------
|
||||
* Fix infinite loop in `cJSON_Minify` (potential Denial of Service). Thanks @Alanscut for reporting, see [#354](https://github.com/DaveGamble/cJSON/issues/354)
|
||||
* Fix link error for Visual Studio. Thanks @tan-wei, see [#352](https://github.com/DaveGamble/cJSON/pull/352).
|
||||
* Undefine `true` and `false` for `cJSON_Utils` before redefining them. Thanks @raiden00pl, see [#347](https://github.com/DaveGamble/cJSON/pull/347).
|
||||
|
||||
1.7.11 (Apr 15, 2019)
|
||||
======
|
||||
Fixes:
|
||||
------
|
||||
* Fix a bug where cJSON_Minify could overflow it's buffer, both reading and writing. This is a security issue, see [#338](https://github.com/DaveGamble/cJSON/issues/338). Big thanks @bigric3 for reporting.
|
||||
* Unset `true` and `false` macros before setting them if they exist. See [#339](https://github.com/DaveGamble/cJSON/issues/339), thanks @raiden00pl for reporting
|
||||
|
||||
1.7.10 (Dec 21, 2018)
|
||||
======
|
||||
Fixes:
|
||||
------
|
||||
* Fix package config file for `libcjson`. Thanks @shiluotang for reporting [#321](https://github.com/DaveGamble/cJSON/issues/321)
|
||||
* Correctly split lists in `cJSON_Utils`'s merge sort. Thanks @andysCaplin for the fix [#322](https://github.com/DaveGamble/cJSON/issues/322)
|
||||
|
||||
1.7.9 (Dec 16, 2018)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix a bug where `cJSON_GetObjectItemCaseSensitive` would pass a nullpointer to `strcmp` when called on an array, see [#315](https://github.com/DaveGamble/cJSON/issues/315). Thanks @yuweol for reporting.
|
||||
* Fix error in `cJSON_Utils` where the case sensitivity was not respected, see [#317](https://github.com/DaveGamble/cJSON/pull/317). Thanks @yuta-oxo for fixing.
|
||||
* Fix some warnings detected by the Visual Studio Static Analyzer, see [#307](https://github.com/DaveGamble/cJSON/pull/307). Thanks @bnason-nf
|
||||
|
||||
1.7.8 (Sep 22, 2018)
|
||||
======
|
||||
Fixes:
|
||||
------
|
||||
* cJSON now works with the `__stdcall` calling convention on Windows, see [#295](https://github.com/DaveGamble/cJSON/pull/295), thanks @zhindes for contributing
|
||||
|
||||
1.7.7 (May 22, 2018)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix a memory leak when realloc fails, see [#267](https://github.com/DaveGamble/cJSON/issues/267), thanks @AlfieDeng for reporting
|
||||
* Fix a typo in the header file, see [#266](https://github.com/DaveGamble/cJSON/pull/266), thanks @zhaozhixu
|
||||
|
||||
1.7.6 (Apr 13, 2018)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Add `SONAME` to the ELF files built by the Makefile, see [#252](https://github.com/DaveGamble/cJSON/issues/252), thanks @YanhaoMo for reporting
|
||||
* Add include guards and `extern "C"` to `cJSON_Utils.h`, see [#256](https://github.com/DaveGamble/cJSON/issues/256), thanks @daschfg for reporting
|
||||
|
||||
Other changes:
|
||||
* Mark the Makefile as deprecated in the README.
|
||||
|
||||
1.7.5 (Mar 23, 2018)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix a bug in the JSON Patch implementation of `cJSON Utils`, see [#251](https://github.com/DaveGamble/cJSON/pull/251), thanks @bobkocisko.
|
||||
|
||||
1.7.4 (Mar 3, 2018)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix potential use after free if the `string` parameter to `cJSON_AddItemToObject` is an alias of the `string` property of the object that is added,see [#248](https://github.com/DaveGamble/cJSON/issues/248). Thanks @hhallen for reporting.
|
||||
|
||||
1.7.3 (Feb 8, 2018)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix potential double free, thanks @projectgus for reporting [#241](https://github.com/DaveGamble/cJSON/issues/241)
|
||||
|
||||
1.7.2 (Feb 6, 2018)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix the use of GNUInstallDirs variables and the pkgconfig file. Thanks @zeerd for reporting [#240](https://github.com/DaveGamble/cJSON/pull/240)
|
||||
|
||||
1.7.1 (Jan 10, 2018)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fixed an Off-By-One error that could lead to an out of bounds write. Thanks @liuyunbin for reporting [#230](https://github.com/DaveGamble/cJSON/issues/230)
|
||||
* Fixed two errors with buffered printing. Thanks @liuyunbin for reporting [#230](https://github.com/DaveGamble/cJSON/issues/230)
|
||||
|
||||
1.7.0 (Dec 31, 2017)
|
||||
=====
|
||||
Features:
|
||||
---------
|
||||
* Large rewrite of the documentation, see [#215](https://github.com/DaveGamble/cJSON/pull/215)
|
||||
* Added the `cJSON_GetStringValue` function
|
||||
* Added the `cJSON_CreateStringReference` function
|
||||
* Added the `cJSON_CreateArrayReference` function
|
||||
* Added the `cJSON_CreateObjectReference` function
|
||||
* The `cJSON_Add...ToObject` macros are now functions that return a pointer to the added item, see [#226](https://github.com/DaveGamble/cJSON/pull/226)
|
||||
|
||||
Fixes:
|
||||
------
|
||||
* Fix a problem with `GNUInstallDirs` in the CMakeLists.txt, thanks @yangfl, see [#210](https://github.com/DaveGamble/cJSON/pull/210)
|
||||
* Fix linking the tests when building as static library, see [#213](https://github.com/DaveGamble/cJSON/issues/213)
|
||||
* New overrides for the CMake option `BUILD_SHARED_LIBS`, see [#207](https://github.com/DaveGamble/cJSON/issues/207)
|
||||
|
||||
Other Changes:
|
||||
--------------
|
||||
* Readme: Explain how to include cJSON, see [#211](https://github.com/DaveGamble/cJSON/pull/211)
|
||||
* Removed some trailing spaces in the code, thanks @yangfl, see [#212](https://github.com/DaveGamble/cJSON/pull/212)
|
||||
* Updated [Unity](https://github.com/ThrowTheSwitch/Unity) and [json-patch-tests](https://github.com/json-patch/json-patch-tests)
|
||||
|
||||
1.6.0 (Oct 9, 2017)
|
||||
=====
|
||||
Features:
|
||||
---------
|
||||
* You can now build cJSON as both shared and static library at once with CMake using `-DBUILD_SHARED_AND_STATIC_LIBS=On`, see [#178](https://github.com/DaveGamble/cJSON/issues/178)
|
||||
* UTF-8 byte order marks are now ignored, see [#184](https://github.com/DaveGamble/cJSON/issues/184)
|
||||
* Locales can now be disabled with the option `-DENABLE_LOCALES=Off`, see [#202](https://github.com/DaveGamble/cJSON/issues/202), thanks @Casperinous
|
||||
* Better support for MSVC and Visual Studio
|
||||
|
||||
Other Changes:
|
||||
--------------
|
||||
* Add the new warnings `-Wswitch-enum`, `-Wused-but-makred-unused`, `-Wmissing-variable-declarations`, `-Wunused-macro`
|
||||
* More number printing tests.
|
||||
* Continuous integration testing with AppVeyor (semi automatic at this point), thanks @simon-p-r
|
||||
|
||||
1.5.9 (Sep 8, 2017)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Set the global error pointer even if `return_parse_end` is passed to `cJSON_ParseWithOpts`, see [#200](https://github.com/DaveGamble/cJSON/pull/200), thanks @rmallins
|
||||
|
||||
1.5.8 (Aug 21, 2017)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix `make test` in the Makefile, thanks @YanhaoMo for reporting this [#195](https://github.com/DaveGamble/cJSON/issues/195)
|
||||
|
||||
1.5.7 (Jul 13, 2017)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix a bug where realloc failing would return a pointer to an invalid memory address. This is a security issue as it could potentially be used by an attacker to write to arbitrary memory addresses, see [#189](https://github.com/DaveGamble/cJSON/issues/189), fixed in [954d61e](https://github.com/DaveGamble/cJSON/commit/954d61e5e7cb9dc6c480fc28ac1cdceca07dd5bd), big thanks @timothyjohncarney for reporting this issue
|
||||
* Fix a spelling mistake in the AFL fuzzer dictionary, see [#185](https://github.com/DaveGamble/cJSON/pull/185), thanks @jwilk
|
||||
|
||||
1.5.6 (Jun 28, 2017)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Make cJSON a lot more tolerant about passing NULL pointers to its functions, it should now fail safely instead of dereferencing the pointer, see [#183](https://github.com/DaveGamble/cJSON/pull/183). Thanks @msichal for reporting [#182](https://github.com/DaveGamble/cJSON/issues/182)
|
||||
|
||||
1.5.5 (Jun 15, 2017)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix pointers to nested arrays in cJSON_Utils, see [9abe](https://github.com/DaveGamble/cJSON/commit/9abe75e072050f34732a7169740989a082b65134)
|
||||
* Fix an error with case sensitivity handling in cJSON_Utils, see [b9cc911](https://github.com/DaveGamble/cJSON/commit/b9cc911831b0b3e1bb72f142389428e59f882b38)
|
||||
* Fix cJSON_Compare for arrays that are prefixes of the other and objects that are a subset of the other, see [03ba72f](https://github.com/DaveGamble/cJSON/commit/03ba72faec115160d1f3aea5582d9b6af5d3e473) and [#180](https://github.com/DaveGamble/cJSON/issues/180), thanks @zhengqb for reporting
|
||||
|
||||
1.5.4 (Jun 5, 2017)
|
||||
======
|
||||
Fixes:
|
||||
------
|
||||
* Fix build with GCC 7.1.1 and optimization level `-O2`, see [bfbd8fe](https://github.com/DaveGamble/cJSON/commit/bfbd8fe0d85f1dd21e508748fc10fc4c27cc51be)
|
||||
|
||||
Other Changes:
|
||||
--------------
|
||||
* Update [Unity](https://github.com/ThrowTheSwitch/Unity) to 3b69beaa58efc41bbbef70a32a46893cae02719d
|
||||
|
||||
1.5.3 (May 23, 2017)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix `cJSON_ReplaceItemInObject` not keeping the name of an item, see [#174](https://github.com/DaveGamble/cJSON/issues/174)
|
||||
|
||||
1.5.2 (May 10, 2017)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix a reading buffer overflow in `parse_string`, see [a167d9e](https://github.com/DaveGamble/cJSON/commit/a167d9e381e5c84bc03de4e261757b031c0c690d)
|
||||
* Fix compiling with -Wcomma, see [186cce3](https://github.com/DaveGamble/cJSON/commit/186cce3ece6ce6dfcb58ac8b2a63f7846c3493ad)
|
||||
* Remove leftover attribute from tests, see [b537ca7](https://github.com/DaveGamble/cJSON/commit/b537ca70a35680db66f1f5b8b437f7114daa699a)
|
||||
|
||||
1.5.1 (May 6, 2017)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Add gcc version guard to the Makefile, see [#164](https://github.com/DaveGamble/cJSON/pull/164), thanks @juvasquezg
|
||||
* Fix incorrect free in `cJSON_Utils` if custom memory allocator is used, see [#166](https://github.com/DaveGamble/cJSON/pull/166), thanks @prefetchnta
|
||||
|
||||
1.5.0 (May 2, 2017)
|
||||
=====
|
||||
Features:
|
||||
* cJSON finally prints numbers without losing precision, see [#153](https://github.com/DaveGamble/cJSON/pull/153), thanks @DeboraG
|
||||
* `cJSON_Compare` recursively checks if two cJSON items contain the same values, see [#148](https://github.com/DaveGamble/cJSON/pull/148)
|
||||
* Provide case sensitive versions of every function where it matters, see [#158](https://github.com/DaveGamble/cJSON/pull/158) and [#159](https://github.com/DaveGamble/cJSON/pull/159)
|
||||
* Added `cJSON_ReplaceItemViaPointer` and `cJSON_DetachItemViaPointer`
|
||||
* Added `cJSON_free` and `cJSON_malloc` that expose the internal configured memory allocators. see [02a05ee](https://github.com/DaveGamble/cJSON/commit/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, see [#139](https://github.com/DaveGamble/cJSON/pull/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 (Apr 19, 2017)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix `cJSONUtils_ApplyPatches`, it was completely broken and apparently nobody noticed (or at least reported it), see [075a06f](https://github.com/DaveGamble/cJSON/commit/075a06f40bdc4f836c7dd7cad690d253a57cfc50)
|
||||
* Fix inconsistent prototype for `cJSON_GetObjectItemCaseSensitive`, see [51d3df6](https://github.com/DaveGamble/cJSON/commit/51d3df6c9f7b56b860c8fb24abe7bab255cd4fa9), thanks @PawelWMS
|
||||
|
||||
1.4.6 (Apr 9, 2017)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Several corrections in the README
|
||||
* Making clear that `valueint` should not be written to
|
||||
* Fix overflow detection in `ensure`, see [2683d4d](https://github.com/DaveGamble/cJSON/commit/2683d4d9873df87c4bdccc523903ddd78d1ad250)
|
||||
* Fix a potential null pointer dereference in cJSON_Utils, see [795c3ac](https://github.com/DaveGamble/cJSON/commit/795c3acabed25c9672006b2c0f40be8845064827)
|
||||
* Replace incorrect `sizeof('\0')` with `sizeof("")`, see [84237ff](https://github.com/DaveGamble/cJSON/commit/84237ff48e69825c94261c624eb0376d0c328139)
|
||||
* Add caveats section to the README, see [50b3c30](https://github.com/DaveGamble/cJSON/commit/50b3c30dfa89830f8f477ce33713500740ac3b79)
|
||||
* Make cJSON locale independent, see [#146](https://github.com/DaveGamble/cJSON/pull/146), Thanks @peterh for reporting
|
||||
* Fix compiling without CMake with MSVC, see [#147](https://github.com/DaveGamble/cJSON/pull/147), Thanks @dertuxmalwieder for reporting
|
||||
|
||||
1.4.5 (Mar 28, 2017)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix bug in `cJSON_SetNumberHelper`, thanks @mmkeeper, see [#138](https://github.com/DaveGamble/cJSON/issues/138) and [ef34500](https://github.com/DaveGamble/cJSON/commit/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 (Mar 24, 2017)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix a theoretical integer overflow, (not sure if it is possible on actual hardware), see [e58f7ec](https://github.com/DaveGamble/cJSON/commit/e58f7ec027d00b7cdcbf63e518c1b5268b29b3da)
|
||||
* Fix an off by one error, see [cc84a44](https://github.com/DaveGamble/cJSON/commit/cc84a446be20cc283bafdc4d94c050ba1111ac02), thanks @gatzka
|
||||
* Double check the offset of the print buffer in `ensure`, see [1934059](https://github.com/DaveGamble/cJSON/commit/1934059554b9a0971e00f79e96900f422cfdd114)
|
||||
|
||||
Improvements:
|
||||
* Add a note in the header about required buffer size when using `cJSON_PrintPreallocated`, see [4bfb8800](https://github.com/DaveGamble/cJSON/commit/4bfb88009342fb568295a7f6dc4b7fee74fbf022)
|
||||
|
||||
1.4.3 (Mar 19, 2017)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix compilation of the tests on 32 bit PowerPC and potentially other systems, see [4ec6e76](https://github.com/DaveGamble/cJSON/commit/4ec6e76ea2eec16f54b58e8c95b4c734e59481e4)
|
||||
* Fix compilation with old GCC compilers (4.3+ were tested), see [227d33](https://github.com/DaveGamble/cJSON/commit/227d3398d6b967879761ebe02c1b63dbd6ea6e0d), [466eb8e](https://github.com/DaveGamble/cJSON/commit/466eb8e3f8a65080f2b3ca4a79ab7b72bd539dba), see also [#126](https://github.com/DaveGamble/cJSON/issues/126)
|
||||
|
||||
1.4.2 (Mar 16, 2017)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix minimum required cmake version, see [30e1e7a](https://github.com/DaveGamble/cJSON/commit/30e1e7af7c63db9b55f5a3cda977a6c032f0b132)
|
||||
* Fix detection of supported compiler flags, see [76e5296](https://github.com/DaveGamble/cJSON/commit/76e5296d0d05ceb3018a9901639e0e171b44a557)
|
||||
* Run `cJSON_test` and `cJSON_test_utils` along with unity tests, see [c597601](https://github.com/DaveGamble/cJSON/commit/c597601cf151a757dcf800548f18034d4ddfe2cb)
|
||||
|
||||
1.4.1 (Mar 16, 2017)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Make `print_number` abort with a failure in out of memory situations, see [cf1842](https://github.com/DaveGamble/cJSON/commit/cf1842dc6f64c49451a022308b4415e4d468be0a)
|
||||
|
||||
1.4.0 (Mar 4, 2017)
|
||||
=====
|
||||
Features
|
||||
--------
|
||||
* Functions to check the type of an item, see [#120](https://github.com/DaveGamble/cJSON/pull/120)
|
||||
* Use dllexport on windows and fvisibility on Unix systems for public functions, see [#116](https://github.com/DaveGamble/cJSON/pull/116), thanks @mjerris
|
||||
* Remove trailing zeroes from printed numbers, see [#123](https://github.com/DaveGamble/cJSON/pull/123)
|
||||
* Expose the internal boolean type `cJSON_bool` in the header, see [2d3520e](https://github.com/DaveGamble/cJSON/commit/2d3520e0b9d0eb870e8886e8a21c571eeddbb310)
|
||||
|
||||
Fixes
|
||||
* Fix handling of NULL pointers in `cJSON_ArrayForEach`, see [b47d0e3](https://github.com/DaveGamble/cJSON/commit/b47d0e34caaef298edfb7bd09a72cfff21d231ff)
|
||||
* Make it compile with GCC 7 (fix -Wimplicit-fallthrough warning), see [9d07917](https://github.com/DaveGamble/cJSON/commit/9d07917feb1b613544a7513d19233d4c851ad7ad)
|
||||
|
||||
Other Improvements
|
||||
* internally use realloc if available ([#110](https://github.com/DaveGamble/cJSON/pull/110))
|
||||
* builtin support for fuzzing with [afl](http://lcamtuf.coredump.cx/afl/) ([#111](https://github.com/DaveGamble/cJSON/pull/111))
|
||||
* unit tests for the print functions ([#112](https://github.com/DaveGamble/cJSON/pull/112))
|
||||
* Always use buffered printing ([#113](https://github.com/DaveGamble/cJSON/pull/113))
|
||||
* simplify the print functions ([#114](https://github.com/DaveGamble/cJSON/pull/114))
|
||||
* Add the compiler flags `-Wdouble-conversion`, `-Wparentheses` and `-Wcomma` ([#122](https://github.com/DaveGamble/cJSON/pull/122))
|
||||
|
||||
1.3.2 (Mar 1, 2017)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Don't build the unity library if testing is disabled, see [#121](https://github.com/DaveGamble/cJSON/pull/121). Thanks @ffontaine
|
||||
|
||||
1.3.1 (Feb 27, 2017)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Bugfix release that fixes an out of bounds read, see [#118](https://github.com/DaveGamble/cJSON/pull/118). This shouldn't have any security implications.
|
||||
|
||||
1.3.0 (Feb 17, 2017)
|
||||
=====
|
||||
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`, see [#108](https://github.com/DaveGamble/cJSON/pull/108)
|
||||
|
||||
Fixes:
|
||||
------
|
||||
* runtime checks for a lot of potential integer overflows
|
||||
* fix incorrect return in cJSON_PrintBuffered [cf9d57d](https://github.com/DaveGamble/cJSON/commit/cf9d57d56cac21fc59465b8d26cf29bf6d2a87b3)
|
||||
* fix several potential issues found by [Coverity](https://scan.coverity.com/projects/cjson)
|
||||
* fix potentially undefined behavior when assigning big numbers to `valueint` ([41e2837](https://github.com/DaveGamble/cJSON/commit/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 ([87f7727](https://github.com/DaveGamble/cJSON/commit/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](https://github.com/DaveGamble/cJSON/issues/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 ([0747669](https://github.com/DaveGamble/cJSON/commit/074766997246481dfc72bfa78f07898a2716473f))
|
||||
* Use goto-fail in several parser functions ([#100](https://github.com/DaveGamble/cJSON/pull/100))
|
||||
* Rewrite/restructure all of the parsing functions to be easier to understand and have less code paths doing the same as another. ([#109](https://github.com/DaveGamble/cJSON/pull/109))
|
||||
* Simplify the buffer allocation strategy to always doubling the needed amount ([9f6fa94](https://github.com/DaveGamble/cJSON/commit/9f6fa94c91a87b71e4c6868dbf2ce431a48517b0))
|
||||
* Combined `cJSON_AddItemToObject` and `cJSON_AddItemToObjectCS` to one function ([cf862d](https://github.com/DaveGamble/cJSON/commit/cf862d0fed7f9407e4b046d78d3d8050d2080d12))
|
||||
|
||||
Other changes
|
||||
-------------
|
||||
* Prevent the usage of incompatible C and header versions via preprocessor directive ([123bb1](https://github.com/DaveGamble/cJSON/commit/123bb1af7bfae41d805337fef4b41045ef6c7d25))
|
||||
* Let CMake automatically detect compiler flags
|
||||
* Add new compiler flags (`-Wundef`, `-Wswitch-default`, `-Wconversion`, `-fstack-protector-strong`) ([#98](https://github.com/DaveGamble/cJSON/pull/98))
|
||||
* Change internal sizes from `int` to `size_t` ([ecd5678](https://github.com/DaveGamble/cJSON/commit/ecd5678527a6bc422da694e5be9e9979878fe6a0))
|
||||
* Change internal strings from `char*` to `unsigned char*` ([28b9ba4](https://github.com/DaveGamble/cJSON/commit/28b9ba4334e0f7309e867e874a31f395c0ac2474))
|
||||
* Add `const` in more places
|
||||
|
||||
1.2.1 (Jan 31, 2017)
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fixes a potential null pointer dereference in cJSON_Utils, discovered using clang's static analyzer by @bnason-nf, see [#96](https://github.com/DaveGamble/cJSON/issues/96)
|
||||
|
||||
1.2.0 (Jan 9, 2017)
|
||||
=====
|
||||
Features:
|
||||
---------
|
||||
* Add a new type of cJSON item for raw JSON and support printing it. Thanks @loigu, see [#65](https://github.com/DaveGamble/cJSON/pull/65), [#90](https://github.com/DaveGamble/cJSON/pull/90)
|
||||
|
||||
Fixes:
|
||||
------
|
||||
* Compiler warning if const is casted away, Thanks @gatzka, see [#83](https://github.com/DaveGamble/cJSON/pull/83)
|
||||
* Fix compile error with strict-overflow on PowerPC, see [#85](https://github.com/DaveGamble/cJSON/issues/85)
|
||||
* Fix typo in the README, thanks @MicroJoe, see [#88](https://github.com/DaveGamble/cJSON/pull/88)
|
||||
* Add compile flag for compatibility with C++ compilers
|
||||
|
||||
1.1.0 (Dec 6, 2016)
|
||||
=====
|
||||
* Add a function `cJSON_PrintPreallocated` to print to a preallocated buffer, thanks @ChisholmKyle, see [#72](https://github.com/DaveGamble/cJSON/pull/72)
|
||||
* More compiler warnings when using Clang or GCC, thanks @gatzka, see [#75](https://github.com/DaveGamble/cJSON/pull/75), [#78](https://github.com/DaveGamble/cJSON/pull/78)
|
||||
* fixed a memory leak in `cJSON_Duplicate`, thanks @alperakcan, see [#81](https://github.com/DaveGamble/cJSON/pull/81)
|
||||
* fix the `ENABLE_CUSTOM_COMPILER_FLAGS` cmake option
|
||||
|
||||
1.0.2 (Nov 25, 2016)
|
||||
=====
|
||||
* Rename internal boolean type, see [#71](https://github.com/DaveGamble/cJSON/issues/71).
|
||||
|
||||
1.0.1 (Nov 20, 2016)
|
||||
=====
|
||||
Small bugfix release.
|
||||
* Fixes a bug with the use of the cJSON structs type in cJSON_Utils, see [d47339e](https://github.com/DaveGamble/cJSON/commit/d47339e2740360e6e0994527d5e4752007480f3a)
|
||||
* improve code readability
|
||||
* initialize all variables
|
||||
|
||||
1.0.0 (Nov 17, 2016)
|
||||
=====
|
||||
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.
|
275
CMakeLists.txt
275
CMakeLists.txt
@ -1,29 +1,113 @@
|
||||
set(CMAKE_LEGACY_CYGWIN_WIN32 0)
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
project(cJSON
|
||||
VERSION 1.7.16
|
||||
LANGUAGES C)
|
||||
|
||||
cmake_policy(SET CMP0054 NEW) # set CMP0054 policy
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
project(cJSON C)
|
||||
|
||||
set(PROJECT_VERSION_MAJOR 1)
|
||||
set(PROJECT_VERSION_MINOR 1)
|
||||
set(PROJECT_VERSION_PATCH 0)
|
||||
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 "Enables custom compiler flags for Clang and GCC" 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 -Wshadow -Winit-self -Wcast-align -Wformat=2 -Wmissing-prototypes -Wstrict-overflow=2")
|
||||
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")
|
||||
# Disable warning c4001 - nonstandard extension 'single line comment' was used
|
||||
# Define _CRT_SECURE_NO_WARNINGS to disable deprecation warnings for "insecure" C library functions
|
||||
list(APPEND custom_compiler_flags
|
||||
/GS
|
||||
/Za
|
||||
/sdl
|
||||
/W4
|
||||
/wd4001
|
||||
/D_CRT_SECURE_NO_WARNINGS
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#variables for pkg-config
|
||||
set(prefix "${CMAKE_INSTALL_PREFIX}")
|
||||
set(libdir "${CMAKE_INSTALL_LIBDIR}")
|
||||
set(version "${PROJECT_VERSION}")
|
||||
set(includedir "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
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-cast-overflow
|
||||
-fsanitize-address-use-after-scope
|
||||
-fsanitize=integer
|
||||
-01
|
||||
-fno-sanitize-recover
|
||||
)
|
||||
endif()
|
||||
|
||||
option(ENABLE_SAFE_STACK "Enables the SafeStack instrumentation pass by the Code Pointer Integrity Project" OFF)
|
||||
if (ENABLE_SAFE_STACK)
|
||||
if (ENABLE_SANITIZERS)
|
||||
message(FATAL_ERROR "ENABLE_SAFE_STACK cannot be used in combination with ENABLE_SANITIZERS")
|
||||
endif()
|
||||
list(APPEND custom_compiler_flags
|
||||
-fsanitize=safe-stack
|
||||
)
|
||||
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}")
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
|
||||
option(ENABLE_TARGET_EXPORT "Enable exporting of CMake targets. Disable when it causes problems!" ON)
|
||||
@ -34,26 +118,61 @@ 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)
|
||||
option(CJSON_OVERRIDE_BUILD_SHARED_LIBS "Override BUILD_SHARED_LIBS with CJSON_BUILD_SHARED_LIBS" OFF)
|
||||
option(CJSON_BUILD_SHARED_LIBS "Overrides BUILD_SHARED_LIBS if CJSON_OVERRIDE_BUILD_SHARED_LIBS is enabled" ON)
|
||||
option(ENABLE_CJSON_VERSION_SO "Enables cJSON so version" ON)
|
||||
|
||||
if ((CJSON_OVERRIDE_BUILD_SHARED_LIBS AND CJSON_BUILD_SHARED_LIBS) OR ((NOT CJSON_OVERRIDE_BUILD_SHARED_LIBS) AND BUILD_SHARED_LIBS))
|
||||
set(CJSON_LIBRARY_TYPE SHARED)
|
||||
else()
|
||||
set(CJSON_LIBRARY_TYPE STATIC)
|
||||
endif()
|
||||
|
||||
|
||||
if (NOT BUILD_SHARED_AND_STATIC_LIBS)
|
||||
add_library("${CJSON_LIB}" "${CJSON_LIBRARY_TYPE}" "${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}")
|
||||
install(FILES cJSON.h DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}/cjson")
|
||||
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson.pc" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/pkgconfig")
|
||||
install(TARGETS "${CJSON_LIB}"
|
||||
EXPORT "${CJSON_LIB}"
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}"
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}"
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}"
|
||||
INCLUDES DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}"
|
||||
)
|
||||
if (BUILD_SHARED_AND_STATIC_LIBS)
|
||||
install(TARGETS "${CJSON_LIB}-static"
|
||||
EXPORT "${CJSON_LIB}"
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}"
|
||||
INCLUDES DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}"
|
||||
)
|
||||
endif()
|
||||
if(ENABLE_TARGET_EXPORT)
|
||||
# export library information for CMake projects
|
||||
install(EXPORT "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cJSON")
|
||||
install(EXPORT "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cJSON")
|
||||
endif()
|
||||
|
||||
set_target_properties("${CJSON_LIB}"
|
||||
PROPERTIES
|
||||
SOVERSION "${CJSON_VERSION_SO}"
|
||||
VERSION "${PROJECT_VERSION}")
|
||||
if(ENABLE_CJSON_VERSION_SO)
|
||||
set_target_properties("${CJSON_LIB}"
|
||||
PROPERTIES
|
||||
SOVERSION "${CJSON_VERSION_SO}"
|
||||
VERSION "${PROJECT_VERSION}")
|
||||
endif()
|
||||
|
||||
#cJSON_Utils
|
||||
option(ENABLE_CJSON_UTILS "Enable building the cJSON_Utils library." OFF)
|
||||
@ -63,48 +182,102 @@ 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}")
|
||||
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/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}")
|
||||
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)
|
||||
# export library information for CMake projects
|
||||
install(EXPORT "${CJSON_UTILS_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cJSON")
|
||||
if (NOT BUILD_SHARED_AND_STATIC_LIBS)
|
||||
add_library("${CJSON_UTILS_LIB}" "${CJSON_LIBRARY_TYPE}" "${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()
|
||||
|
||||
set_target_properties("${CJSON_UTILS_LIB}"
|
||||
PROPERTIES
|
||||
SOVERSION "${CJSON_UTILS_VERSION_SO}"
|
||||
VERSION "${PROJECT_VERSION}")
|
||||
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}"
|
||||
EXPORT "${CJSON_UTILS_LIB}"
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}"
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}"
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}"
|
||||
INCLUDES DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}"
|
||||
)
|
||||
if (BUILD_SHARED_AND_STATIC_LIBS)
|
||||
install(TARGETS "${CJSON_UTILS_LIB}-static"
|
||||
EXPORT "${CJSON_UTILS_LIB}"
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}"
|
||||
INCLUDES DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}"
|
||||
)
|
||||
endif()
|
||||
install(FILES cJSON_Utils.h DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}/cjson")
|
||||
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson_utils.pc" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/pkgconfig")
|
||||
if(ENABLE_TARGET_EXPORT)
|
||||
# export library information for CMake projects
|
||||
install(EXPORT "${CJSON_UTILS_LIB}" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cJSON")
|
||||
endif()
|
||||
|
||||
if(ENABLE_CJSON_VERSION_SO)
|
||||
set_target_properties("${CJSON_UTILS_LIB}"
|
||||
PROPERTIES
|
||||
SOVERSION "${CJSON_UTILS_VERSION_SO}"
|
||||
VERSION "${PROJECT_VERSION}")
|
||||
endif()
|
||||
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
|
||||
install(FILES ${PROJECT_BINARY_DIR}/cJSONConfig.cmake
|
||||
${PROJECT_BINARY_DIR}/cJSONConfigVersion.cmake
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cJSON")
|
||||
if(ENABLE_TARGET_EXPORT)
|
||||
# Install package config files
|
||||
install(FILES ${PROJECT_BINARY_DIR}/cJSONConfig.cmake
|
||||
${PROJECT_BINARY_DIR}/cJSONConfigVersion.cmake
|
||||
DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cJSON")
|
||||
endif()
|
||||
|
||||
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()
|
||||
|
||||
#Create the uninstall target
|
||||
option(ENABLE_CJSON_UNINSTALL "Enable creating uninstall target" ON)
|
||||
if(ENABLE_CJSON_UNINSTALL)
|
||||
add_custom_target(uninstall "${CMAKE_COMMAND}" -P
|
||||
"${PROJECT_SOURCE_DIR}/library_config/uninstall.cmake")
|
||||
endif()
|
||||
|
||||
# Enable the use of locales
|
||||
option(ENABLE_LOCALES "Enable the use of locales" ON)
|
||||
if(ENABLE_LOCALES)
|
||||
add_definitions(-DENABLE_LOCALES)
|
||||
endif()
|
||||
|
||||
add_subdirectory(tests)
|
||||
add_subdirectory(fuzzing)
|
||||
|
@ -1,30 +1,91 @@
|
||||
Contributors
|
||||
============
|
||||
|
||||
Original Author:
|
||||
- [Dave Gamble](https://github.com/DaveGamble)
|
||||
|
||||
Current Maintainer:
|
||||
- [Max Bruckner](https://github.com/FSMaxB)
|
||||
- [Alan Wang](https://github.com/Alanscut)
|
||||
|
||||
Contributors:
|
||||
* [Ajay Bhargav](https://github.com/ajaybhargav)
|
||||
* [AlexanderVasiljev](https://github.com/AlexanderVasiljev)
|
||||
* [Alper Akcan](https://github.com/alperakcan)
|
||||
* [Andrew Tang](https://github.com/singku)
|
||||
* [Andy](https://github.com/mlh0101)
|
||||
* [Anton Sergeev](https://github.com/anton-sergeev)
|
||||
* [Benbuck Nason](https://github.com/bnason-nf)
|
||||
* [Bernt Johan Damslora](https://github.com/bjda)
|
||||
* [Bob Kocisko](https://github.com/bobkocisko)
|
||||
* [Christian Schulze](https://github.com/ChristianSch)
|
||||
* [Dave Gamble](https://github.com/DaveGamble)
|
||||
* [Casperinous](https://github.com/Casperinous)
|
||||
* [ChenYuan](https://github.com/zjuchenyuan)
|
||||
* [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)
|
||||
* [Donough Liu](https://github.com/ldm0)
|
||||
* [Erez Oxman](https://github.com/erez-o)
|
||||
* Eswar Yaganti
|
||||
* [Evan Todd](https://github.com/etodd)
|
||||
* [Fabrice Fontaine](https://github.com/ffontaine)
|
||||
* Ian Mobley
|
||||
* Irwan Djadjadi
|
||||
* [hopper-vul](https://github.com/hopper-vul)
|
||||
* [HuKeping](https://github.com/HuKeping)
|
||||
* [IvanVoid](https://github.com/npi3pak)
|
||||
* [Jakub Wilk](https://github.com/jwilk)
|
||||
* [Jiri Zouhar](https://github.com/loigu)
|
||||
* [Jonathan Fether](https://github.com/jfether)
|
||||
* [Joshua Arulsamy](https://github.com/jarulsamy)
|
||||
* [Julian Ste](https://github.com/julian-st)
|
||||
* [Julián Vásquez](https://github.com/juvasquezg)
|
||||
* [Junbo Zheng](https://github.com/Junbo-Zheng)
|
||||
* [Kevin Branigan](https://github.com/kbranigan)
|
||||
* [Kevin Sapper](https://github.com/sappo)
|
||||
* [Kyle Chisholm](https://github.com/ChisholmKyle)
|
||||
* [Linus Wallgren](https://github.com/ecksun)
|
||||
* [Max Bruckner](https://github.com/FSMaxB)
|
||||
* [MaxBrandtner](https://github.com/MaxBrandtner)
|
||||
* [Mateusz Szafoni](https://github.com/raiden00pl)
|
||||
* Mike Pontillo
|
||||
* [miaoerduo](https://github.com/miaoerduo)
|
||||
* [mohawk2](https://github.com/mohawk2)
|
||||
* [Mike Jerris](https://github.com/mjerris)
|
||||
* [Mike Robinson](https://github.com/mhrobinson)
|
||||
* [Moorthy](https://github.com/moorthy-bs)
|
||||
* [myd7349](https://github.com/myd7349)
|
||||
* [NancyLi1013](https://github.com/NancyLi1013)
|
||||
* Paulo Antonio Alvarez
|
||||
* [Paweł Malowany](https://github.com/PawelMalowany)
|
||||
* [Pawel Winogrodzki](https://github.com/PawelWMS)
|
||||
* [prefetchnta](https://github.com/prefetchnta)
|
||||
* [Rafael Leal Dias](https://github.com/rafaeldias)
|
||||
* [Randy](https://github.com/randy408)
|
||||
* [raiden00pl](https://github.com/raiden00pl)
|
||||
* [Robin Mallinson](https://github.com/rmallins)
|
||||
* [Rod Vagg](https://github.com/rvagg)
|
||||
* [Roland Meertens](https://github.com/rmeertens)
|
||||
* [Romain Porte](https://github.com/MicroJoe)
|
||||
* [SANJEEV BA](https://github.com/basanjeev)
|
||||
* [Sang-Heon Jeon](https://github.com/lntuition)
|
||||
* [Sayan Bandyopadhyay](https://github.com/saynb)
|
||||
* [Simon Sobisch](https://github.com/GitMensch)
|
||||
* [Simon Ricaldone](https://github.com/simon-p-r)
|
||||
* [Stoian Ivanov](https://github.com/sdrsdr)
|
||||
* [SuperH-0630](https://github.com/SuperH-0630)
|
||||
* [Square789](https://github.com/Square789)
|
||||
* [Stephan Gatzka](https://github.com/gatzka)
|
||||
* [Tony Langhammer](https://github.com/BigBrainAFK)
|
||||
* [Vemake](https://github.com/vemakereporter)
|
||||
* [Wei Tan](https://github.com/tan-wei)
|
||||
* [Weston Schmidt](https://github.com/schmidtw)
|
||||
* [xiaomianhehe](https://github.com/xiaomianhehe)
|
||||
* [yangfl](https://github.com/yangfl)
|
||||
* [yuta-oxo](https://github.com/yuta-oxo)
|
||||
* [Zach Hindes](https://github.com/zhindes)
|
||||
* [Zhao Zhixu](https://github.com/zhaozhixu)
|
||||
* [10km](https://github.com/10km)
|
||||
|
||||
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)
|
||||
|
||||
Also thanks to all the people who reported bugs and suggested new features.
|
||||
|
38
LICENSE
38
LICENSE
@ -1,20 +1,20 @@
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
|
47
Makefile
47
Makefile
@ -3,17 +3,18 @@ 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
|
||||
UTILS_TEST_SRC = cJSON.c cJSON_Utils.c test_utils.c
|
||||
|
||||
LDLIBS = -lm
|
||||
|
||||
LIBVERSION = 1.1.0
|
||||
LIBVERSION = 1.7.16
|
||||
CJSON_SOVERSION = 1
|
||||
UTILS_SOVERSION = 1
|
||||
|
||||
CJSON_SO_LDFLAG=-Wl,-soname=$(CJSON_LIBNAME).so.$(CJSON_SOVERSION)
|
||||
UTILS_SO_LDFLAG=-Wl,-soname=$(UTILS_LIBNAME).so.$(UTILS_SOVERSION)
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
INCLUDE_PATH ?= include/cjson
|
||||
LIBRARY_PATH ?= lib
|
||||
@ -23,7 +24,20 @@ INSTALL_LIBRARY_PATH = $(DESTDIR)$(PREFIX)/$(LIBRARY_PATH)
|
||||
|
||||
INSTALL ?= cp -a
|
||||
|
||||
R_CFLAGS = -fPIC -std=c89 -pedantic -Wall -Werror -Wstrict-prototypes -Wwrite-strings -Wshadow -Winit-self -Wcast-align -Wformat=2 -Wmissing-prototypes -Wstrict-overflow=2 $(CFLAGS)
|
||||
CC = gcc -std=c89
|
||||
|
||||
# validate gcc version for use fstack-protector-strong
|
||||
MIN_GCC_VERSION = "4.9"
|
||||
GCC_VERSION := "`$(CC) -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
|
||||
|
||||
PIC_FLAGS = -fPIC
|
||||
R_CFLAGS = $(PIC_FLAGS) -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')
|
||||
|
||||
@ -34,6 +48,8 @@ STATIC = a
|
||||
## create dynamic (shared) library on Darwin (base OS for MacOSX and IOS)
|
||||
ifeq (Darwin, $(uname))
|
||||
SHARED = dylib
|
||||
CJSON_SO_LDFLAG = ""
|
||||
UTILS_SO_LDFLAG = ""
|
||||
endif
|
||||
|
||||
#cJSON library names
|
||||
@ -58,11 +74,10 @@ shared: $(CJSON_SHARED) $(UTILS_SHARED)
|
||||
|
||||
static: $(CJSON_STATIC) $(UTILS_STATIC)
|
||||
|
||||
tests: $(CJSON_TEST) $(UTILS_TEST)
|
||||
tests: $(CJSON_TEST)
|
||||
|
||||
test: tests
|
||||
./$(CJSON_TEST)
|
||||
./$(UTILS_TEST)
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(R_CFLAGS) $<
|
||||
@ -71,9 +86,6 @@ test: tests
|
||||
#cJSON
|
||||
$(CJSON_TEST): $(CJSON_TEST_SRC) cJSON.h
|
||||
$(CC) $(R_CFLAGS) $(CJSON_TEST_SRC) -o $@ $(LDLIBS) -I.
|
||||
#cJSON_Utils
|
||||
$(UTILS_TEST): $(UTILS_TEST_SRC) cJSON.h cJSON_Utils.h
|
||||
$(CC) $(R_CFLAGS) $(UTILS_TEST_SRC) -o $@ $(LDLIBS) -I.
|
||||
|
||||
#static libraries
|
||||
#cJSON
|
||||
@ -86,16 +98,16 @@ $(UTILS_STATIC): $(UTILS_OBJ)
|
||||
#shared libraries .so.1.0.0
|
||||
#cJSON
|
||||
$(CJSON_SHARED_VERSION): $(CJSON_OBJ)
|
||||
$(CC) -shared -o $@ $< $(LDFLAGS)
|
||||
$(CC) -shared -o $@ $< $(CJSON_SO_LDFLAG) $(LDFLAGS)
|
||||
#cJSON_Utils
|
||||
$(UTILS_SHARED_VERSION): $(UTILS_OBJ)
|
||||
$(CC) -shared -o $@ $< $(LDFLAGS)
|
||||
$(CC) -shared -o $@ $< $(CJSON_OBJ) $(UTILS_SO_LDFLAG) $(LDFLAGS)
|
||||
|
||||
#objects
|
||||
#cJSON
|
||||
$(CJSON_OBJ): cJSON.c cJSON.h
|
||||
#cJSON_Utils
|
||||
$(UTILS_OBJ): cJSON_Utils.c cJSON_Utils.h
|
||||
$(UTILS_OBJ): cJSON_Utils.c cJSON_Utils.h cJSON.h
|
||||
|
||||
|
||||
#links .so -> .so.1 -> .so.1.0.0
|
||||
@ -129,9 +141,8 @@ uninstall-cjson: uninstall-utils
|
||||
$(RM) $(INSTALL_LIBRARY_PATH)/$(CJSON_SHARED)
|
||||
$(RM) $(INSTALL_LIBRARY_PATH)/$(CJSON_SHARED_VERSION)
|
||||
$(RM) $(INSTALL_LIBRARY_PATH)/$(CJSON_SHARED_SO)
|
||||
rmdir $(INSTALL_LIBRARY_PATH)
|
||||
$(RM) $(INSTALL_INCLUDE_PATH)/cJSON.h
|
||||
rmdir $(INSTALL_INCLUDE_PATH)
|
||||
|
||||
#cJSON_Utils
|
||||
uninstall-utils:
|
||||
$(RM) $(INSTALL_LIBRARY_PATH)/$(UTILS_SHARED)
|
||||
@ -139,10 +150,14 @@ uninstall-utils:
|
||||
$(RM) $(INSTALL_LIBRARY_PATH)/$(UTILS_SHARED_SO)
|
||||
$(RM) $(INSTALL_INCLUDE_PATH)/cJSON_Utils.h
|
||||
|
||||
uninstall: uninstall-utils uninstall-cjson
|
||||
remove-dir:
|
||||
$(if $(wildcard $(INSTALL_LIBRARY_PATH)/*.*),,rmdir $(INSTALL_LIBRARY_PATH))
|
||||
$(if $(wildcard $(INSTALL_INCLUDE_PATH)/*.*),,rmdir $(INSTALL_INCLUDE_PATH))
|
||||
|
||||
uninstall: uninstall-utils uninstall-cjson remove-dir
|
||||
|
||||
clean:
|
||||
$(RM) $(CJSON_OBJ) $(UTILS_OBJ) #delete object files
|
||||
$(RM) $(CJSON_SHARED) $(CJSON_SHARED_VERSION) $(CJSON_SHARED_SO) $(CJSON_STATIC) #delete cJSON
|
||||
$(RM) $(UTILS_SHARED) $(UTILS_SHARED_VERSION) $(UTILS_SHARED_SO) $(UTILS_STATIC) #delete cJSON_Utils
|
||||
$(RM) $(CJSON_TEST) $(UTILS_TEST) #delete tests
|
||||
$(RM) $(CJSON_TEST) #delete test
|
||||
|
648
README.md
648
README.md
@ -7,13 +7,38 @@ Ultralightweight JSON parser in ANSI C.
|
||||
* [Usage](#usage)
|
||||
* [Welcome to cJSON](#welcome-to-cjson)
|
||||
* [Building](#building)
|
||||
* [Some JSON](#some-json)
|
||||
* [Here's the structure](#heres-the-structure)
|
||||
* [Copying the source](#copying-the-source)
|
||||
* [CMake](#cmake)
|
||||
* [Makefile](#makefile)
|
||||
* [Meson](#meson)
|
||||
* [Vcpkg](#Vcpkg)
|
||||
* [Including cJSON](#including-cjson)
|
||||
* [Data Structure](#data-structure)
|
||||
* [Working with the data structure](#working-with-the-data-structure)
|
||||
* [Basic types](#basic-types)
|
||||
* [Arrays](#arrays)
|
||||
* [Objects](#objects)
|
||||
* [Parsing JSON](#parsing-json)
|
||||
* [Printing JSON](#printing-json)
|
||||
* [Example](#example)
|
||||
* [Printing](#printing)
|
||||
* [Parsing](#parsing)
|
||||
* [Caveats](#caveats)
|
||||
* [Zero Character](#zero-character)
|
||||
* [Character Encoding](#character-encoding)
|
||||
* [C Standard](#c-standard)
|
||||
* [Floating Point Numbers](#floating-point-numbers)
|
||||
* [Deep Nesting Of Arrays And Objects](#deep-nesting-of-arrays-and-objects)
|
||||
* [Thread Safety](#thread-safety)
|
||||
* [Case Sensitivity](#case-sensitivity)
|
||||
* [Duplicate Object Members](#duplicate-object-members)
|
||||
* [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
|
||||
@ -57,12 +82,14 @@ philosophy as JSON itself. Simple, dumb, out of the way.
|
||||
There are several ways to incorporate cJSON into your project.
|
||||
|
||||
#### copying the source
|
||||
|
||||
Because the entire library is only one C file and one header file, you can just copy `cJSON.h` and `cJSON.c` to your projects source and start using it.
|
||||
|
||||
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,294 +106,485 @@ 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)
|
||||
* `-DENABLE_SAFE_STACK`: Enable the [SafeStack](https://clang.llvm.org/docs/SafeStack.html) instrumentation pass. Currently only works with the Clang compiler. (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.
|
||||
* `-DENABLE_LOCALES=On`: Enable the usage of localeconv method. ( on by default )
|
||||
* `-DCJSON_OVERRIDE_BUILD_SHARED_LIBS=On`: Enable overriding the value of `BUILD_SHARED_LIBS` with `-DCJSON_BUILD_SHARED_LIBS`.
|
||||
* `-DENABLE_CJSON_VERSION_SO`: Enable cJSON so version. ( on by default )
|
||||
|
||||
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.
|
||||
On Windows CMake is usually used to create a Visual Studio solution file by running it inside the Developer Command Prompt for Visual Studio, for exact steps follow the official documentation from CMake and Microsoft and use the online search engine of your choice. The descriptions of the the options above still generally apply, although not all of them work on Windows.
|
||||
|
||||
#### Makefile
|
||||
If you don't have CMake available, but still have 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.
|
||||
**NOTE:** This Method is deprecated. Use CMake if at all possible. Makefile support is limited to fixing bugs.
|
||||
|
||||
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 (not the full test suite).
|
||||
|
||||
```
|
||||
make all
|
||||
```
|
||||
|
||||
If you want, you can install the compiled library to your system using `make install`. By default it will install the headers in `/usr/local/include/cjson` and the libraries in `/usr/local/lib`. But you can change this behavior by setting the `PREFIX` and `DESTDIR` variables: `make PREFIX=/usr DESTDIR=temp install`.
|
||||
If you want, you can install the compiled library to your system using `make install`. By default it will install the headers in `/usr/local/include/cjson` and the libraries in `/usr/local/lib`. But you can change this behavior by setting the `PREFIX` and `DESTDIR` variables: `make PREFIX=/usr DESTDIR=temp install`. And uninstall them with: `make PREFIX=/usr DESTDIR=temp uninstall`.
|
||||
|
||||
### Some JSON:
|
||||
#### Meson
|
||||
|
||||
```json
|
||||
To make cjson work in a project using meson, the libcjson dependency has to be included:
|
||||
|
||||
```meson
|
||||
project('c-json-example', 'c')
|
||||
|
||||
cjson = dependency('libcjson')
|
||||
|
||||
example = executable(
|
||||
'example',
|
||||
'example.c',
|
||||
dependencies: [cjson],
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
#### Vcpkg
|
||||
|
||||
You can download and install cJSON using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
|
||||
```
|
||||
git clone https://github.com/Microsoft/vcpkg.git
|
||||
cd vcpkg
|
||||
./bootstrap-vcpkg.sh
|
||||
./vcpkg integrate install
|
||||
vcpkg install cjson
|
||||
```
|
||||
|
||||
The cJSON port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
|
||||
|
||||
### Including cJSON
|
||||
|
||||
If you installed it via CMake or the Makefile, you can include cJSON like this:
|
||||
|
||||
```c
|
||||
#include <cjson/cJSON.h>
|
||||
```
|
||||
|
||||
### Data Structure
|
||||
|
||||
cJSON represents JSON data using the `cJSON` struct data type:
|
||||
|
||||
```c
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON
|
||||
{
|
||||
"name": "Jack (\"Bee\") Nimble",
|
||||
"format": {
|
||||
"type": "rect",
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"interlace": false,
|
||||
"frame rate": 24
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Assume that you got this from a file, a webserver, or magic JSON elves, whatever,
|
||||
you have a `char *` to it. Everything is a `cJSON` struct.
|
||||
Get it parsed:
|
||||
|
||||
```c
|
||||
cJSON * root = cJSON_Parse(my_json_string);
|
||||
```
|
||||
|
||||
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;
|
||||
```
|
||||
|
||||
Want to change the framerate?
|
||||
|
||||
```c
|
||||
cJSON_GetObjectItem(format, "frame rate")->valueint = 25;
|
||||
```
|
||||
|
||||
Back to disk?
|
||||
|
||||
```c
|
||||
char *rendered = cJSON_Print(root);
|
||||
```
|
||||
|
||||
Finished? Delete the root (this takes care of everything else).
|
||||
|
||||
```c
|
||||
cJSON_Delete(root);
|
||||
```
|
||||
|
||||
That's AUTO mode. If you're going to use Auto mode, you really ought to check pointers
|
||||
before you dereference them. If you want to see how you'd build this struct in code?
|
||||
|
||||
```c
|
||||
cJSON *root;
|
||||
cJSON *fmt;
|
||||
root = cJSON_CreateObject();
|
||||
cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble"));
|
||||
cJSON_AddItemToObject(root, "format", fmt = cJSON_CreateObject());
|
||||
cJSON_AddStringToObject(fmt, "type", "rect");
|
||||
cJSON_AddNumberToObject(fmt, "width", 1920);
|
||||
cJSON_AddNumberToObject(fmt, "height", 1080);
|
||||
cJSON_AddFalseToObject (fmt, "interlace");
|
||||
cJSON_AddNumberToObject(fmt, "frame rate", 24);
|
||||
```
|
||||
|
||||
Hopefully we can agree that's not a lot of code? There's no overhead, no unnecessary setup.
|
||||
Look at `test.c` for a bunch of nice examples, mostly all ripped off the [json.org](http://json.org) site, and
|
||||
a few from elsewhere.
|
||||
|
||||
What about manual mode? First up you need some detail.
|
||||
Let's cover how the `cJSON` objects represent the JSON data.
|
||||
cJSON doesn't distinguish arrays from objects in handling; just type.
|
||||
Each `cJSON` has, potentially, a child, siblings, value, a name.
|
||||
|
||||
* The `root` object has: *Object* Type and a Child
|
||||
* The Child has name "name", with value "Jack ("Bee") Nimble", and a sibling:
|
||||
* Sibling has type *Object*, name "format", and a child.
|
||||
* That child has type *String*, name "type", value "rect", and a sibling:
|
||||
* Sibling has type *Number*, name "width", value 1920, and a sibling:
|
||||
* Sibling has type *Number*, name "height", value 1080, and a sibling:
|
||||
* Sibling has type *False*, name "interlace", and a sibling:
|
||||
* Sibling has type *Number*, name "frame rate", value 24
|
||||
|
||||
### Here's the structure:
|
||||
|
||||
```c
|
||||
typedef struct cJSON {
|
||||
struct cJSON *next,*prev;
|
||||
struct cJSON *next;
|
||||
struct cJSON *prev;
|
||||
struct cJSON *child;
|
||||
|
||||
int type;
|
||||
|
||||
char *valuestring;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
double valuedouble;
|
||||
|
||||
char *string;
|
||||
} cJSON;
|
||||
```
|
||||
|
||||
By default all values are 0 unless set by virtue of being meaningful.
|
||||
An item of this type represents a JSON value. The type is stored in `type` as a bit-flag (**this means that you cannot find out the type by just comparing the value of `type`**).
|
||||
|
||||
`next`/`prev` is a doubly linked list of siblings. `next` takes you to your sibling,
|
||||
`prev` takes you back from your sibling to you.
|
||||
Only objects and arrays have a `child`, and it's the head of the doubly linked list.
|
||||
A `child` entry will have `prev == 0`, but next potentially points on. The last sibling has `next == 0`.
|
||||
The type expresses *Null*/*True*/*False*/*Number*/*String*/*Array*/*Object*, all of which are `#defined` in
|
||||
`cJSON.h`.
|
||||
To check the type of an item, use the corresponding `cJSON_Is...` function. It does a `NULL` check followed by a type check and returns a boolean value if the item is of this type.
|
||||
|
||||
A *Number* has `valueint` and `valuedouble`. If you're expecting an `int`, read `valueint`, if not read
|
||||
`valuedouble`.
|
||||
The type can be one of the following:
|
||||
|
||||
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`.
|
||||
`string` is the JSON name for the 'variable name' if you will.
|
||||
* `cJSON_Invalid` (check with `cJSON_IsInvalid`): Represents an invalid item that doesn't contain any value. You automatically have this type if you set the item to all zero bytes.
|
||||
* `cJSON_False` (check with `cJSON_IsFalse`): Represents a `false` boolean value. You can also check for boolean values in general with `cJSON_IsBool`.
|
||||
* `cJSON_True` (check with `cJSON_IsTrue`): Represents a `true` boolean value. You can also check for boolean values in general with `cJSON_IsBool`.
|
||||
* `cJSON_NULL` (check with `cJSON_IsNull`): Represents a `null` value.
|
||||
* `cJSON_Number` (check with `cJSON_IsNumber`): Represents a number value. The value is stored as a double in `valuedouble` and also in `valueint`. If the number is outside of the range of an integer, `INT_MAX` or `INT_MIN` are used for `valueint`.
|
||||
* `cJSON_String` (check with `cJSON_IsString`): Represents a string value. It is stored in the form of a zero terminated string in `valuestring`.
|
||||
* `cJSON_Array` (check with `cJSON_IsArray`): Represent an array value. This is implemented by pointing `child` to a linked list of `cJSON` items that represent the values in the array. The elements are linked together using `next` and `prev`, where the first element has `prev.next == NULL` and the last element `next == NULL`.
|
||||
* `cJSON_Object` (check with `cJSON_IsObject`): Represents an object value. Objects are stored same way as an array, the only difference is that the items in the object store their keys in `string`.
|
||||
* `cJSON_Raw` (check with `cJSON_IsRaw`): Represents any kind of JSON that is stored as a zero terminated array of characters in `valuestring`. This can be used, for example, to avoid printing the same static JSON over and over again to save performance. cJSON will never create this type when parsing. Also note that cJSON doesn't check if it is valid JSON.
|
||||
|
||||
Now you can trivially walk the lists, recursively, and parse as you please.
|
||||
You can invoke `cJSON_Parse` to get cJSON to parse for you, and then you can take
|
||||
the root object, and traverse the structure (which is, formally, an N-tree),
|
||||
and tokenise as you please. If you wanted to build a callback style parser, this is how
|
||||
you'd do it (just an example, since these things are very specific):
|
||||
Additionally there are the following two flags:
|
||||
|
||||
* `cJSON_IsReference`: Specifies that the item that `child` points to and/or `valuestring` is not owned by this item, it is only a reference. So `cJSON_Delete` and other functions will only deallocate this item, not its `child`/`valuestring`.
|
||||
* `cJSON_StringIsConst`: This means that `string` points to a constant string. This means that `cJSON_Delete` and other functions will not try to deallocate `string`.
|
||||
|
||||
### Working with the data structure
|
||||
|
||||
For every value type there is a `cJSON_Create...` function that can be used to create an item of that type.
|
||||
All of these will allocate a `cJSON` struct that can later be deleted with `cJSON_Delete`.
|
||||
Note that you have to delete them at some point, otherwise you will get a memory leak.
|
||||
**Important**: If you have added an item to an array or an object already, you **mustn't** delete it with `cJSON_Delete`. Adding it to an array or object transfers its ownership so that when that array or object is deleted,
|
||||
it gets deleted as well. You also could use `cJSON_SetValuestring` to change a `cJSON_String`'s `valuestring`, and you needn't to free the previous `valuestring` manually.
|
||||
|
||||
#### Basic types
|
||||
|
||||
* **null** is created with `cJSON_CreateNull`
|
||||
* **booleans** are created with `cJSON_CreateTrue`, `cJSON_CreateFalse` or `cJSON_CreateBool`
|
||||
* **numbers** are created with `cJSON_CreateNumber`. This will set both `valuedouble` and `valueint`. If the number is outside of the range of an integer, `INT_MAX` or `INT_MIN` are used for `valueint`
|
||||
* **strings** are created with `cJSON_CreateString` (copies the string) or with `cJSON_CreateStringReference` (directly points to the string. This means that `valuestring` won't be deleted by `cJSON_Delete` and you are responsible for its lifetime, useful for constants)
|
||||
|
||||
#### Arrays
|
||||
|
||||
You can create an empty array with `cJSON_CreateArray`. `cJSON_CreateArrayReference` can be used to create an array that doesn't "own" its content, so its content doesn't get deleted by `cJSON_Delete`.
|
||||
|
||||
To add items to an array, use `cJSON_AddItemToArray` to append items to the end.
|
||||
Using `cJSON_AddItemReferenceToArray` an element can be added as a reference to another item, array or string. This means that `cJSON_Delete` will not delete that items `child` or `valuestring` properties, so no double frees are occurring if they are already used elsewhere.
|
||||
To insert items in the middle, use `cJSON_InsertItemInArray`. It will insert an item at the given 0 based index and shift all the existing items to the right.
|
||||
|
||||
If you want to take an item out of an array at a given index and continue using it, use `cJSON_DetachItemFromArray`, it will return the detached item, so be sure to assign it to a pointer, otherwise you will have a memory leak.
|
||||
|
||||
Deleting items is done with `cJSON_DeleteItemFromArray`. It works like `cJSON_DetachItemFromArray`, but deletes the detached item via `cJSON_Delete`.
|
||||
|
||||
You can also replace an item in an array in place. Either with `cJSON_ReplaceItemInArray` using an index or with `cJSON_ReplaceItemViaPointer` given a pointer to an element. `cJSON_ReplaceItemViaPointer` will return `0` if it fails. What this does internally is to detach the old item, delete it and insert the new item in its place.
|
||||
|
||||
To get the size of an array, use `cJSON_GetArraySize`. Use `cJSON_GetArrayItem` to get an element at a given index.
|
||||
|
||||
Because an array is stored as a linked list, iterating it via index is inefficient (`O(n²)`), so you can iterate over an array using the `cJSON_ArrayForEach` macro in `O(n)` time complexity.
|
||||
|
||||
#### Objects
|
||||
|
||||
You can create an empty object with `cJSON_CreateObject`. `cJSON_CreateObjectReference` can be used to create an object that doesn't "own" its content, so its content doesn't get deleted by `cJSON_Delete`.
|
||||
|
||||
To add items to an object, use `cJSON_AddItemToObject`. Use `cJSON_AddItemToObjectCS` to add an item to an object with a name that is a constant or reference (key of the item, `string` in the `cJSON` struct), so that it doesn't get freed by `cJSON_Delete`.
|
||||
Using `cJSON_AddItemReferenceToArray` an element can be added as a reference to another object, array or string. This means that `cJSON_Delete` will not delete that items `child` or `valuestring` properties, so no double frees are occurring if they are already used elsewhere.
|
||||
|
||||
If you want to take an item out of an object, use `cJSON_DetachItemFromObjectCaseSensitive`, it will return the detached item, so be sure to assign it to a pointer, otherwise you will have a memory leak.
|
||||
|
||||
Deleting items is done with `cJSON_DeleteItemFromObjectCaseSensitive`. It works like `cJSON_DetachItemFromObjectCaseSensitive` followed by `cJSON_Delete`.
|
||||
|
||||
You can also replace an item in an object in place. Either with `cJSON_ReplaceItemInObjectCaseSensitive` using a key or with `cJSON_ReplaceItemViaPointer` given a pointer to an element. `cJSON_ReplaceItemViaPointer` will return `0` if it fails. What this does internally is to detach the old item, delete it and insert the new item in its place.
|
||||
|
||||
To get the size of an object, you can use `cJSON_GetArraySize`, this works because internally objects are stored as arrays.
|
||||
|
||||
If you want to access an item in an object, use `cJSON_GetObjectItemCaseSensitive`.
|
||||
|
||||
To iterate over an object, you can use the `cJSON_ArrayForEach` macro the same way as for arrays.
|
||||
|
||||
cJSON also provides convenient helper functions for quickly creating a new item and adding it to an object, like `cJSON_AddNullToObject`. They return a pointer to the new item or `NULL` if they failed.
|
||||
|
||||
### Parsing JSON
|
||||
|
||||
Given some JSON in a zero terminated string, you can parse it with `cJSON_Parse`.
|
||||
|
||||
```c
|
||||
void parse_and_callback(cJSON *item, const char *prefix)
|
||||
cJSON *json = cJSON_Parse(string);
|
||||
```
|
||||
|
||||
Given some JSON in a string (whether zero terminated or not), you can parse it with `cJSON_ParseWithLength`.
|
||||
|
||||
```c
|
||||
cJSON *json = cJSON_ParseWithLength(string, buffer_length);
|
||||
```
|
||||
|
||||
It will parse the JSON and allocate a tree of `cJSON` items that represents it. Once it returns, you are fully responsible for deallocating it after use with `cJSON_Delete`.
|
||||
|
||||
The allocator used by `cJSON_Parse` is `malloc` and `free` by default but can be changed (globally) with `cJSON_InitHooks`.
|
||||
|
||||
If an error occurs a pointer to the position of the error in the input string can be accessed using `cJSON_GetErrorPtr`. Note though that this can produce race conditions in multithreading scenarios, in that case it is better to use `cJSON_ParseWithOpts` with `return_parse_end`.
|
||||
By default, characters in the input string that follow the parsed JSON will not be considered as an error.
|
||||
|
||||
If you want more options, use `cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)`.
|
||||
`return_parse_end` returns a pointer to the end of the JSON in the input string or the position that an error occurs at (thereby replacing `cJSON_GetErrorPtr` in a thread safe way). `require_null_terminated`, if set to `1` will make it an error if the input string contains data after the JSON.
|
||||
|
||||
If you want more options giving buffer length, use `cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated)`.
|
||||
|
||||
### Printing JSON
|
||||
|
||||
Given a tree of `cJSON` items, you can print them as a string using `cJSON_Print`.
|
||||
|
||||
```c
|
||||
char *string = cJSON_Print(json);
|
||||
```
|
||||
|
||||
It will allocate a string and print a JSON representation of the tree into it. Once it returns, you are fully responsible for deallocating it after use with your allocator. (usually `free`, depends on what has been set with `cJSON_InitHooks`).
|
||||
|
||||
`cJSON_Print` will print with whitespace for formatting. If you want to print without formatting, use `cJSON_PrintUnformatted`.
|
||||
|
||||
If you have a rough idea of how big your resulting string will be, you can use `cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)`. `fmt` is a boolean to turn formatting with whitespace on and off. `prebuffer` specifies the first buffer size to use for printing. `cJSON_Print` currently uses 256 bytes for its first buffer size. Once printing runs out of space, a new buffer is allocated and the old gets copied over before printing is continued.
|
||||
|
||||
These dynamic buffer allocations can be completely avoided by using `cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)`. It takes a buffer to a pointer to print to and its length. If the length is reached, printing will fail and it returns `0`. In case of success, `1` is returned. Note that you should provide 5 bytes more than is actually needed, because cJSON is not 100% accurate in estimating if the provided memory is enough.
|
||||
|
||||
### Example
|
||||
|
||||
In this example we want to build and parse the following JSON:
|
||||
|
||||
```json
|
||||
{
|
||||
while (item)
|
||||
{
|
||||
char *newprefix = malloc(strlen(prefix) + strlen(item->name) + 2);
|
||||
sprintf(newprefix, "%s/%s", prefix, item->name);
|
||||
int dorecurse = callback(newprefix, item->type, item);
|
||||
if (item->child && dorecurse)
|
||||
"name": "Awesome 4K",
|
||||
"resolutions": [
|
||||
{
|
||||
parse_and_callback(item->child, newprefix);
|
||||
"width": 1280,
|
||||
"height": 720
|
||||
},
|
||||
{
|
||||
"width": 1920,
|
||||
"height": 1080
|
||||
},
|
||||
{
|
||||
"width": 3840,
|
||||
"height": 2160
|
||||
}
|
||||
item = item->next;
|
||||
free(newprefix);
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The `prefix` process will build you a separated list, to simplify your callback handling.
|
||||
The `dorecurse` flag would let the callback decide to handle sub-arrays on it's own, or
|
||||
let you invoke it per-item. For the item above, your callback might look like this:
|
||||
#### Printing
|
||||
|
||||
Let's build the above JSON and print it to a string:
|
||||
|
||||
```c
|
||||
int callback(const char *name, int type, cJSON *item)
|
||||
//create a monitor with a list of supported resolutions
|
||||
//NOTE: Returns a heap allocated string, you are required to free it after use.
|
||||
char *create_monitor(void)
|
||||
{
|
||||
if (!strcmp(name, "name"))
|
||||
const unsigned int resolution_numbers[3][2] = {
|
||||
{1280, 720},
|
||||
{1920, 1080},
|
||||
{3840, 2160}
|
||||
};
|
||||
char *string = NULL;
|
||||
cJSON *name = NULL;
|
||||
cJSON *resolutions = NULL;
|
||||
cJSON *resolution = NULL;
|
||||
cJSON *width = NULL;
|
||||
cJSON *height = NULL;
|
||||
size_t index = 0;
|
||||
|
||||
cJSON *monitor = cJSON_CreateObject();
|
||||
if (monitor == NULL)
|
||||
{
|
||||
/* populate name */
|
||||
}
|
||||
else if (!strcmp(name, "format/type")
|
||||
{
|
||||
/* handle "rect" */ }
|
||||
else if (!strcmp(name, "format/width")
|
||||
{
|
||||
/* 800 */
|
||||
}
|
||||
else if (!strcmp(name, "format/height")
|
||||
{
|
||||
/* 600 */
|
||||
}
|
||||
else if (!strcmp(name, "format/interlace")
|
||||
{
|
||||
/* false */
|
||||
}
|
||||
else if (!strcmp(name, "format/frame rate")
|
||||
{
|
||||
/* 24 */
|
||||
goto end;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, you might like to parse iteratively.
|
||||
You'd use:
|
||||
|
||||
```c
|
||||
void parse_object(cJSON *item)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < cJSON_GetArraySize(item); i++)
|
||||
name = cJSON_CreateString("Awesome 4K");
|
||||
if (name == NULL)
|
||||
{
|
||||
cJSON *subitem = cJSON_GetArrayItem(item, i);
|
||||
// handle subitem
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
```
|
||||
/* after creation was successful, immediately add it to the monitor,
|
||||
* thereby transferring ownership of the pointer to it */
|
||||
cJSON_AddItemToObject(monitor, "name", name);
|
||||
|
||||
Or, for PROPER manual mode:
|
||||
|
||||
```c
|
||||
void parse_object(cJSON *item)
|
||||
{
|
||||
cJSON *subitem = item->child;
|
||||
while (subitem)
|
||||
resolutions = cJSON_CreateArray();
|
||||
if (resolutions == NULL)
|
||||
{
|
||||
// handle subitem
|
||||
if (subitem->child)
|
||||
goto end;
|
||||
}
|
||||
cJSON_AddItemToObject(monitor, "resolutions", resolutions);
|
||||
|
||||
for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index)
|
||||
{
|
||||
resolution = cJSON_CreateObject();
|
||||
if (resolution == NULL)
|
||||
{
|
||||
parse_object(subitem->child);
|
||||
goto end;
|
||||
}
|
||||
cJSON_AddItemToArray(resolutions, resolution);
|
||||
|
||||
width = cJSON_CreateNumber(resolution_numbers[index][0]);
|
||||
if (width == NULL)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
cJSON_AddItemToObject(resolution, "width", width);
|
||||
|
||||
height = cJSON_CreateNumber(resolution_numbers[index][1]);
|
||||
if (height == NULL)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
cJSON_AddItemToObject(resolution, "height", height);
|
||||
}
|
||||
|
||||
string = cJSON_Print(monitor);
|
||||
if (string == NULL)
|
||||
{
|
||||
fprintf(stderr, "Failed to print monitor.\n");
|
||||
}
|
||||
|
||||
end:
|
||||
cJSON_Delete(monitor);
|
||||
return string;
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively we can use the `cJSON_Add...ToObject` helper functions to make our lives a little easier:
|
||||
|
||||
```c
|
||||
//NOTE: Returns a heap allocated string, you are required to free it after use.
|
||||
char *create_monitor_with_helpers(void)
|
||||
{
|
||||
const unsigned int resolution_numbers[3][2] = {
|
||||
{1280, 720},
|
||||
{1920, 1080},
|
||||
{3840, 2160}
|
||||
};
|
||||
char *string = NULL;
|
||||
cJSON *resolutions = NULL;
|
||||
size_t index = 0;
|
||||
|
||||
cJSON *monitor = cJSON_CreateObject();
|
||||
|
||||
if (cJSON_AddStringToObject(monitor, "name", "Awesome 4K") == NULL)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
|
||||
resolutions = cJSON_AddArrayToObject(monitor, "resolutions");
|
||||
if (resolutions == NULL)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index)
|
||||
{
|
||||
cJSON *resolution = cJSON_CreateObject();
|
||||
|
||||
if (cJSON_AddNumberToObject(resolution, "width", resolution_numbers[index][0]) == NULL)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
|
||||
subitem = subitem->next;
|
||||
if (cJSON_AddNumberToObject(resolution, "height", resolution_numbers[index][1]) == NULL)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
|
||||
cJSON_AddItemToArray(resolutions, resolution);
|
||||
}
|
||||
|
||||
string = cJSON_Print(monitor);
|
||||
if (string == NULL)
|
||||
{
|
||||
fprintf(stderr, "Failed to print monitor.\n");
|
||||
}
|
||||
|
||||
end:
|
||||
cJSON_Delete(monitor);
|
||||
return string;
|
||||
}
|
||||
```
|
||||
|
||||
Of course, this should look familiar, since this is just a stripped-down version
|
||||
of the callback-parser.
|
||||
#### Parsing
|
||||
|
||||
This should cover most uses you'll find for parsing. The rest should be possible
|
||||
to infer.. and if in doubt, read the source! There's not a lot of it! ;)
|
||||
|
||||
In terms of constructing JSON data, the example code above is the right way to do it.
|
||||
You can, of course, hand your sub-objects to other functions to populate.
|
||||
Also, if you find a use for it, you can manually build the objects.
|
||||
For instance, suppose you wanted to build an array of objects?
|
||||
In this example we will parse a JSON in the above format and check if the monitor supports a Full HD resolution while printing some diagnostic output:
|
||||
|
||||
```c
|
||||
cJSON *objects[24];
|
||||
|
||||
cJSON *Create_array_of_anything(cJSON **items, int num)
|
||||
/* return 1 if the monitor supports full hd, 0 otherwise */
|
||||
int supports_full_hd(const char * const monitor)
|
||||
{
|
||||
int i;
|
||||
cJSON *prev;
|
||||
cJSON *root = cJSON_CreateArray();
|
||||
for (i = 0; i < 24; i++)
|
||||
const cJSON *resolution = NULL;
|
||||
const cJSON *resolutions = NULL;
|
||||
const cJSON *name = NULL;
|
||||
int status = 0;
|
||||
cJSON *monitor_json = cJSON_Parse(monitor);
|
||||
if (monitor_json == NULL)
|
||||
{
|
||||
if (!i)
|
||||
const char *error_ptr = cJSON_GetErrorPtr();
|
||||
if (error_ptr != NULL)
|
||||
{
|
||||
root->child = objects[i];
|
||||
fprintf(stderr, "Error before: %s\n", error_ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
prev->next = objects[i];
|
||||
objects[i]->prev = prev;
|
||||
}
|
||||
|
||||
prev = objects[i];
|
||||
status = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
return root;
|
||||
name = cJSON_GetObjectItemCaseSensitive(monitor_json, "name");
|
||||
if (cJSON_IsString(name) && (name->valuestring != NULL))
|
||||
{
|
||||
printf("Checking monitor \"%s\"\n", name->valuestring);
|
||||
}
|
||||
|
||||
resolutions = cJSON_GetObjectItemCaseSensitive(monitor_json, "resolutions");
|
||||
cJSON_ArrayForEach(resolution, resolutions)
|
||||
{
|
||||
cJSON *width = cJSON_GetObjectItemCaseSensitive(resolution, "width");
|
||||
cJSON *height = cJSON_GetObjectItemCaseSensitive(resolution, "height");
|
||||
|
||||
if (!cJSON_IsNumber(width) || !cJSON_IsNumber(height))
|
||||
{
|
||||
status = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((width->valuedouble == 1920) && (height->valuedouble == 1080))
|
||||
{
|
||||
status = 1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
cJSON_Delete(monitor_json);
|
||||
return status;
|
||||
}
|
||||
```
|
||||
|
||||
and simply: `Create_array_of_anything(objects, 24);`
|
||||
Note that there are no NULL checks except for the result of `cJSON_Parse` because `cJSON_GetObjectItemCaseSensitive` checks for `NULL` inputs already, so a `NULL` value is just propagated and `cJSON_IsNumber` and `cJSON_IsString` return `0` if the input is `NULL`.
|
||||
|
||||
cJSON doesn't make any assumptions about what order you create things in.
|
||||
You can attach the objects, as above, and later add children to each
|
||||
of those objects.
|
||||
### Caveats
|
||||
|
||||
As soon as you call `cJSON_Print`, it renders the structure to text.
|
||||
#### Zero Character
|
||||
|
||||
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[]`.
|
||||
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.
|
||||
|
||||
#### Duplicate Object Members
|
||||
|
||||
cJSON supports parsing and printing JSON that contains objects that have multiple members with the same name. `cJSON_GetObjectItemCaseSensitive` however will always only return the first one.
|
||||
|
||||
# Enjoy cJSON!
|
||||
|
||||
- Dave Gamble, Aug 2009
|
||||
- Dave Gamble (original author)
|
||||
- Max Bruckner and Alan Wang (current maintainer)
|
||||
- and the other [cJSON contributors](CONTRIBUTORS.md)
|
||||
|
86
appveyor.yml
Normal file
86
appveyor.yml
Normal file
@ -0,0 +1,86 @@
|
||||
os: Visual Studio 2015
|
||||
|
||||
# ENABLE_CUSTOM_COMPILER_FLAGS - on by default
|
||||
# ENABLE_SANITIZERS - off by default
|
||||
# ENABLE_PUBLIC_SYMBOLS - on by default
|
||||
# BUILD_SHARED_LIBS - on by default
|
||||
# ENABLE_TARGET_EXPORT - on by default
|
||||
# ENABLE_CJSON_UTILS - off by default
|
||||
# ENABLE_CJSON_TEST -on by default
|
||||
# ENABLE_VALGRIND - off by default
|
||||
# ENABLE_FUZZING - off by default
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- GENERATOR: "Visual Studio 14 2015"
|
||||
BUILD_SHARED_LIBS: ON
|
||||
ENABLE_CJSON_TEST: OFF
|
||||
ENABLE_CJSON_UTILS: ON
|
||||
|
||||
- GENERATOR: "Visual Studio 14 2015"
|
||||
BUILD_SHARED_LIBS: OFF
|
||||
ENABLE_CJSON_TEST: OFF
|
||||
ENABLE_CJSON_UTILS: ON
|
||||
|
||||
- GENERATOR: "Visual Studio 12 2013"
|
||||
BUILD_SHARED_LIBS: ON
|
||||
ENABLE_CJSON_TEST: OFF
|
||||
ENABLE_CJSON_UTILS: ON
|
||||
|
||||
- GENERATOR: "Visual Studio 12 2013"
|
||||
BUILD_SHARED_LIBS: OFF
|
||||
ENABLE_CJSON_TEST: OFF
|
||||
ENABLE_CJSON_UTILS: ON
|
||||
|
||||
- GENERATOR: "Visual Studio 11 2012"
|
||||
BUILD_SHARED_LIBS: ON
|
||||
ENABLE_CJSON_TEST: OFF
|
||||
ENABLE_CJSON_UTILS: ON
|
||||
|
||||
- GENERATOR: "Visual Studio 11 2012"
|
||||
BUILD_SHARED_LIBS: OFF
|
||||
ENABLE_CJSON_TEST: OFF
|
||||
ENABLE_CJSON_UTILS: ON
|
||||
|
||||
- GENERATOR: "Visual Studio 10 2010"
|
||||
BUILD_SHARED_LIBS: ON
|
||||
ENABLE_CJSON_TEST: OFF
|
||||
ENABLE_CJSON_UTILS: ON
|
||||
|
||||
- GENERATOR: "Visual Studio 10 2010"
|
||||
BUILD_SHARED_LIBS: OFF
|
||||
ENABLE_CJSON_TEST: OFF
|
||||
ENABLE_CJSON_UTILS: ON
|
||||
|
||||
- GENERATOR: "Visual Studio 9 2008"
|
||||
BUILD_SHARED_LIBS: ON
|
||||
ENABLE_CJSON_TEST: OFF
|
||||
ENABLE_CJSON_UTILS: ON
|
||||
|
||||
- GENERATOR: "Visual Studio 9 2008"
|
||||
BUILD_SHARED_LIBS: OFF
|
||||
ENABLE_CJSON_TEST: OFF
|
||||
ENABLE_CJSON_UTILS: ON
|
||||
|
||||
|
||||
platform:
|
||||
- x86
|
||||
- x64
|
||||
matrix:
|
||||
exclude:
|
||||
- platform: x64
|
||||
GENERATOR: "Visual Studio 9 2008"
|
||||
|
||||
configuration:
|
||||
- Release
|
||||
|
||||
|
||||
build_script:
|
||||
- ps: if($env:PLATFORM -eq "x64") { $env:CMAKE_GEN_SUFFIX=" Win64" }
|
||||
- cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -DBUILD_SHARED_LIBS=%BUILD_SHARED_LIBS% -DENABLE_CJSON_TEST=%ENABLE_CJSON_TEST% -H. -Bbuild
|
||||
- cmake --build build --config "%CONFIGURATION%"
|
||||
|
||||
|
||||
on_failure:
|
||||
- ps: if(Test-Path builds/CMakeFiles/CMakeOutput.log) { cat builds/CMakeFiles/CMakeOutput.log }
|
||||
- ps: if(Test-Path builds/CMakeFiles/CMakeError.log) { cat builds/CMakeFiles/CMakeError.log }
|
264
cJSON.h
264
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,65 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#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 3 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
|
||||
|
||||
*/
|
||||
|
||||
#define CJSON_CDECL __cdecl
|
||||
#define CJSON_STDCALL __stdcall
|
||||
|
||||
/* 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 CJSON_STDCALL
|
||||
#elif defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
|
||||
#elif defined(CJSON_IMPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
|
||||
#endif
|
||||
#else /* !__WINDOWS__ */
|
||||
#define CJSON_CDECL
|
||||
#define CJSON_STDCALL
|
||||
|
||||
#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
|
||||
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 7
|
||||
#define CJSON_VERSION_PATCH 16
|
||||
|
||||
#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 +94,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 +111,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;
|
||||
@ -67,101 +124,174 @@ typedef struct cJSON
|
||||
|
||||
typedef struct cJSON_Hooks
|
||||
{
|
||||
void *(*malloc_fn)(size_t sz);
|
||||
void (*free_fn)(void *ptr);
|
||||
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
|
||||
void *(CJSON_CDECL *malloc_fn)(size_t sz);
|
||||
void (CJSON_CDECL *free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
typedef int cJSON_bool;
|
||||
|
||||
/* 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);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
|
||||
/* 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 so will match cJSON_GetErrorPtr(). */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, 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);
|
||||
/* Render a cJSON entity to text using a buffer already allocated in memory with length buf_len. Returns 1 on success and 0 on failure. */
|
||||
extern int cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const int fmt);
|
||||
CJSON_PUBLIC(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 *item);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
extern 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(int) cJSON_GetArraySize(const cJSON *array);
|
||||
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
|
||||
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);
|
||||
|
||||
/* Check item type and return its value */
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
|
||||
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
|
||||
|
||||
/* 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);
|
||||
/* Create a string where valuestring references a string so
|
||||
* it will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
||||
/* Create an object/array that only references it's elements so
|
||||
* they will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
||||
|
||||
/* These utilities create an Array of count items.
|
||||
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
|
||||
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 *const *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);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) 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` */
|
||||
extern void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) 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(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) 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);
|
||||
/* Remove/Detach items from Arrays/Objects. */
|
||||
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(cJSON_bool) 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(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) 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. */
|
||||
* 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);
|
||||
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
|
||||
* The input pointer json cannot point to a read-only address area, such as a string constant,
|
||||
* but should point to a readable and writable address area. */
|
||||
CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||
|
||||
extern void cJSON_Minify(char *json);
|
||||
|
||||
/* Macros for creating things quickly. */
|
||||
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
|
||||
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
|
||||
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
|
||||
#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))
|
||||
/* Helper functions for creating and adding items to an object at the same time.
|
||||
* They return the added item or NULL on failure. */
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
|
||||
|
||||
/* 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))
|
||||
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
|
||||
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
|
||||
|
||||
/* Macro for iterating over an array */
|
||||
#define cJSON_ArrayForEach(pos, head) for(pos = (head)->child; pos != NULL; pos = pos->next)
|
||||
/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
|
||||
#define cJSON_SetBoolValue(object, boolValue) ( \
|
||||
(object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \
|
||||
(object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \
|
||||
cJSON_Invalid\
|
||||
)
|
||||
|
||||
/* 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
|
||||
}
|
||||
|
1523
cJSON_Utils.c
1523
cJSON_Utils.c
File diff suppressed because it is too large
Load Diff
@ -1,14 +1,48 @@
|
||||
/*
|
||||
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_Utils__h
|
||||
#define cJSON_Utils__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#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 +67,22 @@ 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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
1
fuzzing/.gitignore
vendored
Normal file
1
fuzzing/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
afl-build
|
34
fuzzing/CMakeLists.txt
Normal file
34
fuzzing/CMakeLists.txt
Normal file
@ -0,0 +1,34 @@
|
||||
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()
|
||||
|
||||
if(ENABLE_CJSON_TEST)
|
||||
ADD_EXECUTABLE(fuzz_main fuzz_main.c cjson_read_fuzzer.c)
|
||||
TARGET_LINK_LIBRARIES(fuzz_main cjson)
|
||||
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
|
77
fuzzing/cjson_read_fuzzer.c
Normal file
77
fuzzing/cjson_read_fuzzer.c
Normal file
@ -0,0 +1,77 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../cJSON.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); /* required by C89 */
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
||||
{
|
||||
cJSON *json;
|
||||
size_t offset = 4;
|
||||
unsigned char *copied;
|
||||
char *printed_json = NULL;
|
||||
int minify, require_termination, formatted, buffered;
|
||||
|
||||
|
||||
if(size <= offset) return 0;
|
||||
if(data[size-1] != '\0') return 0;
|
||||
if(data[0] != '1' && data[0] != '0') return 0;
|
||||
if(data[1] != '1' && data[1] != '0') return 0;
|
||||
if(data[2] != '1' && data[2] != '0') return 0;
|
||||
if(data[3] != '1' && data[3] != '0') return 0;
|
||||
|
||||
minify = data[0] == '1' ? 1 : 0;
|
||||
require_termination = data[1] == '1' ? 1 : 0;
|
||||
formatted = data[2] == '1' ? 1 : 0;
|
||||
buffered = data[3] == '1' ? 1 : 0;
|
||||
|
||||
json = cJSON_ParseWithOpts((const char*)data + offset, NULL, require_termination);
|
||||
|
||||
if(json == NULL) return 0;
|
||||
|
||||
if(buffered)
|
||||
{
|
||||
printed_json = cJSON_PrintBuffered(json, 1, formatted);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unbuffered printing */
|
||||
if(formatted)
|
||||
{
|
||||
printed_json = cJSON_Print(json);
|
||||
}
|
||||
else
|
||||
{
|
||||
printed_json = cJSON_PrintUnformatted(json);
|
||||
}
|
||||
}
|
||||
|
||||
if(printed_json != NULL) free(printed_json);
|
||||
|
||||
if(minify)
|
||||
{
|
||||
copied = (unsigned char*)malloc(size);
|
||||
if(copied == NULL) return 0;
|
||||
|
||||
memcpy(copied, data, size);
|
||||
|
||||
cJSON_Minify((char*)copied + offset);
|
||||
|
||||
free(copied);
|
||||
}
|
||||
|
||||
cJSON_Delete(json);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
54
fuzzing/fuzz_main.c
Normal file
54
fuzzing/fuzz_main.c
Normal file
@ -0,0 +1,54 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); /* required by C89 */
|
||||
|
||||
/* fuzz target entry point, works without libFuzzer */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
FILE *f;
|
||||
char *buf = NULL;
|
||||
long siz_buf;
|
||||
|
||||
if(argc < 2)
|
||||
{
|
||||
fprintf(stderr, "no input file\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
f = fopen(argv[1], "rb");
|
||||
if(f == NULL)
|
||||
{
|
||||
fprintf(stderr, "error opening input file %s\n", argv[1]);
|
||||
goto err;
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
|
||||
siz_buf = ftell(f);
|
||||
rewind(f);
|
||||
|
||||
if(siz_buf < 1) goto err;
|
||||
|
||||
buf = (char*)malloc((size_t)siz_buf);
|
||||
if(buf == NULL)
|
||||
{
|
||||
fprintf(stderr, "malloc() failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if(fread(buf, (size_t)siz_buf, 1, f) != 1)
|
||||
{
|
||||
fprintf(stderr, "fread() failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
(void)LLVMFuzzerTestOneInput((uint8_t*)buf, (size_t)siz_buf);
|
||||
|
||||
err:
|
||||
free(buf);
|
||||
|
||||
return 0;
|
||||
}
|
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="\\\\"
|
||||
escape_sequence_slash="\\/"
|
||||
escape_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"
|
18
fuzzing/ossfuzz.sh
Executable file
18
fuzzing/ossfuzz.sh
Executable file
@ -0,0 +1,18 @@
|
||||
#!/bin/bash -eu
|
||||
|
||||
# This script is meant to be run by
|
||||
# https://github.com/google/oss-fuzz/blob/master/projects/cjson/Dockerfile
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DBUILD_SHARED_LIBS=OFF -DENABLE_CJSON_TEST=OFF ..
|
||||
make -j$(nproc)
|
||||
|
||||
$CXX $CXXFLAGS $SRC/cjson/fuzzing/cjson_read_fuzzer.c -I. \
|
||||
-o $OUT/cjson_read_fuzzer \
|
||||
$LIB_FUZZING_ENGINE $SRC/cjson/build/libcjson.a
|
||||
|
||||
find $SRC/cjson/fuzzing/inputs -name "*" | \
|
||||
xargs zip $OUT/cjson_read_fuzzer_seed_corpus.zip
|
||||
|
||||
cp $SRC/cjson/fuzzing/json.dict $OUT/cjson_read_fuzzer.dict
|
@ -1,11 +0,0 @@
|
||||
prefix=@prefix@
|
||||
libdir=${prefix}/@libdir@
|
||||
includedir=${prefix}/@includedir@
|
||||
|
||||
Name: libcjson
|
||||
Version: @version@
|
||||
Description: Ultralightweight JSON parser in ANSI C
|
||||
URL: https://github.com/DaveGamble/cJSON
|
||||
Libs: -L${libdir} -lcjson
|
||||
Libs.Private: -lm
|
||||
Cflags: -I${includedir}
|
@ -2,8 +2,8 @@
|
||||
set(CJSON_UTILS_FOUND @ENABLE_CJSON_UTILS@)
|
||||
|
||||
# The include directories used by cJSON
|
||||
set(CJSON_INCLUDE_DIRS "@prefix@/@includedir@")
|
||||
set(CJSON_INCLUDE_DIR "@prefix@/@includedir@")
|
||||
set(CJSON_INCLUDE_DIRS "@CMAKE_INSTALL_FULL_INCLUDEDIR@")
|
||||
set(CJSON_INCLUDE_DIR "@CMAKE_INSTALL_FULL_INCLUDEDIR@")
|
||||
|
||||
get_filename_component(_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
|
10
library_config/libcjson.pc.in
Normal file
10
library_config/libcjson.pc.in
Normal file
@ -0,0 +1,10 @@
|
||||
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
|
||||
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
||||
|
||||
Name: libcjson
|
||||
Version: @PROJECT_VERSION@
|
||||
Description: Ultralightweight JSON parser in ANSI C
|
||||
URL: https://github.com/DaveGamble/cJSON
|
||||
Libs: -L${libdir} -lcjson
|
||||
Libs.private: -lm
|
||||
Cflags: -I${includedir} -I${includedir}/cjson
|
@ -1,11 +1,10 @@
|
||||
prefix=@prefix@
|
||||
libdir=${prefix}/@libdir@
|
||||
includedir=${prefix}/@includedir@
|
||||
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
|
||||
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
||||
|
||||
Name: libcjson_utils
|
||||
Version: @version@
|
||||
Version: @PROJECT_VERSION@
|
||||
Description: An implementation of JSON Pointer, Patch and Merge Patch based on cJSON.
|
||||
URL: https://github.com/DaveGamble/cJSON
|
||||
Libs: -L${libdir} -lcjson_utils
|
||||
Cflags: -I${includedir}
|
||||
Cflags: -I${includedir} -I${includedir}/cjson
|
||||
Requires: libcjson
|
27
library_config/uninstall.cmake
Normal file
27
library_config/uninstall.cmake
Normal file
@ -0,0 +1,27 @@
|
||||
cmake_minimum_required(VERSION 2.8.5)
|
||||
|
||||
set(MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt")
|
||||
|
||||
if(NOT EXISTS ${MANIFEST})
|
||||
message(FATAL_ERROR "Cannot find install mainfest: ${MANIFEST}")
|
||||
endif()
|
||||
|
||||
file(STRINGS ${MANIFEST} files)
|
||||
foreach(file ${files})
|
||||
if(EXISTS ${file} OR IS_SYMLINK ${file})
|
||||
message(STATUS "Removing: ${file}")
|
||||
|
||||
execute_process(COMMAND rm -f ${file}
|
||||
RESULT_VARIABLE result
|
||||
OUTPUT_QUIET
|
||||
ERROR_VARIABLE stderr
|
||||
ERROR_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
if(NOT ${result} EQUAL 0)
|
||||
message(FATAL_ERROR "${stderr}")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Does-not-exist: ${file}")
|
||||
endif()
|
||||
endforeach(file)
|
161
test.c
161
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
|
||||
@ -25,57 +25,6 @@
|
||||
#include <string.h>
|
||||
#include "cJSON.h"
|
||||
|
||||
/* Parse text to JSON, then render back to text, and print! */
|
||||
static void doit(char *text)
|
||||
{
|
||||
char *out = NULL;
|
||||
cJSON *json = NULL;
|
||||
|
||||
json = cJSON_Parse(text);
|
||||
if (!json)
|
||||
{
|
||||
printf("Error before: [%s]\n", cJSON_GetErrorPtr());
|
||||
}
|
||||
else
|
||||
{
|
||||
out = cJSON_Print(json);
|
||||
cJSON_Delete(json);
|
||||
printf("%s\n", out);
|
||||
free(out);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Read a file, parse, render back, etc. */
|
||||
static void dofile(char *filename)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
long len = 0;
|
||||
char *data = NULL;
|
||||
|
||||
/* open in read binary mode */
|
||||
f = fopen(filename,"rb");
|
||||
/* get the length */
|
||||
fseek(f, 0, SEEK_END);
|
||||
len = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
data = (char*)malloc(len + 1);
|
||||
if (data == NULL)
|
||||
{
|
||||
printf("Failed to allocate memory.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fread(data, 1, len, f);
|
||||
data[len] = '\0';
|
||||
fclose(f);
|
||||
|
||||
doit(data);
|
||||
free(data);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Used by some code below as an example datatype. */
|
||||
struct record
|
||||
{
|
||||
@ -97,16 +46,16 @@ static int print_preallocated(cJSON *root)
|
||||
char *out = NULL;
|
||||
char *buf = NULL;
|
||||
char *buf_fail = NULL;
|
||||
int len = 0;
|
||||
int len_fail = 0;
|
||||
size_t len = 0;
|
||||
size_t len_fail = 0;
|
||||
|
||||
/* formatted print */
|
||||
out = cJSON_Print(root);
|
||||
|
||||
/* create buffer to succeed */
|
||||
/* the extra 64 bytes are in case a floating point value is printed */
|
||||
len = strlen(out) + 64;
|
||||
buf = malloc(len);
|
||||
/* 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");
|
||||
@ -115,7 +64,7 @@ static int print_preallocated(cJSON *root)
|
||||
|
||||
/* create buffer to fail */
|
||||
len_fail = strlen(out);
|
||||
buf_fail = malloc(len_fail);
|
||||
buf_fail = (char*)malloc(len_fail);
|
||||
if (buf_fail == NULL)
|
||||
{
|
||||
printf("Failed to allocate memory.\n");
|
||||
@ -123,7 +72,7 @@ static int print_preallocated(cJSON *root)
|
||||
}
|
||||
|
||||
/* Print to buffer */
|
||||
if (!cJSON_PrintPreallocated(root, buf, len, 1)) {
|
||||
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");
|
||||
@ -140,7 +89,7 @@ static int print_preallocated(cJSON *root)
|
||||
printf("%s\n", buf);
|
||||
|
||||
/* force it to fail */
|
||||
if (cJSON_PrintPreallocated(root, buf_fail, len_fail, 1)) {
|
||||
if (cJSON_PrintPreallocated(root, buf_fail, (int)len_fail, 1)) {
|
||||
printf("cJSON_PrintPreallocated failed to show error with insufficient memory!\n");
|
||||
printf("cJSON_Print result:\n%s\n", out);
|
||||
printf("cJSON_PrintPreallocated result:\n%s\n", buf_fail);
|
||||
@ -307,96 +256,10 @@ static void create_objects(void)
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int CJSON_CDECL 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();
|
||||
|
206
test_utils.c
206
test_utils.c
@ -1,206 +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 = 0;
|
||||
/* JSON Pointer tests: */
|
||||
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"
|
||||
"}";
|
||||
|
||||
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};
|
||||
char *before = NULL;
|
||||
char *after = NULL;
|
||||
cJSON *object = NULL;
|
||||
cJSON *nums = NULL;
|
||||
cJSON *num6 = NULL;
|
||||
cJSON *sortme = NULL;
|
||||
|
||||
|
||||
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_to_be_patched = cJSON_Parse(patches[i][0]);
|
||||
cJSON *patch = cJSON_Parse(patches[i][1]);
|
||||
int err = cJSONUtils_ApplyPatches(object_to_be_patched, patch);
|
||||
char *output = cJSON_Print(object_to_be_patched);
|
||||
printf("Test %d (err %d):\n%s\n\n", i + 1, err, output);
|
||||
|
||||
free(output);
|
||||
cJSON_Delete(object_to_be_patched);
|
||||
cJSON_Delete(patch);
|
||||
}
|
||||
|
||||
/* JSON Generate Patch tests: */
|
||||
printf("JSON Generate Patch Tests\n");
|
||||
for (i = 0; i < 15; i++)
|
||||
{
|
||||
cJSON *from;
|
||||
cJSON *to;
|
||||
cJSON *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_to_be_merged = cJSON_Parse(merges[i][0]);
|
||||
cJSON *patch = cJSON_Parse(merges[i][1]);
|
||||
char *before_merge = cJSON_PrintUnformatted(object_to_be_merged);
|
||||
patchtext = cJSON_PrintUnformatted(patch);
|
||||
printf("Before: [%s] -> [%s] = ", before_merge, patchtext);
|
||||
object_to_be_merged = cJSONUtils_MergePatch(object_to_be_merged, patch);
|
||||
after = cJSON_PrintUnformatted(object_to_be_merged);
|
||||
printf("[%s] vs [%s] (%s)\n", after, merges[i][2], strcmp(after, merges[i][2]) ? "FAIL" : "OK");
|
||||
|
||||
free(before_merge);
|
||||
free(patchtext);
|
||||
free(after);
|
||||
cJSON_Delete(object_to_be_merged);
|
||||
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;
|
||||
}
|
119
tests/CMakeLists.txt
Normal file
119
tests/CMakeLists.txt
Normal file
@ -0,0 +1,119 @@
|
||||
if(ENABLE_CJSON_TEST)
|
||||
add_library(unity STATIC 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
|
||||
cjson_add
|
||||
readme_examples
|
||||
minify_tests
|
||||
)
|
||||
|
||||
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 --suppressions=${CMAKE_CURRENT_SOURCE_DIR}/../valgrind.supp)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
foreach(unity_test ${unity_tests})
|
||||
add_executable("${unity_test}" "${unity_test}.c")
|
||||
if("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC")
|
||||
target_sources(${unity_test} PRIVATE unity_setup.c)
|
||||
endif()
|
||||
target_link_libraries("${unity_test}" "${CJSON_LIB}" unity)
|
||||
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)
|
||||
if("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC")
|
||||
target_sources(${cjson_utils_test} PRIVATE unity_setup.c)
|
||||
endif()
|
||||
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()
|
471
tests/cjson_add.c
Normal file
471
tests/cjson_add.c
Normal file
@ -0,0 +1,471 @@
|
||||
/*
|
||||
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_CDECL failing_malloc(size_t size)
|
||||
{
|
||||
(void)size;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* work around MSVC error C2322: '...' address of dillimport '...' is not static */
|
||||
static void CJSON_CDECL normal_free(void *pointer)
|
||||
{
|
||||
free(pointer);
|
||||
}
|
||||
|
||||
static cJSON_Hooks failing_hooks = {
|
||||
failing_malloc,
|
||||
normal_free
|
||||
};
|
||||
|
||||
static void cjson_add_null_should_add_null(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
cJSON *null = NULL;
|
||||
|
||||
cJSON_AddNullToObject(root, "null");
|
||||
|
||||
TEST_ASSERT_NOT_NULL(null = cJSON_GetObjectItemCaseSensitive(root, "null"));
|
||||
TEST_ASSERT_EQUAL_INT(null->type, cJSON_NULL);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_null_should_fail_with_null_pointers(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_AddNullToObject(NULL, "null"));
|
||||
TEST_ASSERT_NULL(cJSON_AddNullToObject(root, NULL));
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_null_should_fail_on_allocation_failure(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
cJSON_InitHooks(&failing_hooks);
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_AddNullToObject(root, "null"));
|
||||
|
||||
cJSON_InitHooks(NULL);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_true_should_add_true(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
cJSON *true_item = NULL;
|
||||
|
||||
cJSON_AddTrueToObject(root, "true");
|
||||
|
||||
TEST_ASSERT_NOT_NULL(true_item = cJSON_GetObjectItemCaseSensitive(root, "true"));
|
||||
TEST_ASSERT_EQUAL_INT(true_item->type, cJSON_True);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_true_should_fail_with_null_pointers(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_AddTrueToObject(NULL, "true"));
|
||||
TEST_ASSERT_NULL(cJSON_AddTrueToObject(root, NULL));
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_true_should_fail_on_allocation_failure(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
cJSON_InitHooks(&failing_hooks);
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_AddTrueToObject(root, "true"));
|
||||
|
||||
cJSON_InitHooks(NULL);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_create_int_array_should_fail_on_allocation_failure(void)
|
||||
{
|
||||
int numbers[] = {1, 2, 3};
|
||||
|
||||
cJSON_InitHooks(&failing_hooks);
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_CreateIntArray(numbers, 3));
|
||||
|
||||
cJSON_InitHooks(NULL);
|
||||
}
|
||||
|
||||
static void cjson_create_float_array_should_fail_on_allocation_failure(void)
|
||||
{
|
||||
float numbers[] = {1.0f, 2.0f, 3.0f};
|
||||
|
||||
cJSON_InitHooks(&failing_hooks);
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_CreateFloatArray(numbers, 3));
|
||||
|
||||
cJSON_InitHooks(NULL);
|
||||
}
|
||||
|
||||
static void cjson_create_double_array_should_fail_on_allocation_failure(void)
|
||||
{
|
||||
double numbers[] = {1.0, 2.0, 3.0};
|
||||
|
||||
cJSON_InitHooks(&failing_hooks);
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_CreateDoubleArray(numbers, 3));
|
||||
|
||||
cJSON_InitHooks(NULL);
|
||||
}
|
||||
|
||||
static void cjson_create_string_array_should_fail_on_allocation_failure(void)
|
||||
{
|
||||
const char* strings[] = {"1", "2", "3"};
|
||||
|
||||
cJSON_InitHooks(&failing_hooks);
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_CreateStringArray(strings, 3));
|
||||
|
||||
cJSON_InitHooks(NULL);
|
||||
}
|
||||
|
||||
static void cjson_add_false_should_add_false(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
cJSON *false_item = NULL;
|
||||
|
||||
cJSON_AddFalseToObject(root, "false");
|
||||
|
||||
TEST_ASSERT_NOT_NULL(false_item = cJSON_GetObjectItemCaseSensitive(root, "false"));
|
||||
TEST_ASSERT_EQUAL_INT(false_item->type, cJSON_False);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_false_should_fail_with_null_pointers(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_AddFalseToObject(NULL, "false"));
|
||||
TEST_ASSERT_NULL(cJSON_AddFalseToObject(root, NULL));
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_false_should_fail_on_allocation_failure(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
cJSON_InitHooks(&failing_hooks);
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_AddFalseToObject(root, "false"));
|
||||
|
||||
cJSON_InitHooks(NULL);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_bool_should_add_bool(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
cJSON *true_item = NULL;
|
||||
cJSON *false_item = NULL;
|
||||
|
||||
/* true */
|
||||
cJSON_AddBoolToObject(root, "true", true);
|
||||
TEST_ASSERT_NOT_NULL(true_item = cJSON_GetObjectItemCaseSensitive(root, "true"));
|
||||
TEST_ASSERT_EQUAL_INT(true_item->type, cJSON_True);
|
||||
|
||||
/* false */
|
||||
cJSON_AddBoolToObject(root, "false", false);
|
||||
TEST_ASSERT_NOT_NULL(false_item = cJSON_GetObjectItemCaseSensitive(root, "false"));
|
||||
TEST_ASSERT_EQUAL_INT(false_item->type, cJSON_False);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_bool_should_fail_with_null_pointers(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_AddBoolToObject(NULL, "false", false));
|
||||
TEST_ASSERT_NULL(cJSON_AddBoolToObject(root, NULL, false));
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_bool_should_fail_on_allocation_failure(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
cJSON_InitHooks(&failing_hooks);
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_AddBoolToObject(root, "false", false));
|
||||
|
||||
cJSON_InitHooks(NULL);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_number_should_add_number(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
cJSON *number = NULL;
|
||||
|
||||
cJSON_AddNumberToObject(root, "number", 42);
|
||||
|
||||
TEST_ASSERT_NOT_NULL(number = cJSON_GetObjectItemCaseSensitive(root, "number"));
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(number->type, cJSON_Number);
|
||||
TEST_ASSERT_EQUAL_DOUBLE(number->valuedouble, 42);
|
||||
TEST_ASSERT_EQUAL_INT(number->valueint, 42);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_number_should_fail_with_null_pointers(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_AddNumberToObject(NULL, "number", 42));
|
||||
TEST_ASSERT_NULL(cJSON_AddNumberToObject(root, NULL, 42));
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_number_should_fail_on_allocation_failure(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
cJSON_InitHooks(&failing_hooks);
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_AddNumberToObject(root, "number", 42));
|
||||
|
||||
cJSON_InitHooks(NULL);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_string_should_add_string(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
cJSON *string = NULL;
|
||||
|
||||
cJSON_AddStringToObject(root, "string", "Hello World!");
|
||||
|
||||
TEST_ASSERT_NOT_NULL(string = cJSON_GetObjectItemCaseSensitive(root, "string"));
|
||||
TEST_ASSERT_EQUAL_INT(string->type, cJSON_String);
|
||||
TEST_ASSERT_EQUAL_STRING(string->valuestring, "Hello World!");
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_string_should_fail_with_null_pointers(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_AddStringToObject(NULL, "string", "string"));
|
||||
TEST_ASSERT_NULL(cJSON_AddStringToObject(root, NULL, "string"));
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_string_should_fail_on_allocation_failure(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
cJSON_InitHooks(&failing_hooks);
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_AddStringToObject(root, "string", "string"));
|
||||
|
||||
cJSON_InitHooks(NULL);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_raw_should_add_raw(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
cJSON *raw = NULL;
|
||||
|
||||
cJSON_AddRawToObject(root, "raw", "{}");
|
||||
|
||||
TEST_ASSERT_NOT_NULL(raw = cJSON_GetObjectItemCaseSensitive(root, "raw"));
|
||||
TEST_ASSERT_EQUAL_INT(raw->type, cJSON_Raw);
|
||||
TEST_ASSERT_EQUAL_STRING(raw->valuestring, "{}");
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_raw_should_fail_with_null_pointers(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_AddRawToObject(NULL, "raw", "{}"));
|
||||
TEST_ASSERT_NULL(cJSON_AddRawToObject(root, NULL, "{}"));
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_raw_should_fail_on_allocation_failure(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
cJSON_InitHooks(&failing_hooks);
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_AddRawToObject(root, "raw", "{}"));
|
||||
|
||||
cJSON_InitHooks(NULL);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cJSON_add_object_should_add_object(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
cJSON *object = NULL;
|
||||
|
||||
cJSON_AddObjectToObject(root, "object");
|
||||
TEST_ASSERT_NOT_NULL(object = cJSON_GetObjectItemCaseSensitive(root, "object"));
|
||||
TEST_ASSERT_EQUAL_INT(object->type, cJSON_Object);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_object_should_fail_with_null_pointers(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_AddObjectToObject(NULL, "object"));
|
||||
TEST_ASSERT_NULL(cJSON_AddObjectToObject(root, NULL));
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_object_should_fail_on_allocation_failure(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
cJSON_InitHooks(&failing_hooks);
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_AddObjectToObject(root, "object"));
|
||||
|
||||
cJSON_InitHooks(NULL);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cJSON_add_array_should_add_array(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
cJSON *array = NULL;
|
||||
|
||||
cJSON_AddArrayToObject(root, "array");
|
||||
TEST_ASSERT_NOT_NULL(array = cJSON_GetObjectItemCaseSensitive(root, "array"));
|
||||
TEST_ASSERT_EQUAL_INT(array->type, cJSON_Array);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_array_should_fail_with_null_pointers(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_AddArrayToObject(NULL, "array"));
|
||||
TEST_ASSERT_NULL(cJSON_AddArrayToObject(root, NULL));
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_array_should_fail_on_allocation_failure(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
cJSON_InitHooks(&failing_hooks);
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_AddArrayToObject(root, "array"));
|
||||
|
||||
cJSON_InitHooks(NULL);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
|
||||
RUN_TEST(cjson_add_null_should_add_null);
|
||||
RUN_TEST(cjson_add_null_should_fail_with_null_pointers);
|
||||
RUN_TEST(cjson_add_null_should_fail_on_allocation_failure);
|
||||
|
||||
RUN_TEST(cjson_add_true_should_add_true);
|
||||
RUN_TEST(cjson_add_true_should_fail_with_null_pointers);
|
||||
RUN_TEST(cjson_add_true_should_fail_on_allocation_failure);
|
||||
|
||||
RUN_TEST(cjson_create_int_array_should_fail_on_allocation_failure);
|
||||
RUN_TEST(cjson_create_float_array_should_fail_on_allocation_failure);
|
||||
RUN_TEST(cjson_create_double_array_should_fail_on_allocation_failure);
|
||||
RUN_TEST(cjson_create_string_array_should_fail_on_allocation_failure);
|
||||
|
||||
RUN_TEST(cjson_add_false_should_add_false);
|
||||
RUN_TEST(cjson_add_false_should_fail_with_null_pointers);
|
||||
RUN_TEST(cjson_add_false_should_fail_on_allocation_failure);
|
||||
|
||||
RUN_TEST(cjson_add_bool_should_add_bool);
|
||||
RUN_TEST(cjson_add_bool_should_fail_with_null_pointers);
|
||||
RUN_TEST(cjson_add_bool_should_fail_on_allocation_failure);
|
||||
|
||||
RUN_TEST(cjson_add_number_should_add_number);
|
||||
RUN_TEST(cjson_add_number_should_fail_with_null_pointers);
|
||||
RUN_TEST(cjson_add_number_should_fail_on_allocation_failure);
|
||||
|
||||
RUN_TEST(cjson_add_string_should_add_string);
|
||||
RUN_TEST(cjson_add_string_should_fail_with_null_pointers);
|
||||
RUN_TEST(cjson_add_string_should_fail_on_allocation_failure);
|
||||
|
||||
RUN_TEST(cjson_add_raw_should_add_raw);
|
||||
RUN_TEST(cjson_add_raw_should_fail_with_null_pointers);
|
||||
RUN_TEST(cjson_add_raw_should_fail_on_allocation_failure);
|
||||
|
||||
RUN_TEST(cJSON_add_object_should_add_object);
|
||||
RUN_TEST(cjson_add_object_should_fail_with_null_pointers);
|
||||
RUN_TEST(cjson_add_object_should_fail_on_allocation_failure);
|
||||
|
||||
RUN_TEST(cJSON_add_array_should_add_array);
|
||||
RUN_TEST(cjson_add_array_should_fail_with_null_pointers);
|
||||
RUN_TEST(cjson_add_array_should_fail_on_allocation_failure);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
122
tests/common.h
Normal file
122
tests/common.h
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
void reset(cJSON *item);
|
||||
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));
|
||||
}
|
||||
|
||||
char* read_file(const char *filename);
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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
|
208
tests/compare_tests.c
Normal file
208
tests/compare_tests.c
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
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_TRUE(compare_from_string("1E100", "10E99", false));
|
||||
|
||||
TEST_ASSERT_FALSE(compare_from_string("0.5E-100", "0.5E-101", 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 CJSON_CDECL 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()"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
"width": 500,
|
||||
"height": 500
|
||||
},
|
||||
"image": {
|
||||
"image": {
|
||||
"src": "Images/Sun.png",
|
||||
"name": "sun1",
|
||||
"hOffset": 250,
|
||||
@ -23,4 +23,4 @@
|
||||
"alignment": "center",
|
||||
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
|
||||
}
|
||||
}}
|
||||
}}
|
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;"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
{"web-app": {
|
||||
"servlet": [
|
||||
"servlet": [
|
||||
{
|
||||
"servlet-name": "cofaxCDS",
|
||||
"servlet-class": "org.cofax.cds.CDSServlet",
|
||||
@ -55,7 +55,7 @@
|
||||
{
|
||||
"servlet-name": "cofaxAdmin",
|
||||
"servlet-class": "org.cofax.cds.AdminServlet"},
|
||||
|
||||
|
||||
{
|
||||
"servlet-name": "fileServlet",
|
||||
"servlet-class": "org.cofax.cds.FileServlet"},
|
||||
@ -82,7 +82,7 @@
|
||||
"cofaxAdmin": "/admin/*",
|
||||
"fileServlet": "/static/*",
|
||||
"cofaxTools": "/tools/*"},
|
||||
|
||||
|
||||
"taglib": {
|
||||
"taglib-uri": "cofax.tld",
|
||||
"taglib-location": "/WEB-INF/tlds/cofax.tld"}}}
|
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.
|
||||
|
91
tests/json-patch-tests/cjson-utils-tests.json
Normal file
91
tests/json-patch-tests/cjson-utils-tests.json
Normal file
@ -0,0 +1,91 @@
|
||||
[
|
||||
{
|
||||
"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"]] }
|
||||
},
|
||||
|
||||
{
|
||||
"comment": "15",
|
||||
"doc": {"foo": {"bar": 1}},
|
||||
"patch": [{"op": "add", "path": "/foo/bar/baz", "value": "5"}],
|
||||
"error": "attempting to add to subfield of non-object"
|
||||
}
|
||||
]
|
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"]]
|
||||
}
|
||||
}
|
||||
|
||||
]
|
464
tests/json-patch-tests/tests.json
Normal file
464
tests/json-patch-tests/tests.json
Normal file
@ -0,0 +1,464 @@
|
||||
[
|
||||
{ "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": "test replace with missing parent key should fail",
|
||||
"doc": {"bar": "baz"},
|
||||
"patch": [{"op": "replace", "path": "/foo/bar", "value": false}],
|
||||
"error": "replace op should fail with missing parent key" },
|
||||
|
||||
{ "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}],
|
||||
"expected": {"foo": 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}}],
|
||||
"expected": {"foo": {"foo": 1, "bar": 2}},
|
||||
"comment": "test should pass despite rearrangement" },
|
||||
|
||||
{ "doc": {"foo": [{"foo": 1, "bar": 2}]},
|
||||
"patch": [{"op": "test", "path": "/foo", "value": [{"bar": 2, "foo": 1}]}],
|
||||
"expected": {"foo": [{"foo": 1, "bar": 2}]},
|
||||
"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]}}],
|
||||
"expected": {"foo": {"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}],
|
||||
"expected": { "": 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}],
|
||||
"expected": {
|
||||
"": 0,
|
||||
" ": 7,
|
||||
"a/b": 1,
|
||||
"c%d": 2,
|
||||
"e^f": 3,
|
||||
"foo": [
|
||||
"bar",
|
||||
"baz"
|
||||
],
|
||||
"g|h": 4,
|
||||
"i\\j": 5,
|
||||
"k\"l": 6,
|
||||
"m~n": 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 location to copy",
|
||||
"doc": { "foo": 1 },
|
||||
"patch": [ { "op": "copy", "from": "/bar", "path": "/foo" } ],
|
||||
"error": "missing 'from' location" },
|
||||
|
||||
{ "comment": "missing from parameter to move",
|
||||
"doc": { "foo": 1 },
|
||||
"patch": [ { "op": "move", "path": "" } ],
|
||||
"error": "missing 'from' parameter" },
|
||||
|
||||
{ "comment": "missing from location to move",
|
||||
"doc": { "foo": 1 },
|
||||
"patch": [ { "op": "move", "from": "/bar", "path": "/foo" } ],
|
||||
"error": "missing 'from' location" },
|
||||
|
||||
{ "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 unknown\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();
|
||||
}
|
174
tests/minify_tests.c
Normal file
174
tests/minify_tests.c
Normal file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
Copyright (c) 2009-2019 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_minify_should_not_overflow_buffer(void)
|
||||
{
|
||||
char unclosed_multiline_comment[] = "/* bla";
|
||||
char pending_escape[] = "\"\\";
|
||||
|
||||
cJSON_Minify(unclosed_multiline_comment);
|
||||
TEST_ASSERT_EQUAL_STRING("", unclosed_multiline_comment);
|
||||
|
||||
cJSON_Minify(pending_escape);
|
||||
TEST_ASSERT_EQUAL_STRING("\"\\", pending_escape);
|
||||
}
|
||||
|
||||
static void cjson_minify_should_remove_single_line_comments(void)
|
||||
{
|
||||
const char to_minify[] = "{// this is {} \"some kind\" of [] comment /*, don't you see\n}";
|
||||
|
||||
char* minified = (char*) malloc(sizeof(to_minify));
|
||||
TEST_ASSERT_NOT_NULL(minified);
|
||||
strcpy(minified, to_minify);
|
||||
|
||||
cJSON_Minify(minified);
|
||||
TEST_ASSERT_EQUAL_STRING("{}", minified);
|
||||
|
||||
free(minified);
|
||||
}
|
||||
|
||||
static void cjson_minify_should_remove_spaces(void)
|
||||
{
|
||||
const char to_minify[] = "{ \"key\":\ttrue\r\n }";
|
||||
|
||||
char* minified = (char*) malloc(sizeof(to_minify));
|
||||
TEST_ASSERT_NOT_NULL(minified);
|
||||
strcpy(minified, to_minify);
|
||||
|
||||
cJSON_Minify(minified);
|
||||
TEST_ASSERT_EQUAL_STRING("{\"key\":true}", minified);
|
||||
|
||||
free(minified);
|
||||
}
|
||||
|
||||
static void cjson_minify_should_remove_multiline_comments(void)
|
||||
{
|
||||
const char to_minify[] = "{/* this is\n a /* multi\n //line \n {comment \"\\\" */}";
|
||||
|
||||
char* minified = (char*) malloc(sizeof(to_minify));
|
||||
TEST_ASSERT_NOT_NULL(minified);
|
||||
strcpy(minified, to_minify);
|
||||
|
||||
cJSON_Minify(minified);
|
||||
TEST_ASSERT_EQUAL_STRING("{}", minified);
|
||||
|
||||
free(minified);
|
||||
}
|
||||
|
||||
static void cjson_minify_should_not_modify_strings(void)
|
||||
{
|
||||
const char to_minify[] = "\"this is a string \\\" \\t bla\"";
|
||||
|
||||
char* minified = (char*) malloc(sizeof(to_minify));
|
||||
TEST_ASSERT_NOT_NULL(minified);
|
||||
strcpy(minified, to_minify);
|
||||
|
||||
cJSON_Minify(minified);
|
||||
TEST_ASSERT_EQUAL_STRING(to_minify, minified);
|
||||
|
||||
free(minified);
|
||||
}
|
||||
|
||||
static void cjson_minify_should_minify_json(void) {
|
||||
const char to_minify[] =
|
||||
"{\n"
|
||||
" \"glossary\": { // comment\n"
|
||||
" \"title\": \"example glossary\",\n"
|
||||
" /* multi\n"
|
||||
" line */\n"
|
||||
" \"GlossDiv\": {\n"
|
||||
" \"title\": \"S\",\n"
|
||||
" \"GlossList\": {\n"
|
||||
" \"GlossEntry\": {\n"
|
||||
" \"ID\": \"SGML\",\n"
|
||||
" \"SortAs\": \"SGML\",\n"
|
||||
" \"Acronym\": \"SGML\",\n"
|
||||
" \"Abbrev\": \"ISO 8879:1986\",\n"
|
||||
" \"GlossDef\": {\n"
|
||||
" \"GlossSeeAlso\": [\"GML\", \"XML\"]\n"
|
||||
" },\n"
|
||||
" \"GlossSee\": \"markup\"\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"}";
|
||||
const char* minified =
|
||||
"{"
|
||||
"\"glossary\":{"
|
||||
"\"title\":\"example glossary\","
|
||||
"\"GlossDiv\":{"
|
||||
"\"title\":\"S\","
|
||||
"\"GlossList\":{"
|
||||
"\"GlossEntry\":{"
|
||||
"\"ID\":\"SGML\","
|
||||
"\"SortAs\":\"SGML\","
|
||||
"\"Acronym\":\"SGML\","
|
||||
"\"Abbrev\":\"ISO 8879:1986\","
|
||||
"\"GlossDef\":{"
|
||||
"\"GlossSeeAlso\":[\"GML\",\"XML\"]"
|
||||
"},"
|
||||
"\"GlossSee\":\"markup\""
|
||||
"}"
|
||||
"}"
|
||||
"}"
|
||||
"}"
|
||||
"}";
|
||||
|
||||
char *buffer = (char*) malloc(sizeof(to_minify));
|
||||
strcpy(buffer, to_minify);
|
||||
|
||||
cJSON_Minify(buffer);
|
||||
TEST_ASSERT_EQUAL_STRING(minified, buffer);
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
static void cjson_minify_should_not_loop_infinitely(void) {
|
||||
char string[] = { '8', ' ', '/', ' ', '5', '\n', '\0' };
|
||||
/* this should not be an infinite loop */
|
||||
cJSON_Minify(string);
|
||||
}
|
||||
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
|
||||
RUN_TEST(cjson_minify_should_not_overflow_buffer);
|
||||
RUN_TEST(cjson_minify_should_minify_json);
|
||||
RUN_TEST(cjson_minify_should_remove_single_line_comments);
|
||||
RUN_TEST(cjson_minify_should_remove_multiline_comments);
|
||||
RUN_TEST(cjson_minify_should_remove_spaces);
|
||||
RUN_TEST(cjson_minify_should_not_modify_strings);
|
||||
RUN_TEST(cjson_minify_should_not_loop_infinitely);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
745
tests/misc_tests.c
Normal file
745
tests/misc_tests.c
Normal file
@ -0,0 +1,745 @@
|
||||
/*
|
||||
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 cjson_get_object_item_should_not_crash_with_array(void)
|
||||
{
|
||||
cJSON *array = NULL;
|
||||
cJSON *found = NULL;
|
||||
array = cJSON_Parse("[1]");
|
||||
|
||||
found = cJSON_GetObjectItem(array, "name");
|
||||
TEST_ASSERT_NULL(found);
|
||||
|
||||
cJSON_Delete(array);
|
||||
}
|
||||
|
||||
static void cjson_get_object_item_case_sensitive_should_not_crash_with_array(void)
|
||||
{
|
||||
cJSON *array = NULL;
|
||||
cJSON *found = NULL;
|
||||
array = cJSON_Parse("[1]");
|
||||
|
||||
found = cJSON_GetObjectItemCaseSensitive(array, "name");
|
||||
TEST_ASSERT_NULL(found);
|
||||
|
||||
cJSON_Delete(array);
|
||||
}
|
||||
|
||||
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]);
|
||||
list[0].prev = &(list[3]);
|
||||
|
||||
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 == &(list[3])) && (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_TRUE(replacements[0].prev == end);
|
||||
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;
|
||||
cJSON_bool flag = false;
|
||||
|
||||
child = cJSON_CreateNumber(1);
|
||||
TEST_ASSERT_NOT_NULL(child);
|
||||
replacement = cJSON_CreateNumber(2);
|
||||
TEST_ASSERT_NOT_NULL(replacement);
|
||||
|
||||
flag = cJSON_AddItemToObject(root, "child", child);
|
||||
TEST_ASSERT_TRUE_MESSAGE(flag, "add item to object failed");
|
||||
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_should_not_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);
|
||||
TEST_ASSERT_FALSE(cJSON_InsertItemInArray(NULL, 0, item));
|
||||
TEST_ASSERT_FALSE(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));
|
||||
TEST_ASSERT_FALSE(cJSON_ReplaceItemInArray(item, 0, NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_ReplaceItemInArray(NULL, 0, item));
|
||||
TEST_ASSERT_FALSE(cJSON_ReplaceItemInObject(NULL, "item", item));
|
||||
TEST_ASSERT_FALSE(cJSON_ReplaceItemInObject(item, NULL, item));
|
||||
TEST_ASSERT_FALSE(cJSON_ReplaceItemInObject(item, "item", NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_ReplaceItemInObjectCaseSensitive(NULL, "item", item));
|
||||
TEST_ASSERT_FALSE(cJSON_ReplaceItemInObjectCaseSensitive(item, NULL, item));
|
||||
TEST_ASSERT_FALSE(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);
|
||||
}
|
||||
|
||||
static void *CJSON_CDECL failing_realloc(void *pointer, size_t size)
|
||||
{
|
||||
(void)size;
|
||||
(void)pointer;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ensure_should_fail_on_failed_realloc(void)
|
||||
{
|
||||
printbuffer buffer = {NULL, 10, 0, 0, false, false, {&malloc, &free, &failing_realloc}};
|
||||
buffer.buffer = (unsigned char *)malloc(100);
|
||||
TEST_ASSERT_NOT_NULL(buffer.buffer);
|
||||
|
||||
TEST_ASSERT_NULL_MESSAGE(ensure(&buffer, 200), "Ensure didn't fail with failing realloc.");
|
||||
}
|
||||
|
||||
static void skip_utf8_bom_should_skip_bom(void)
|
||||
{
|
||||
const unsigned char string[] = "\xEF\xBB\xBF{}";
|
||||
parse_buffer buffer = {0, 0, 0, 0, {0, 0, 0}};
|
||||
buffer.content = string;
|
||||
buffer.length = sizeof(string);
|
||||
buffer.hooks = global_hooks;
|
||||
|
||||
TEST_ASSERT_TRUE(skip_utf8_bom(&buffer) == &buffer);
|
||||
TEST_ASSERT_EQUAL_UINT(3U, (unsigned int)buffer.offset);
|
||||
}
|
||||
|
||||
static void skip_utf8_bom_should_not_skip_bom_if_not_at_beginning(void)
|
||||
{
|
||||
const unsigned char string[] = " \xEF\xBB\xBF{}";
|
||||
parse_buffer buffer = {0, 0, 0, 0, {0, 0, 0}};
|
||||
buffer.content = string;
|
||||
buffer.length = sizeof(string);
|
||||
buffer.hooks = global_hooks;
|
||||
buffer.offset = 1;
|
||||
|
||||
TEST_ASSERT_NULL(skip_utf8_bom(&buffer));
|
||||
}
|
||||
|
||||
static void cjson_get_string_value_should_get_a_string(void)
|
||||
{
|
||||
cJSON *string = cJSON_CreateString("test");
|
||||
cJSON *number = cJSON_CreateNumber(1);
|
||||
|
||||
TEST_ASSERT_TRUE(cJSON_GetStringValue(string) == string->valuestring);
|
||||
TEST_ASSERT_NULL(cJSON_GetStringValue(number));
|
||||
TEST_ASSERT_NULL(cJSON_GetStringValue(NULL));
|
||||
|
||||
cJSON_Delete(number);
|
||||
cJSON_Delete(string);
|
||||
}
|
||||
|
||||
static void cjson_get_number_value_should_get_a_number(void)
|
||||
{
|
||||
cJSON *string = cJSON_CreateString("test");
|
||||
cJSON *number = cJSON_CreateNumber(1);
|
||||
|
||||
TEST_ASSERT_EQUAL_DOUBLE(cJSON_GetNumberValue(number), number->valuedouble);
|
||||
TEST_ASSERT_DOUBLE_IS_NAN(cJSON_GetNumberValue(string));
|
||||
TEST_ASSERT_DOUBLE_IS_NAN(cJSON_GetNumberValue(NULL));
|
||||
|
||||
cJSON_Delete(number);
|
||||
cJSON_Delete(string);
|
||||
}
|
||||
|
||||
static void cjson_create_string_reference_should_create_a_string_reference(void)
|
||||
{
|
||||
const char *string = "I am a string!";
|
||||
|
||||
cJSON *string_reference = cJSON_CreateStringReference(string);
|
||||
TEST_ASSERT_TRUE(string_reference->valuestring == string);
|
||||
TEST_ASSERT_EQUAL_INT(cJSON_IsReference | cJSON_String, string_reference->type);
|
||||
|
||||
cJSON_Delete(string_reference);
|
||||
}
|
||||
|
||||
static void cjson_create_object_reference_should_create_an_object_reference(void)
|
||||
{
|
||||
cJSON *number_reference = NULL;
|
||||
cJSON *number_object = cJSON_CreateObject();
|
||||
cJSON *number = cJSON_CreateNumber(42);
|
||||
const char key[] = "number";
|
||||
|
||||
TEST_ASSERT_TRUE(cJSON_IsNumber(number));
|
||||
TEST_ASSERT_TRUE(cJSON_IsObject(number_object));
|
||||
cJSON_AddItemToObjectCS(number_object, key, number);
|
||||
|
||||
number_reference = cJSON_CreateObjectReference(number);
|
||||
TEST_ASSERT_TRUE(number_reference->child == number);
|
||||
TEST_ASSERT_EQUAL_INT(cJSON_Object | cJSON_IsReference, number_reference->type);
|
||||
|
||||
cJSON_Delete(number_object);
|
||||
cJSON_Delete(number_reference);
|
||||
}
|
||||
|
||||
static void cjson_create_array_reference_should_create_an_array_reference(void)
|
||||
{
|
||||
cJSON *number_reference = NULL;
|
||||
cJSON *number_array = cJSON_CreateArray();
|
||||
cJSON *number = cJSON_CreateNumber(42);
|
||||
|
||||
TEST_ASSERT_TRUE(cJSON_IsNumber(number));
|
||||
TEST_ASSERT_TRUE(cJSON_IsArray(number_array));
|
||||
cJSON_AddItemToArray(number_array, number);
|
||||
|
||||
number_reference = cJSON_CreateArrayReference(number);
|
||||
TEST_ASSERT_TRUE(number_reference->child == number);
|
||||
TEST_ASSERT_EQUAL_INT(cJSON_Array | cJSON_IsReference, number_reference->type);
|
||||
|
||||
cJSON_Delete(number_array);
|
||||
cJSON_Delete(number_reference);
|
||||
}
|
||||
|
||||
static void cjson_add_item_to_object_or_array_should_not_add_itself(void)
|
||||
{
|
||||
cJSON *object = cJSON_CreateObject();
|
||||
cJSON *array = cJSON_CreateArray();
|
||||
cJSON_bool flag = false;
|
||||
|
||||
flag = cJSON_AddItemToObject(object, "key", object);
|
||||
TEST_ASSERT_FALSE_MESSAGE(flag, "add an object to itself should fail");
|
||||
|
||||
flag = cJSON_AddItemToArray(array, array);
|
||||
TEST_ASSERT_FALSE_MESSAGE(flag, "add an array to itself should fail");
|
||||
|
||||
cJSON_Delete(object);
|
||||
cJSON_Delete(array);
|
||||
}
|
||||
|
||||
static void cjson_add_item_to_object_should_not_use_after_free_when_string_is_aliased(void)
|
||||
{
|
||||
cJSON *object = cJSON_CreateObject();
|
||||
cJSON *number = cJSON_CreateNumber(42);
|
||||
char *name = (char *)cJSON_strdup((const unsigned char *)"number", &global_hooks);
|
||||
|
||||
TEST_ASSERT_NOT_NULL(object);
|
||||
TEST_ASSERT_NOT_NULL(number);
|
||||
TEST_ASSERT_NOT_NULL(name);
|
||||
|
||||
number->string = name;
|
||||
|
||||
/* The following should not have a use after free
|
||||
* that would show up in valgrind or with AddressSanitizer */
|
||||
cJSON_AddItemToObject(object, number->string, number);
|
||||
|
||||
cJSON_Delete(object);
|
||||
}
|
||||
|
||||
static void cjson_delete_item_from_array_should_not_broken_list_structure(void)
|
||||
{
|
||||
const char expected_json1[] = "{\"rd\":[{\"a\":\"123\"}]}";
|
||||
const char expected_json2[] = "{\"rd\":[{\"a\":\"123\"},{\"b\":\"456\"}]}";
|
||||
const char expected_json3[] = "{\"rd\":[{\"b\":\"456\"}]}";
|
||||
char *str1 = NULL;
|
||||
char *str2 = NULL;
|
||||
char *str3 = NULL;
|
||||
|
||||
cJSON *root = cJSON_Parse("{}");
|
||||
|
||||
cJSON *array = cJSON_AddArrayToObject(root, "rd");
|
||||
cJSON *item1 = cJSON_Parse("{\"a\":\"123\"}");
|
||||
cJSON *item2 = cJSON_Parse("{\"b\":\"456\"}");
|
||||
|
||||
cJSON_AddItemToArray(array, item1);
|
||||
str1 = cJSON_PrintUnformatted(root);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_json1, str1);
|
||||
free(str1);
|
||||
|
||||
cJSON_AddItemToArray(array, item2);
|
||||
str2 = cJSON_PrintUnformatted(root);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_json2, str2);
|
||||
free(str2);
|
||||
|
||||
/* this should not broken list structure */
|
||||
cJSON_DeleteItemFromArray(array, 0);
|
||||
str3 = cJSON_PrintUnformatted(root);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_json3, str3);
|
||||
free(str3);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_set_valuestring_to_object_should_not_leak_memory(void)
|
||||
{
|
||||
cJSON *root = cJSON_Parse("{}");
|
||||
const char *stringvalue = "valuestring could be changed safely";
|
||||
const char *reference_valuestring = "reference item should be freed by yourself";
|
||||
const char *short_valuestring = "shorter valuestring";
|
||||
const char *long_valuestring = "new valuestring which much longer than previous should be changed safely";
|
||||
cJSON *item1 = cJSON_CreateString(stringvalue);
|
||||
cJSON *item2 = cJSON_CreateStringReference(reference_valuestring);
|
||||
char *ptr1 = NULL;
|
||||
char *return_value = NULL;
|
||||
|
||||
cJSON_AddItemToObject(root, "one", item1);
|
||||
cJSON_AddItemToObject(root, "two", item2);
|
||||
|
||||
ptr1 = item1->valuestring;
|
||||
return_value = cJSON_SetValuestring(cJSON_GetObjectItem(root, "one"), short_valuestring);
|
||||
TEST_ASSERT_NOT_NULL(return_value);
|
||||
TEST_ASSERT_EQUAL_PTR_MESSAGE(ptr1, return_value, "new valuestring shorter than old should not reallocate memory");
|
||||
TEST_ASSERT_EQUAL_STRING(short_valuestring, cJSON_GetObjectItem(root, "one")->valuestring);
|
||||
|
||||
/* we needn't to free the original valuestring manually */
|
||||
ptr1 = item1->valuestring;
|
||||
return_value = cJSON_SetValuestring(cJSON_GetObjectItem(root, "one"), long_valuestring);
|
||||
TEST_ASSERT_NOT_NULL(return_value);
|
||||
TEST_ASSERT_NOT_EQUAL_MESSAGE(ptr1, return_value, "new valuestring longer than old should reallocate memory")
|
||||
TEST_ASSERT_EQUAL_STRING(long_valuestring, cJSON_GetObjectItem(root, "one")->valuestring);
|
||||
|
||||
return_value = cJSON_SetValuestring(cJSON_GetObjectItem(root, "two"), long_valuestring);
|
||||
TEST_ASSERT_NULL_MESSAGE(return_value, "valuestring of reference object should not be changed");
|
||||
TEST_ASSERT_EQUAL_STRING(reference_valuestring, cJSON_GetObjectItem(root, "two")->valuestring);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_set_bool_value_must_not_break_objects(void)
|
||||
{
|
||||
cJSON *bobj, *sobj, *oobj, *refobj = NULL;
|
||||
|
||||
TEST_ASSERT_TRUE((cJSON_SetBoolValue(refobj, 1) == cJSON_Invalid));
|
||||
|
||||
bobj = cJSON_CreateFalse();
|
||||
TEST_ASSERT_TRUE(cJSON_IsFalse(bobj));
|
||||
TEST_ASSERT_TRUE((cJSON_SetBoolValue(bobj, 1) == cJSON_True));
|
||||
TEST_ASSERT_TRUE(cJSON_IsTrue(bobj));
|
||||
cJSON_SetBoolValue(bobj, 1);
|
||||
TEST_ASSERT_TRUE(cJSON_IsTrue(bobj));
|
||||
TEST_ASSERT_TRUE((cJSON_SetBoolValue(bobj, 0) == cJSON_False));
|
||||
TEST_ASSERT_TRUE(cJSON_IsFalse(bobj));
|
||||
cJSON_SetBoolValue(bobj, 0);
|
||||
TEST_ASSERT_TRUE(cJSON_IsFalse(bobj));
|
||||
|
||||
sobj = cJSON_CreateString("test");
|
||||
TEST_ASSERT_TRUE(cJSON_IsString(sobj));
|
||||
cJSON_SetBoolValue(sobj, 1);
|
||||
TEST_ASSERT_TRUE(cJSON_IsString(sobj));
|
||||
cJSON_SetBoolValue(sobj, 0);
|
||||
TEST_ASSERT_TRUE(cJSON_IsString(sobj));
|
||||
|
||||
oobj = cJSON_CreateObject();
|
||||
TEST_ASSERT_TRUE(cJSON_IsObject(oobj));
|
||||
cJSON_SetBoolValue(oobj, 1);
|
||||
TEST_ASSERT_TRUE(cJSON_IsObject(oobj));
|
||||
cJSON_SetBoolValue(oobj, 0);
|
||||
TEST_ASSERT_TRUE(cJSON_IsObject(oobj));
|
||||
|
||||
refobj = cJSON_CreateStringReference("conststring");
|
||||
TEST_ASSERT_TRUE(cJSON_IsString(refobj));
|
||||
TEST_ASSERT_TRUE(refobj->type & cJSON_IsReference);
|
||||
cJSON_SetBoolValue(refobj, 1);
|
||||
TEST_ASSERT_TRUE(cJSON_IsString(refobj));
|
||||
TEST_ASSERT_TRUE(refobj->type & cJSON_IsReference);
|
||||
cJSON_SetBoolValue(refobj, 0);
|
||||
TEST_ASSERT_TRUE(cJSON_IsString(refobj));
|
||||
TEST_ASSERT_TRUE(refobj->type & cJSON_IsReference);
|
||||
cJSON_Delete(refobj);
|
||||
|
||||
refobj = cJSON_CreateObjectReference(oobj);
|
||||
TEST_ASSERT_TRUE(cJSON_IsObject(refobj));
|
||||
TEST_ASSERT_TRUE(refobj->type & cJSON_IsReference);
|
||||
cJSON_SetBoolValue(refobj, 1);
|
||||
TEST_ASSERT_TRUE(cJSON_IsObject(refobj));
|
||||
TEST_ASSERT_TRUE(refobj->type & cJSON_IsReference);
|
||||
cJSON_SetBoolValue(refobj, 0);
|
||||
TEST_ASSERT_TRUE(cJSON_IsObject(refobj));
|
||||
TEST_ASSERT_TRUE(refobj->type & cJSON_IsReference);
|
||||
cJSON_Delete(refobj);
|
||||
|
||||
cJSON_Delete(oobj);
|
||||
cJSON_Delete(bobj);
|
||||
cJSON_Delete(sobj);
|
||||
}
|
||||
|
||||
int CJSON_CDECL 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(cjson_get_object_item_should_not_crash_with_array);
|
||||
RUN_TEST(cjson_get_object_item_case_sensitive_should_not_crash_with_array);
|
||||
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_should_not_crash_with_null_pointers);
|
||||
RUN_TEST(ensure_should_fail_on_failed_realloc);
|
||||
RUN_TEST(skip_utf8_bom_should_skip_bom);
|
||||
RUN_TEST(skip_utf8_bom_should_not_skip_bom_if_not_at_beginning);
|
||||
RUN_TEST(cjson_get_string_value_should_get_a_string);
|
||||
RUN_TEST(cjson_get_number_value_should_get_a_number);
|
||||
RUN_TEST(cjson_create_string_reference_should_create_a_string_reference);
|
||||
RUN_TEST(cjson_create_object_reference_should_create_an_object_reference);
|
||||
RUN_TEST(cjson_create_array_reference_should_create_an_array_reference);
|
||||
RUN_TEST(cjson_add_item_to_object_or_array_should_not_add_itself);
|
||||
RUN_TEST(cjson_add_item_to_object_should_not_use_after_free_when_string_is_aliased);
|
||||
RUN_TEST(cjson_delete_item_from_array_should_not_broken_list_structure);
|
||||
RUN_TEST(cjson_set_valuestring_to_object_should_not_leak_memory);
|
||||
RUN_TEST(cjson_set_bool_value_must_not_break_objects);
|
||||
|
||||
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();
|
||||
}
|
225
tests/old_utils_tests.c
Normal file
225
tests/old_utils_tests.c
Normal file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
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 *object1 = NULL;
|
||||
cJSON *object2 = NULL;
|
||||
cJSON *object3 = NULL;
|
||||
cJSON *object4 = 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);
|
||||
|
||||
object1 = cJSON_CreateObject();
|
||||
object2 = cJSON_CreateString("m~n");
|
||||
cJSON_AddItemToObject(object1, "m~n", object2);
|
||||
pointer = cJSONUtils_FindPointerFromObjectTo(object1, object2);
|
||||
TEST_ASSERT_EQUAL_STRING("/m~0n",pointer);
|
||||
free(pointer);
|
||||
|
||||
object3 = cJSON_CreateObject();
|
||||
object4 = cJSON_CreateString("m/n");
|
||||
cJSON_AddItemToObject(object3, "m/n", object4);
|
||||
pointer = cJSONUtils_FindPointerFromObjectTo(object3, object4);
|
||||
TEST_ASSERT_EQUAL_STRING("/m~1n",pointer);
|
||||
free(pointer);
|
||||
|
||||
cJSON_Delete(object);
|
||||
cJSON_Delete(object1);
|
||||
cJSON_Delete(object3);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
167
tests/parse_array.c
Normal file
167
tests/parse_array.c
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
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);
|
||||
TEST_ASSERT_NOT_NULL(item->child);
|
||||
assert_has_type(item->child, cJSON_Array);
|
||||
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 CJSON_CDECL 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();
|
||||
}
|
271
tests/parse_examples.c
Normal file
271
tests/parse_examples.c
Normal file
@ -0,0 +1,271 @@
|
||||
/*
|
||||
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_PTR_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");
|
||||
}
|
||||
|
||||
static void test12_should_not_be_parsed(void)
|
||||
{
|
||||
const char *test12 = "{ \"name\": ";
|
||||
cJSON *tree = NULL;
|
||||
|
||||
tree = cJSON_Parse(test12);
|
||||
TEST_ASSERT_NULL_MESSAGE(tree, "Should fail to parse incomplete JSON.");
|
||||
|
||||
TEST_ASSERT_EQUAL_PTR_MESSAGE(test12 + strlen(test12), cJSON_GetErrorPtr(), "Error pointer is incorrect.");
|
||||
|
||||
if (tree != NULL)
|
||||
{
|
||||
cJSON_Delete(tree);
|
||||
}
|
||||
}
|
||||
|
||||
static void test13_should_be_parsed_without_null_termination(void)
|
||||
{
|
||||
cJSON *tree = NULL;
|
||||
const char test_13[] = "{" \
|
||||
"\"Image\":{" \
|
||||
"\"Width\":800," \
|
||||
"\"Height\":600," \
|
||||
"\"Title\":\"Viewfrom15thFloor\"," \
|
||||
"\"Thumbnail\":{" \
|
||||
"\"Url\":\"http:/*www.example.com/image/481989943\"," \
|
||||
"\"Height\":125," \
|
||||
"\"Width\":\"100\"" \
|
||||
"}," \
|
||||
"\"IDs\":[116,943,234,38793]" \
|
||||
"}" \
|
||||
"}";
|
||||
|
||||
char test_13_wo_null[sizeof(test_13) - 1];
|
||||
memcpy(test_13_wo_null, test_13, sizeof(test_13) - 1);
|
||||
|
||||
tree = cJSON_ParseWithLength(test_13_wo_null, sizeof(test_13) - 1);
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(tree, "Failed to parse valid json.");
|
||||
|
||||
if (tree != NULL)
|
||||
{
|
||||
cJSON_Delete(tree);
|
||||
}
|
||||
}
|
||||
|
||||
static void test14_should_not_be_parsed(void)
|
||||
{
|
||||
cJSON *tree = NULL;
|
||||
const char test_14[] = "{" \
|
||||
"\"Image\":{" \
|
||||
"\"Width\":800," \
|
||||
"\"Height\":600," \
|
||||
"\"Title\":\"Viewfrom15thFloor\"," \
|
||||
"\"Thumbnail\":{" \
|
||||
"\"Url\":\"http:/*www.example.com/image/481989943\"," \
|
||||
"\"Height\":125," \
|
||||
"\"Width\":\"100\"" \
|
||||
"}," \
|
||||
"\"IDs\":[116,943,234,38793]" \
|
||||
"}" \
|
||||
"}";
|
||||
|
||||
tree = cJSON_ParseWithLength(test_14, sizeof(test_14) - 2);
|
||||
TEST_ASSERT_NULL_MESSAGE(tree, "Should not continue after buffer_length is reached.");
|
||||
|
||||
if (tree != NULL)
|
||||
{
|
||||
cJSON_Delete(tree);
|
||||
}
|
||||
}
|
||||
|
||||
int CJSON_CDECL 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);
|
||||
RUN_TEST(test12_should_not_be_parsed);
|
||||
RUN_TEST(test13_should_be_parsed_without_null_termination);
|
||||
RUN_TEST(test14_should_not_be_parsed);
|
||||
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 CJSON_CDECL 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 CJSON_CDECL 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 CJSON_CDECL 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 CJSON_CDECL 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 CJSON_CDECL 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();
|
||||
}
|
112
tests/parse_with_opts.c
Normal file
112
tests/parse_with_opts.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 "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));
|
||||
TEST_ASSERT_EQUAL_PTR(empty_string, cJSON_GetErrorPtr());
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_ParseWithOpts(empty_string, &error_pointer, false));
|
||||
TEST_ASSERT_EQUAL_PTR(empty_string, error_pointer);
|
||||
TEST_ASSERT_EQUAL_PTR(empty_string, cJSON_GetErrorPtr());
|
||||
}
|
||||
|
||||
static void parse_with_opts_should_handle_incomplete_json(void)
|
||||
{
|
||||
const char json[] = "{ \"name\": ";
|
||||
const char *parse_end = NULL;
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_ParseWithOpts(json, &parse_end, false));
|
||||
TEST_ASSERT_EQUAL_PTR(json + strlen(json), parse_end);
|
||||
TEST_ASSERT_EQUAL_PTR(json + strlen(json), cJSON_GetErrorPtr());
|
||||
}
|
||||
|
||||
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_PTR(json + 2, parse_end);
|
||||
cJSON_Delete(item);
|
||||
}
|
||||
|
||||
static void parse_with_opts_should_parse_utf8_bom(void)
|
||||
{
|
||||
cJSON *with_bom = NULL;
|
||||
cJSON *without_bom = NULL;
|
||||
|
||||
with_bom = cJSON_ParseWithOpts("\xEF\xBB\xBF{}", NULL, true);
|
||||
TEST_ASSERT_NOT_NULL(with_bom);
|
||||
without_bom = cJSON_ParseWithOpts("{}", NULL, true);
|
||||
TEST_ASSERT_NOT_NULL(with_bom);
|
||||
|
||||
TEST_ASSERT_TRUE(cJSON_Compare(with_bom, without_bom, true));
|
||||
|
||||
cJSON_Delete(with_bom);
|
||||
cJSON_Delete(without_bom);
|
||||
}
|
||||
|
||||
int CJSON_CDECL 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_handle_incomplete_json);
|
||||
RUN_TEST(parse_with_opts_should_require_null_if_requested);
|
||||
RUN_TEST(parse_with_opts_should_return_parse_end);
|
||||
RUN_TEST(parse_with_opts_should_parse_utf8_bom);
|
||||
|
||||
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 CJSON_CDECL 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();
|
||||
}
|
125
tests/print_number.c
Normal file
125
tests/print_number.c
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "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];
|
||||
unsigned char new_buffer[26];
|
||||
unsigned int i = 0;
|
||||
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;
|
||||
buffer.buffer = new_buffer;
|
||||
|
||||
memset(item, 0, sizeof(item));
|
||||
memset(new_buffer, 0, sizeof(new_buffer));
|
||||
cJSON_SetNumberValue(item, input);
|
||||
TEST_ASSERT_TRUE_MESSAGE(print_number(item, &buffer), "Failed to print number.");
|
||||
|
||||
/* In MinGW or visual studio(before 2015),the exponten is represented using three digits,like:"1e-009","1e+017"
|
||||
* remove extra "0" to output "1e-09" or "1e+17",which makes testcase PASS */
|
||||
for(i = 0;i <sizeof(new_buffer);i++)
|
||||
{
|
||||
if(i >3 && new_buffer[i] =='0')
|
||||
{
|
||||
if((new_buffer[i-3] =='e' && new_buffer[i-2] == '-' && new_buffer[i] =='0') ||(new_buffer[i-2] =='e' && new_buffer[i-1] =='+'))
|
||||
{
|
||||
while(new_buffer[i] !='\0')
|
||||
{
|
||||
new_buffer[i] = new_buffer[i+1];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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 CJSON_CDECL 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 CJSON_CDECL 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 CJSON_CDECL 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 CJSON_CDECL 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();
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user