Initial work on also doing battle stuff in tests.

This commit is contained in:
Deukhoofd 2021-08-23 21:44:59 +02:00
parent 3488339d51
commit c821e6f53b
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
9 changed files with 123 additions and 32 deletions

@ -1 +1 @@
Subproject commit 069eadf7c9f94ca4b8616dca8eb7562c9ecf26e0 Subproject commit 9b27ad72f18d4924d0851a523b64fbff0c779620

3
src/Globals.cpp Normal file
View File

@ -0,0 +1,3 @@
#include "Globals.hpp"
ArbUt::OptionalUniquePtr<const PkmnLib::Battling::BattleLibrary> Globals::Library = nullptr;

10
src/Globals.hpp Normal file
View File

@ -0,0 +1,10 @@
#ifndef POKEMONSCRIPTTESTER_GLOBALS_HPP
#define POKEMONSCRIPTTESTER_GLOBALS_HPP
#include <PkmnLib/Battling/Library/BattleLibrary.hpp>
class Globals {
public:
static ArbUt::OptionalUniquePtr<const PkmnLib::Battling::BattleLibrary> Library;
};
#endif // POKEMONSCRIPTTESTER_GLOBALS_HPP

View File

@ -0,0 +1,52 @@
#ifndef POKEMONSCRIPTTESTER_BATTLEBUILDER_HPP
#define POKEMONSCRIPTTESTER_BATTLEBUILDER_HPP
#include <PkmnLib/Battling/Battle/Battle.hpp>
#include <PkmnLib/Battling/Pokemon/CreatePokemon.hpp>
#include <angelscript.h>
#include "../TestEnvironment.hpp"
class BattleBuilder {
static PkmnLib::Battling::Battle* CreateSimpleBattle(u32 seed, const ArbUt::StringView& species1,
const ArbUt::StringView& species2, u8 level) {
auto* ctx = asGetActiveContext();
TestEnvironment* env = static_cast<TestEnvironment*>(ctx->GetUserData());
auto lib = Globals::Library.GetValue();
auto mon1 = PkmnLib::Battling::CreatePokemon(lib, species1, level).Build();
auto p1 = new CreatureLib::Battling::CreatureParty(1);
p1->SwapInto(0, mon1);
auto mon2 = PkmnLib::Battling::CreatePokemon(lib, species2, level).Build();
auto p2 = new CreatureLib::Battling::CreatureParty(1);
p1->SwapInto(0, mon2);
auto battle = new PkmnLib::Battling::Battle(
lib,
{new CreatureLib::Battling::BattleParty(p1, {CreatureLib::Battling::CreatureIndex(0, 0)}),
new CreatureLib::Battling::BattleParty(p2, {CreatureLib::Battling::CreatureIndex(1, 0)})},
true, // can flee
2, // 2 sides
1, // 1 mon per side
seed // with seed
);
battle->SwitchCreature(0, 0, mon1);
battle->SwitchCreature(1, 0, mon2);
env->AddGarbage(battle);
env->AddGarbage(p1);
env->AddGarbage(p2);
return battle;
}
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);
}
};
#endif // POKEMONSCRIPTTESTER_BATTLEBUILDER_HPP

View File

