Detect more invalid test cases (#2955)

This commit is contained in:
Eduardo Quezada D'Ottone 2023-05-07 11:04:07 -04:00 committed by GitHub
commit b6722ad5b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 119 additions and 90 deletions

View File

@ -658,6 +658,7 @@ struct BattleStruct
u8 storedLunarDance:4; // Each battler as a bit.
u16 supremeOverlordModifier[MAX_BATTLERS_COUNT];
u8 itemPartyIndex[MAX_BATTLERS_COUNT];
u8 itemMoveIndex[MAX_BATTLERS_COUNT];
bool8 trainerSlideHalfHpMsgDone;
u8 trainerSlideFirstCriticalHitMsgState:2;
u8 trainerSlideFirstSuperEffectiveHitMsgState:2;

View File

@ -1443,7 +1443,7 @@ static void RecordedOpponentHandleChooseItem(void)
u8 byte2 = RecordedBattle_GetBattlerAction(RECORDED_ITEM_ID, gActiveBattler);
gBattleStruct->chosenItem[gActiveBattler] = (byte1 << 8) | byte2;
gBattleStruct->itemPartyIndex[gActiveBattler] = RecordedBattle_GetBattlerAction(RECORDED_ITEM_TARGET, gActiveBattler);
gChosenMovePos = RecordedBattle_GetBattlerAction(RECORDED_ITEM_MOVE, gActiveBattler);
gBattleStruct->itemMoveIndex[gActiveBattler] = RecordedBattle_GetBattlerAction(RECORDED_ITEM_MOVE, gActiveBattler);
BtlController_EmitOneReturnValue(BUFFER_B, gBattleStruct->chosenItem[gActiveBattler]);
RecordedOpponentBufferExecCompleted();
}

View File

@ -1467,7 +1467,7 @@ static void RecordedPlayerHandleChooseItem(void)
u8 byte2 = RecordedBattle_GetBattlerAction(RECORDED_ITEM_ID, gActiveBattler);
gBattleStruct->chosenItem[gActiveBattler] = (byte1 << 8) | byte2;
gBattleStruct->itemPartyIndex[gActiveBattler] = RecordedBattle_GetBattlerAction(RECORDED_ITEM_TARGET, gActiveBattler);
gChosenMovePos = RecordedBattle_GetBattlerAction(RECORDED_ITEM_MOVE, gActiveBattler);
gBattleStruct->itemMoveIndex[gActiveBattler] = RecordedBattle_GetBattlerAction(RECORDED_ITEM_MOVE, gActiveBattler);
BtlController_EmitOneReturnValue(BUFFER_B, gBattleStruct->chosenItem[gActiveBattler]);
RecordedPlayerBufferExecCompleted();
}

View File

