Initial work on WebAssembly script provider
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
2022-05-14 11:48:27 +02:00
parent c6775d7089
commit e32d655d80
31 changed files with 995 additions and 19 deletions

View File

@@ -0,0 +1,421 @@
#if TESTS_BUILD and ANGELSCRIPT
#include <doctest.h>
#include "../../src/Battling/Pokemon/CreatePokemon.hpp"
#include "../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp"
#include "../../src/ScriptResolving/AngelScript/ContextPool.hpp"
#include "../TestLibrary/TestLibrary.hpp"
#define AS_CLASS(name, contents) \
{ \
#name, "namespace Pokemon{ [Pokemon effect=" #name "] shared class " #name " : PkmnScript { " contents "}}" \
}
static std::unordered_map<const char*, const char*> _scripts = std::unordered_map<const char*, const char*>{
AS_CLASS(blankScript, ),
AS_CLASS(initializeScript, R"(
uint64 length = 0;
bool boolValue = false;
int64 intValue = 0;
constString stringValue;
void OnInitialize(const BattleLibrary@ library, const narray<EffectParameter@>@ parameters) override {
length = parameters.Length;
boolValue = parameters[0].AsBool();
intValue = parameters[1].AsInt();
stringValue = parameters[2].AsString();
}
uint64 GetLength() { return length; }
bool GetBoolValue() { return boolValue; }
int64 GetIntValue() { return intValue; }
constString GetStringValue() { return stringValue; }
)"),
AS_CLASS(stackScript, "int value = 0; void Stack() override { value++; } int GetValue() { return value; }"),
AS_CLASS(onRemoveScript, "int value = 0; void OnRemove() override { value++; } int GetValue() { return value; }"),
{"doubleInheritanceScript", R"(
class doubleInheritanceScriptBase : PkmnScript {
int value = 0;
void Stack() override{
value++;
}
int GetValue(){ return value; }
}
[Pokemon effect=doubleInheritanceScript]
class doubleInheritanceScript : doubleInheritanceScriptBase {}
)"},
AS_CLASS(preventAttackScript,
R"(void PreventAttack(ExecutingMove@ attack, bool& result) override{ result = !result; })"),
AS_CLASS(stopBeforeAttackScript, R"(
void StopBeforeAttack(ExecutingMove@ attack, bool& result) override{
result = !result;
})"),
AS_CLASS(OnBeforeAttackScript, "int value = 0; void OnBeforeAttack(ExecutingMove@ attack) override { value++; } "
"int GetValue() { return value; }"),
AS_CLASS(
FailIncomingAttackScript,
R"(void FailIncomingAttack(ExecutingMove@ attack, Pokemon@ target, bool& result) override{ result = !result; })"),
AS_CLASS(
IsInvulnerableScript,
R"(void IsInvulnerable(ExecutingMove@ attack, Pokemon@ target, bool& result) override{ result = !result; })"),
AS_CLASS(OnAttackMissScript,
R"(
int value = 0;
void OnAttackMiss(ExecutingMove@ attack, Pokemon@ target) override { value++; }
int GetValue() { return value; }
)"),
AS_CLASS(
ChangeAttackTypeScript,
R"(void ChangeAttackType(ExecutingMove@ attack, Pokemon@ target, uint8 hit, uint8& outType) override{outType = 1; };)"),
AS_CLASS(
ChangeEffectivenessScript,
R"(void ChangeEffectiveness(ExecutingMove@ attack, Pokemon@ target, uint8 hit, float& eff) override{eff = 0.75; };)"),
AS_CLASS(
PreventSecondaryEffectsScript,
R"(void PreventSecondaryEffects(ExecutingMove@ attack, Pokemon@ target, uint8 hit, bool& result) override{ result = !result; })"),
AS_CLASS(OnSecondaryEffectScript, R"(
int value = 0;
void OnSecondaryEffect(ExecutingMove@ attack, Pokemon@ target, uint8 hit) override {
value++;
}
int GetValue() { return value; })"),
AS_CLASS(OnAfterHitsScript,
"int value = 0; void OnAfterHits(ExecutingMove@ attack, Pokemon@ target) override { value++; } "
"int GetValue() { return value; }"),
AS_CLASS(throwScript,
R"(void PreventAttack(ExecutingMove@ attack, bool& result) override{ throw("test exception"); })"),
AS_CLASS(AddVolatileModMain,
R"(
void OnSecondaryEffect(ExecutingMove@ attack, Pokemon@ target, uint8 hit) override {
auto script = cast<AddVolatileModSecondary>(target.AddVolatile("AddVolatileModSecondary"));
script.value++;
};
)"),
AS_CLASS(AddVolatileModSecondary,
R"(
int value = 0;
int GetValue() { return value; }
)"),
};
static AngelScriptResolver* GetScriptResolver(PkmnLib::Battling::BattleLibrary* mainLib) {
auto res = dynamic_cast<AngelScriptResolver*>(mainLib->GetScriptResolver().get());
res->Reset(mainLib);
for (auto kv : _scripts) {
res->CreateScript(kv.first, kv.second);
}
res->FinalizeModule();
return res;
}
static AngelScriptScript* GetScript(PkmnLib::Battling::BattleLibrary* mainLib, const ArbUt::StringView& scriptName) {
auto lib = GetScriptResolver(mainLib);
auto s = lib->LoadScript(nullptr, ScriptCategory::Creature, scriptName);
auto script = dynamic_cast<AngelScriptScript*>(s);
REQUIRE(script != nullptr);
return script;
}
TEST_CASE("Invoke non-implemented script function") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "blankScript"_cnc);
REQUIRE(script != nullptr);
script->Stack();
delete script;
}
TEST_CASE("Invoke OnInitialize script function") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "initializeScript"_cnc);
REQUIRE(script != nullptr);
auto parameters = {new CreatureLib::Library::EffectParameter(true),
new CreatureLib::Library::EffectParameter((int64_t)684),
new CreatureLib::Library::EffectParameter(ArbUt::StringView("foobar"))};
script->OnInitialize(mainLib, parameters);
auto ctxPool = script->GetContextPool();
auto ctx = ctxPool->RequestContext();
script->PrepareMethod("GetLength"_cnc, ctx);
REQUIRE(ctx->Execute() == asEXECUTION_FINISHED);
REQUIRE_EQ((uint64_t)ctx->GetReturnQWord(), 3);
ctxPool->ReturnContextToPool(ctx);
ctx = ctxPool->RequestContext();
script->PrepareMethod("GetBoolValue"_cnc, ctx);
REQUIRE(ctx->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)ctx->GetReturnDWord());
ctxPool->ReturnContextToPool(ctx);
ctx = ctxPool->RequestContext();
script->PrepareMethod("GetIntValue"_cnc, ctx);
REQUIRE(ctx->Execute() == asEXECUTION_FINISHED);
REQUIRE(ctx->GetReturnQWord() == 684);
ctxPool->ReturnContextToPool(ctx);
ctx = ctxPool->RequestContext();
script->PrepareMethod("GetStringValue"_cnc, ctx);
REQUIRE(ctx->Execute() == asEXECUTION_FINISHED);
ctxPool->ReturnContextToPool(ctx);
for (auto p : parameters) {
delete p;
}
delete script;
}
TEST_CASE("Invoke Stack script function") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "stackScript"_cnc);
REQUIRE(script != nullptr);
for (int i = 1; i <= 10; i++) {
script->Stack();
auto ctxPool = script->GetContextPool();
auto ctx = ctxPool->RequestContext();
script->PrepareMethod("GetValue"_cnc, ctx);
REQUIRE(ctx->Execute() == asEXECUTION_FINISHED);
REQUIRE(ctx->GetReturnDWord() == i);
ctxPool->ReturnContextToPool(ctx);
}
delete script;
}
TEST_CASE("Invoke OnRemove script function") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "onRemoveScript"_cnc);
REQUIRE(script != nullptr);
script->OnRemove();
auto ctxPool = script->GetContextPool();
auto ctx = ctxPool->RequestContext();
script->PrepareMethod("GetValue"_cnc, ctx);
REQUIRE(ctx->Execute() == asEXECUTION_FINISHED);
REQUIRE(ctx->GetReturnDWord() == 1);
ctxPool->ReturnContextToPool(ctx);
delete script;
}
TEST_CASE("Invoke Stack script function with implementation in base class") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "doubleInheritanceScript"_cnc);
for (int i = 1; i <= 10; i++) {
script->Stack();
auto ctxPool = script->GetContextPool();
auto ctx = ctxPool->RequestContext();
script->PrepareMethod("GetValue"_cnc, ctx);
REQUIRE(ctx->Execute() == asEXECUTION_FINISHED);
REQUIRE(ctx->GetReturnDWord() == i);
ctxPool->ReturnContextToPool(ctx);
}
delete script;
}
TEST_CASE("Invoke preventAttackScript script function") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "preventAttackScript"_cnc);
bool b = false;
script->PreventAttack(nullptr, &b);
REQUIRE(b);
delete script;
}
TEST_CASE("Invoke StopBeforeAttack script function") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "stopBeforeAttackScript"_cnc);
bool b = false;
script->StopBeforeAttack(nullptr, &b);
REQUIRE(b);
delete script;
}
TEST_CASE("Invoke OnBeforeAttack script function") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "OnBeforeAttackScript"_cnc);
REQUIRE(script != nullptr);
script->OnBeforeAttack(nullptr);
auto ctxPool = script->GetContextPool();
auto ctx = ctxPool->RequestContext();
script->PrepareMethod("GetValue"_cnc, ctx);
REQUIRE(ctx->Execute() == asEXECUTION_FINISHED);
REQUIRE(ctx->GetReturnDWord() == 1);
ctxPool->ReturnContextToPool(ctx);
delete script;
}
TEST_CASE("Invoke FailIncomingAttack script function") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "FailIncomingAttackScript"_cnc);
REQUIRE(script != nullptr);
bool b = false;
script->FailIncomingAttack(nullptr, nullptr, &b);
REQUIRE(b);
delete script;
}
TEST_CASE("Invoke OnAttackMiss script function") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "OnAttackMissScript"_cnc);
REQUIRE(script != nullptr);
script->OnAttackMiss(nullptr, nullptr);
auto ctxPool = script->GetContextPool();
auto ctx = ctxPool->RequestContext();
script->PrepareMethod("GetValue"_cnc, ctx);
REQUIRE(ctx->Execute() == asEXECUTION_FINISHED);
REQUIRE(ctx->GetReturnDWord() == 1);
ctxPool->ReturnContextToPool(ctx);
delete script;
}
TEST_CASE("Invoke ChangeAttackType script function") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "ChangeAttackTypeScript"_cnc);
REQUIRE(script != nullptr);
uint8_t b = 0;
script->ChangeAttackType(nullptr, nullptr, 0, &b);
REQUIRE(b == 1);
delete script;
}
TEST_CASE("Invoke ChangeEffectiveness script function") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "ChangeEffectivenessScript"_cnc);
REQUIRE(script != nullptr);
float b = 0;
script->ChangeEffectiveness(nullptr, nullptr, 0, &b);
REQUIRE(b == doctest::Approx(0.75));
delete script;
}
TEST_CASE("Invoke PreventSecondaryEffects script function") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "PreventSecondaryEffectsScript"_cnc);
bool b = false;
script->PreventSecondaryEffects(nullptr, nullptr, 0, &b);
REQUIRE(b);
delete script;
}
TEST_CASE("Invoke OnSecondaryEffect script function") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "OnSecondaryEffectScript"_cnc);
script->OnSecondaryEffect(nullptr, nullptr, 0);
auto ctxPool = script->GetContextPool();
auto ctx = ctxPool->RequestContext();
script->PrepareMethod("GetValue"_cnc, ctx);
REQUIRE(ctx->Execute() == asEXECUTION_FINISHED);
REQUIRE(ctx->GetReturnDWord() == 1);
ctxPool->ReturnContextToPool(ctx);
delete script;
}
TEST_CASE("Invoke OnAfterHits script function") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "OnAfterHitsScript"_cnc);
REQUIRE(script != nullptr);
script->OnAfterHits(nullptr, nullptr);
auto ctxPool = script->GetContextPool();
auto ctx = ctxPool->RequestContext();
script->PrepareMethod("GetValue"_cnc, ctx);
REQUIRE(ctx->Execute() == asEXECUTION_FINISHED);
REQUIRE(ctx->GetReturnDWord() == 1);
ctxPool->ReturnContextToPool(ctx);
delete script;
}
void TryException(AngelScriptScript* script) {
bool b = false;
script->PreventAttack(nullptr, &b);
}
TEST_CASE("Get script name.") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "throwScript"_cnc);
REQUIRE(script != nullptr);
INFO(script->GetName().c_str());
INFO(script->GetName().std_str());
CHECK(strcmp(script->GetName().c_str(), "throwScript") == 0);
delete script;
}
TEST_CASE("Handle script exceptions.") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "throwScript"_cnc);
REQUIRE(script != nullptr);
try {
TryException(script);
} catch (const ArbUt::Exception& e) {
REQUIRE(strcmp(e.what(), "Script exception in script 'throwScript', line 1. Message: 'test exception'.") == 0);
delete script;
return;
}
throw ArbUt::Exception("Didn't throw");
}
static PkmnLib::Library::TimeOfDay GetTime() { return PkmnLib::Library::TimeOfDay::Morning; }
TEST_CASE("Add Volatile with return script function") {
auto statCalc = new PkmnLib::Battling::StatCalculator();
auto resolver = dynamic_cast<AngelScriptResolver*>(PkmnLib::Battling::BattleLibrary::CreateScriptResolver());
auto mainLib = new PkmnLib::Battling::BattleLibrary(
TestLibrary::BuildStaticLibrary(), statCalc, new PkmnLib::Battling::DamageLibrary(),
new PkmnLib::Battling::ExperienceLibrary(), resolver, new PkmnLib::Battling::MiscLibrary(GetTime),
new PkmnLib::Battling::CaptureLibrary());
resolver->Initialize(mainLib);
for (auto kv : _scripts) {
resolver->CreateScript(kv.first, kv.second);
}
resolver->FinalizeModule();
auto script = GetScript(mainLib, "AddVolatileModMain"_cnc);
auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies"_cnc, 30).Build();
script->OnSecondaryEffect(nullptr, mon, 0);
ArbUt::BorrowedPtr<CreatureLib::Battling::BattleScript> scriptObj = (CreatureLib::Battling::BattleScript*)1;
REQUIRE(const_cast<CreatureLib::Battling::ScriptAggregator&>(mon->GetScriptIterator()).GetNext(scriptObj));
REQUIRE(scriptObj->GetName() == "AddVolatileModSecondary"_cnc);
auto script2 = scriptObj.As<AngelScriptScript>();
auto ctxPool = script2->GetContextPool();
auto ctx = ctxPool->RequestContext();
script2->PrepareMethod("GetValue"_cnc, ctx);
REQUIRE(ctx->Execute() == asEXECUTION_FINISHED);
REQUIRE(ctx->GetReturnDWord() == 1);
ctxPool->ReturnContextToPool(ctx);
delete mon;
delete script;
delete mainLib;
}
#endif

