]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
rtla/tests: Add unit tests for CLI option callbacks
authorTomas Glozar <tglozar@redhat.com>
Thu, 28 May 2026 10:32:54 +0000 (12:32 +0200)
committerTomas Glozar <tglozar@redhat.com>
Thu, 28 May 2026 11:02:48 +0000 (13:02 +0200)
In addition to testing all tool_parse_args() functions, test also all
callbacks used for parsing custom option formats.

The callbacks represent a middle layer between the parsing functions
and utility functions dedicated to checking specific argument formats,
for example, scheduling class and duration. Callback tests are run
before parsing functions to make sure any issue in the former is
reported before it is encountered through the latter.

Tests verify both successful parsing and proper rejection of invalid
inputs (via exit tests). To enable testing static callbacks, a pragma
once guard is added to timerlat.h for safe inclusion by cli_p.h.

Add dependency of UNIT_TESTS_IN on LIBSUBCMD_INCLUDES, as the new test
file tests/unit/cli_opt_callback.c includes cli_p.h which includes
subcmd/parse-options.h.

Link: https://lore.kernel.org/r/20260528103254.2990068-7-tglozar@redhat.com
Signed-off-by: Tomas Glozar <tglozar@redhat.com>
tools/tracing/rtla/src/timerlat.h
tools/tracing/rtla/tests/unit/Build
tools/tracing/rtla/tests/unit/Makefile.unit
tools/tracing/rtla/tests/unit/cli_opt_callback.c [new file with mode: 0644]
tools/tracing/rtla/tests/unit/unit_tests.c

