1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-23 15:16:17 +00:00

Completion Tests: Add script to owner

This commit is contained in:
HolonProduction
2024-03-25 16:11:44 +01:00
parent fe01776f05
commit d2c2194937
39 changed files with 100 additions and 11 deletions

View File

@@ -13,6 +13,12 @@ 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. 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 script files won't be parsable GDScript since it contains an invalid char and and often the code is not complete during autocompletion. To allow for a valid base when used with a scene, the
runner will remove the line which contains `➡`. Therefore the scripts need to be valid if this line is removed, otherwise the test might behave in unexpected ways. This may for example require
adding an additional `pass` statement.
This also means, that the runner will add the script to its owner node, so the script should not be loaded through the scene file.
The config file contains two section: The config file contains two section:
`[input]` contains keys that configure the test environment. The following keys are possible: `[input]` contains keys that configure the test environment. The following keys are possible:
@@ -20,6 +26,7 @@ The config file contains two section:
- `cs: boolean = false`: If `true`, the test will be skipped when running a non C# build. - `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. - `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. - `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.
- `node_path: String`: The node path of the node which holds the current script inside of the scene. Defaults to the scene root node.
`[output]` specifies the expected results for the test. The following key are supported: `[output]` specifies the expected results for the test. The following key are supported:

View File

@@ -0,0 +1,3 @@
[gd_scene load_steps=1 format=3 uid="uid://dl28pdkxcjvym"]
[node name="GetNode" type="Node"]

View File

@@ -0,0 +1,8 @@
[input]
scene="res://completion/argument_options/argument_options.tscn"
[output]
include=[
; Node
{"display": "\"signal_a\""},
{"display": "\"child_entered_tree\""},
]

View File

@@ -0,0 +1,7 @@
extends Node
signal signal_a()
func _ready():
connect()
pass

View File

@@ -2,3 +2,4 @@ extends Node
func a(): func a():
%AnimationPlayer. %AnimationPlayer.
pass

View File

@@ -2,3 +2,4 @@ extends Node
func a(): func a():
$UniqueAnimationPlayer. $UniqueAnimationPlayer.
pass

View File

@@ -2,3 +2,4 @@ extends Node
func a(): func a():
$A. $A.
pass

View File

@@ -2,3 +2,4 @@ extends Node
func a(): func a():
$AnimationPlayer. $AnimationPlayer.
pass

View File

@@ -2,3 +2,4 @@ extends Node
func a(): func a():
%UniqueA. %UniqueA.
pass

View File

@@ -2,3 +2,4 @@ extends Node
func a(): func a():
%UniqueAnimationPlayer. %UniqueAnimationPlayer.
pass

View File

@@ -3,3 +3,4 @@ extends Node
func a(): func a():
var test = $AnimationPlayer var test = $AnimationPlayer
test. test.
pass

View File

@@ -3,3 +3,4 @@ extends Node
func a(): func a():
var test := $AnimationPlayer var test := $AnimationPlayer
test. test.
pass

View File

@@ -3,3 +3,4 @@ extends Node
func a(): func a():
var test := $A var test := $A
test. test.
pass

View File

@@ -3,3 +3,4 @@ extends Node
func a(): func a():
var test := $AnimationPlayer var test := $AnimationPlayer
test. test.
pass

View File

@@ -3,3 +3,4 @@ extends Node
func a(): func a():
var test = $A var test = $A
test. test.
pass

View File

@@ -3,3 +3,4 @@ extends Node
func a(): func a():
var test = $AnimationPlayer var test = $AnimationPlayer
test. test.
pass

View File

@@ -5,3 +5,4 @@ const A := preload("res://completion/class_a.notest.gd")
func a(): func a():
var test: A = $A var test: A = $A
test. test.
pass

View File

@@ -3,3 +3,4 @@ extends Node
func a(): func a():
var test: AnimationPlayer = $AnimationPlayer var test: AnimationPlayer = $AnimationPlayer
test. test.
pass

View File

@@ -5,3 +5,4 @@ const A := preload("res://completion/class_a.notest.gd")
func a(): func a():
var test: A = $A var test: A = $A
test. test.
pass

View File

@@ -3,3 +3,4 @@ extends Node
func a(): func a():
var test: AnimationPlayer = $AnimationPlayer var test: AnimationPlayer = $AnimationPlayer
test. test.
pass

View File

@@ -4,3 +4,4 @@ extends Node
func a(): func a():
var test: Node = $A var test: Node = $A
test. test.
pass

View File

@@ -4,3 +4,4 @@ extends Node
func a(): func a():
var test: Node = $AnimationPlayer var test: Node = $AnimationPlayer
test. test.
pass

View File

@@ -3,3 +3,4 @@ extends Node
func a(): func a():
var test: Area2D = $A var test: Area2D = $A
test. test.
pass

View File

@@ -3,3 +3,4 @@ extends Node
func a(): func a():
var test: Area2D = $AnimationPlayer var test: Area2D = $AnimationPlayer
test. test.
pass

View File

@@ -4,3 +4,4 @@ var test = $AnimationPlayer
func a(): func a():
test. test.
pass

View File

@@ -4,3 +4,4 @@ var test := $AnimationPlayer
func a(): func a():
test. test.
pass

View File

@@ -4,3 +4,4 @@ var test := $A
func a(): func a():
test. test.
pass

View File

@@ -4,3 +4,4 @@ var test := $AnimationPlayer
func a(): func a():
test. test.
pass