View File

@@ -0,0 +1,83 @@
#if TESTS_BUILD and ANGELSCRIPT
#include <doctest.h>
#include "../../src/Battling/Pokemon/CreatePokemon.hpp"
#include "../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp"
#include "../TestLibrary/TestLibrary.hpp"
#define AS_CLASS(name, contents) \
{ #name, "namespace Pokemon{ [ItemUse effect=" #name "] class " #name " : ItemUseScript { " contents "}}" }
static std::unordered_map<const char*, const char*> _scripts = std::unordered_map<const char*, const char*>{
AS_CLASS(blankClass, R"(
)"),
AS_CLASS(isItemUsable, R"(
bool IsItemUsable() override {
return true;
}
)"),
AS_CLASS(isPokemonUseItem, R"(
bool IsPokemonUseItem() override {
return true;
}
)"),
};
static AngelScriptResolver* _resolverCache = nullptr;
static AngelScriptResolver* GetScriptResolver(PkmnLib::Battling::BattleLibrary* mainLib) {
if (_resolverCache != nullptr) {
delete _resolverCache;
}
_resolverCache = dynamic_cast<AngelScriptResolver*>(PkmnLib::Battling::BattleLibrary::CreateScriptResolver());
_resolverCache->Initialize(mainLib);
for (auto kv : _scripts) {
_resolverCache->CreateScript(kv.first, kv.second);
}
_resolverCache->FinalizeModule();
return _resolverCache;
}
static AngelScriptItemUseScript* GetScript(PkmnLib::Battling::BattleLibrary* mainLib, const ArbUt::StringView& name) {
auto lib = GetScriptResolver(mainLib);
auto item = CreatureLib::Library::Item(name, CreatureLib::Library::ItemCategory::MiscItem,
CreatureLib::Library::BattleItemCategory::None, 0,
new CreatureLib::Library::SecondaryEffect(100, name, {}), nullptr, {});
auto s = lib->LoadItemScript(&item);
auto script = dynamic_cast<AngelScriptItemUseScript*>(s);
REQUIRE(script != nullptr);
return script;
}
TEST_CASE("Invoke isItemUsable item use script function on empty class") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "blankClass"_cnc);
REQUIRE(script != nullptr);
REQUIRE_FALSE(script->IsItemUsable());
}
TEST_CASE("Invoke isItemUsable item use script function") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "isItemUsable"_cnc);
REQUIRE(script != nullptr);
REQUIRE(script->IsItemUsable());
}
TEST_CASE("Invoke isPokemonUseItem item use script function on empty class") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "blankClass"_cnc);
REQUIRE(script != nullptr);
REQUIRE_FALSE(script->IsCreatureUseItem());
}
TEST_CASE("Invoke isPokemonUseItem item use script function") {
auto mainLib = TestLibrary::GetLibrary();
auto script = GetScript(mainLib, "isPokemonUseItem"_cnc);
REQUIRE(script != nullptr);
REQUIRE(script->IsCreatureUseItem());
}
#endif

View File

