Adds a couple of helper functions for battles to run turns, prettify outputs.

This commit is contained in:
2021-08-24 21:19:44 +02:00
parent c821e6f53b
commit 1e36f8f5e3
7 changed files with 1031 additions and 14 deletions

View File

@@ -1,6 +1,8 @@
#ifndef POKEMONSCRIPTTESTER_BATTLEBUILDER_HPP
#define POKEMONSCRIPTTESTER_BATTLEBUILDER_HPP
#include <CreatureLib/Battling/TurnChoices/AttackTurnChoice.hpp>
#include <CreatureLib/Battling/TurnChoices/PassTurnChoice.hpp>
#include <PkmnLib/Battling/Battle/Battle.hpp>
#include <PkmnLib/Battling/Pokemon/CreatePokemon.hpp>
#include <angelscript.h>
@@ -13,11 +15,23 @@ class BattleBuilder {
TestEnvironment* env = static_cast<TestEnvironment*>(ctx->GetUserData());
auto lib = Globals::Library.GetValue();
auto mon1 = PkmnLib::Battling::CreatePokemon(lib, species1, level).Build();
auto mon1 = PkmnLib::Battling::CreatePokemon(lib, species1, level)
.WithEffortValues(0, 0, 0, 0, 0, 0)
.WithIndividualValues(31, 31, 31, 31, 31, 31)
.WithNature("hardy"_cnc)
.WithGender(CreatureLib::Library::Gender::Male)
.IsAllowedExperienceGain(false)
.Build();
auto p1 = new CreatureLib::Battling::CreatureParty(1);
p1->SwapInto(0, mon1);
auto mon2 = PkmnLib::Battling::CreatePokemon(lib, species2, level).Build();
auto mon2 = PkmnLib::Battling::CreatePokemon(lib, species2, level)
.WithEffortValues(0, 0, 0, 0, 0, 0)
.WithIndividualValues(31, 31, 31, 31, 31, 31)
.WithNature("hardy"_cnc)
.WithGender(CreatureLib::Library::Gender::Male)
.IsAllowedExperienceGain(false)
.Build();
auto p2 = new CreatureLib::Battling::CreatureParty(1);
p1->SwapInto(0, mon2);
@@ -40,12 +54,56 @@ class BattleBuilder {
return battle;
}
static bool UseMove(PkmnLib::Battling::Pokemon* user, const ArbUt::StringView& moveName, u8 sideTarget, u8 target) {
auto battle = user->GetBattle();
if (!battle.HasValue()) {
return false;
}
auto move = Globals::Library.GetValue()->GetMoveLibrary()->TryGet(moveName);
if (!move.has_value()) {
return false;
}
auto* ctx = asGetActiveContext();
TestEnvironment* env = static_cast<TestEnvironment*>(ctx->GetUserData());
auto learnedMove =
new PkmnLib::Battling::LearnedMove(move.value(), CreatureLib::Battling::AttackLearnMethod::Unknown);
env->AddGarbage(learnedMove);
auto choice = new CreatureLib::Battling::AttackTurnChoice(
user, learnedMove, CreatureLib::Battling::CreatureIndex(sideTarget, target));
auto b = battle.GetValue()->TrySetChoice(choice);
if (!b) {
delete choice;
}
return b;
}
static bool PassTurn(PkmnLib::Battling::Pokemon* user) {
auto battle = user->GetBattle();
if (!battle.HasValue()) {
return false;
}
auto choice = new CreatureLib::Battling::PassTurnChoice(user);
auto b = battle.GetValue()->TrySetChoice(choice);
if (!b) {
delete choice;
}
return b;
}
public:
static void Register(AngelScriptResolver* scriptResolver) {
auto engine = scriptResolver->GetBuilder().GetEngine();
Ensure(engine->RegisterGlobalFunction("Battle@ CreateSimpleBattle(uint seed, const constString&in species1, "
"const constString&in species2, uint8 level)",
asFUNCTION(CreateSimpleBattle), asCALL_CDECL) >= 0);
Ensure(engine->RegisterObjectMethod("Pokemon",
"bool UseMove(const constString&in move, uint8 side, uint8 index)",
asFUNCTION(UseMove), asCALL_CDECL_OBJFIRST) >= 0);
Ensure(engine->RegisterObjectMethod("Pokemon", "bool PassTurn()", asFUNCTION(PassTurn),
asCALL_CDECL_OBJFIRST) >= 0);
}
};

View File