@ -16536,10 +16536,10 @@ void BS_ItemRestorePP(void) {
// Check whether to apply to all moves.
if (effect[4] & ITEM4_HEAL_PP_ONE)
{
i = gChosenMovePos;
loopEnd = gChosenMovePos + 1;
i = gBattleStruct->itemMoveIndex[gBattlerAttacker];
loopEnd = i + 1;
}
else
else
{
i = 0;
loopEnd = MAX_MON_MOVES;

View File

@ -4944,7 +4944,7 @@ static void TryUseItemOnMove(u8 taskId)
else
{
gBattleStruct->itemPartyIndex[gBattlerInMenuId] = GetPartyIdFromBattleSlot(gPartyMenu.slotId);
gChosenMovePos = ptr->data1;
gBattleStruct->itemMoveIndex[gBattlerInMenuId] = ptr->data1;
gPartyMenuUseExitCallback = TRUE;
RemoveBagItem(gSpecialVar_ItemId, 1);
ScheduleBgCopyTilemapToVram(2);

View File

@ -6,7 +6,7 @@ SINGLE_BATTLE_TEST("Compound Eyes raises accuracy")
PASSES_RANDOMLY(91, 100, RNG_ACCURACY);
GIVEN {
ASSUME(gBattleMoves[MOVE_THUNDER].accuracy == 70);
PLAYER(SPECIES_BUTTERFREE) { Ability(ABILITY_COMPOUND_EYES); };
PLAYER(SPECIES_BUTTERFREE) { Ability(ABILITY_COMPOUND_EYES); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_THUNDER); }
@ -16,16 +16,13 @@ SINGLE_BATTLE_TEST("Compound Eyes raises accuracy")
}
}
// This fails even though the ability works correctly. The failure is due to
// a statistical anomaly in the test system where FISSURE hits 3 times more often
// than we expect.
SINGLE_BATTLE_TEST("Compound Eyes does not affect OHKO moves")
{
PASSES_RANDOMLY(30, 100, RNG_ACCURACY);
GIVEN {
ASSUME(gBattleMoves[MOVE_FISSURE].accuracy == 30);
ASSUME(gBattleMoves[MOVE_FISSURE].effect == EFFECT_OHKO);
PLAYER(SPECIES_BUTTERFREE) { Ability(ABILITY_COMPOUND_EYES); };
PLAYER(SPECIES_BUTTERFREE) { Ability(ABILITY_COMPOUND_EYES); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_FISSURE); }

View File

@ -33,10 +33,13 @@ SINGLE_BATTLE_TEST("Dry Skin heals 1/8th Max HP in Rain")
SINGLE_BATTLE_TEST("Dry Skin increases damage taken from Fire-type moves by 25%", s16 damage)
{
u32 ability;
PARAMETRIZE { ability = ABILITY_EFFECT_SPORE; }
PARAMETRIZE { ability = ABILITY_DRY_SKIN; }
GIVEN {
ASSUME(gBattleMoves[MOVE_EMBER].type == TYPE_FIRE);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_PARASECT) { Ability(ABILITY_DRY_SKIN); };
OPPONENT(SPECIES_PARASECT) { Ability(ability); };
} WHEN {
TURN {MOVE(player, MOVE_EMBER); }
} SCENE {

View File

@ -63,8 +63,9 @@ SINGLE_BATTLE_TEST("Volt Absorb is only triggered once on multi strike moves")
}
}
DOUBLE_BATTLE_TEST("Volt Absorb does not stop Electric Typed Explosion from damaging other pokemon", s16 damage1, s16 damage2) // Fixed issue #1961
DOUBLE_BATTLE_TEST("Volt Absorb does not stop Electric Typed Explosion from damaging other pokemon") // Fixed issue #1961
{
s16 damage1, damage2;
GIVEN {
ASSUME(gBattleMoves[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION);
ASSUME(gBattleMoves[MOVE_EXPLOSION].type == TYPE_NORMAL);
@ -78,12 +79,11 @@ DOUBLE_BATTLE_TEST("Volt Absorb does not stop Electric Typed Explosion from dama
ABILITY_POPUP(playerLeft, ABILITY_VOLT_ABSORB);
HP_BAR(playerLeft, hp: TEST_MAX_HP / 4 + 1);
MESSAGE("Jolteon restored HP using its Volt Absorb!");
HP_BAR(playerRight, captureDamage: &results->damage1);
HP_BAR(opponentRight, captureDamage: &results->damage2);
}
FINALLY {
EXPECT_NE(results[0].damage1, 0);
EXPECT_NE(results[0].damage2, 0);
HP_BAR(playerRight, captureDamage: &damage1);
HP_BAR(opponentRight, captureDamage: &damage2);
} THEN {
EXPECT_NE(damage1, 0);
EXPECT_NE(damage2, 0);
}
}

View File

@ -11,14 +11,11 @@ SINGLE_BATTLE_TEST("Berserk Gene sharply raises attack at the start of battle",
u16 useItem;
PARAMETRIZE { useItem = FALSE; }
PARAMETRIZE { useItem = TRUE; }
if (useItem) PASSES_RANDOMLY(66, 100, RNG_CONFUSION);
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { if (useItem) Item(ITEM_BERSERK_GENE); };
PLAYER(SPECIES_WOBBUFFET) { if (useItem) Item(ITEM_BERSERK_GENE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN {
MOVE(player, MOVE_TACKLE);
}
TURN { MOVE(player, MOVE_TACKLE, WITH_RNG(RNG_CONFUSION, FALSE)); }
} SCENE {
if (useItem)
{
@ -38,17 +35,13 @@ SINGLE_BATTLE_TEST("Berserk Gene activates on switch in", s16 damage)
u16 useItem;
PARAMETRIZE { useItem = FALSE; }
PARAMETRIZE { useItem = TRUE; }
if (useItem) PASSES_RANDOMLY(66, 100, RNG_CONFUSION);
GIVEN {
PLAYER(SPECIES_WYNAUT);
PLAYER(SPECIES_WOBBUFFET) { if (useItem) Item(ITEM_BERSERK_GENE); };
PLAYER(SPECIES_WOBBUFFET) { if (useItem) Item(ITEM_BERSERK_GENE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN {
SWITCH(player, 1);
} TURN {
MOVE(player, MOVE_TACKLE);
}
TURN { SWITCH(player, 1); }
TURN { MOVE(player, MOVE_TACKLE, WITH_RNG(RNG_CONFUSION, FALSE)); }
} SCENE {
if (useItem)
{

View File

@ -9,8 +9,8 @@ ASSUMPTIONS
SINGLE_BATTLE_TEST("Mirror Herb copies all of foe's stat changes in a turn", s16 damage)
{
u32 item;
PARAMETRIZE{ item = ITEM_NONE; }
PARAMETRIZE{ item = ITEM_MIRROR_HERB; }
PARAMETRIZE { item = ITEM_NONE; }
PARAMETRIZE { item = ITEM_MIRROR_HERB; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Speed(4); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(5); Item(item); }
@ -34,7 +34,7 @@ SINGLE_BATTLE_TEST("Mirror Herb copies all of foe's stat changes in a turn", s16
}
}
SINGLE_BATTLE_TEST("Mirror Herb copies all of of Stuff Cheeks", s16 damage)
SINGLE_BATTLE_TEST("Mirror Herb copies all of of Stuff Cheeks")
{
GIVEN {
ASSUME(gItems[ITEM_LIECHI_BERRY].holdEffect == HOLD_EFFECT_ATTACK_UP);

View File

@ -126,7 +126,7 @@ SINGLE_BATTLE_TEST("X Speed sharply raises battler's Speed stat", s16 damage)
}
}
SINGLE_BATTLE_TEST("X Accuracy sharply raises battler's Accuracy stat", s16 damage)
SINGLE_BATTLE_TEST("X Accuracy sharply raises battler's Accuracy stat")
{
ASSUME(gBattleMoves[MOVE_SING].accuracy == 55);

View File

@ -183,4 +183,4 @@ SINGLE_BATTLE_TEST("Sitrus Berry restores a battler's HP by 25% of its max HP(30
}
#undef TEST_HP
#undef MAX_HP
#undef MAX_HP

View File

@ -28,7 +28,7 @@ SINGLE_BATTLE_TEST("Bide deals twice the taken damage over two turns")
MESSAGE("Wobbuffet unleashed energy!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_BIDE, player);
HP_BAR(opponent, captureDamage: &bideDamage);
} FINALLY {
EXPECT_EQ(bideDamage, damage1 + damage2);
} THEN {
EXPECT_EQ(bideDamage, 2 * (damage1 + damage2));
}
}

View File

@ -6,7 +6,7 @@ ASSUMPTIONS
ASSUME(gBattleMoves[MOVE_TRIPLE_KICK].effect & EFFECT_TRIPLE_KICK);
}
SINGLE_BATTLE_TEST("Triple Kick damage is increaased by its base damage for each hit")
SINGLE_BATTLE_TEST("Triple Kick damage is increased by its base damage for each hit")
{
s16 firstHit;
s16 secondHit;
@ -24,8 +24,8 @@ SINGLE_BATTLE_TEST("Triple Kick damage is increaased by its base damage for each
HP_BAR(opponent, captureDamage: &secondHit);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TRIPLE_KICK, player);
HP_BAR(opponent, captureDamage: &thirdHit);
} FINALLY {
EXPECT_EQ(secondHit, firstHit * 2);
EXPECT_EQ(thirdHit, firstHit * 3);
} THEN {
EXPECT_MUL_EQ(firstHit, Q_4_12(2.0), secondHit);
EXPECT_MUL_EQ(firstHit, Q_4_12(3.0), thirdHit);
}
}

View File

@ -20,7 +20,7 @@ SINGLE_BATTLE_TEST("Three-strike flag turns a move into a 3-hit move")
HP_BAR(opponent, captureDamage: &secondHit);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TRIPLE_DIVE, player);
HP_BAR(opponent, captureDamage: &thirdHit);
} FINALLY {
} THEN {
EXPECT_EQ(firstHit, secondHit);
EXPECT_EQ(secondHit, thirdHit);
EXPECT_EQ(firstHit, thirdHit);
@ -49,7 +49,7 @@ SINGLE_BATTLE_TEST("Surging Strikes hits 3 times with each hit being a critical
ANIMATION(ANIM_TYPE_MOVE, MOVE_SURGING_STRIKES, player);
HP_BAR(opponent, captureDamage: &thirdHit);
MESSAGE("A critical hit!");
} FINALLY {
} THEN {
EXPECT_EQ(firstHit, secondHit);
EXPECT_EQ(secondHit, thirdHit);
EXPECT_EQ(firstHit, thirdHit);

View File

@ -34,7 +34,7 @@ SINGLE_BATTLE_TEST("Electric Terrain activates Electric Seed and Mimicry")
MESSAGE("Using Electric Seed, the Defense of Wobbuffet rose!");
ABILITY_POPUP(opponent);
MESSAGE("Foe Stunfisk's type changed to Electr!");
} FINALLY {
} THEN {
EXPECT_EQ(gBattleMons[B_POSITION_OPPONENT_LEFT].type1, TYPE_ELECTRIC);
}
}

View File

@ -30,7 +30,7 @@ SINGLE_BATTLE_TEST("Grassy Terrain activates Grassy Seed and Mimicry")
MESSAGE("Using Grassy Seed, the Defense of Wobbuffet rose!");
ABILITY_POPUP(opponent);
MESSAGE("Foe Stunfisk's type changed to Grass!");
} FINALLY {
} THEN {
EXPECT_EQ(gBattleMons[B_POSITION_OPPONENT_LEFT].type1, TYPE_GRASS);
}
}

View File

@ -34,7 +34,7 @@ SINGLE_BATTLE_TEST("Misty Terrain activates Misty Seed and Mimicry")
MESSAGE("Using Misty Seed, the Sp. Def of Wobbuffet rose!");
ABILITY_POPUP(opponent);
MESSAGE("Foe Stunfisk's type changed to Fairy!");
} FINALLY {
} THEN {
EXPECT_EQ(gBattleMons[B_POSITION_OPPONENT_LEFT].type1, TYPE_FAIRY);
}
}

View File

@ -33,7 +33,7 @@ SINGLE_BATTLE_TEST("Psychic Terrain activates Psychic Seed and Mimicry")
MESSAGE("Using Psychic Seed, the Sp. Def of Wobbuffet rose!");
ABILITY_POPUP(opponent);
MESSAGE("Foe Stunfisk's type changed to Psychc!");
} FINALLY {
} THEN {
EXPECT_EQ(gBattleMons[B_POSITION_OPPONENT_LEFT].type1, TYPE_PSYCHIC);
}
}
@ -61,7 +61,7 @@ SINGLE_BATTLE_TEST("Psychic Terrain increases power of Psychic-type moves by 30/
}
}
SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target the user", s16 damage)
SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target the user")
{
GIVEN {
PLAYER(SPECIES_SABLEYE) { Ability(ABILITY_PRANKSTER); HP(1); }
@ -76,7 +76,7 @@ SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target the
}
}
SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target all battlers", s16 damage)
SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target all battlers")
{
KNOWN_FAILING;
GIVEN {
@ -91,7 +91,7 @@ SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target all
}
}
SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target all opponents", s16 damage)
SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target all opponents")
{
KNOWN_FAILING;
GIVEN {
@ -106,7 +106,7 @@ SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target all
}
}
DOUBLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target allies", s16 damage)
DOUBLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target allies")
{
GIVEN {
PLAYER(SPECIES_SABLEYE) { Ability(ABILITY_PRANKSTER); }
@ -122,7 +122,7 @@ DOUBLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target all
}
}
SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority field moves", s16 damage)
SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority field moves")
{
KNOWN_FAILING;
GIVEN {

View File

@ -897,7 +897,9 @@ void QueueStatus(u32 sourceLine, struct BattlePokemon *battler, struct StatusEve
/* Finally */
#define FINALLY for (; gBattleTestRunnerState->runFinally; gBattleTestRunnerState->runFinally = FALSE) if ((gBattleTestRunnerState->runningFinally = TRUE))
#define FINALLY for (ValidateFinally(__LINE__); gBattleTestRunnerState->runFinally; gBattleTestRunnerState->runFinally = FALSE) if ((gBattleTestRunnerState->runningFinally = TRUE))
void ValidateFinally(u32 sourceLine);
/* Expect */

View File

@ -42,7 +42,14 @@ static bool32 PrefixMatch(const char *pattern, const char *string)
}
}
enum { STATE_INIT, STATE_NEXT_TEST, STATE_REPORT_RESULT, STATE_EXIT };
enum
{
STATE_INIT,
STATE_NEXT_TEST,
STATE_RUN_TEST,
STATE_REPORT_RESULT,
STATE_EXIT,
};
void CB2_TestRunner(void)
{
@ -81,6 +88,26 @@ void CB2_TestRunner(void)
return;
}
MgbaPrintf_(":N%s", gTestRunnerState.test->name);
gTestRunnerState.result = TEST_RESULT_PASS;
gTestRunnerState.expectedResult = TEST_RESULT_PASS;
gTestRunnerState.expectLeaks = FALSE;
if (gTestRunnerHeadless)
gTestRunnerState.timeoutSeconds = TIMEOUT_SECONDS;
else
gTestRunnerState.timeoutSeconds = UINT_MAX;
InitHeap(gHeap, HEAP_SIZE);
EnableInterrupts(INTR_FLAG_TIMER2);
REG_TM2CNT_L = UINT16_MAX - (274 * 60); // Approx. 1 second.
REG_TM2CNT_H = TIMER_ENABLE | TIMER_INTR_ENABLE | TIMER_1024CLK;
// NOTE: Assumes that the compiler interns __FILE__.
if (gTestRunnerState.skipFilename == gTestRunnerState.test->filename)
{
gTestRunnerState.result = TEST_RESULT_ASSUMPTION_FAIL;
return;
}
// Greedily assign tests to processes based on estimated cost.
// TODO: Make processCosts a min heap.
if (gTestRunnerState.test->runner != &gAssumptionsRunner)
@ -98,40 +125,26 @@ void CB2_TestRunner(void)
}
}
if (minCostProcess == gTestRunnerI)
gTestRunnerState.state = STATE_RUN_TEST;
else
gTestRunnerState.state = STATE_NEXT_TEST;
// XXX: If estimateCost exits only on some processes then
// processCosts will be inconsistent.
if (gTestRunnerState.test->runner->estimateCost)
gTestRunnerState.processCosts[minCostProcess] += gTestRunnerState.test->runner->estimateCost(gTestRunnerState.test->data);
else
gTestRunnerState.processCosts[minCostProcess] += 1;
if (minCostProcess != gTestRunnerI)
return;
}
MgbaPrintf_(":N%s", gTestRunnerState.test->name);
break;
case STATE_RUN_TEST:
gTestRunnerState.state = STATE_REPORT_RESULT;
gTestRunnerState.result = TEST_RESULT_PASS;
gTestRunnerState.expectedResult = TEST_RESULT_PASS;
gTestRunnerState.expectLeaks = FALSE;
if (gTestRunnerHeadless)
gTestRunnerState.timeoutSeconds = TIMEOUT_SECONDS;
else
gTestRunnerState.timeoutSeconds = UINT_MAX;
InitHeap(gHeap, HEAP_SIZE);
EnableInterrupts(INTR_FLAG_TIMER2);
REG_TM2CNT_L = UINT16_MAX - (274 * 60); // Approx. 1 second.
REG_TM2CNT_H = TIMER_ENABLE | TIMER_INTR_ENABLE | TIMER_1024CLK;
// NOTE: Assumes that the compiler interns __FILE__.
if (gTestRunnerState.skipFilename == gTestRunnerState.test->filename)
{
gTestRunnerState.result = TEST_RESULT_ASSUMPTION_FAIL;
}
else
{
if (gTestRunnerState.test->runner->setUp)
gTestRunnerState.test->runner->setUp(gTestRunnerState.test->data);
gTestRunnerState.test->runner->run(gTestRunnerState.test->data);
}
if (gTestRunnerState.test->runner->setUp)
gTestRunnerState.test->runner->setUp(gTestRunnerState.test->data);
gTestRunnerState.test->runner->run(gTestRunnerState.test->data);
break;
case STATE_REPORT_RESULT:
@ -345,6 +358,8 @@ static void Intr_Timer2(void)
}
else
{
if (gTestRunnerState.state == STATE_RUN_TEST)
gTestRunnerState.state = STATE_REPORT_RESULT;
gTestRunnerState.result = TEST_RESULT_TIMEOUT;
ReinitCallbacks();
IRQ_LR = ((uintptr_t)JumpToAgbMainLoop & ~1) + 4;
@ -354,16 +369,19 @@ static void Intr_Timer2(void)
void Test_ExitWithResult(enum TestResult result, const char *fmt, ...)
{
bool32 handled = FALSE;
gTestRunnerState.result = result;
ReinitCallbacks();
if (gTestRunnerState.test->runner->handleExitWithResult)
handled = gTestRunnerState.test->runner->handleExitWithResult(gTestRunnerState.test->data, result);
if (!handled && gTestRunnerState.result != gTestRunnerState.expectedResult)
if (gTestRunnerState.state == STATE_REPORT_RESULT
&& gTestRunnerState.test->runner->handleExitWithResult)
{
va_list va;
va_start(va, fmt);
MgbaVPrintf_(fmt, va);
if (!gTestRunnerState.test->runner->handleExitWithResult(gTestRunnerState.test->data, result)
&& gTestRunnerState.result != gTestRunnerState.expectedResult)
{
va_list va;
va_start(va, fmt);
MgbaVPrintf_(fmt, va);
va_end(va);
}
}
JumpToAgbMainLoop();
}

View File

@ -134,6 +134,8 @@ static void BattleTest_SetUp(void *data)
Test_ExitWithResult(TEST_RESULT_ERROR, "OOM: STATE = AllocZerod(%d)", sizeof(*STATE));
InvokeTestFunction(test);
STATE->parameters = STATE->parametersCount;
if (STATE->parametersCount == 0 && test->resultsSize > 0)
Test_ExitWithResult(TEST_RESULT_INVALID, "results without PARAMETRIZE");
STATE->results = AllocZeroed(test->resultsSize * STATE->parameters);
if (!STATE->results)
Test_ExitWithResult(TEST_RESULT_ERROR, "OOM: STATE->results = AllocZerod(%d)", sizeof(test->resultsSize * STATE->parameters));
@ -939,6 +941,8 @@ static bool32 BattleTest_HandleExitWithResult(void *data, enum TestResult result
void Randomly(u32 sourceLine, u32 passes, u32 trials, struct RandomlyContext ctx)
{
const struct BattleTest *test = gTestRunnerState.test->data;
INVALID_IF(test->resultsSize > 0, "PASSES_RANDOMLY is incompatible with results");
INVALID_IF(passes > trials, "%d passes specified, but only %d trials", passes, trials);
STATE->rngTag = ctx.tag;
STATE->runTrial = 0;
@ -1564,6 +1568,10 @@ void UseItem(u32 sourceLine, struct BattlePokemon *battler, struct ItemContext c
}
INVALID_IF(i == MAX_MON_MOVES, "USE_ITEM on invalid move: %d", ctx.move);
}
else
{
i = 0;
}
PushBattlerAction(sourceLine, battlerId, RECORDED_ACTION_TYPE, B_ACTION_USE_ITEM);
PushBattlerAction(sourceLine, battlerId, RECORDED_ITEM_ID, (ctx.itemId >> 8) & 0xFF);
PushBattlerAction(sourceLine, battlerId, RECORDED_ITEM_ID, ctx.itemId & 0xFF);
@ -1719,7 +1727,6 @@ void QueueMessage(u32 sourceLine, const u8 *pattern)
};
}
void QueueStatus(u32 sourceLine, struct BattlePokemon *battler, struct StatusEventContext ctx)
{
s32 battlerId = battler - gBattleMons;
@ -1759,3 +1766,11 @@ void QueueStatus(u32 sourceLine, struct BattlePokemon *battler, struct StatusEve
}},
};
}
void ValidateFinally(u32 sourceLine)
{
// Defer this error until after estimating the cost.
if (STATE->results == NULL)
return;
INVALID_IF(STATE->parametersCount == 0, "FINALLY without PARAMETRIZE");
}