@@ -0,0 +1,68 @@
#ifdef TESTS_BUILD
#include "../../../src/ScriptResolving/AngelScript/AngelScriptMetadata.hpp"
#include "Arbutils/StringView.hpp"
#include "doctest.h"
TEST_CASE("Metadata without parameters") {
auto m = AngelscriptMetadata("Foo");
REQUIRE_EQ(m.GetIdentifier(), "Foo"_cnc);
}
TEST_CASE("Metadata with single parameter") {
auto m = AngelscriptMetadata("Foo bar=zet");
REQUIRE_EQ(m.GetIdentifier(), "Foo"_cnc);
REQUIRE_EQ(m.GetParameter("bar"_cnc), "zet");
}
TEST_CASE("Metadata with single parameter with trailing space") {
auto m = AngelscriptMetadata("Foo bar=zet ");
REQUIRE_EQ(m.GetIdentifier(), "Foo"_cnc);
REQUIRE_EQ(m.GetParameter("bar"_cnc), "zet");
}
TEST_CASE("Metadata with single parameter with two spaces") {
auto m = AngelscriptMetadata("Foo bar=zet");
REQUIRE_EQ(m.GetIdentifier(), "Foo"_cnc);
REQUIRE_EQ(m.GetParameter("bar"_cnc), "zet");
}
TEST_CASE("Metadata with two parameters") {
auto m = AngelscriptMetadata("Foo bar=zet met=blabla");
REQUIRE_EQ(m.GetIdentifier(), "Foo"_cnc);
REQUIRE_EQ(m.GetParameter("bar"_cnc), "zet");
REQUIRE_EQ(m.GetParameter("met"_cnc), "blabla");
}
TEST_CASE("Metadata with two parameters and two spaces") {
auto m = AngelscriptMetadata("Foo bar=zet met=blabla");
REQUIRE_EQ(m.GetIdentifier(), "Foo"_cnc);
REQUIRE_EQ(m.GetParameter("bar"_cnc), "zet");
REQUIRE_EQ(m.GetParameter("met"_cnc), "blabla");
}
TEST_CASE("Metadata with single parameter in quotes") {
auto m = AngelscriptMetadata("Foo bar=\"this is a test string\"");
REQUIRE_EQ(m.GetIdentifier(), "Foo"_cnc);
REQUIRE_EQ(m.GetParameter("bar"_cnc), "this is a test string");
}
TEST_CASE("Metadata with single parameter in quotes with trailing space") {
auto m = AngelscriptMetadata("Foo bar=\"this is a test string\" ");
REQUIRE_EQ(m.GetIdentifier(), "Foo"_cnc);
REQUIRE_EQ(m.GetParameter("bar"_cnc), "this is a test string");
}
TEST_CASE("Metadata with single parameter in quotes without closing quote") {
auto m = AngelscriptMetadata("Foo bar=\"this is a test string");
REQUIRE_EQ(m.GetIdentifier(), "Foo"_cnc);
REQUIRE_EQ(m.GetParameter("bar"_cnc), "this is a test string");
}
TEST_CASE("Metadata with two parameters in quotes") {
auto m = AngelscriptMetadata("Foo bar=\"this is a test string\" parameter2=\"xoxo another string\"");
REQUIRE_EQ(m.GetIdentifier(), "Foo"_cnc);
REQUIRE_EQ(m.GetParameter("bar"_cnc), "this is a test string");
REQUIRE_EQ(m.GetParameter("parameter2"_cnc), "xoxo another string");
}
#endif

View File

