test: Add a way to detect a test that breaks another

When running unit tests, some may have side effects which cause a
subsequent test to break. This can sometimes be seen when using 'ut dm'
or similar.

Add a new argument which allows a particular (failing) test to be run
immediately after a certain number of tests have run. This allows the
test causing the failure to be determined.

Update the documentation also.

Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/test/cmd_ut.c b/test/cmd_ut.c
index 76e37f3..2736582 100644
--- a/test/cmd_ut.c
+++ b/test/cmd_ut.c
@@ -21,6 +21,7 @@
 		    struct unit_test *tests, int n_ents,
 		    int argc, char *const argv[])
 {
+	const char *test_insert = NULL;
 	int runs_per_text = 1;
 	bool force_run = false;
 	int ret;
@@ -35,13 +36,17 @@
 		case 'f':
 			force_run = true;
 			break;
+		case 'I':
+			test_insert = str + 2;
+			break;
 		}
 		argv++;
-		argc++;
+		argc--;
 	}
 
 	ret = ut_run_list(name, prefix, tests, n_ents,
-			  argc > 1 ? argv[1] : NULL, runs_per_text, force_run);
+			  argc > 1 ? argv[1] : NULL, runs_per_text, force_run,
+			  test_insert);
 
 	return ret ? CMD_RET_FAILURE : 0;
 }
diff --git a/test/test-main.c b/test/test-main.c
index ab3b00a..5931e94 100644
--- a/test/test-main.c
+++ b/test/test-main.c
@@ -498,12 +498,29 @@
  */
 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 *select_name, const char *test_insert)
 {
-	struct unit_test *test;
+	struct unit_test *test, *one;
 	int found = 0;
+	int pos = 0;
+	int upto;
 
-	for (test = tests; test < tests + count; test++) {
+	one = NULL;
+	if (test_insert) {
+		char *p;
+
+		pos = dectoul(test_insert, NULL);
+		p = strchr(test_insert, ':');
+		if (p)
+			p++;
+
+		for (test = tests; test < tests + count; test++) {
+			if (!strcmp(p, test->name))
+				one = test;
+		}
+	}
+
+	for (upto = 0, test = tests; test < tests + count; test++, upto++) {
 		const char *test_name = test->name;
 		int ret, i, old_fail_count;
 
@@ -534,6 +551,17 @@
 			}
 		}
 		old_fail_count = uts->fail_count;
+
+		if (one && upto == pos) {
+			ret = ut_run_test_live_flat(uts, one);
+			if (uts->fail_count != old_fail_count) {
+				printf("Test %s failed %d times (position %d)\n",
+				       one->name,
+				       uts->fail_count - old_fail_count, pos);
+			}
+			return -EBADF;
+		}
+
 		for (i = 0; i < uts->runs_per_test; i++)
 			ret = ut_run_test_live_flat(uts, test);
 		if (uts->fail_count != old_fail_count) {
@@ -554,7 +582,7 @@
 
 int ut_run_list(const char *category, const char *prefix,
 		struct unit_test *tests, int count, const char *select_name,
-		int runs_per_test, bool force_run)
+		int runs_per_test, bool force_run, const char *test_insert)
 {
 	struct unit_test_state uts = { .fail_count = 0 };
 	bool has_dm_tests = false;
@@ -589,7 +617,8 @@
 		memcpy(uts.fdt_copy, gd->fdt_blob, uts.fdt_size);
 	}
 	uts.force_run = force_run;
-	ret = ut_run_tests(&uts, prefix, tests, count, select_name);
+	ret = ut_run_tests(&uts, prefix, tests, count, select_name,
+			   test_insert);
 
 	/* Best efforts only...ignore errors */
 	if (has_dm_tests)