You've already forked godot
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:
@@ -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:
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[gd_scene load_steps=1 format=3 uid="uid://dl28pdkxcjvym"]
|
||||||
|
|
||||||
|
[node name="GetNode" type="Node"]
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
[input]
|
||||||
|
scene="res://completion/argument_options/argument_options.tscn"
|
||||||
|
[output]
|
||||||
|
include=[
|
||||||
|
; Node
|
||||||
|
{"display": "\"signal_a\""},
|
||||||
|
{"display": "\"child_entered_tree\""},
|
||||||
|
]
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
signal signal_a()
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
connect(➡)
|
||||||
|
pass
|
||||||
@@ -2,3 +2,4 @@ extends Node
|
|||||||
|
|
||||||
func a():
|
func a():
|
||||||
%AnimationPlayer.➡
|
%AnimationPlayer.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ extends Node
|
|||||||
|
|
||||||
func a():
|
func a():
|
||||||
$UniqueAnimationPlayer.➡
|
$UniqueAnimationPlayer.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ extends Node
|
|||||||
|
|
||||||
func a():
|
func a():
|
||||||
$A.➡
|
$A.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ extends Node
|
|||||||
|
|
||||||
func a():
|
func a():
|
||||||
$AnimationPlayer.➡
|
$AnimationPlayer.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ extends Node
|
|||||||
|
|
||||||
func a():
|
func a():
|
||||||
%UniqueA.➡
|
%UniqueA.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ extends Node
|
|||||||
|
|
||||||
func a():
|
func a():
|
||||||
%UniqueAnimationPlayer.➡
|
%UniqueAnimationPlayer.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ extends Node
|
|||||||
func a():
|
func a():
|
||||||
var test = $AnimationPlayer
|
var test = $AnimationPlayer
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ extends Node
|
|||||||
func a():
|
func a():
|
||||||
var test := $AnimationPlayer
|
var test := $AnimationPlayer
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ extends Node
|
|||||||
func a():
|
func a():
|
||||||
var test := $A
|
var test := $A
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ extends Node
|
|||||||
func a():
|
func a():
|
||||||
var test := $AnimationPlayer
|
var test := $AnimationPlayer
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ extends Node
|
|||||||
func a():
|
func a():
|
||||||
var test = $A
|
var test = $A
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ extends Node
|
|||||||
func a():
|
func a():
|
||||||
var test = $AnimationPlayer
|
var test = $AnimationPlayer
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ extends Node
|
|||||||
func a():
|
func a():
|
||||||
var test: AnimationPlayer = $AnimationPlayer
|
var test: AnimationPlayer = $AnimationPlayer
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ extends Node
|
|||||||
func a():
|
func a():
|
||||||
var test: AnimationPlayer = $AnimationPlayer
|
var test: AnimationPlayer = $AnimationPlayer
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ extends Node
|
|||||||
func a():
|
func a():
|
||||||
var test: Node = $A
|
var test: Node = $A
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ extends Node
|
|||||||
func a():
|
func a():
|
||||||
var test: Node = $AnimationPlayer
|
var test: Node = $AnimationPlayer
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ extends Node
|
|||||||
func a():
|
func a():
|
||||||
var test: Area2D = $A
|
var test: Area2D = $A
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ extends Node
|
|||||||
func a():
|
func a():
|
||||||
var test: Area2D = $AnimationPlayer
|
var test: Area2D = $AnimationPlayer
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ var test = $AnimationPlayer
|
|||||||
|
|
||||||
func a():
|
func a():
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ var test := $AnimationPlayer
|
|||||||
|
|
||||||
func a():
|
func a():
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ var test := $A
|
|||||||
|
|
||||||
func a():
|
func a():
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ var test := $AnimationPlayer
|
|||||||
|
|
||||||
func a():
|
func a():
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ var test = $A
|
|||||||
|
|
||||||
func a():
|
func a():
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ var test = $AnimationPlayer
|
|||||||
|
|
||||||
func a():
|
func a():
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -6,3 +6,4 @@ var test: A = $A
|
|||||||
|
|
||||||
func a():
|
func a():
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ var test: AnimationPlayer = $AnimationPlayer
|
|||||||
|
|
||||||
func a():
|
func a():
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -6,3 +6,4 @@ const A := preload("res://completion/class_a.notest.gd")
|
|||||||
|
|
||||||
func a():
|
func a():
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ var test: AnimationPlayer = $AnimationPlayer
|
|||||||
|
|
||||||
func a():
|
func a():
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ var test: Node = $A
|
|||||||
|
|
||||||
func a():
|
func a():
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ var test: Node = $AnimationPlayer
|
|||||||
|
|
||||||
func a():
|
func a():
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ var test: Area2D = $A
|
|||||||
|
|
||||||
func a():
|
func a():
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ var test: Area2D = $AnimationPlayer
|
|||||||
|
|
||||||
func a():
|
func a():
|
||||||
test.➡
|
test.➡
|
||||||
|
pass
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user