@@ -0,0 +1,102 @@
#if TESTS_BUILD and ANGELSCRIPT
#include <doctest.h>
#include "../../src/Battling/Pokemon/CreatePokemon.hpp"
#include "../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp"
#include "../../src/ScriptResolving/AngelScript/ContextPool.hpp"
#include "../TestLibrary/TestLibrary.hpp"
static std::unordered_map<const char*, const char*> _scripts =
std::unordered_map<const char*, const char*>{{"basic_ownership_test",
R"(namespace Pokemon {
[Pokemon effect="basic_ownership_test"]
shared class basic_ownership_test : PkmnScript {
void Test(){
auto mon = cast<Pokemon@>(GetOwner());
if (mon is null){
print("mon was null");
throw("Owner was null!");
}
}
}
})"},
{"volatile_test",
R"(namespace Pokemon {
[Pokemon effect="volatile_test"]
shared class volatile_test : PkmnScript {
void Test(){
auto mon = cast<Pokemon@>(GetOwner());
if (mon is null){
throw("Owner was null!");
}
}
}
})"}};
void MessageCallback(const asSMessageInfo* msg, void*) {
const char* type = "ERR ";
if (msg->type == asMSGTYPE_WARNING)
type = "WARN";
else if (msg->type == asMSGTYPE_INFORMATION)
type = "INFO";
printf("%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message);
}
static AngelScriptResolver* GetScriptResolver(PkmnLib::Battling::BattleLibrary* mainLib) {
auto res = dynamic_cast<AngelScriptResolver*>(mainLib->GetScriptResolver().get());
res->Reset(mainLib);
res->GetEngine()->SetMessageCallback(asFUNCTION(MessageCallback), nullptr, asCALL_CDECL);
for (auto kv : _scripts) {
res->CreateScript(kv.first, kv.second);
}
res->FinalizeModule();
return res;
}
static AngelScriptScript* GetScript(PkmnLib::Battling::BattleLibrary* mainLib, const ArbUt::StringView& scriptName,
PkmnLib::Battling::Pokemon* owner) {
auto* lib = GetScriptResolver(mainLib);
auto* s = lib->LoadScript(owner, ScriptCategory::Creature, scriptName);
auto* script = dynamic_cast<AngelScriptScript*>(s);
REQUIRE(script != nullptr);
return script;
}
TEST_CASE("Basic script owner tests.") {
auto lib = TestLibrary::GetLibrary();
auto mon = PkmnLib::Battling::CreatePokemon(lib, "testSpecies"_cnc, 1).Build();
auto script = GetScript(lib, "basic_ownership_test"_cnc, mon);
REQUIRE(script != nullptr);
script->OnRemove();
auto ctxPool = script->GetContextPool();
auto ctx = ctxPool->RequestContext();
script->PrepareMethod("Test"_cnc, ctx);
REQUIRE(ctx->Execute() == asEXECUTION_FINISHED);
ctxPool->ReturnContextToPool(ctx);
delete script;
delete mon;
}
TEST_CASE("Add volatile and get owner.") {
auto lib = TestLibrary::GetLibrary();
auto mon = PkmnLib::Battling::CreatePokemon(lib, "testSpecies"_cnc, 1).Build();
auto res = dynamic_cast<AngelScriptResolver*>(lib->GetScriptResolver().get());
res->Reset(lib);
for (auto kv : _scripts) {
res->CreateScript(kv.first, kv.second);
}
res->FinalizeModule();
auto script = (AngelScriptScript*)mon->AddVolatileScript("volatile_test"_cnc);
REQUIRE(script != nullptr);
auto owner = script->GetAngelscriptOwner();
REQUIRE_EQ(owner->GetType(), res->GetEngine()->GetTypeInfoByName("Pokemon"));
delete mon;
}
#endif

View File

@@ -0,0 +1,127 @@
#if TESTS_BUILD && ANGELSCRIPT
#include <doctest.h>
#include "../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp"
#include "../../src/ScriptResolving/AngelScript/ContextPool.hpp"
#include "../TestLibrary/TestLibrary.hpp"
static std::unordered_map<const char*, const char*> _scripts =
std::unordered_map<const char*, const char*>{{"testScript1", R"(
namespace Pokemon{
[Pokemon effect=testScript1]
class testScript1 : PkmnScript {
int add(int a, int b) {
return a + b;
}
void testFunc2(const Species@ s){
if (s.Name != "testSpecies2"){
throw("err");
}
}
void OnInitialize(const BattleLibrary@ library, const narray<EffectParameter@>@ parameters) override { }
}
}
)"}};
TEST_CASE("Get a script resolver, initialize it, then delete it") {
auto lib = PkmnLib::Battling::BattleLibrary::CreateScriptResolver();
lib->Initialize(TestLibrary::GetLibrary());
delete lib;
}
TEST_CASE("Get a script resolver, set script load function, load script, then build module") {
auto lib = dynamic_cast<AngelScriptResolver*>(PkmnLib::Battling::BattleLibrary::CreateScriptResolver());
lib->Initialize(TestLibrary::GetLibrary());
lib->CreateScript("testScript1", _scripts["testScript1"]);
lib->FinalizeModule();
delete lib;
}
TEST_CASE("Build script resolver, then create object") {
auto lib = dynamic_cast<AngelScriptResolver*>(PkmnLib::Battling::BattleLibrary::CreateScriptResolver());
lib->Initialize(TestLibrary::GetLibrary());
lib->CreateScript("testScript1", _scripts["testScript1"]);
lib->FinalizeModule();
auto obj = lib->LoadScript(nullptr, ScriptCategory::Creature, "testScript1"_cnc);
delete obj;
delete lib;
}
TEST_CASE("Build script resolver, create object, invoke addition method") {
auto lib = dynamic_cast<AngelScriptResolver*>(PkmnLib::Battling::BattleLibrary::CreateScriptResolver());
lib->Initialize(TestLibrary::GetLibrary());
lib->CreateScript("testScript1", _scripts["testScript1"]);
lib->FinalizeModule();
auto obj = dynamic_cast<AngelScriptScript*>(lib->LoadScript(nullptr, ScriptCategory::Creature, "testScript1"_cnc));
REQUIRE(obj != nullptr);
auto ctxPool = obj->GetContextPool();
auto ctx = ctxPool->RequestContext();
auto func = obj->PrepareMethod("add"_cnc, ctx);
REQUIRE(func != nullptr);
ctx->SetArgDWord(0, 5);
ctx->SetArgDWord(1, 100);
auto result = ctx->Execute();
if (result == asEXECUTION_EXCEPTION) {
FAIL(ctx->GetExceptionString());
}
CHECK(result == asEXECUTION_FINISHED);
auto returnValue = ctx->GetReturnDWord();
REQUIRE(returnValue == 105);
ctxPool->ReturnContextToPool(ctx);
delete obj;
delete lib;
}
TEST_CASE("Get a script resolver, save the byte code to memory, create new script resolver from it") {
auto originLib = dynamic_cast<AngelScriptResolver*>(PkmnLib::Battling::BattleLibrary::CreateScriptResolver());
originLib->Initialize(TestLibrary::GetLibrary());
originLib->CreateScript("testScript1", _scripts["testScript1"]);
originLib->FinalizeModule();
auto obj =
dynamic_cast<AngelScriptScript*>(originLib->LoadScript(nullptr, ScriptCategory::Creature, "testScript1"_cnc));
REQUIRE(obj != nullptr);
REQUIRE(obj->GetType()->GetOnInitialize().Exists);
delete obj;
size_t size;
auto byteCode = originLib->WriteByteCodeToMemory(size);
auto newLib = dynamic_cast<AngelScriptResolver*>(PkmnLib::Battling::BattleLibrary::CreateScriptResolver());
newLib->Initialize(TestLibrary::GetLibrary());
newLib->LoadByteCodeFromMemory(byteCode, size);
obj = dynamic_cast<AngelScriptScript*>(newLib->LoadScript(nullptr, ScriptCategory::Creature, "testScript1"_cnc));
REQUIRE(obj != nullptr);
REQUIRE(obj->GetType()->GetOnInitialize().Exists);
delete obj;
delete originLib;
delete newLib;
free(byteCode);
}
TEST_CASE("Get a script resolver, save the byte code to file, create new script resolver from it") {
auto originLib = dynamic_cast<AngelScriptResolver*>(PkmnLib::Battling::BattleLibrary::CreateScriptResolver());
originLib->Initialize(TestLibrary::GetLibrary());
originLib->CreateScript("testScript1", _scripts["testScript1"]);
originLib->FinalizeModule();
originLib->WriteByteCodeToFile("foo.bin");
auto newLib = dynamic_cast<AngelScriptResolver*>(PkmnLib::Battling::BattleLibrary::CreateScriptResolver());
newLib->Initialize(TestLibrary::GetLibrary());
newLib->LoadByteCodeFromFile("foo.bin");
auto obj =
dynamic_cast<AngelScriptScript*>(newLib->LoadScript(nullptr, ScriptCategory::Creature, "testScript1"_cnc));
REQUIRE(obj != nullptr);
delete obj;
delete originLib;
delete newLib;
remove("foo.bin");
}
#endif

View File

@@ -0,0 +1,100 @@
#if TESTS_BUILD and ANGELSCRIPT
#include <doctest.h>
#include "../../../../src/Battling/Battle/Battle.hpp"
#include "../../../../src/Battling/Pokemon/CreatePokemon.hpp"
#include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp"
#include "../../../../src/ScriptResolving/AngelScript/ContextPool.hpp"
#include "../../../TestLibrary/TestLibrary.hpp"
static std::unordered_map<const char*, const char*> _scripts =
std::unordered_map<const char*, const char*>{{"testScript1", R"(
namespace Pokemon{
[Pokemon effect=testScript1]
class testScript1 : PkmnScript {
bool testGetPokemonIndex(BattleSide@ b, const Pokemon@ pokemon){ return b.GetPokemonIndex(pokemon) == 0; }
bool testGetSides(BattleSide@ a, BattleSide@ b, Battle@ battle) {
return battle.Sides.At(0) is a;
}
}}
)"}};
struct ScriptData {
AngelScriptScript* Script = nullptr;
AngelScriptResolver* Resolver = nullptr;
asIScriptFunction* Func = nullptr;
asIScriptContext* Context = nullptr;
~ScriptData() {
Script->GetContextPool()->ReturnContextToPool(Context);
delete Script;
}
};
static AngelScriptResolver* _resolverCache = nullptr;
static AngelScriptResolver* GetScriptResolver(PkmnLib::Battling::BattleLibrary* mainLib) {
if (_resolverCache == nullptr) {
_resolverCache = dynamic_cast<AngelScriptResolver*>(PkmnLib::Battling::BattleLibrary::CreateScriptResolver());
_resolverCache->Initialize(mainLib);
_resolverCache->CreateScript("testScript1", _scripts["testScript1"]);
_resolverCache->FinalizeModule();
}
return _resolverCache;
}
static ScriptData GetScript(PkmnLib::Battling::BattleLibrary* mainLib, const ArbUt::StringView& funcName) {
auto lib = GetScriptResolver(mainLib);
auto s = lib->LoadScript(nullptr, ScriptCategory::Creature, "testScript1"_cnc);
auto script = dynamic_cast<AngelScriptScript*>(s);
REQUIRE(script != nullptr);
auto ctxPool = script->GetContextPool();
auto ctx = ctxPool->RequestContext();
auto func = script->PrepareMethod(funcName, ctx);
REQUIRE(func != nullptr);
return {.Script = script, .Resolver = lib, .Func = func, .Context = ctx};
}
TEST_CASE("Validate Battle Side GetPokemonIndex") {
auto mainLib = TestLibrary::GetLibrary();
auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies"_cnc, 30).Build();
auto mon2 = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies"_cnc, 30).Build();
auto userParty = CreatureLib::Battling::CreatureParty({mon});
auto targetParty = CreatureLib::Battling::CreatureParty({mon2});
auto battle = PkmnLib::Battling::Battle(
mainLib, {
new CreatureLib::Battling::BattleParty(&userParty, {CreatureLib::Battling::CreatureIndex(0, 0)}),
new CreatureLib::Battling::BattleParty(&targetParty, {CreatureLib::Battling::CreatureIndex(1, 0)}),
});
battle.SwitchCreature(0, 0, mon);
battle.SwitchCreature(1, 0, mon2);
auto data = GetScript(mainLib, "testGetPokemonIndex"_cnc);
data.Context->SetArgObject(0, battle.GetSides()[0]);
data.Context->SetArgObject(1, mon);
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
}
TEST_CASE("Validate Battle GetBattleSides") {
auto mainLib = TestLibrary::GetLibrary();
auto battle = new PkmnLib::Battling::Battle(mainLib, {});
auto data = GetScript(mainLib, "testGetSides"_cnc);
data.Context->SetArgObject(0, battle->GetSides()[0].GetRaw());
data.Context->SetArgObject(1, battle->GetSides()[1].GetRaw());
data.Context->SetArgObject(2, battle);
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
delete battle;
}
#endif

View File

@@ -0,0 +1,369 @@
#if TESTS_BUILD and ANGELSCRIPT
#include <doctest.h>
#include "../../../../src/Battling/Pokemon/CreatePokemon.hpp"
#include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp"
#include "../../../../src/ScriptResolving/AngelScript/ContextPool.hpp"
#include "../../../TestLibrary/TestLibrary.hpp"
static std::unordered_map<const char*, const char*> _scripts =
std::unordered_map<const char*, const char*>{{"testScript1", R"(
namespace Pokemon{
[Pokemon effect=testScript1]
class testScript1 : PkmnScript {
bool testSpecies(Pokemon@ p, const Species@ species){ return p.Species is species; }
bool testForme(Pokemon@ p, const Forme@ forme){ return p.Forme is forme; }
bool testLevel(Pokemon@ p, uint8 level){ return p.Level == level; }
bool testExperience(Pokemon@ p, uint experience){ return p.Experience == experience; }
bool testGender(Pokemon@ p, Gender gender){ return p.Gender == gender; }
bool testShiny(Pokemon@ p, bool shiny){ return p.Shiny == shiny; }
bool testHeldItem(Pokemon@ p, Item@ item){ return p.HeldItem is item; }
bool testCurrentHealth(Pokemon@ p, uint health){ return p.CurrentHealth == health; }
bool testNickname(Pokemon@ p, const string& name){ return p.Nickname == name; }
bool testActiveAbility(Pokemon@ p, const constString &in ability){ return p.ActiveAbility == ability; }
bool testIsFainted(Pokemon@ p, bool b){ return p.IsFainted == b; }
bool testHasType(Pokemon@ p, uint8 type){ return p.HasType(type); }
void testDamage(Pokemon@ p, uint32 damage, DamageSource source){ p.Damage(damage, source); }
void testHeal(Pokemon@ p, uint32 amount){ p.Heal(amount); }
bool testMove(Pokemon@ p, uint index, LearnedMove@ move){ return p.Moves[index] is move; }
bool testHasHeldItem(Pokemon@ p, const constString &in item){ return p.HasHeldItem(item); }
void testSetHeldItem(Pokemon@ p, const constString &in item){ p.SetHeldItem(item); }
void testSetHeldItem2(Pokemon@ p){ p.SetHeldItem("testItem"); }
}}
)"}};
struct ScriptData {
AngelScriptScript* Script = nullptr;
AngelScriptResolver* Resolver = nullptr;
asIScriptFunction* Func = nullptr;
asIScriptContext* Context = nullptr;
~ScriptData() {
Script->GetContextPool()->ReturnContextToPool(Context);
delete Script;
}
};
static AngelScriptResolver* _resolverCache = nullptr;
static AngelScriptResolver* GetScriptResolver(PkmnLib::Battling::BattleLibrary* mainLib) {
if (_resolverCache == nullptr) {
_resolverCache = dynamic_cast<AngelScriptResolver*>(PkmnLib::Battling::BattleLibrary::CreateScriptResolver());
_resolverCache->Initialize(mainLib);
_resolverCache->CreateScript("testScript1", _scripts["testScript1"]);
_resolverCache->FinalizeModule();
}
return _resolverCache;
}
static ScriptData GetScript(PkmnLib::Battling::BattleLibrary* mainLib, const ArbUt::StringView& funcName) {
auto lib = GetScriptResolver(mainLib);
auto s = lib->LoadScript(nullptr, ScriptCategory::Creature, "testScript1"_cnc);
auto script = dynamic_cast<AngelScriptScript*>(s);
REQUIRE(script != nullptr);
auto ctxPool = script->GetContextPool();
auto ctx = ctxPool->RequestContext();
auto func = script->PrepareMethod(funcName, ctx);
REQUIRE(func != nullptr);
return {.Script = script, .Resolver = lib, .Func = func, .Context = ctx};
}
TEST_CASE("Validate Pokemon Species in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testSpecies"_cnc);
auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies"_cnc, 30).Build();
data.Context->SetArgObject(0, const_cast<PkmnLib::Battling::Pokemon*>(mon));
data.Context->SetArgObject(1, (void*)mon->GetSpecies().GetRaw());
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
delete mon;
}
TEST_CASE("Validate Pokemon Forme in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testForme"_cnc);
auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies"_cnc, 30).WithForme("default"_cnc).Build();
data.Context->SetArgObject(0, (void*)mon);
data.Context->SetArgObject(1, (void*)mon->GetForme().GetRaw());
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
delete mon;
}
TEST_CASE("Validate Pokemon Level in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testLevel"_cnc);
auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies"_cnc, 30).WithForme("default"_cnc).Build();
data.Context->SetArgObject(0, const_cast<PkmnLib::Battling::Pokemon*>(mon));
data.Context->SetArgByte(1, mon->GetLevel());
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
delete mon;
}
TEST_CASE("Validate Pokemon Experience in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testExperience"_cnc);
auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies"_cnc, 30).WithForme("default"_cnc).Build();
data.Context->SetArgObject(0, const_cast<PkmnLib::Battling::Pokemon*>(mon));
data.Context->SetArgDWord(1, mon->GetExperience());
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
delete mon;
}
TEST_CASE("Validate Pokemon Gender in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testGender"_cnc);
auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies"_cnc, 30)
.WithForme("default"_cnc)
.WithGender(CreatureLib::Library::Gender::Male)
.Build();
data.Context->SetArgObject(0, const_cast<PkmnLib::Battling::Pokemon*>(mon));
data.Context->SetArgDWord(1, (int)mon->GetGender());
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
delete mon;
}
TEST_CASE("Validate Pokemon Shininess in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testShiny"_cnc);
auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies"_cnc, 30)
.WithForme("default"_cnc)
.WithGender(CreatureLib::Library::Gender::Male)
.Build();
data.Context->SetArgObject(0, const_cast<PkmnLib::Battling::Pokemon*>(mon));
data.Context->SetArgByte(1, mon->IsShiny());
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
delete mon;
}
TEST_CASE("Validate Pokemon HeldItem in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testHeldItem"_cnc);
auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies"_cnc, 30)
.WithForme("default"_cnc)
.WithHeldItem("testItem"_cnc)
.WithGender(CreatureLib::Library::Gender::Male)
.Build();
data.Context->SetArgObject(0, const_cast<PkmnLib::Battling::Pokemon*>(mon));
data.Context->SetArgObject(1, (void*)mon->GetHeldItem().GetValue());
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
delete mon;
}
TEST_CASE("Validate Pokemon CurrentHealth in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testCurrentHealth"_cnc);
auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies"_cnc, 30)
.WithForme("default"_cnc)
.WithGender(CreatureLib::Library::Gender::Male)
.Build();
data.Context->SetArgObject(0, const_cast<PkmnLib::Battling::Pokemon*>(mon));
data.Context->SetArgDWord(1, mon->GetCurrentHealth());
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
delete mon;
}
TEST_CASE("Validate Pokemon Nickname in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testNickname"_cnc);
auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies"_cnc, 30)
.WithForme("default"_cnc)
.WithGender(CreatureLib::Library::Gender::Male)
.WithNickname("foobar")
.Build();
data.Context->SetArgObject(0, (void*)mon);
auto name = std::string(mon->GetNickname().value());
data.Context->SetArgAddress(1, &name);
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
delete mon;
}
TEST_CASE("Validate Pokemon Active Ability in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testActiveAbility"_cnc);
auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies"_cnc, 30)
.WithForme("default"_cnc)
.WithGender(CreatureLib::Library::Gender::Male)
.Build();
data.Context->SetArgObject(0, (void*)mon);
auto name = mon->GetActiveTalent()->GetName();
data.Context->SetArgAddress(1, &name);
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
delete mon;
}
TEST_CASE("Validate Pokemon IsFainted in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testIsFainted"_cnc);
auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies"_cnc, 30)
.WithForme("default"_cnc)
.WithGender(CreatureLib::Library::Gender::Male)
.Build();
data.Context->SetArgObject(0, const_cast<PkmnLib::Battling::Pokemon*>(mon));
data.Context->SetArgByte(1, mon->IsFainted());
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
delete mon;
}
TEST_CASE("Validate Pokemon HasType in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies3"_cnc, 30)
.WithForme("default"_cnc)
.WithGender(CreatureLib::Library::Gender::Male)
.Build();
for (auto t : mon->GetTypes()) {
auto data = GetScript(mainLib, "testHasType"_cnc);
data.Context->SetArgObject(0, const_cast<PkmnLib::Battling::Pokemon*>(mon));
data.Context->SetArgByte(1, t);
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
}
delete mon;
}
TEST_CASE("Validate Pokemon Damage in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies3"_cnc, 30)
.WithForme("default"_cnc)
.WithGender(CreatureLib::Library::Gender::Male)
.Build();
auto data = GetScript(mainLib, "testDamage"_cnc);
data.Context->SetArgObject(0, const_cast<PkmnLib::Battling::Pokemon*>(mon));
data.Context->SetArgDWord(1, 30);
data.Context->SetArgDWord(2, (asDWORD)CreatureLib::Battling::DamageSource::AttackDamage);
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE(mon->GetCurrentHealth() == mon->GetBoostedStat(PkmnLib::Library::Statistic::HealthPoints) - 30);
delete mon;
}
TEST_CASE("Validate Pokemon Heal in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies3"_cnc, 30)
.WithForme("default"_cnc)
.WithGender(CreatureLib::Library::Gender::Male)
.Build();
mon->Damage(50, CreatureLib::Battling::DamageSource::AttackDamage);
auto data = GetScript(mainLib, "testHeal"_cnc);
data.Context->SetArgObject(0, const_cast<PkmnLib::Battling::Pokemon*>(mon));
data.Context->SetArgDWord(1, 30);
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE(mon->GetCurrentHealth() == mon->GetBoostedStat(PkmnLib::Library::Statistic::HealthPoints) - 20);
delete mon;
}
TEST_CASE("Validate Pokemon GetMoves in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies3"_cnc, 30)
.WithForme("default"_cnc)
.LearnMove("testMove"_cnc, CreatureLib::Battling::AttackLearnMethod::Level)
.LearnMove("testMove2"_cnc, CreatureLib::Battling::AttackLearnMethod::Unknown)
.Build();
for (size_t i = 0; i < mon->GetMoves().Count(); i++) {
auto data = GetScript(mainLib, "testMove"_cnc);
data.Context->SetArgObject(0, const_cast<PkmnLib::Battling::Pokemon*>(mon));
data.Context->SetArgDWord(1, i);
data.Context->SetArgObject(2, (void*)mon->GetMoves()[i]);
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
}
delete mon;
}
TEST_CASE("Validate Pokemon HasHeldItem in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies3"_cnc, 30)
.WithForme("default"_cnc)
.WithHeldItem("testItem"_cnc)
.Build();
auto data = GetScript(mainLib, "testHasHeldItem"_cnc);
data.Context->SetArgObject(0, const_cast<PkmnLib::Battling::Pokemon*>(mon));
ArbUt::StringView item = "testItem"_cnc;
data.Context->SetArgAddress(1, &item);
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnDWord());
delete mon;
}
TEST_CASE("Test Pokemon SetHeldItem in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies3"_cnc, 30).WithForme("default"_cnc).Build();
auto data = GetScript(mainLib, "testSetHeldItem"_cnc);
data.Context->SetArgObject(0, const_cast<PkmnLib::Battling::Pokemon*>(mon));
ArbUt::StringView item = "testItem"_cnc;
data.Context->SetArgAddress(1, &item);
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE(mon->HasHeldItem("testItem"_cnc));
delete mon;
}
TEST_CASE("Test Pokemon SetHeldItem2 in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies3"_cnc, 30).WithForme("default"_cnc).Build();
auto data = GetScript(mainLib, "testSetHeldItem2"_cnc);
data.Context->SetArgObject(0, const_cast<PkmnLib::Battling::Pokemon*>(mon));
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE(mon->HasHeldItem("testItem"_cnc));
delete mon;
}
#endif