View File

@@ -4,3 +4,4 @@ var test = $A
func a(): func a():
test. test.
pass

View File

@@ -4,3 +4,4 @@ var test = $AnimationPlayer
func a(): func a():
test. test.
pass

View File

@@ -6,3 +6,4 @@ var test: A = $A
func a(): func a():
test. test.
pass

View File

@@ -4,3 +4,4 @@ var test: AnimationPlayer = $AnimationPlayer
func a(): func a():
test. test.
pass

View File

@@ -6,3 +6,4 @@ const A := preload("res://completion/class_a.notest.gd")
func a(): func a():
test. test.
pass

View File

@@ -4,3 +4,4 @@ var test: AnimationPlayer = $AnimationPlayer
func a(): func a():
test. test.
pass

View File

@@ -4,3 +4,4 @@ var test: Node = $A
func a(): func a():
test. test.
pass

View File

@@ -4,3 +4,4 @@ var test: Node = $AnimationPlayer
func a(): func a():
test. test.
pass

View File

@@ -4,3 +4,4 @@ var test: Area2D = $A
func a(): func a():
test. test.
pass

View File

@@ -4,3 +4,4 @@ var test: Area2D = $AnimationPlayer
func a(): func a():
test. test.
pass

View File

@@ -33,6 +33,7 @@
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
#include "core/config/project_settings.h"
#include "core/io/config_file.h" #include "core/io/config_file.h"
#include "core/io/dir_access.h" #include "core/io/dir_access.h"
#include "core/io/file_access.h" #include "core/io/file_access.h"
@@ -111,7 +112,10 @@ static void test_directory(const String &p_dir) {
// For ease of reading ➡ (0x27A1) acts as sentinel char instead of 0xFFFF in the files. // For ease of reading ➡ (0x27A1) acts as sentinel char instead of 0xFFFF in the files.
code = code.replace_first(String::chr(0x27A1), String::chr(0xFFFF)); code = code.replace_first(String::chr(0x27A1), String::chr(0xFFFF));
// Require pointer sentinel char in scripts. // Require pointer sentinel char in scripts.
CHECK(code.find_char(0xFFFF) != -1); int location = code.find_char(0xFFFF);
CHECK(location != -1);
String res_path = ProjectSettings::get_singleton()->localize_path(path.path_join(next));
ConfigFile conf; ConfigFile conf;
if (conf.load(path.path_join(next.get_basename() + ".cfg")) != OK) { if (conf.load(path.path_join(next.get_basename() + ".cfg")) != OK) {
@@ -137,20 +141,46 @@ static void test_directory(const String &p_dir) {
String call_hint; String call_hint;
bool forced; bool forced;
Node *owner = nullptr; Node *scene = nullptr;
if (conf.has_section_key("input", "scene")) { if (conf.has_section_key("input", "scene")) {
Ref<PackedScene> scene = ResourceLoader::load(conf.get_value("input", "scene"), "PackedScene", ResourceFormatLoader::CACHE_MODE_IGNORE_DEEP); Ref<PackedScene> packed_scene = ResourceLoader::load(conf.get_value("input", "scene"), "PackedScene", ResourceFormatLoader::CACHE_MODE_IGNORE_DEEP);
if (scene.is_valid()) { if (packed_scene.is_valid()) {
owner = scene->instantiate(); scene = packed_scene->instantiate();
} }
} else if (dir->file_exists(next.get_basename() + ".tscn")) { } else if (dir->file_exists(next.get_basename() + ".tscn")) {
Ref<PackedScene> scene = ResourceLoader::load(path.path_join(next.get_basename() + ".tscn"), "PackedScene"); Ref<PackedScene> packed_scene = ResourceLoader::load(path.path_join(next.get_basename() + ".tscn"), "PackedScene");
if (scene.is_valid()) { if (packed_scene.is_valid()) {
owner = scene->instantiate(); scene = packed_scene->instantiate();
} }
} }
Node *owner = nullptr;
if (scene != nullptr) {
owner = scene->get_node(conf.get_value("input", "node_path", "."));
}
GDScriptLanguage::get_singleton()->complete_code(code, path.path_join(next), owner, &options, forced, call_hint); if (owner != nullptr) {
// Remove the line which contains the sentinel char, to get a valid script.
Ref<GDScript> scr;
scr.instantiate();
int start = location;
int end = location;
for (; start >= 0; --start) {
if (code.get(start) == '\n') {
break;
}
}
for (; end < code.size(); ++end) {
if (code.get(end) == '\n') {
break;
}
}
scr->set_source_code(code.erase(start, end - start));
scr->reload();
scr->set_path(res_path);
owner->set_script(scr);
}
GDScriptLanguage::get_singleton()->complete_code(code, res_path, owner, &options, forced, call_hint);
String contains_excluded; String contains_excluded;
for (ScriptLanguage::CodeCompletionOption &option : options) { for (ScriptLanguage::CodeCompletionOption &option : options) {
for (const Dictionary &E : exclude) { for (const Dictionary &E : exclude) {
@@ -179,8 +209,8 @@ static void test_directory(const String &p_dir) {
CHECK(expected_call_hint == call_hint); CHECK(expected_call_hint == call_hint);
CHECK(expected_forced == forced); CHECK(expected_forced == forced);
if (owner) { if (scene) {
memdelete(owner); memdelete(scene);
} }
} }
next = dir->get_next(); next = dir->get_next();