@@ -152,7 +152,8 @@ void spl_board_init(void)
ut_init_state(&uts);
ret = ut_run_list(&uts, "spl", NULL, tests, count,
- state->select_unittests, 1, false, NULL);
+ state->select_unittests, 1, false, NULL,
+ 0, NULL);
ut_report(&uts.cur, 1);
ut_uninit_state(&uts);
/* continue execution into U-Boot */
@@ -9,6 +9,8 @@
#include <malloc.h>
#include <linux/bitops.h>
+#define UT_MAX_ARGS 8
+
/**
* struct ut_stats - Statistics about tests run
*
@@ -90,6 +92,8 @@ struct ut_arg {
* @soft_fail: continue execution of the test even after it fails
* @expect_str: Temporary string used to hold expected string value
* @actual_str: Temporary string used to hold actual string value
+ * @args: Parsed argument values for current test
+ * @arg_count: Number of parsed arguments
*/
struct unit_test_state {
struct ut_stats cur;
@@ -116,6 +120,8 @@ struct unit_test_state {
bool soft_fail;
char expect_str[1024];
char actual_str[1024];
+ struct ut_arg args[UT_MAX_ARGS];
+ int arg_count;
};
/* Test flags for each test */
@@ -618,12 +618,14 @@ void ut_uninit_state(struct unit_test_state *uts);
* name is the name of the test to run. This is used to find which test causes
* another test to fail. If the one test fails, testing stops immediately.
* Pass NULL to disable this
+ * @argc: Number of test arguments (key=value pairs), 0 if none
+ * @argv: Test argument array, NULL if none
* Return: 0 if all tests passed, -1 if any failed
*/
int ut_run_list(struct unit_test_state *uts, const char *category,
const char *prefix, struct unit_test *tests, int count,
const char *select_name, int runs_per_test, bool force_run,
- const char *test_insert);
+ const char *test_insert, int argc, char *const argv[]);
/**
* ut_report() - Report stats on a test run
@@ -132,7 +132,8 @@ static int run_suite(struct unit_test_state *uts, struct suite *ste,
snprintf(prefix, sizeof(prefix), "%s_test_", ste->name);
ret = ut_run_list(uts, ste->name, prefix, ste->start, n_ents,
- select_name, runs_per_test, force_run, test_insert);
+ select_name, runs_per_test, force_run, test_insert,
+ 0, NULL);
return ret;
}
@@ -89,6 +89,154 @@ void ut_uninit_state(struct unit_test_state *uts)
}
}
+/**
+ * ut_count_args() - Count the number of arguments in a NULL-terminated array
+ *
+ * @defs: Argument definitions array (NULL-terminated)
+ * Return: Number of arguments
+ */
+static int ut_count_args(const struct ut_arg_def *defs)
+{
+ int count = 0;
+
+ if (defs) {
+ while (defs[count].name)
+ count++;
+ }
+
+ return count;
+}
+
+/**
+ * ut_set_arg() - Find and set an argument value
+ *
+ * Search through argument definitions to find a matching key and set its value.
+ *
+ * @defs: Argument definitions array
+ * @args: Argument values array to update
+ * @count: Number of argument definitions
+ * @key: Key name to search for
+ * @key_len: Length of key name
+ * @val: Value string to parse
+ * Return: true if argument was found and set, false otherwise
+ */
+static bool ut_set_arg(const struct ut_arg_def *defs, struct ut_arg *args,
+ int count, const char *key, int key_len, const char *val)
+{
+ int j;
+
+ for (j = 0; j < count; j++) {
+ if (strlen(defs[j].name) == key_len &&
+ !strncmp(defs[j].name, key, key_len)) {
+ switch (defs[j].type) {
+ case UT_ARG_INT:
+ args[j].vint = simple_strtol(val, NULL, 0);
+ break;
+ case UT_ARG_BOOL:
+ args[j].vbool = *val == '1';
+ break;
+ case UT_ARG_STR:
+ args[j].vstr = val;
+ break;
+ }
+ args[j].provided = true;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * ut_parse_args() - Parse command-line arguments for a test
+ *
+ * Parse key=value arguments from the command line and set up uts->args based on
+ * the test's argument definitions.
+ *
+ * @uts: Unit test state (args and arg_count will be set)
+ * @test: Test being run (provides arg_defs)
+ * @argc: Number of arguments
+ * @argv: Argument array (key=value strings)
+ * Return: 0 on success, -EINVAL on parse error
+ */
+static int ut_parse_args(struct unit_test_state *uts, struct unit_test *test,
+ int argc, char *const argv[])
+{
+ const struct ut_arg_def *defs = test->arg_defs;
+ struct ut_arg *args = uts->args;
+ int count = ut_count_args(defs);
+ int i;
+
+ uts->arg_count = 0;
+
+ /* No arguments expected */
+ if (!count) {
+ if (argc > 0) {
+ printf("Test '%s' does not accept arguments\n",
+ test->name);
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ if (count > UT_MAX_ARGS) {
+ printf("Test '%s' has too many arguments (%d > %d)\n",
+ test->name, count, UT_MAX_ARGS);
+ return -EINVAL;
+ }
+
+ /* Initialise from defaults */
+ for (i = 0; i < count; i++) {
+ args[i].name = defs[i].name;
+ args[i].type = defs[i].type;
+ args[i].provided = false;
+ switch (defs[i].type) {
+ case UT_ARG_INT:
+ args[i].vint = defs[i].def.vint;
+ break;
+ case UT_ARG_BOOL:
+ args[i].vbool = defs[i].def.vbool;
+ break;
+ case UT_ARG_STR:
+ args[i].vstr = defs[i].def.vstr;
+ break;
+ }
+ }
+
+ /* Parse command-line key=value pairs */
+ for (i = 0; i < argc; i++) {
+ const char *arg = argv[i];
+ const char *eq = strchr(arg, '=');
+ int key_len;
+
+ if (!eq) {
+ printf("Invalid argument '%s' (expected key=value)\n",
+ arg);
+ return -EINVAL;
+ }
+ key_len = eq - arg;
+
+ if (!ut_set_arg(defs, args, count, arg, key_len, eq + 1)) {
+ printf("Unknown argument '%.*s' for test '%s'\n",
+ key_len, arg, test->name);
+ return -EINVAL;
+ }
+ }
+
+ /* Check required arguments are provided */
+ for (i = 0; i < count; i++) {
+ if (!args[i].provided && !(defs[i].flags & UT_ARGF_OPTIONAL)) {
+ printf("Missing required argument '%s' for test '%s'\n",
+ defs[i].name, test->name);
+ return -EINVAL;
+ }
+ }
+
+ uts->arg_count = count;
+
+ return 0;
+}
+
/**
* dm_test_pre_run() - Get ready to run a driver model test
*
@@ -593,12 +741,15 @@ static int ut_run_test_live_flat(struct unit_test_state *uts,
* @test_insert: String describing a test to run after n other tests run, in the
* format n:name where n is the number of tests to run before this one and
* name is the name of the test to run
+ * @argc: Number of test arguments (key=value pairs)
+ * @argv: Test argument array
* Return: 0 if all tests passed, -ENOENT if test @select_name was not found,
* -EBADF if any failed
*/
static int ut_run_tests(struct unit_test_state *uts, const char *prefix,
struct unit_test *tests, int count,
- const char *select_name, const char *test_insert)
+ const char *select_name, const char *test_insert,
+ int argc, char *const argv[])
{
int prefix_len = prefix ? strlen(prefix) : 0;
struct unit_test *test, *one;
@@ -654,6 +805,11 @@ static int ut_run_tests(struct unit_test_state *uts, const char *prefix,
uts->cur.test_count++;
if (one && upto == pos) {
+ ret = ut_parse_args(uts, one, argc, argv);
+ if (ret) {
+ uts->cur.fail_count++;
+ return ret;
+ }
ret = ut_run_test_live_flat(uts, one, NULL);
if (uts->cur.fail_count != old_fail_count) {
printf("Test '%s' failed %d times (position %d)\n",
@@ -667,6 +823,12 @@ static int ut_run_tests(struct unit_test_state *uts, const char *prefix,
if (prefix_len && !strncmp(test_name, prefix, prefix_len))
test_name = test_name + prefix_len;
+ ret = ut_parse_args(uts, test, argc, argv);
+ if (ret) {
+ found++;
+ uts->cur.fail_count++;
+ continue;
+ }
for (i = 0; i < uts->runs_per_test; i++)
ret = ut_run_test_live_flat(uts, test, test_name);
if (uts->cur.fail_count != old_fail_count) {
@@ -706,9 +868,8 @@ void ut_report(struct ut_stats *stats, int run_count)
int ut_run_list(struct unit_test_state *uts, const char *category,
const char *prefix, struct unit_test *tests, int count,
const char *select_name, int runs_per_test, bool force_run,
- const char *test_insert)
+ const char *test_insert, int argc, char *const argv[])
{
- ;
bool was_bypassed, has_dm_tests = false;
ulong start_offset = 0;
ulong test_offset = 0;
@@ -751,7 +912,7 @@ int ut_run_list(struct unit_test_state *uts, const char *category,
uts->force_run = force_run;
was_bypassed = pager_set_test_bypass(gd_pager(), true);
ret = ut_run_tests(uts, prefix, tests, count, select_name,
- test_insert);
+ test_insert, argc, argv);
pager_set_test_bypass(gd_pager(), was_bypassed);
/* Best efforts only...ignore errors */