View File

@@ -0,0 +1,176 @@
#if TESTS_BUILD and ANGELSCRIPT
#include <doctest.h>
#include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp"
#include "../../../../src/ScriptResolving/AngelScript/ContextPool.hpp"
#include "../../../TestLibrary/TestLibrary.hpp"
static std::unordered_map<const char*, const char*> _scripts =
std::unordered_map<const char*, const char*>{{"testScript1", R"(
namespace Pokemon{
[Pokemon effect=testScript1]
class testScript1 : PkmnScript {
bool testName(const Forme@ s, const constString &in name){ return s.Name == name; }
bool testWeight(const Forme@ s, float weight){ return s.Weight == weight; }
bool testHeight(const Forme@ s, float height){ return s.Height == height; }
bool testBaseExperience(const Forme@ s, uint baseExperience){ return s.BaseExperience == baseExperience; }
bool testTypeCount(const Forme@ s, int typeCount){ return s.TypeCount == typeCount; }
bool testGetType(const Forme@ s, uint8 type){ return s.GetType(0) == type; }
bool testGetStatistic(const Forme@ s, Statistic stat, uint value){ return s.GetStatistic(stat) == value; }
bool testGetAbility(const Forme@ s, const constString &in ability){ return s.GetAbility(false, 0) == ability; }
}}
)"}};
struct ScriptData {
AngelScriptScript* Script = nullptr;
AngelScriptResolver* Resolver = nullptr;
asIScriptFunction* Func = nullptr;
asIScriptContext* Context = nullptr;
~ScriptData() {
Script->GetContextPool()->ReturnContextToPool(Context);
delete Script;
}
};
static AngelScriptResolver* _resolverCache = nullptr;
static AngelScriptResolver* GetScriptResolver(PkmnLib::Battling::BattleLibrary* mainLib) {
if (_resolverCache == nullptr) {
_resolverCache = dynamic_cast<AngelScriptResolver*>(PkmnLib::Battling::BattleLibrary::CreateScriptResolver());
_resolverCache->Initialize(mainLib);
_resolverCache->CreateScript("testScript1", _scripts["testScript1"]);
_resolverCache->FinalizeModule();
}
return _resolverCache;
}
static ScriptData GetScript(PkmnLib::Battling::BattleLibrary* mainLib, const ArbUt::StringView& funcName) {
auto lib = GetScriptResolver(mainLib);
auto s = lib->LoadScript(nullptr, ScriptCategory::Creature, "testScript1"_cnc);
auto script = dynamic_cast<AngelScriptScript*>(s);
REQUIRE(script != nullptr);
auto ctxPool = script->GetContextPool();
auto ctx = ctxPool->RequestContext();
auto func = script->PrepareMethod(funcName, ctx);
REQUIRE(func != nullptr);
return {.Script = script, .Resolver = lib, .Func = func, .Context = ctx};
}
TEST_CASE("Validate Forme Name in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testName"_cnc);
auto forme = mainLib->GetSpeciesLibrary()->Get("testSpecies2"_cnc)->GetDefaultForme();
data.Context->SetArgObject(0, (void*)forme.GetRaw());
auto name = forme->GetName();
data.Context->SetArgAddress(1, &name);
auto result = data.Context->Execute();
REQUIRE(result == asEXECUTION_FINISHED);
auto v = (bool)data.Context->GetReturnWord();
REQUIRE(v);
}
TEST_CASE("Validate Forme Weight in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testWeight"_cnc);
auto forme = mainLib->GetSpeciesLibrary()->Get("testSpecies2"_cnc)->GetDefaultForme();
data.Context->SetArgObject(0, (void*)forme.GetRaw());
data.Context->SetArgFloat(1, forme->GetWeight());
auto result = data.Context->Execute();
REQUIRE(result == asEXECUTION_FINISHED);
auto v = (bool)data.Context->GetReturnWord();
REQUIRE(v);
}
TEST_CASE("Validate Forme Height in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testHeight"_cnc);
auto forme = mainLib->GetSpeciesLibrary()->Get("testSpecies2"_cnc)->GetDefaultForme();
data.Context->SetArgObject(0, (void*)forme.GetRaw());
data.Context->SetArgFloat(1, forme->GetHeight());
auto result = data.Context->Execute();
REQUIRE(result == asEXECUTION_FINISHED);
auto v = (bool)data.Context->GetReturnWord();
REQUIRE(v);
}
TEST_CASE("Validate Forme Base Experience in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testBaseExperience"_cnc);
auto forme = mainLib->GetSpeciesLibrary()->Get("testSpecies2"_cnc)->GetDefaultForme();
data.Context->SetArgObject(0, (void*)forme.GetRaw());
data.Context->SetArgDWord(1, forme->GetBaseExperience());
auto result = data.Context->Execute();
REQUIRE(result == asEXECUTION_FINISHED);
auto v = (bool)data.Context->GetReturnWord();
REQUIRE(v);
}
TEST_CASE("Validate Forme Type Count in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testTypeCount"_cnc);
auto forme = mainLib->GetSpeciesLibrary()->Get("testSpecies2"_cnc)->GetDefaultForme();
data.Context->SetArgObject(0, (void*)forme.GetRaw());
data.Context->SetArgDWord(1, forme->GetTypeCount());
auto result = data.Context->Execute();
REQUIRE(result == asEXECUTION_FINISHED);
auto v = (bool)data.Context->GetReturnWord();
REQUIRE(v);
}
TEST_CASE("Validate Forme GetType in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testGetType"_cnc);
auto forme = mainLib->GetSpeciesLibrary()->Get("testSpecies2"_cnc)->GetDefaultForme();
data.Context->SetArgObject(0, (void*)forme.GetRaw());
data.Context->SetArgByte(1, forme->GetType(0));
auto result = data.Context->Execute();
REQUIRE(result == asEXECUTION_FINISHED);
auto v = (bool)data.Context->GetReturnWord();
REQUIRE(v);
}
TEST_CASE("Validate Forme GetStatistic in Script") {
auto mainLib = TestLibrary::GetLibrary();
// Iterate over each stat, ensure they return the expected value.
for (uint8_t statInt = static_cast<uint8_t>(CreatureLib::Library::Statistic::Health);
statInt != static_cast<uint8_t>(CreatureLib::Library::Statistic::Speed); statInt++) {
auto stat = static_cast<CreatureLib::Library::Statistic>(statInt);
auto data = GetScript(mainLib, "testGetStatistic"_cnc);
auto forme = mainLib->GetSpeciesLibrary()->Get("testSpecies2"_cnc)->GetDefaultForme();
data.Context->SetArgObject(0, (void*)forme.GetRaw());
data.Context->SetArgDWord(1, static_cast<asDWORD>(stat));
data.Context->SetArgDWord(2, forme->GetStatistic(stat));
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
}
}
TEST_CASE("Validate Forme GetAbility in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testGetAbility"_cnc);
auto forme = mainLib->GetSpeciesLibrary()->Get("testSpecies2"_cnc)->GetDefaultForme();
data.Context->SetArgObject(0, (void*)forme.GetRaw());
auto ability = forme->GetAbility(CreatureLib::Library::TalentIndex(false, 0))->GetName();
data.Context->SetArgAddress(1, &ability);
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
}
#endif

