Skip to content

Commit

Permalink
t Add unit testing to Godot using DocTest and added to GitHub Actions CI
Browse files Browse the repository at this point in the history
Implements exit codes into the engine so tests can return their statuses.
Ideally we don't do this, and we use FIXUP logic to 'begin' and 'end' the engine execution for tests specifically.

Since realistically we're initialising the engine here we don't want to do that, since String should not require an engine startup to test a single header.

This lowers the complexity of running the unit tests and even for
physics should be possible to implement such a fix.
  • Loading branch information
RevoluPowered committed Jul 24, 2020
1 parent 93b50a6 commit 5793428
Show file tree
Hide file tree
Showing 24 changed files with 7,422 additions and 1,402 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/linux_builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ jobs:
run: |
scons -j2 verbose=yes warnings=all werror=yes platform=linuxbsd tools=yes target=release_debug module_mono_enabled=yes mono_glue=no
# Execute unit tests for the editor
- name: Unit Tests
run: |
./bin/godot.linuxbsd.opt.tools.64.mono --test
linux-template:
runs-on: "ubuntu-20.04"
name: Template w/ Mono (target=release, tools=no)
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/macos_builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ jobs:
run: |
scons -j2 verbose=yes warnings=all werror=yes platform=osx tools=yes target=release_debug
# Execute unit tests for the editor
- name: Unit Tests
run: |
./bin/godot.osx.opt.tools.64 --test
macos-template:
runs-on: "macos-latest"
name: Template (target=release, tools=no)
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/windows_builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ jobs:
run: |
scons -j2 verbose=yes warnings=all werror=yes platform=windows tools=yes target=release_debug
# Execute unit tests for the editor
- name: Unit Tests
run: |
./bin/godot.windows.opt.tools.64.exe --test
# Build Product Upload (tested and working)
# sorry this is disabled until github can give us some more space as we would hit our limit very quickly
# tested this code and it works fine so just enable it to get them back
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ doc/_build/
# CLion
cmake-build-debug

# clangd
.clangd/

# Android specific
.gradle
local.properties
*.iml
.idea
.gradletasknamecache
project.properties
platform/android/java/lib/.cxx/
Expand Down
5 changes: 5 additions & 0 deletions COPYRIGHT.txt
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ Copyright: 2018, Eric Lasota
2018, Microsoft Corp.
License: Expat

Files: ./thirdparty/doctest/
Comment: doctest
Copyright: 2016-2019, Viktor Kirilov
License: Expat

Files: ./thirdparty/enet/
Comment: ENet
Copyright: 2002-2020, Lee Salzman
Expand Down
3 changes: 3 additions & 0 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,9 @@ if selected_platform in platform_list:
}
)

# enable test framework globally and inform it of configuration method
env.Append(CPPDEFINES=["DOCTEST_CONFIG_IMPLEMENT"])

scons_cache_path = os.environ.get("SCONS_CACHE")
if scons_cache_path != None:
CacheDir(scons_cache_path)
Expand Down
4 changes: 3 additions & 1 deletion core/string_name.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
#include "core/safe_refcount.h"
#include "core/ustring.h"

class Main;