index 37a808f1611ed7705dff8e13c76fc3c314372173..38ab6b41a15e046939969c755d5da29db8a41c13 100644 (file)
@@ -1,4 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
+#pragma once
+
 #include "osnoise.h"
 
 /*
index 16139f17ea1feb792b2883ac279dd90e0967dcf1..d5a0f13922be17ab9c3814b08b751290c3c098c9 100644 (file)
@@ -5,3 +5,4 @@ unit_tests-y += osnoise_top_cli.o
 unit_tests-y += osnoise_hist_cli.o
 unit_tests-y += timerlat_top_cli.o
 unit_tests-y += timerlat_hist_cli.o
+unit_tests-y += cli_opt_callback.o
index 8c33a9583c303e21b876fd5b56fbdf9e26a5a203..839abda64b76ec8f6a40bf4fd4b27428e762c46d 100644 (file)
@@ -6,7 +6,7 @@ UNIT_TESTS_IN := $(UNIT_TESTS)-in.o
 $(UNIT_TESTS): $(UNIT_TESTS_IN) $(RTLA_IN) $(LIBSUBCMD) $(LIB_STRING) $(LIB_STR_ERROR_R)
        $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $^ $(EXTLIBS) -lcheck
 
-$(UNIT_TESTS_IN): fixdep
+$(UNIT_TESTS_IN): fixdep $(LIBSUBCMD_INCLUDES)
        make $(build)=unit_tests
 
 unit-tests: FORCE
diff --git a/tools/tracing/rtla/tests/unit/cli_opt_callback.c b/tools/tracing/rtla/tests/unit/cli_opt_callback.c
new file mode 100644 (file)
index 0000000..01647f4
--- /dev/null
@@ -0,0 +1,704 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <check.h>
+
+#define RTLA_ALLOW_CLI_P_H
+#include "../../src/cli_p.h"
+#include "cli_params_assert.h"
+
+#define TEST_CALLBACK(value, cb) OPT_CALLBACK('t', "test", value, "test value", "test help", cb)
+
+START_TEST(test_opt_llong_callback_simple)
+{
+       long long test_value = 0;
+       const struct option opt = TEST_CALLBACK(&test_value, opt_llong_callback);
+
+       ck_assert_int_eq(opt_llong_callback(&opt, "1234567890", 0), 0);
+       ck_assert_int_eq(test_value, 1234567890);
+}
+END_TEST
+
+START_TEST(test_opt_llong_callback_max)
+{
+       long long test_value = 0;
+       const struct option opt = TEST_CALLBACK(&test_value, opt_llong_callback);
+
+       ck_assert_int_eq(opt_llong_callback(&opt, "9223372036854775807", 0), 0);
+       ck_assert_int_eq(test_value, 9223372036854775807LL);
+}
+END_TEST
+
+START_TEST(test_opt_llong_callback_min)
+{
+       long long test_value = 0;
+       const struct option opt = TEST_CALLBACK(&test_value, opt_llong_callback);
+
+       ck_assert_int_eq(opt_llong_callback(&opt, "-9223372036854775808", 0), 0);
+       ck_assert_int_eq(test_value, ~9223372036854775807LL);
+}
+END_TEST
+
+START_TEST(test_opt_int_callback_simple)
+{
+       int test_value = 0;
+       const struct option opt = TEST_CALLBACK(&test_value, opt_int_callback);
+
+       ck_assert_int_eq(opt_int_callback(&opt, "1234567890", 0), 0);
+       ck_assert_int_eq(test_value, 1234567890);
+}
+END_TEST
+
+START_TEST(test_opt_int_callback_max)
+{
+       int test_value = 0;
+       const struct option opt = TEST_CALLBACK(&test_value, opt_int_callback);
+
+       ck_assert_int_eq(opt_int_callback(&opt, "2147483647", 0), 0);
+       ck_assert_int_eq(test_value, 2147483647);
+}
+END_TEST
+
+START_TEST(test_opt_int_callback_min)
+{
+       int test_value = 0;
+       const struct option opt = TEST_CALLBACK(&test_value, opt_int_callback);
+
+       ck_assert_int_eq(opt_int_callback(&opt, "-2147483648", 0), 0);
+       ck_assert_int_eq(test_value, -2147483648);
+}
+END_TEST
+
+START_TEST(test_opt_int_callback_non_numeric)
+{
+       int test_value = 0;
+       const struct option opt = TEST_CALLBACK(&test_value, opt_int_callback);
+
+       ck_assert_int_eq(opt_int_callback(&opt, "abc", 0), -1);
+       ck_assert_int_eq(test_value, 0);
+}
+END_TEST
+
+START_TEST(test_opt_int_callback_non_numeric_suffix)
+{
+       int test_value = 0;
+       const struct option opt = TEST_CALLBACK(&test_value, opt_int_callback);
+
+       ck_assert_int_eq(opt_int_callback(&opt, "1234567890abc", 0), -1);
+       ck_assert_int_eq(test_value, 0);
+}
+END_TEST
+
+START_TEST(test_opt_cpus_cb)
+{
+       struct common_params params = {0};
+       const struct option opt = TEST_CALLBACK(&params, opt_cpus_cb);
+
+       nr_cpus = 4;
+       ck_assert_int_eq(opt_cpus_cb(&opt, "0-3", 0), 0);
+       ck_assert_str_eq(params.cpus, "0-3");
+}
+END_TEST
+
+START_TEST(test_opt_cpus_cb_invalid)
+{
+       struct common_params params = {0};
+       const struct option opt = TEST_CALLBACK(&params, opt_cpus_cb);
+
+       nr_cpus = 4;
+       assert(freopen("/dev/null", "w", stderr));
+       opt_cpus_cb(&opt, "0-3,5", 0);
+}
+END_TEST
+
+START_TEST(test_opt_cgroup_cb)
+{
+       struct common_params params = {0};
+       const struct option opt = TEST_CALLBACK(&params, opt_cgroup_cb);
+
+       ck_assert_int_eq(opt_cgroup_cb(&opt, "cgroup", 0), 0);
+       ck_assert_int_eq(params.cgroup, 1);
+       ck_assert_str_eq(params.cgroup_name, "cgroup");
+}
+END_TEST
+
+START_TEST(test_opt_cgroup_cb_equals)
+{
+       struct common_params params = {0};
+       const struct option opt = TEST_CALLBACK(&params, opt_cgroup_cb);
+
+       ck_assert_int_eq(opt_cgroup_cb(&opt, "=cgroup", 0), 0);
+       ck_assert_int_eq(params.cgroup, 1);
+       ck_assert_str_eq(params.cgroup_name, "cgroup");
+}
+END_TEST
+
+START_TEST(test_opt_duration_cb)
+{
+       struct common_params params = {0};
+       const struct option opt = TEST_CALLBACK(&params, opt_duration_cb);
+
+       ck_assert_int_eq(opt_duration_cb(&opt, "1m", 0), 0);
+       ck_assert_int_eq(params.duration, 60);
+}
+END_TEST
+
+START_TEST(test_opt_duration_cb_invalid)
+{
+       struct common_params params = {0};
+       const struct option opt = TEST_CALLBACK(&params, opt_duration_cb);
+
+       assert(freopen("/dev/null", "w", stderr));
+       opt_duration_cb(&opt, "abc", 0);
+}
+END_TEST
+
+START_TEST(test_opt_event_cb)
+{
+       struct trace_events *events = NULL;
+       const struct option opt = TEST_CALLBACK(&events, opt_event_cb);
+
+       ck_assert_int_eq(opt_event_cb(&opt, "sched:sched_switch", 0), 0);
+       ck_assert_str_eq(events->system, "sched");
+       ck_assert_str_eq(events->event, "sched_switch");
+       ck_assert_ptr_eq(events->next, NULL);
+}
+END_TEST
+
+START_TEST(test_opt_event_cb_multiple)
+{
+       struct trace_events *events = NULL;
+       const struct option opt = TEST_CALLBACK(&events, opt_event_cb);
+
+       ck_assert_int_eq(opt_event_cb(&opt, "sched:sched_switch", 0), 0);
+       ck_assert_int_eq(opt_event_cb(&opt, "sched:sched_wakeup", 0), 0);
+       ck_assert_str_eq(events->system, "sched");
+       ck_assert_str_eq(events->event, "sched_wakeup");
+       ck_assert_str_eq(events->next->system, "sched");
+       ck_assert_str_eq(events->next->event, "sched_switch");
+       ck_assert_ptr_eq(events->next->next, NULL);
+}
+END_TEST
+
+START_TEST(test_opt_housekeeping_cb)
+{
+       struct common_params __params = {0};
+       struct common_params *params = &__params;
+       const struct option opt = TEST_CALLBACK(params, opt_housekeeping_cb);
+
+       nr_cpus = 4;
+       ck_assert_int_eq(opt_housekeeping_cb(&opt, "0-3", 0), 0);
+       ck_assert_int_eq(params->hk_cpus, 1);
+       CLI_ASSERT_CPUSET(hk_cpu_set, 0, 1, 2, 3);
+}
+END_TEST
+
+START_TEST(test_opt_housekeeping_cb_invalid)
+{
+       struct common_params params = {0};
+       const struct option opt = TEST_CALLBACK(&params, opt_housekeeping_cb);
+
+       nr_cpus = 4;
+       assert(freopen("/dev/null", "w", stderr));
+       opt_housekeeping_cb(&opt, "0-3,5", 0);
+}
+END_TEST
+
+START_TEST(test_opt_priority_cb)
+{
+       struct common_params params = {0};
+       const struct option opt = TEST_CALLBACK(&params, opt_priority_cb);
+
+       ck_assert_int_eq(opt_priority_cb(&opt, "f:95", 0), 0);
+       ck_assert_int_eq(params.sched_param.sched_policy, SCHED_FIFO);
+       ck_assert_int_eq(params.sched_param.sched_priority, 95);
+}
+END_TEST
+
+START_TEST(test_opt_priority_cb_invalid)
+{
+       struct common_params params = {0};
+       const struct option opt = TEST_CALLBACK(&params, opt_priority_cb);
+
+       assert(freopen("/dev/null", "w", stderr));
+       opt_priority_cb(&opt, "abc", 0);
+}
+END_TEST
+
+START_TEST(test_opt_trigger_cb)
+{
+       struct trace_events *events = trace_event_alloc("sched:sched_switch");
+       const struct option opt = TEST_CALLBACK(&events, opt_trigger_cb);
+
+       ck_assert_int_eq(opt_trigger_cb(&opt, "stacktrace", 0), 0);
+       ck_assert_str_eq(events->trigger, "stacktrace");
+}
+END_TEST
+
+START_TEST(test_opt_trigger_cb_no_event)
+{
+       struct trace_events *events = NULL;
+       const struct option opt = TEST_CALLBACK(&events, opt_trigger_cb);
+
+       assert(freopen("/dev/null", "w", stderr));
+       opt_trigger_cb(&opt, "stacktrace", 0);
+}
+END_TEST
+
+START_TEST(test_opt_filter_cb)
+{
+       struct trace_events *events = trace_event_alloc("sched:sched_switch");
+       const struct option opt = TEST_CALLBACK(&events, opt_filter_cb);
+
+       ck_assert_int_eq(opt_filter_cb(&opt, "comm ~ \"rtla\"", 0), 0);
+       ck_assert_str_eq(events->filter, "comm ~ \"rtla\"");
+}
+END_TEST
+
+START_TEST(test_opt_filter_cb_no_event)
+{
+       struct trace_events *events = NULL;
+       const struct option opt = TEST_CALLBACK(&events, opt_filter_cb);
+
+       assert(freopen("/dev/null", "w", stderr));
+       opt_filter_cb(&opt, "comm ~ \"rtla\"", 0);
+}
+END_TEST
+
+START_TEST(test_opt_osnoise_auto_cb)
+{
+       struct osnoise_params params = {0};
+       struct osnoise_cb_data cb_data = {&params};
+       const struct option opt = TEST_CALLBACK(&cb_data, opt_osnoise_auto_cb);
+
+       ck_assert_int_eq(opt_osnoise_auto_cb(&opt, "10", 0), 0);
+       ck_assert_int_eq(params.common.stop_us, 10);
+       ck_assert_int_eq(params.threshold, 1);
+       ck_assert_str_eq(cb_data.trace_output, "osnoise_trace.txt");
+}
+END_TEST
+
+START_TEST(test_opt_osnoise_period_cb)
+{
+       unsigned long long period = 0;
+       const struct option opt = TEST_CALLBACK(&period, opt_osnoise_period_cb);
+
+       ck_assert_int_eq(opt_osnoise_period_cb(&opt, "1000000", 0), 0);
+       ck_assert_int_eq(period, 1000000);
+}
+END_TEST
+
+START_TEST(test_opt_osnoise_period_cb_invalid)
+{
+       unsigned long long period = 0;
+       const struct option opt = TEST_CALLBACK(&period, opt_osnoise_period_cb);
+
+       assert(freopen("/dev/null", "w", stderr));
+       opt_osnoise_period_cb(&opt, "10000001", 0);
+}
+END_TEST
+
+START_TEST(test_opt_osnoise_runtime_cb)
+{
+       unsigned long long runtime = 0;
+       const struct option opt = TEST_CALLBACK(&runtime, opt_osnoise_runtime_cb);
+
+       ck_assert_int_eq(opt_osnoise_runtime_cb(&opt, "900000", 0), 0);
+       ck_assert_int_eq(runtime, 900000);
+}
+END_TEST
+
+START_TEST(test_opt_osnoise_runtime_cb_invalid)
+{
+       unsigned long long runtime = 0;
+       const struct option opt = TEST_CALLBACK(&runtime, opt_osnoise_runtime_cb);
+
+       assert(freopen("/dev/null", "w", stderr));
+       opt_osnoise_runtime_cb(&opt, "99", 0);
+}
+END_TEST
+
+START_TEST(test_opt_osnoise_trace_output_cb)
+{
+       const char *trace_output = NULL;
+       const struct option opt = TEST_CALLBACK(&trace_output, opt_osnoise_trace_output_cb);
+
+       ck_assert_int_eq(opt_osnoise_trace_output_cb(&opt, "trace.txt", 0), 0);
+       ck_assert_str_eq(trace_output, "trace.txt");
+}
+END_TEST
+
+START_TEST(test_opt_osnoise_trace_output_cb_noarg)
+{
+       const char *trace_output = NULL;
+       const struct option opt = TEST_CALLBACK(&trace_output, opt_osnoise_trace_output_cb);
+
+       ck_assert_int_eq(opt_osnoise_trace_output_cb(&opt, NULL, 0), 0);
+       ck_assert_str_eq(trace_output, "osnoise_trace.txt");
+}
+END_TEST
+
+START_TEST(test_opt_osnoise_on_threshold_cb)
+{
+       struct actions actions = {0};
+       const struct option opt = TEST_CALLBACK(&actions, opt_osnoise_on_threshold_cb);
+
+       ck_assert_int_eq(opt_osnoise_on_threshold_cb(&opt, "trace", 0), 0);
+       ck_assert_int_eq(actions.len, 1);
+       ck_assert_int_eq(actions.list[0].type, ACTION_TRACE_OUTPUT);
+       ck_assert_str_eq(actions.list[0].trace_output, "osnoise_trace.txt");
+}
+END_TEST
+
+START_TEST(test_opt_osnoise_on_threshold_cb_invalid)
+{
+       struct actions actions = {0};
+       const struct option opt = TEST_CALLBACK(&actions, opt_osnoise_on_threshold_cb);
+
+       assert(freopen("/dev/null", "w", stderr));
+       opt_osnoise_on_threshold_cb(&opt, "abc", 0);
+}
+END_TEST
+
+START_TEST(test_opt_osnoise_on_end_cb)
+{
+       struct actions actions = {0};
+       const struct option opt = TEST_CALLBACK(&actions, opt_osnoise_on_end_cb);
+
+       ck_assert_int_eq(opt_osnoise_on_end_cb(&opt, "trace", 0), 0);
+       ck_assert_int_eq(actions.len, 1);
+       ck_assert_int_eq(actions.list[0].type, ACTION_TRACE_OUTPUT);
+       ck_assert_str_eq(actions.list[0].trace_output, "osnoise_trace.txt");
+}
+END_TEST
+
+START_TEST(test_opt_osnoise_on_end_cb_invalid)
+{
+       struct actions actions = {0};
+       const struct option opt = TEST_CALLBACK(&actions, opt_osnoise_on_end_cb);
+
+       assert(freopen("/dev/null", "w", stderr));
+       opt_osnoise_on_end_cb(&opt, "abc", 0);
+}
+END_TEST
+
+START_TEST(test_opt_timerlat_period_cb)
+{
+       long long period = 0;
+       const struct option opt = TEST_CALLBACK(&period, opt_timerlat_period_cb);
+
+       ck_assert_int_eq(opt_timerlat_period_cb(&opt, "1000", 0), 0);
+       ck_assert_int_eq(period, 1000);
+}
+END_TEST
+
+START_TEST(test_opt_timerlat_period_cb_invalid)
+{
+       long long period = 0;
+       const struct option opt = TEST_CALLBACK(&period, opt_timerlat_period_cb);
+
+       assert(freopen("/dev/null", "w", stderr));
+       opt_timerlat_period_cb(&opt, "1000001", 0);
+}
+END_TEST
+
+START_TEST(test_opt_timerlat_auto_cb)
+{
+       struct timerlat_params params = {0};
+       struct timerlat_cb_data cb_data = {&params};
+       const struct option opt = TEST_CALLBACK(&cb_data, opt_timerlat_auto_cb);
+
+       ck_assert_int_eq(opt_timerlat_auto_cb(&opt, "10", 0), 0);
+       ck_assert_int_eq(params.common.stop_us, 10);
+       ck_assert_int_eq(params.common.stop_total_us, 10);
+       ck_assert_int_eq(params.print_stack, 10);
+       ck_assert_str_eq(cb_data.trace_output, "timerlat_trace.txt");
+}
+END_TEST
+
+START_TEST(test_opt_dma_latency_cb)
+{
+       int dma_latency = 0;
+       const struct option opt = TEST_CALLBACK(&dma_latency, opt_dma_latency_cb);
+
+       ck_assert_int_eq(opt_dma_latency_cb(&opt, "1000", 0), 0);
+       ck_assert_int_eq(dma_latency, 1000);
+}
+END_TEST
+
+START_TEST(test_opt_dma_latency_cb_min)
+{
+       int dma_latency = 0;
+       const struct option opt = TEST_CALLBACK(&dma_latency, opt_dma_latency_cb);
+
+       assert(freopen("/dev/null", "w", stderr));
+       opt_dma_latency_cb(&opt, "-1", 0);
+}
+END_TEST
+
+START_TEST(test_opt_dma_latency_cb_max)
+{
+       int dma_latency = 0;
+       const struct option opt = TEST_CALLBACK(&dma_latency, opt_dma_latency_cb);
+
+       assert(freopen("/dev/null", "w", stderr));
+       opt_dma_latency_cb(&opt, "10001", 0);
+}
+END_TEST
+
+START_TEST(test_opt_aa_only_cb)
+{
+       struct timerlat_params params = {0};
+       const struct option opt = TEST_CALLBACK(&params, opt_aa_only_cb);
+
+       ck_assert_int_eq(opt_aa_only_cb(&opt, "10", 0), 0);
+       ck_assert_int_eq(params.common.stop_us, 10);
+       ck_assert_int_eq(params.common.stop_total_us, 10);
+       ck_assert_int_eq(params.print_stack, 10);
+       ck_assert_int_eq(params.common.aa_only, 1);
+}
+END_TEST
+
+START_TEST(test_opt_timerlat_trace_output_cb)
+{
+       const char *trace_output = NULL;
+       const struct option opt = TEST_CALLBACK(&trace_output, opt_timerlat_trace_output_cb);
+
+       ck_assert_int_eq(opt_timerlat_trace_output_cb(&opt, "trace.txt", 0), 0);
+       ck_assert_str_eq(trace_output, "trace.txt");
+}
+END_TEST
+
+START_TEST(test_opt_timerlat_trace_output_cb_noarg)
+{
+       const char *trace_output = NULL;
+       const struct option opt = TEST_CALLBACK(&trace_output, opt_timerlat_trace_output_cb);
+
+       ck_assert_int_eq(opt_timerlat_trace_output_cb(&opt, NULL, 0), 0);
+       ck_assert_str_eq(trace_output, "timerlat_trace.txt");
+}
+END_TEST
+
+START_TEST(test_opt_timerlat_on_threshold_cb)
+{
+       struct actions actions = {0};
+       const struct option opt = TEST_CALLBACK(&actions, opt_timerlat_on_threshold_cb);
+
+       ck_assert_int_eq(opt_timerlat_on_threshold_cb(&opt, "trace", 0), 0);
+       ck_assert_int_eq(actions.len, 1);
+       ck_assert_int_eq(actions.list[0].type, ACTION_TRACE_OUTPUT);
+       ck_assert_str_eq(actions.list[0].trace_output, "timerlat_trace.txt");
+}
+END_TEST
+
+START_TEST(test_opt_timerlat_on_threshold_cb_invalid)
+{
+       struct actions actions = {0};
+       const struct option opt = TEST_CALLBACK(&actions, opt_timerlat_on_threshold_cb);
+
+       assert(freopen("/dev/null", "w", stderr));
+       opt_timerlat_on_threshold_cb(&opt, "abc", 0);
+}
+END_TEST
+
+START_TEST(test_opt_timerlat_on_end_cb)
+{
+       struct actions actions = {0};
+       const struct option opt = TEST_CALLBACK(&actions, opt_timerlat_on_end_cb);
+
+       ck_assert_int_eq(opt_timerlat_on_end_cb(&opt, "trace", 0), 0);
+       ck_assert_int_eq(actions.len, 1);
+       ck_assert_int_eq(actions.list[0].type, ACTION_TRACE_OUTPUT);
+       ck_assert_str_eq(actions.list[0].trace_output, "timerlat_trace.txt");
+}
+END_TEST
+
+START_TEST(test_opt_timerlat_on_end_cb_invalid)
+{
+       struct actions actions = {0};
+       const struct option opt = TEST_CALLBACK(&actions, opt_timerlat_on_end_cb);
+
+       assert(freopen("/dev/null", "w", stderr));
+       opt_timerlat_on_end_cb(&opt, "abc", 0);
+}
+END_TEST
+
+START_TEST(test_opt_user_threads_cb)
+{
+       struct timerlat_params params = {0};
+       const struct option opt = TEST_CALLBACK(&params, opt_user_threads_cb);
+
+       ck_assert_int_eq(opt_user_threads_cb(&opt, NULL, 0), 0);
+       ck_assert_int_eq(params.common.user_workload, 1);
+       ck_assert_int_eq(params.common.user_data, 1);
+}
+END_TEST
+
+START_TEST(test_opt_nano_cb)
+{
+       struct timerlat_params params = {0};
+       const struct option opt = TEST_CALLBACK(&params, opt_nano_cb);
+
+       ck_assert_int_eq(opt_nano_cb(&opt, NULL, 0), 0);
+       ck_assert_int_eq(params.common.output_divisor, 1);
+}
+END_TEST
+
+START_TEST(test_opt_stack_format_cb)
+{
+       int stack_format = 0;
+       const struct option opt = TEST_CALLBACK(&stack_format, opt_stack_format_cb);
+
+       ck_assert_int_eq(opt_stack_format_cb(&opt, "full", 0), 0);
+       ck_assert_int_eq(stack_format, STACK_FORMAT_FULL);
+}
+END_TEST
+
+START_TEST(test_opt_stack_format_cb_invalid)
+{
+       int stack_format = 0;
+       const struct option opt = TEST_CALLBACK(&stack_format, opt_stack_format_cb);
+
+       assert(freopen("/dev/null", "w", stderr));
+       opt_stack_format_cb(&opt, "abc", 0);
+}
+END_TEST
+
+START_TEST(test_opt_bucket_size_cb)
+{
+       int bucket_size = 0;
+       const struct option opt = TEST_CALLBACK(&bucket_size, opt_bucket_size_cb);
+
+       ck_assert_int_eq(opt_bucket_size_cb(&opt, "100", 0), 0);
+       ck_assert_int_eq(bucket_size, 100);
+}
+END_TEST
+
+START_TEST(test_opt_bucket_size_min)
+{
+       int bucket_size = 0;
+       const struct option opt = TEST_CALLBACK(&bucket_size, opt_bucket_size_cb);
+
+       assert(freopen("/dev/null", "w", stderr));
+       opt_bucket_size_cb(&opt, "0", 0);
+}
+END_TEST
+
+START_TEST(test_opt_bucket_size_max)
+{
+       int bucket_size = 0;
+       const struct option opt = TEST_CALLBACK(&bucket_size, opt_bucket_size_cb);
+
+       assert(freopen("/dev/null", "w", stderr));
+       opt_bucket_size_cb(&opt, "1000001", 0);
+}
+END_TEST
+
+START_TEST(test_opt_entries_cb)
+{
+       int entries = 0;
+       const struct option opt = TEST_CALLBACK(&entries, opt_entries_cb);
+
+       ck_assert_int_eq(opt_entries_cb(&opt, "100", 0), 0);
+       ck_assert_int_eq(entries, 100);
+}
+END_TEST
+
+START_TEST(test_opt_entries_min)
+{
+       int entries = 0;
+       const struct option opt = TEST_CALLBACK(&entries, opt_entries_cb);
+
+       assert(freopen("/dev/null", "w", stderr));
+       opt_entries_cb(&opt, "9", 0);
+}
+END_TEST
+
+START_TEST(test_opt_entries_max)
+{
+       int entries = 0;
+       const struct option opt = TEST_CALLBACK(&entries, opt_entries_cb);
+
+       assert(freopen("/dev/null", "w", stderr));
+       opt_entries_cb(&opt, "10000000", 0);
+}
+END_TEST
+
+Suite *cli_opt_callback_suite(void)
+{
+       Suite *s = suite_create("cli_opt_callback");
+       TCase *tc;
+
+       tc = tcase_create("common");
+       tcase_add_test(tc, test_opt_llong_callback_simple);
+       tcase_add_test(tc, test_opt_llong_callback_max);
+       tcase_add_test(tc, test_opt_llong_callback_min);
+       tcase_add_test(tc, test_opt_int_callback_simple);
+       tcase_add_test(tc, test_opt_int_callback_max);
+       tcase_add_test(tc, test_opt_int_callback_min);
+       tcase_add_test(tc, test_opt_int_callback_non_numeric);
+       tcase_add_test(tc, test_opt_int_callback_non_numeric_suffix);
+       tcase_add_test(tc, test_opt_cpus_cb);
+       tcase_add_exit_test(tc, test_opt_cpus_cb_invalid, EXIT_FAILURE);
+       tcase_add_test(tc, test_opt_cgroup_cb);
+       tcase_add_test(tc, test_opt_cgroup_cb_equals);
+       tcase_add_test(tc, test_opt_duration_cb);
+       tcase_add_exit_test(tc, test_opt_duration_cb_invalid, EXIT_FAILURE);
+       tcase_add_test(tc, test_opt_event_cb);
+       tcase_add_test(tc, test_opt_event_cb_multiple);
+       tcase_add_test(tc, test_opt_housekeeping_cb);
+       tcase_add_exit_test(tc, test_opt_housekeeping_cb_invalid, EXIT_FAILURE);
+       tcase_add_test(tc, test_opt_priority_cb);
+       tcase_add_exit_test(tc, test_opt_priority_cb_invalid, EXIT_FAILURE);
+       tcase_add_test(tc, test_opt_trigger_cb);
+       tcase_add_exit_test(tc, test_opt_trigger_cb_no_event, EXIT_FAILURE);
+       tcase_add_test(tc, test_opt_filter_cb);
+       tcase_add_exit_test(tc, test_opt_filter_cb_no_event, EXIT_FAILURE);
+       suite_add_tcase(s, tc);
+
+       tc = tcase_create("osnoise");
+       tcase_add_test(tc, test_opt_osnoise_auto_cb);
+       tcase_add_test(tc, test_opt_osnoise_period_cb);
+       tcase_add_exit_test(tc, test_opt_osnoise_period_cb_invalid, EXIT_FAILURE);
+       tcase_add_test(tc, test_opt_osnoise_runtime_cb);
+       tcase_add_exit_test(tc, test_opt_osnoise_runtime_cb_invalid, EXIT_FAILURE);
+       tcase_add_test(tc, test_opt_osnoise_trace_output_cb);
+       tcase_add_test(tc, test_opt_osnoise_trace_output_cb_noarg);
+       tcase_add_test(tc, test_opt_osnoise_on_threshold_cb);
+       tcase_add_exit_test(tc, test_opt_osnoise_on_threshold_cb_invalid, EXIT_FAILURE);
+       tcase_add_test(tc, test_opt_osnoise_on_end_cb);
+       tcase_add_exit_test(tc, test_opt_osnoise_on_end_cb_invalid, EXIT_FAILURE);
+       suite_add_tcase(s, tc);
+
+       tc = tcase_create("timerlat");
+       tcase_add_test(tc, test_opt_timerlat_period_cb);
+       tcase_add_exit_test(tc, test_opt_timerlat_period_cb_invalid, EXIT_FAILURE);
+       tcase_add_test(tc, test_opt_timerlat_auto_cb);
+       tcase_add_test(tc, test_opt_dma_latency_cb);
+       tcase_add_exit_test(tc, test_opt_dma_latency_cb_min, EXIT_FAILURE);
+       tcase_add_exit_test(tc, test_opt_dma_latency_cb_max, EXIT_FAILURE);
+       tcase_add_test(tc, test_opt_aa_only_cb);
+       tcase_add_test(tc, test_opt_timerlat_trace_output_cb);
+       tcase_add_test(tc, test_opt_timerlat_trace_output_cb_noarg);
+       tcase_add_test(tc, test_opt_timerlat_on_threshold_cb);
+       tcase_add_exit_test(tc, test_opt_timerlat_on_threshold_cb_invalid, EXIT_FAILURE);
+       tcase_add_test(tc, test_opt_timerlat_on_end_cb);
+       tcase_add_exit_test(tc, test_opt_timerlat_on_end_cb_invalid, EXIT_FAILURE);
+       tcase_add_test(tc, test_opt_user_threads_cb);
+       tcase_add_test(tc, test_opt_nano_cb);
+       tcase_add_test(tc, test_opt_stack_format_cb);
+       tcase_add_exit_test(tc, test_opt_stack_format_cb_invalid, EXIT_FAILURE);
+       suite_add_tcase(s, tc);
+
+       tc = tcase_create("histogram");
+       tcase_add_test(tc, test_opt_bucket_size_cb);
+       tcase_add_exit_test(tc, test_opt_bucket_size_min, EXIT_FAILURE);
+       tcase_add_exit_test(tc, test_opt_bucket_size_max, EXIT_FAILURE);
+       tcase_add_test(tc, test_opt_entries_cb);
+       tcase_add_exit_test(tc, test_opt_entries_min, EXIT_FAILURE);
+       tcase_add_exit_test(tc, test_opt_entries_max, EXIT_FAILURE);
+       suite_add_tcase(s, tc);
+
+       return s;
+}
index 64884f6cbdebee324b8abe4e44ba41b7c8e828e2..75ca813f81ca088c24b1614bcbc21c06c84e0752 100644 (file)
@@ -13,6 +13,7 @@ Suite *osnoise_top_cli_suite(void);
 Suite *osnoise_hist_cli_suite(void);
 Suite *timerlat_top_cli_suite(void);
 Suite *timerlat_hist_cli_suite(void);
+Suite *cli_opt_callback_suite(void);
 
 int main(int argc, char *argv[])
 {
@@ -22,6 +23,7 @@ int main(int argc, char *argv[])
        in_unit_test = true;
 
        sr = srunner_create(utils_suite());
+       srunner_add_suite(sr, cli_opt_callback_suite());
        srunner_add_suite(sr, actions_suite());
        srunner_add_suite(sr, osnoise_top_cli_suite());
        srunner_add_suite(sr, osnoise_hist_cli_suite());