View File

@@ -0,0 +1,106 @@
#if TESTS_BUILD and ANGELSCRIPT
#include <doctest.h>
#include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp"
#include "../../../../src/ScriptResolving/AngelScript/ContextPool.hpp"
#include "../../../TestLibrary/TestLibrary.hpp"
static std::unordered_map<const char*, const char*> _scripts =
std::unordered_map<const char*, const char*>{{"testScript1", R"(
namespace Pokemon{
[Pokemon effect=testScript1]
class testScript1 : PkmnScript {
bool testName(const Item@ i, const constString &in name){ return i.Name == name; }
bool testCategory(const Item@ i, ItemCategory category){ return i.Category == category; }
bool testBattleCategory(const Item@ i, BattleItemCategory category){ return i.BattleCategory == category; }
bool testPrice(const Item@ i, int price){ return i.Price == price; }
}}
)"}};
struct ScriptData {
AngelScriptScript* Script = nullptr;
AngelScriptResolver* Resolver = nullptr;
asIScriptFunction* Func = nullptr;
asIScriptContext* Context = nullptr;
~ScriptData() {
Script->GetContextPool()->ReturnContextToPool(Context);
delete Script;
}
};
static AngelScriptResolver* _resolverCache = nullptr;
static AngelScriptResolver* GetScriptResolver(PkmnLib::Battling::BattleLibrary* mainLib) {
if (_resolverCache == nullptr) {
_resolverCache = dynamic_cast<AngelScriptResolver*>(PkmnLib::Battling::BattleLibrary::CreateScriptResolver());
_resolverCache->Initialize(mainLib);
_resolverCache->CreateScript("testScript1", _scripts["testScript1"]);
_resolverCache->FinalizeModule();
}
return _resolverCache;
}
static ScriptData GetScript(PkmnLib::Battling::BattleLibrary* mainLib, const ArbUt::StringView& funcName) {
auto lib = GetScriptResolver(mainLib);
auto s = lib->LoadScript(nullptr, ScriptCategory::Creature, "testScript1"_cnc);
auto script = dynamic_cast<AngelScriptScript*>(s);
REQUIRE(script != nullptr);
auto ctxPool = script->GetContextPool();
auto ctx = ctxPool->RequestContext();
auto func = script->PrepareMethod(funcName, ctx);
REQUIRE(func != nullptr);
return {.Script = script, .Resolver = lib, .Func = func, .Context = ctx};
}
TEST_CASE("Validate Item Name in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testName"_cnc);
auto item = mainLib->GetItemLibrary()->Get("testItem"_cnc);
data.Context->SetArgObject(0, (void*)item.GetRaw());
auto name = item->GetName();
data.Context->SetArgAddress(1, &name);
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
}
TEST_CASE("Validate Item Category in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testCategory"_cnc);
auto item = mainLib->GetItemLibrary()->Get("testItem"_cnc);
data.Context->SetArgObject(0, (void*)item.GetRaw());
data.Context->SetArgDWord(1, static_cast<int32_t>(item->GetCategory()));
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
}
TEST_CASE("Validate Item Battle Category in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testBattleCategory"_cnc);
auto item = mainLib->GetItemLibrary()->Get("testItem"_cnc);
data.Context->SetArgObject(0, (void*)item.GetRaw());
data.Context->SetArgDWord(1, static_cast<int32_t>(item->GetBattleCategory()));
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
}
TEST_CASE("Validate Item Price in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testPrice"_cnc);
auto item = mainLib->GetItemLibrary()->Get("testItem"_cnc);
data.Context->SetArgObject(0, (void*)item.GetRaw());
data.Context->SetArgDWord(1, static_cast<int32_t>(item->GetPrice()));
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
}
#endif

