From 501e2500aef53c7c7c3ce9138e4cbf5882dc86c7 Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Mon, 30 Sep 2019 15:13:25 -0400 Subject: [PATCH] cli: print map value in ASCII-betical order of keys The test plugins/src.ctf.fs/query/test_query_metadata_info (and maybe others that I don't know about) relies on the CLI outputting query results in a constant way. However, it isn't currently the case, as the map entries are printed in the order that bt_value_map_foreach_entry_const, therefore g_hash_table_iter_next, provides them. This test currently fails on the CI Windows machine for this reason. This patch makes the CLI print map values in a sorted order (defined by comparing keys with strcmp). This makes the tests stable, but it is also convenient for the user, as the results will be sorted and in a stable order. Change-Id: I034b295bc238e146337844ac5d2c43a305fb90e0 Signed-off-by: Simon Marchi Reviewed-on: https://review.lttng.org/c/babeltrace/+/2109 Reviewed-by: Francis Deslauriers Tested-by: jenkins --- src/cli/babeltrace2.c | 96 ++++++++++++++----- .../query/metadata-info-succeed1.expect | 2 +- 2 files changed, 72 insertions(+), 26 deletions(-) diff --git a/src/cli/babeltrace2.c b/src/cli/babeltrace2.c index aa195d1c..4cc4234e 100644 --- a/src/cli/babeltrace2.c +++ b/src/cli/babeltrace2.c @@ -277,43 +277,55 @@ void print_value(FILE *, const bt_value *, size_t); static void print_value_rec(FILE *, const bt_value *, size_t); -struct print_map_value_data { - size_t indent; - FILE *fp; -}; - static -bt_bool print_map_value(const char *key, const bt_value *object, - void *data) +void print_map_value(const char *key, const bt_value *object, FILE *fp, + size_t indent) { - struct print_map_value_data *print_map_value_data = data; - - print_indent(print_map_value_data->fp, print_map_value_data->indent); - fprintf(print_map_value_data->fp, "%s: ", key); + print_indent(fp, indent); + fprintf(fp, "%s: ", key); BT_ASSERT(object); if (bt_value_is_array(object) && bt_value_array_is_empty(object)) { - fprintf(print_map_value_data->fp, "[ ]\n"); - return true; + fprintf(fp, "[ ]\n"); + goto end; } if (bt_value_is_map(object) && bt_value_map_is_empty(object)) { - fprintf(print_map_value_data->fp, "{ }\n"); - return true; + fprintf(fp, "{ }\n"); + goto end; } if (bt_value_is_array(object) || bt_value_is_map(object)) { - fprintf(print_map_value_data->fp, "\n"); + fprintf(fp, "\n"); } - print_value_rec(print_map_value_data->fp, object, - print_map_value_data->indent + 2); + print_value_rec(fp, object, indent + 2); + +end: + return; +} + +static +bt_bool collect_map_keys(const char *key, const bt_value *object, void *data) +{ + GPtrArray *map_keys = data; + + g_ptr_array_add(map_keys, (gpointer *) key); + return BT_TRUE; } +static +gint g_ptr_array_sort_strings(gconstpointer a, gconstpointer b) { + const char *s1 = *((const char **) a); + const char *s2 = *((const char **) b); + + return g_strcmp0(s1, s2); +} + static void print_value_rec(FILE *fp, const bt_value *value, size_t indent) { @@ -324,9 +336,10 @@ void print_value_rec(FILE *fp, const bt_value *value, size_t indent) const char *str_val; int size; int i; + GPtrArray *map_keys = NULL; if (!value) { - return; + goto end; } switch (bt_value_get_type(value)) { @@ -409,10 +422,8 @@ void print_value_rec(FILE *fp, const bt_value *value, size_t indent) break; case BT_VALUE_TYPE_MAP: { - struct print_map_value_data data = { - .indent = indent, - .fp = fp, - }; + guint i; + bt_value_map_foreach_entry_const_status foreach_status; if (bt_value_map_is_empty(value)) { print_indent(fp, indent); @@ -420,17 +431,52 @@ void print_value_rec(FILE *fp, const bt_value *value, size_t indent) break; } - bt_value_map_foreach_entry_const(value, print_map_value, &data); + map_keys = g_ptr_array_new(); + if (!map_keys) { + BT_CLI_LOGE_APPEND_CAUSE("Failed to allocated on GPtrArray."); + goto end; + } + + /* + * We want to print the map entries in a stable order. Collect + * all the map's keys in a GPtrArray, sort it, then print the + * entries in that order. + */ + foreach_status = bt_value_map_foreach_entry_const(value, + collect_map_keys, map_keys); + if (foreach_status != BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_OK) { + BT_CLI_LOGE_APPEND_CAUSE("Failed to iterator on map value."); + goto end; + } + + g_ptr_array_sort(map_keys, g_ptr_array_sort_strings); + + for (i = 0; i < map_keys->len; i++) { + const char *map_key = g_ptr_array_index(map_keys, i); + const bt_value *map_value; + + map_value = bt_value_map_borrow_entry_value_const(value, map_key); + BT_ASSERT(map_value); + + print_map_value(map_key, map_value, fp, indent); + } + break; } default: abort(); } - return; + + goto end; error: BT_LOGE("Error printing value of type %s.", bt_common_value_type_string(bt_value_get_type(value))); + +end: + if (map_keys) { + g_ptr_array_free(map_keys, TRUE); + } } static diff --git a/tests/data/plugins/src.ctf.fs/query/metadata-info-succeed1.expect b/tests/data/plugins/src.ctf.fs/query/metadata-info-succeed1.expect index 7a3adb87..5f202187 100644 --- a/tests/data/plugins/src.ctf.fs/query/metadata-info-succeed1.expect +++ b/tests/data/plugins/src.ctf.fs/query/metadata-info-succeed1.expect @@ -1,3 +1,4 @@ +is-packetized: no text: /* CTF 1.8 */ typealias integer { size = 8; align = 8; signed = false; } := uint8_t; typealias integer { size = 32; align = 32; signed = false; } := uint32_t; @@ -25,4 +26,3 @@ event { fields := struct { string str; }; }; -is-packetized: no -- 2.34.1