Home | History | Annotate | Line # | Download | only in unit
      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