Initial commit.

This commit is contained in:
Deukhoofd 2021-08-22 19:03:03 +02:00
commit a6013437b2
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
17 changed files with 27667 additions and 0 deletions

124
.clang-format Normal file
View File

@ -0,0 +1,124 @@
# ClangFormatConfigureSource: 'LLVM'
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Merge
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 1
- Regex: '.*'
Priority: 3
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
- Ensure
- EnsureNotNull
- Try
TabWidth: 8
UseTab: Never
...

11
.clang-tidy Normal file
View File

@ -0,0 +1,11 @@
Checks: 'readability-*,clang-diagnostic-*,clang-analyzer-*,-clang-analyzer-alpha*,performance-*,cppcoreguidelines-*,
bugprone-*,modernize-*,-modernize-use-trailing-return-type,-cppcoreguidelines-non-private-member-variables-in-classes'
HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false
CheckOptions:
- key: readability-identifier-naming.ClassCase
value: CamelCase
- key: readability-identifier-naming.PrivateMemberCase
value: camelBack
- key: readability-identifier-naming.PrivateMemberPrefix
value: '_'

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/cmake-build-debug/
/cmake-build-release/
/.idea/

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "src/BuildData"]
path = src/BuildData
url = git@ssh.p-epsilon.com:Deukhoofd/BuildData.git

21
CMakeLists.txt Normal file
View File