@@ -12,10 +12,7 @@ private:
size_t Line;
};
static RequirementData GetRequirementData() {
auto* ctx = asGetActiveContext();
TestEnvironment* env = static_cast<TestEnvironment*>(ctx->GetUserData());
env->AssertionCount += 1;
static RequirementData GetRequirementData(asIScriptContext* ctx) {
auto filename = ctx->GetFunction()->GetScriptSectionName();
auto line = ctx->GetLineNumber();
return RequirementData{
@@ -25,8 +22,12 @@ private:
}
static bool Require(bool value) {
auto* ctx = asGetActiveContext();
TestEnvironment* env = static_cast<TestEnvironment*>(ctx->GetUserData());
env->TotalRequirements += 1;
if (!value) {
auto data = GetRequirementData();
env->FailedRequirements += 1;
auto data = GetRequirementData(ctx);
throw RequirementFailed(data.FileName, data.Line);
}
return true;
@@ -41,8 +42,12 @@ private:
}
static bool RequireEqualsI32(i32 expected, i32 actual) {
auto* ctx = asGetActiveContext();
TestEnvironment* env = static_cast<TestEnvironment*>(ctx->GetUserData());
env->TotalRequirements += 1;
if (expected != actual) {
auto data = GetRequirementData();
env->FailedRequirements += 1;
auto data = GetRequirementData(ctx);
GetEqualityMessage(expected, actual);
throw RequirementFailed(data.FileName, data.Line, eqMsg);
}
@@ -50,8 +55,11 @@ private:
}
static bool RequireEqualsString(const std::string& expected, const std::string& actual) {
auto* ctx = asGetActiveContext();
TestEnvironment* env = static_cast<TestEnvironment*>(ctx->GetUserData());
if (expected != actual) {
auto data = GetRequirementData();
env->FailedRequirements += 1;
auto data = GetRequirementData(ctx);
std::string eqMsg;
{
std::ostringstream ss;

View File

@@ -30,6 +30,9 @@ public:
inline TestResult GetResult() const noexcept { return _result; }
inline const std::string& GetErrorMessage() const noexcept { return _errorMessage; }
inline size_t GetTotalRequirements() const noexcept { return _env->TotalRequirements; }
inline size_t GetFailedRequirements() const noexcept { return _env->FailedRequirements; }
private:
std::string _name;
asIScriptFunction* _function;

View File

@@ -2,7 +2,8 @@
#define POKEMONSCRIPTTESTER_TESTENVIRONMENT_HPP
struct TestEnvironment {
size_t AssertionCount = 0;
size_t TotalRequirements = 0;
size_t FailedRequirements = 0;
template <typename T> void AddGarbage(T* data) { _garbage.Append(GarbageObject(data)); }

View File

@@ -2,6 +2,7 @@
#define POKEMONSCRIPTTESTER_TESTRUNNER_HPP
#include <PkmnLib/ScriptResolving/AngelScript/AngelScriptMetadata.hpp>
#include "../../extern/termcolor.hpp"
#include "Test.hpp"
class TestRunner {
@@ -34,27 +35,62 @@ public:
size_t notRunTests = 0;
size_t successfulTests = 0;
size_t failedTests = 0;
size_t totalRequirements = 0;
size_t failedRequirements = 0;
for (auto& test : _tests) {
auto result = test.second->GetResult();
switch (result) {
case TestResult::NotRan: notRunTests += 1; break;
case TestResult::Success: successfulTests += 1; break;
case TestResult::Failed: {
std::cout << "Test '" << test.first << "' failed with message: " << std::endl;
std::cout << termcolor::red << "Test '" << termcolor::yellow << test.first << termcolor::red
<< "' failed with message: " << termcolor::reset << std::endl;
std::cout << test.second->GetErrorMessage() << std::endl << std::endl;
failedTests += 1;
break;
}
}
totalRequirements += test.second->GetTotalRequirements();
failedRequirements += test.second->GetFailedRequirements();
}
std::cout << "Ran " << successfulTests + failedTests << " tests. Passed tests: " << successfulTests
<< ". Failed tests: " << failedTests << "." << std::endl;
auto totalTests = successfulTests + failedTests;
auto digitWidth = std::log10(std::max(totalTests, totalRequirements)) + 2;
std::cout << termcolor::blue << "=====================================================================";
for (int i = 0; i < digitWidth; ++i) {
std::cout << "===";
}
std::cout << termcolor::reset << std::endl;
ReportResults("Test cases", digitWidth, totalTests, successfulTests, failedTests, notRunTests);
ReportResults("Requirements", digitWidth, totalRequirements, totalRequirements - failedRequirements,
failedRequirements, {});
if (failedTests > 0) {
return 1;
}
return 0;
}
static void ReportResults(const std::string& label, double digitWidth, size_t total, size_t passed, size_t failed,
std::optional<size_t> skipped) {
std::cout << std::left // Left align
<< std::setw(16) << label + ":" << std::setw(digitWidth) << total << std::setw(3) << "|";
if (passed > 0) {
std::cout << termcolor::green;
}
std::cout << std::left << std::setw(14) << "Passed:" << std::setw(digitWidth) << passed << termcolor::reset
<< std::setw(3) << "|";
if (failed > 0) {
std::cout << termcolor::red;
}
std::cout << std::setw(14) << "Failed:" << std::setw(digitWidth) << failed << termcolor::reset;
if (skipped.has_value()) {
std::cout << std::setw(3) << "|" << std::setw(14) << "Skipped:" << std::setw(digitWidth) << skipped.value()
<< std::endl;
}
}
};
#endif // POKEMONSCRIPTTESTER_TESTRUNNER_HPP