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;
}
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
return NULL;
}

View file

@ -518,7 +518,6 @@ typedef void (*DoubleBattleTestFunction)(void *, const u32, struct BattlePokemon
struct BattleTest
{
u8 type;
u16 sourceLine;
union
{
SingleBattleTestFunction singles;
@ -762,10 +761,10 @@ extern struct BattleTestRunnerState *const gBattleTestRunnerState;
.name = _name, \
.filename = __FILE__, \
.runner = &gBattleTestRunner, \
.sourceLine = __LINE__, \
.data = (void *)&(const struct BattleTest) \
{ \
.type = _type, \
.sourceLine = __LINE__, \
.function = { .singles = (SingleBattleTestFunction)CAT(Test, __LINE__) }, \
.resultsSize = sizeof(struct CAT(Result, __LINE__)), \
}, \
@ -780,10 +779,10 @@ extern struct BattleTestRunnerState *const gBattleTestRunnerState;
.name = _name, \
.filename = __FILE__, \
.runner = &gBattleTestRunner, \
.sourceLine = __LINE__, \
.data = (void *)&(const struct BattleTest) \
{ \
.type = _type, \
.sourceLine = __LINE__, \
.function = { .doubles = (DoubleBattleTestFunction)CAT(Test, __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 _t = max(Q_4_12_TO_INT(abs(_m) + Q_4_12_ROUND), 1); \
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)
#endif

View file

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

View file

@ -179,6 +179,7 @@ top:
}
MgbaPrintf_(":N%s", gTestRunnerState.test->name);
MgbaPrintf_(":L%s:%d", gTestRunnerState.test->filename);
gTestRunnerState.result = TEST_RESULT_PASS;
gTestRunnerState.expectedResult = TEST_RESULT_PASS;
gTestRunnerState.expectLeaks = FALSE;
@ -216,6 +217,7 @@ top:
// NOTE: Assumes that the compiler interns __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;
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.failedAssumptionsBlockLine = stopLine;
ReinitCallbacks();
if (gTestRunnerState.state == STATE_REPORT_RESULT
&& gTestRunnerState.result != gTestRunnerState.expectedResult)
@ -690,3 +693,24 @@ void DACSHandle(void)
ReinitCallbacks();
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
#endif
#define INVALID(fmt, ...) Test_ExitWithResult(TEST_RESULT_INVALID, "%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(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, 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 DATA gBattleTestRunnerState->data
@ -145,21 +145,6 @@ static bool32 IsAITest(void)
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)
{
u32 cost;
@ -184,9 +169,9 @@ static void BattleTest_SetUp(void *data)
InvokeTestFunction(test);
STATE->parameters = STATE->parametersCount;
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))
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));
memset(STATE->results, 0, test->resultsSize * STATE->parameters);
switch (test->type)
@ -260,7 +245,7 @@ static void SetImplicitSpeeds(void)
}
}
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;
}
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)
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++)
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
&& 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
@ -392,7 +377,7 @@ u32 RandomUniform(enum RandomTag tag, u32 lo, u32 hi)
}
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;
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 (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;
}
}
@ -434,7 +419,7 @@ u32 RandomUniformExcept(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32
while (reject(STATE->runTrial + lo + STATE->rngTrialOffset))
{
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++;
}
@ -445,7 +430,7 @@ u32 RandomUniformExcept(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32
while (reject(default_))
{
if (default_ == lo)
Test_ExitWithResult(TEST_RESULT_INVALID, "RandomUniformExcept rejected all values");
Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LRandomUniformExcept rejected all values");
default_--;
}
return default_;
@ -456,7 +441,7 @@ u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights)
const struct BattlerTurn *turn = NULL;
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)
{
@ -475,7 +460,7 @@ u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights)
}
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.
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)
{
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--;
}
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;
}
// 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)
{
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;
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;
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;
@ -662,7 +647,7 @@ void TestRunner_Battle_RecordAnimation(u32 animType, u32 animId)
{
const char *filename = gTestRunnerState.test->filename;
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;
@ -752,7 +737,7 @@ void TestRunner_Battle_RecordHP(u32 battlerId, u32 oldHP, u32 newHP)
{
const char *filename = gTestRunnerState.test->filename;
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;
@ -807,10 +792,10 @@ void TestRunner_Battle_CheckChosenMove(u32 battlerId, u32 moveId, u32 target)
bool32 movePasses = FALSE;
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)
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++)
{
@ -844,16 +829,16 @@ void TestRunner_Battle_CheckChosenMove(u32 battlerId, u32 moveId, u32 target)
u32 moveSlot = GetMoveSlot(gBattleMons[battlerId].moves, moveId);
PrintAiMoveLog(battlerId, moveSlot, moveId, gBattleStruct->aiFinalScore[battlerId][expectedAction->target][moveSlot]);
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
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 (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
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
@ -873,17 +858,17 @@ void TestRunner_Battle_CheckSwitch(u32 battlerId, u32 partyIndex)
if (!expectedAction->pass)
{
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)
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]++;
}
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]);
}
@ -933,7 +918,7 @@ static void CheckIfMaxScoreEqualExpectMove(u32 battlerId, s32 target, struct Exp
&& (aiAction->moveSlots & gBitTable[i])
&& !(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]));
}
// 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[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]));
}
}
@ -985,7 +970,7 @@ static void PrintAiMoveLog(u32 battlerId, u32 moveSlot, u32 moveId, s32 totalSco
}
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);
}
@ -1023,7 +1008,7 @@ void TestRunner_Battle_CheckAiMoveScores(u32 battlerId)
PrintAiMoveLog(battlerId, scoreCtx->moveSlot1, moveId1, scores[scoreCtx->moveSlot1]);
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]);
}
}
@ -1034,7 +1019,7 @@ void TestRunner_Battle_CheckAiMoveScores(u32 battlerId)
PrintAiMoveLog(battlerId, scoreCtx->moveSlot2, moveId2, scores[scoreCtx->moveSlot2]);
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]);
}
}
@ -1134,7 +1119,7 @@ void TestRunner_Battle_RecordExp(u32 battlerId, u32 oldExp, u32 newExp)
{
const char *filename = gTestRunnerState.test->filename;
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;
@ -1223,7 +1208,7 @@ void TestRunner_Battle_RecordMessage(const u8 *string)
{
const char *filename = gTestRunnerState.test->filename;
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;
@ -1288,7 +1273,7 @@ void TestRunner_Battle_RecordStatus1(u32 battlerId, u32 status1)
{
const char *filename = gTestRunnerState.test->filename;
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;
@ -1323,7 +1308,7 @@ void TestRunner_Battle_AfterLastTurn(void)
if (DATA.turns - 1 != DATA.lastActionTurn)
{
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
@ -1336,7 +1321,7 @@ void TestRunner_Battle_AfterLastTurn(void)
const char *filename = gTestRunnerState.test->filename;
u32 line = SourceLine(DATA.queuedEvents[DATA.queuedEvent].sourceLineOffset);
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;
@ -1418,7 +1403,7 @@ static void CB2_BattleTest_NextTrial(void)
if (abs(STATE->observedRatio - STATE->expectedRatio) <= Q_4_12(0.02))
gTestRunnerState.result = TEST_RESULT_PASS;
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]++;
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.battleRecordSourceLineOffsets[battlerId][recordIndex] = SourceLineOffset(sourceLine);
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)
{
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)
@ -1884,13 +1869,13 @@ void TestRunner_Battle_CheckBattleRecordActionType(u32 battlerId, u32 recordInde
switch (actionType)
{
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:
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
@ -1898,7 +1883,7 @@ void TestRunner_Battle_CheckBattleRecordActionType(u32 battlerId, u32 recordInde
if (DATA.lastActionTurn == gBattleResults.battleTurnCounter)
{
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");
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.actionBattlers = 0x00;
DATA.moveBattlers = 0x00;
@ -2422,7 +2407,7 @@ void QueueAbility(u32 sourceLine, struct BattlePokemon *battler, struct AbilityE
s32 battlerId = battler - gBattleMons;
INVALID_IF(!STATE->runScene, "ABILITY_POPUP outside of SCENE");
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) {
.type = QUEUED_ABILITY_POPUP_EVENT,
.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");
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;
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");
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)
{
@ -2530,7 +2515,7 @@ void QueueExp(u32 sourceLine, struct BattlePokemon *battler, struct ExpEventCont
INVALID_IF(!STATE->runScene, "EXPERIENCE_BAR outside of SCENE");
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)
{
@ -2567,7 +2552,7 @@ void QueueMessage(u32 sourceLine, const u8 *pattern)
{
INVALID_IF(!STATE->runScene, "MESSAGE outside of SCENE");
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) {
.type = QUEUED_MESSAGE_EVENT,
.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");
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)
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;
}

View file

@ -8,6 +8,7 @@
*
* COMMANDS
* 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
* output buffered since the previous R.
* P/K/F/A: Sets the result to the remaining of the line, flushes any
@ -46,6 +47,7 @@ struct Runner
int outfd;
char rom_path[FILENAME_MAX];
char test_name[256];
char filename_line[256];
size_t input_buffer_size;
size_t input_buffer_capacity;
char *input_buffer;
@ -59,8 +61,12 @@ struct Runner
int assumptionFails;
int fails;
int results;
char failedTestNames[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
char knownFailingPassedTestNames[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
char failed_TestNames[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;
@ -102,6 +108,16 @@ static void handle_read(int i, struct Runner *runner)
strncpy(runner->test_name, soc, eol - soc - 1);
runner->test_name[eol - soc - 1] = '\0';
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':
runner->passes++;
@ -111,18 +127,29 @@ static void handle_read(int i, struct Runner *runner)
goto add_to_results;
case 'U':
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++;
goto add_to_results;
case 'T':
runner->todos++;
goto add_to_results;
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++;
goto add_to_results;
case 'F':
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++;
add_to_results:
runner->results++;
@ -532,8 +559,14 @@ int main(int argc, char *argv[])
int fails = 0;
int results = 0;
char failedTestNames[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_TestNames[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++)
{
@ -552,33 +585,43 @@ int main(int argc, char *argv[])
for (int j = 0; j < runners[i].knownFailsPassing; j++)
{
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++;
}
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++)
{
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++;
}
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)
{
fprintf(stdout, "\nNo tests found.\n");
}
else
{
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);
fprintf(stdout, "\n \e[31mFAILED\e[0m tests:\n");
for (int i = 0; i < fails; i++)
{
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);
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)
{
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++)
{
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;
}
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");