@ -2,32 +2,32 @@
#define POKEMONSCRIPTTESTER_TESTFUNCTIONS_HPP #define POKEMONSCRIPTTESTER_TESTFUNCTIONS_HPP
#include <angelscript.h> #include <angelscript.h>
#include "AssertionFailed.hpp" #include "../RequirementFailed.hpp"
#include "TestEnvironment.hpp" #include "../TestEnvironment.hpp"
class TestFunctions { class TestFunctions {
private: private:
struct AssertionData { struct RequirementData {
std::string FileName; std::string FileName;
size_t Line; size_t Line;
}; };
static AssertionData GetAssertionData() { static RequirementData GetRequirementData() {
auto* ctx = asGetActiveContext(); auto* ctx = asGetActiveContext();
TestEnvironment* env = static_cast<TestEnvironment*>(ctx->GetUserData()); TestEnvironment* env = static_cast<TestEnvironment*>(ctx->GetUserData());
env->AssertionCount += 1; env->AssertionCount += 1;
auto filename = ctx->GetFunction()->GetScriptSectionName(); auto filename = ctx->GetFunction()->GetScriptSectionName();
auto line = ctx->GetLineNumber(); auto line = ctx->GetLineNumber();
return AssertionData{ return RequirementData{
.FileName = filename, .FileName = filename,
.Line = (size_t)line, .Line = (size_t)line,
}; };
} }
static bool Assert(bool value) { static bool Require(bool value) {
if (!value) { if (!value) {
auto data = GetAssertionData(); auto data = GetRequirementData();
throw AssertionFailed(data.FileName, data.Line); throw RequirementFailed(data.FileName, data.Line);
} }
return true; return true;
} }
@ -40,25 +40,25 @@ private:
eqMsg = ss.str(); \ eqMsg = ss.str(); \
} }
static bool AssertEqualsI32(i32 expected, i32 actual) { static bool RequireEqualsI32(i32 expected, i32 actual) {
if (expected != actual) { if (expected != actual) {
auto data = GetAssertionData(); auto data = GetRequirementData();
GetEqualityMessage(expected, actual); GetEqualityMessage(expected, actual);
throw AssertionFailed(data.FileName, data.Line, eqMsg); throw RequirementFailed(data.FileName, data.Line, eqMsg);
} }
return true; return true;
} }
static bool AssertEqualsString(const std::string& expected, const std::string& actual) { static bool RequireEqualsString(const std::string& expected, const std::string& actual) {
if (expected != actual) { if (expected != actual) {
auto data = GetAssertionData(); auto data = GetRequirementData();
std::string eqMsg; std::string eqMsg;
{ {
std::ostringstream ss; std::ostringstream ss;
ss << "Expected: '" << expected << "', but was: '" << actual << "'"; ss << "Expected: '" << expected << "', but was: '" << actual << "'";
eqMsg = ss.str(); eqMsg = ss.str();
} }
throw AssertionFailed(data.FileName, data.Line, eqMsg); throw RequirementFailed(data.FileName, data.Line, eqMsg);
} }
return true; return true;
} }
@ -66,11 +66,11 @@ private:
public: public:
static void Register(AngelScriptResolver* scriptResolver) { static void Register(AngelScriptResolver* scriptResolver) {
auto engine = scriptResolver->GetBuilder().GetEngine(); auto engine = scriptResolver->GetBuilder().GetEngine();
Ensure(engine->RegisterGlobalFunction("bool Assert(bool expression)", asFUNCTION(Assert), asCALL_CDECL) >= 0); Ensure(engine->RegisterGlobalFunction("bool Require(bool expression)", asFUNCTION(Require), asCALL_CDECL) >= 0);
Ensure(engine->RegisterGlobalFunction("bool AssertEquals(int expected, int actual)", Ensure(engine->RegisterGlobalFunction("bool RequireEquals(int expected, int actual)",
asFUNCTION(AssertEqualsI32), asCALL_CDECL) >= 0); asFUNCTION(RequireEqualsI32), asCALL_CDECL) >= 0);
Ensure(engine->RegisterGlobalFunction("bool AssertEquals(const string &in expected, const string &in actual)", Ensure(engine->RegisterGlobalFunction("bool RequireEquals(const string &in expected, const string &in actual)",
asFUNCTION(AssertEqualsString), asCALL_CDECL) >= 0); asFUNCTION(RequireEqualsString), asCALL_CDECL) >= 0);
} }
}; };

View File