View File

@@ -0,0 +1,161 @@
#if TESTS_BUILD and ANGELSCRIPT
#include <doctest.h>
#include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp"
#include "../../../../src/ScriptResolving/AngelScript/ContextPool.hpp"
#include "../../../TestLibrary/TestLibrary.hpp"
static std::unordered_map<const char*, const char*> _scripts =
std::unordered_map<const char*, const char*>{{"testScript1", R"(
namespace Pokemon{
[Pokemon effect=testScript1]
class testScript1 : PkmnScript {
bool testName(const MoveData@ s, const constString &in name){ return s.Name == name; }
bool testType(const MoveData@ s, uint8 type){ return s.Type == type; }
bool testCategory(const MoveData@ s, MoveCategory category){ return s.Category == category; }
bool testBasePower(const MoveData@ s, uint8 basePower){ return s.BasePower == basePower; }
bool testAccuracy(const MoveData@ s, uint8 accuracy){ return s.Accuracy == accuracy; }
bool testBaseUsages(const MoveData@ s, uint8 baseUsages){ return s.BaseUsages == baseUsages; }
bool testTarget(const MoveData@ s, MoveTarget target){ return s.Target == target; }
bool testPriority(const MoveData@ s, int8 priority){ return s.Priority == priority; }
}}
)"}};
struct ScriptData {
AngelScriptScript* Script = nullptr;
AngelScriptResolver* Resolver = nullptr;
asIScriptFunction* Func = nullptr;
asIScriptContext* Context = nullptr;
~ScriptData() {
Script->GetContextPool()->ReturnContextToPool(Context);
delete Script;
}
};
static AngelScriptResolver* _resolverCache = nullptr;
static AngelScriptResolver* GetScriptResolver(PkmnLib::Battling::BattleLibrary* mainLib) {
if (_resolverCache == nullptr) {
_resolverCache = dynamic_cast<AngelScriptResolver*>(PkmnLib::Battling::BattleLibrary::CreateScriptResolver());
_resolverCache->Initialize(mainLib);
_resolverCache->CreateScript("testScript1", _scripts["testScript1"]);
_resolverCache->FinalizeModule();
}
return _resolverCache;
}
static ScriptData GetScript(PkmnLib::Battling::BattleLibrary* mainLib, const ArbUt::StringView& funcName) {
auto lib = GetScriptResolver(mainLib);
auto s = lib->LoadScript(nullptr, ScriptCategory::Creature, "testScript1"_cnc);
auto script = dynamic_cast<AngelScriptScript*>(s);
REQUIRE(script != nullptr);
auto ctxPool = script->GetContextPool();
auto ctx = ctxPool->RequestContext();
auto func = script->PrepareMethod(funcName, ctx);
REQUIRE(func != nullptr);
return {.Script = script, .Resolver = lib, .Func = func, .Context = ctx};
}
TEST_CASE("Validate Move Name in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testName"_cnc);
auto move = mainLib->GetMoveLibrary()->Get("testMove"_cnc);
data.Context->SetArgObject(0, (void*)move.GetRaw());
auto name = move->GetName();
data.Context->SetArgAddress(1, &name);
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
}
TEST_CASE("Validate Move Type in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testType"_cnc);
auto move = mainLib->GetMoveLibrary()->Get("testMove"_cnc);
data.Context->SetArgObject(0, (void*)move.GetRaw());
data.Context->SetArgByte(1, move->GetType());
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
}
TEST_CASE("Validate Move Category in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testCategory"_cnc);
auto move = mainLib->GetMoveLibrary()->Get("testMove"_cnc);
data.Context->SetArgObject(0, (void*)move.GetRaw());
data.Context->SetArgDWord(1, (asDWORD)move->GetCategory());
auto result = data.Context->Execute();
INFO("exception: " << data.Context->GetExceptionString());
REQUIRE(result == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnByte());
}
TEST_CASE("Validate Move BasePower in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testBasePower"_cnc);
auto move = mainLib->GetMoveLibrary()->Get("testMove"_cnc);
data.Context->SetArgObject(0, (void*)move.GetRaw());
data.Context->SetArgByte(1, move->GetBasePower());
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
}
TEST_CASE("Validate Move Accuracy in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testAccuracy"_cnc);
auto move = mainLib->GetMoveLibrary()->Get("testMove"_cnc);
data.Context->SetArgObject(0, (void*)move.GetRaw());
data.Context->SetArgByte(1, move->GetAccuracy());
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
}
TEST_CASE("Validate Move BaseUsages in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testBaseUsages"_cnc);
auto move = mainLib->GetMoveLibrary()->Get("testMove"_cnc);
data.Context->SetArgObject(0, (void*)move.GetRaw());
data.Context->SetArgByte(1, move->GetBaseUsages());
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
}
TEST_CASE("Validate Move Target in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testTarget"_cnc);
auto move = mainLib->GetMoveLibrary()->Get("testMove"_cnc);
data.Context->SetArgObject(0, (void*)move.GetRaw());
data.Context->SetArgDWord(1, (uint32_t)move->GetTarget());
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
}
TEST_CASE("Validate Move Priority in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testPriority"_cnc);
auto move = mainLib->GetMoveLibrary()->Get("testMove"_cnc);
data.Context->SetArgObject(0, (void*)move.GetRaw());
data.Context->SetArgByte(1, move->GetPriority());
REQUIRE(data.Context->Execute() == asEXECUTION_FINISHED);
REQUIRE((bool)data.Context->GetReturnWord());
}
#endif

View File

