#include "test/jemalloc_test.h" #include "jemalloc/internal/emitter.h" /* * This is so useful for debugging and feature work, we'll leave printing * functionality committed but disabled by default. */ /* Print the text as it will appear. */ static bool print_raw = false; /* Print the text escaped, so it can be copied back into the test case. */ static bool print_escaped = false; typedef struct buf_descriptor_s buf_descriptor_t; struct buf_descriptor_s { char *buf; size_t len; bool mid_quote; }; /* * Forwards all writes to the passed-in buf_v (which should be cast from a * buf_descriptor_t *). */ static void forwarding_cb(void *buf_descriptor_v, const char *str) { buf_descriptor_t *buf_descriptor = (buf_descriptor_t *)buf_descriptor_v; if (print_raw) { malloc_printf("%s", str); } if (print_escaped) { const char *it = str; while (*it != '\0') { if (!buf_descriptor->mid_quote) { malloc_printf("\""); buf_descriptor->mid_quote = true; } switch (*it) { case '\\': malloc_printf("\\"); break; case '\"': malloc_printf("\\\""); break; case '\t': malloc_printf("\\t"); break; case '\n': malloc_printf("\\n\"\n"); buf_descriptor->mid_quote = false; break; default: malloc_printf("%c", *it); } it++; } } size_t written = malloc_snprintf( buf_descriptor->buf, buf_descriptor->len, "%s", str); expect_zu_eq(written, strlen(str), "Buffer overflow!"); buf_descriptor->buf += written; buf_descriptor->len -= written; expect_zu_gt(buf_descriptor->len, 0, "Buffer out of space!"); } static void expect_emit_output(void (*emit_fn)(emitter_t *), const char *expected_json_output, const char *expected_json_compact_output, const char *expected_table_output) { emitter_t emitter; char buf[MALLOC_PRINTF_BUFSIZE]; buf_descriptor_t buf_descriptor; buf_descriptor.buf = buf; buf_descriptor.len = MALLOC_PRINTF_BUFSIZE; buf_descriptor.mid_quote = false; emitter_init( &emitter, emitter_output_json, &forwarding_cb, &buf_descriptor); (*emit_fn)(&emitter); expect_str_eq(expected_json_output, buf, "json output failure"); buf_descriptor.buf = buf; buf_descriptor.len = MALLOC_PRINTF_BUFSIZE; buf_descriptor.mid_quote = false; emitter_init(&emitter, emitter_output_json_compact, &forwarding_cb, &buf_descriptor); (*emit_fn)(&emitter); expect_str_eq( expected_json_compact_output, buf, "compact json output failure"); buf_descriptor.buf = buf; buf_descriptor.len = MALLOC_PRINTF_BUFSIZE; buf_descriptor.mid_quote = false; emitter_init( &emitter, emitter_output_table, &forwarding_cb, &buf_descriptor); (*emit_fn)(&emitter); expect_str_eq(expected_table_output, buf, "table output failure"); } static void emit_dict(emitter_t *emitter) { bool b_false = false; bool b_true = true; int i_123 = 123; const char *str = "a string"; emitter_begin(emitter); emitter_dict_begin(emitter, "foo", "This is the foo table:"); emitter_kv(emitter, "abc", "ABC", emitter_type_bool, &b_false); emitter_kv(emitter, "def", "DEF", emitter_type_bool, &b_true); emitter_kv_note(emitter, "ghi", "GHI", emitter_type_int, &i_123, "note_key1", emitter_type_string, &str); emitter_kv_note(emitter, "jkl", "JKL", emitter_type_string, &str, "note_key2", emitter_type_bool, &b_false); emitter_dict_end(emitter); emitter_end(emitter); } static const char *dict_json = "{\n" "\t\"foo\": {\n" "\t\t\"abc\": false,\n" "\t\t\"def\": true,\n" "\t\t\"ghi\": 123,\n" "\t\t\"jkl\": \"a string\"\n" "\t}\n" "}\n"; static const char *dict_json_compact = "{" "\"foo\":{" "\"abc\":false," "\"def\":true," "\"ghi\":123," "\"jkl\":\"a string\"" "}" "}"; static const char *dict_table = "This is the foo table:\n" " ABC: false\n" " DEF: true\n" " GHI: 123 (note_key1: \"a string\")\n" " JKL: \"a string\" (note_key2: false)\n"; static void emit_table_printf(emitter_t *emitter) { emitter_begin(emitter); emitter_table_printf(emitter, "Table note 1\n"); emitter_table_printf( emitter, "Table note 2 %s\n", "with format string"); emitter_end(emitter); } static const char *table_printf_json = "{\n" "}\n"; static const char *table_printf_json_compact = "{}"; static const char *table_printf_table = "Table note 1\n" "Table note 2 with format string\n"; static void emit_nested_dict(emitter_t *emitter) { int val = 123; emitter_begin(emitter); emitter_dict_begin(emitter, "json1", "Dict 1"); emitter_dict_begin(emitter, "json2", "Dict 2"); emitter_kv(emitter, "primitive", "A primitive", emitter_type_int, &val); emitter_dict_end(emitter); /* Close 2 */ emitter_dict_begin(emitter, "json3", "Dict 3"); emitter_dict_end(emitter); /* Close 3 */ emitter_dict_end(emitter); /* Close 1 */ emitter_dict_begin(emitter, "json4", "Dict 4"); emitter_kv( emitter, "primitive", "Another primitive", emitter_type_int, &val); emitter_dict_end(emitter); /* Close 4 */ emitter_end(emitter); } static const char *nested_dict_json = "{\n" "\t\"json1\": {\n" "\t\t\"json2\": {\n" "\t\t\t\"primitive\": 123\n" "\t\t},\n" "\t\t\"json3\": {\n" "\t\t}\n" "\t},\n" "\t\"json4\": {\n" "\t\t\"primitive\": 123\n" "\t}\n" "}\n"; static const char *nested_dict_json_compact = "{" "\"json1\":{" "\"json2\":{" "\"primitive\":123" "}," "\"json3\":{" "}" "}," "\"json4\":{" "\"primitive\":123" "}" "}"; static const char *nested_dict_table = "Dict 1\n" " Dict 2\n" " A primitive: 123\n" " Dict 3\n" "Dict 4\n" " Another primitive: 123\n"; static void emit_types(emitter_t *emitter) { bool b = false; int i = -123; unsigned u = 123; ssize_t zd = -456; size_t zu = 456; const char *str = "string"; const char *long_str = "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz"; uint32_t u32 = 789; uint64_t u64 = 10000000000ULL; emitter_begin(emitter); emitter_kv(emitter, "k1", "K1", emitter_type_bool, &b); emitter_kv(emitter, "k2", "K2", emitter_type_int, &i); emitter_kv(emitter, "k3", "K3", emitter_type_unsigned, &u); emitter_kv(emitter, "k4", "K4", emitter_type_ssize, &zd); emitter_kv(emitter, "k5", "K5", emitter_type_size, &zu); emitter_kv(emitter, "k6", "K6", emitter_type_string, &str); emitter_kv(emitter, "k7", "K7", emitter_type_string, &long_str); emitter_kv(emitter, "k8", "K8", emitter_type_uint32, &u32); emitter_kv(emitter, "k9", "K9", emitter_type_uint64, &u64); /* * We don't test the title type, since it's only used for tables. It's * tested in the emitter_table_row tests. */ emitter_end(emitter); } static const char *types_json = "{\n" "\t\"k1\": false,\n" "\t\"k2\": -123,\n" "\t\"k3\": 123,\n" "\t\"k4\": -456,\n" "\t\"k5\": 456,\n" "\t\"k6\": \"string\",\n" "\t\"k7\": \"abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz\",\n" "\t\"k8\": 789,\n" "\t\"k9\": 10000000000\n" "}\n"; static const char *types_json_compact = "{" "\"k1\":false," "\"k2\":-123," "\"k3\":123," "\"k4\":-456," "\"k5\":456," "\"k6\":\"string\"," "\"k7\":\"abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz\"," "\"k8\":789," "\"k9\":10000000000" "}"; static const char *types_table = "K1: false\n" "K2: -123\n" "K3: 123\n" "K4: -456\n" "K5: 456\n" "K6: \"string\"\n" "K7: \"abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz\"\n" "K8: 789\n" "K9: 10000000000\n"; static void emit_modal(emitter_t *emitter) { int val = 123; emitter_begin(emitter); emitter_dict_begin(emitter, "j0", "T0"); emitter_json_key(emitter, "j1"); emitter_json_object_begin(emitter); emitter_kv(emitter, "i1", "I1", emitter_type_int, &val); emitter_json_kv(emitter, "i2", emitter_type_int, &val); emitter_table_kv(emitter, "I3", emitter_type_int, &val); emitter_table_dict_begin(emitter, "T1"); emitter_kv(emitter, "i4", "I4", emitter_type_int, &val); emitter_json_object_end(emitter); /* Close j1 */ emitter_kv(emitter, "i5", "I5", emitter_type_int, &val); emitter_table_dict_end(emitter); /* Close T1 */ emitter_kv(emitter, "i6", "I6", emitter_type_int, &val); emitter_dict_end(emitter); /* Close j0 / T0 */ emitter_end(emitter); } const char *modal_json = "{\n" "\t\"j0\": {\n" "\t\t\"j1\": {\n" "\t\t\t\"i1\": 123,\n" "\t\t\t\"i2\": 123,\n" "\t\t\t\"i4\": 123\n" "\t\t},\n" "\t\t\"i5\": 123,\n" "\t\t\"i6\": 123\n" "\t}\n" "}\n"; const char *modal_json_compact = "{" "\"j0\":{" "\"j1\":{" "\"i1\":123," "\"i2\":123," "\"i4\":123" "}," "\"i5\":123," "\"i6\":123" "}" "}"; const char *modal_table = "T0\n" " I1: 123\n" " I3: 123\n" " T1\n" " I4: 123\n" " I5: 123\n" " I6: 123\n"; static void emit_json_array(emitter_t *emitter) { int ival = 123; emitter_begin(emitter); emitter_json_key(emitter, "dict"); emitter_json_object_begin(emitter); emitter_json_key(emitter, "arr"); emitter_json_array_begin(emitter); emitter_json_object_begin(emitter); emitter_json_kv(emitter, "foo", emitter_type_int, &ival); emitter_json_object_end(emitter); /* Close arr[0] */ /* arr[1] and arr[2] are primitives. */ emitter_json_value(emitter, emitter_type_int, &ival); emitter_json_value(emitter, emitter_type_int, &ival); emitter_json_object_begin(emitter); emitter_json_kv(emitter, "bar", emitter_type_int, &ival); emitter_json_kv(emitter, "baz", emitter_type_int, &ival); emitter_json_object_end(emitter); /* Close arr[3]. */ emitter_json_array_end(emitter); /* Close arr. */ emitter_json_object_end(emitter); /* Close dict. */ emitter_end(emitter); } static const char *json_array_json = "{\n" "\t\"dict\": {\n" "\t\t\"arr\": [\n" "\t\t\t{\n" "\t\t\t\t\"foo\": 123\n" "\t\t\t},\n" "\t\t\t123,\n" "\t\t\t123,\n" "\t\t\t{\n" "\t\t\t\t\"bar\": 123,\n" "\t\t\t\t\"baz\": 123\n" "\t\t\t}\n" "\t\t]\n" "\t}\n" "}\n"; static const char *json_array_json_compact = "{" "\"dict\":{" "\"arr\":[" "{" "\"foo\":123" "}," "123," "123," "{" "\"bar\":123," "\"baz\":123" "}" "]" "}" "}"; static const char *json_array_table = ""; static void emit_json_nested_array(emitter_t *emitter) { int ival = 123; char *sval = "foo"; emitter_begin(emitter); emitter_json_array_begin(emitter); emitter_json_array_begin(emitter); emitter_json_value(emitter, emitter_type_int, &ival); emitter_json_value(emitter, emitter_type_string, &sval); emitter_json_value(emitter, emitter_type_int, &ival); emitter_json_value(emitter, emitter_type_string, &sval); emitter_json_array_end(emitter); emitter_json_array_begin(emitter); emitter_json_value(emitter, emitter_type_int, &ival); emitter_json_array_end(emitter); emitter_json_array_begin(emitter); emitter_json_value(emitter, emitter_type_string, &sval); emitter_json_value(emitter, emitter_type_int, &ival); emitter_json_array_end(emitter); emitter_json_array_begin(emitter); emitter_json_array_end(emitter); emitter_json_array_end(emitter); emitter_end(emitter); } static const char *json_nested_array_json = "{\n" "\t[\n" "\t\t[\n" "\t\t\t123,\n" "\t\t\t\"foo\",\n" "\t\t\t123,\n" "\t\t\t\"foo\"\n" "\t\t],\n" "\t\t[\n" "\t\t\t123\n" "\t\t],\n" "\t\t[\n" "\t\t\t\"foo\",\n" "\t\t\t123\n" "\t\t],\n" "\t\t[\n" "\t\t]\n" "\t]\n" "}\n"; static const char *json_nested_array_json_compact = "{" "[" "[" "123," "\"foo\"," "123," "\"foo\"" "]," "[" "123" "]," "[" "\"foo\"," "123" "]," "[" "]" "]" "}"; static const char *json_nested_array_table = ""; static void emit_table_row(emitter_t *emitter) { emitter_begin(emitter); emitter_row_t row; emitter_col_t abc = { emitter_justify_left, 10, emitter_type_title}; abc.str_val = "ABC title"; emitter_col_t def = { emitter_justify_right, 15, emitter_type_title}; def.str_val = "DEF title"; emitter_col_t ghi = { emitter_justify_right, 5, emitter_type_title}; ghi.str_val = "GHI"; emitter_row_init(&row); emitter_col_init(&abc, &row); emitter_col_init(&def, &row); emitter_col_init(&ghi, &row); emitter_table_row(emitter, &row); abc.type = emitter_type_int; def.type = emitter_type_bool; ghi.type = emitter_type_int; abc.int_val = 123; def.bool_val = true; ghi.int_val = 456; emitter_table_row(emitter, &row); abc.int_val = 789; def.bool_val = false; ghi.int_val = 1011; emitter_table_row(emitter, &row); abc.type = emitter_type_string; abc.str_val = "a string"; def.bool_val = false; ghi.type = emitter_type_title; ghi.str_val = "ghi"; emitter_table_row(emitter, &row); emitter_end(emitter); } static const char *table_row_json = "{\n" "}\n"; static const char *table_row_json_compact = "{}"; static const char *table_row_table = "ABC title DEF title GHI\n" "123 true 456\n" "789 false 1011\n" "\"a string\" false ghi\n"; /* * emitter_row(): columns that carry a json_key render both to the aligned * table (all columns) and, in JSON mode, to "json_key": value pairs in column * order; columns without a json_key are table-only. */ static void emit_row(emitter_t *emitter) { emitter_begin(emitter); emitter_row_t row; emitter_row_init(&row); /* Table-only column (no json_key set). */ emitter_col_t col_label; emitter_col_init(&col_label, &row); col_label.justify = emitter_justify_left; col_label.width = 6; col_label.type = emitter_type_title; col_label.str_val = "row:"; /* Dual columns: rendered in both table and JSON. */ emitter_col_t col_x; emitter_col_init(&col_x, &row); col_x.justify = emitter_justify_right; col_x.width = 6; col_x.type = emitter_type_unsigned; col_x.unsigned_val = 10; col_x.json_key = "x"; emitter_col_t col_y; emitter_col_init(&col_y, &row); col_y.justify = emitter_justify_right; col_y.width = 6; col_y.type = emitter_type_unsigned; col_y.unsigned_val = 20; col_y.json_key = "y"; emitter_json_object_kv_begin(emitter, "obj"); emitter_row(emitter, &row); emitter_json_object_end(emitter); emitter_end(emitter); } static const char *row_json = "{\n" "\t\"obj\": {\n" "\t\t\"x\": 10,\n" "\t\t\"y\": 20\n" "\t}\n" "}\n"; static const char *row_json_compact = "{\"obj\":{\"x\":10,\"y\":20}}"; static const char *row_table = "row: 10 20\n"; /* * emitter_sparse_row(): the table side collapses runs of all-zero ("gap") rows * to a single "---" separator (on a gap->non-gap transition and at a trailing * gap), while the JSON side still emits every row's json-keyed columns. */ static void emit_sparse_row(emitter_t *emitter) { emitter_begin(emitter); emitter_row_t row; emitter_row_init(&row); emitter_col_t col_v; emitter_col_init(&col_v, &row); col_v.justify = emitter_justify_right; col_v.width = 6; col_v.type = emitter_type_unsigned; col_v.json_key = "v"; unsigned vals[] = {1, 0, 0, 2, 0, 0}; bool gap[] = {false, true, true, false, true, true}; emitter_json_array_kv_begin(emitter, "arr"); emitter_table_sparse_begin(emitter); for (unsigned i = 0; i < sizeof(vals) / sizeof(vals[0]); i++) { col_v.unsigned_val = vals[i]; emitter_json_object_begin(emitter); emitter_sparse_row(emitter, &row, gap[i]); emitter_json_object_end(emitter); } emitter_table_sparse_end(emitter); emitter_json_array_end(emitter); emitter_end(emitter); } static const char *sparse_row_json = "{\n" "\t\"arr\": [\n" "\t\t{\n" "\t\t\t\"v\": 1\n" "\t\t},\n" "\t\t{\n" "\t\t\t\"v\": 0\n" "\t\t},\n" "\t\t{\n" "\t\t\t\"v\": 0\n" "\t\t},\n" "\t\t{\n" "\t\t\t\"v\": 2\n" "\t\t},\n" "\t\t{\n" "\t\t\t\"v\": 0\n" "\t\t},\n" "\t\t{\n" "\t\t\t\"v\": 0\n" "\t\t}\n" "\t]\n" "}\n"; static const char *sparse_row_json_compact = "{\"arr\":[{\"v\":1},{\"v\":0},{\"v\":0},{\"v\":2},{\"v\":0},{\"v\":0}]}"; static const char *sparse_row_table = " 1\n" " ---\n" " 2\n" " ---\n"; typedef struct { size_t size; uint64_t count; uint64_t prof_count; uint64_t requests; } col_table_test_row_t; #define COL_TABLE_TEST_GETTER(name, member, value_member) \ static void \ col_table_test_get_##name(const void *vrow, emitter_col_t *col) { \ const col_table_test_row_t *row = vrow; \ col->value_member = row->member; \ } COL_TABLE_TEST_GETTER(size, size, size_val) COL_TABLE_TEST_GETTER(count, count, uint64_val) COL_TABLE_TEST_GETTER(prof_count, prof_count, uint64_val) COL_TABLE_TEST_GETTER(requests, requests, uint64_val) #undef COL_TABLE_TEST_GETTER enum { COL_TABLE_TEST_SIZE, COL_TABLE_TEST_COUNT, COL_TABLE_TEST_PROF_COUNT, COL_TABLE_TEST_REQUESTS, COL_TABLE_TEST_NCOLS }; #define COL_TABLE_TEST_FLAG_PROF (1U << 0) static const emitter_col_desc_t col_table_test_descs[] = { {NULL, "size", emitter_justify_right, 8, emitter_type_size, 0, col_table_test_get_size}, {"count", "count", emitter_justify_right, 8, emitter_type_uint64, 0, col_table_test_get_count}, {"prof_count", "prof", emitter_justify_right, 6, emitter_type_uint64, COL_TABLE_TEST_FLAG_PROF, col_table_test_get_prof_count}, {"requests", "requests", emitter_justify_right, 10, emitter_type_uint64, 0, col_table_test_get_requests}, }; _Static_assert( sizeof(col_table_test_descs) / sizeof(col_table_test_descs[0]) == COL_TABLE_TEST_NCOLS, "col_table_test_descs must match COL_TABLE_TEST_NCOLS"); TEST_BEGIN(test_col_desc_flags) { expect_true(emitter_col_desc_active( &col_table_test_descs[COL_TABLE_TEST_COUNT], 0), "A column without requirements should always be active"); expect_false(emitter_col_desc_active( &col_table_test_descs[COL_TABLE_TEST_PROF_COUNT], 0), "A column with an unmet requirement should be inactive"); expect_true(emitter_col_desc_active( &col_table_test_descs[COL_TABLE_TEST_PROF_COUNT], COL_TABLE_TEST_FLAG_PROF), "A column with a satisfied requirement should be active"); } TEST_END static const unsigned col_table_test_json_order[] = { COL_TABLE_TEST_REQUESTS, COL_TABLE_TEST_PROF_COUNT, COL_TABLE_TEST_COUNT, }; static void emit_col_table(emitter_t *emitter) { col_table_test_row_t value = {42, 7, 100, 9}; emitter_row_t row, header_row; emitter_col_t cols[COL_TABLE_TEST_NCOLS]; emitter_col_t header_cols[COL_TABLE_TEST_NCOLS]; emitter_begin(emitter); emitter_col_table_build(col_table_test_descs, COL_TABLE_TEST_NCOLS, COL_TABLE_TEST_FLAG_PROF, &row, cols, &header_row, header_cols); emitter_col_table_header( emitter, &header_row, &header_cols[0], "mock:", "rows"); emitter_col_table_fill(col_table_test_descs, COL_TABLE_TEST_NCOLS, COL_TABLE_TEST_FLAG_PROF, cols, &value); emitter_json_object_begin(emitter); emitter_col_table_emit_json(emitter, col_table_test_descs, COL_TABLE_TEST_NCOLS, COL_TABLE_TEST_FLAG_PROF, cols, col_table_test_json_order, sizeof(col_table_test_json_order) / sizeof(col_table_test_json_order[0])); emitter_json_object_end(emitter); emitter_table_row(emitter, &row); emitter_json_array_end(emitter); emitter_end(emitter); } static const char *col_table_json = "{\n" "\t\"rows\": [\n" "\t\t{\n" "\t\t\t\"requests\": 9,\n" "\t\t\t\"prof_count\": 100,\n" "\t\t\t\"count\": 7\n" "\t\t}\n" "\t]\n" "}\n"; static const char *col_table_json_compact = "{\"rows\":[{\"requests\":9,\"prof_count\":100,\"count\":7}]}"; static const char *col_table_table = "mock:size count prof requests\n" " 42 7 100 9\n"; #define GENERATE_TEST(feature) \ TEST_BEGIN(test_##feature) { \ expect_emit_output(emit_##feature, feature##_json, \ feature##_json_compact, feature##_table); \ } \ TEST_END GENERATE_TEST(dict) GENERATE_TEST(table_printf) GENERATE_TEST(nested_dict) GENERATE_TEST(types) GENERATE_TEST(modal) GENERATE_TEST(json_array) GENERATE_TEST(json_nested_array) GENERATE_TEST(table_row) GENERATE_TEST(row) GENERATE_TEST(sparse_row) GENERATE_TEST(col_table) int main(void) { return test_no_reentrancy(test_dict, test_table_printf, test_nested_dict, test_types, test_modal, test_json_array, test_json_nested_array, test_table_row, test_row, test_sparse_row, test_col_table, test_col_desc_flags); }