@ -1,9 +1,9 @@
#ifndef POKEMONSCRIPTTESTER_ASSERTIONFAILED_HPP #ifndef POKEMONSCRIPTTESTER_REQUIREMENTFAILED_HPP
#define POKEMONSCRIPTTESTER_ASSERTIONFAILED_HPP #define POKEMONSCRIPTTESTER_REQUIREMENTFAILED_HPP
#include <exception> #include <exception>
#include <sstream> #include <sstream>
class AssertionFailed : public std::exception { class RequirementFailed : public std::exception {
static inline std::string& ltrim(std::string& s, const char* t = " \t\n\r\f\v") { static inline std::string& ltrim(std::string& s, const char* t = " \t\n\r\f\v") {
s.erase(0, s.find_first_not_of(t)); s.erase(0, s.find_first_not_of(t));
return s; return s;
@ -26,10 +26,10 @@ class AssertionFailed : public std::exception {
char* _msg; char* _msg;
public: public:
AssertionFailed(const std::string& path, size_t line, const std::string& message = "") { RequirementFailed(const std::string& path, size_t line, const std::string& message = "") {
auto l = GetLine(path, line); auto l = GetLine(path, line);
std::stringstream ss; std::stringstream ss;
ss << "Assertion failed at: " << path << ":" << line << std::endl; ss << "Requirement failed at: " << path << ":" << line << std::endl;
ss << l; ss << l;
if (message.length() > 0) { if (message.length() > 0) {
ss << std::endl << message; ss << std::endl << message;
@ -40,9 +40,9 @@ public:
_msg[str.length()] = 0; _msg[str.length()] = 0;
} }
~AssertionFailed() { delete[] _msg; } ~RequirementFailed() { delete[] _msg; }
const char* what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW override { return _msg; } const char* what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW override { return _msg; }
}; };
#endif // POKEMONSCRIPTTESTER_ASSERTIONFAILED_HPP #endif // POKEMONSCRIPTTESTER_REQUIREMENTFAILED_HPP

View File

@ -15,6 +15,7 @@ public:
ctx->Prepare(_function); ctx->Prepare(_function);
ctx->SetUserData(_env.get()); ctx->SetUserData(_env.get());
auto e = ctx->Execute(); auto e = ctx->Execute();
_env->CollectGarbage();
if (e == asEXECUTION_EXCEPTION) { if (e == asEXECUTION_EXCEPTION) {
_errorMessage = ctx->GetExceptionString(); _errorMessage = ctx->GetExceptionString();
_result = TestResult::Failed; _result = TestResult::Failed;

View File

@ -3,6 +3,28 @@
struct TestEnvironment { struct TestEnvironment {
size_t AssertionCount = 0; size_t AssertionCount = 0;
template <typename T> void AddGarbage(T* data) { _garbage.Append(GarbageObject(data)); }
void CollectGarbage() {
for (auto& o : _garbage) {
o.Destructor(o.Ptr);
}
_garbage.Clear();
}
private:
struct GarbageObject {
void* Ptr;
std::function<void(void* ptr)> Destructor;
template <typename T> GarbageObject(T* ptr) {
Ptr = ptr;
Destructor = [](void* v) { delete static_cast<T*>(v); };
}
};
ArbUt::List<GarbageObject> _garbage;
}; };
#endif // POKEMONSCRIPTTESTER_TESTENVIRONMENT_HPP #endif // POKEMONSCRIPTTESTER_TESTENVIRONMENT_HPP

View File

@ -3,7 +3,9 @@
#include <iostream> #include <iostream>
#include "../extern/args.hpp" #include "../extern/args.hpp"
#include "BuildData/BuildLibrary.hpp" #include "BuildData/BuildLibrary.hpp"
#include "Tester/TestFunctions.hpp" #include "Globals.hpp"
#include "Tester/AngelScript/BattleBuilder.hpp"
#include "Tester/AngelScript/TestFunctions.hpp"
#include "Tester/TestRunner.hpp" #include "Tester/TestRunner.hpp"
int main(int argc, char** argv) { int main(int argc, char** argv) {
@ -41,13 +43,14 @@ int main(int argc, char** argv) {
auto* scriptResolver = dynamic_cast<AngelScriptResolver*>(resolver); auto* scriptResolver = dynamic_cast<AngelScriptResolver*>(resolver);
scriptResolver->DefineWord("TEST"); scriptResolver->DefineWord("TEST");
TestFunctions::Register(scriptResolver); TestFunctions::Register(scriptResolver);
BattleBuilder::Register(scriptResolver);
}; };
auto battleLib = ArbUt::OptionalScopedPtr(BuildLibrary::Build("", initialize)); Globals::Library = BuildLibrary::Build("", initialize);
if (!battleLib.HasValue()) { if (!Globals::Library.HasValue()) {
return 1; return 1;
} }
auto* scriptResolver = dynamic_cast<AngelScriptResolver*>(battleLib.GetValue()->GetScriptResolver().get()); auto* scriptResolver = dynamic_cast<AngelScriptResolver*>(Globals::Library.GetValue()->GetScriptResolver().get());
auto testRunner = TestRunner(scriptResolver); auto testRunner = TestRunner(scriptResolver);
auto* engine = scriptResolver->GetBuilder().GetEngine(); auto* engine = scriptResolver->GetBuilder().GetEngine();
return testRunner.RunAll(engine); return testRunner.RunAll(engine);