t Add unit testing to Godot using DocTest and added to GitHub Actions CI
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.
This commit is contained in:
parent
93b50a62e3
commit
579342810f
24 changed files with 7417 additions and 1397 deletions
5
.github/workflows/linux_builds.yml
vendored
5
.github/workflows/linux_builds.yml
vendored
|
@ -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)
|
||||
|
|
5
.github/workflows/macos_builds.yml
vendored
5
.github/workflows/macos_builds.yml
vendored
|
@ -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)
|
||||
|
|
5
.github/workflows/windows_builds.yml
vendored
5
.github/workflows/windows_builds.yml
vendored
|
@ -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
|
||||
|
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -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/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
@ -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();
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
395
main/main.cpp
395
main/main.cpp
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "main.h"
|
||||
|
||||
#include "core/core_string_names.h"
|
||||
#include "core/crypto/crypto.h"
|
||||
#include "core/debugger/engine_debugger.h"
|
||||
#include "core/input/input.h"
|
||||
|
@ -75,12 +76,14 @@
|
|||
#include "servers/xr_server.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
#include "editor/doc_data.h"
|
||||
#include "editor/doc_data_class_path.gen.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_settings.h"
|
||||
#include "editor/progress_dialog.h"
|
||||
#include "editor/project_manager.h"
|
||||
|
||||
#endif
|
||||
|
||||
/* Static members */
|
||||
|
@ -186,7 +189,8 @@ static String get_full_version_string() {
|
|||
// to have less code in main.cpp.
|
||||
void initialize_physics() {
|
||||
/// 3D Physics Server
|
||||
physics_server = PhysicsServer3DManager::new_server(ProjectSettings::get_singleton()->get(PhysicsServer3DManager::setting_property_name));
|
||||
physics_server = PhysicsServer3DManager::new_server(
|
||||
ProjectSettings::get_singleton()->get(PhysicsServer3DManager::setting_property_name));
|
||||
if (!physics_server) {
|
||||
// Physics server not found, Use the default physics
|
||||
physics_server = PhysicsServer3DManager::new_default_server();
|
||||
|
@ -195,7 +199,8 @@ void initialize_physics() {
|
|||
physics_server->init();
|
||||
|
||||
/// 2D Physics server
|
||||
physics_2d_server = PhysicsServer2DManager::new_server(ProjectSettings::get_singleton()->get(PhysicsServer2DManager::setting_property_name));
|
||||
physics_2d_server = PhysicsServer2DManager::new_server(
|
||||
ProjectSettings::get_singleton()->get(PhysicsServer2DManager::setting_property_name));
|
||||
if (!physics_2d_server) {
|
||||
// Physics server not found, Use the default physics
|
||||
physics_2d_server = PhysicsServer2DManager::new_default_server();
|
||||
|
@ -254,20 +259,25 @@ void Main::print_help(const char *p_binary) {
|
|||
OS::get_singleton()->print(" -h, --help Display this help message.\n");
|
||||
OS::get_singleton()->print(" --version Display the version string.\n");
|
||||
OS::get_singleton()->print(" -v, --verbose Use verbose stdout mode.\n");
|
||||
OS::get_singleton()->print(" --quiet Quiet mode, silences stdout messages. Errors are still displayed.\n");
|
||||
OS::get_singleton()->print(
|
||||
" --quiet Quiet mode, silences stdout messages. Errors are still displayed.\n");
|
||||
OS::get_singleton()->print("\n");
|
||||
|
||||
OS::get_singleton()->print("Run options:\n");
|
||||
#ifdef TOOLS_ENABLED
|
||||
OS::get_singleton()->print(" -e, --editor Start the editor instead of running the scene.\n");
|
||||
OS::get_singleton()->print(" -p, --project-manager Start the project manager, even if a project is auto-detected.\n");
|
||||
OS::get_singleton()->print(
|
||||
" -p, --project-manager Start the project manager, even if a project is auto-detected.\n");
|
||||
#endif
|
||||
OS::get_singleton()->print(" -q, --quit Quit after the first iteration.\n");
|
||||
OS::get_singleton()->print(" -l, --language <locale> Use a specific locale (<locale> being a two-letter code).\n");
|
||||
OS::get_singleton()->print(" --path <directory> Path to a project (<directory> must contain a 'project.godot' file).\n");
|
||||
OS::get_singleton()->print(
|
||||
" -l, --language <locale> Use a specific locale (<locale> being a two-letter code).\n");
|
||||
OS::get_singleton()->print(
|
||||
" --path <directory> Path to a project (<directory> must contain a 'project.godot' file).\n");
|
||||
OS::get_singleton()->print(" -u, --upwards Scan folders upwards for project.godot file.\n");
|
||||
OS::get_singleton()->print(" --main-pack <file> Path to a pack (.pck) file to load.\n");
|
||||
OS::get_singleton()->print(" --render-thread <mode> Render thread mode ('unsafe', 'safe', 'separate').\n");
|
||||
OS::get_singleton()->print(
|
||||
" --render-thread <mode> Render thread mode ('unsafe', 'safe', 'separate').\n");
|
||||
OS::get_singleton()->print(" --remote-fs <address> Remote filesystem (<host/IP>[:<port>] address).\n");
|
||||
OS::get_singleton()->print(" --remote-fs-password <password> Password for remote filesystem.\n");
|
||||
|
||||
|
@ -308,9 +318,12 @@ void Main::print_help(const char *p_binary) {
|
|||
OS::get_singleton()->print(" --resolution <W>x<H> Request window resolution.\n");
|
||||
OS::get_singleton()->print(" --position <X>,<Y> Request window position.\n");
|
||||
OS::get_singleton()->print(" --low-dpi Force low-DPI mode (macOS and Windows only).\n");
|
||||
OS::get_singleton()->print(" --no-window Disable window creation (Windows only). Useful together with --script.\n");
|
||||
OS::get_singleton()->print(" --enable-vsync-via-compositor When vsync is enabled, vsync via the OS' window compositor (Windows only).\n");
|
||||
OS::get_singleton()->print(" --disable-vsync-via-compositor Disable vsync via the OS' window compositor (Windows only).\n");
|
||||
OS::get_singleton()->print(
|
||||
" --no-window Disable window creation (Windows only). Useful together with --script.\n");
|
||||
OS::get_singleton()->print(
|
||||
" --enable-vsync-via-compositor When vsync is enabled, vsync via the OS' window compositor (Windows only).\n");
|
||||
OS::get_singleton()->print(
|
||||
" --disable-vsync-via-compositor Disable vsync via the OS' window compositor (Windows only).\n");
|
||||
OS::get_singleton()->print(" --single-window Use a single window (no separate subwindows).\n");
|
||||
OS::get_singleton()->print(" --tablet-driver Tablet input driver (");
|
||||
for (int i = 0; i < OS::get_singleton()->get_tablet_driver_count(); i++) {
|
||||
|
@ -324,35 +337,51 @@ void Main::print_help(const char *p_binary) {
|
|||
|
||||
OS::get_singleton()->print("Debug options:\n");
|
||||
OS::get_singleton()->print(" -d, --debug Debug (local stdout debugger).\n");
|
||||
OS::get_singleton()->print(" -b, --breakpoints Breakpoint list as source::line comma-separated pairs, no spaces (use %%20 instead).\n");
|
||||
OS::get_singleton()->print(
|
||||
" -b, --breakpoints Breakpoint list as source::line comma-separated pairs, no spaces (use %%20 instead).\n");
|
||||
OS::get_singleton()->print(" --profiling Enable profiling in the script debugger.\n");
|
||||
OS::get_singleton()->print(" --gpu-abort Abort on GPU errors (usually validation layer errors), may help see the problem if your system freezes.\n");
|
||||
OS::get_singleton()->print(" --remote-debug <uri> Remote debug (<protocol>://<host/IP>[:<port>], e.g. tcp://127.0.0.1:6007).\n");
|
||||
OS::get_singleton()->print(
|
||||
" --gpu-abort Abort on GPU errors (usually validation layer errors), may help see the problem if your system freezes.\n");
|
||||
OS::get_singleton()->print(
|
||||
" --remote-debug <uri> Remote debug (<protocol>://<host/IP>[:<port>], e.g. tcp://127.0.0.1:6007).\n");
|
||||
#if defined(DEBUG_ENABLED) && !defined(SERVER_ENABLED)
|
||||
OS::get_singleton()->print(" --debug-collisions Show collision shapes when running the scene.\n");
|
||||
OS::get_singleton()->print(" --debug-navigation Show navigation polygons when running the scene.\n");
|
||||
#endif
|
||||
OS::get_singleton()->print(" --frame-delay <ms> Simulate high CPU load (delay each frame by <ms> milliseconds).\n");
|
||||
OS::get_singleton()->print(" --time-scale <scale> Force time scale (higher values are faster, 1.0 is normal speed).\n");
|
||||
OS::get_singleton()->print(" --disable-render-loop Disable render loop so rendering only occurs when called explicitly from script.\n");
|
||||
OS::get_singleton()->print(" --disable-crash-handler Disable crash handler when supported by the platform code.\n");
|
||||
OS::get_singleton()->print(" --fixed-fps <fps> Force a fixed number of frames per second. This setting disables real-time synchronization.\n");
|
||||
OS::get_singleton()->print(
|
||||
" --frame-delay <ms> Simulate high CPU load (delay each frame by <ms> milliseconds).\n");
|
||||
OS::get_singleton()->print(
|
||||
" --time-scale <scale> Force time scale (higher values are faster, 1.0 is normal speed).\n");
|
||||
OS::get_singleton()->print(
|
||||
" --disable-render-loop Disable render loop so rendering only occurs when called explicitly from script.\n");
|
||||
OS::get_singleton()->print(
|
||||
" --disable-crash-handler Disable crash handler when supported by the platform code.\n");
|
||||
OS::get_singleton()->print(
|
||||
" --fixed-fps <fps> Force a fixed number of frames per second. This setting disables real-time synchronization.\n");
|
||||
OS::get_singleton()->print(" --print-fps Print the frames per second to the stdout.\n");
|
||||
OS::get_singleton()->print("\n");
|
||||
|
||||
OS::get_singleton()->print("Standalone tools:\n");
|
||||
OS::get_singleton()->print(" -s, --script <script> Run a script.\n");
|
||||
OS::get_singleton()->print(" --check-only Only parse for errors and quit (use with --script).\n");
|
||||
OS::get_singleton()->print(
|
||||
" --check-only Only parse for errors and quit (use with --script).\n");
|
||||
#ifdef TOOLS_ENABLED
|
||||
OS::get_singleton()->print(" --export <preset> <path> Export the project using the given preset and matching release template. The preset name should match one defined in export_presets.cfg.\n");
|
||||
OS::get_singleton()->print(" <path> should be absolute or relative to the project directory, and include the filename for the binary (e.g. 'builds/game.exe'). The target directory should exist.\n");
|
||||
OS::get_singleton()->print(
|
||||
" --export <preset> <path> Export the project using the given preset and matching release template. The preset name should match one defined in export_presets.cfg.\n");
|
||||
OS::get_singleton()->print(
|
||||
" <path> should be absolute or relative to the project directory, and include the filename for the binary (e.g. 'builds/game.exe'). The target directory should exist.\n");
|
||||
OS::get_singleton()->print(" --export-debug <preset> <path> Same as --export, but using the debug template.\n");
|
||||
OS::get_singleton()->print(" --export-pack <preset> <path> Same as --export, but only export the game pack for the given preset. The <path> extension determines whether it will be in PCK or ZIP format.\n");
|
||||
OS::get_singleton()->print(" --doctool <path> Dump the engine API reference to the given <path> in XML format, merging if existing files are found.\n");
|
||||
OS::get_singleton()->print(" --no-docbase Disallow dumping the base types (used with --doctool).\n");
|
||||
OS::get_singleton()->print(" --build-solutions Build the scripting solutions (e.g. for C# projects). Implies --editor and requires a valid project to edit.\n");
|
||||
OS::get_singleton()->print(
|
||||
" --export-pack <preset> <path> Same as --export, but only export the game pack for the given preset. The <path> extension determines whether it will be in PCK or ZIP format.\n");
|
||||
OS::get_singleton()->print(
|
||||
" --doctool <path> Dump the engine API reference to the given <path> in XML format, merging if existing files are found.\n");
|
||||
OS::get_singleton()->print(
|
||||
" --no-docbase Disallow dumping the base types (used with --doctool).\n");
|
||||
OS::get_singleton()->print(
|
||||
" --build-solutions Build the scripting solutions (e.g. for C# projects). Implies --editor and requires a valid project to edit.\n");
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
OS::get_singleton()->print(" --gdnative-generate-json-api Generate JSON dump of the Godot API for GDNative bindings.\n");
|
||||
OS::get_singleton()->print(
|
||||
" --gdnative-generate-json-api Generate JSON dump of the Godot API for GDNative bindings.\n");
|
||||
#endif
|
||||
OS::get_singleton()->print(" --test <test> Run a unit test [");
|
||||
const char **test_names = tests_get_names();
|
||||
|
@ -366,6 +395,23 @@ void Main::print_help(const char *p_binary) {
|
|||
#endif
|
||||
}
|
||||
|
||||
int Main::test_entrypoint(int argc, char *argv[], bool &tests_need_run) {
|
||||
#ifdef TOOLS_ENABLED // templates can't run unit test tool
|
||||
OS::get_singleton()->initialize();
|
||||
StringName::setup();
|
||||
for (int x = 0; x < argc; x++) {
|
||||
if (strncmp(argv[x], "--test", 6)) {
|
||||
tests_need_run = true;
|
||||
return test_main(argc, argv);
|
||||
}
|
||||
}
|
||||
StringName::cleanup();
|
||||
OS::get_singleton()->finalize();
|
||||
#endif
|
||||
tests_need_run = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Engine initialization
|
||||
*
|
||||
* Consists of several methods that are called by each platform's specific main(argc, argv).
|
||||
|
@ -418,7 +464,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
ClassDB::register_class<Performance>();
|
||||
engine->add_singleton(Engine::Singleton("Performance", performance));
|
||||
|
||||
GLOBAL_DEF("debug/settings/crash_handler/message", String("Please include this when reporting the bug on https://github.com/godotengine/godot/issues"));
|
||||
GLOBAL_DEF("debug/settings/crash_handler/message",
|
||||
String("Please include this when reporting the bug on https://github.com/godotengine/godot/issues"));
|
||||
|
||||
MAIN_PRINT("Main: Parse CMDLine");
|
||||
|
||||
|
@ -523,7 +570,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
}
|
||||
|
||||
if (!found) {
|
||||
OS::get_singleton()->print("Unknown audio driver '%s', aborting.\nValid options are ", audio_driver.utf8().get_data());
|
||||
OS::get_singleton()->print("Unknown audio driver '%s', aborting.\nValid options are ",
|
||||
audio_driver.utf8().get_data());
|
||||
|
||||
for (int i = 0; i < AudioDriverManager::get_driver_count(); i++) {
|
||||
if (i == AudioDriverManager::get_driver_count() - 1) {
|
||||
|
@ -559,7 +607,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
}
|
||||
|
||||
if (!found) {
|
||||
OS::get_singleton()->print("Unknown display driver '%s', aborting.\nValid options are ", display_driver.utf8().get_data());
|
||||
OS::get_singleton()->print("Unknown display driver '%s', aborting.\nValid options are ",
|
||||
display_driver.utf8().get_data());
|
||||
|
||||
for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
|
||||
if (i == DisplayServer::get_create_function_count() - 1) {
|
||||
|
@ -607,7 +656,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
}
|
||||
|
||||
if (!found) {
|
||||
OS::get_singleton()->print("Unknown tablet driver '%s', aborting.\n", tablet_driver.utf8().get_data());
|
||||
OS::get_singleton()->print("Unknown tablet driver '%s', aborting.\n",
|
||||
tablet_driver.utf8().get_data());
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -629,7 +679,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
|
||||
if (vm.find("x") == -1) { // invalid parameter format
|
||||
|
||||
OS::get_singleton()->print("Invalid resolution '%s', it should be e.g. '1280x720'.\n", vm.utf8().get_data());
|
||||
OS::get_singleton()->print("Invalid resolution '%s', it should be e.g. '1280x720'.\n",
|
||||
vm.utf8().get_data());
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -637,7 +688,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
int h = vm.get_slice("x", 1).to_int();
|
||||
|
||||
if (w <= 0 || h <= 0) {
|
||||
OS::get_singleton()->print("Invalid resolution '%s', width and height must be above 0.\n", vm.utf8().get_data());
|
||||
OS::get_singleton()->print("Invalid resolution '%s', width and height must be above 0.\n",
|
||||
vm.utf8().get_data());
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -658,7 +710,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
|
||||
if (vm.find(",") == -1) { // invalid parameter format
|
||||
|
||||
OS::get_singleton()->print("Invalid position '%s', it should be e.g. '80,128'.\n", vm.utf8().get_data());
|
||||
OS::get_singleton()->print("Invalid position '%s', it should be e.g. '80,128'.\n",
|
||||
vm.utf8().get_data());
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -754,7 +807,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
// We still pass it to the main arguments since the argument handling itself is not done in this function
|
||||
main_args.push_back(I->get());
|
||||
#endif
|
||||
} else if (I->get() == "--export" || I->get() == "--export-debug" || I->get() == "--export-pack") { // Export project
|
||||
} else if (I->get() == "--export" || I->get() == "--export-debug" ||
|
||||
I->get() == "--export-pack") { // Export project
|
||||
|
||||
editor = true;
|
||||
main_args.push_back(I->get());
|
||||
|
@ -847,7 +901,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
if (I->next()) {
|
||||
debug_uri = I->next()->get();
|
||||
if (debug_uri.find("://") == -1) { // wrong address
|
||||
OS::get_singleton()->print("Invalid debug host address, it should be of the form <protocol>://<host/IP>:<port>.\n");
|
||||
OS::get_singleton()->print(
|
||||
"Invalid debug host address, it should be of the form <protocol>://<host/IP>:<port>.\n");
|
||||
goto error;
|
||||
}
|
||||
N = I->next()->next();
|
||||
|
@ -888,7 +943,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (editor && project_manager) {
|
||||
OS::get_singleton()->print("Error: Command line arguments implied opening both editor and project manager, which is not possible. Aborting.\n");
|
||||
OS::get_singleton()->print(
|
||||
"Error: Command line arguments implied opening both editor and project manager, which is not possible. Aborting.\n");
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
|
@ -935,15 +991,35 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
OS::get_singleton()->ensure_user_data_dir();
|
||||
|
||||
GLOBAL_DEF("memory/limits/multithreaded_server/rid_pool_prealloc", 60);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("memory/limits/multithreaded_server/rid_pool_prealloc", PropertyInfo(Variant::INT, "memory/limits/multithreaded_server/rid_pool_prealloc", PROPERTY_HINT_RANGE, "0,500,1")); // No negative and limit to 500 due to crashes
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("memory/limits/multithreaded_server/rid_pool_prealloc",
|
||||
PropertyInfo(Variant::INT,
|
||||
"memory/limits/multithreaded_server/rid_pool_prealloc",
|
||||
PROPERTY_HINT_RANGE,
|
||||
"0,500,1")); // No negative and limit to 500 due to crashes
|
||||
GLOBAL_DEF("network/limits/debugger/max_chars_per_second", 32768);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("network/limits/debugger/max_chars_per_second", PropertyInfo(Variant::INT, "network/limits/debugger/max_chars_per_second", PROPERTY_HINT_RANGE, "0, 4096, 1, or_greater"));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("network/limits/debugger/max_chars_per_second",
|
||||
PropertyInfo(Variant::INT,
|
||||
"network/limits/debugger/max_chars_per_second",
|
||||
PROPERTY_HINT_RANGE,
|
||||
"0, 4096, 1, or_greater"));
|
||||
GLOBAL_DEF("network/limits/debugger/max_queued_messages", 2048);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("network/limits/debugger/max_queued_messages", PropertyInfo(Variant::INT, "network/limits/debugger/max_queued_messages", PROPERTY_HINT_RANGE, "0, 8192, 1, or_greater"));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("network/limits/debugger/max_queued_messages",
|
||||
PropertyInfo(Variant::INT,
|
||||
"network/limits/debugger/max_queued_messages",
|
||||
PROPERTY_HINT_RANGE,
|
||||
"0, 8192, 1, or_greater"));
|
||||
GLOBAL_DEF("network/limits/debugger/max_errors_per_second", 400);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("network/limits/debugger/max_errors_per_second", PropertyInfo(Variant::INT, "network/limits/debugger/max_errors_per_second", PROPERTY_HINT_RANGE, "0, 200, 1, or_greater"));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("network/limits/debugger/max_errors_per_second",
|
||||
PropertyInfo(Variant::INT,
|
||||
"network/limits/debugger/max_errors_per_second",
|
||||
PROPERTY_HINT_RANGE,
|
||||
"0, 200, 1, or_greater"));
|
||||
GLOBAL_DEF("network/limits/debugger/max_warnings_per_second", 400);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("network/limits/debugger/max_warnings_per_second", PropertyInfo(Variant::INT, "network/limits/debugger/max_warnings_per_second", PROPERTY_HINT_RANGE, "0, 200, 1, or_greater"));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("network/limits/debugger/max_warnings_per_second",
|
||||
PropertyInfo(Variant::INT,
|
||||
"network/limits/debugger/max_warnings_per_second",
|
||||
PROPERTY_HINT_RANGE,
|
||||
"0, 200, 1, or_greater"));
|
||||
|
||||
EngineDebugger::initialize(debug_uri, skip_breakpoints, breakpoints);
|
||||
|
||||
|
@ -978,8 +1054,13 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
GLOBAL_DEF("logging/file_logging/enable_file_logging.pc", true);
|
||||
GLOBAL_DEF("logging/file_logging/log_path", "user://logs/godot.log");
|
||||
GLOBAL_DEF("logging/file_logging/max_log_files", 5);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("logging/file_logging/max_log_files", PropertyInfo(Variant::INT, "logging/file_logging/max_log_files", PROPERTY_HINT_RANGE, "0,20,1,or_greater")); //no negative numbers
|
||||
if (!project_manager && !editor && FileAccess::get_create_func(FileAccess::ACCESS_USERDATA) && GLOBAL_GET("logging/file_logging/enable_file_logging")) {
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("logging/file_logging/max_log_files",
|
||||
PropertyInfo(Variant::INT,
|
||||
"logging/file_logging/max_log_files",
|
||||
PROPERTY_HINT_RANGE,
|
||||
"0,20,1,or_greater")); //no negative numbers
|
||||
if (!project_manager && !editor && FileAccess::get_create_func(FileAccess::ACCESS_USERDATA) &&
|
||||
GLOBAL_GET("logging/file_logging/enable_file_logging")) {
|
||||
// Don't create logs for the project manager as they would be written to
|
||||
// the current working directory, which is inconvenient.
|
||||
String base_path = GLOBAL_GET("logging/file_logging/log_path");
|
||||
|
@ -1020,7 +1101,10 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
OS::get_singleton()->set_cmdline(execpath, main_args);
|
||||
|
||||
GLOBAL_DEF("rendering/quality/driver/driver_name", "Vulkan");
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/driver/driver_name", PropertyInfo(Variant::STRING, "rendering/quality/driver/driver_name", PROPERTY_HINT_ENUM, "Vulkan,GLES2"));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/driver/driver_name",
|
||||
PropertyInfo(Variant::STRING,
|
||||
"rendering/quality/driver/driver_name",
|
||||
PROPERTY_HINT_ENUM, "Vulkan,GLES2"));
|
||||
if (display_driver == "") {
|
||||
display_driver = GLOBAL_GET("rendering/quality/driver/driver_name");
|
||||
}
|
||||
|
@ -1029,24 +1113,39 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
GLOBAL_DEF("rendering/quality/2d/gles2_use_nvidia_rect_flicker_workaround", false);
|
||||
|
||||
GLOBAL_DEF("display/window/size/width", 1024);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/width", PropertyInfo(Variant::INT, "display/window/size/width", PROPERTY_HINT_RANGE, "0,7680,or_greater")); // 8K resolution
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/width",
|
||||
PropertyInfo(Variant::INT, "display/window/size/width",
|
||||
PROPERTY_HINT_RANGE,
|
||||
"0,7680,or_greater")); // 8K resolution
|
||||
GLOBAL_DEF("display/window/size/height", 600);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/height", PropertyInfo(Variant::INT, "display/window/size/height", PROPERTY_HINT_RANGE, "0,4320,or_greater")); // 8K resolution
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/height",
|
||||
PropertyInfo(Variant::INT, "display/window/size/height",
|
||||
PROPERTY_HINT_RANGE,
|
||||
"0,4320,or_greater")); // 8K resolution
|
||||
GLOBAL_DEF("display/window/size/resizable", true);
|
||||
GLOBAL_DEF("display/window/size/borderless", false);
|
||||
GLOBAL_DEF("display/window/size/fullscreen", false);
|
||||
GLOBAL_DEF("display/window/size/always_on_top", false);
|
||||
GLOBAL_DEF("display/window/size/test_width", 0);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/test_width", PropertyInfo(Variant::INT, "display/window/size/test_width", PROPERTY_HINT_RANGE, "0,7680,or_greater")); // 8K resolution
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/test_width",
|
||||
PropertyInfo(Variant::INT,
|
||||
"display/window/size/test_width",
|
||||
PROPERTY_HINT_RANGE,
|
||||
"0,7680,or_greater")); // 8K resolution
|
||||
GLOBAL_DEF("display/window/size/test_height", 0);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/test_height", PropertyInfo(Variant::INT, "display/window/size/test_height", PROPERTY_HINT_RANGE, "0,4320,or_greater")); // 8K resolution
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/test_height",
|
||||
PropertyInfo(Variant::INT,
|
||||
"display/window/size/test_height",
|
||||
PROPERTY_HINT_RANGE,
|
||||
"0,4320,or_greater")); // 8K resolution
|
||||
|
||||
if (use_custom_res) {
|
||||
if (!force_res) {
|
||||
window_size.width = GLOBAL_GET("display/window/size/width");
|
||||
window_size.height = GLOBAL_GET("display/window/size/height");
|
||||
|
||||
if (globals->has_setting("display/window/size/test_width") && globals->has_setting("display/window/size/test_height")) {
|
||||
if (globals->has_setting("display/window/size/test_width") &&
|
||||
globals->has_setting("display/window/size/test_height")) {
|
||||
int tw = globals->get("display/window/size/test_width");
|
||||
if (tw > 0) {
|
||||
window_size.width = tw;
|
||||
|
@ -1106,8 +1205,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
}
|
||||
|
||||
/* todo restore
|
||||
OS::get_singleton()->_allow_layered = GLOBAL_DEF("display/window/per_pixel_transparency/allowed", false);
|
||||
video_mode.layered = GLOBAL_DEF("display/window/per_pixel_transparency/enabled", false);
|
||||
OS::get_singleton()->_allow_layered = GLOBAL_DEF("display/window/per_pixel_transparency/allowed", false);
|
||||
video_mode.layered = GLOBAL_DEF("display/window/per_pixel_transparency/enabled", false);
|
||||
*/
|
||||
GLOBAL_DEF("rendering/quality/intended_usage/framebuffer_allocation", 2);
|
||||
GLOBAL_DEF("rendering/quality/intended_usage/framebuffer_allocation.mobile", 3);
|
||||
|
@ -1180,10 +1279,15 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
}
|
||||
|
||||
Engine::get_singleton()->set_iterations_per_second(GLOBAL_DEF("physics/common/physics_fps", 60));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("physics/common/physics_fps", PropertyInfo(Variant::INT, "physics/common/physics_fps", PROPERTY_HINT_RANGE, "1,120,1,or_greater"));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("physics/common/physics_fps",
|
||||
PropertyInfo(Variant::INT, "physics/common/physics_fps",
|
||||
PROPERTY_HINT_RANGE, "1,120,1,or_greater"));
|
||||
Engine::get_singleton()->set_physics_jitter_fix(GLOBAL_DEF("physics/common/physics_jitter_fix", 0.5));
|
||||
Engine::get_singleton()->set_target_fps(GLOBAL_DEF("debug/settings/fps/force_fps", 0));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("debug/settings/fps/force_fps", PropertyInfo(Variant::INT, "debug/settings/fps/force_fps", PROPERTY_HINT_RANGE, "0,120,1,or_greater"));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("debug/settings/fps/force_fps",
|
||||
PropertyInfo(Variant::INT,
|
||||
"debug/settings/fps/force_fps",
|
||||
PROPERTY_HINT_RANGE, "0,120,1,or_greater"));
|
||||
|
||||
GLOBAL_DEF("debug/settings/stdout/print_fps", false);
|
||||
GLOBAL_DEF("debug/settings/stdout/verbose_stdout", false);
|
||||
|
@ -1194,12 +1298,21 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
|
||||
if (frame_delay == 0) {
|
||||
frame_delay = GLOBAL_DEF("application/run/frame_delay_msec", 0);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("application/run/frame_delay_msec", PropertyInfo(Variant::INT, "application/run/frame_delay_msec", PROPERTY_HINT_RANGE, "0,100,1,or_greater")); // No negative numbers
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("application/run/frame_delay_msec",
|
||||
PropertyInfo(Variant::INT,
|
||||
"application/run/frame_delay_msec",
|
||||
PROPERTY_HINT_RANGE,
|
||||
"0,100,1,or_greater")); // No negative numbers
|
||||
}
|
||||
|
||||
OS::get_singleton()->set_low_processor_usage_mode(GLOBAL_DEF("application/run/low_processor_mode", false));
|
||||
OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(GLOBAL_DEF("application/run/low_processor_mode_sleep_usec", 6900)); // Roughly 144 FPS
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("application/run/low_processor_mode_sleep_usec", PropertyInfo(Variant::INT, "application/run/low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "0,33200,1,or_greater")); // No negative numbers
|
||||
OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(
|
||||
GLOBAL_DEF("application/run/low_processor_mode_sleep_usec", 6900)); // Roughly 144 FPS
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("application/run/low_processor_mode_sleep_usec",
|
||||
PropertyInfo(Variant::INT,
|
||||
"application/run/low_processor_mode_sleep_usec",
|
||||
PROPERTY_HINT_RANGE,
|
||||
"0,33200,1,or_greater")); // No negative numbers
|
||||
|
||||
GLOBAL_DEF("display/window/ios/hide_home_indicator", true);
|
||||
|
||||
|
@ -1286,14 +1399,16 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
|
|||
String rendering_driver; // temp broken
|
||||
|
||||
Error err;
|
||||
display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_flags, window_size, err);
|
||||
display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_flags,
|
||||
window_size, err);
|
||||
if (err != OK) {
|
||||
//ok i guess we can't use this display server, try other ones
|
||||
for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
|
||||
if (i == display_driver_idx) {
|
||||
continue; //don't try the same twice
|
||||
}
|
||||
display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_flags, window_size, err);
|
||||
display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_flags,
|
||||
window_size, err);
|
||||
if (err == OK) {
|
||||
break;
|
||||
}
|
||||
|
@ -1314,7 +1429,9 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
|
|||
|
||||
rendering_server = memnew(RenderingServerRaster);
|
||||
if (OS::get_singleton()->get_render_thread_mode() != OS::RENDER_THREAD_UNSAFE) {
|
||||
rendering_server = memnew(RenderingServerWrapMT(rendering_server, OS::get_singleton()->get_render_thread_mode() == OS::RENDER_SEPARATE_THREAD));
|
||||
rendering_server = memnew(RenderingServerWrapMT(rendering_server,
|
||||
OS::get_singleton()->get_render_thread_mode() ==
|
||||
OS::RENDER_SEPARATE_THREAD));
|
||||
}
|
||||
|
||||
rendering_server->init();
|
||||
|
@ -1379,7 +1496,10 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
|
|||
String boot_logo_path = GLOBAL_DEF("application/boot_splash/image", String());
|
||||
bool boot_logo_scale = GLOBAL_DEF("application/boot_splash/fullsize", true);
|
||||
bool boot_logo_filter = GLOBAL_DEF("application/boot_splash/use_filter", true);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("application/boot_splash/image", PropertyInfo(Variant::STRING, "application/boot_splash/image", PROPERTY_HINT_FILE, "*.png"));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("application/boot_splash/image",
|
||||
PropertyInfo(Variant::STRING,
|
||||
"application/boot_splash/image",
|
||||
PROPERTY_HINT_FILE, "*.png"));
|
||||
|
||||
Ref<Image> boot_logo;
|
||||
|
||||
|
@ -1396,7 +1516,8 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
|
|||
Color boot_bg_color = GLOBAL_DEF("application/boot_splash/bg_color", boot_splash_bg_color);
|
||||
if (boot_logo.is_valid()) {
|
||||
OS::get_singleton()->_msec_splash = OS::get_singleton()->get_ticks_msec();
|
||||
RenderingServer::get_singleton()->set_boot_image(boot_logo, boot_bg_color, boot_logo_scale, boot_logo_filter);
|
||||
RenderingServer::get_singleton()->set_boot_image(boot_logo, boot_bg_color, boot_logo_scale,
|
||||
boot_logo_filter);
|
||||
|
||||
} else {
|
||||
#ifndef NO_DEFAULT_BOOT_LOGO
|
||||
|
@ -1421,21 +1542,31 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
|
|||
}
|
||||
|
||||
MAIN_PRINT("Main: DCC");
|
||||
RenderingServer::get_singleton()->set_default_clear_color(GLOBAL_DEF("rendering/environment/default_clear_color", Color(0.3, 0.3, 0.3)));
|
||||
RenderingServer::get_singleton()->set_default_clear_color(
|
||||
GLOBAL_DEF("rendering/environment/default_clear_color", Color(0.3, 0.3, 0.3)));
|
||||
MAIN_PRINT("Main: END");
|
||||
|
||||
GLOBAL_DEF("application/config/icon", String());
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("application/config/icon", PropertyInfo(Variant::STRING, "application/config/icon", PROPERTY_HINT_FILE, "*.png,*.webp"));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("application/config/icon",
|
||||
PropertyInfo(Variant::STRING, "application/config/icon",
|
||||
PROPERTY_HINT_FILE, "*.png,*.webp"));
|
||||
|
||||
GLOBAL_DEF("application/config/macos_native_icon", String());
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("application/config/macos_native_icon", PropertyInfo(Variant::STRING, "application/config/macos_native_icon", PROPERTY_HINT_FILE, "*.icns"));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("application/config/macos_native_icon",
|
||||
PropertyInfo(Variant::STRING,
|
||||
"application/config/macos_native_icon",
|
||||
PROPERTY_HINT_FILE, "*.icns"));
|
||||
|
||||
GLOBAL_DEF("application/config/windows_native_icon", String());
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("application/config/windows_native_icon", PropertyInfo(Variant::STRING, "application/config/windows_native_icon", PROPERTY_HINT_FILE, "*.ico"));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("application/config/windows_native_icon",
|
||||
PropertyInfo(Variant::STRING,
|
||||
"application/config/windows_native_icon",
|
||||
PROPERTY_HINT_FILE, "*.ico"));
|
||||
|
||||
Input *id = Input::get_singleton();
|
||||
if (id) {
|
||||
if (bool(GLOBAL_DEF("input_devices/pointing/emulate_touch_from_mouse", false)) && !(editor || project_manager)) {
|
||||
if (bool(GLOBAL_DEF("input_devices/pointing/emulate_touch_from_mouse", false)) &&
|
||||
!(editor || project_manager)) {
|
||||
bool found_touchscreen = false;
|
||||
for (int i = 0; i < DisplayServer::get_singleton()->get_screen_count(); i++) {
|
||||
if (DisplayServer::get_singleton()->screen_is_touchscreen(i)) {
|
||||
|
@ -1460,10 +1591,14 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
|
|||
GLOBAL_DEF("display/mouse_cursor/custom_image", String());
|
||||
GLOBAL_DEF("display/mouse_cursor/custom_image_hotspot", Vector2());
|
||||
GLOBAL_DEF("display/mouse_cursor/tooltip_position_offset", Point2(10, 10));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("display/mouse_cursor/custom_image", PropertyInfo(Variant::STRING, "display/mouse_cursor/custom_image", PROPERTY_HINT_FILE, "*.png,*.webp"));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("display/mouse_cursor/custom_image",
|
||||
PropertyInfo(Variant::STRING,
|
||||
"display/mouse_cursor/custom_image",
|
||||
PROPERTY_HINT_FILE, "*.png,*.webp"));
|
||||
|
||||
if (String(ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image")) != String()) {
|
||||
Ref<Texture2D> cursor = ResourceLoader::load(ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image"));
|
||||
Ref<Texture2D> cursor = ResourceLoader::load(
|
||||
ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image"));
|
||||
if (cursor.is_valid()) {
|
||||
Vector2 hotspot = ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image_hotspot");
|
||||
Input::get_singleton()->set_custom_mouse_cursor(cursor, Input::CURSOR_ARROW, hotspot);
|
||||
|
@ -1544,7 +1679,6 @@ bool Main::start() {
|
|||
String positional_arg;
|
||||
String game_path;
|
||||
String script;
|
||||
String test;
|
||||
bool check_only = false;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
@ -1555,10 +1689,12 @@ bool Main::start() {
|
|||
#endif
|
||||
|
||||
main_timer_sync.init(OS::get_singleton()->get_ticks_usec());
|
||||
|
||||
List<String> args = OS::get_singleton()->get_cmdline_args();
|
||||
|
||||
// parameters that do not have an argument to the right
|
||||
for (int i = 0; i < args.size(); i++) {
|
||||
//parameters that do not have an argument to the right
|
||||
// Doctest Unit Testing Handler
|
||||
// Designed to override and pass arguments to the unit test handler.
|
||||
if (args[i] == "--check-only") {
|
||||
check_only = true;
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
@ -1591,8 +1727,6 @@ bool Main::start() {
|
|||
bool parsed_pair = true;
|
||||
if (args[i] == "-s" || args[i] == "--script") {
|
||||
script = args[i + 1];
|
||||
} else if (args[i] == "--test") {
|
||||
test = args[i + 1];
|
||||
#ifdef TOOLS_ENABLED
|
||||
} else if (args[i] == "--doctool") {
|
||||
doc_tool = args[i + 1];
|
||||
|
@ -1624,7 +1758,8 @@ bool Main::start() {
|
|||
String main_loop_type;
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (doc_tool != "") {
|
||||
Engine::get_singleton()->set_editor_hint(true); // Needed to instance editor-only classes for their default values
|
||||
Engine::get_singleton()->set_editor_hint(
|
||||
true); // Needed to instance editor-only classes for their default values
|
||||
|
||||
{
|
||||
DirAccessRef da = DirAccess::open(doc_tool);
|
||||
|
@ -1694,7 +1829,7 @@ bool Main::start() {
|
|||
print_line("Generating new docs...");
|
||||
doc.save_classes(index_path, doc_data_classes);
|
||||
|
||||
return false;
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (_export_preset != "") {
|
||||
|
@ -1702,7 +1837,7 @@ bool Main::start() {
|
|||
String err = "Command line includes export parameter option, but no destination path was given.\n";
|
||||
err += "Please specify the binary's file path to export to. Aborting export.";
|
||||
ERR_PRINT(err);
|
||||
return false;
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1716,16 +1851,7 @@ bool Main::start() {
|
|||
main_loop = memnew(SceneTree);
|
||||
};
|
||||
|
||||
if (test != "") {
|
||||
#ifdef TOOLS_ENABLED
|
||||
main_loop = test_main(test, args);
|
||||
|
||||
if (!main_loop) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
} else if (script != "") {
|
||||
if (script != "") {
|
||||
Ref<Script> script_res = ResourceLoader::load(script);
|
||||
ERR_FAIL_COND_V_MSG(script_res.is_null(), false, "Can't load script: " + script);
|
||||
|
||||
|
@ -1733,7 +1859,7 @@ bool Main::start() {
|
|||
if (!script_res->is_valid()) {
|
||||
OS::get_singleton()->set_exit_code(1);
|
||||
}
|
||||
return false;
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (script_res->can_instance()) {
|
||||
|
@ -1744,13 +1870,15 @@ bool Main::start() {
|
|||
if (obj) {
|
||||
memdelete(obj);
|
||||
}
|
||||
ERR_FAIL_V_MSG(false, vformat("Can't load the script \"%s\" as it doesn't inherit from SceneTree or MainLoop.", script));
|
||||
ERR_FAIL_V_MSG(false,
|
||||
vformat("Can't load the script \"%s\" as it doesn't inherit from SceneTree or MainLoop.",
|
||||
script));
|
||||
}
|
||||
|
||||
script_loop->set_init_script(script_res);
|
||||
main_loop = script_loop;
|
||||
} else {
|
||||
return false;
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -1764,7 +1892,7 @@ bool Main::start() {
|
|||
if (!main_loop) {
|
||||
if (!ClassDB::class_exists(main_loop_type)) {
|
||||
DisplayServer::get_singleton()->alert("Error: MainLoop type doesn't exist: " + main_loop_type);
|
||||
return false;
|
||||
return FAILED;
|
||||
} else {
|
||||
Object *ml = ClassDB::instance(main_loop_type);
|
||||
ERR_FAIL_COND_V_MSG(!ml, false, "Can't instance MainLoop type.");
|
||||
|
@ -1832,7 +1960,9 @@ bool Main::start() {
|
|||
|
||||
Object *obj = ClassDB::instance(ibt);
|
||||
|
||||
ERR_CONTINUE_MSG(obj == nullptr, "Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt));
|
||||
ERR_CONTINUE_MSG(obj == nullptr,
|
||||
"Cannot instance script for autoload, expected 'Node' inheritance, got: " +
|
||||
String(ibt));
|
||||
|
||||
n = Object::cast_to<Node>(obj);
|
||||
n->set_script(script_res);
|
||||
|
@ -1880,7 +2010,8 @@ bool Main::start() {
|
|||
|
||||
String stretch_mode = GLOBAL_DEF("display/window/stretch/mode", "disabled");
|
||||
String stretch_aspect = GLOBAL_DEF("display/window/stretch/aspect", "ignore");
|
||||
Size2i stretch_size = Size2(GLOBAL_DEF("display/window/size/width", 0), GLOBAL_DEF("display/window/size/height", 0));
|
||||
Size2i stretch_size = Size2(GLOBAL_DEF("display/window/size/width", 0),
|
||||
GLOBAL_DEF("display/window/size/height", 0));
|
||||
|
||||
Window::ContentScaleMode cs_sm = Window::CONTENT_SCALE_MODE_DISABLED;
|
||||
if (stretch_mode == "canvas_items") {
|
||||
|
@ -1924,10 +2055,14 @@ bool Main::start() {
|
|||
int shadow_atlas_q3_subdiv = GLOBAL_GET("rendering/quality/shadow_atlas/quadrant_3_subdiv");
|
||||
|
||||
sml->get_root()->set_shadow_atlas_size(shadow_atlas_size);
|
||||
sml->get_root()->set_shadow_atlas_quadrant_subdiv(0, Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q0_subdiv));
|
||||
sml->get_root()->set_shadow_atlas_quadrant_subdiv(1, Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q1_subdiv));
|
||||
sml->get_root()->set_shadow_atlas_quadrant_subdiv(2, Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q2_subdiv));
|
||||
sml->get_root()->set_shadow_atlas_quadrant_subdiv(3, Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q3_subdiv));
|
||||
sml->get_root()->set_shadow_atlas_quadrant_subdiv(0, Viewport::ShadowAtlasQuadrantSubdiv(
|
||||
shadow_atlas_q0_subdiv));
|
||||
sml->get_root()->set_shadow_atlas_quadrant_subdiv(1, Viewport::ShadowAtlasQuadrantSubdiv(
|
||||
shadow_atlas_q1_subdiv));
|
||||
sml->get_root()->set_shadow_atlas_quadrant_subdiv(2, Viewport::ShadowAtlasQuadrantSubdiv(
|
||||
shadow_atlas_q2_subdiv));
|
||||
sml->get_root()->set_shadow_atlas_quadrant_subdiv(3, Viewport::ShadowAtlasQuadrantSubdiv(
|
||||
shadow_atlas_q3_subdiv));
|
||||
|
||||
bool snap_controls = GLOBAL_DEF("gui/common/snap_controls_to_pixels", true);
|
||||
sml->get_root()->set_snap_controls_to_pixels(snap_controls);
|
||||
|
@ -1937,30 +2072,51 @@ bool Main::start() {
|
|||
|
||||
int texture_filter = GLOBAL_DEF("rendering/canvas_textures/default_texture_filter", 1);
|
||||
int texture_repeat = GLOBAL_DEF("rendering/canvas_textures/default_texture_repeat", 0);
|
||||
sml->get_root()->set_default_canvas_item_texture_filter(Viewport::DefaultCanvasItemTextureFilter(texture_filter));
|
||||
sml->get_root()->set_default_canvas_item_texture_repeat(Viewport::DefaultCanvasItemTextureRepeat(texture_repeat));
|
||||
sml->get_root()->set_default_canvas_item_texture_filter(
|
||||
Viewport::DefaultCanvasItemTextureFilter(texture_filter));
|
||||
sml->get_root()->set_default_canvas_item_texture_repeat(
|
||||
Viewport::DefaultCanvasItemTextureRepeat(texture_repeat));
|
||||
|
||||
} else {
|
||||
GLOBAL_DEF("display/window/stretch/mode", "disabled");
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/mode", PropertyInfo(Variant::STRING, "display/window/stretch/mode", PROPERTY_HINT_ENUM, "disabled,canvas_items,viewport"));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/mode",
|
||||
PropertyInfo(Variant::STRING,
|
||||
"display/window/stretch/mode",
|
||||
PROPERTY_HINT_ENUM,
|
||||
"disabled,canvas_items,viewport"));
|
||||
GLOBAL_DEF("display/window/stretch/aspect", "ignore");
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/aspect", PropertyInfo(Variant::STRING, "display/window/stretch/aspect", PROPERTY_HINT_ENUM, "ignore,keep,keep_width,keep_height,expand"));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/aspect",
|
||||
PropertyInfo(Variant::STRING,
|
||||
"display/window/stretch/aspect",
|
||||
PROPERTY_HINT_ENUM,
|
||||
"ignore,keep,keep_width,keep_height,expand"));
|
||||
GLOBAL_DEF("display/window/stretch/shrink", 1.0);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/shrink", PropertyInfo(Variant::FLOAT, "display/window/stretch/shrink", PROPERTY_HINT_RANGE, "1.0,8.0,0.1"));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/shrink",
|
||||
PropertyInfo(Variant::FLOAT,
|
||||
"display/window/stretch/shrink",
|
||||
PROPERTY_HINT_RANGE,
|
||||
"1.0,8.0,0.1"));
|
||||
sml->set_auto_accept_quit(GLOBAL_DEF("application/config/auto_accept_quit", true));
|
||||
sml->set_quit_on_go_back(GLOBAL_DEF("application/config/quit_on_go_back", true));
|
||||
GLOBAL_DEF("gui/common/snap_controls_to_pixels", true);
|
||||
GLOBAL_DEF("rendering/quality/dynamic_fonts/use_oversampling", true);
|
||||
|
||||
GLOBAL_DEF("rendering/canvas_textures/default_texture_filter", 1);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("rendering/canvas_textures/default_texture_filter", PropertyInfo(Variant::INT, "rendering/canvas_textures/default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,MipmapLinear,MipmapNearest"));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info(
|
||||
"rendering/canvas_textures/default_texture_filter",
|
||||
PropertyInfo(Variant::INT, "rendering/canvas_textures/default_texture_filter", PROPERTY_HINT_ENUM,
|
||||
"Nearest,Linear,MipmapLinear,MipmapNearest"));
|
||||
GLOBAL_DEF("rendering/canvas_textures/default_texture_repeat", 0);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("rendering/canvas_textures/default_texture_repeat", PropertyInfo(Variant::INT, "rendering/canvas_textures/default_texture_repeat", PROPERTY_HINT_ENUM, "Disable,Enable,Mirror"));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info(
|
||||
"rendering/canvas_textures/default_texture_repeat",
|
||||
PropertyInfo(Variant::INT, "rendering/canvas_textures/default_texture_repeat", PROPERTY_HINT_ENUM,
|
||||
"Disable,Enable,Mirror"));
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (editor) {
|
||||
bool editor_embed_subwindows = EditorSettings::get_singleton()->get_setting("interface/editor/single_window_mode");
|
||||
bool editor_embed_subwindows = EditorSettings::get_singleton()->get_setting(
|
||||
"interface/editor/single_window_mode");
|
||||
|
||||
if (editor_embed_subwindows) {
|
||||
sml->get_root()->set_embed_subwindows_hint(true);
|
||||
|
@ -1973,7 +2129,8 @@ bool Main::start() {
|
|||
local_game_path = game_path.replace("\\", "/");
|
||||
|
||||
if (!local_game_path.begins_with("res://")) {
|
||||
bool absolute = (local_game_path.size() > 1) && (local_game_path[0] == '/' || local_game_path[1] == ':');
|
||||
bool absolute =
|
||||
(local_game_path.size() > 1) && (local_game_path[0] == '/' || local_game_path[1] == ':');
|
||||
|
||||
if (!absolute) {
|
||||
if (ProjectSettings::get_singleton()->is_using_datapack()) {
|
||||
|
@ -1989,7 +2146,8 @@ bool Main::start() {
|
|||
} else {
|
||||
DirAccess *da = DirAccess::open(local_game_path.substr(0, sep));
|
||||
if (da) {
|
||||
local_game_path = da->get_current_dir().plus_file(local_game_path.substr(sep + 1, local_game_path.length()));
|
||||
local_game_path = da->get_current_dir().plus_file(
|
||||
local_game_path.substr(sep + 1, local_game_path.length()));
|
||||
memdelete(da);
|
||||
}
|
||||
}
|
||||
|
@ -2059,7 +2217,7 @@ bool Main::start() {
|
|||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (project_manager || (script == "" && test == "" && game_path == "" && !editor)) {
|
||||
if (project_manager || (script == "" && game_path == "" && !editor)) {
|
||||
Engine::get_singleton()->set_editor_hint(true);
|
||||
ProjectManager *pmanager = memnew(ProjectManager);
|
||||
ProgressDialog *progress_dialog = memnew(ProgressDialog);
|
||||
|
@ -2072,12 +2230,16 @@ bool Main::start() {
|
|||
if (project_manager || editor) {
|
||||
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CONSOLE_WINDOW)) {
|
||||
// Hide console window if requested (Windows-only).
|
||||
bool hide_console = EditorSettings::get_singleton()->get_setting("interface/editor/hide_console_window");
|
||||
bool hide_console = EditorSettings::get_singleton()->get_setting(
|
||||
"interface/editor/hide_console_window");
|
||||
DisplayServer::get_singleton()->console_set_visible(!hide_console);
|
||||
}
|
||||
|
||||
// Load SSL Certificates from Editor Settings (or builtin)
|
||||
Crypto::load_default_certificates(EditorSettings::get_singleton()->get_setting("network/ssl/editor_ssl_certificates").operator String());
|
||||
Crypto::load_default_certificates(EditorSettings::get_singleton()->get_setting(
|
||||
"network/ssl/editor_ssl_certificates")
|
||||
.
|
||||
operator String());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -2089,7 +2251,7 @@ bool Main::start() {
|
|||
|
||||
OS::get_singleton()->set_main_loop(main_loop);
|
||||
|
||||
return true;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Main iteration
|
||||
|
@ -2107,6 +2269,7 @@ uint32_t Main::frames = 0;
|
|||
uint32_t Main::frame = 0;
|
||||
bool Main::force_redraw_requested = false;
|
||||
int Main::iterating = 0;
|
||||
|
||||
bool Main::is_iterating() {
|
||||
return iterating > 0;
|
||||
}
|
||||
|
@ -2182,7 +2345,8 @@ bool Main::iteration() {
|
|||
|
||||
message_queue->flush();
|
||||
|
||||
physics_process_ticks = MAX(physics_process_ticks, OS::get_singleton()->get_ticks_usec() - physics_begin); // keep the largest one for reference
|
||||
physics_process_ticks = MAX(physics_process_ticks, OS::get_singleton()->get_ticks_usec() -
|
||||
physics_begin); // keep the largest one for reference
|
||||
physics_process_max = MAX(OS::get_singleton()->get_ticks_usec() - physics_begin, physics_process_max);
|
||||
Engine::get_singleton()->_physics_frames++;
|
||||
}
|
||||
|
@ -2198,7 +2362,8 @@ bool Main::iteration() {
|
|||
|
||||
RenderingServer::get_singleton()->sync(); //sync if still drawing from previous frames.
|
||||
|
||||
if (DisplayServer::get_singleton()->can_any_window_draw() && RenderingServer::get_singleton()->is_render_loop_enabled()) {
|
||||
if (DisplayServer::get_singleton()->can_any_window_draw() &&
|
||||
RenderingServer::get_singleton()->is_render_loop_enabled()) {
|
||||
if ((!force_redraw_requested) && OS::get_singleton()->is_in_low_processor_usage_mode()) {
|
||||
if (RenderingServer::get_singleton()->has_changed()) {
|
||||
RenderingServer::get_singleton()->draw(true, scaled_step); // flush visual commands
|
||||
|
@ -2260,10 +2425,12 @@ bool Main::iteration() {
|
|||
auto_build_solutions = false;
|
||||
// Only relevant when running the editor.
|
||||
if (!editor) {
|
||||
ERR_FAIL_V_MSG(true, "Command line option --build-solutions was passed, but no project is being edited. Aborting.");
|
||||
ERR_FAIL_V_MSG(true,
|
||||
"Command line option --build-solutions was passed, but no project is being edited. Aborting.");
|
||||
}
|
||||
if (!EditorNode::get_singleton()->call_build()) {
|
||||
ERR_FAIL_V_MSG(true, "Command line option --build-solutions was passed, but the build callback failed. Aborting.");
|
||||
ERR_FAIL_V_MSG(true,
|
||||
"Command line option --build-solutions was passed, but the build callback failed. Aborting.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
17
main/main.h
17
main/main.h
|
@ -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();
|
||||
|
@ -58,4 +58,19 @@ public:
|
|||
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
|
||||
|
|
|
@ -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",
|
||||
|
@ -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();
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_test == "math") {
|
||||
return TestMath::test();
|
||||
// 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);
|
||||
}
|
||||
|
||||
if (p_test == "basis") {
|
||||
return TestBasis::test();
|
||||
}
|
||||
test_context.applyCommandLine(valid_arguments.size(), args);
|
||||
|
||||
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;
|
||||
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
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -31,12 +31,768 @@
|
|||
#ifndef TEST_STRING_H
|
||||
#define TEST_STRING_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "core/io/ip_address.h"
|
||||
#include "core/os/main_loop.h"
|
||||
#include "core/os/os.h"
|
||||
#include "core/ustring.h"
|
||||
|
||||
#ifdef MODULE_REGEX_ENABLED
|
||||
#include "modules/regex/regex.h"
|
||||
#endif
|
||||
|
||||
#include "thirdparty/doctest/doctest.h"
|
||||
|
||||
namespace TestString {
|
||||
|
||||
MainLoop *test();
|
||||
TEST_CASE("[String] Assign from cstr") {
|
||||
String s = "Hello";
|
||||
CHECK(wcscmp(s.c_str(), L"Hello") == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Assign from string (operator=)") {
|
||||
String s = "Dolly";
|
||||
const String &t = s;
|
||||
CHECK(wcscmp(t.c_str(), L"Dolly") == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Assign from c-string (copycon)") {
|
||||
String s("Sheep");
|
||||
const String &t(s);
|
||||
CHECK(wcscmp(t.c_str(), L"Sheep") == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Assign from c-widechar (operator=)") {
|
||||
String s(L"Give me");
|
||||
CHECK(wcscmp(s.c_str(), L"Give me") == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Assign from c-widechar (copycon)") {
|
||||
String s(L"Wool");
|
||||
CHECK(wcscmp(s.c_str(), L"Wool") == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Comparisons (equal)") {
|
||||
String s = "Test Compare";
|
||||
CHECK(s == "Test Compare");
|
||||
CHECK(s == L"Test Compare");
|
||||
CHECK(s == String("Test Compare"));
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Comparisons (not equal)") {
|
||||
String s = "Test Compare";
|
||||
CHECK(s != "Peanut");
|
||||
CHECK(s != L"Coconut");
|
||||
CHECK(s != String("Butter"));
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Comparisons (operator <)") {
|
||||
String s = "Bees";
|
||||
CHECK(s < "Elephant");
|
||||
CHECK(!(s < L"Amber"));
|
||||
CHECK(!(s < String("Beatrix")));
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Concatenation") {
|
||||
String s;
|
||||
|
||||
s += "Have";
|
||||
s += ' ';
|
||||
s += 'a';
|
||||
s += String(" ");
|
||||
s = s + L"Nice";
|
||||
s = s + " ";
|
||||
s = s + String("Day");
|
||||
|
||||
CHECK(s == "Have a Nice Day");
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Testing size and length of string") {
|
||||
// todo: expand this test to do more tests on size() as it is complicated under the hood.
|
||||
CHECK(String("Mellon").size() == 7);
|
||||
CHECK(String("Mellon1").size() == 8);
|
||||
|
||||
// length works fine and is easier to test
|
||||
CHECK(String("Mellon").length() == 6);
|
||||
CHECK(String("Mellon1").length() == 7);
|
||||
CHECK(String("Mellon2").length() == 7);
|
||||
CHECK(String("Mellon3").length() == 7);
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Testing for empty string") {
|
||||
CHECK(!String("Mellon").empty());
|
||||
// do this more than once, to check for string corruption
|
||||
CHECK(String("").empty());
|
||||
CHECK(String("").empty());
|
||||
CHECK(String("").empty());
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Operator []") {
|
||||
String a = "Kugar Sane";
|
||||
a[0] = 'S';
|
||||
a[6] = 'C';
|
||||
CHECK(a == "Sugar Cane");
|
||||
CHECK(a[1] == 'u');
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Case function test") {
|
||||
String a = "MoMoNgA";
|
||||
|
||||
CHECK(a.to_upper() == "MOMONGA");
|
||||
CHECK(a.nocasecmp_to("momonga") == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("[String] UTF8") {
|
||||
/* how can i embed UTF in here? */
|
||||
static const CharType ustr[] = { 0x304A, 0x360F, 0x3088, 0x3046, 0 };
|
||||
//static const wchar_t ustr[] = { 'P', 0xCE, 'p',0xD3, 0 };
|
||||
String s = ustr;
|
||||
s.parse_utf8(s.utf8().get_data());
|
||||
CHECK(s == ustr);
|
||||
}
|
||||
|
||||
TEST_CASE("[String] ASCII") {
|
||||
String s = L"Primero Leche";
|
||||
String t = s.ascii().get_data();
|
||||
CHECK(s == t);
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Substr") {
|
||||
String s = "Killer Baby";
|
||||
CHECK(s.substr(3, 4) == "ler ");
|
||||
}
|
||||
|
||||
TEST_CASE("[string] Find") {
|
||||
String s = "Pretty Woman";
|
||||
s.find("Revenge of the Monster Truck");
|
||||
|
||||
CHECK(s.find("tty") == 3);
|
||||
CHECK(s.find("Revenge of the Monster Truck") == -1);
|
||||
}
|
||||
|
||||
TEST_CASE("[String] find no case") {
|
||||
String s = "Pretty Whale";
|
||||
CHECK(s.findn("WHA") == 7);
|
||||
CHECK(s.findn("Revenge of the Monster SawFish") == -1);
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Find and replace") {
|
||||
String s = "Happy Birthday, Anna!";
|
||||
s = s.replace("Birthday", "Halloween");
|
||||
CHECK(s == "Happy Halloween, Anna!");
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Insertion") {
|
||||
String s = "Who is Frederic?";
|
||||
s = s.insert(s.find("?"), " Chopin");
|
||||
CHECK(s == "Who is Frederic Chopin?");
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Number to string") {
|
||||
CHECK(String::num(3.141593) == "3.141593");
|
||||
}
|
||||
|
||||
TEST_CASE("[String] String to integer") {
|
||||
static const char *nums[4] = { "1237461283", "- 22", "0", " - 1123412" };
|
||||
static const int num[4] = { 1237461283, -22, 0, -1123412 };
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
CHECK(String(nums[i]).to_int() == num[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("[String] String to float") {
|
||||
static const char *nums[4] = { "-12348298412.2", "0.05", "2.0002", " -0.0001" };
|
||||
static const double num[4] = { -12348298412.2, 0.05, 2.0002, -0.0001 };
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
CHECK(!(ABS(String(nums[i]).to_double() - num[i]) > 0.00001));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Slicing") {
|
||||
String s = "Mars,Jupiter,Saturn,Uranus";
|
||||
|
||||
const char *slices[4] = { "Mars", "Jupiter", "Saturn", "Uranus" };
|
||||
for (int i = 0; i < s.get_slice_count(","); i++) {
|
||||
CHECK(s.get_slice(",", i) == slices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Erasing") {
|
||||
String s = "Josephine is such a cute girl!";
|
||||
s.erase(s.find("cute "), String("cute ").length());
|
||||
CHECK(s == "Josephine is such a girl!");
|
||||
}
|
||||
|
||||
#ifdef MODULE_REGEX_ENABLED
|
||||
TEST_CASE("[String] Regex substitution") {
|
||||
String s = "Double all the vowels.";
|
||||
RegEx re("(?<vowel>[aeiou])");
|
||||
s = re.sub(s, "$0$vowel", true);
|
||||
CHECK(s == "Doouublee aall thee vooweels.");
|
||||
}
|
||||
#endif
|
||||
|
||||
struct test_27_data {
|
||||
char const *data;
|
||||
char const *begin;
|
||||
bool expected;
|
||||
};
|
||||
|
||||
TEST_CASE("[String] Begins with") {
|
||||
test_27_data tc[] = {
|
||||
{ "res://foobar", "res://", true },
|
||||
{ "res", "res://", false },
|
||||
{ "abc", "abc", true }
|
||||
};
|
||||
size_t count = sizeof(tc) / sizeof(tc[0]);
|
||||
bool state = true;
|
||||
for (size_t i = 0; state && i < count; ++i) {
|
||||
String s = tc[i].data;
|
||||
state = s.begins_with(tc[i].begin) == tc[i].expected;
|
||||
if (state) {
|
||||
String sb = tc[i].begin;
|
||||
state = s.begins_with(sb) == tc[i].expected;
|
||||
}
|
||||
CHECK(state);
|
||||
if (!state) {
|
||||
break;
|
||||
}
|
||||
};
|
||||
CHECK(state);
|
||||
}
|
||||
|
||||
TEST_CASE("[String] sprintf") {
|
||||
String format, output;
|
||||
Array args;
|
||||
bool error;
|
||||
|
||||
// %%
|
||||
format = "fish %% frog";
|
||||
args.clear();
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish % frog"));
|
||||
//////// INTS
|
||||
|
||||
// Int
|
||||
format = "fish %d frog";
|
||||
args.clear();
|
||||
args.push_back(5);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish 5 frog"));
|
||||
|
||||
// Int left padded with zeroes.
|
||||
format = "fish %05d frog";
|
||||
args.clear();
|
||||
args.push_back(5);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish 00005 frog"));
|
||||
|
||||
// Int left padded with spaces.
|
||||
format = "fish %5d frog";
|
||||
args.clear();
|
||||
args.push_back(5);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish 5 frog"));
|
||||
|
||||
// Int right padded with spaces.
|
||||
format = "fish %-5d frog";
|
||||
args.clear();
|
||||
args.push_back(5);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish 5 frog"));
|
||||
|
||||
// Int with sign (positive).
|
||||
format = "fish %+d frog";
|
||||
args.clear();
|
||||
args.push_back(5);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish +5 frog"));
|
||||
|
||||
// Negative int.
|
||||
format = "fish %d frog";
|
||||
args.clear();
|
||||
args.push_back(-5);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish -5 frog"));
|
||||
|
||||
// Hex (lower)
|
||||
format = "fish %x frog";
|
||||
args.clear();
|
||||
args.push_back(45);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish 2d frog"));
|
||||
|
||||
// Hex (upper)
|
||||
format = "fish %X frog";
|
||||
args.clear();
|
||||
args.push_back(45);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish 2D frog"));
|
||||
|
||||
// Octal
|
||||
format = "fish %o frog";
|
||||
args.clear();
|
||||
args.push_back(99);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish 143 frog"));
|
||||
|
||||
////// REALS
|
||||
|
||||
// Real
|
||||
format = "fish %f frog";
|
||||
args.clear();
|
||||
args.push_back(99.99);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish 99.990000 frog"));
|
||||
|
||||
// Real left-padded
|
||||
format = "fish %11f frog";
|
||||
args.clear();
|
||||
args.push_back(99.99);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish 99.990000 frog"));
|
||||
|
||||
// Real right-padded
|
||||
format = "fish %-11f frog";
|
||||
args.clear();
|
||||
args.push_back(99.99);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish 99.990000 frog"));
|
||||
|
||||
// Real given int.
|
||||
format = "fish %f frog";
|
||||
args.clear();
|
||||
args.push_back(99);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish 99.000000 frog"));
|
||||
|
||||
// Real with sign (positive).
|
||||
format = "fish %+f frog";
|
||||
args.clear();
|
||||
args.push_back(99.99);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish +99.990000 frog"));
|
||||
|
||||
// Real with 1 decimals.
|
||||
format = "fish %.1f frog";
|
||||
args.clear();
|
||||
args.push_back(99.99);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish 100.0 frog"));
|
||||
|
||||
// Real with 12 decimals.
|
||||
format = "fish %.12f frog";
|
||||
args.clear();
|
||||
args.push_back(99.99);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish 99.990000000000 frog"));
|
||||
|
||||
// Real with no decimals.
|
||||
format = "fish %.f frog";
|
||||
args.clear();
|
||||
args.push_back(99.99);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish 100 frog"));
|
||||
|
||||
/////// Strings.
|
||||
|
||||
// String
|
||||
format = "fish %s frog";
|
||||
args.clear();
|
||||
args.push_back("cheese");
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish cheese frog"));
|
||||
|
||||
// String left-padded
|
||||
format = "fish %10s frog";
|
||||
args.clear();
|
||||
args.push_back("cheese");
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish cheese frog"));
|
||||
|
||||
// String right-padded
|
||||
format = "fish %-10s frog";
|
||||
args.clear();
|
||||
args.push_back("cheese");
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish cheese frog"));
|
||||
|
||||
///// Characters
|
||||
|
||||
// Character as string.
|
||||
format = "fish %c frog";
|
||||
args.clear();
|
||||
args.push_back("A");
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish A frog"));
|
||||
|
||||
// Character as int.
|
||||
format = "fish %c frog";
|
||||
args.clear();
|
||||
args.push_back(65);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish A frog"));
|
||||
|
||||
///// Dynamic width
|
||||
|
||||
// String dynamic width
|
||||
format = "fish %*s frog";
|
||||
args.clear();
|
||||
args.push_back(10);
|
||||
args.push_back("cheese");
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
REQUIRE(output == String("fish cheese frog"));
|
||||
|
||||
// Int dynamic width
|
||||
format = "fish %*d frog";
|
||||
args.clear();
|
||||
args.push_back(10);
|
||||
args.push_back(99);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
REQUIRE(output == String("fish 99 frog"));
|
||||
|
||||
// Float dynamic width
|
||||
format = "fish %*.*f frog";
|
||||
args.clear();
|
||||
args.push_back(10);
|
||||
args.push_back(3);
|
||||
args.push_back(99.99);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error == false);
|
||||
CHECK(output == String("fish 99.990 frog"));
|
||||
|
||||
///// Errors
|
||||
|
||||
// More formats than arguments.
|
||||
format = "fish %s %s frog";
|
||||
args.clear();
|
||||
args.push_back("cheese");
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error);
|
||||
CHECK(output == "not enough arguments for format string");
|
||||
|
||||
// More arguments than formats.
|
||||
format = "fish %s frog";
|
||||
args.clear();
|
||||
args.push_back("hello");
|
||||
args.push_back("cheese");
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error);
|
||||
CHECK(output == "not all arguments converted during string formatting");
|
||||
|
||||
// Incomplete format.
|
||||
format = "fish %10";
|
||||
args.clear();
|
||||
args.push_back("cheese");
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error);
|
||||
CHECK(output == "incomplete format");
|
||||
|
||||
// Bad character in format string
|
||||
format = "fish %&f frog";
|
||||
args.clear();
|
||||
args.push_back("cheese");
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error);
|
||||
CHECK(output == "unsupported format character");
|
||||
|
||||
// Too many decimals.
|
||||
format = "fish %2.2.2f frog";
|
||||
args.clear();
|
||||
args.push_back(99.99);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error);
|
||||
CHECK(output == "too many decimal points in format");
|
||||
|
||||
// * not a number
|
||||
format = "fish %*f frog";
|
||||
args.clear();
|
||||
args.push_back("cheese");
|
||||
args.push_back(99.99);
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error);
|
||||
CHECK(output == "* wants number");
|
||||
|
||||
// Character too long.
|
||||
format = "fish %c frog";
|
||||
args.clear();
|
||||
args.push_back("sc");
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error);
|
||||
CHECK(output == "%c requires number or single-character string");
|
||||
|
||||
// Character bad type.
|
||||
format = "fish %c frog";
|
||||
args.clear();
|
||||
args.push_back(Array());
|
||||
output = format.sprintf(args, &error);
|
||||
REQUIRE(error);
|
||||
CHECK(output == "%c requires number or single-character string");
|
||||
}
|
||||
|
||||
TEST_CASE("[String] IPVX address to string") {
|
||||
IP_Address ip0("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
|
||||
IP_Address ip(0x0123, 0x4567, 0x89ab, 0xcdef, true);
|
||||
IP_Address ip2("fe80::52e5:49ff:fe93:1baf");
|
||||
IP_Address ip3("::ffff:192.168.0.1");
|
||||
String ip4 = "192.168.0.1";
|
||||
CHECK(ip4.is_valid_ip_address());
|
||||
|
||||
ip4 = "192.368.0.1";
|
||||
CHECK(!ip4.is_valid_ip_address());
|
||||
|
||||
String ip6 = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
|
||||
CHECK(ip6.is_valid_ip_address());
|
||||
|
||||
ip6 = "2001:0db8:85j3:0000:0000:8a2e:0370:7334";
|
||||
CHECK(!ip6.is_valid_ip_address());
|
||||
|
||||
ip6 = "2001:0db8:85f345:0000:0000:8a2e:0370:7334";
|
||||
CHECK(!ip6.is_valid_ip_address());
|
||||
|
||||
ip6 = "2001:0db8::0:8a2e:370:7334";
|
||||
CHECK(ip6.is_valid_ip_address());
|
||||
|
||||
ip6 = "::ffff:192.168.0.1";
|
||||
CHECK(ip6.is_valid_ip_address());
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Capitalize against many strings") {
|
||||
String input = "bytes2var";
|
||||
String output = "Bytes 2 Var";
|
||||
CHECK(input.capitalize() == output);
|
||||
|
||||
input = "linear2db";
|
||||
output = "Linear 2 Db";
|
||||
CHECK(input.capitalize() == output);
|
||||
|
||||
input = "vector3";
|
||||
output = "Vector 3";
|
||||
CHECK(input.capitalize() == output);
|
||||
|
||||
input = "sha256";
|
||||
output = "Sha 256";
|
||||
CHECK(input.capitalize() == output);
|
||||
|
||||
input = "2db";
|
||||
output = "2 Db";
|
||||
CHECK(input.capitalize() == output);
|
||||
|
||||
input = "PascalCase";
|
||||
output = "Pascal Case";
|
||||
CHECK(input.capitalize() == output);
|
||||
|
||||
input = "PascalPascalCase";
|
||||
output = "Pascal Pascal Case";
|
||||
CHECK(input.capitalize() == output);
|
||||
|
||||
input = "snake_case";
|
||||
output = "Snake Case";
|
||||
CHECK(input.capitalize() == output);
|
||||
|
||||
input = "snake_snake_case";
|
||||
output = "Snake Snake Case";
|
||||
CHECK(input.capitalize() == output);
|
||||
|
||||
input = "sha256sum";
|
||||
output = "Sha 256 Sum";
|
||||
CHECK(input.capitalize() == output);
|
||||
|
||||
input = "cat2dog";
|
||||
output = "Cat 2 Dog";
|
||||
CHECK(input.capitalize() == output);
|
||||
|
||||
input = "function(name)";
|
||||
output = "Function(name)";
|
||||
CHECK(input.capitalize() == output);
|
||||
|
||||
input = "snake_case_function(snake_case_arg)";
|
||||
output = "Snake Case Function(snake Case Arg)";
|
||||
CHECK(input.capitalize() == output);
|
||||
|
||||
input = "snake_case_function( snake_case_arg )";
|
||||
output = "Snake Case Function( Snake Case Arg )";
|
||||
CHECK(input.capitalize() == output);
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Checking string is empty when it should be") {
|
||||
bool state = true;
|
||||
bool success;
|
||||
|
||||
String a = "";
|
||||
success = a[0] == 0;
|
||||
if (!success) {
|
||||
state = false;
|
||||
}
|
||||
String b = "Godot";
|
||||
success = b[b.size()] == 0;
|
||||
if (!success) {
|
||||
state = false;
|
||||
}
|
||||
const String c = "";
|
||||
success = c[0] == 0;
|
||||
if (!success) {
|
||||
state = false;
|
||||
}
|
||||
|
||||
const String d = "Godot";
|
||||
success = d[d.size()] == 0;
|
||||
if (!success) {
|
||||
state = false;
|
||||
}
|
||||
|
||||
CHECK(state);
|
||||
}
|
||||
|
||||
TEST_CASE("[String] lstrip and rstrip") {
|
||||
#define STRIP_TEST(x) \
|
||||
{ \
|
||||
bool success = x; \
|
||||
state = state && success; \
|
||||
}
|
||||
|
||||
bool state = true;
|
||||
|
||||
// strip none
|
||||
STRIP_TEST(String("abc").lstrip("") == "abc");
|
||||
STRIP_TEST(String("abc").rstrip("") == "abc");
|
||||
// strip one
|
||||
STRIP_TEST(String("abc").lstrip("a") == "bc");
|
||||
STRIP_TEST(String("abc").rstrip("c") == "ab");
|
||||
// strip lots
|
||||
STRIP_TEST(String("bababbababccc").lstrip("ab") == "ccc");
|
||||
STRIP_TEST(String("aaabcbcbcbbcbbc").rstrip("cb") == "aaa");
|
||||
// strip empty string
|
||||
STRIP_TEST(String("").lstrip("") == "");
|
||||
STRIP_TEST(String("").rstrip("") == "");
|
||||
// strip to empty string
|
||||
STRIP_TEST(String("abcabcabc").lstrip("bca") == "");
|
||||
STRIP_TEST(String("abcabcabc").rstrip("bca") == "");
|
||||
// don't strip wrong end
|
||||
STRIP_TEST(String("abc").lstrip("c") == "abc");
|
||||
STRIP_TEST(String("abca").lstrip("a") == "bca");
|
||||
STRIP_TEST(String("abc").rstrip("a") == "abc");
|
||||
STRIP_TEST(String("abca").rstrip("a") == "abc");
|
||||
// in utf-8 "¿" (\u00bf) has the same first byte as "µ" (\u00b5)
|
||||
// and the same second as "ÿ" (\u00ff)
|
||||
STRIP_TEST(String::utf8("¿").lstrip(String::utf8("µÿ")) == String::utf8("¿"));
|
||||
STRIP_TEST(String::utf8("¿").rstrip(String::utf8("µÿ")) == String::utf8("¿"));
|
||||
STRIP_TEST(String::utf8("µ¿ÿ").lstrip(String::utf8("µÿ")) == String::utf8("¿ÿ"));
|
||||
STRIP_TEST(String::utf8("µ¿ÿ").rstrip(String::utf8("µÿ")) == String::utf8("µ¿"));
|
||||
|
||||
// the above tests repeated with additional superfluous strip chars
|
||||
|
||||
// strip none
|
||||
STRIP_TEST(String("abc").lstrip("qwjkl") == "abc");
|
||||
STRIP_TEST(String("abc").rstrip("qwjkl") == "abc");
|
||||
// strip one
|
||||
STRIP_TEST(String("abc").lstrip("qwajkl") == "bc");
|
||||
STRIP_TEST(String("abc").rstrip("qwcjkl") == "ab");
|
||||
// strip lots
|
||||
STRIP_TEST(String("bababbababccc").lstrip("qwabjkl") == "ccc");
|
||||
STRIP_TEST(String("aaabcbcbcbbcbbc").rstrip("qwcbjkl") == "aaa");
|
||||
// strip empty string
|
||||
STRIP_TEST(String("").lstrip("qwjkl") == "");
|
||||
STRIP_TEST(String("").rstrip("qwjkl") == "");
|
||||
// strip to empty string
|
||||
STRIP_TEST(String("abcabcabc").lstrip("qwbcajkl") == "");
|
||||
STRIP_TEST(String("abcabcabc").rstrip("qwbcajkl") == "");
|
||||
// don't strip wrong end
|
||||
STRIP_TEST(String("abc").lstrip("qwcjkl") == "abc");
|
||||
STRIP_TEST(String("abca").lstrip("qwajkl") == "bca");
|
||||
STRIP_TEST(String("abc").rstrip("qwajkl") == "abc");
|
||||
STRIP_TEST(String("abca").rstrip("qwajkl") == "abc");
|
||||
// in utf-8 "¿" (\u00bf) has the same first byte as "µ" (\u00b5)
|
||||
// and the same second as "ÿ" (\u00ff)
|
||||
STRIP_TEST(String::utf8("¿").lstrip(String::utf8("qwaµÿjkl")) == String::utf8("¿"));
|
||||
STRIP_TEST(String::utf8("¿").rstrip(String::utf8("qwaµÿjkl")) == String::utf8("¿"));
|
||||
STRIP_TEST(String::utf8("µ¿ÿ").lstrip(String::utf8("qwaµÿjkl")) == String::utf8("¿ÿ"));
|
||||
STRIP_TEST(String::utf8("µ¿ÿ").rstrip(String::utf8("qwaµÿjkl")) == String::utf8("µ¿"));
|
||||
|
||||
CHECK(state);
|
||||
|
||||
#undef STRIP_TEST
|
||||
}
|
||||
|
||||
TEST_CASE("[String] ensuring empty string into parse_utf8 passes empty string") {
|
||||
String empty;
|
||||
CHECK(empty.parse_utf8(NULL, -1));
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Cyrillic to_lower()") {
|
||||
String upper = String::utf8("АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ");
|
||||
String lower = String::utf8("абвгдеёжзийклмнопрстуфхцчшщъыьэюя");
|
||||
|
||||
String test = upper.to_lower();
|
||||
|
||||
bool state = test == lower;
|
||||
|
||||
CHECK(state);
|
||||
}
|
||||
|
||||
TEST_CASE("[String] Count and countn functionality") {
|
||||
#define COUNT_TEST(x) \
|
||||
{ \
|
||||
bool success = x; \
|
||||
state = state && success; \
|
||||
}
|
||||
|
||||
bool state = true;
|
||||
|
||||
COUNT_TEST(String("").count("Test") == 0);
|
||||
COUNT_TEST(String("Test").count("") == 0);
|
||||
COUNT_TEST(String("Test").count("test") == 0);
|
||||
COUNT_TEST(String("Test").count("TEST") == 0);
|
||||
COUNT_TEST(String("TEST").count("TEST") == 1);
|
||||
COUNT_TEST(String("Test").count("Test") == 1);
|
||||
COUNT_TEST(String("aTest").count("Test") == 1);
|
||||
COUNT_TEST(String("Testa").count("Test") == 1);
|
||||
COUNT_TEST(String("TestTestTest").count("Test") == 3);
|
||||
COUNT_TEST(String("TestTestTest").count("TestTest") == 1);
|
||||
COUNT_TEST(String("TestGodotTestGodotTestGodot").count("Test") == 3);
|
||||
|
||||
COUNT_TEST(String("TestTestTestTest").count("Test", 4, 8) == 1);
|
||||
COUNT_TEST(String("TestTestTestTest").count("Test", 4, 12) == 2);
|
||||
COUNT_TEST(String("TestTestTestTest").count("Test", 4, 16) == 3);
|
||||
COUNT_TEST(String("TestTestTestTest").count("Test", 4) == 3);
|
||||
|
||||
COUNT_TEST(String("Test").countn("test") == 1);
|
||||
COUNT_TEST(String("Test").countn("TEST") == 1);
|
||||
COUNT_TEST(String("testTest-Testatest").countn("tEst") == 4);
|
||||
COUNT_TEST(String("testTest-TeStatest").countn("tEsT", 4, 16) == 2);
|
||||
|
||||
CHECK(state);
|
||||
}
|
||||
} // namespace TestString
|
||||
|
||||
#endif // TEST_STRING_H
|
||||
|
|
42
main/tests/test_validate_testing.h
Normal file
42
main/tests/test_validate_testing.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*************************************************************************/
|
||||
/* test_validate_testing.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef TEST_VALIDATE_TESTING_H
|
||||
#define TEST_VALIDATE_TESTING_H
|
||||
|
||||
#include "core/os/os.h"
|
||||
|
||||
#include "thirdparty/doctest/doctest.h"
|
||||
|
||||
TEST_CASE("Validate Test will always pass") {
|
||||
CHECK(true);
|
||||
}
|
||||
|
||||
#endif // TEST_VALIDATE_TESTING_H
|
|
@ -67,6 +67,9 @@ int iphone_main(int width, int height, int argc, char **argv, String data_dir) {
|
|||
printf("cwd %s\n", cwd);
|
||||
os = new OSIPhone(width, height, data_dir);
|
||||
|
||||
// We must override main when testing is enabled
|
||||
TEST_MAIN_OVERRIDE
|
||||
|
||||
char *fargv[64];
|
||||
for (int i = 0; i < argc; i++) {
|
||||
fargv[i] = argv[i];
|
||||
|
|
|
@ -131,6 +131,10 @@ int main(int argc, char *argv[]) {
|
|||
/* clang-format on */
|
||||
|
||||
os = new OS_JavaScript();
|
||||
|
||||
// We must override main when testing is enabled
|
||||
TEST_MAIN_OVERRIDE
|
||||
|
||||
Main::setup(argv[0], argc - 1, &argv[1], false);
|
||||
emscripten_set_main_loop(main_loop_callback, -1, false);
|
||||
emscripten_pause_main_loop(); // Will need to wait for FS sync.
|
||||
|
|
|
@ -41,6 +41,9 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
setlocale(LC_CTYPE, "");
|
||||
|
||||
// We must override main when testing is enabled
|
||||
TEST_MAIN_OVERRIDE
|
||||
|
||||
char *cwd = (char *)malloc(PATH_MAX);
|
||||
ERR_FAIL_COND_V(!cwd, ERR_OUT_OF_MEMORY);
|
||||
char *ret = getcwd(cwd, PATH_MAX);
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
int main(int argc, char **argv) {
|
||||
#if defined(VULKAN_ENABLED)
|
||||
//MoltenVK - enable full component swizzling support
|
||||
// MoltenVK - enable full component swizzling support
|
||||
setenv("MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE", "1", 1);
|
||||
#endif
|
||||
|
||||
|
@ -60,6 +60,9 @@ int main(int argc, char **argv) {
|
|||
OS_OSX os;
|
||||
Error err;
|
||||
|
||||
// We must override main when testing is enabled
|
||||
TEST_MAIN_OVERRIDE
|
||||
|
||||
if (os.open_with_filename != "") {
|
||||
char *argv_c = (char *)malloc(os.open_with_filename.utf8().size());
|
||||
memcpy(argv_c, os.open_with_filename.utf8().get_data(), os.open_with_filename.utf8().size());
|
||||
|
|
|
@ -34,6 +34,9 @@
|
|||
int main(int argc, char *argv[]) {
|
||||
OS_Server os;
|
||||
|
||||
// We must override main when testing is enabled
|
||||
TEST_MAIN_OVERRIDE
|
||||
|
||||
Error err = Main::setup(argv[0], argc - 1, &argv[1]);
|
||||
if (err != OK)
|
||||
return 255;
|
||||
|
|
|
@ -146,6 +146,8 @@ int widechar_main(int argc, wchar_t **argv) {
|
|||
argv_utf8[i] = wc_to_utf8(argv[i]);
|
||||
}
|
||||
|
||||
TEST_MAIN_PARAM_OVERRIDE(argc, argv_utf8)
|
||||
|
||||
Error err = Main::setup(argv_utf8[0], argc - 1, &argv_utf8[1]);
|
||||
|
||||
if (err != OK) {
|
||||
|
@ -186,10 +188,12 @@ int _main() {
|
|||
return result;
|
||||
}
|
||||
|
||||
int main(int _argc, char **_argv) {
|
||||
int main(int argc, char **argv) {
|
||||
// override the arguments for the test handler / if symbol is provided
|
||||
// TEST_MAIN_OVERRIDE
|
||||
|
||||
// _argc and _argv are ignored
|
||||
// we are going to use the WideChar version of them instead
|
||||
|
||||
#ifdef CRASH_HANDLER_EXCEPTION
|
||||
__try {
|
||||
return _main();
|
||||
|
|
8
thirdparty/README.md
vendored
8
thirdparty/README.md
vendored
|
@ -74,6 +74,14 @@ Files extracted from upstream source:
|
|||
- all .cpp, .h, and .txt files in ConvectionKernels/
|
||||
|
||||
|
||||
## doctest
|
||||
- Upstream: https://github.com/onqtam/doctest
|
||||
- Version: 1c8da00 (2.4.0)
|
||||
- License: MIT
|
||||
|
||||
Extracted from .zip provided. Extracted license and header only.
|
||||
|
||||
|
||||
## enet
|
||||
|
||||
- Upstream: http://enet.bespin.org
|
||||
|
|
21
thirdparty/doctest/LICENSE.txt
vendored
Normal file
21
thirdparty/doctest/LICENSE.txt
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Viktor Kirilov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
6205
thirdparty/doctest/doctest.h
vendored
Normal file
6205
thirdparty/doctest/doctest.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue