summaryrefslogtreecommitdiffstats
path: root/modules/gdscript/tests
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript/tests')
-rw-r--r--modules/gdscript/tests/README.md41
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/uid_duplicate.gd5
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/uid_duplicate.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/uid_invalid.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/uid_invalid.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/uid_too_late.gd5
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/uid_too_late.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/uid.gd5
-rw-r--r--modules/gdscript/tests/scripts/parser/features/uid.out1
-rw-r--r--modules/gdscript/tests/test_completion.h18
-rw-r--r--modules/gdscript/tests/test_gdscript_uid.h115
12 files changed, 194 insertions, 8 deletions
diff --git a/modules/gdscript/tests/README.md b/modules/gdscript/tests/README.md
index 361d586d32..cea251bab5 100644
--- a/modules/gdscript/tests/README.md
+++ b/modules/gdscript/tests/README.md
@@ -6,3 +6,44 @@ and output files.
See the
[Integration tests for GDScript documentation](https://docs.godotengine.org/en/latest/contributing/development/core_and_modules/unit_testing.html#integration-tests-for-gdscript)
for information about creating and running GDScript integration tests.
+
+# GDScript Autocompletion tests
+
+The `script/completion` folder contains test for the GDScript autocompletion.
+
+Each test case consists of at least one `.gd` file, which contains the code, and one `.cfg` file, which contains expected results and configuration. Inside of the GDScript file the character `➡` represents the cursor position, at which autocompletion is invoked.
+
+The config file contains two section:
+
+`[input]` contains keys that configure the test environment. The following keys are possible:
+
+- `cs: boolean = false`: If `true`, the test will be skipped when running a non C# build.
+- `use_single_quotes: boolean = false`: Configures the corresponding editor setting for the test.
+- `scene: String`: Allows to specify a scene which is opened while autocompletion is performed. If this is not set the test runner will search for a `.tscn` file with the same basename as the GDScript file. If that isn't found either, autocompletion will behave as if no scene was opened.
+
+`[output]` specifies the expected results for the test. The following key are supported:
+
+- `include: Array`: An unordered list of suggestions that should be in the result. Each entry is one dictionary with the following keys: `display`, `insert_text`, `kind`, `location`, which correspond to the suggestion struct which is used in the code. The runner only tests against specified keys, so in most cases `display` will suffice.
+- `exclude: Array`: An array of suggestions which should not be in the result. The entries take the same form as for `include`.
+- `call_hint: String`: The expected call hint returned by autocompletion.
+- `forced: boolean`: Whether autocompletion is expected to force opening a completion window.
+
+Tests will only test against entries in `[output]` that were specified.
+
+## Writing autocompletion tests
+
+To avoid failing edge cases a certain behaviour needs to be tested multiple times. Some things that tests should account for:
+
+- All possible types: Test with all possible types that apply to the tested behaviour. (For the last points testing against `SCRIPT` and `CLASS` should suffice. `CLASS` can be obtained through C#, `SCRIPT` through GDScript. Relying on autoloads to be of type `SCRIPT` is not good, since this might change in the future.)
+
+ - `BUILTIN`
+ - `NATIVE`
+ - GDScripts (with `class_name` as well as `preload`ed)
+ - C# (as standin for all other language bindings) (with `class_name` as well as `preload`ed)
+ - Autoloads
+
+- Possible contexts: the completion might be placed in different places of the program. e.g:
+ - initializers of class members
+ - directly inside a suite
+ - assignments inside a suite
+ - as parameter to a call
diff --git a/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg b/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg
index 4edee46039..27e695d245 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg
@@ -1,4 +1,4 @@
[output]
-expected=[
+include=[
{"display": "autoplay"},
]
diff --git a/modules/gdscript/tests/scripts/parser/errors/uid_duplicate.gd b/modules/gdscript/tests/scripts/parser/errors/uid_duplicate.gd
new file mode 100644
index 0000000000..4ded8e65db
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/uid_duplicate.gd
@@ -0,0 +1,5 @@
+@uid("uid://c4ckv3ryprcn4")
+@uid("uid://c4ckv3ryprcn4")
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/parser/errors/uid_duplicate.out b/modules/gdscript/tests/scripts/parser/errors/uid_duplicate.out
new file mode 100644
index 0000000000..be1061401a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/uid_duplicate.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+"@uid" annotation can only be used once.
diff --git a/modules/gdscript/tests/scripts/parser/errors/uid_invalid.gd b/modules/gdscript/tests/scripts/parser/errors/uid_invalid.gd
new file mode 100644
index 0000000000..114d5b7e98
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/uid_invalid.gd
@@ -0,0 +1,4 @@
+@uid("not a valid uid")
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/parser/errors/uid_invalid.out b/modules/gdscript/tests/scripts/parser/errors/uid_invalid.out
new file mode 100644
index 0000000000..83f9f63cbf
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/uid_invalid.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+The annotated UID is invalid.
diff --git a/modules/gdscript/tests/scripts/parser/errors/uid_too_late.gd b/modules/gdscript/tests/scripts/parser/errors/uid_too_late.gd
new file mode 100644
index 0000000000..2b332447b7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/uid_too_late.gd
@@ -0,0 +1,5 @@
+extends Object
+@uid("uid://c4ckv3ryprcn4")
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/parser/errors/uid_too_late.out b/modules/gdscript/tests/scripts/parser/errors/uid_too_late.out
new file mode 100644
index 0000000000..328459923f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/uid_too_late.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Annotation "@uid" must be at the top of the script, before "extends" and "class_name".
diff --git a/modules/gdscript/tests/scripts/parser/features/uid.gd b/modules/gdscript/tests/scripts/parser/features/uid.gd
new file mode 100644
index 0000000000..4070500608
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/uid.gd
@@ -0,0 +1,5 @@
+@uid("uid://c4ckv3ryprcn4")
+extends Object
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/parser/features/uid.out b/modules/gdscript/tests/scripts/parser/features/uid.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/uid.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/test_completion.h b/modules/gdscript/tests/test_completion.h
index abc34bd4bf..fd6b5321e6 100644
--- a/modules/gdscript/tests/test_completion.h
+++ b/modules/gdscript/tests/test_completion.h
@@ -128,19 +128,23 @@ static void test_directory(const String &p_dir) {
EditorSettings::get_singleton()->set_setting("text_editor/completion/use_single_quotes", conf.get_value("input", "use_single_quotes", false));
List<Dictionary> include;
- to_dict_list(conf.get_value("result", "include", Array()), include);
+ to_dict_list(conf.get_value("output", "include", Array()), include);
List<Dictionary> exclude;
- to_dict_list(conf.get_value("result", "exclude", Array()), exclude);
+ to_dict_list(conf.get_value("output", "exclude", Array()), exclude);
List<ScriptLanguage::CodeCompletionOption> options;
String call_hint;
bool forced;
Node *owner = nullptr;
- if (dir->file_exists(next.get_basename() + ".tscn")) {
- String project_path = "res://completion";
- Ref<PackedScene> scene = ResourceLoader::load(project_path.path_join(next.get_basename() + ".tscn"), "PackedScene");
+ if (conf.has_section_key("input", "scene")) {
+ Ref<PackedScene> scene = ResourceLoader::load(conf.get_value("input", "scene"), "PackedScene");
+ if (scene.is_valid()) {
+ owner = scene->instantiate();
+ }
+ } else if (dir->file_exists(next.get_basename() + ".tscn")) {
+ Ref<PackedScene> scene = ResourceLoader::load(path.path_join(next.get_basename() + ".tscn"), "PackedScene");
if (scene.is_valid()) {
owner = scene->instantiate();
}
@@ -169,8 +173,8 @@ static void test_directory(const String &p_dir) {
CHECK_MESSAGE(contains_excluded.is_empty(), "Autocompletion suggests illegal option '", contains_excluded, "' for '", path.path_join(next), "'.");
CHECK(include.is_empty());
- String expected_call_hint = conf.get_value("result", "call_hint", call_hint);
- bool expected_forced = conf.get_value("result", "forced", forced);
+ String expected_call_hint = conf.get_value("output", "call_hint", call_hint);
+ bool expected_forced = conf.get_value("output", "forced", forced);
CHECK(expected_call_hint == call_hint);
CHECK(expected_forced == forced);
diff --git a/modules/gdscript/tests/test_gdscript_uid.h b/modules/gdscript/tests/test_gdscript_uid.h
new file mode 100644
index 0000000000..918fe65890
--- /dev/null
+++ b/modules/gdscript/tests/test_gdscript_uid.h
@@ -0,0 +1,115 @@
+/**************************************************************************/
+/* test_gdscript_uid.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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_GDSCRIPT_UID_H
+#define TEST_GDSCRIPT_UID_H
+
+#ifdef TOOLS_ENABLED
+
+#include "core/io/resource_saver.h"
+#include "core/os/os.h"
+#include "gdscript_test_runner.h"
+
+#include "../gdscript.h"
+#include "tests/test_macros.h"
+
+namespace GDScriptTests {
+
+static HashMap<String, ResourceUID::ID> id_cache;
+
+ResourceUID::ID _resource_saver_get_resource_id_for_path(const String &p_path, bool p_generate) {
+ return ResourceUID::get_singleton()->text_to_id("uid://baba");
+}
+
+static void test_script(const String &p_source, const String &p_target_source) {
+ const String script_path = OS::get_singleton()->get_cache_path().path_join("script.gd");
+
+ Ref<GDScript> script;
+ script.instantiate();
+ script->set_source_code(p_source);
+ ResourceSaver::save(script, script_path);
+
+ Ref<FileAccess> fa = FileAccess::open(script_path, FileAccess::READ);
+ CHECK_EQ(fa->get_as_text(), p_target_source);
+}
+
+TEST_SUITE("[Modules][GDScript][UID]") {
+ TEST_CASE("[ResourceSaver] Adding UID line to script") {
+ init_language("modules/gdscript/tests/scripts");
+ ResourceSaver::set_get_resource_id_for_path(_resource_saver_get_resource_id_for_path);
+
+ const String source = R"(extends Node
+class_name TestClass
+)";
+ const String final_source = R"(@uid("uid://baba") # Generated automatically, do not modify.
+extends Node
+class_name TestClass
+)";
+
+ // Script has no UID, add it.
+ test_script(source, final_source);
+ }
+
+ TEST_CASE("[ResourceSaver] Updating UID line in script") {
+ init_language("modules/gdscript/tests/scripts");
+ ResourceSaver::set_get_resource_id_for_path(_resource_saver_get_resource_id_for_path);
+
+ const String wrong_id_source = R"(
+
+@uid(
+ "uid://dead"
+ ) # G
+extends Node
+class_name TestClass
+)";
+ const String corrected_id_source = R"(
+
+@uid("uid://baba") # Generated automatically, do not modify.
+extends Node
+class_name TestClass
+)";
+ const String correct_id_source = R"(@uid("uid://baba") # G
+extends Node
+class_name TestClass
+)";
+
+ // Script has wrong UID saved. Remove it and add a correct one.
+ // Inserts in the same line, but multiline annotations are flattened.
+ test_script(wrong_id_source, corrected_id_source);
+ // The stored UID is correct, so do not modify it.
+ test_script(correct_id_source, correct_id_source);
+ }
+}
+
+} // namespace GDScriptTests
+
+#endif
+
+#endif // TEST_GDSCRIPT_UID_H