Improved Test Runner Summary (#4641)

* Filename in list (no proper sorting yet)

* Line number and message in error list + removed sorting

* Style adjustment

* Added missing file/line number to "expected N passes/successes"

* Fixed Known Failing Passing test list

* Separated test list from totals

* Assumption fails list

* Better names

* Filename for KNOWN_FAILINGs passing

* Moved total back to the bottom

* Spaces correction

* Fixed test list count

* Source file for Alloc fails on tests

* Moved sourceLine from BattleTest to Test struct

* Fixed assumptions failed "and more" counter

* Fixed ASSUMPTION block not printing their line numbers

* Fixed when stopLine is printed

* Renamed stopLine to failedAssumptionsBlockLine
This commit is contained in:
Eduardo Quezada 2024-07-20 12:22:40 -04:00 committed by GitHub
parent f2311b4c97
commit 9d5e253867
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 192 additions and 115 deletions

View file

@ -99,7 +99,7 @@ void *AllocInternal(void *heapStart, u32 size, const char *location)
block = block->next; block = block->next;
} }
while (block != head); while (block != head);
Test_ExitWithResult(TEST_RESULT_ERROR, "%s: OOM allocating %d bytes", location, size); Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":L%s:%d, %s: OOM allocating %d bytes", gTestRunnerState.test->filename, SourceLine(0), location, size);
#endif #endif
return NULL; return NULL;
} }

View file

