1 #include "test/jemalloc_test.h" 2 #include "jemalloc/internal/emitter.h" 3 4 /* 5 * This is so useful for debugging and feature work, we'll leave printing 6 * functionality committed but disabled by default. 7 */ 8 /* Print the text as it will appear. */ 9 static bool print_raw = false; 10 /* Print the text escaped, so it can be copied back into the test case. */ 11 static bool print_escaped = false; 12 13 typedef struct buf_descriptor_s buf_descriptor_t; 14 struct buf_descriptor_s { 15 char *buf; 16 size_t len; 17 bool mid_quote; 18 }; 19 20 /* 21 * Forwards all writes to the passed-in buf_v (which should be cast from a 22 * buf_descriptor_t *). 23 */ 24 static void 25 forwarding_cb(void *buf_descriptor_v, const char *str) { 26 buf_descriptor_t *buf_descriptor = (buf_descriptor_t *)buf_descriptor_v; 27 28 if (print_raw) { 29 malloc_printf("%s", str); 30 } 31 if (print_escaped) { 32 const char *it = str; 33 while (*it != '\0') { 34 if (!buf_descriptor->mid_quote) { 35 malloc_printf("\""); 36 buf_descriptor->mid_quote = true; 37 } 38 switch (*it) { 39 case '\\': 40 malloc_printf("\\"); 41 break; 42 case '\"': 43 malloc_printf("\\\""); 44 break; 45 case '\t': 46 malloc_printf("\\t"); 47 break; 48 case '\n': 49 malloc_printf("\\n\"\n"); 50 buf_descriptor->mid_quote = false; 51 break; 52 default: 53 malloc_printf("%c", *it); 54 } 55 it++; 56 } 57 } 58 59 size_t written = malloc_snprintf(buf_descriptor->buf, 60 buf_descriptor->len, "%s", str); 61 expect_zu_eq(written, strlen(str), "Buffer overflow!"); 62 buf_descriptor->buf += written; 63 buf_descriptor->len -= written; 64 expect_zu_gt(buf_descriptor->len, 0, "Buffer out of space!"); 65 } 66 67 static void 68 expect_emit_output(void (*emit_fn)(emitter_t *), 69 const char *expected_json_output, 70 const char *expected_json_compact_output, 71 const char *expected_table_output) { 72 emitter_t emitter; 73 char buf[MALLOC_PRINTF_BUFSIZE]; 74 buf_descriptor_t buf_descriptor; 75 76 buf_descriptor.buf = buf; 77 buf_descriptor.len = MALLOC_PRINTF_BUFSIZE; 78 buf_descriptor.mid_quote = false; 79 80 emitter_init(&emitter, emitter_output_json, &forwarding_cb, 81 &buf_descriptor); 82 (*emit_fn)(&emitter); 83 expect_str_eq(expected_json_output, buf, "json output failure"); 84 85 buf_descriptor.buf = buf; 86 buf_descriptor.len = MALLOC_PRINTF_BUFSIZE; 87 buf_descriptor.mid_quote = false; 88 89 emitter_init(&emitter, emitter_output_json_compact, &forwarding_cb, 90 &buf_descriptor); 91 (*emit_fn)(&emitter); 92 expect_str_eq(expected_json_compact_output, buf, 93 "compact json output failure"); 94 95 buf_descriptor.buf = buf; 96 buf_descriptor.len = MALLOC_PRINTF_BUFSIZE; 97 buf_descriptor.mid_quote = false; 98 99 emitter_init(&emitter, emitter_output_table, &forwarding_cb, 100 &buf_descriptor); 101 (*emit_fn)(&emitter); 102 expect_str_eq(expected_table_output, buf, "table output failure"); 103 } 104 105 static void 106 emit_dict(emitter_t *emitter) { 107 bool b_false = false; 108 bool b_true = true; 109 int i_123 = 123; 110 const char *str = "a string"; 111 112 emitter_begin(emitter); 113 emitter_dict_begin(emitter, "foo", "This is the foo table:"); 114 emitter_kv(emitter, "abc", "ABC", emitter_type_bool, &b_false); 115 emitter_kv(emitter, "def", "DEF", emitter_type_bool, &b_true); 116 emitter_kv_note(emitter, "ghi", "GHI", emitter_type_int, &i_123, 117 "note_key1", emitter_type_string, &str); 118 emitter_kv_note(emitter, "jkl", "JKL", emitter_type_string, &str, 119 "note_key2", emitter_type_bool, &b_false); 120 emitter_dict_end(emitter); 121 emitter_end(emitter); 122 } 123 124 static const char *dict_json = 125 "{\n" 126 "\t\"foo\": {\n" 127 "\t\t\"abc\": false,\n" 128 "\t\t\"def\": true,\n" 129 "\t\t\"ghi\": 123,\n" 130 "\t\t\"jkl\": \"a string\"\n" 131 "\t}\n" 132 "}\n"; 133 static const char *dict_json_compact = 134 "{" 135 "\"foo\":{" 136 "\"abc\":false," 137 "\"def\":true," 138 "\"ghi\":123," 139 "\"jkl\":\"a string\"" 140 "}" 141 "}"; 142 static const char *dict_table = 143 "This is the foo table:\n" 144 " ABC: false\n" 145 " DEF: true\n" 146 " GHI: 123 (note_key1: \"a string\")\n" 147 " JKL: \"a string\" (note_key2: false)\n"; 148 149 static void 150 emit_table_printf(emitter_t *emitter) { 151 emitter_begin(emitter); 152 emitter_table_printf(emitter, "Table note 1\n"); 153 emitter_table_printf(emitter, "Table note 2 %s\n", 154 "with format string"); 155 emitter_end(emitter); 156 } 157 158 static const char *table_printf_json = 159 "{\n" 160 "}\n"; 161 static const char *table_printf_json_compact = "{}"; 162 static const char *table_printf_table = 163 "Table note 1\n" 164 "Table note 2 with format string\n"; 165 166 static void emit_nested_dict(emitter_t *emitter) { 167 int val = 123; 168 emitter_begin(emitter); 169 emitter_dict_begin(emitter, "json1", "Dict 1"); 170 emitter_dict_begin(emitter, "json2", "Dict 2"); 171 emitter_kv(emitter, "primitive", "A primitive", emitter_type_int, &val); 172 emitter_dict_end(emitter); /* Close 2 */ 173 emitter_dict_begin(emitter, "json3", "Dict 3"); 174 emitter_dict_end(emitter); /* Close 3 */ 175 emitter_dict_end(emitter); /* Close 1 */ 176 emitter_dict_begin(emitter, "json4", "Dict 4"); 177 emitter_kv(emitter, "primitive", "Another primitive", 178 emitter_type_int, &val); 179 emitter_dict_end(emitter); /* Close 4 */ 180 emitter_end(emitter); 181 } 182 183 static const char *nested_dict_json = 184 "{\n" 185 "\t\"json1\": {\n" 186 "\t\t\"json2\": {\n" 187 "\t\t\t\"primitive\": 123\n" 188 "\t\t},\n" 189 "\t\t\"json3\": {\n" 190 "\t\t}\n" 191 "\t},\n" 192 "\t\"json4\": {\n" 193 "\t\t\"primitive\": 123\n" 194 "\t}\n" 195 "}\n"; 196 static const char *nested_dict_json_compact = 197 "{" 198 "\"json1\":{" 199 "\"json2\":{" 200 "\"primitive\":123" 201 "}," 202 "\"json3\":{" 203 "}" 204 "}," 205 "\"json4\":{" 206 "\"primitive\":123" 207 "}" 208 "}"; 209 static const char *nested_dict_table = 210 "Dict 1\n" 211 " Dict 2\n" 212 " A primitive: 123\n" 213 " Dict 3\n" 214 "Dict 4\n" 215 " Another primitive: 123\n"; 216 217 static void 218 emit_types(emitter_t *emitter) { 219 bool b = false; 220 int i = -123; 221 unsigned u = 123; 222 ssize_t zd = -456; 223 size_t zu = 456; 224 const char *str = "string"; 225 uint32_t u32 = 789; 226 uint64_t u64 = 10000000000ULL; 227 228 emitter_begin(emitter); 229 emitter_kv(emitter, "k1", "K1", emitter_type_bool, &b); 230 emitter_kv(emitter, "k2", "K2", emitter_type_int, &i); 231 emitter_kv(emitter, "k3", "K3", emitter_type_unsigned, &u); 232 emitter_kv(emitter, "k4", "K4", emitter_type_ssize, &zd); 233 emitter_kv(emitter, "k5", "K5", emitter_type_size, &zu); 234 emitter_kv(emitter, "k6", "K6", emitter_type_string, &str); 235 emitter_kv(emitter, "k7", "K7", emitter_type_uint32, &u32); 236 emitter_kv(emitter, "k8", "K8", emitter_type_uint64, &u64); 237 /* 238 * We don't test the title type, since it's only used for tables. It's 239 * tested in the emitter_table_row tests. 240 */ 241 emitter_end(emitter); 242 } 243 244 static const char *types_json = 245 "{\n" 246 "\t\"k1\": false,\n" 247 "\t\"k2\": -123,\n" 248 "\t\"k3\": 123,\n" 249 "\t\"k4\": -456,\n" 250 "\t\"k5\": 456,\n" 251 "\t\"k6\": \"string\",\n" 252 "\t\"k7\": 789,\n" 253 "\t\"k8\": 10000000000\n" 254 "}\n"; 255 static const char *types_json_compact = 256 "{" 257 "\"k1\":false," 258 "\"k2\":-123," 259 "\"k3\":123," 260 "\"k4\":-456," 261 "\"k5\":456," 262 "\"k6\":\"string\"," 263 "\"k7\":789," 264 "\"k8\":10000000000" 265 "}"; 266 static const char *types_table = 267 "K1: false\n" 268 "K2: -123\n" 269 "K3: 123\n" 270 "K4: -456\n" 271 "K5: 456\n" 272 "K6: \"string\"\n" 273 "K7: 789\n" 274 "K8: 10000000000\n"; 275 276 static void 277 emit_modal(emitter_t *emitter) { 278 int val = 123; 279 emitter_begin(emitter); 280 emitter_dict_begin(emitter, "j0", "T0"); 281 emitter_json_key(emitter, "j1"); 282 emitter_json_object_begin(emitter); 283 emitter_kv(emitter, "i1", "I1", emitter_type_int, &val); 284 emitter_json_kv(emitter, "i2", emitter_type_int, &val); 285 emitter_table_kv(emitter, "I3", emitter_type_int, &val); 286 emitter_table_dict_begin(emitter, "T1"); 287 emitter_kv(emitter, "i4", "I4", emitter_type_int, &val); 288 emitter_json_object_end(emitter); /* Close j1 */ 289 emitter_kv(emitter, "i5", "I5", emitter_type_int, &val); 290 emitter_table_dict_end(emitter); /* Close T1 */ 291 emitter_kv(emitter, "i6", "I6", emitter_type_int, &val); 292 emitter_dict_end(emitter); /* Close j0 / T0 */ 293 emitter_end(emitter); 294 } 295 296 const char *modal_json = 297 "{\n" 298 "\t\"j0\": {\n" 299 "\t\t\"j1\": {\n" 300 "\t\t\t\"i1\": 123,\n" 301 "\t\t\t\"i2\": 123,\n" 302 "\t\t\t\"i4\": 123\n" 303 "\t\t},\n" 304 "\t\t\"i5\": 123,\n" 305 "\t\t\"i6\": 123\n" 306 "\t}\n" 307 "}\n"; 308 const char *modal_json_compact = 309 "{" 310 "\"j0\":{" 311 "\"j1\":{" 312 "\"i1\":123," 313 "\"i2\":123," 314 "\"i4\":123" 315 "}," 316 "\"i5\":123," 317 "\"i6\":123" 318 "}" 319 "}"; 320 const char *modal_table = 321 "T0\n" 322 " I1: 123\n" 323 " I3: 123\n" 324 " T1\n" 325 " I4: 123\n" 326 " I5: 123\n" 327 " I6: 123\n"; 328 329 static void 330 emit_json_array(emitter_t *emitter) { 331 int ival = 123; 332 333 emitter_begin(emitter); 334 emitter_json_key(emitter, "dict"); 335 emitter_json_object_begin(emitter); 336 emitter_json_key(emitter, "arr"); 337 emitter_json_array_begin(emitter); 338 emitter_json_object_begin(emitter); 339 emitter_json_kv(emitter, "foo", emitter_type_int, &ival); 340 emitter_json_object_end(emitter); /* Close arr[0] */ 341 /* arr[1] and arr[2] are primitives. */ 342 emitter_json_value(emitter, emitter_type_int, &ival); 343 emitter_json_value(emitter, emitter_type_int, &ival); 344 emitter_json_object_begin(emitter); 345 emitter_json_kv(emitter, "bar", emitter_type_int, &ival); 346 emitter_json_kv(emitter, "baz", emitter_type_int, &ival); 347 emitter_json_object_end(emitter); /* Close arr[3]. */ 348 emitter_json_array_end(emitter); /* Close arr. */ 349 emitter_json_object_end(emitter); /* Close dict. */ 350 emitter_end(emitter); 351 } 352 353 static const char *json_array_json = 354 "{\n" 355 "\t\"dict\": {\n" 356 "\t\t\"arr\": [\n" 357 "\t\t\t{\n" 358 "\t\t\t\t\"foo\": 123\n" 359 "\t\t\t},\n" 360 "\t\t\t123,\n" 361 "\t\t\t123,\n" 362 "\t\t\t{\n" 363 "\t\t\t\t\"bar\": 123,\n" 364 "\t\t\t\t\"baz\": 123\n" 365 "\t\t\t}\n" 366 "\t\t]\n" 367 "\t}\n" 368 "}\n"; 369 static const char *json_array_json_compact = 370 "{" 371 "\"dict\":{" 372 "\"arr\":[" 373 "{" 374 "\"foo\":123" 375 "}," 376 "123," 377 "123," 378 "{" 379 "\"bar\":123," 380 "\"baz\":123" 381 "}" 382 "]" 383 "}" 384 "}"; 385 static const char *json_array_table = ""; 386 387 static void 388 emit_json_nested_array(emitter_t *emitter) { 389 int ival = 123; 390 char *sval = "foo"; 391 emitter_begin(emitter); 392 emitter_json_array_begin(emitter); 393 emitter_json_array_begin(emitter); 394 emitter_json_value(emitter, emitter_type_int, &ival); 395 emitter_json_value(emitter, emitter_type_string, &sval); 396 emitter_json_value(emitter, emitter_type_int, &ival); 397 emitter_json_value(emitter, emitter_type_string, &sval); 398 emitter_json_array_end(emitter); 399 emitter_json_array_begin(emitter); 400 emitter_json_value(emitter, emitter_type_int, &ival); 401 emitter_json_array_end(emitter); 402 emitter_json_array_begin(emitter); 403 emitter_json_value(emitter, emitter_type_string, &sval); 404 emitter_json_value(emitter, emitter_type_int, &ival); 405 emitter_json_array_end(emitter); 406 emitter_json_array_begin(emitter); 407 emitter_json_array_end(emitter); 408 emitter_json_array_end(emitter); 409 emitter_end(emitter); 410 } 411 412 static const char *json_nested_array_json = 413 "{\n" 414 "\t[\n" 415 "\t\t[\n" 416 "\t\t\t123,\n" 417 "\t\t\t\"foo\",\n" 418 "\t\t\t123,\n" 419 "\t\t\t\"foo\"\n" 420 "\t\t],\n" 421 "\t\t[\n" 422 "\t\t\t123\n" 423 "\t\t],\n" 424 "\t\t[\n" 425 "\t\t\t\"foo\",\n" 426 "\t\t\t123\n" 427 "\t\t],\n" 428 "\t\t[\n" 429 "\t\t]\n" 430 "\t]\n" 431 "}\n"; 432 static const char *json_nested_array_json_compact = 433 "{" 434 "[" 435 "[" 436 "123," 437 "\"foo\"," 438 "123," 439 "\"foo\"" 440 "]," 441 "[" 442 "123" 443 "]," 444 "[" 445 "\"foo\"," 446 "123" 447 "]," 448 "[" 449 "]" 450 "]" 451 "}"; 452 static const char *json_nested_array_table = ""; 453 454 static void 455 emit_table_row(emitter_t *emitter) { 456 emitter_begin(emitter); 457 emitter_row_t row; 458 emitter_col_t abc = {emitter_justify_left, 10, emitter_type_title, {0}, {0, 0}}; 459 abc.str_val = "ABC title"; 460 emitter_col_t def = {emitter_justify_right, 15, emitter_type_title, {0}, {0, 0}}; 461 def.str_val = "DEF title"; 462 emitter_col_t ghi = {emitter_justify_right, 5, emitter_type_title, {0}, {0, 0}}; 463 ghi.str_val = "GHI"; 464 465 emitter_row_init(&row); 466 emitter_col_init(&abc, &row); 467 emitter_col_init(&def, &row); 468 emitter_col_init(&ghi, &row); 469 470 emitter_table_row(emitter, &row); 471 472 abc.type = emitter_type_int; 473 def.type = emitter_type_bool; 474 ghi.type = emitter_type_int; 475 476 abc.int_val = 123; 477 def.bool_val = true; 478 ghi.int_val = 456; 479 emitter_table_row(emitter, &row); 480 481 abc.int_val = 789; 482 def.bool_val = false; 483 ghi.int_val = 1011; 484 emitter_table_row(emitter, &row); 485 486 abc.type = emitter_type_string; 487 abc.str_val = "a string"; 488 def.bool_val = false; 489 ghi.type = emitter_type_title; 490 ghi.str_val = "ghi"; 491 emitter_table_row(emitter, &row); 492 493 emitter_end(emitter); 494 } 495 496 static const char *table_row_json = 497 "{\n" 498 "}\n"; 499 static const char *table_row_json_compact = "{}"; 500 static const char *table_row_table = 501 "ABC title DEF title GHI\n" 502 "123 true 456\n" 503 "789 false 1011\n" 504 "\"a string\" false ghi\n"; 505 506 #define GENERATE_TEST(feature) \ 507 TEST_BEGIN(test_##feature) { \ 508 expect_emit_output(emit_##feature, feature##_json, \ 509 feature##_json_compact, feature##_table); \ 510 } \ 511 TEST_END 512 513 GENERATE_TEST(dict) 514 GENERATE_TEST(table_printf) 515 GENERATE_TEST(nested_dict) 516 GENERATE_TEST(types) 517 GENERATE_TEST(modal) 518 GENERATE_TEST(json_array) 519 GENERATE_TEST(json_nested_array) 520 GENERATE_TEST(table_row) 521 522 int 523 main(void) { 524 return test_no_reentrancy( 525 test_dict, 526 test_table_printf, 527 test_nested_dict, 528 test_types, 529 test_modal, 530 test_json_array, 531 test_json_nested_array, 532 test_table_row); 533 } 534