1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* util/support/t_json.c - JSON test program */ 3 /* 4 * Copyright (c) 2010 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Portions Copyright (c) 2010 Apple Inc. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * 3. Neither the name of the Institute nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 /* 38 * Copyright (C) 2012 by the Massachusetts Institute of Technology. 39 * All rights reserved. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 45 * * Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 48 * * Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in 50 * the documentation and/or other materials provided with the 51 * distribution. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 54 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 55 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 56 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 57 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 58 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 59 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 60 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 62 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 63 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 64 * OF THE POSSIBILITY OF SUCH DAMAGE. 65 */ 66 67 #include <errno.h> 68 #include <stdio.h> 69 #include <stdlib.h> 70 #include <string.h> 71 72 #include <k5-json.h> 73 74 static void 75 err(const char *str) 76 { 77 fprintf(stderr, "%s\n", str); 78 exit(1); 79 } 80 81 static void 82 check(int pred, const char *str) 83 { 84 if (!pred) 85 err(str); 86 } 87 88 static void 89 test_array() 90 { 91 k5_json_string v1; 92 k5_json_number v2; 93 k5_json_null v3; 94 k5_json_array a; 95 k5_json_value v; 96 97 k5_json_array_create(&a); 98 k5_json_string_create("abc", &v1); 99 k5_json_array_add(a, v1); 100 k5_json_number_create(2, &v2); 101 k5_json_array_add(a, v2); 102 k5_json_null_create(&v3); 103 k5_json_array_add(a, v3); 104 105 check(k5_json_array_length(a) == 3, "array length"); 106 v = k5_json_array_get(a, 2); 107 check(k5_json_get_tid(v) == K5_JSON_TID_NULL, "array[2] tid"); 108 v = k5_json_array_get(a, 1); 109 check(k5_json_get_tid(v) == K5_JSON_TID_NUMBER, "array[1] tid"); 110 check(k5_json_number_value(v) == 2, "array[1] value"); 111 v = k5_json_array_get(a, 0); 112 check(k5_json_get_tid(v) == K5_JSON_TID_STRING, "array[0] tid"); 113 check(strcmp(k5_json_string_utf8(v), "abc") == 0, "array[0] value"); 114 115 k5_json_release(v1); 116 k5_json_release(v2); 117 k5_json_release(a); 118 119 k5_json_array_fmt(&a, "vnbiLssB", v3, 1, 9, (long long)-6, "def", NULL, 120 (void *)"ghij", (size_t)4); 121 v = k5_json_array_get(a, 0); 122 check(k5_json_get_tid(v) == K5_JSON_TID_NULL, "fmt array[0] tid"); 123 v = k5_json_array_get(a, 1); 124 check(k5_json_get_tid(v) == K5_JSON_TID_NULL, "fmt array[1] tid"); 125 v = k5_json_array_get(a, 2); 126 check(k5_json_get_tid(v) == K5_JSON_TID_BOOL, "fmt array[2] tid"); 127 check(k5_json_bool_value(v), "fmt array[2] value"); 128 v = k5_json_array_get(a, 3); 129 check(k5_json_get_tid(v) == K5_JSON_TID_NUMBER, "fmt array[3] tid"); 130 check(k5_json_number_value(v) == 9, "fmt array[3] value"); 131 v = k5_json_array_get(a, 4); 132 check(k5_json_get_tid(v) == K5_JSON_TID_NUMBER, "fmt array[4] tid"); 133 check(k5_json_number_value(v) == -6, "fmt array[4] value"); 134 v = k5_json_array_get(a, 5); 135 check(k5_json_get_tid(v) == K5_JSON_TID_STRING, "fmt array[5] tid"); 136 check(strcmp(k5_json_string_utf8(v), "def") == 0, "fmt array[5] value"); 137 v = k5_json_array_get(a, 6); 138 check(k5_json_get_tid(v) == K5_JSON_TID_NULL, "fmt array[6] tid"); 139 v = k5_json_array_get(a, 7); 140 check(k5_json_get_tid(v) == K5_JSON_TID_STRING, "fmt array[7] tid"); 141 check(strcmp(k5_json_string_utf8(v), "Z2hpag==") == 0, 142 "fmt array[7] value"); 143 k5_json_release(v3); 144 k5_json_release(a); 145 } 146 147 static void 148 test_object(void) 149 { 150 k5_json_object object; 151 k5_json_number n, v1; 152 k5_json_string s, v2; 153 154 k5_json_object_create(&object); 155 k5_json_number_create(1, &v1); 156 k5_json_object_set(object, "key1", v1); 157 k5_json_string_create("hejsan", &v2); 158 k5_json_object_set(object, "key2", v2); 159 160 n = k5_json_object_get(object, "key1"); 161 if (k5_json_number_value(n) != 1) 162 err("Retrieving key1 from object failed"); 163 164 s = k5_json_object_get(object, "key2"); 165 if (strcmp(k5_json_string_utf8(s), "hejsan") != 0) 166 err("Retrieving key2 from object failed"); 167 168 check(k5_json_object_get(object, "key3") == NULL, 169 "object nonexistent key"); 170 171 k5_json_object_set(object, "key1", NULL); 172 check(k5_json_object_get(object, "key1") == NULL, 173 "object removed key"); 174 check(k5_json_object_get(object, "key2") != NULL, 175 "object remaining key"); 176 177 k5_json_release(v1); 178 k5_json_release(v2); 179 k5_json_release(object); 180 } 181 182 static void 183 test_string(void) 184 { 185 k5_json_string s1, s2, s3; 186 unsigned char *data; 187 size_t len; 188 189 k5_json_string_create("hejsan", &s1); 190 k5_json_string_create("hejsan", &s2); 191 k5_json_string_create_base64("55555", 5, &s3); 192 193 if (strcmp(k5_json_string_utf8(s1), k5_json_string_utf8(s2)) != 0) 194 err("Identical strings are not identical"); 195 if (strcmp(k5_json_string_utf8(s3), "NTU1NTU=") != 0) 196 err("base64 string has incorrect value"); 197 k5_json_string_unbase64(s3, &data, &len); 198 if (len != 5 || memcmp(data, "55555", 5) != 0) 199 err("base64 string doesn't decode to correct value"); 200 free(data); 201 202 k5_json_release(s1); 203 k5_json_release(s2); 204 k5_json_release(s3); 205 } 206 207 static void 208 test_json(void) 209 { 210 static char *tests[] = { 211 "{\"k1\":\"s1\",\"k2\":\"s2\"}", 212 "{\"k1\":[\"s1\",\"s2\",\"s3\"],\"k2\":\"s3\"}", 213 "{\"k1\":{\"k2\":\"s1\",\"k3\":\"s2\",\"k4\":\"s3\"},\"k5\":\"s4\"}", 214 "[\"v1\",\"v2\",[\"v3\",\"v4\",[\"v 5\",\" v 7 \"]],-123456789," 215 "null,true,false,123456789,\"\"]", 216 "-1", 217 "\"\\\\abc\\\"\\nde\\b\\r/\\ff\\tghi\\u0001\\u001F\"", 218 "9223372036854775807", 219 "-9223372036854775808", 220 NULL 221 }; 222 char **tptr, *s, *enc, *p, orig; 223 int i; 224 k5_json_value v, v2; 225 226 check(k5_json_decode("\"string\"", &v) == 0, "string1"); 227 check(k5_json_get_tid(v) == K5_JSON_TID_STRING, "string1 tid"); 228 check(strcmp(k5_json_string_utf8(v), "string") == 0, "string1 utf8"); 229 k5_json_release(v); 230 231 check(k5_json_decode("\t \"foo\\\"bar\" ", &v) == 0, "string2"); 232 check(k5_json_get_tid(v) == K5_JSON_TID_STRING, "string2 tid"); 233 check(strcmp(k5_json_string_utf8(v), "foo\"bar") == 0, "string2 utf8"); 234 k5_json_release(v); 235 236 check(k5_json_decode(" { \"key\" : \"value\" }", &v) == 0, "object1"); 237 check(k5_json_get_tid(v) == K5_JSON_TID_OBJECT, "object1 tid"); 238 v2 = k5_json_object_get(v, "key"); 239 check(v2 != NULL, "object[key]"); 240 check(k5_json_get_tid(v2) == K5_JSON_TID_STRING, "object1[key] tid"); 241 check(strcmp(k5_json_string_utf8(v2), "value") == 0, "object1[key] utf8"); 242 k5_json_release(v); 243 244 check(k5_json_decode("{ \"k1\" : { \"k2\" : \"s2\", \"k3\" : \"s3\" }, " 245 "\"k4\" : \"s4\" }", &v) == 0, "object2"); 246 v2 = k5_json_object_get(v, "k1"); 247 check(v2 != NULL, "object2[k1]"); 248 check(k5_json_get_tid(v2) == K5_JSON_TID_OBJECT, "object2[k1] tid"); 249 v2 = k5_json_object_get(v2, "k3"); 250 check(v2 != NULL, "object2[k1][k3]"); 251 check(k5_json_get_tid(v2) == K5_JSON_TID_STRING, "object2[k1][k3] tid"); 252 check(strcmp(k5_json_string_utf8(v2), "s3") == 0, "object2[k1][k3] utf8"); 253 k5_json_release(v); 254 255 check(k5_json_decode("{ \"k1\" : 1 }", &v) == 0, "object3"); 256 check(k5_json_get_tid(v) == K5_JSON_TID_OBJECT, "object3 id"); 257 v2 = k5_json_object_get(v, "k1"); 258 check(k5_json_get_tid(v2) == K5_JSON_TID_NUMBER, "object3[k1] tid"); 259 check(k5_json_number_value(v2) == 1, "object3[k1] value"); 260 k5_json_release(v); 261 262 check(k5_json_decode("-10", &v) == 0, "number1"); 263 check(k5_json_get_tid(v) == K5_JSON_TID_NUMBER, "number1 tid"); 264 check(k5_json_number_value(v) == -10, "number1 value"); 265 k5_json_release(v); 266 267 check(k5_json_decode("99", &v) == 0, "number2"); 268 check(k5_json_get_tid(v) == K5_JSON_TID_NUMBER, "number2 tid"); 269 check(k5_json_number_value(v) == 99, "number2 value"); 270 k5_json_release(v); 271 272 check(k5_json_decode(" [ 1 ]", &v) == 0, "array1"); 273 check(k5_json_get_tid(v) == K5_JSON_TID_ARRAY, "array1 tid"); 274 check(k5_json_array_length(v) == 1, "array1 len"); 275 v2 = k5_json_array_get(v, 0); 276 check(v2 != NULL, "array1[0]"); 277 check(k5_json_get_tid(v2) == K5_JSON_TID_NUMBER, "array1[0] tid"); 278 check(k5_json_number_value(v2) == 1, "array1[0] value"); 279 k5_json_release(v); 280 281 check(k5_json_decode(" [ -1 ]", &v) == 0, "array2"); 282 check(k5_json_get_tid(v) == K5_JSON_TID_ARRAY, "array2 tid"); 283 check(k5_json_array_length(v) == 1, "array2 len"); 284 v2 = k5_json_array_get(v, 0); 285 check(v2 != NULL, "array2[0]"); 286 check(k5_json_get_tid(v2) == K5_JSON_TID_NUMBER, "array2[0] tid"); 287 check(k5_json_number_value(v2) == -1, "array2[0] value"); 288 k5_json_release(v); 289 290 check(k5_json_decode("18446744073709551616", &v) == EOVERFLOW, 291 "unsigned 64-bit overflow"); 292 check(k5_json_decode("9223372036854775808", &v) == EOVERFLOW, 293 "signed 64-bit positive overflow"); 294 check(k5_json_decode("-9223372036854775809", &v) == EOVERFLOW, 295 "signed 64-bit negative overflow"); 296 297 for (tptr = tests; *tptr != NULL; tptr++) { 298 s = strdup(*tptr); 299 if (k5_json_decode(s, &v)) 300 err(s); 301 if (k5_json_encode(v, &enc) || strcmp(enc, s) != 0) 302 err(s); 303 free(enc); 304 k5_json_release(v); 305 306 /* Fuzz bytes. Parsing may succeed or fail; we're just looking for 307 * memory access bugs. */ 308 for (p = s; *p != '\0'; p++) { 309 orig = *p; 310 for (i = 0; i <= 255; i++) { 311 *p = i; 312 k5_json_decode(s, &v); 313 k5_json_release(v); 314 } 315 *p = orig; 316 } 317 free(s); 318 } 319 } 320 321 int 322 main(int argc, char **argv) 323 { 324 test_array(); 325 test_object(); 326 test_string(); 327 test_json(); 328 return 0; 329 } 330