feat: modules moved and engine moved to submodule

This commit is contained in:
Jan van der Weide 2025-04-12 18:40:44 +02:00
parent dfb5e645cd
commit c33d2130cc
5136 changed files with 225275 additions and 64485 deletions

View file

@ -478,7 +478,7 @@ void GDScriptTest::error_handler(void *p_this, const char *p_function, const cha
if (include_source_info) {
header += vformat(" at %s:%d on %s()",
String::utf8(p_file).trim_prefix(self->base_dir).replace("\\", "/"),
String::utf8(p_file).trim_prefix(self->base_dir).replace_char('\\', '/'),
p_line,
String::utf8(p_function));
}

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GDSCRIPT_TEST_RUNNER_H
#define GDSCRIPT_TEST_RUNNER_H
#pragma once
#include "../gdscript.h"
@ -136,5 +135,3 @@ public:
};
} // namespace GDScriptTests
#endif // GDSCRIPT_TEST_RUNNER_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GDSCRIPT_TEST_RUNNER_SUITE_H
#define GDSCRIPT_TEST_RUNNER_SUITE_H
#pragma once
#include "gdscript_test_runner.h"
@ -81,9 +80,8 @@ TEST_CASE("[Modules][GDScript] Validate built-in API") {
SUBCASE("[Modules][GDScript] Validate built-in methods") {
for (const MethodInfo &mi : builtin_methods) {
int i = 0;
for (List<PropertyInfo>::ConstIterator itr = mi.arguments.begin(); itr != mi.arguments.end(); ++itr, ++i) {
TEST_COND((itr->name.is_empty() || itr->name.begins_with("_unnamed_arg")),
for (int64_t i = 0; i < mi.arguments.size(); ++i) {
TEST_COND((mi.arguments[i].name.is_empty() || mi.arguments[i].name.begins_with("_unnamed_arg")),
vformat("Unnamed argument in position %d of built-in method '%s'.", i, mi.name));
}
}
@ -95,9 +93,8 @@ TEST_CASE("[Modules][GDScript] Validate built-in API") {
SUBCASE("[Modules][GDScript] Validate built-in annotations") {
for (const MethodInfo &ai : builtin_annotations) {
int i = 0;
for (List<PropertyInfo>::ConstIterator itr = ai.arguments.begin(); itr != ai.arguments.end(); ++itr, ++i) {
TEST_COND((itr->name.is_empty() || itr->name.begins_with("_unnamed_arg")),
for (int64_t i = 0; i < ai.arguments.size(); ++i) {
TEST_COND((ai.arguments[i].name.is_empty() || ai.arguments[i].name.begins_with("_unnamed_arg")),
vformat("Unnamed argument in position %d of built-in annotation '%s'.", i, ai.name));
}
}
@ -105,5 +102,3 @@ TEST_CASE("[Modules][GDScript] Validate built-in API") {
}
} // namespace GDScriptTests
#endif // GDSCRIPT_TEST_RUNNER_SUITE_H

View file

@ -1,3 +1,5 @@
extends Node
@onready var anim := $AnimationPlayer
func test():

View file

@ -1,3 +1,5 @@
extends Node
@onready var anim: AnimationPlayer = $AnimationPlayer
func test():

View file

@ -1,3 +1,5 @@
extends Node
@onready var anim = $AnimationPlayer
func test():

View file

@ -0,0 +1,5 @@
[output]
include=[
; GDScript: class_a.notest.gd
{"display": "func_of_a()"},
]

View file

@ -0,0 +1,7 @@
extends "res://completion/class_a.notest.gd"
func test():
super.
if true:
pass

View file

@ -0,0 +1,5 @@
[output]
include=[
; GDScript: class_a.notest.gd
{"display": "func_of_a()"},
]

View file

@ -0,0 +1,7 @@
extends "res://completion/class_a.notest.gd"
func test():
super.f
if true:
pass

View file

@ -1,5 +1,5 @@
extends Node
func a():
%AnimationPlayer.
$UniqueAnimationPlayer.
pass

View file

@ -1,5 +1,5 @@
extends Node
func a():
$UniqueAnimationPlayer.
%AnimationPlayer.
pass

View file

@ -1,6 +1,6 @@
extends Node
var test = $A
@onready var test = $A
func a():
test.

View file

@ -1,6 +1,6 @@
extends Node
var test = $AnimationPlayer
@onready var test = $AnimationPlayer
func a():
test.

View file

@ -1,6 +1,6 @@
extends Node
var test: AnimationPlayer = $AnimationPlayer
@onready var test: AnimationPlayer = $AnimationPlayer
func a():
test.

View file

@ -1,6 +1,6 @@
extends Node
var test: Node = $A
@onready var test: Node = $A
func a():
test.

View file

@ -1,6 +1,6 @@
extends Node
var test: Node = $AnimationPlayer
@onready var test: Node = $AnimationPlayer
func a():
test.

View file

@ -1,6 +1,6 @@
extends Node
var test: Area2D = $A
@onready var test: Area2D = $A
func a():
test.

View file

@ -1,6 +1,6 @@
extends Node
var test: Area2D = $AnimationPlayer
@onready var test: Area2D = $AnimationPlayer
func a():
test.

View file

@ -0,0 +1,8 @@
[output]
include=[
{"display": "hello_world", "insert_text": "hello_world"},
]
exclude=[
{"insert_text": "hello_world()"},
{"insert_text": "hello_world("},
]

View file

@ -0,0 +1,8 @@
signal test
func _init() -> void:
test.connect(h)
pass
func hello_world():
pass

View file

@ -0,0 +1,8 @@
[output]
include=[
{"display": "hello_world", "insert_text": "hello_world"},
]
exclude=[
{"insert_text": "hello_world()"},
{"insert_text": "hello_world("},
]

View file

@ -0,0 +1,8 @@
var arr: Array
func _init() -> void:
arr.sort_custom(h
pass
func hello_world():
pass

View file

@ -0,0 +1,8 @@
[output]
include=[
{"display": "hello_world", "insert_text": "hello_world"},
]
exclude=[
{"insert_text": "hello_world()"},
{"insert_text": "hello_world("},
]

View file

@ -0,0 +1,9 @@
func test(a: Callable, b):
pass
func _init() -> void:
test(h)
pass
func hello_world():
pass

View file

@ -0,0 +1,8 @@
[output]
include=[
{"display": "hello_world", "insert_text": "hello_world"},
]
exclude=[
{"insert_text": "hello_world()"},
{"insert_text": "hello_world("},
]

View file

@ -0,0 +1,9 @@
func test(a, b: Callable):
pass
func _init() -> void:
test(hello_world(), h)
pass
func hello_world():
pass

View file

@ -0,0 +1,8 @@
[output]
include=[
{"display": "hello_world()", "insert_text": "hello_world()"},
]
exclude=[
{"insert_text": "hello_world"},
{"insert_text": "hello_world("},
]

View file

@ -0,0 +1,9 @@
func test(a, b: Callable):
pass
func _init() -> void:
test(h)
pass
func hello_world():
pass

View file

@ -0,0 +1,8 @@
[output]
include=[
{"display": "hello_world", "insert_text": "hello_world"},
]
exclude=[
{"display": "hello_world", "insert_text": "hello_world()"},
{"display": "hello_world", "insert_text": "hello_world("},
]

View file

@ -0,0 +1,8 @@
extends Node
func _init() -> void:
create_tween().tween_callback(h)
pass
func hello_world():
pass

View file

@ -0,0 +1,5 @@
class_name Test
extends Node
func _init():
pass

View file

@ -0,0 +1,12 @@
# TODO: This test is currently disabled since it triggers some complex memory leaks. Try enabling it again once GH-101830 is fixed.
signal finished
const scr: GDScript = preload("reload_suspended_function_helper.notest.gd")
func test():
@warning_ignore("UNSAFE_METHOD_ACCESS")
scr.test(self)
@warning_ignore("RETURN_VALUE_DISCARDED")
scr.reload(true)
finished.emit()

View file

@ -0,0 +1,2 @@
GDTEST_RUNTIME_ERROR
>> WARNING: Canceling suspended execution of "test" due to a script reload.

View file

@ -0,0 +1,3 @@
static func test(a):
await a.finished
pass

View file

@ -0,0 +1,26 @@
var array_var: Array = ["one", "two", "three", "four"]
const array_const: Array = ["one", "two", "three", "four"]
var array_nested_var: Array = [["one"], ["two"], ["three"], ["four"]]
const array_nested_const: Array = [["one"], ["two"], ["three"], ["four"]]
func test():
Utils.check(array_const.is_read_only() == true)
Utils.check(array_nested_const.is_read_only() == true)
print("TEST Callable::callv")
print_four_variants.callv(array_var)
print_four_variants.callv(array_const)
print_four_variants.callv(array_nested_var)
print_four_variants.callv(array_nested_const)
print("TEST Object::callv")
self.callv("print_four_variants", array_var)
self.callv("print_four_variants", array_const)
self.callv("print_four_variants", array_nested_var)
self.callv("print_four_variants", array_nested_const)
func print_four_variants(v1, v2, v3, v4):
print("%s %s %s %s" % [v1, v2, v3, v4])

View file

@ -0,0 +1,11 @@
GDTEST_OK
TEST Callable::callv
one two three four
one two three four
["one"] ["two"] ["three"] ["four"]
["one"] ["two"] ["three"] ["four"]
TEST Object::callv
one two three four
one two three four
["one"] ["two"] ["three"] ["four"]
["one"] ["two"] ["three"] ["four"]

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef TEST_COMPLETION_H
#define TEST_COMPLETION_H
#pragma once
#ifdef TOOLS_ENABLED
@ -161,6 +160,8 @@ static void test_directory(const String &p_dir) {
owner = scene->get_node(conf.get_value("input", "node_path", "."));
}
// The only requirement is for the script to be parsable, warnings and errors from the analyzer might happen and completion should still work.
ERR_PRINT_OFF;
if (owner != nullptr) {
// Remove the line which contains the sentinel char, to get a valid script.
Ref<GDScript> scr;
@ -184,6 +185,8 @@ static void test_directory(const String &p_dir) {
}
GDScriptLanguage::get_singleton()->complete_code(code, res_path, owner, &options, forced, call_hint);
ERR_PRINT_ON;
String contains_excluded;
for (ScriptLanguage::CodeCompletionOption &option : options) {
for (const Dictionary &E : exclude) {
@ -232,5 +235,3 @@ TEST_SUITE("[Modules][GDScript][Completion]") {
} // namespace GDScriptTests
#endif
#endif // TEST_COMPLETION_H

View file

@ -309,8 +309,7 @@ void test(TestType p_type) {
fa->get_buffer(buf.ptrw(), flen);
buf.write[flen] = 0;
String code;
code.parse_utf8((const char *)&buf[0]);
String code = String::utf8((const char *)&buf[0]);
Vector<String> lines;
int last = 0;

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef TEST_GDSCRIPT_H
#define TEST_GDSCRIPT_H
#pragma once
#include "gdscript_test_runner.h"
@ -48,5 +47,3 @@ enum TestType {
void test(TestType p_type);
} // namespace GDScriptTests
#endif // TEST_GDSCRIPT_H

View file

@ -28,11 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef TEST_LSP_H
#define TEST_LSP_H
#pragma once
#ifdef TOOLS_ENABLED
#include "modules/modules_enabled.gen.h" // For jsonrpc.
#ifdef MODULE_JSONRPC_ENABLED
#include "tests/test_macros.h"
#include "../language_server/gdscript_extend_parser.h"
@ -52,15 +55,15 @@
#include "thirdparty/doctest/doctest.h"
template <>
struct doctest::StringMaker<lsp::Position> {
static doctest::String convert(const lsp::Position &p_val) {
struct doctest::StringMaker<LSP::Position> {
static doctest::String convert(const LSP::Position &p_val) {
return p_val.to_string().utf8().get_data();
}
};
template <>
struct doctest::StringMaker<lsp::Range> {
static doctest::String convert(const lsp::Range &p_val) {
struct doctest::StringMaker<LSP::Range> {
static doctest::String convert(const LSP::Range &p_val) {
return p_val.to_string().utf8().get_data();
}
};
@ -102,32 +105,32 @@ GDScriptLanguageProtocol *initialize(const String &p_root) {
return proto;
}
lsp::Position pos(const int p_line, const int p_character) {
lsp::Position p;
LSP::Position pos(const int p_line, const int p_character) {
LSP::Position p;
p.line = p_line;
p.character = p_character;
return p;
}
lsp::Range range(const lsp::Position p_start, const lsp::Position p_end) {
lsp::Range r;
LSP::Range range(const LSP::Position p_start, const LSP::Position p_end) {
LSP::Range r;
r.start = p_start;
r.end = p_end;
return r;
}
lsp::TextDocumentPositionParams pos_in(const lsp::DocumentUri &p_uri, const lsp::Position p_pos) {
lsp::TextDocumentPositionParams params;
LSP::TextDocumentPositionParams pos_in(const LSP::DocumentUri &p_uri, const LSP::Position p_pos) {
LSP::TextDocumentPositionParams params;
params.textDocument.uri = p_uri;
params.position = p_pos;
return params;
}
const lsp::DocumentSymbol *test_resolve_symbol_at(const String &p_uri, const lsp::Position p_pos, const String &p_expected_uri, const String &p_expected_name, const lsp::Range &p_expected_range) {
const LSP::DocumentSymbol *test_resolve_symbol_at(const String &p_uri, const LSP::Position p_pos, const String &p_expected_uri, const String &p_expected_name, const LSP::Range &p_expected_range) {
Ref<GDScriptWorkspace> workspace = GDScriptLanguageProtocol::get_singleton()->get_workspace();
lsp::TextDocumentPositionParams params = pos_in(p_uri, p_pos);
const lsp::DocumentSymbol *symbol = workspace->resolve_symbol(params);
LSP::TextDocumentPositionParams params = pos_in(p_uri, p_pos);
const LSP::DocumentSymbol *symbol = workspace->resolve_symbol(params);
CHECK(symbol);
if (symbol) {
@ -140,7 +143,7 @@ const lsp::DocumentSymbol *test_resolve_symbol_at(const String &p_uri, const lsp
}
struct InlineTestData {
lsp::Range range;
LSP::Range range;
String text;
String name;
String ref;
@ -257,7 +260,7 @@ void test_resolve_symbol(const String &p_uri, const InlineTestData &p_test_data,
REQUIRE_MESSAGE(target, vformat("No target for ref '%s'", p_test_data.ref));
Ref<GDScriptWorkspace> workspace = GDScriptLanguageProtocol::get_singleton()->get_workspace();
lsp::Position pos = p_test_data.range.start;
LSP::Position pos = p_test_data.range.start;
SUBCASE("start of identifier") {
pos.character = p_test_data.range.start.character;
@ -308,17 +311,17 @@ void assert_no_errors_in(const String &p_path) {
REQUIRE_MESSAGE(err == OK, vformat("Errors while analyzing '%s'", p_path));
}
inline lsp::Position lsp_pos(int line, int character) {
lsp::Position p;
inline LSP::Position lsp_pos(int line, int character) {
LSP::Position p;
p.line = line;
p.character = character;
return p;
}
void test_position_roundtrip(lsp::Position p_lsp, GodotPosition p_gd, const PackedStringArray &p_lines) {
void test_position_roundtrip(LSP::Position p_lsp, GodotPosition p_gd, const PackedStringArray &p_lines) {
GodotPosition actual_gd = GodotPosition::from_lsp(p_lsp, p_lines);
CHECK_EQ(p_gd, actual_gd);
lsp::Position actual_lsp = p_gd.to_lsp(p_lines);
LSP::Position actual_lsp = p_gd.to_lsp(p_lines);
CHECK_EQ(p_lsp, actual_lsp);
}
@ -343,25 +346,25 @@ func f():
PackedStringArray lines = code.split("\n");
SUBCASE("line after end") {
lsp::Position lsp = lsp_pos(7, 0);
LSP::Position lsp = lsp_pos(7, 0);
GodotPosition gd(8, 1);
test_position_roundtrip(lsp, gd, lines);
}
SUBCASE("first char in first line") {
lsp::Position lsp = lsp_pos(0, 0);
LSP::Position lsp = lsp_pos(0, 0);
GodotPosition gd(1, 1);
test_position_roundtrip(lsp, gd, lines);
}
SUBCASE("with tabs") {
// On `v` in `value` in `var value := ...`.
lsp::Position lsp = lsp_pos(5, 6);
LSP::Position lsp = lsp_pos(5, 6);
GodotPosition gd(6, 13);
test_position_roundtrip(lsp, gd, lines);
}
SUBCASE("doesn't fail with column outside of character length") {
lsp::Position lsp = lsp_pos(2, 100);
LSP::Position lsp = lsp_pos(2, 100);
GodotPosition::from_lsp(lsp, lines);
GodotPosition gd(3, 100);
@ -369,7 +372,7 @@ func f():
}
SUBCASE("doesn't fail with line outside of line length") {
lsp::Position lsp = lsp_pos(200, 100);
LSP::Position lsp = lsp_pos(200, 100);
GodotPosition::from_lsp(lsp, lines);
GodotPosition gd(300, 100);
@ -378,26 +381,26 @@ func f():
SUBCASE("special case: zero column for root class") {
GodotPosition gd(1, 0);
lsp::Position expected = lsp_pos(0, 0);
lsp::Position actual = gd.to_lsp(lines);
LSP::Position expected = lsp_pos(0, 0);
LSP::Position actual = gd.to_lsp(lines);
CHECK_EQ(actual, expected);
}
SUBCASE("special case: zero line and column for root class") {
GodotPosition gd(0, 0);
lsp::Position expected = lsp_pos(0, 0);
lsp::Position actual = gd.to_lsp(lines);
LSP::Position expected = lsp_pos(0, 0);
LSP::Position actual = gd.to_lsp(lines);
CHECK_EQ(actual, expected);
}
SUBCASE("special case: negative line for root class") {
GodotPosition gd(-1, 0);
lsp::Position expected = lsp_pos(0, 0);
lsp::Position actual = gd.to_lsp(lines);
LSP::Position expected = lsp_pos(0, 0);
LSP::Position actual = gd.to_lsp(lines);
CHECK_EQ(actual, expected);
}
SUBCASE("special case: lines.length() + 1 for root class") {
GodotPosition gd(lines.size() + 1, 0);
lsp::Position expected = lsp_pos(lines.size(), 0);
lsp::Position actual = gd.to_lsp(lines);
LSP::Position expected = lsp_pos(lines.size(), 0);
LSP::Position actual = gd.to_lsp(lines);
CHECK_EQ(actual, expected);
}
}
@ -489,15 +492,21 @@ func f():
REQUIRE(proto);
SUBCASE("selectionRange of root class must be inside range") {
String path = "res://lsp/first_line_comment.gd";
assert_no_errors_in(path);
GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_local_script(path);
ExtendGDScriptParser *parser = GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_results[path];
REQUIRE(parser);
lsp::DocumentSymbol cls = parser->get_symbols();
LocalVector<String> paths = {
"res://lsp/first_line_comment.gd", // Comment on first line
"res://lsp/first_line_class_name.gd", // class_name (and thus selection range) before extends
};
REQUIRE(((cls.range.start.line == cls.selectionRange.start.line && cls.range.start.character <= cls.selectionRange.start.character) || (cls.range.start.line < cls.selectionRange.start.line)));
REQUIRE(((cls.range.end.line == cls.selectionRange.end.line && cls.range.end.character >= cls.selectionRange.end.character) || (cls.range.end.line > cls.selectionRange.end.line)));
for (const String &path : paths) {
assert_no_errors_in(path);
GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_local_script(path);
ExtendGDScriptParser *parser = GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_results[path];
REQUIRE(parser);
LSP::DocumentSymbol cls = parser->get_symbols();
REQUIRE(((cls.range.start.line == cls.selectionRange.start.line && cls.range.start.character <= cls.selectionRange.start.character) || (cls.range.start.line < cls.selectionRange.start.line)));
REQUIRE(((cls.range.end.line == cls.selectionRange.end.line && cls.range.end.character >= cls.selectionRange.end.character) || (cls.range.end.line > cls.selectionRange.end.line)));
}
}
memdelete(proto);
@ -507,6 +516,6 @@ func f():
} // namespace GDScriptTests
#endif // TOOLS_ENABLED
#endif // MODULE_JSONRPC_ENABLED
#endif // TEST_LSP_H
#endif // TOOLS_ENABLED