@@ -0,0 +1,147 @@
#if TESTS_BUILD && ANGELSCRIPT
#include <doctest.h>
#include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp"
#include "../../../../src/ScriptResolving/AngelScript/ContextPool.hpp"
#include "../../../TestLibrary/TestLibrary.hpp"
static std::unordered_map<const char*, const char*> _scripts =
std::unordered_map<const char*, const char*>{{"testScript1", R"(
namespace Pokemon{
[Pokemon effect=testScript1]
class testScript1 : PkmnScript {
bool testName(const Species@ s, const constString &in name){ return s.Name == name; }
bool testId(const Species@ s, uint16 id){ return s.Id == id; }
bool testGenderRate(const Species@ s, float rate){ return s.GenderRate == rate; }
bool testCaptureRate(const Species@ s, uint8 rate){ return s.CaptureRate == rate; }
bool testGetForme(const Species@ s, const Forme@ forme){ return s.GetForme("default") is forme; }
bool testGetDefaultForme(const Species@ s, const Forme@ forme){ return s.DefaultForme is forme; }
}}
)"}};
struct ScriptData {
AngelScriptScript* Script;
AngelScriptResolver* Resolver;
asIScriptFunction* Func;
asIScriptContext* Context;
~ScriptData() {
Script->GetContextPool()->ReturnContextToPool(Context);
delete Script;
}
};
static AngelScriptResolver* _resolverCache = nullptr;
static AngelScriptResolver* GetScriptResolver(PkmnLib::Battling::BattleLibrary* mainLib) {
if (_resolverCache == nullptr) {
_resolverCache = dynamic_cast<AngelScriptResolver*>(PkmnLib::Battling::BattleLibrary::CreateScriptResolver());
_resolverCache->Initialize(mainLib);
_resolverCache->CreateScript("testScript1", _scripts["testScript1"]);
_resolverCache->FinalizeModule();
}
return _resolverCache;
}
static ScriptData GetScript(PkmnLib::Battling::BattleLibrary* mainLib, const ArbUt::StringView& funcName) {
auto lib = GetScriptResolver(mainLib);
auto s = lib->LoadScript(nullptr, ScriptCategory::Creature, "testScript1"_cnc);
auto script = dynamic_cast<AngelScriptScript*>(s);
REQUIRE(script != nullptr);
auto ctxPool = script->GetContextPool();
auto ctx = ctxPool->RequestContext();
auto func = script->PrepareMethod(funcName, ctx);
REQUIRE(func != nullptr);
return {.Script = script, .Resolver = lib, .Func = func, .Context = ctx};
}
TEST_CASE("Validate Species Name in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testName"_cnc);
auto species = mainLib->GetSpeciesLibrary()->Get("testSpecies2"_cnc);
data.Context->SetArgObject(0, (void*)species.GetRaw());
auto name = species->GetName();
data.Context->SetArgAddress(1, &name);
auto result = data.Context->Execute();
REQUIRE(result == asEXECUTION_FINISHED);
auto v = (bool)data.Context->GetReturnWord();
REQUIRE(v);
}
TEST_CASE("Validate Species Id in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testId"_cnc);
auto species = mainLib->GetSpeciesLibrary()->Get("testSpecies2"_cnc);
data.Context->SetArgObject(0, (void*)species.GetRaw());
data.Context->SetArgWord(1, species->GetId());
auto result = data.Context->Execute();
REQUIRE(result == asEXECUTION_FINISHED);
auto v = (bool)data.Context->GetReturnWord();
REQUIRE(v);
}
TEST_CASE("Validate Species Gender Rate in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testGenderRate"_cnc);
auto species = mainLib->GetSpeciesLibrary()->Get("testSpecies2"_cnc);
data.Context->SetArgObject(0, (void*)species.GetRaw());
data.Context->SetArgFloat(1, species->GetGenderRate());
auto result = data.Context->Execute();
REQUIRE(result == asEXECUTION_FINISHED);
auto v = (bool)data.Context->GetReturnDWord();
REQUIRE(v);
}
TEST_CASE("Validate Species Capture Rate in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testCaptureRate"_cnc);
auto species = mainLib->GetSpeciesLibrary()->Get("testSpecies2"_cnc);
data.Context->SetArgObject(0, (void*)species.GetRaw());
data.Context->SetArgByte(1, species->GetCaptureRate());
auto result = data.Context->Execute();
REQUIRE(result == asEXECUTION_FINISHED);
auto v = (bool)data.Context->GetReturnWord();
REQUIRE(v);
}
TEST_CASE("Validate Species Get Forme in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testGetForme"_cnc);
auto species = mainLib->GetSpeciesLibrary()->Get("testSpecies2"_cnc);
data.Context->SetArgObject(0, (void*)species.GetRaw());
data.Context->SetArgObject(1, (void*)species->GetForme("default"_cnc).GetRaw());
auto result = data.Context->Execute();
if (result == asEXECUTION_EXCEPTION) {
FAIL(data.Context->GetExceptionString());
}
REQUIRE(result == asEXECUTION_FINISHED);
auto v = (bool)data.Context->GetReturnWord();
REQUIRE(v);
}
TEST_CASE("Validate Species Get Default Forme in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testGetDefaultForme"_cnc);
auto species = mainLib->GetSpeciesLibrary()->Get("testSpecies2"_cnc);
data.Context->SetArgObject(0, (void*)species.GetRaw());
data.Context->SetArgObject(1, (void*)species->GetDefaultForme().GetRaw());
auto result = data.Context->Execute();
REQUIRE(result == asEXECUTION_FINISHED);
auto v = (bool)data.Context->GetReturnWord();
REQUIRE(v);
}
#endif

View File

@@ -0,0 +1,151 @@
#if TESTS_BUILD and ANGELSCRIPT
#include <doctest.h>
#include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp"
#include "../../../../src/ScriptResolving/AngelScript/ContextPool.hpp"
#include "../../../TestLibrary/TestLibrary.hpp"
static std::unordered_map<const char*, const char*> _scripts =
std::unordered_map<const char*, const char*>{{"testScript1", R"(
namespace Pokemon{
[Pokemon effect=testScript1]
class testScript1 : PkmnScript {
bool testMaximumLevel(const StaticLibrary@ s, uint8 level){ return s.Settings.MaximalLevel == level; }
bool testMaximumMoves(const StaticLibrary@ s, uint8 moveCount){ return s.Settings.MaximalMoves == moveCount; }
bool testSpeciesLibrary(const StaticLibrary@ s, const SpeciesLibrary@ speciesLib){ return s.SpeciesLibrary is speciesLib; }
bool testMoveLibrary(const StaticLibrary@ s, const MoveLibrary@ moveLib){ return s.MoveLibrary is moveLib; }
bool testItemLibrary(const StaticLibrary@ s, const ItemLibrary@ itemLib){ return s.ItemLibrary is itemLib; }
bool testGrowthRateLibrary(const StaticLibrary@ s, const GrowthRateLibrary@ gl){ return s.GrowthRateLibrary is gl; }
bool testTypeLibrary(const StaticLibrary@ s, const TypeLibrary@ tl){ return s.TypeLibrary is tl; }
}}
)"}};
struct ScriptData {
AngelScriptScript* Script;
AngelScriptResolver* Resolver;
asIScriptFunction* Func;
asIScriptContext* Context;
~ScriptData() {
Script->GetContextPool()->ReturnContextToPool(Context);
delete Script;
}
};
static AngelScriptResolver* _resolverCache = nullptr;
static AngelScriptResolver* GetScriptResolver(PkmnLib::Battling::BattleLibrary* mainLib) {
if (_resolverCache == nullptr) {
_resolverCache = dynamic_cast<AngelScriptResolver*>(PkmnLib::Battling::BattleLibrary::CreateScriptResolver());
_resolverCache->Initialize(mainLib);
_resolverCache->CreateScript("testScript1", _scripts["testScript1"]);
_resolverCache->FinalizeModule();
}
return _resolverCache;
}
static ScriptData GetScript(PkmnLib::Battling::BattleLibrary* mainLib, const ArbUt::StringView& funcName) {
auto lib = GetScriptResolver(mainLib);
auto s = lib->LoadScript(nullptr, ScriptCategory::Creature, "testScript1"_cnc);
auto script = dynamic_cast<AngelScriptScript*>(s);
REQUIRE(script != nullptr);
auto ctxPool = script->GetContextPool();
auto ctx = ctxPool->RequestContext();
auto func = script->PrepareMethod(funcName, ctx);
REQUIRE(func != nullptr);
return {.Script = script, .Resolver = lib, .Func = func, .Context = ctx};
}
TEST_CASE("Validate StaticLibrary Maximum Level in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testMaximumLevel"_cnc);
data.Context->SetArgObject(0, (void*)mainLib->GetStaticLib().get());
data.Context->SetArgByte(1, mainLib->GetStaticLib()->GetSettings()->GetMaximalLevel());
auto result = data.Context->Execute();
REQUIRE(result == asEXECUTION_FINISHED);
auto v = (bool)data.Context->GetReturnWord();
REQUIRE(v);
}
TEST_CASE("Validate StaticLibrary Maximum Moves in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testMaximumMoves"_cnc);
data.Context->SetArgObject(0, (void*)mainLib->GetStaticLib().get());
data.Context->SetArgByte(1, mainLib->GetStaticLib()->GetSettings()->GetMaximalAttacks());
auto result = data.Context->Execute();
REQUIRE(result == asEXECUTION_FINISHED);
auto v = (bool)data.Context->GetReturnWord();
REQUIRE(v);
}
TEST_CASE("Validate StaticLibrary Species Library in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testSpeciesLibrary"_cnc);
data.Context->SetArgObject(0, (void*)mainLib->GetStaticLib().get());
data.Context->SetArgObject(1, (void*)mainLib->GetStaticLib()->GetSpeciesLibrary().get());
auto result = data.Context->Execute();
REQUIRE(result == asEXECUTION_FINISHED);
auto v = (bool)data.Context->GetReturnWord();
REQUIRE(v);
}
TEST_CASE("Validate StaticLibrary Move Library in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testMoveLibrary"_cnc);
data.Context->SetArgObject(0, (void*)mainLib->GetStaticLib().get());
data.Context->SetArgObject(1, (void*)mainLib->GetStaticLib()->GetMoveLibrary().get());
auto result = data.Context->Execute();
REQUIRE(result == asEXECUTION_FINISHED);
auto v = (bool)data.Context->GetReturnWord();
REQUIRE(v);
}
TEST_CASE("Validate StaticLibrary Item Library in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testItemLibrary"_cnc);
data.Context->SetArgObject(0, (void*)mainLib->GetStaticLib().get());
data.Context->SetArgObject(1, (void*)mainLib->GetStaticLib()->GetItemLibrary().get());
auto result = data.Context->Execute();
REQUIRE(result == asEXECUTION_FINISHED);
auto v = (bool)data.Context->GetReturnWord();
REQUIRE(v);
}
TEST_CASE("Validate StaticLibrary Growth Rate Library in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testGrowthRateLibrary"_cnc);
data.Context->SetArgObject(0, (void*)mainLib->GetStaticLib().get());
data.Context->SetArgObject(1, (void*)mainLib->GetStaticLib()->GetGrowthRates().get());
auto result = data.Context->Execute();
REQUIRE(result == asEXECUTION_FINISHED);
auto v = (bool)data.Context->GetReturnWord();
REQUIRE(v);
}
TEST_CASE("Validate StaticLibrary Type Library in Script") {
auto mainLib = TestLibrary::GetLibrary();
auto data = GetScript(mainLib, "testTypeLibrary"_cnc);
data.Context->SetArgObject(0, (void*)mainLib->GetStaticLib().get());
data.Context->SetArgObject(1, (void*)mainLib->GetStaticLib()->GetTypeLibrary().get());
auto result = data.Context->Execute();
REQUIRE(result == asEXECUTION_FINISHED);
auto v = (bool)data.Context->GetReturnWord();
REQUIRE(v);
}
#endif