@ -518,7 +518,6 @@ typedef void (*DoubleBattleTestFunction)(void *, const u32, struct BattlePokemon
struct BattleTest struct BattleTest
{ {
u8 type; u8 type;
u16 sourceLine;
union union
{ {
SingleBattleTestFunction singles; SingleBattleTestFunction singles;
@ -762,10 +761,10 @@ extern struct BattleTestRunnerState *const gBattleTestRunnerState;
.name = _name, \ .name = _name, \
.filename = __FILE__, \ .filename = __FILE__, \
.runner = &gBattleTestRunner, \ .runner = &gBattleTestRunner, \
.sourceLine = __LINE__, \
.data = (void *)&(const struct BattleTest) \ .data = (void *)&(const struct BattleTest) \
{ \ { \
.type = _type, \ .type = _type, \
.sourceLine = __LINE__, \
.function = { .singles = (SingleBattleTestFunction)CAT(Test, __LINE__) }, \ .function = { .singles = (SingleBattleTestFunction)CAT(Test, __LINE__) }, \
.resultsSize = sizeof(struct CAT(Result, __LINE__)), \ .resultsSize = sizeof(struct CAT(Result, __LINE__)), \
}, \ }, \
@ -780,10 +779,10 @@ extern struct BattleTestRunnerState *const gBattleTestRunnerState;
.name = _name, \ .name = _name, \
.filename = __FILE__, \ .filename = __FILE__, \
.runner = &gBattleTestRunner, \ .runner = &gBattleTestRunner, \
.sourceLine = __LINE__, \
.data = (void *)&(const struct BattleTest) \ .data = (void *)&(const struct BattleTest) \
{ \ { \
.type = _type, \ .type = _type, \
.sourceLine = __LINE__, \
.function = { .doubles = (DoubleBattleTestFunction)CAT(Test, __LINE__) }, \ .function = { .doubles = (DoubleBattleTestFunction)CAT(Test, __LINE__) }, \
.resultsSize = sizeof(struct CAT(Result, __LINE__)), \ .resultsSize = sizeof(struct CAT(Result, __LINE__)), \
}, \ }, \
@ -1091,7 +1090,7 @@ void ValidateFinally(u32 sourceLine);
s32 _am = Q_4_12_TO_INT(_a * _m); \ s32 _am = Q_4_12_TO_INT(_a * _m); \
s32 _t = max(Q_4_12_TO_INT(abs(_m) + Q_4_12_ROUND), 1); \ s32 _t = max(Q_4_12_TO_INT(abs(_m) + Q_4_12_ROUND), 1); \
if (abs(_am-_b) > _t) \ if (abs(_am-_b) > _t) \
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_MUL_EQ(%d, %q, %d) failed: %d not in [%d..%d]", gTestRunnerState.test->filename, __LINE__, _a, _m, _b, _am, _b-_t, _b+_t); \ Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_MUL_EQ(%d, %q, %d) failed: %d not in [%d..%d]", gTestRunnerState.test->filename, __LINE__, _a, _m, _b, _am, _b-_t, _b+_t); \
} while (0) } while (0)
#endif #endif

View file

@ -33,6 +33,7 @@ struct Test
const char *filename; const char *filename;
const struct TestRunner *runner; const struct TestRunner *runner;
void *data; void *data;
u16 sourceLine;
}; };
struct TestRunnerState struct TestRunnerState
@ -40,6 +41,7 @@ struct TestRunnerState
u8 state; u8 state;
u8 exitCode; u8 exitCode;
const char *skipFilename; const char *skipFilename;
u32 failedAssumptionsBlockLine;
const struct Test *test; const struct Test *test;
u32 processCosts[MAX_PROCESSES]; u32 processCosts[MAX_PROCESSES];
@ -73,7 +75,9 @@ void CB2_TestRunner(void);
void Test_ExpectedResult(enum TestResult); void Test_ExpectedResult(enum TestResult);
void Test_ExpectLeaks(bool32); void Test_ExpectLeaks(bool32);
void Test_ExitWithResult(enum TestResult, const char *fmt, ...); void Test_ExitWithResult(enum TestResult, u32 stopLine, const char *fmt, ...);
u32 SourceLine(u32 sourceLineOffset);
u32 SourceLineOffset(u32 sourceLine);
s32 MgbaPrintf_(const char *fmt, ...); s32 MgbaPrintf_(const char *fmt, ...);
@ -84,6 +88,7 @@ s32 MgbaPrintf_(const char *fmt, ...);
.name = _name, \ .name = _name, \
.filename = __FILE__, \ .filename = __FILE__, \
.runner = &gFunctionTestRunner, \ .runner = &gFunctionTestRunner, \
.sourceLine = __LINE__, \
.data = (void *)CAT(Test, __LINE__), \ .data = (void *)CAT(Test, __LINE__), \
}; \ }; \
static void CAT(Test, __LINE__)(void) static void CAT(Test, __LINE__)(void)
@ -95,6 +100,7 @@ s32 MgbaPrintf_(const char *fmt, ...);
.name = "ASSUMPTIONS: " __FILE__, \ .name = "ASSUMPTIONS: " __FILE__, \
.filename = __FILE__, \ .filename = __FILE__, \
.runner = &gAssumptionsRunner, \ .runner = &gAssumptionsRunner, \
.sourceLine = __LINE__, \
.data = Assumptions, \ .data = Assumptions, \
}; \ }; \
static void Assumptions(void) static void Assumptions(void)
@ -103,14 +109,14 @@ s32 MgbaPrintf_(const char *fmt, ...);
do \ do \
{ \ { \
if (!(c)) \ if (!(c)) \
Test_ExitWithResult(TEST_RESULT_ASSUMPTION_FAIL, "%s:%d: ASSUME failed", gTestRunnerState.test->filename, __LINE__); \ Test_ExitWithResult(TEST_RESULT_ASSUMPTION_FAIL, __LINE__, ":L%s:%d: ASSUME failed", gTestRunnerState.test->filename, __LINE__); \
} while (0) } while (0)
#define EXPECT(c) \ #define EXPECT(c) \
do \ do \
{ \ { \
if (!(c)) \ if (!(c)) \
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT failed", gTestRunnerState.test->filename, __LINE__); \ Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT failed", gTestRunnerState.test->filename, __LINE__); \
} while (0) } while (0)
#define EXPECT_EQ(a, b) \ #define EXPECT_EQ(a, b) \
@ -118,7 +124,7 @@ s32 MgbaPrintf_(const char *fmt, ...);
{ \ { \
typeof(a) _a = (a), _b = (b); \ typeof(a) _a = (a), _b = (b); \
if (_a != _b) \ if (_a != _b) \
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_EQ(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \ Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_EQ(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \
} while (0) } while (0)
#define EXPECT_NE(a, b) \ #define EXPECT_NE(a, b) \
@ -126,7 +132,7 @@ s32 MgbaPrintf_(const char *fmt, ...);
{ \ { \
typeof(a) _a = (a), _b = (b); \ typeof(a) _a = (a), _b = (b); \
if (_a == _b) \ if (_a == _b) \
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_NE(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \ Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_NE(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \
} while (0) } while (0)
#define EXPECT_LT(a, b) \ #define EXPECT_LT(a, b) \
@ -134,7 +140,7 @@ s32 MgbaPrintf_(const char *fmt, ...);
{ \ { \
typeof(a) _a = (a), _b = (b); \ typeof(a) _a = (a), _b = (b); \
if (_a >= _b) \ if (_a >= _b) \
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_LT(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \ Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_LT(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \
} while (0) } while (0)
#define EXPECT_LE(a, b) \ #define EXPECT_LE(a, b) \
@ -142,7 +148,7 @@ s32 MgbaPrintf_(const char *fmt, ...);
{ \ { \
typeof(a) _a = (a), _b = (b); \ typeof(a) _a = (a), _b = (b); \
if (_a > _b) \ if (_a > _b) \
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_LE(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \ Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_LE(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \
} while (0) } while (0)
#define EXPECT_GT(a, b) \ #define EXPECT_GT(a, b) \
@ -150,7 +156,7 @@ s32 MgbaPrintf_(const char *fmt, ...);
{ \ { \
typeof(a) _a = (a), _b = (b); \ typeof(a) _a = (a), _b = (b); \
if (_a <= _b) \ if (_a <= _b) \
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_GT(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \ Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_GT(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \
} while (0) } while (0)
#define EXPECT_GE(a, b) \ #define EXPECT_GE(a, b) \
@ -158,7 +164,7 @@ s32 MgbaPrintf_(const char *fmt, ...);
{ \ { \
typeof(a) _a = (a), _b = (b); \ typeof(a) _a = (a), _b = (b); \
if (_a < _b) \ if (_a < _b) \
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_GE(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \ Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_GE(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \
} while (0) } while (0)
struct Benchmark { s32 ticks; }; struct Benchmark { s32 ticks; };
@ -195,7 +201,7 @@ static inline struct Benchmark BenchmarkStop(void)
u32 a_ = (a).ticks; u32 b_ = (b).ticks; \ u32 a_ = (a).ticks; u32 b_ = (b).ticks; \
MgbaPrintf_(#a ": %d ticks, " #b ": %d ticks", a_, b_); \ MgbaPrintf_(#a ": %d ticks, " #b ": %d ticks", a_, b_); \
if (((a_ - BENCHMARK_ABS) * BENCHMARK_REL) >= (b_ * 100)) \ if (((a_ - BENCHMARK_ABS) * BENCHMARK_REL) >= (b_ * 100)) \
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_FASTER(" #a ", " #b ") failed", gTestRunnerState.test->filename, __LINE__); \ Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_FASTER(" #a ", " #b ") failed", gTestRunnerState.test->filename, __LINE__); \
} while (0) } while (0)
#define EXPECT_SLOWER(a, b) \ #define EXPECT_SLOWER(a, b) \
@ -204,7 +210,7 @@ static inline struct Benchmark BenchmarkStop(void)
u32 a_ = (a).ticks; u32 b_ = (b).ticks; \ u32 a_ = (a).ticks; u32 b_ = (b).ticks; \
MgbaPrintf_(#a ": %d ticks, " #b ": %d ticks", a_, b_); \ MgbaPrintf_(#a ": %d ticks, " #b ": %d ticks", a_, b_); \
if ((a_ * 100) <= ((b_ - BENCHMARK_ABS) * BENCHMARK_REL)) \ if ((a_ * 100) <= ((b_ - BENCHMARK_ABS) * BENCHMARK_REL)) \
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_SLOWER(" #a ", " #b ") failed", gTestRunnerState.test->filename, __LINE__); \ Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_SLOWER(" #a ", " #b ") failed", gTestRunnerState.test->filename, __LINE__); \
} while (0) } while (0)
#define KNOWN_FAILING \ #define KNOWN_FAILING \
@ -218,7 +224,7 @@ static inline struct Benchmark BenchmarkStop(void)
#define TO_DO \ #define TO_DO \
do { \ do { \
Test_ExpectedResult(TEST_RESULT_TODO); \ Test_ExpectedResult(TEST_RESULT_TODO); \
Test_ExitWithResult(TEST_RESULT_TODO, "%s:%d: EXPECT_TO_DO", gTestRunnerState.test->filename, __LINE__); \ Test_ExitWithResult(TEST_RESULT_TODO, __LINE__, ":L%s:%d: EXPECT_TO_DO", gTestRunnerState.test->filename, __LINE__); \
} while (0) } while (0)
#endif #endif

View file

@ -179,6 +179,7 @@ top:
} }
MgbaPrintf_(":N%s", gTestRunnerState.test->name); MgbaPrintf_(":N%s", gTestRunnerState.test->name);
MgbaPrintf_(":L%s:%d", gTestRunnerState.test->filename);
gTestRunnerState.result = TEST_RESULT_PASS; gTestRunnerState.result = TEST_RESULT_PASS;
gTestRunnerState.expectedResult = TEST_RESULT_PASS; gTestRunnerState.expectedResult = TEST_RESULT_PASS;
gTestRunnerState.expectLeaks = FALSE; gTestRunnerState.expectLeaks = FALSE;
@ -216,6 +217,7 @@ top:
// NOTE: Assumes that the compiler interns __FILE__. // NOTE: Assumes that the compiler interns __FILE__.
if (gTestRunnerState.skipFilename == gTestRunnerState.test->filename) // Assumption fails for tests in this file. if (gTestRunnerState.skipFilename == gTestRunnerState.test->filename) // Assumption fails for tests in this file.
{ {
MgbaPrintf_(":L%s:%d", gTestRunnerState.test->filename, gTestRunnerState.failedAssumptionsBlockLine);
gTestRunnerState.result = TEST_RESULT_ASSUMPTION_FAIL; gTestRunnerState.result = TEST_RESULT_ASSUMPTION_FAIL;
return; return;
} }
@ -480,9 +482,10 @@ static void Intr_Timer2(void)
} }
} }
void Test_ExitWithResult(enum TestResult result, const char *fmt, ...) void Test_ExitWithResult(enum TestResult result, u32 stopLine, const char *fmt, ...)
{ {
gTestRunnerState.result = result; gTestRunnerState.result = result;
gTestRunnerState.failedAssumptionsBlockLine = stopLine;
ReinitCallbacks(); ReinitCallbacks();
if (gTestRunnerState.state == STATE_REPORT_RESULT if (gTestRunnerState.state == STATE_REPORT_RESULT
&& gTestRunnerState.result != gTestRunnerState.expectedResult) && gTestRunnerState.result != gTestRunnerState.expectedResult)
@ -690,3 +693,24 @@ void DACSHandle(void)
ReinitCallbacks(); ReinitCallbacks();
DACS_LR = ((uintptr_t)JumpToAgbMainLoop & ~1) + 4; DACS_LR = ((uintptr_t)JumpToAgbMainLoop & ~1) + 4;
} }
static const struct Test *GetTest(void)
{
const struct Test *test = gTestRunnerState.test;
return test;
}
u32 SourceLine(u32 sourceLineOffset)
{
const struct Test *test = GetTest();
return test->sourceLine + sourceLineOffset;
}
u32 SourceLineOffset(u32 sourceLine)
{
const struct Test *test = GetTest();
if (sourceLine - test->sourceLine > 0xFF)
return 0;
else
return sourceLine - test->sourceLine;
}

View file

@ -25,10 +25,10 @@
#undef TestRunner_Battle_GetForcedAbility #undef TestRunner_Battle_GetForcedAbility
#endif #endif
#define INVALID(fmt, ...) Test_ExitWithResult(TEST_RESULT_INVALID, "%s:%d: " fmt, gTestRunnerState.test->filename, sourceLine, ##__VA_ARGS__) #define INVALID(fmt, ...) Test_ExitWithResult(TEST_RESULT_INVALID, sourceLine, ":L%s:%d: " fmt, gTestRunnerState.test->filename, sourceLine, ##__VA_ARGS__)
#define INVALID_IF(c, fmt, ...) do { if (c) Test_ExitWithResult(TEST_RESULT_INVALID, "%s:%d: " fmt, gTestRunnerState.test->filename, sourceLine, ##__VA_ARGS__); } while (0) #define INVALID_IF(c, fmt, ...) do { if (c) Test_ExitWithResult(TEST_RESULT_INVALID, sourceLine, ":L%s:%d: " fmt, gTestRunnerState.test->filename, sourceLine, ##__VA_ARGS__); } while (0)
#define ASSUMPTION_FAIL_IF(c, fmt, ...) do { if (c) Test_ExitWithResult(TEST_RESULT_ASSUMPTION_FAIL, "%s:%d: " fmt, gTestRunnerState.test->filename, sourceLine, ##__VA_ARGS__); } while (0) #define ASSUMPTION_FAIL_IF(c, fmt, ...) do { if (c) Test_ExitWithResult(TEST_RESULT_ASSUMPTION_FAIL, sourceLine, ":L%s:%d: " fmt, gTestRunnerState.test->filename, sourceLine, ##__VA_ARGS__); } while (0)
#define STATE gBattleTestRunnerState #define STATE gBattleTestRunnerState
#define DATA gBattleTestRunnerState->data #define DATA gBattleTestRunnerState->data
@ -145,21 +145,6 @@ static bool32 IsAITest(void)
return FALSE; return FALSE;
} }
static u32 SourceLine(u32 sourceLineOffset)
{
const struct BattleTest *test = GetBattleTest();
return test->sourceLine + sourceLineOffset;
}
static u32 SourceLineOffset(u32 sourceLine)
{
const struct BattleTest *test = GetBattleTest();
if (sourceLine - test->sourceLine > 0xFF)
return 0;
else
return sourceLine - test->sourceLine;
}
static u32 BattleTest_EstimateCost(void *data) static u32 BattleTest_EstimateCost(void *data)
{ {
u32 cost; u32 cost;
@ -184,9 +169,9 @@ static void BattleTest_SetUp(void *data)
InvokeTestFunction(test); InvokeTestFunction(test);
STATE->parameters = STATE->parametersCount; STATE->parameters = STATE->parametersCount;
if (STATE->parametersCount == 0 && test->resultsSize > 0) if (STATE->parametersCount == 0 && test->resultsSize > 0)
Test_ExitWithResult(TEST_RESULT_INVALID, "results without PARAMETRIZE"); Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":Lresults without PARAMETRIZE");
if (sizeof(*STATE) + test->resultsSize * STATE->parameters > sizeof(sBackupMapData)) if (sizeof(*STATE) + test->resultsSize * STATE->parameters > sizeof(sBackupMapData))
Test_ExitWithResult(TEST_RESULT_ERROR, "OOM: STATE (%d) + STATE->results (%d) too big for sBackupMapData (%d)", sizeof(*STATE), test->resultsSize * STATE->parameters, sizeof(sBackupMapData)); Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LOOM: STATE (%d) + STATE->results (%d) too big for sBackupMapData (%d)", sizeof(*STATE), test->resultsSize * STATE->parameters, sizeof(sBackupMapData));
STATE->results = (void *)((char *)sBackupMapData + sizeof(struct BattleTestRunnerState)); STATE->results = (void *)((char *)sBackupMapData + sizeof(struct BattleTestRunnerState));
memset(STATE->results, 0, test->resultsSize * STATE->parameters); memset(STATE->results, 0, test->resultsSize * STATE->parameters);
switch (test->type) switch (test->type)
@ -260,7 +245,7 @@ static void SetImplicitSpeeds(void)
} }
} }
if (!madeProgress) if (!madeProgress)
Test_ExitWithResult(TEST_RESULT_INVALID, "TURNs have contradictory speeds"); Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LTURNs have contradictory speeds");
} }
} }
@ -334,9 +319,9 @@ static void BattleTest_Run(void *data)
requiredOpponentPartySize = DATA.currentMonIndexes[i] + 1; requiredOpponentPartySize = DATA.currentMonIndexes[i] + 1;
} }
if (DATA.playerPartySize < requiredPlayerPartySize) if (DATA.playerPartySize < requiredPlayerPartySize)
Test_ExitWithResult(TEST_RESULT_INVALID, "%d PLAYER Pokemon required", requiredPlayerPartySize); Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":L%d PLAYER Pokemon required", requiredPlayerPartySize);
if (DATA.opponentPartySize < requiredOpponentPartySize) if (DATA.opponentPartySize < requiredOpponentPartySize)
Test_ExitWithResult(TEST_RESULT_INVALID, "%d OPPONENT Pokemon required", requiredOpponentPartySize); Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":L%d OPPONENT Pokemon required", requiredOpponentPartySize);
for (i = 0; i < STATE->battlersCount; i++) for (i = 0; i < STATE->battlersCount; i++)
PushBattlerAction(0, i, RECORDED_BYTE, 0xFF); PushBattlerAction(0, i, RECORDED_BYTE, 0xFF);
@ -346,7 +331,7 @@ static void BattleTest_Run(void *data)
if (DATA.explicitSpeeds[B_SIDE_PLAYER] != (1 << DATA.playerPartySize) - 1 if (DATA.explicitSpeeds[B_SIDE_PLAYER] != (1 << DATA.playerPartySize) - 1
&& DATA.explicitSpeeds[B_SIDE_OPPONENT] != (1 << DATA.opponentPartySize) - 1) && DATA.explicitSpeeds[B_SIDE_OPPONENT] != (1 << DATA.opponentPartySize) - 1)
{ {
Test_ExitWithResult(TEST_RESULT_INVALID, "Speed required for all PLAYERs and OPPONENTs"); Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LSpeed required for all PLAYERs and OPPONENTs");
} }
} }
else else
@ -392,7 +377,7 @@ u32 RandomUniform(enum RandomTag tag, u32 lo, u32 hi)
} }
else if (STATE->trials != n) else if (STATE->trials != n)
{ {
Test_ExitWithResult(TEST_RESULT_ERROR, "RandomUniform called with inconsistent trials %d and %d", STATE->trials, n); Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomUniform called with inconsistent trials %d and %d", STATE->trials, n);
} }
STATE->trialRatio = Q_4_12(1) / STATE->trials; STATE->trialRatio = Q_4_12(1) / STATE->trials;
return STATE->runTrial + lo; return STATE->runTrial + lo;
@ -413,7 +398,7 @@ u32 RandomUniformExcept(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32
if (turn && turn->rng.tag == tag) if (turn && turn->rng.tag == tag)
{ {
if (reject(turn->rng.value)) if (reject(turn->rng.value))
Test_ExitWithResult(TEST_RESULT_INVALID, "WITH_RNG specified a rejected value (%d)", turn->rng.value); Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LWITH_RNG specified a rejected value (%d)", turn->rng.value);
return turn->rng.value; return turn->rng.value;
} }
} }
@ -434,7 +419,7 @@ u32 RandomUniformExcept(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32
while (reject(STATE->runTrial + lo + STATE->rngTrialOffset)) while (reject(STATE->runTrial + lo + STATE->rngTrialOffset))
{ {
if (STATE->runTrial + lo + STATE->rngTrialOffset > hi) if (STATE->runTrial + lo + STATE->rngTrialOffset > hi)
Test_ExitWithResult(TEST_RESULT_INVALID, "RandomUniformExcept called with inconsistent reject"); Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LRandomUniformExcept called with inconsistent reject");
STATE->rngTrialOffset++; STATE->rngTrialOffset++;
} }
@ -445,7 +430,7 @@ u32 RandomUniformExcept(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32
while (reject(default_)) while (reject(default_))
{ {
if (default_ == lo) if (default_ == lo)
Test_ExitWithResult(TEST_RESULT_INVALID, "RandomUniformExcept rejected all values"); Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LRandomUniformExcept rejected all values");
default_--; default_--;
} }
return default_; return default_;
@ -456,7 +441,7 @@ u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights)
const struct BattlerTurn *turn = NULL; const struct BattlerTurn *turn = NULL;
if (sum == 0) if (sum == 0)
Test_ExitWithResult(TEST_RESULT_ERROR, "RandomWeightedArray called with zero sum"); Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeightedArray called with zero sum");
if (gCurrentTurnActionNumber < gBattlersCount) if (gCurrentTurnActionNumber < gBattlersCount)
{ {
@ -475,7 +460,7 @@ u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights)
} }
else if (STATE->trials != n) else if (STATE->trials != n)
{ {
Test_ExitWithResult(TEST_RESULT_ERROR, "RandomWeighted called with inconsistent trials %d and %d", STATE->trials, n); Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeighted called with inconsistent trials %d and %d", STATE->trials, n);
} }
// TODO: Detect inconsistent sum. // TODO: Detect inconsistent sum.
STATE->trialRatio = Q_4_12(weights[STATE->runTrial]) / sum; STATE->trialRatio = Q_4_12(weights[STATE->runTrial]) / sum;
@ -509,7 +494,7 @@ u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights)
while (weights[n-1] == 0) while (weights[n-1] == 0)
{ {
if (n == 1) if (n == 1)
Test_ExitWithResult(TEST_RESULT_ERROR, "RandomWeightedArray called with all zero weights"); Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeightedArray called with all zero weights");
n--; n--;
} }
return n-1; return n-1;
@ -535,7 +520,7 @@ const void *RandomElementArray(enum RandomTag tag, const void *array, size_t siz
return (const u8 *)array + size * index; return (const u8 *)array + size * index;
} }
// TODO: Incorporate the line number. // TODO: Incorporate the line number.
Test_ExitWithResult(TEST_RESULT_ERROR, "%s: RandomElement illegal value requested: %d", gTestRunnerState.test->filename, turn->rng.value); Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":L%s: RandomElement illegal value requested: %d", gTestRunnerState.test->filename, turn->rng.value);
} }
} }
@ -548,7 +533,7 @@ const void *RandomElementArray(enum RandomTag tag, const void *array, size_t siz
} }
else if (STATE->trials != count) else if (STATE->trials != count)
{ {
Test_ExitWithResult(TEST_RESULT_ERROR, "RandomElement called with inconsistent trials %d and %d", STATE->trials, count); Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomElement called with inconsistent trials %d and %d", STATE->trials, count);
} }
STATE->trialRatio = Q_4_12(1) / count; STATE->trialRatio = Q_4_12(1) / count;
return (const u8 *)array + size * STATE->runTrial; return (const u8 *)array + size * STATE->runTrial;
@ -599,7 +584,7 @@ void TestRunner_Battle_RecordAbilityPopUp(u32 battlerId, u32 ability)
{ {
const char *filename = gTestRunnerState.test->filename; const char *filename = gTestRunnerState.test->filename;
u32 line = SourceLine(DATA.queuedEvents[match].sourceLineOffset); u32 line = SourceLine(DATA.queuedEvents[match].sourceLineOffset);
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Matched ABILITY_POPUP", filename, line); Test_ExitWithResult(TEST_RESULT_FAIL, line, ":L%s:%d: Matched ABILITY_POPUP", filename, line);
} }
queuedEvent += event->groupSize; queuedEvent += event->groupSize;
@ -662,7 +647,7 @@ void TestRunner_Battle_RecordAnimation(u32 animType, u32 animId)
{ {
const char *filename = gTestRunnerState.test->filename; const char *filename = gTestRunnerState.test->filename;
u32 line = SourceLine(DATA.queuedEvents[match].sourceLineOffset); u32 line = SourceLine(DATA.queuedEvents[match].sourceLineOffset);
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Matched ANIMATION", filename, line); Test_ExitWithResult(TEST_RESULT_FAIL, line, ":L%s:%d: Matched ANIMATION", filename, line);
} }
queuedEvent += event->groupSize; queuedEvent += event->groupSize;
@ -752,7 +737,7 @@ void TestRunner_Battle_RecordHP(u32 battlerId, u32 oldHP, u32 newHP)
{ {
const char *filename = gTestRunnerState.test->filename; const char *filename = gTestRunnerState.test->filename;
u32 line = SourceLine(DATA.queuedEvents[match].sourceLineOffset); u32 line = SourceLine(DATA.queuedEvents[match].sourceLineOffset);
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Matched HP_BAR", filename, line); Test_ExitWithResult(TEST_RESULT_FAIL, line, ":L%s:%d: Matched HP_BAR", filename, line);
} }
queuedEvent += event->groupSize; queuedEvent += event->groupSize;
@ -807,10 +792,10 @@ void TestRunner_Battle_CheckChosenMove(u32 battlerId, u32 moveId, u32 target)
bool32 movePasses = FALSE; bool32 movePasses = FALSE;
if (expectedAction->type != B_ACTION_USE_MOVE) if (expectedAction->type != B_ACTION_USE_MOVE)
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Expected %s, got MOVE", filename, expectedAction->sourceLine, sBattleActionNames[expectedAction->type]); Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Expected %s, got MOVE", filename, expectedAction->sourceLine, sBattleActionNames[expectedAction->type]);
if (expectedAction->explicitTarget && expectedAction->target != target) if (expectedAction->explicitTarget && expectedAction->target != target)
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Expected target %s, got %s", filename, expectedAction->sourceLine, BattlerIdentifier(expectedAction->target), BattlerIdentifier(target)); Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Expected target %s, got %s", filename, expectedAction->sourceLine, BattlerIdentifier(expectedAction->target), BattlerIdentifier(target));
for (i = 0; i < MAX_MON_MOVES; i++) for (i = 0; i < MAX_MON_MOVES; i++)
{ {
@ -844,16 +829,16 @@ void TestRunner_Battle_CheckChosenMove(u32 battlerId, u32 moveId, u32 target)
u32 moveSlot = GetMoveSlot(gBattleMons[battlerId].moves, moveId); u32 moveSlot = GetMoveSlot(gBattleMons[battlerId].moves, moveId);
PrintAiMoveLog(battlerId, moveSlot, moveId, gBattleStruct->aiFinalScore[battlerId][expectedAction->target][moveSlot]); PrintAiMoveLog(battlerId, moveSlot, moveId, gBattleStruct->aiFinalScore[battlerId][expectedAction->target][moveSlot]);
if (countExpected > 1) if (countExpected > 1)
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Unmatched EXPECT_MOVES %S, got %S", filename, expectedAction->sourceLine, GetMoveName(expectedMoveId), GetMoveName(moveId)); Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Unmatched EXPECT_MOVES %S, got %S", filename, expectedAction->sourceLine, GetMoveName(expectedMoveId), GetMoveName(moveId));
else else
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Unmatched EXPECT_MOVE %S, got %S", filename, expectedAction->sourceLine, GetMoveName(expectedMoveId), GetMoveName(moveId)); Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Unmatched EXPECT_MOVE %S, got %S", filename, expectedAction->sourceLine, GetMoveName(expectedMoveId), GetMoveName(moveId));
} }
if (expectedAction->notMove && !movePasses) if (expectedAction->notMove && !movePasses)
{ {
if (countExpected > 1) if (countExpected > 1)
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Unmatched NOT_EXPECT_MOVES %S", filename, expectedAction->sourceLine, GetMoveName(expectedMoveId)); Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Unmatched NOT_EXPECT_MOVES %S", filename, expectedAction->sourceLine, GetMoveName(expectedMoveId));
else else
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Unmatched NOT_EXPECT_MOVE %S", filename, expectedAction->sourceLine, GetMoveName(expectedMoveId)); Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Unmatched NOT_EXPECT_MOVE %S", filename, expectedAction->sourceLine, GetMoveName(expectedMoveId));
} }
} }
// Turn passed, clear logs from the turn // Turn passed, clear logs from the turn
@ -873,17 +858,17 @@ void TestRunner_Battle_CheckSwitch(u32 battlerId, u32 partyIndex)
if (!expectedAction->pass) if (!expectedAction->pass)
{ {
if (expectedAction->type != B_ACTION_SWITCH) if (expectedAction->type != B_ACTION_SWITCH)
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Expected %s, got SWITCH/SEND_OUT", filename, expectedAction->sourceLine, sBattleActionNames[expectedAction->type]); Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Expected %s, got SWITCH/SEND_OUT", filename, expectedAction->sourceLine, sBattleActionNames[expectedAction->type]);
if (expectedAction->target != partyIndex) if (expectedAction->target != partyIndex)
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Expected partyIndex %d, got %d", filename, expectedAction->sourceLine, expectedAction->target, partyIndex); Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Expected partyIndex %d, got %d", filename, expectedAction->sourceLine, expectedAction->target, partyIndex);
} }
DATA.aiActionsPlayed[battlerId]++; DATA.aiActionsPlayed[battlerId]++;
} }
void TestRunner_Battle_InvalidNoHPMon(u32 battlerId, u32 partyIndex) void TestRunner_Battle_InvalidNoHPMon(u32 battlerId, u32 partyIndex)
{ {
Test_ExitWithResult(TEST_RESULT_INVALID, "%s: INVALID: %s trying to send out a mon(id: %d) with 0 HP.", Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":L%s: INVALID: %s trying to send out a mon(id: %d) with 0 HP.",
gTestRunnerState.test->filename, BattlerIdentifier(battlerId), gBattlerPartyIndexes[battlerId]); gTestRunnerState.test->filename, BattlerIdentifier(battlerId), gBattlerPartyIndexes[battlerId]);
} }
@ -933,7 +918,7 @@ static void CheckIfMaxScoreEqualExpectMove(u32 battlerId, s32 target, struct Exp
&& (aiAction->moveSlots & gBitTable[i]) && (aiAction->moveSlots & gBitTable[i])
&& !(aiAction->moveSlots & gBitTable[bestScoreId])) && !(aiAction->moveSlots & gBitTable[bestScoreId]))
{ {
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_MOVE %S has the same best score(%d) as not expected MOVE %S", filename, Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: EXPECT_MOVE %S has the same best score(%d) as not expected MOVE %S", filename,
aiAction->sourceLine, GetMoveName(moves[i]), scores[i], GetMoveName(moves[bestScoreId])); aiAction->sourceLine, GetMoveName(moves[i]), scores[i], GetMoveName(moves[bestScoreId]));
} }
// We DO NOT expect move 'i', but it has the same best score as another move. // We DO NOT expect move 'i', but it has the same best score as another move.
@ -942,7 +927,7 @@ static void CheckIfMaxScoreEqualExpectMove(u32 battlerId, s32 target, struct Exp
&& (aiAction->moveSlots & gBitTable[i]) && (aiAction->moveSlots & gBitTable[i])
&& !(aiAction->moveSlots & gBitTable[bestScoreId])) && !(aiAction->moveSlots & gBitTable[bestScoreId]))
{ {
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: NOT_EXPECT_MOVE %S has the same best score(%d) as MOVE %S", filename, Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: NOT_EXPECT_MOVE %S has the same best score(%d) as MOVE %S", filename,
aiAction->sourceLine, GetMoveName(moves[i]), scores[i], GetMoveName(moves[bestScoreId])); aiAction->sourceLine, GetMoveName(moves[i]), scores[i], GetMoveName(moves[bestScoreId]));
} }
} }
@ -985,7 +970,7 @@ static void PrintAiMoveLog(u32 battlerId, u32 moveSlot, u32 moveId, s32 totalSco
} }
if (scoreFromLogs != totalScore) if (scoreFromLogs != totalScore)
{ {
Test_ExitWithResult(TEST_RESULT_ERROR, "Warning! Score from logs(%d) is different than actual score(%d). Make sure all of the score adjustments use the ADJUST_SCORE macro\n", scoreFromLogs, totalScore); Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LWarning! Score from logs(%d) is different than actual score(%d). Make sure all of the score adjustments use the ADJUST_SCORE macro\n", scoreFromLogs, totalScore);
} }
MgbaPrintf_("Total: %d\n", totalScore); MgbaPrintf_("Total: %d\n", totalScore);
} }
@ -1023,7 +1008,7 @@ void TestRunner_Battle_CheckAiMoveScores(u32 battlerId)
PrintAiMoveLog(battlerId, scoreCtx->moveSlot1, moveId1, scores[scoreCtx->moveSlot1]); PrintAiMoveLog(battlerId, scoreCtx->moveSlot1, moveId1, scores[scoreCtx->moveSlot1]);
if (!CheckComparision(scores[scoreCtx->moveSlot1], scoreCtx->value, scoreCtx->cmp)) if (!CheckComparision(scores[scoreCtx->moveSlot1], scoreCtx->value, scoreCtx->cmp))
{ {
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Unmatched SCORE_%s_VAL %S %d, got %d", Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Unmatched SCORE_%s_VAL %S %d, got %d",
filename, scoreCtx->sourceLine, sCmpToStringTable[scoreCtx->cmp], GetMoveName(moveId1), scoreCtx->value, scores[scoreCtx->moveSlot1]); filename, scoreCtx->sourceLine, sCmpToStringTable[scoreCtx->cmp], GetMoveName(moveId1), scoreCtx->value, scores[scoreCtx->moveSlot1]);
} }
} }
@ -1034,7 +1019,7 @@ void TestRunner_Battle_CheckAiMoveScores(u32 battlerId)
PrintAiMoveLog(battlerId, scoreCtx->moveSlot2, moveId2, scores[scoreCtx->moveSlot2]); PrintAiMoveLog(battlerId, scoreCtx->moveSlot2, moveId2, scores[scoreCtx->moveSlot2]);
if (!CheckComparision(scores[scoreCtx->moveSlot1], scores[scoreCtx->moveSlot2], scoreCtx->cmp)) if (!CheckComparision(scores[scoreCtx->moveSlot1], scores[scoreCtx->moveSlot2], scoreCtx->cmp))
{ {
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Unmatched SCORE_%s, got %S: %d, %S: %d", Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Unmatched SCORE_%s, got %S: %d, %S: %d",
filename, scoreCtx->sourceLine, sCmpToStringTable[scoreCtx->cmp], GetMoveName(moveId1), scores[scoreCtx->moveSlot1], GetMoveName(moveId2), scores[scoreCtx->moveSlot2]); filename, scoreCtx->sourceLine, sCmpToStringTable[scoreCtx->cmp], GetMoveName(moveId1), scores[scoreCtx->moveSlot1], GetMoveName(moveId2), scores[scoreCtx->moveSlot2]);
} }
} }
@ -1134,7 +1119,7 @@ void TestRunner_Battle_RecordExp(u32 battlerId, u32 oldExp, u32 newExp)
{ {
const char *filename = gTestRunnerState.test->filename; const char *filename = gTestRunnerState.test->filename;
u32 line = SourceLine(DATA.queuedEvents[match].sourceLineOffset); u32 line = SourceLine(DATA.queuedEvents[match].sourceLineOffset);
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Matched EXPERIENCE_BAR", filename, line); Test_ExitWithResult(TEST_RESULT_FAIL, line, ":L%s:%d: Matched EXPERIENCE_BAR", filename, line);
} }
queuedEvent += event->groupSize; queuedEvent += event->groupSize;
@ -1223,7 +1208,7 @@ void TestRunner_Battle_RecordMessage(const u8 *string)
{ {
const char *filename = gTestRunnerState.test->filename; const char *filename = gTestRunnerState.test->filename;
u32 line = SourceLine(DATA.queuedEvents[match].sourceLineOffset); u32 line = SourceLine(DATA.queuedEvents[match].sourceLineOffset);
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Matched MESSAGE", filename, line); Test_ExitWithResult(TEST_RESULT_FAIL, line, ":L%s:%d: Matched MESSAGE", filename, line);
} }
queuedEvent += event->groupSize; queuedEvent += event->groupSize;
@ -1288,7 +1273,7 @@ void TestRunner_Battle_RecordStatus1(u32 battlerId, u32 status1)
{ {
const char *filename = gTestRunnerState.test->filename; const char *filename = gTestRunnerState.test->filename;
u32 line = SourceLine(DATA.queuedEvents[match].sourceLineOffset); u32 line = SourceLine(DATA.queuedEvents[match].sourceLineOffset);
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Matched STATUS_ICON", filename, line); Test_ExitWithResult(TEST_RESULT_FAIL, line, ":L%s:%d: Matched STATUS_ICON", filename, line);
} }
queuedEvent += event->groupSize; queuedEvent += event->groupSize;
@ -1323,7 +1308,7 @@ void TestRunner_Battle_AfterLastTurn(void)
if (DATA.turns - 1 != DATA.lastActionTurn) if (DATA.turns - 1 != DATA.lastActionTurn)
{ {
const char *filename = gTestRunnerState.test->filename; const char *filename = gTestRunnerState.test->filename;
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: %d TURNs specified, but %d ran", filename, SourceLine(0), DATA.turns, DATA.lastActionTurn + 1); Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: %d TURNs specified, but %d ran", filename, SourceLine(0), DATA.turns, DATA.lastActionTurn + 1);
} }
while (DATA.queuedEvent < DATA.queuedEventsCount while (DATA.queuedEvent < DATA.queuedEventsCount
@ -1336,7 +1321,7 @@ void TestRunner_Battle_AfterLastTurn(void)
const char *filename = gTestRunnerState.test->filename; const char *filename = gTestRunnerState.test->filename;
u32 line = SourceLine(DATA.queuedEvents[DATA.queuedEvent].sourceLineOffset); u32 line = SourceLine(DATA.queuedEvents[DATA.queuedEvent].sourceLineOffset);
const char *macro = sEventTypeMacros[DATA.queuedEvents[DATA.queuedEvent].type]; const char *macro = sEventTypeMacros[DATA.queuedEvents[DATA.queuedEvent].type];
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Unmatched %s", filename, line, macro); Test_ExitWithResult(TEST_RESULT_FAIL, line, ":L%s:%d: Unmatched %s", filename, line, macro);
} }
STATE->runThen = TRUE; STATE->runThen = TRUE;
@ -1418,7 +1403,7 @@ static void CB2_BattleTest_NextTrial(void)
if (abs(STATE->observedRatio - STATE->expectedRatio) <= Q_4_12(0.02)) if (abs(STATE->observedRatio - STATE->expectedRatio) <= Q_4_12(0.02))
gTestRunnerState.result = TEST_RESULT_PASS; gTestRunnerState.result = TEST_RESULT_PASS;
else else
Test_ExitWithResult(TEST_RESULT_FAIL, "Expected %q passes/successes, observed %q", STATE->expectedRatio, STATE->observedRatio); Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Expected %q passes/successes, observed %q", gTestRunnerState.test->filename, SourceLine(0), STATE->expectedRatio, STATE->observedRatio);
} }
} }
@ -1831,7 +1816,7 @@ static void PushBattlerAction(u32 sourceLine, s32 battlerId, u32 actionType, u32
{ {
u32 recordIndex = DATA.recordIndexes[battlerId]++; u32 recordIndex = DATA.recordIndexes[battlerId]++;
if (recordIndex >= BATTLER_RECORD_SIZE) if (recordIndex >= BATTLER_RECORD_SIZE)
Test_ExitWithResult(TEST_RESULT_INVALID, "Too many actions"); Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LToo many actions");
DATA.battleRecordTypes[battlerId][recordIndex] = actionType; DATA.battleRecordTypes[battlerId][recordIndex] = actionType;
DATA.battleRecordSourceLineOffsets[battlerId][recordIndex] = SourceLineOffset(sourceLine); DATA.battleRecordSourceLineOffsets[battlerId][recordIndex] = SourceLineOffset(sourceLine);
DATA.recordedBattle.battleRecord[battlerId][recordIndex] = byte; DATA.recordedBattle.battleRecord[battlerId][recordIndex] = byte;
@ -1853,10 +1838,10 @@ void TestRunner_Battle_CheckBattleRecordActionType(u32 battlerId, u32 recordInde
&& DATA.recordedBattle.battleRecord[battlerId][i-1] == B_ACTION_USE_MOVE) && DATA.recordedBattle.battleRecord[battlerId][i-1] == B_ACTION_USE_MOVE)
{ {
u32 line = SourceLine(DATA.battleRecordSourceLineOffsets[battlerId][i-1]); u32 line = SourceLine(DATA.battleRecordSourceLineOffsets[battlerId][i-1]);
Test_ExitWithResult(TEST_RESULT_INVALID, "%s:%d: Illegal MOVE", filename, line); Test_ExitWithResult(TEST_RESULT_INVALID, line, ":L%s:%d: Illegal MOVE", filename, line);
} }
} }
Test_ExitWithResult(TEST_RESULT_INVALID, "%s:%d: Illegal MOVE", filename, SourceLine(0)); Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":L%s:%d: Illegal MOVE", filename, SourceLine(0));
} }
if (DATA.battleRecordTypes[battlerId][recordIndex] != RECORDED_BYTE) if (DATA.battleRecordTypes[battlerId][recordIndex] != RECORDED_BYTE)
@ -1884,13 +1869,13 @@ void TestRunner_Battle_CheckBattleRecordActionType(u32 battlerId, u32 recordInde
switch (actionType) switch (actionType)
{ {
case RECORDED_ACTION_TYPE: case RECORDED_ACTION_TYPE:
Test_ExitWithResult(TEST_RESULT_INVALID, "%s:%d: Expected MOVE/SWITCH, got %s", filename, line, actualMacro); Test_ExitWithResult(TEST_RESULT_INVALID, line, ":L%s:%d: Expected MOVE/SWITCH, got %s", filename, line, actualMacro);
case RECORDED_PARTY_INDEX: case RECORDED_PARTY_INDEX:
Test_ExitWithResult(TEST_RESULT_INVALID, "%s:%d: Expected SEND_OUT, got %s", filename, line, actualMacro); Test_ExitWithResult(TEST_RESULT_INVALID, line, ":L%s:%d: Expected SEND_OUT, got %s", filename, line, actualMacro);
} }
} }
Test_ExitWithResult(TEST_RESULT_ERROR, "%s:%d: Illegal battle record", filename, line); Test_ExitWithResult(TEST_RESULT_ERROR, line, ":L%s:%d: Illegal battle record", filename, line);
} }
} }
else else
@ -1898,7 +1883,7 @@ void TestRunner_Battle_CheckBattleRecordActionType(u32 battlerId, u32 recordInde
if (DATA.lastActionTurn == gBattleResults.battleTurnCounter) if (DATA.lastActionTurn == gBattleResults.battleTurnCounter)
{ {
const char *filename = gTestRunnerState.test->filename; const char *filename = gTestRunnerState.test->filename;
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: TURN %d incomplete", filename, SourceLine(0), gBattleResults.battleTurnCounter + 1); Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: TURN %d incomplete", filename, SourceLine(0), gBattleResults.battleTurnCounter + 1);
} }
} }
} }
@ -1907,7 +1892,7 @@ void OpenTurn(u32 sourceLine)
{ {
INVALID_IF(DATA.turnState != TURN_CLOSED, "Nested TURN"); INVALID_IF(DATA.turnState != TURN_CLOSED, "Nested TURN");
if (DATA.turns == MAX_TURNS) if (DATA.turns == MAX_TURNS)
Test_ExitWithResult(TEST_RESULT_ERROR, "%s:%d: TURN exceeds MAX_TURNS", gTestRunnerState.test->filename, sourceLine); Test_ExitWithResult(TEST_RESULT_ERROR, sourceLine, ":L%s:%d: TURN exceeds MAX_TURNS", gTestRunnerState.test->filename, sourceLine);
DATA.turnState = TURN_OPEN; DATA.turnState = TURN_OPEN;
DATA.actionBattlers = 0x00; DATA.actionBattlers = 0x00;
DATA.moveBattlers = 0x00; DATA.moveBattlers = 0x00;
@ -2422,7 +2407,7 @@ void QueueAbility(u32 sourceLine, struct BattlePokemon *battler, struct AbilityE
s32 battlerId = battler - gBattleMons; s32 battlerId = battler - gBattleMons;
INVALID_IF(!STATE->runScene, "ABILITY_POPUP outside of SCENE"); INVALID_IF(!STATE->runScene, "ABILITY_POPUP outside of SCENE");
if (DATA.queuedEventsCount == MAX_QUEUED_EVENTS) if (DATA.queuedEventsCount == MAX_QUEUED_EVENTS)
Test_ExitWithResult(TEST_RESULT_ERROR, "%s:%d: ABILITY exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine); Test_ExitWithResult(TEST_RESULT_ERROR, sourceLine, ":L%s:%d: ABILITY exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine);
DATA.queuedEvents[DATA.queuedEventsCount++] = (struct QueuedEvent) { DATA.queuedEvents[DATA.queuedEventsCount++] = (struct QueuedEvent) {
.type = QUEUED_ABILITY_POPUP_EVENT, .type = QUEUED_ABILITY_POPUP_EVENT,
.sourceLineOffset = SourceLineOffset(sourceLine), .sourceLineOffset = SourceLineOffset(sourceLine),
@ -2442,7 +2427,7 @@ void QueueAnimation(u32 sourceLine, u32 type, u32 id, struct AnimationEventConte
INVALID_IF(!STATE->runScene, "ANIMATION outside of SCENE"); INVALID_IF(!STATE->runScene, "ANIMATION outside of SCENE");
if (DATA.queuedEventsCount == MAX_QUEUED_EVENTS) if (DATA.queuedEventsCount == MAX_QUEUED_EVENTS)
Test_ExitWithResult(TEST_RESULT_ERROR, "%s:%d: ANIMATION exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine); Test_ExitWithResult(TEST_RESULT_ERROR, sourceLine, ":L%s:%d: ANIMATION exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine);
attackerId = ctx.attacker ? ctx.attacker - gBattleMons : 0xF; attackerId = ctx.attacker ? ctx.attacker - gBattleMons : 0xF;
if (type == ANIM_TYPE_MOVE) if (type == ANIM_TYPE_MOVE)
@ -2477,7 +2462,7 @@ void QueueHP(u32 sourceLine, struct BattlePokemon *battler, struct HPEventContex
INVALID_IF(!STATE->runScene, "HP_BAR outside of SCENE"); INVALID_IF(!STATE->runScene, "HP_BAR outside of SCENE");
if (DATA.queuedEventsCount == MAX_QUEUED_EVENTS) if (DATA.queuedEventsCount == MAX_QUEUED_EVENTS)
Test_ExitWithResult(TEST_RESULT_ERROR, "%s:%d: HP_BAR exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine); Test_ExitWithResult(TEST_RESULT_ERROR, sourceLine, ":L%s:%d: HP_BAR exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine);
if (ctx.explicitHP) if (ctx.explicitHP)
{ {
@ -2530,7 +2515,7 @@ void QueueExp(u32 sourceLine, struct BattlePokemon *battler, struct ExpEventCont
INVALID_IF(!STATE->runScene, "EXPERIENCE_BAR outside of SCENE"); INVALID_IF(!STATE->runScene, "EXPERIENCE_BAR outside of SCENE");
if (DATA.queuedEventsCount == MAX_QUEUED_EVENTS) if (DATA.queuedEventsCount == MAX_QUEUED_EVENTS)
Test_ExitWithResult(TEST_RESULT_ERROR, "%s:%d: EXPERIENCE_BAR exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine); Test_ExitWithResult(TEST_RESULT_ERROR, sourceLine, ":L%s:%d: EXPERIENCE_BAR exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine);
if (ctx.explicitExp) if (ctx.explicitExp)
{ {
@ -2567,7 +2552,7 @@ void QueueMessage(u32 sourceLine, const u8 *pattern)
{ {
INVALID_IF(!STATE->runScene, "MESSAGE outside of SCENE"); INVALID_IF(!STATE->runScene, "MESSAGE outside of SCENE");
if (DATA.queuedEventsCount == MAX_QUEUED_EVENTS) if (DATA.queuedEventsCount == MAX_QUEUED_EVENTS)
Test_ExitWithResult(TEST_RESULT_ERROR, "%s:%d: MESSAGE exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine); Test_ExitWithResult(TEST_RESULT_ERROR, sourceLine, ":L%s:%d: MESSAGE exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine);
DATA.queuedEvents[DATA.queuedEventsCount++] = (struct QueuedEvent) { DATA.queuedEvents[DATA.queuedEventsCount++] = (struct QueuedEvent) {
.type = QUEUED_MESSAGE_EVENT, .type = QUEUED_MESSAGE_EVENT,
.sourceLineOffset = SourceLineOffset(sourceLine), .sourceLineOffset = SourceLineOffset(sourceLine),
@ -2586,7 +2571,7 @@ void QueueStatus(u32 sourceLine, struct BattlePokemon *battler, struct StatusEve
INVALID_IF(!STATE->runScene, "STATUS_ICON outside of SCENE"); INVALID_IF(!STATE->runScene, "STATUS_ICON outside of SCENE");
if (DATA.queuedEventsCount == MAX_QUEUED_EVENTS) if (DATA.queuedEventsCount == MAX_QUEUED_EVENTS)
Test_ExitWithResult(TEST_RESULT_ERROR, "%s:%d: STATUS_ICON exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine); Test_ExitWithResult(TEST_RESULT_ERROR, sourceLine, ":L%s:%d: STATUS_ICON exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine);
if (ctx.none) if (ctx.none)
mask = 0; mask = 0;
@ -2645,7 +2630,7 @@ struct AILogLine *GetLogLine(u32 battlerId, u32 moveIndex)
} }
} }
Test_ExitWithResult(TEST_RESULT_ERROR, "Too many AI log lines"); Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LToo many AI log lines");
return NULL; return NULL;
} }

View file

@ -8,6 +8,7 @@
* *
* COMMANDS * COMMANDS
* N: Sets the test name to the remainder of the line. * N: Sets the test name to the remainder of the line.
* L: Sets the filename to the remainder of the line.
* R: Sets the result to the remainder of the line, and flushes any * R: Sets the result to the remainder of the line, and flushes any
* output buffered since the previous R. * output buffered since the previous R.
* P/K/F/A: Sets the result to the remaining of the line, flushes any * P/K/F/A: Sets the result to the remaining of the line, flushes any
@ -46,6 +47,7 @@ struct Runner
int outfd; int outfd;
char rom_path[FILENAME_MAX]; char rom_path[FILENAME_MAX];
char test_name[256]; char test_name[256];
char filename_line[256];
size_t input_buffer_size; size_t input_buffer_size;
size_t input_buffer_capacity; size_t input_buffer_capacity;
char *input_buffer; char *input_buffer;
@ -59,8 +61,12 @@ struct Runner
int assumptionFails; int assumptionFails;
int fails; int fails;
int results; int results;
char failedTestNames[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH]; char failed_TestNames[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
char knownFailingPassedTestNames[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH]; char failed_TestFilenameLine[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
char knownFailingPassed_TestNames[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
char knownFailingPassed_FilenameLine[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
char assumeFailed_TestNames[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
char assumeFailed_FilenameLine[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
}; };
static unsigned nrunners = 0; static unsigned nrunners = 0;
@ -102,6 +108,16 @@ static void handle_read(int i, struct Runner *runner)
strncpy(runner->test_name, soc, eol - soc - 1); strncpy(runner->test_name, soc, eol - soc - 1);
runner->test_name[eol - soc - 1] = '\0'; runner->test_name[eol - soc - 1] = '\0';
break; break;
case 'L':
soc += 2;
if (sizeof(runner->filename_line) <= eol - soc - 1)
{
fprintf(stderr, "filename_line too long\n");
exit(2);
}
strncpy(runner->filename_line, soc, eol - soc - 1);
runner->filename_line[eol - soc - 1] = '\0';
break;
case 'P': case 'P':
runner->passes++; runner->passes++;
@ -111,18 +127,29 @@ static void handle_read(int i, struct Runner *runner)
goto add_to_results; goto add_to_results;
case 'U': case 'U':
if (runner->knownFailsPassing < MAX_SUMMARY_TESTS_TO_LIST) if (runner->knownFailsPassing < MAX_SUMMARY_TESTS_TO_LIST)
strcpy(runner->knownFailingPassedTestNames[runner->knownFailsPassing], runner->test_name); {
strcpy(runner->knownFailingPassed_TestNames[runner->knownFailsPassing], runner->test_name);
strcpy(runner->knownFailingPassed_FilenameLine[runner->knownFailsPassing], runner->filename_line);
}
runner->knownFailsPassing++; runner->knownFailsPassing++;
goto add_to_results; goto add_to_results;
case 'T': case 'T':
runner->todos++; runner->todos++;
goto add_to_results; goto add_to_results;
case 'A': case 'A':
if (runner->assumptionFails < MAX_SUMMARY_TESTS_TO_LIST)
{
strcpy(runner->assumeFailed_TestNames[runner->assumptionFails], runner->test_name);
strcpy(runner->assumeFailed_FilenameLine[runner->assumptionFails], runner->filename_line);
}
runner->assumptionFails++; runner->assumptionFails++;
goto add_to_results; goto add_to_results;
case 'F': case 'F':
if (runner->fails < MAX_SUMMARY_TESTS_TO_LIST) if (runner->fails < MAX_SUMMARY_TESTS_TO_LIST)
strcpy(runner->failedTestNames[runner->fails], runner->test_name); {
strcpy(runner->failed_TestNames[runner->fails], runner->test_name);
strcpy(runner->failed_TestFilenameLine[runner->fails], runner->filename_line);
}
runner->fails++; runner->fails++;
add_to_results: add_to_results:
runner->results++; runner->results++;
@ -532,8 +559,14 @@ int main(int argc, char *argv[])
int fails = 0; int fails = 0;
int results = 0; int results = 0;
char failedTestNames[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH]; char failed_TestNames[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
char knownFailingPassedTestNames[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH]; char failed_TestFilenameLine[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
char knownFailingPassed_TestNames[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
char knownFailingPassed_FilenameLine[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
char assumeFailed_TestNames[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
char assumeFailed_FilenameLine[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
for (int i = 0; i < nrunners; i++) for (int i = 0; i < nrunners; i++)
{ {
@ -552,33 +585,43 @@ int main(int argc, char *argv[])
for (int j = 0; j < runners[i].knownFailsPassing; j++) for (int j = 0; j < runners[i].knownFailsPassing; j++)
{ {
if (j < MAX_SUMMARY_TESTS_TO_LIST) if (j < MAX_SUMMARY_TESTS_TO_LIST)
strcpy(knownFailingPassedTestNames[fails], runners[i].knownFailingPassedTestNames[j]); {
strcpy(knownFailingPassed_TestNames[knownFailsPassing], runners[i].knownFailingPassed_TestNames[j]);
strcpy(knownFailingPassed_FilenameLine[knownFailsPassing], runners[i].knownFailingPassed_FilenameLine[j]);
}
knownFailsPassing++; knownFailsPassing++;
} }
todos += runners[i].todos; todos += runners[i].todos;
assumptionFails += runners[i].assumptionFails; for (int j = 0; j < runners[i].assumptionFails; j++)
{
if (j < MAX_SUMMARY_TESTS_TO_LIST)
{
strcpy(assumeFailed_TestNames[assumptionFails], runners[i].assumeFailed_TestNames[j]);
strcpy(assumeFailed_FilenameLine[assumptionFails], runners[i].assumeFailed_FilenameLine[j]);
}
assumptionFails++;
}
for (int j = 0; j < runners[i].fails; j++) for (int j = 0; j < runners[i].fails; j++)
{ {
if (j < MAX_SUMMARY_TESTS_TO_LIST) if (j < MAX_SUMMARY_TESTS_TO_LIST)
strcpy(failedTestNames[fails], runners[i].failedTestNames[j]); {
strcpy(failed_TestNames[fails], runners[i].failed_TestNames[j]);
strcpy(failed_TestFilenameLine[fails], runners[i].failed_TestFilenameLine[j]);
}
fails++; fails++;
} }
results += runners[i].results; results += runners[i].results;
} }
qsort(failedTestNames, min(fails, MAX_SUMMARY_TESTS_TO_LIST), sizeof(char) * MAX_TEST_LIST_BUFFER_LENGTH, compare_strings);
qsort(knownFailingPassedTestNames, min(fails, MAX_SUMMARY_TESTS_TO_LIST), sizeof(char) * MAX_TEST_LIST_BUFFER_LENGTH, compare_strings);
if (results == 0) if (results == 0)
{ {
fprintf(stdout, "\nNo tests found.\n"); fprintf(stdout, "\nNo tests found.\n");
} }
else else
{ {
fprintf(stdout, "\n");
if (fails > 0) if (fails > 0)
{ {
fprintf(stdout, "- Tests \e[31mFAILED\e[0m : %d Add TESTS='X' to run tests with the defined prefix.\n", fails); fprintf(stdout, "\n \e[31mFAILED\e[0m tests:\n");
for (int i = 0; i < fails; i++) for (int i = 0; i < fails; i++)
{ {
if (i >= MAX_SUMMARY_TESTS_TO_LIST) if (i >= MAX_SUMMARY_TESTS_TO_LIST)
@ -586,31 +629,51 @@ int main(int argc, char *argv[])
fprintf(stdout, " - \e[31mand %d more...\e[0m\n", fails - MAX_SUMMARY_TESTS_TO_LIST); fprintf(stdout, " - \e[31mand %d more...\e[0m\n", fails - MAX_SUMMARY_TESTS_TO_LIST);
break; break;
} }
fprintf(stdout, " - \e[31m%s\e[0m.\n", failedTestNames[i]); fprintf(stdout, " - \e[31m%s\e[0m - %s.\n", failed_TestFilenameLine[i], failed_TestNames[i]);
} }
} }
if (assumptionFails > 0)
{
fprintf(stdout, "\n Tests with \e[33mASSUMPTIONS_FAILED\e[0m:\n");
for (int i = 0; i < assumptionFails; i++)
{
if (i >= MAX_SUMMARY_TESTS_TO_LIST)
{
fprintf(stdout, " - \e[33mand %d more...\e[0m\n", assumptionFails - MAX_SUMMARY_TESTS_TO_LIST);
break;
}
fprintf(stdout, " - \e[33m%s\e[0m - %s.\n", assumeFailed_FilenameLine[i], assumeFailed_TestNames[i]);
}
}
if (knownFailsPassing > 0) if (knownFailsPassing > 0)
{ {
fprintf(stdout, "- \e[31mKNOWN_FAILING_PASSED\e[0m: %d \e[31mPlease remove KNOWN_FAILING if these tests intentionally PASS\e[0m\n", knownFailsPassing); fprintf(stdout, "\n \e[33mKNOWN_FAILING\e[0m tests \e[32mPASSING\e[0m:\n");
for (int i = 0; i < knownFailsPassing; i++) for (int i = 0; i < knownFailsPassing; i++)
{ {
if (i >= MAX_SUMMARY_TESTS_TO_LIST) if (i >= MAX_SUMMARY_TESTS_TO_LIST)
{ {
fprintf(stdout, " - \e[31mand %d more...\e[0m\n", knownFailsPassing - MAX_SUMMARY_TESTS_TO_LIST); fprintf(stdout, " - \e[32mand %d more...\e[0m\n", knownFailsPassing - MAX_SUMMARY_TESTS_TO_LIST);
break; break;
} }
fprintf(stdout, " - \e[31m%s\e[0m.\n", knownFailingPassedTestNames[i]); fprintf(stdout, " - \e[32m%s\e[0m - %s.\n", knownFailingPassed_FilenameLine[i], knownFailingPassed_TestNames[i]);
} }
} }
fprintf(stdout, "- Tests \e[32mPASSED\e[0m: %d\n", passes);
if (knownFails > 0)
fprintf(stdout, "- Tests \e[33mKNOWN_FAILING\e[0m: %d\n", knownFails);
if (todos > 0)
fprintf(stdout, "- Tests \e[33mTO_DO\e[0m: %d\n", todos);
if (assumptionFails > 0)
fprintf(stdout, "- \e[33mASSUMPTIONS_FAILED\e[0m: %d\n", assumptionFails);
fprintf(stdout, "- Tests \e[34mTOTAL\e[0m: %d\n", results); fprintf(stdout, "\n");
if (fails > 0)
fprintf(stdout, "- Tests \e[31mFAILED\e[0m : %d Add TESTS='X' to run tests with the defined prefix.\n", fails);
if (knownFails > 0)
fprintf(stdout, "- Tests \e[33mKNOWN_FAILING\e[0m: %d\n", knownFails);
if (assumptionFails > 0)
fprintf(stdout, "- \e[33mASSUMPTIONS_FAILED\e[0m: %d\n", assumptionFails);
if (todos > 0)
fprintf(stdout, "- Tests \e[33mTO_DO\e[0m: %d\n", todos);
if (knownFailsPassing > 0)
fprintf(stdout, "- \e[32mKNOWN_FAILING_PASSING\e[0m: %d \e[33mPlease remove KNOWN_FAILING if these tests intentionally PASS\e[0m\n", knownFailsPassing);
fprintf(stdout, "- Tests \e[32mPASSED\e[0m: %d\n", passes);
fprintf(stdout, "- Tests \e[34mTOTAL\e[0m: %d\n", results);
} }
fprintf(stdout, "\n"); fprintf(stdout, "\n");