--- /dev/null
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2020 Geneviève Bastien <gbastien@versatic.net>
+
+import bt2
+
+
+class TheIteratorOfProblems(bt2._UserMessageIterator):
+ def __init__(self, config, port):
+ tc, sc, ec1, params = port.user_data
+ trace = tc()
+ stream = trace.create_stream(sc)
+ event_value = params['value']
+ self._msgs = []
+
+ self._msgs.append(self._create_stream_beginning_message(stream))
+
+ ev_msg1 = self._create_event_message(ec1, stream)
+ ev_msg1.event.payload_field["enum_field"] = event_value
+
+ self._msgs.append(ev_msg1)
+
+ self._msgs.append(self._create_stream_end_message(stream))
+
+ self._at = 0
+ config.can_seek_forward = True
+
+ def _user_seek_beginning(self):
+ self._at = 0
+
+ def __next__(self):
+ if self._at < len(self._msgs):
+ msg = self._msgs[self._at]
+ self._at += 1
+ return msg
+ else:
+ raise StopIteration
+
+
+@bt2.plugin_component_class
+class TheSourceOfProblems(
+ bt2._UserSourceComponent, message_iterator_class=TheIteratorOfProblems
+):
+ def __init__(self, config, params, obj):
+ tc = self._create_trace_class()
+
+ enum_values_str = params['enum-values']
+
+ sc = tc.create_stream_class()
+
+ # Create the enumeration field with the values in parameter
+ if params['enum-signed']:
+ enumfc = tc.create_signed_enumeration_field_class()
+ else:
+ enumfc = tc.create_unsigned_enumeration_field_class()
+
+ groups = str(enum_values_str).split(' ')
+ mappings = {}
+ range_set_type = (
+ bt2.SignedIntegerRangeSet
+ if params['enum-signed']
+ else bt2.UnsignedIntegerRangeSet
+ )
+ for group in groups:
+ label, low, high = group.split(',')
+
+ if label not in mappings.keys():
+ mappings[label] = range_set_type()
+
+ mappings[label].add((int(low), int(high)))
+
+ for x, y in mappings.items():
+ enumfc.add_mapping(x, y)
+
+ # Create the struct field to contain the enum field class
+ struct_fc = tc.create_structure_field_class()
+ struct_fc.append_member('enum_field', enumfc)
+
+ # Create an event class on this stream with the struct field
+ ec1 = sc.create_event_class(name='with_enum', payload_field_class=struct_fc)
+ self._add_output_port('out', (tc, sc, ec1, params))
+
+
+bt2.register_plugin(__name__, 'test-pretty')
--- /dev/null
+#!/bin/bash
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2020 Geneviève Bastien <gbastien@versatic.net>
+#
+# This file tests pretty printing in details some event classes that are
+# not all covered by the main babeltrace tests with traces.
+SH_TAP=1
+
+if [ "x${BT_TESTS_SRCDIR:-}" != "x" ]; then
+ UTILSSH="$BT_TESTS_SRCDIR/utils/utils.sh"
+else
+ UTILSSH="$(dirname "$0")/../../utils/utils.sh"
+fi
+
+# shellcheck source=../../utils/utils.sh
+source "$UTILSSH"
+
+data_dir="$BT_TESTS_DATADIR/plugins/sink.text.pretty"
+temp_stdout_expected_file=$(mktemp -t test_pretty_expected_stdout.XXXXXX)
+temp_stderr_expected="/dev/null"
+
+plan_tests 14
+
+function compare_enum_sorted
+{
+ local expected_file="$1"
+ local actual_file="$2"
+
+ # The order in which enum labels are printed by a `sink.text.pretty`
+ # component directly depends on the order in which mappings were added
+ # to the enum field class in the source component. This order should
+ # not be relied on when testing. Relying on it caused problems with
+ # Python component classes because different versions of Python sort
+ # data structures differently (e.g. dictionaries are insertion sorted
+ # since Python 3.7).
+
+ run_python_bt2 python3 "${BT_TESTS_SRCDIR}/utils/python/split_sort_compare.py" \
+ "$(cat $expected_file)" "$(cat $actual_file)"
+}
+
+function run_test
+{
+ local test_name=$1
+ local expected_to_fail="$2"
+ local value="$3"
+ local expected_stdout_file="$4"
+ local test_text=
+ local actual_stdout_file
+ local actual_stderr_file
+ local ret=0
+ local local_args=(
+ "--plugin-path" "$data_dir"
+ "-c" "src.test-pretty.TheSourceOfProblems"
+ "-p" "enum-values=\"$enum_values\""
+ "-p" "value=$value"
+ "-p" "enum-signed=$enum_signed"
+ "-c" "sink.text.pretty"
+ )
+
+ actual_stdout_file="$(mktemp -t actual_pretty_stdout.XXXXXX)"
+ actual_stderr_file="$(mktemp -t actual_pretty_stderr.XXXXXX)"
+
+ bt_cli "$actual_stdout_file" "$actual_stderr_file" "${local_args[@]}"
+
+ compare_enum_sorted "$expected_stdout_file" "$actual_stdout_file"
+ ret_stdout=$?
+
+ bt_diff /dev/null "$actual_stderr_file"
+ ret_stderr=$?
+
+ if ((ret_stdout != 0 || ret_stderr != 0)); then
+ ret=1
+ fi
+
+ rm -f "$actual_stdout_file" "$actual_stderr_file"
+
+ if (($expected_to_fail)); then
+ isnt $ret 0 "$test_name signed=$enum_signed with value=$value doesn't match as expected"
+ else
+ ok $ret "$test_name signed=$enum_signed with value=$value matches"
+ fi
+
+}
+
+function test_normal_enum {
+ test_name="Normal enum"
+ enum_signed="$1"
+ enum_values="single,1,1 single2,2,2 single3,4,4 range,4,8 range2,15,20"
+
+ # Hit a single value
+ cat <<- 'END' > "$temp_stdout_expected_file"
+ with_enum: { enum_field = ( "single" : container = 1 ) }
+ END
+ run_test "$test_name" 0 1 "$temp_stdout_expected_file"
+
+ # Hit a single range
+ cat <<- 'END' > "$temp_stdout_expected_file"
+ with_enum: { enum_field = ( "range" : container = 7 ) }
+ END
+ run_test "$test_name" 0 7 "$temp_stdout_expected_file"
+
+ # Unknown
+ cat <<- 'END' > "$temp_stdout_expected_file"
+ with_enum: { enum_field = ( <unknown> : container = 21 ) }
+ END
+ run_test "$test_name" 0 21 "$temp_stdout_expected_file"
+
+ # Unknown but with bits with a value, but range larger than 1 element
+ cat <<- 'END' > "$temp_stdout_expected_file"
+ with_enum: { enum_field = ( <unknown> : container = 12 ) }
+ END
+ run_test "$test_name" 0 12 "$temp_stdout_expected_file"
+
+ # Unknown value of 0
+ cat <<- 'END' > "$temp_stdout_expected_file"
+ with_enum: { enum_field = ( <unknown> : container = 0 ) }
+ END
+ run_test "$test_name" 0 0 "$temp_stdout_expected_file"
+}
+
+function test_normal_enum_negative {
+ test_name="Normal enum with negative value"
+ enum_signed="true"
+ enum_values="zero,0,0 single,1,1 single2,2,2 single3,4,4 range,4,8 negative,-1,-1 rangeNegative,-6,-2"
+
+ # Hit a single negative value
+ cat <<- 'END' > "$temp_stdout_expected_file"
+ with_enum: { enum_field = ( "negative" : container = -1 ) }
+ END
+ run_test "$test_name" 0 -1 "$temp_stdout_expected_file"
+
+ # Hit a single negative range
+ cat <<- 'END' > "$temp_stdout_expected_file"
+ with_enum: { enum_field = ( "rangeNegative" : container = -6 ) }
+ END
+ run_test "$test_name" 0 -6 "$temp_stdout_expected_file"
+
+ # Unknown
+ cat <<- 'END' > "$temp_stdout_expected_file"
+ with_enum: { enum_field = ( <unknown> : container = -7 ) }
+ END
+ run_test "$test_name" 0 -7 "$temp_stdout_expected_file"
+
+ # value of 0
+ cat <<- 'END' > "$temp_stdout_expected_file"
+ with_enum: { enum_field = ( "zero" : container = 0 ) }
+ END
+ run_test "$test_name" 0 0 "$temp_stdout_expected_file"
+}
+
+# Enumerations tests
+test_normal_enum "false"
+test_normal_enum "true"
+test_normal_enum_negative
+
+# Do not `rm` $temp_stderr_expected because it's set to `/dev/null` right now
+# and that would print an error.
+rm -f "$temp_stdout_expected_file"