mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
synced 2026-10-31 14:23:49 +01:00
The current handling of invalid command line option arguments is
inconsistent:
- opt_llong_callback() treats non-numerical input the same as "-1",
which might or might not be rejected later.
- opt_int_callback() returns -1 on non-numerical input without an error
message, which makes parsing fail silently (libsubcmd will
automatically print the usage of the option only, no error message).
- custom callbacks abort command line parsing using fatal(), which
displays an error message and exits, without libsubcmd printing the
usage.
Unify this such that all invalid options, regardless of the format,
print an error message similar to the out of range case:
Error: --opt: 'value' is not a valid XY
followed by the usage of the option, e.g.:
$ rtla timerlat hist --period=1us
Error: --period: '1us' is not a valid number
Usage: rtla timerlat hist [<options>] [-h|--help]
-p, --period <us> timerlat period in us
As this is a libsubcmd help path, all option parsing failures now return
the exit code of 129 (help).
The unified handling is implemented using a new error message helper,
opt_err(), which is called from two new CLI-specific parsing functions,
strtoll_safe() and strtoi_safe(), as well as from custom helpers.
Option callback tests are updated to cover the new behavior.
Assisted-by: Claude:claude-opus-4-6
Reviewed-by: Wander Lairson Costa <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Tomas Glozar <[email protected]>
913 lines
27 KiB
C
913 lines
27 KiB
C
// 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)
|
|
#define TEST_LLONG_RANGE(value, lo, hi) \
|
|
RTLA_OPT_CALLBACK_DATA('t', "test", value, "test value", "test help", \
|
|
opt_llong_callback, LLONG_RANGE(lo, hi))
|
|
#define TEST_INT_RANGE(value, lo, hi) \
|
|
RTLA_OPT_CALLBACK_DATA('t', "test", value, "test value", "test help", \
|
|
opt_int_callback, INT_RANGE(lo, hi))
|
|
|
|
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_llong_callback_non_numeric)
|
|
{
|
|
long long test_value = 0;
|
|
const struct option opt = TEST_CALLBACK(&test_value, opt_llong_callback);
|
|
|
|
assert(freopen("/dev/null", "w", stderr));
|
|
ck_assert_int_eq(opt_llong_callback(&opt, "abc", 0), -1);
|
|
ck_assert_int_eq(test_value, 0);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_llong_callback_non_numeric_suffix)
|
|
{
|
|
long long test_value = 0;
|
|
const struct option opt = TEST_CALLBACK(&test_value, opt_llong_callback);
|
|
|
|
assert(freopen("/dev/null", "w", stderr));
|
|
ck_assert_int_eq(opt_llong_callback(&opt, "1234567890abc", 0), -1);
|
|
ck_assert_int_eq(test_value, 0);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_llong_callback_unset)
|
|
{
|
|
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(opt_llong_callback(&opt, NULL, 1), 0);
|
|
ck_assert_int_eq(test_value, 0);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_llong_callback_unset_defval)
|
|
{
|
|
long long test_value = 0;
|
|
const long long default_value = 42;
|
|
const struct option opt = RTLA_OPT_LLONG_DEFVAL('t', "test", &test_value, "test value",
|
|
"test help", &default_value);
|
|
|
|
ck_assert_int_eq(opt_llong_callback(&opt, "1234567890", 0), 0);
|
|
ck_assert_int_eq(opt_llong_callback(&opt, NULL, 1), 0);
|
|
ck_assert_int_eq(test_value, default_value);
|
|
}
|
|
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);
|
|
|
|
assert(freopen("/dev/null", "w", stderr));
|
|
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);
|
|
|
|
assert(freopen("/dev/null", "w", stderr));
|
|
ck_assert_int_eq(opt_int_callback(&opt, "1234567890abc", 0), -1);
|
|
ck_assert_int_eq(test_value, 0);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_int_callback_unset)
|
|
{
|
|
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(opt_int_callback(&opt, NULL, 1), 0);
|
|
ck_assert_int_eq(test_value, 0);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_int_callback_unset_defval)
|
|
{
|
|
int test_value = 0;
|
|
const struct option opt = RTLA_OPT_INT_DEFVAL('t', "test", &test_value, "test value",
|
|
"test help", 42);
|
|
|
|
ck_assert_int_eq(opt_int_callback(&opt, "1234567890", 0), 0);
|
|
ck_assert_int_eq(opt_int_callback(&opt, NULL, 1), 0);
|
|
ck_assert_int_eq(test_value, 42);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_llong_callback_range_in)
|
|
{
|
|
long long test_value = 0;
|
|
const struct option opt = TEST_LLONG_RANGE(&test_value, 10, 100);
|
|
|
|
ck_assert_int_eq(opt_llong_callback(&opt, "50", 0), 0);
|
|
ck_assert_int_eq(test_value, 50);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_llong_callback_range_below)
|
|
{
|
|
long long test_value = 0;
|
|
const struct option opt = TEST_LLONG_RANGE(&test_value, 10, 100);
|
|
|
|
assert(freopen("/dev/null", "w", stderr));
|
|
ck_assert_int_eq(opt_llong_callback(&opt, "9", 0), -1);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_llong_callback_range_above)
|
|
{
|
|
long long test_value = 0;
|
|
const struct option opt = TEST_LLONG_RANGE(&test_value, 10, 100);
|
|
|
|
assert(freopen("/dev/null", "w", stderr));
|
|
ck_assert_int_eq(opt_llong_callback(&opt, "101", 0), -1);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_llong_callback_range_boundary)
|
|
{
|
|
long long test_value = 0;
|
|
const struct option opt = TEST_LLONG_RANGE(&test_value, 10, 100);
|
|
|
|
ck_assert_int_eq(opt_llong_callback(&opt, "10", 0), 0);
|
|
ck_assert_int_eq(test_value, 10);
|
|
ck_assert_int_eq(opt_llong_callback(&opt, "100", 0), 0);
|
|
ck_assert_int_eq(test_value, 100);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_int_callback_range_in)
|
|
{
|
|
int test_value = 0;
|
|
const struct option opt = TEST_INT_RANGE(&test_value, 0, 10000);
|
|
|
|
ck_assert_int_eq(opt_int_callback(&opt, "5000", 0), 0);
|
|
ck_assert_int_eq(test_value, 5000);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_int_callback_range_below)
|
|
{
|
|
int test_value = 0;
|
|
const struct option opt = TEST_INT_RANGE(&test_value, 0, 10000);
|
|
|
|
assert(freopen("/dev/null", "w", stderr));
|
|
ck_assert_int_eq(opt_int_callback(&opt, "-1", 0), -1);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_int_callback_range_above)
|
|
{
|
|
int test_value = 0;
|
|
const struct option opt = TEST_INT_RANGE(&test_value, 0, 10000);
|
|
|
|
assert(freopen("/dev/null", "w", stderr));
|
|
ck_assert_int_eq(opt_int_callback(&opt, "10001", 0), -1);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_int_callback_range_boundary)
|
|
{
|
|
int test_value = 0;
|
|
const struct option opt = TEST_INT_RANGE(&test_value, 0, 10000);
|
|
|
|
ck_assert_int_eq(opt_int_callback(&opt, "0", 0), 0);
|
|
ck_assert_int_eq(test_value, 0);
|
|
ck_assert_int_eq(opt_int_callback(&opt, "10000", 0), 0);
|
|
ck_assert_int_eq(test_value, 10000);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_cpus_cb)
|
|
{
|
|
struct common_params params = {0};
|
|
const struct option opt = TEST_CALLBACK(¶ms, 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(¶ms, opt_cpus_cb);
|
|
|
|
nr_cpus = 4;
|
|
assert(freopen("/dev/null", "w", stderr));
|
|
ck_assert_int_eq(opt_cpus_cb(&opt, "0-3,5", 0), -1);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_cgroup_cb)
|
|
{
|
|
struct common_params params = {0};
|
|
const struct option opt = TEST_CALLBACK(¶ms, 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(¶ms, 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_unset)
|
|
{
|
|
struct common_params params = {0};
|
|
const struct option opt = TEST_CALLBACK(¶ms, opt_cgroup_cb);
|
|
|
|
ck_assert_int_eq(opt_cgroup_cb(&opt, "cgroup", 0), 0);
|
|
ck_assert_int_eq(opt_cgroup_cb(&opt, NULL, 1), 0);
|
|
ck_assert_int_eq(params.cgroup, 0);
|
|
ck_assert_ptr_null(params.cgroup_name);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_duration_cb)
|
|
{
|
|
struct common_params params = {0};
|
|
const struct option opt = TEST_CALLBACK(¶ms, 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(¶ms, opt_duration_cb);
|
|
|
|
assert(freopen("/dev/null", "w", stderr));
|
|
ck_assert_int_eq(opt_duration_cb(&opt, "abc", 0), -1);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_duration_cb_unset)
|
|
{
|
|
struct common_params params = {0};
|
|
const struct option opt = TEST_CALLBACK(¶ms, opt_duration_cb);
|
|
|
|
ck_assert_int_eq(opt_duration_cb(&opt, "1m", 0), 0);
|
|
ck_assert_int_eq(opt_duration_cb(&opt, NULL, 1), 0);
|
|
ck_assert_int_eq(params.duration, 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(¶ms, opt_housekeeping_cb);
|
|
|
|
nr_cpus = 4;
|
|
assert(freopen("/dev/null", "w", stderr));
|
|
ck_assert_int_eq(opt_housekeeping_cb(&opt, "0-3,5", 0), -1);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_housekeeping_cb_unset)
|
|
{
|
|
struct common_params params = {0};
|
|
const struct option opt = TEST_CALLBACK(¶ms, opt_housekeeping_cb);
|
|
|
|
nr_cpus = 4;
|
|
ck_assert_int_eq(opt_housekeeping_cb(&opt, "0-3", 0), 0);
|
|
ck_assert_int_eq(opt_housekeeping_cb(&opt, NULL, 1), 0);
|
|
ck_assert_int_eq(params.hk_cpus, 0);
|
|
ck_assert_int_eq(CPU_COUNT(¶ms.hk_cpu_set), 0);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_priority_cb)
|
|
{
|
|
struct common_params params = {0};
|
|
const struct option opt = TEST_CALLBACK(¶ms, 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(¶ms, opt_priority_cb);
|
|
|
|
assert(freopen("/dev/null", "w", stderr));
|
|
ck_assert_int_eq(opt_priority_cb(&opt, "abc", 0), -1);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_priority_cb_unset)
|
|
{
|
|
struct common_params params = {0};
|
|
const struct option opt = TEST_CALLBACK(¶ms, opt_priority_cb);
|
|
|
|
ck_assert_int_eq(opt_priority_cb(&opt, "f:95", 0), 0);
|
|
ck_assert_int_eq(opt_priority_cb(&opt, NULL, 1), 0);
|
|
ck_assert_int_eq(params.sched_param.sched_policy, 0);
|
|
ck_assert_int_eq(params.sched_param.sched_priority, 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));
|
|
ck_assert_int_eq(opt_trigger_cb(&opt, "stacktrace", 0), -1);
|
|
}
|
|
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));
|
|
ck_assert_int_eq(opt_filter_cb(&opt, "comm ~ \"rtla\"", 0), -1);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_osnoise_auto_cb)
|
|
{
|
|
struct osnoise_params params = {0};
|
|
struct osnoise_cb_data cb_data = {¶ms};
|
|
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_auto_cb_unset)
|
|
{
|
|
struct osnoise_params params = {0};
|
|
struct osnoise_cb_data cb_data = {¶ms};
|
|
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(opt_osnoise_auto_cb(&opt, NULL, 1), 0);
|
|
ck_assert_int_eq(params.common.stop_us, 0);
|
|
ck_assert_int_eq(params.threshold, 0);
|
|
ck_assert_ptr_null(cb_data.trace_output);
|
|
}
|
|
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_trace_output_cb_unset)
|
|
{
|
|
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_int_eq(opt_osnoise_trace_output_cb(&opt, NULL, 1), 0);
|
|
ck_assert_ptr_null(trace_output);
|
|
}
|
|
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));
|
|
ck_assert_int_eq(opt_osnoise_on_threshold_cb(&opt, "abc", 0), -1);
|
|
}
|
|
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));
|
|
ck_assert_int_eq(opt_osnoise_on_end_cb(&opt, "abc", 0), -1);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_timerlat_auto_cb)
|
|
{
|
|
struct timerlat_params params = {0};
|
|
struct timerlat_cb_data cb_data = {¶ms};
|
|
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_timerlat_auto_cb_unset)
|
|
{
|
|
struct timerlat_params params = {0};
|
|
struct timerlat_cb_data cb_data = {¶ms};
|
|
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(opt_timerlat_auto_cb(&opt, NULL, 1), 0);
|
|
ck_assert_int_eq(params.common.stop_us, 0);
|
|
ck_assert_int_eq(params.common.stop_total_us, 0);
|
|
ck_assert_int_eq(params.print_stack, 0);
|
|
ck_assert_ptr_null(cb_data.trace_output);
|
|
}
|
|
END_TEST
|
|
|
|
|
|
START_TEST(test_opt_aa_only_cb)
|
|
{
|
|
struct timerlat_params params = {0};
|
|
const struct option opt = TEST_CALLBACK(¶ms, 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_aa_only_cb_unset)
|
|
{
|
|
struct timerlat_params params = {0};
|
|
const struct option opt = TEST_CALLBACK(¶ms, opt_aa_only_cb);
|
|
|
|
ck_assert_int_eq(opt_aa_only_cb(&opt, "10", 0), 0);
|
|
ck_assert_int_eq(opt_aa_only_cb(&opt, NULL, 1), 0);
|
|
ck_assert_int_eq(params.common.stop_us, 0);
|
|
ck_assert_int_eq(params.common.stop_total_us, 0);
|
|
ck_assert_int_eq(params.print_stack, 0);
|
|
ck_assert_int_eq(params.common.aa_only, 0);
|
|
}
|
|
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_trace_output_cb_unset)
|
|
{
|
|
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_int_eq(opt_timerlat_trace_output_cb(&opt, NULL, 1), 0);
|
|
ck_assert_ptr_null(trace_output);
|
|
}
|
|
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));
|
|
ck_assert_int_eq(opt_timerlat_on_threshold_cb(&opt, "abc", 0), -1);
|
|
}
|
|
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));
|
|
ck_assert_int_eq(opt_timerlat_on_end_cb(&opt, "abc", 0), -1);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_user_threads_cb)
|
|
{
|
|
struct timerlat_params params = {0};
|
|
const struct option opt = TEST_CALLBACK(¶ms, 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_user_threads_cb_unset)
|
|
{
|
|
struct timerlat_params params = {0};
|
|
const struct option opt = TEST_CALLBACK(¶ms, opt_user_threads_cb);
|
|
|
|
ck_assert_int_eq(opt_user_threads_cb(&opt, NULL, 0), 0);
|
|
ck_assert_int_eq(opt_user_threads_cb(&opt, NULL, 1), 0);
|
|
ck_assert_int_eq(params.common.user_workload, 0);
|
|
ck_assert_int_eq(params.common.user_data, 0);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_nano_cb)
|
|
{
|
|
struct timerlat_params params = {0};
|
|
const struct option opt = TEST_CALLBACK(¶ms, 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_nano_cb_unset)
|
|
{
|
|
struct timerlat_params params = {0};
|
|
const struct option opt = TEST_CALLBACK(¶ms, opt_nano_cb);
|
|
|
|
ck_assert_int_eq(opt_nano_cb(&opt, NULL, 0), 0);
|
|
ck_assert_int_eq(opt_nano_cb(&opt, NULL, 1), 0);
|
|
ck_assert_int_eq(params.common.output_divisor, default_output_divisor);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_timerlat_align_cb)
|
|
{
|
|
struct timerlat_params params = {0};
|
|
const struct option opt = RTLA_OPT_CALLBACK_DATA('A', "aligned", ¶ms, "us",
|
|
"test", opt_timerlat_align_cb, LLONG_RANGE(0, LLONG_MAX));
|
|
|
|
ck_assert_int_eq(opt_timerlat_align_cb(&opt, "500", 0), 0);
|
|
ck_assert(params.timerlat_align);
|
|
ck_assert_int_eq(params.timerlat_align_us, 500);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_timerlat_align_cb_invalid)
|
|
{
|
|
struct timerlat_params params = {0};
|
|
const struct option opt = RTLA_OPT_CALLBACK_DATA('A', "aligned", ¶ms, "us",
|
|
"test", opt_timerlat_align_cb, LLONG_RANGE(0, LLONG_MAX));
|
|
|
|
assert(freopen("/dev/null", "w", stderr));
|
|
ck_assert_int_eq(opt_timerlat_align_cb(&opt, "-1", 0), -1);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_timerlat_align_cb_unset)
|
|
{
|
|
struct timerlat_params params = {0};
|
|
const struct option opt = RTLA_OPT_CALLBACK_DATA('A', "aligned", ¶ms, "us",
|
|
"test", opt_timerlat_align_cb, LLONG_RANGE(0, LLONG_MAX));
|
|
|
|
ck_assert_int_eq(opt_timerlat_align_cb(&opt, "500", 0), 0);
|
|
ck_assert_int_eq(opt_timerlat_align_cb(&opt, NULL, 1), 0);
|
|
ck_assert_int_eq(params.timerlat_align, 0);
|
|
ck_assert_int_eq(params.timerlat_align_us, 0);
|
|
}
|
|
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));
|
|
ck_assert_int_eq(opt_stack_format_cb(&opt, "abc", 0), -1);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_opt_stack_format_cb_unset)
|
|
{
|
|
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(opt_stack_format_cb(&opt, NULL, 1), 0);
|
|
ck_assert_int_eq(stack_format, default_stack_format);
|
|
}
|
|
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_llong_callback_non_numeric);
|
|
tcase_add_test(tc, test_opt_llong_callback_non_numeric_suffix);
|
|
tcase_add_test(tc, test_opt_llong_callback_unset);
|
|
tcase_add_test(tc, test_opt_llong_callback_unset_defval);
|
|
tcase_add_test(tc, test_opt_llong_callback_range_in);
|
|
tcase_add_test(tc, test_opt_llong_callback_range_below);
|
|
tcase_add_test(tc, test_opt_llong_callback_range_above);
|
|
tcase_add_test(tc, test_opt_llong_callback_range_boundary);
|
|
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_int_callback_unset);
|
|
tcase_add_test(tc, test_opt_int_callback_unset_defval);
|
|
tcase_add_test(tc, test_opt_int_callback_range_in);
|
|
tcase_add_test(tc, test_opt_int_callback_range_below);
|
|
tcase_add_test(tc, test_opt_int_callback_range_above);
|
|
tcase_add_test(tc, test_opt_int_callback_range_boundary);
|
|
tcase_add_test(tc, test_opt_cpus_cb);
|
|
tcase_add_test(tc, test_opt_cpus_cb_invalid);
|
|
tcase_add_test(tc, test_opt_cgroup_cb);
|
|
tcase_add_test(tc, test_opt_cgroup_cb_equals);
|
|
tcase_add_test(tc, test_opt_cgroup_cb_unset);
|
|
tcase_add_test(tc, test_opt_duration_cb);
|
|
tcase_add_test(tc, test_opt_duration_cb_unset);
|
|
tcase_add_test(tc, test_opt_duration_cb_invalid);
|
|
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_test(tc, test_opt_housekeeping_cb_invalid);
|
|
tcase_add_test(tc, test_opt_housekeeping_cb_unset);
|
|
tcase_add_test(tc, test_opt_priority_cb);
|
|
tcase_add_test(tc, test_opt_priority_cb_invalid);
|
|
tcase_add_test(tc, test_opt_priority_cb_unset);
|
|
tcase_add_test(tc, test_opt_trigger_cb);
|
|
tcase_add_test(tc, test_opt_trigger_cb_no_event);
|
|
tcase_add_test(tc, test_opt_filter_cb);
|
|
tcase_add_test(tc, test_opt_filter_cb_no_event);
|
|
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_auto_cb_unset);
|
|
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_trace_output_cb_unset);
|
|
tcase_add_test(tc, test_opt_osnoise_on_threshold_cb);
|
|
tcase_add_test(tc, test_opt_osnoise_on_threshold_cb_invalid);
|
|
tcase_add_test(tc, test_opt_osnoise_on_end_cb);
|
|
tcase_add_test(tc, test_opt_osnoise_on_end_cb_invalid);
|
|
suite_add_tcase(s, tc);
|
|
|
|
tc = tcase_create("timerlat");
|
|
tcase_add_test(tc, test_opt_timerlat_auto_cb);
|
|
tcase_add_test(tc, test_opt_timerlat_auto_cb_unset);
|
|
tcase_add_test(tc, test_opt_aa_only_cb);
|
|
tcase_add_test(tc, test_opt_aa_only_cb_unset);
|
|
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_trace_output_cb_unset);
|
|
tcase_add_test(tc, test_opt_timerlat_on_threshold_cb);
|
|
tcase_add_test(tc, test_opt_timerlat_on_threshold_cb_invalid);
|
|
tcase_add_test(tc, test_opt_timerlat_on_end_cb);
|
|
tcase_add_test(tc, test_opt_timerlat_on_end_cb_invalid);
|
|
tcase_add_test(tc, test_opt_user_threads_cb);
|
|
tcase_add_test(tc, test_opt_user_threads_cb_unset);
|
|
tcase_add_test(tc, test_opt_nano_cb);
|
|
tcase_add_test(tc, test_opt_nano_cb_unset);
|
|
tcase_add_test(tc, test_opt_stack_format_cb);
|
|
tcase_add_test(tc, test_opt_stack_format_cb_invalid);
|
|
tcase_add_test(tc, test_opt_stack_format_cb_unset);
|
|
tcase_add_test(tc, test_opt_timerlat_align_cb);
|
|
tcase_add_test(tc, test_opt_timerlat_align_cb_invalid);
|
|
tcase_add_test(tc, test_opt_timerlat_align_cb_unset);
|
|
suite_add_tcase(s, tc);
|
|
|
|
return s;
|
|
}
|