From 7b5844762dda10f163d7fd9b1fb5bee265a334c9 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Wed, 13 Aug 2025 09:39:55 +0100 Subject: [PATCH] make check TESTS="..." support for filenames and infix matches (#7536) --- Makefile | 2 +- include/test/battle.h | 7 ++++++- include/test/test.h | 8 ++++++++ test/test_runner.c | 45 ++++++++++++++++++++++++++++++++++++++----- 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 759512ea63..8e5259ad1e 100644 --- a/Makefile +++ b/Makefile @@ -300,7 +300,7 @@ $(TESTELF): $(OBJ_DIR)/ld_script_test.ld $(OBJS) $(TEST_OBJS) libagbsyscall tool @echo "cd $(OBJ_DIR) && $(LD) -T ld_script_test.ld -o ../../$@ " @cd $(OBJ_DIR) && $(LD) $(TESTLDFLAGS) -T ld_script_test.ld -o ../../$@ $(OBJS_REL) $(TEST_OBJS_REL) $(LIB) $(FIX) $@ -t"$(TITLE)" -c$(GAME_CODE) -m$(MAKER_CODE) -r$(REVISION) -d0 --silent - $(PATCHELF) $(TESTELF) gTestRunnerArgv "$(TESTS)\0" + $(PATCHELF) $(TESTELF) gTestRunnerArgv "$(TESTS:%*=%)\0" ifeq ($(GITHUB_REPOSITORY_OWNER),rh-hideout) TEST_SKIP_IS_FAIL := \x01 diff --git a/include/test/battle.h b/include/test/battle.h index b95038b09e..d909aa0332 100644 --- a/include/test/battle.h +++ b/include/test/battle.h @@ -2,8 +2,13 @@ * * To run all the tests use: * make check -j - * To run specific tests, e.g. Spikes ones, use: + * To run specific tests, e.g. Spikes ones, use either: * make check TESTS="Spikes" + * make check TESTS="*Spikes*" + * The first runs tests with names that start with Spikes, whereas the + * second runs tests with names that include Spikes anywhere in them. + * To run tests from a specific file, e.g. 'test/battle/move_effect/spikes.c', use: + * make check TESTS="test/battle/move_effect/spikes.c" * To build a ROM (pokemerald-test.elf) that can be opened in mgba to * view specific tests, e.g. Spikes ones, use: * make pokeemerald-test.elf TESTS="Spikes" diff --git a/include/test/test.h b/include/test/test.h index 835634df7b..48a6e84aa2 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -37,10 +37,18 @@ struct Test u16 sourceLine; }; +enum TestFilterMode +{ + TEST_FILTER_MODE_TEST_NAME_PREFIX, + TEST_FILTER_MODE_TEST_NAME_INFIX, + TEST_FILTER_MODE_FILENAME_EXACT, +}; + struct TestRunnerState { u8 state; u8 exitCode; + enum TestFilterMode filterMode:8; const char *skipFilename; u32 failedAssumptionsBlockLine; const struct Test *test; diff --git a/test/test_runner.c b/test/test_runner.c index 99ba3f42ab..fe9a5eccb6 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -34,6 +34,25 @@ static void Intr_Timer2(void); extern const struct Test __start_tests[]; extern const struct Test __stop_tests[]; +static enum TestFilterMode DetectFilterMode(const char *pattern) +{ + size_t n = strlen(pattern); + if (n > 2 && pattern[n-2] == '.' && pattern[n-1] == 'c') + return TEST_FILTER_MODE_FILENAME_EXACT; + else if (pattern[0] == '*') // TODO: Support '*pattern*'. + return TEST_FILTER_MODE_TEST_NAME_INFIX; + else + return TEST_FILTER_MODE_TEST_NAME_PREFIX; +} + +static bool32 ExactMatch(const char *pattern, const char *string) +{ + if (string == NULL) + return TRUE; + + return strcmp(pattern, string) == 0; +} + static bool32 PrefixMatch(const char *pattern, const char *string) { if (string == NULL) @@ -50,6 +69,14 @@ static bool32 PrefixMatch(const char *pattern, const char *string) } } +static bool32 InfixMatch(const char *pattern, const char *string) +{ + if (string == NULL) + return TRUE; + + return strstr(string, &pattern[1]) != NULL; +} + enum { STATE_INIT, @@ -171,6 +198,8 @@ top: return; } + gTestRunnerState.filterMode = DetectFilterMode(gTestRunnerArgv); + MoveSaveBlocks_ResetHeap(); ClearSav1(); ClearSav2(); @@ -231,11 +260,17 @@ top: gTestRunnerState.state = STATE_EXIT; return; } - if (gTestRunnerState.test->runner != &gAssumptionsRunner - && !PrefixMatch(gTestRunnerArgv, gTestRunnerState.test->name)) - ++gTestRunnerState.test; - else - break; + if (gTestRunnerState.test->runner != &gAssumptionsRunner) + { + if ((gTestRunnerState.filterMode == TEST_FILTER_MODE_TEST_NAME_PREFIX && !PrefixMatch(gTestRunnerArgv, gTestRunnerState.test->name)) + || (gTestRunnerState.filterMode == TEST_FILTER_MODE_TEST_NAME_INFIX && !InfixMatch(gTestRunnerArgv, gTestRunnerState.test->name)) + || (gTestRunnerState.filterMode == TEST_FILTER_MODE_FILENAME_EXACT && !ExactMatch(gTestRunnerArgv, gTestRunnerState.test->filename))) + { + ++gTestRunnerState.test; + continue; + } + } + break; } Test_MgbaPrintf(":N%s", gTestRunnerState.test->name);