struct StaticCString {
const char *ptr;
static StaticCString create(const char *p_ptr);
Expand Down Expand Up @@ -73,7 +75,7 @@ class StringName {
void unref();
friend void register_core_types();
friend void unregister_core_types();

friend class Main;
static Mutex mutex;
static void setup();
static void cleanup();
Expand Down
1 change: 0 additions & 1 deletion main/SCsub
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ env.main_sources = []

env.add_source_files(env.main_sources, "*.cpp")


env.Depends("#main/splash.gen.h", "#main/splash.png")
env.CommandNoCache("#main/splash.gen.h", "#main/splash.png", run_in_subprocess(main_builders.make_splash))

Expand Down
395 changes: 281 additions & 114 deletions main/main.cpp

Large diffs are not rendered by default.

17 changes: 16 additions & 1 deletion main/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class Main {

public:
static bool is_project_manager();

static int test_entrypoint(int argc, char *argv[], bool &tests_need_run);
static Error setup(const char *execpath, int argc, char *argv[], bool p_second_phase = true);
static Error setup2(Thread::ID p_main_tid_override = 0);
static bool start();
Expand All @@ -58,4 +58,19 @@ class Main {
static void cleanup();
};

// Test main override is for the testing behaviour
#define TEST_MAIN_OVERRIDE \
bool run_test = false; \
int return_code = Main::test_entrypoint(argc, argv, run_test); \
if (run_test) { \
return return_code; \
}

#define TEST_MAIN_PARAM_OVERRIDE(argc, argv) \
bool run_test = false; \
int return_code = Main::test_entrypoint(argc, argv, run_test); \
if (run_test) { \
return return_code; \
}

#endif // MAIN_H
111 changes: 39 additions & 72 deletions main/tests/test_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,14 @@
#include "test_render.h"
#include "test_shader_lang.h"
#include "test_string.h"
#include "test_validate_testing.h"

#include "thirdparty/doctest/doctest.h"

const char **tests_get_names() {
static const char *test_names[] = {
"string",
"*",
"all",
"math",
"basis",
"physics_2d",
Expand All @@ -72,75 +76,38 @@ const char **tests_get_names() {
return test_names;
}

MainLoop *test_main(String p_test, const List<String> &p_args) {
if (p_test == "string") {
return TestString::test();
}

if (p_test == "math") {
return TestMath::test();
}

if (p_test == "basis") {
return TestBasis::test();
}

if (p_test == "physics_2d") {
return TestPhysics2D::test();
}

if (p_test == "physics_3d") {
return TestPhysics3D::test();
}

if (p_test == "render") {
return TestRender::test();
}

if (p_test == "oa_hash_map") {
return TestOAHashMap::test();
}

if (p_test == "class_db") {
return TestClassDB::test();
}

#ifndef _3D_DISABLED
if (p_test == "gui") {
return TestGUI::test();
}
#endif

if (p_test == "shaderlang") {
return TestShaderLang::test();
}

if (p_test == "gd_tokenizer") {
return TestGDScript::test(TestGDScript::TEST_TOKENIZER);
}

if (p_test == "gd_parser") {
return TestGDScript::test(TestGDScript::TEST_PARSER);
}

if (p_test == "gd_compiler") {
return TestGDScript::test(TestGDScript::TEST_COMPILER);
}

if (p_test == "gd_bytecode") {
return TestGDScript::test(TestGDScript::TEST_BYTECODE);
}

if (p_test == "ordered_hash_map") {
return TestOrderedHashMap::test();
}

if (p_test == "astar") {
return TestAStar::test();
}

print_line("Unknown test: " + p_test);
return nullptr;
int test_main(int argc, char *argv[]) {
// doctest runner for when legacy unit tests are no found
doctest::Context test_context;
List<String> valid_arguments;

// clean arguments of --test from the args
int argument_count = 0;
for (int x = 0; x < argc; x++) {
if (strncmp(argv[x], "--test", 6) != 0) {
valid_arguments.push_back(String(argv[x]));
argument_count++;
}
}

// convert godot command line arguments back to standard arguments.
char **args = new char *[valid_arguments.size()];
for (int x = 0; x < valid_arguments.size(); x++) {
// operation to convert godot string to non wchar string
const char *str = valid_arguments[x].utf8().ptr();
// allocate the string copy
args[x] = new char[strlen(str) + 1];
// copy this into memory
std::memcpy(args[x], str, strlen(str) + 1);
}

test_context.applyCommandLine(valid_arguments.size(), args);

test_context.setOption("order-by", "name");
test_context.setOption("abort-after", 5);
test_context.setOption("no-breaks", true);
delete[] args;
return test_context.run();
}

#else
Expand All @@ -153,8 +120,8 @@ const char **tests_get_names() {
return test_names;
}

MainLoop *test_main(String p_test, const List<String> &p_args) {
return nullptr;
int test_main(int argc, char *argv[]) {
return 0;
}

#endif
2 changes: 1 addition & 1 deletion main/tests/test_main.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@
#include "core/ustring.h"

const char **tests_get_names();
MainLoop *test_main(String p_test, const List<String> &p_args);
int test_main(int argc, char *argv[]);

#endif // TEST_MAIN_H
Loading

0 comments on commit 5793428

Please sign in to comment.