2
0

emitter.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. #include "test/jemalloc_test.h"
  2. #include "jemalloc/internal/emitter.h"
  3. /*
  4. * This is so useful for debugging and feature work, we'll leave printing
  5. * functionality committed but disabled by default.
  6. */
  7. /* Print the text as it will appear. */
  8. static bool print_raw = false;
  9. /* Print the text escaped, so it can be copied back into the test case. */
  10. static bool print_escaped = false;
  11. typedef struct buf_descriptor_s buf_descriptor_t;
  12. struct buf_descriptor_s {
  13. char *buf;
  14. size_t len;
  15. bool mid_quote;
  16. };
  17. /*
  18. * Forwards all writes to the passed-in buf_v (which should be cast from a
  19. * buf_descriptor_t *).
  20. */
  21. static void
  22. forwarding_cb(void *buf_descriptor_v, const char *str) {
  23. buf_descriptor_t *buf_descriptor = (buf_descriptor_t *)buf_descriptor_v;
  24. if (print_raw) {
  25. malloc_printf("%s", str);
  26. }
  27. if (print_escaped) {
  28. const char *it = str;
  29. while (*it != '\0') {
  30. if (!buf_descriptor->mid_quote) {
  31. malloc_printf("\"");
  32. buf_descriptor->mid_quote = true;
  33. }
  34. switch (*it) {
  35. case '\\':
  36. malloc_printf("\\");
  37. break;
  38. case '\"':
  39. malloc_printf("\\\"");
  40. break;
  41. case '\t':
  42. malloc_printf("\\t");
  43. break;
  44. case '\n':
  45. malloc_printf("\\n\"\n");
  46. buf_descriptor->mid_quote = false;
  47. break;
  48. default:
  49. malloc_printf("%c", *it);
  50. }
  51. it++;
  52. }
  53. }
  54. size_t written = malloc_snprintf(buf_descriptor->buf,
  55. buf_descriptor->len, "%s", str);
  56. assert_zu_eq(written, strlen(str), "Buffer overflow!");
  57. buf_descriptor->buf += written;
  58. buf_descriptor->len -= written;
  59. assert_zu_gt(buf_descriptor->len, 0, "Buffer out of space!");
  60. }
  61. static void
  62. assert_emit_output(void (*emit_fn)(emitter_t *),
  63. const char *expected_json_output, const char *expected_table_output) {
  64. emitter_t emitter;
  65. char buf[MALLOC_PRINTF_BUFSIZE];
  66. buf_descriptor_t buf_descriptor;
  67. buf_descriptor.buf = buf;
  68. buf_descriptor.len = MALLOC_PRINTF_BUFSIZE;
  69. buf_descriptor.mid_quote = false;
  70. emitter_init(&emitter, emitter_output_json, &forwarding_cb,
  71. &buf_descriptor);
  72. (*emit_fn)(&emitter);
  73. assert_str_eq(expected_json_output, buf, "json output failure");
  74. buf_descriptor.buf = buf;
  75. buf_descriptor.len = MALLOC_PRINTF_BUFSIZE;
  76. buf_descriptor.mid_quote = false;
  77. emitter_init(&emitter, emitter_output_table, &forwarding_cb,
  78. &buf_descriptor);
  79. (*emit_fn)(&emitter);
  80. assert_str_eq(expected_table_output, buf, "table output failure");
  81. }
  82. static void
  83. emit_dict(emitter_t *emitter) {
  84. bool b_false = false;
  85. bool b_true = true;
  86. int i_123 = 123;
  87. const char *str = "a string";
  88. emitter_begin(emitter);
  89. emitter_dict_begin(emitter, "foo", "This is the foo table:");
  90. emitter_kv(emitter, "abc", "ABC", emitter_type_bool, &b_false);
  91. emitter_kv(emitter, "def", "DEF", emitter_type_bool, &b_true);
  92. emitter_kv_note(emitter, "ghi", "GHI", emitter_type_int, &i_123,
  93. "note_key1", emitter_type_string, &str);
  94. emitter_kv_note(emitter, "jkl", "JKL", emitter_type_string, &str,
  95. "note_key2", emitter_type_bool, &b_false);
  96. emitter_dict_end(emitter);
  97. emitter_end(emitter);
  98. }
  99. static const char *dict_json =
  100. "{\n"
  101. "\t\"foo\": {\n"
  102. "\t\t\"abc\": false,\n"
  103. "\t\t\"def\": true,\n"
  104. "\t\t\"ghi\": 123,\n"
  105. "\t\t\"jkl\": \"a string\"\n"
  106. "\t}\n"
  107. "}\n";
  108. static const char *dict_table =
  109. "This is the foo table:\n"
  110. " ABC: false\n"
  111. " DEF: true\n"
  112. " GHI: 123 (note_key1: \"a string\")\n"
  113. " JKL: \"a string\" (note_key2: false)\n";
  114. TEST_BEGIN(test_dict) {
  115. assert_emit_output(&emit_dict, dict_json, dict_table);
  116. }
  117. TEST_END
  118. static void
  119. emit_table_printf(emitter_t *emitter) {
  120. emitter_begin(emitter);
  121. emitter_table_printf(emitter, "Table note 1\n");
  122. emitter_table_printf(emitter, "Table note 2 %s\n",
  123. "with format string");
  124. emitter_end(emitter);
  125. }
  126. static const char *table_printf_json =
  127. "{\n"
  128. "}\n";
  129. static const char *table_printf_table =
  130. "Table note 1\n"
  131. "Table note 2 with format string\n";
  132. TEST_BEGIN(test_table_printf) {
  133. assert_emit_output(&emit_table_printf, table_printf_json,
  134. table_printf_table);
  135. }
  136. TEST_END
  137. static void emit_nested_dict(emitter_t *emitter) {
  138. int val = 123;
  139. emitter_begin(emitter);
  140. emitter_dict_begin(emitter, "json1", "Dict 1");
  141. emitter_dict_begin(emitter, "json2", "Dict 2");
  142. emitter_kv(emitter, "primitive", "A primitive", emitter_type_int, &val);
  143. emitter_dict_end(emitter); /* Close 2 */
  144. emitter_dict_begin(emitter, "json3", "Dict 3");
  145. emitter_dict_end(emitter); /* Close 3 */
  146. emitter_dict_end(emitter); /* Close 1 */
  147. emitter_dict_begin(emitter, "json4", "Dict 4");
  148. emitter_kv(emitter, "primitive", "Another primitive",
  149. emitter_type_int, &val);
  150. emitter_dict_end(emitter); /* Close 4 */
  151. emitter_end(emitter);
  152. }
  153. static const char *nested_dict_json =
  154. "{\n"
  155. "\t\"json1\": {\n"
  156. "\t\t\"json2\": {\n"
  157. "\t\t\t\"primitive\": 123\n"
  158. "\t\t},\n"
  159. "\t\t\"json3\": {\n"
  160. "\t\t}\n"
  161. "\t},\n"
  162. "\t\"json4\": {\n"
  163. "\t\t\"primitive\": 123\n"
  164. "\t}\n"
  165. "}\n";
  166. static const char *nested_dict_table =
  167. "Dict 1\n"
  168. " Dict 2\n"
  169. " A primitive: 123\n"
  170. " Dict 3\n"
  171. "Dict 4\n"
  172. " Another primitive: 123\n";
  173. TEST_BEGIN(test_nested_dict) {
  174. assert_emit_output(&emit_nested_dict, nested_dict_json,
  175. nested_dict_table);
  176. }
  177. TEST_END
  178. static void
  179. emit_types(emitter_t *emitter) {
  180. bool b = false;
  181. int i = -123;
  182. unsigned u = 123;
  183. ssize_t zd = -456;
  184. size_t zu = 456;
  185. const char *str = "string";
  186. uint32_t u32 = 789;
  187. uint64_t u64 = 10000000000ULL;
  188. emitter_begin(emitter);
  189. emitter_kv(emitter, "k1", "K1", emitter_type_bool, &b);
  190. emitter_kv(emitter, "k2", "K2", emitter_type_int, &i);
  191. emitter_kv(emitter, "k3", "K3", emitter_type_unsigned, &u);
  192. emitter_kv(emitter, "k4", "K4", emitter_type_ssize, &zd);
  193. emitter_kv(emitter, "k5", "K5", emitter_type_size, &zu);
  194. emitter_kv(emitter, "k6", "K6", emitter_type_string, &str);
  195. emitter_kv(emitter, "k7", "K7", emitter_type_uint32, &u32);
  196. emitter_kv(emitter, "k8", "K8", emitter_type_uint64, &u64);
  197. /*
  198. * We don't test the title type, since it's only used for tables. It's
  199. * tested in the emitter_table_row tests.
  200. */
  201. emitter_end(emitter);
  202. }
  203. static const char *types_json =
  204. "{\n"
  205. "\t\"k1\": false,\n"
  206. "\t\"k2\": -123,\n"
  207. "\t\"k3\": 123,\n"
  208. "\t\"k4\": -456,\n"
  209. "\t\"k5\": 456,\n"
  210. "\t\"k6\": \"string\",\n"
  211. "\t\"k7\": 789,\n"
  212. "\t\"k8\": 10000000000\n"
  213. "}\n";
  214. static const char *types_table =
  215. "K1: false\n"
  216. "K2: -123\n"
  217. "K3: 123\n"
  218. "K4: -456\n"
  219. "K5: 456\n"
  220. "K6: \"string\"\n"
  221. "K7: 789\n"
  222. "K8: 10000000000\n";
  223. TEST_BEGIN(test_types) {
  224. assert_emit_output(&emit_types, types_json, types_table);
  225. }
  226. TEST_END
  227. static void
  228. emit_modal(emitter_t *emitter) {
  229. int val = 123;
  230. emitter_begin(emitter);
  231. emitter_dict_begin(emitter, "j0", "T0");
  232. emitter_json_dict_begin(emitter, "j1");
  233. emitter_kv(emitter, "i1", "I1", emitter_type_int, &val);
  234. emitter_json_kv(emitter, "i2", emitter_type_int, &val);
  235. emitter_table_kv(emitter, "I3", emitter_type_int, &val);
  236. emitter_table_dict_begin(emitter, "T1");
  237. emitter_kv(emitter, "i4", "I4", emitter_type_int, &val);
  238. emitter_json_dict_end(emitter); /* Close j1 */
  239. emitter_kv(emitter, "i5", "I5", emitter_type_int, &val);
  240. emitter_table_dict_end(emitter); /* Close T1 */
  241. emitter_kv(emitter, "i6", "I6", emitter_type_int, &val);
  242. emitter_dict_end(emitter); /* Close j0 / T0 */
  243. emitter_end(emitter);
  244. }
  245. const char *modal_json =
  246. "{\n"
  247. "\t\"j0\": {\n"
  248. "\t\t\"j1\": {\n"
  249. "\t\t\t\"i1\": 123,\n"
  250. "\t\t\t\"i2\": 123,\n"
  251. "\t\t\t\"i4\": 123\n"
  252. "\t\t},\n"
  253. "\t\t\"i5\": 123,\n"
  254. "\t\t\"i6\": 123\n"
  255. "\t}\n"
  256. "}\n";
  257. const char *modal_table =
  258. "T0\n"
  259. " I1: 123\n"
  260. " I3: 123\n"
  261. " T1\n"
  262. " I4: 123\n"
  263. " I5: 123\n"
  264. " I6: 123\n";
  265. TEST_BEGIN(test_modal) {
  266. assert_emit_output(&emit_modal, modal_json, modal_table);
  267. }
  268. TEST_END
  269. static void
  270. emit_json_arr(emitter_t *emitter) {
  271. int ival = 123;
  272. emitter_begin(emitter);
  273. emitter_json_dict_begin(emitter, "dict");
  274. emitter_json_arr_begin(emitter, "arr");
  275. emitter_json_arr_obj_begin(emitter);
  276. emitter_json_kv(emitter, "foo", emitter_type_int, &ival);
  277. emitter_json_arr_obj_end(emitter); /* Close arr[0] */
  278. /* arr[1] and arr[2] are primitives. */
  279. emitter_json_arr_value(emitter, emitter_type_int, &ival);
  280. emitter_json_arr_value(emitter, emitter_type_int, &ival);
  281. emitter_json_arr_obj_begin(emitter);
  282. emitter_json_kv(emitter, "bar", emitter_type_int, &ival);
  283. emitter_json_kv(emitter, "baz", emitter_type_int, &ival);
  284. emitter_json_arr_obj_end(emitter); /* Close arr[3]. */
  285. emitter_json_arr_end(emitter); /* Close arr. */
  286. emitter_json_dict_end(emitter); /* Close dict. */
  287. emitter_end(emitter);
  288. }
  289. static const char *json_arr_json =
  290. "{\n"
  291. "\t\"dict\": {\n"
  292. "\t\t\"arr\": [\n"
  293. "\t\t\t{\n"
  294. "\t\t\t\t\"foo\": 123\n"
  295. "\t\t\t},\n"
  296. "\t\t\t123,\n"
  297. "\t\t\t123,\n"
  298. "\t\t\t{\n"
  299. "\t\t\t\t\"bar\": 123,\n"
  300. "\t\t\t\t\"baz\": 123\n"
  301. "\t\t\t}\n"
  302. "\t\t]\n"
  303. "\t}\n"
  304. "}\n";
  305. static const char *json_arr_table = "";
  306. TEST_BEGIN(test_json_arr) {
  307. assert_emit_output(&emit_json_arr, json_arr_json, json_arr_table);
  308. }
  309. TEST_END
  310. static void
  311. emit_table_row(emitter_t *emitter) {
  312. emitter_begin(emitter);
  313. emitter_row_t row;
  314. emitter_col_t abc = {emitter_justify_left, 10, emitter_type_title};
  315. abc.str_val = "ABC title";
  316. emitter_col_t def = {emitter_justify_right, 15, emitter_type_title};
  317. def.str_val = "DEF title";
  318. emitter_col_t ghi = {emitter_justify_right, 5, emitter_type_title};
  319. ghi.str_val = "GHI";
  320. emitter_row_init(&row);
  321. emitter_col_init(&abc, &row);
  322. emitter_col_init(&def, &row);
  323. emitter_col_init(&ghi, &row);
  324. emitter_table_row(emitter, &row);
  325. abc.type = emitter_type_int;
  326. def.type = emitter_type_bool;
  327. ghi.type = emitter_type_int;
  328. abc.int_val = 123;
  329. def.bool_val = true;
  330. ghi.int_val = 456;
  331. emitter_table_row(emitter, &row);
  332. abc.int_val = 789;
  333. def.bool_val = false;
  334. ghi.int_val = 1011;
  335. emitter_table_row(emitter, &row);
  336. abc.type = emitter_type_string;
  337. abc.str_val = "a string";
  338. def.bool_val = false;
  339. ghi.type = emitter_type_title;
  340. ghi.str_val = "ghi";
  341. emitter_table_row(emitter, &row);
  342. emitter_end(emitter);
  343. }
  344. static const char *table_row_json =
  345. "{\n"
  346. "}\n";
  347. static const char *table_row_table =
  348. "ABC title DEF title GHI\n"
  349. "123 true 456\n"
  350. "789 false 1011\n"
  351. "\"a string\" false ghi\n";
  352. TEST_BEGIN(test_table_row) {
  353. assert_emit_output(&emit_table_row, table_row_json, table_row_table);
  354. }
  355. TEST_END
  356. int
  357. main(void) {
  358. return test_no_reentrancy(
  359. test_dict,
  360. test_table_printf,
  361. test_nested_dict,
  362. test_types,
  363. test_modal,
  364. test_json_arr,
  365. test_table_row);
  366. }