• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
forwarding_cb(void * buf_descriptor_v,const char * str)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 	assert_zu_eq(written, strlen(str), "Buffer overflow!");
62 	buf_descriptor->buf += written;
63 	buf_descriptor->len -= written;
64 	assert_zu_gt(buf_descriptor->len, 0, "Buffer out of space!");
65 }
66 
67 static void
assert_emit_output(void (* emit_fn)(emitter_t *),const char * expected_json_output,const char * expected_table_output)68 assert_emit_output(void (*emit_fn)(emitter_t *),
69     const char *expected_json_output, const char *expected_table_output) {
70 	emitter_t emitter;
71 	char buf[MALLOC_PRINTF_BUFSIZE];
72 	buf_descriptor_t buf_descriptor;
73 
74 	buf_descriptor.buf = buf;
75 	buf_descriptor.len = MALLOC_PRINTF_BUFSIZE;
76 	buf_descriptor.mid_quote = false;
77 
78 	emitter_init(&emitter, emitter_output_json, &forwarding_cb,
79 	    &buf_descriptor);
80 	(*emit_fn)(&emitter);
81 	assert_str_eq(expected_json_output, buf, "json output failure");
82 
83 	buf_descriptor.buf = buf;
84 	buf_descriptor.len = MALLOC_PRINTF_BUFSIZE;
85 	buf_descriptor.mid_quote = false;
86 
87 	emitter_init(&emitter, emitter_output_table, &forwarding_cb,
88 	    &buf_descriptor);
89 	(*emit_fn)(&emitter);
90 	assert_str_eq(expected_table_output, buf, "table output failure");
91 }
92 
93 static void
emit_dict(emitter_t * emitter)94 emit_dict(emitter_t *emitter) {
95 	bool b_false = false;
96 	bool b_true = true;
97 	int i_123 = 123;
98 	const char *str = "a string";
99 
100 	emitter_begin(emitter);
101 	emitter_dict_begin(emitter, "foo", "This is the foo table:");
102 	emitter_kv(emitter, "abc", "ABC", emitter_type_bool, &b_false);
103 	emitter_kv(emitter, "def", "DEF", emitter_type_bool, &b_true);
104 	emitter_kv_note(emitter, "ghi", "GHI", emitter_type_int, &i_123,
105 	    "note_key1", emitter_type_string, &str);
106 	emitter_kv_note(emitter, "jkl", "JKL", emitter_type_string, &str,
107 	    "note_key2", emitter_type_bool, &b_false);
108 	emitter_dict_end(emitter);
109 	emitter_end(emitter);
110 }
111 static const char *dict_json =
112 "{\n"
113 "\t\"foo\": {\n"
114 "\t\t\"abc\": false,\n"
115 "\t\t\"def\": true,\n"
116 "\t\t\"ghi\": 123,\n"
117 "\t\t\"jkl\": \"a string\"\n"
118 "\t}\n"
119 "}\n";
120 static const char *dict_table =
121 "This is the foo table:\n"
122 "  ABC: false\n"
123 "  DEF: true\n"
124 "  GHI: 123 (note_key1: \"a string\")\n"
125 "  JKL: \"a string\" (note_key2: false)\n";
126 
TEST_BEGIN(test_dict)127 TEST_BEGIN(test_dict) {
128 	assert_emit_output(&emit_dict, dict_json, dict_table);
129 }
130 TEST_END
131 
132 static void
emit_table_printf(emitter_t * emitter)133 emit_table_printf(emitter_t *emitter) {
134 	emitter_begin(emitter);
135 	emitter_table_printf(emitter, "Table note 1\n");
136 	emitter_table_printf(emitter, "Table note 2 %s\n",
137 	    "with format string");
138 	emitter_end(emitter);
139 }
140 
141 static const char *table_printf_json =
142 "{\n"
143 "}\n";
144 
145 static const char *table_printf_table =
146 "Table note 1\n"
147 "Table note 2 with format string\n";
148 
TEST_BEGIN(test_table_printf)149 TEST_BEGIN(test_table_printf) {
150 	assert_emit_output(&emit_table_printf, table_printf_json,
151 	    table_printf_table);
152 }
153 TEST_END
154 
emit_nested_dict(emitter_t * emitter)155 static void emit_nested_dict(emitter_t *emitter) {
156 	int val = 123;
157 	emitter_begin(emitter);
158 	emitter_dict_begin(emitter, "json1", "Dict 1");
159 	emitter_dict_begin(emitter, "json2", "Dict 2");
160 	emitter_kv(emitter, "primitive", "A primitive", emitter_type_int, &val);
161 	emitter_dict_end(emitter); /* Close 2 */
162 	emitter_dict_begin(emitter, "json3", "Dict 3");
163 	emitter_dict_end(emitter); /* Close 3 */
164 	emitter_dict_end(emitter); /* Close 1 */
165 	emitter_dict_begin(emitter, "json4", "Dict 4");
166 	emitter_kv(emitter, "primitive", "Another primitive",
167 	    emitter_type_int, &val);
168 	emitter_dict_end(emitter); /* Close 4 */
169 	emitter_end(emitter);
170 }
171 
172 static const char *nested_dict_json =
173 "{\n"
174 "\t\"json1\": {\n"
175 "\t\t\"json2\": {\n"
176 "\t\t\t\"primitive\": 123\n"
177 "\t\t},\n"
178 "\t\t\"json3\": {\n"
179 "\t\t}\n"
180 "\t},\n"
181 "\t\"json4\": {\n"
182 "\t\t\"primitive\": 123\n"
183 "\t}\n"
184 "}\n";
185 
186 static const char *nested_dict_table =
187 "Dict 1\n"
188 "  Dict 2\n"
189 "    A primitive: 123\n"
190 "  Dict 3\n"
191 "Dict 4\n"
192 "  Another primitive: 123\n";
193 
TEST_BEGIN(test_nested_dict)194 TEST_BEGIN(test_nested_dict) {
195 	assert_emit_output(&emit_nested_dict, nested_dict_json,
196 	    nested_dict_table);
197 }
198 TEST_END
199 
200 static void
emit_types(emitter_t * emitter)201 emit_types(emitter_t *emitter) {
202 	bool b = false;
203 	int i = -123;
204 	unsigned u = 123;
205 	ssize_t zd = -456;
206 	size_t zu = 456;
207 	const char *str = "string";
208 	uint32_t u32 = 789;
209 	uint64_t u64 = 10000000000ULL;
210 
211 	emitter_begin(emitter);
212 	emitter_kv(emitter, "k1", "K1", emitter_type_bool, &b);
213 	emitter_kv(emitter, "k2", "K2", emitter_type_int, &i);
214 	emitter_kv(emitter, "k3", "K3", emitter_type_unsigned, &u);
215 	emitter_kv(emitter, "k4", "K4", emitter_type_ssize, &zd);
216 	emitter_kv(emitter, "k5", "K5", emitter_type_size, &zu);
217 	emitter_kv(emitter, "k6", "K6", emitter_type_string, &str);
218 	emitter_kv(emitter, "k7", "K7", emitter_type_uint32, &u32);
219 	emitter_kv(emitter, "k8", "K8", emitter_type_uint64, &u64);
220 	/*
221 	 * We don't test the title type, since it's only used for tables.  It's
222 	 * tested in the emitter_table_row tests.
223 	 */
224 	emitter_end(emitter);
225 }
226 
227 static const char *types_json =
228 "{\n"
229 "\t\"k1\": false,\n"
230 "\t\"k2\": -123,\n"
231 "\t\"k3\": 123,\n"
232 "\t\"k4\": -456,\n"
233 "\t\"k5\": 456,\n"
234 "\t\"k6\": \"string\",\n"
235 "\t\"k7\": 789,\n"
236 "\t\"k8\": 10000000000\n"
237 "}\n";
238 
239 static const char *types_table =
240 "K1: false\n"
241 "K2: -123\n"
242 "K3: 123\n"
243 "K4: -456\n"
244 "K5: 456\n"
245 "K6: \"string\"\n"
246 "K7: 789\n"
247 "K8: 10000000000\n";
248 
TEST_BEGIN(test_types)249 TEST_BEGIN(test_types) {
250 	assert_emit_output(&emit_types, types_json, types_table);
251 }
252 TEST_END
253 
254 static void
emit_modal(emitter_t * emitter)255 emit_modal(emitter_t *emitter) {
256 	int val = 123;
257 	emitter_begin(emitter);
258 	emitter_dict_begin(emitter, "j0", "T0");
259 	emitter_json_dict_begin(emitter, "j1");
260 	emitter_kv(emitter, "i1", "I1", emitter_type_int, &val);
261 	emitter_json_kv(emitter, "i2", emitter_type_int, &val);
262 	emitter_table_kv(emitter, "I3", emitter_type_int, &val);
263 	emitter_table_dict_begin(emitter, "T1");
264 	emitter_kv(emitter, "i4", "I4", emitter_type_int, &val);
265 	emitter_json_dict_end(emitter); /* Close j1 */
266 	emitter_kv(emitter, "i5", "I5", emitter_type_int, &val);
267 	emitter_table_dict_end(emitter); /* Close T1 */
268 	emitter_kv(emitter, "i6", "I6", emitter_type_int, &val);
269 	emitter_dict_end(emitter); /* Close j0 / T0 */
270 	emitter_end(emitter);
271 }
272 
273 const char *modal_json =
274 "{\n"
275 "\t\"j0\": {\n"
276 "\t\t\"j1\": {\n"
277 "\t\t\t\"i1\": 123,\n"
278 "\t\t\t\"i2\": 123,\n"
279 "\t\t\t\"i4\": 123\n"
280 "\t\t},\n"
281 "\t\t\"i5\": 123,\n"
282 "\t\t\"i6\": 123\n"
283 "\t}\n"
284 "}\n";
285 
286 const char *modal_table =
287 "T0\n"
288 "  I1: 123\n"
289 "  I3: 123\n"
290 "  T1\n"
291 "    I4: 123\n"
292 "    I5: 123\n"
293 "  I6: 123\n";
294 
TEST_BEGIN(test_modal)295 TEST_BEGIN(test_modal) {
296 	assert_emit_output(&emit_modal, modal_json, modal_table);
297 }
298 TEST_END
299 
300 static void
emit_json_arr(emitter_t * emitter)301 emit_json_arr(emitter_t *emitter) {
302 	int ival = 123;
303 
304 	emitter_begin(emitter);
305 	emitter_json_dict_begin(emitter, "dict");
306 	emitter_json_arr_begin(emitter, "arr");
307 	emitter_json_arr_obj_begin(emitter);
308 	emitter_json_kv(emitter, "foo", emitter_type_int, &ival);
309 	emitter_json_arr_obj_end(emitter); /* Close arr[0] */
310 	/* arr[1] and arr[2] are primitives. */
311 	emitter_json_arr_value(emitter, emitter_type_int, &ival);
312 	emitter_json_arr_value(emitter, emitter_type_int, &ival);
313 	emitter_json_arr_obj_begin(emitter);
314 	emitter_json_kv(emitter, "bar", emitter_type_int, &ival);
315 	emitter_json_kv(emitter, "baz", emitter_type_int, &ival);
316 	emitter_json_arr_obj_end(emitter); /* Close arr[3]. */
317 	emitter_json_arr_end(emitter); /* Close arr. */
318 	emitter_json_dict_end(emitter); /* Close dict. */
319 	emitter_end(emitter);
320 }
321 
322 static const char *json_arr_json =
323 "{\n"
324 "\t\"dict\": {\n"
325 "\t\t\"arr\": [\n"
326 "\t\t\t{\n"
327 "\t\t\t\t\"foo\": 123\n"
328 "\t\t\t},\n"
329 "\t\t\t123,\n"
330 "\t\t\t123,\n"
331 "\t\t\t{\n"
332 "\t\t\t\t\"bar\": 123,\n"
333 "\t\t\t\t\"baz\": 123\n"
334 "\t\t\t}\n"
335 "\t\t]\n"
336 "\t}\n"
337 "}\n";
338 
339 static const char *json_arr_table = "";
340 
TEST_BEGIN(test_json_arr)341 TEST_BEGIN(test_json_arr) {
342 	assert_emit_output(&emit_json_arr, json_arr_json, json_arr_table);
343 }
344 TEST_END
345 
346 static void
emit_table_row(emitter_t * emitter)347 emit_table_row(emitter_t *emitter) {
348 	emitter_begin(emitter);
349 	emitter_row_t row;
350 	emitter_col_t abc = {emitter_justify_left, 10, emitter_type_title};
351 	abc.str_val = "ABC title";
352 	emitter_col_t def = {emitter_justify_right, 15, emitter_type_title};
353 	def.str_val = "DEF title";
354 	emitter_col_t ghi = {emitter_justify_right, 5, emitter_type_title};
355 	ghi.str_val = "GHI";
356 
357 	emitter_row_init(&row);
358 	emitter_col_init(&abc, &row);
359 	emitter_col_init(&def, &row);
360 	emitter_col_init(&ghi, &row);
361 
362 	emitter_table_row(emitter, &row);
363 
364 	abc.type = emitter_type_int;
365 	def.type = emitter_type_bool;
366 	ghi.type = emitter_type_int;
367 
368 	abc.int_val = 123;
369 	def.bool_val = true;
370 	ghi.int_val = 456;
371 	emitter_table_row(emitter, &row);
372 
373 	abc.int_val = 789;
374 	def.bool_val = false;
375 	ghi.int_val = 1011;
376 	emitter_table_row(emitter, &row);
377 
378 	abc.type = emitter_type_string;
379 	abc.str_val = "a string";
380 	def.bool_val = false;
381 	ghi.type = emitter_type_title;
382 	ghi.str_val = "ghi";
383 	emitter_table_row(emitter, &row);
384 
385 	emitter_end(emitter);
386 }
387 
388 static const char *table_row_json =
389 "{\n"
390 "}\n";
391 
392 static const char *table_row_table =
393 "ABC title       DEF title  GHI\n"
394 "123                  true  456\n"
395 "789                 false 1011\n"
396 "\"a string\"          false  ghi\n";
397 
TEST_BEGIN(test_table_row)398 TEST_BEGIN(test_table_row) {
399 	assert_emit_output(&emit_table_row, table_row_json, table_row_table);
400 }
401 TEST_END
402 
403 int
main(void)404 main(void) {
405 	return test_no_reentrancy(
406 	    test_dict,
407 	    test_table_printf,
408 	    test_nested_dict,
409 	    test_types,
410 	    test_modal,
411 	    test_json_arr,
412 	    test_table_row);
413 }
414