@ -0,0 +1,21 @@
cmake_minimum_required(VERSION 3.20)
project(PokemonScriptTester)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror")
option(WINDOWS "Whether the build target is Windows or not." OFF)
set(STATICC TRUE)
include(CMakeLists.txt.in)
include_pkmnlib()
file(GLOB_RECURSE SRC_FILES src/*.cpp src/*.hpp)
add_executable(PokemonScriptTester ${SRC_FILES})
target_precompile_headers(PokemonScriptTester PUBLIC src/Precompiled.hxx)
add_definitions(-DLEVEL_U8)
SET(_LINKS Arbutils CreatureLib pkmnLib -lpthread)
target_link_libraries(PokemonScriptTester PUBLIC ${_LINKS})
target_compile_options(PokemonScriptTester PRIVATE -Wall -Wextra -Werror)

52
CMakeLists.txt.in Normal file
View File

@ -0,0 +1,52 @@
cmake_minimum_required(VERSION 2.8.12)
project(PokemonScriptTester NONE)
include(ExternalProject)
ExternalProject_Add(pkmnlib
GIT_REPOSITORY https://git.p-epsilon.com/Deukhoofd/PkmnLib
GIT_TAG master
PREFIX "${CMAKE_CURRENT_BINARY_DIR}/PkmnLib"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
CMAKE_ARGS "-DSHARED=${SHARED} -DWINDOWS=${WINDOWS} -DSTATICC=${STATICC}"
)
function(include_pkmnlib)
# Download and unpack googletest at configure time
configure_file(CMakeLists.txt.in PkmnLib/download/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/download)
if (result)
message(FATAL_ERROR "CMake step for pkmnlib failed: ${result}")
endif ()
execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/download)
if (result)
message(FATAL_ERROR "Build step for pkmnlib failed: ${result}")
endif ()
# Add googletest directly to our build. This defines
# the gtest and gtest_main targets.
add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/src/pkmnlib
${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/bin
EXCLUDE_FROM_ALL)
execute_process(COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/include)
execute_process(COMMAND ln -s ${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/src/pkmnlib/src
${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/include/PkmnLib)
execute_process(COMMAND cp -r ${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/src/pkmnlib/extern
${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/include/PkmnLib/extern)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/include
${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/bin/CreatureLib/include
${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/bin/Angelscript/src/AngelscriptProj/angelscript/include
${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/bin/CreatureLib/bin/Arbutils/include)
endfunction()

4310
extern/args.hpp vendored Normal file

File diff suppressed because it is too large Load Diff

22875
extern/json.hpp vendored Normal file

File diff suppressed because it is too large Load Diff

1
src/BuildData Submodule

@ -0,0 +1 @@
Subproject commit 069eadf7c9f94ca4b8616dca8eb7562c9ecf26e0

6
src/Precompiled.hxx Normal file
View File

@ -0,0 +1,6 @@
#ifndef POKEMONSCRIPTTESTER_PRECOMPILED_HXX
#define POKEMONSCRIPTTESTER_PRECOMPILED_HXX
#include <PkmnLib/Precompiled.hxx>
#endif // POKEMONSCRIPTTESTER_PRECOMPILED_HXX

View File

@ -0,0 +1,48 @@
#ifndef POKEMONSCRIPTTESTER_ASSERTIONFAILED_HPP
#define POKEMONSCRIPTTESTER_ASSERTIONFAILED_HPP
#include <exception>
#include <sstream>
class AssertionFailed : public std::exception {
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));
return s;
}
static std::string GetLine(const std::string& path, size_t num) {
std::ifstream file;
file.open(path);
file.seekg(std::ios::beg);
for (size_t i = 0; i < num - 1; ++i) {
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
std::string line;
std::getline(file, line);
file.close();
line = ltrim(line);
return line;
}
char* _msg;
public:
AssertionFailed(const std::string& path, size_t line, const std::string& message = "") {
auto l = GetLine(path, line);
std::stringstream ss;
ss << "Assertion failed at: " << path << ":" << line << std::endl;
ss << l;
if (message.length() > 0) {
ss << std::endl << message;
}
auto str = ss.str();
_msg = new char[str.length() + 1];
str.copy(_msg, str.length(), 0);
_msg[str.length()] = 0;
}
~AssertionFailed() { delete[] _msg; }
const char* what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW override { return _msg; }
};
#endif // POKEMONSCRIPTTESTER_ASSERTIONFAILED_HPP

40
src/Tester/Test.hpp Normal file
View File

@ -0,0 +1,40 @@
#ifndef POKEMONSCRIPTTESTER_TEST_HPP
#define POKEMONSCRIPTTESTER_TEST_HPP
#include <angelscript.h>
#include "TestEnvironment.hpp"
#include "TestResult.hpp"
class Test {
public:
Test(const std::string name, asIScriptFunction* function)
: _name(name), _function(function), _env(new TestEnvironment()) {}
void Run(asIScriptContext* ctx) {
ctx->Prepare(_function);
ctx->SetUserData(_env);
auto e = ctx->Execute();
if (e == asEXECUTION_EXCEPTION) {
_errorMessage = ctx->GetExceptionString();
_result = TestResult::Failed;
ctx->Release();
return;
}
ctx->Release();
Ensure(e == asEXECUTION_FINISHED);
_result = TestResult::Success;
}
inline TestResult GetResult() const noexcept { return _result; }
inline const std::string& GetErrorMessage() const noexcept { return _errorMessage; }
private:
std::string _name;
asIScriptFunction* _function;
TestEnvironment* _env;
TestResult _result = TestResult::NotRan;
std::string _errorMessage = "";
};
#endif // POKEMONSCRIPTTESTER_TEST_HPP

View File

@ -0,0 +1,8 @@
#ifndef POKEMONSCRIPTTESTER_TESTENVIRONMENT_HPP
#define POKEMONSCRIPTTESTER_TESTENVIRONMENT_HPP
struct TestEnvironment{
size_t AssertionCount = 0;
};
#endif // POKEMONSCRIPTTESTER_TESTENVIRONMENT_HPP

View File

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

View File

@ -0,0 +1,6 @@
#ifndef POKEMONSCRIPTTESTER_TESTRESULT_HPP
#define POKEMONSCRIPTTESTER_TESTRESULT_HPP
ENUM(TestResult, u8, NotRan, Success, Failed)
#endif // POKEMONSCRIPTTESTER_TESTRESULT_HPP

42
src/Tester/TestRunner.hpp Normal file
View File

@ -0,0 +1,42 @@
#ifndef POKEMONSCRIPTTESTER_TESTRUNNER_HPP
#define POKEMONSCRIPTTESTER_TESTRUNNER_HPP
#include <PkmnLib/ScriptResolving/AngelScript/AngelScriptMetadata.hpp>
#include "Test.hpp"
class TestRunner {
ArbUt::Dictionary<std::string, Test> _tests;
public:
TestRunner(AngelScriptResolver* scriptResolver) {
const auto* module = scriptResolver->GetMainModule();
auto builder = scriptResolver->GetBuilder();
for (u32 i = 0; i < module->GetFunctionCount(); ++i) {
auto* func = module->GetFunctionByIndex(i);
auto metaData = builder.GetMetadataForFunc(func);
for (const auto& m : metaData) {
auto meta = AngelscriptMetadata(m);
if (meta.GetIdentifier() == "Test"_cnc) {
auto name = meta.GetParameter("name"_cnc);
_tests.Insert(name, Test(name, func));
}
}
}
}
void RunAll(asIScriptEngine* engine) {
auto ctx = engine->CreateContext();
for (auto& test : _tests) {
test.second.Run(ctx);
}
for (auto& test : _tests) {
if (test.second.GetResult() == TestResult::Failed) {
std::cout << "Test '" << test.first << "' failed with message: " << std::endl;
std::cout << test.second.GetErrorMessage() << std::endl << std::endl;
}
}
}
};
#endif // POKEMONSCRIPTTESTER_TESTRUNNER_HPP

56
src/main.cpp Normal file
View File

@ -0,0 +1,56 @@
#include <PkmnLib/ScriptResolving/AngelScript/AngelScriptResolver.hpp>
#include <filesystem>
#include <iostream>
#include "../extern/args.hpp"
#include "BuildData/BuildLibrary.hpp"
#include "Tester/TestFunctions.hpp"
#include "Tester/TestRunner.hpp"
int main(int argc, char** argv) {
args::ArgumentParser parser("PkmnLib Script Tester.", "");
args::HelpFlag help(parser, "help", "Display this help menu", {'h', "help"});
std::string workingDirectory;
args::HelpFlag helpFlag(parser, "help", "Display this help menu", {'h', "help"});
args::ValueFlag<std::string> workingDirFlag(parser, "Working Directory", "Which work directory to use.",
{"workdir"});
try {
parser.ParseCLI(argc, argv);
} catch (args::Help&) {
std::cout << parser;
return 0;
} catch (args::ParseError& e) {
std::cerr << e.what() << std::endl;
std::cerr << parser;
return 1;
} catch (args::ValidationError& e) {
std::cerr << e.what() << std::endl;
std::cerr << parser;
return 1;
}
if (workingDirFlag) {
workingDirectory = args::get(workingDirFlag);
}
if (!workingDirectory.empty()) {
chdir(std::filesystem::path(workingDirectory).c_str());
}
std::function<void(PkmnLib::Battling::ScriptResolver*)> initialize =
[](PkmnLib::Battling::ScriptResolver* resolver) {
auto* scriptResolver = dynamic_cast<AngelScriptResolver*>(resolver);
scriptResolver->DefineWord("TEST");
TestFunctions::Register(scriptResolver);
};
auto battleLib = ArbUt::OptionalScopedPtr(BuildLibrary::Build("", initialize));
if (!battleLib.HasValue()) {
return 1;
}
auto* scriptResolver = dynamic_cast<AngelScriptResolver*>(battleLib.GetValue()->GetScriptResolver().get());
auto testRunner = TestRunner(scriptResolver);
auto engine = scriptResolver->GetBuilder().GetEngine();
testRunner.RunAll(engine);
return 0;
}