From af4cbaf75125cdb1f37ece93802e75b03af9d96f Mon Sep 17 00:00:00 2001 From: HolonProduction Date: Tue, 21 Nov 2023 16:06:43 +0100 Subject: Add unit test runner for autocompletion --- modules/gdscript/tests/gdscript_test_runner.cpp | 2 +- .../get_node/get_node_member_annotated.cfg | 4 + .../get_node/get_node_member_annotated.gd | 6 + modules/gdscript/tests/scripts/lsp/class.gd | 132 ++++++++++++++ modules/gdscript/tests/scripts/lsp/class.notest.gd | 132 -------------- modules/gdscript/tests/scripts/lsp/enums.gd | 26 +++ modules/gdscript/tests/scripts/lsp/enums.notest.gd | 26 --- modules/gdscript/tests/scripts/lsp/indentation.gd | 28 +++ .../tests/scripts/lsp/indentation.notest.gd | 28 --- modules/gdscript/tests/scripts/lsp/lambdas.gd | 91 ++++++++++ .../gdscript/tests/scripts/lsp/lambdas.notest.gd | 91 ---------- .../gdscript/tests/scripts/lsp/local_variables.gd | 25 +++ .../tests/scripts/lsp/local_variables.notest.gd | 25 --- modules/gdscript/tests/scripts/lsp/properties.gd | 65 +++++++ .../tests/scripts/lsp/properties.notest.gd | 65 ------- modules/gdscript/tests/scripts/lsp/scopes.gd | 106 +++++++++++ .../gdscript/tests/scripts/lsp/scopes.notest.gd | 106 ----------- .../tests/scripts/lsp/shadowing_initializer.gd | 56 ++++++ .../scripts/lsp/shadowing_initializer.notest.gd | 56 ------ modules/gdscript/tests/scripts/project.godot | 2 +- modules/gdscript/tests/test_completion.h | 199 +++++++++++++++++++++ modules/gdscript/tests/test_lsp.h | 18 +- 22 files changed, 749 insertions(+), 540 deletions(-) create mode 100644 modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg create mode 100644 modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.gd create mode 100644 modules/gdscript/tests/scripts/lsp/class.gd delete mode 100644 modules/gdscript/tests/scripts/lsp/class.notest.gd create mode 100644 modules/gdscript/tests/scripts/lsp/enums.gd delete mode 100644 modules/gdscript/tests/scripts/lsp/enums.notest.gd create mode 100644 modules/gdscript/tests/scripts/lsp/indentation.gd delete mode 100644 modules/gdscript/tests/scripts/lsp/indentation.notest.gd create mode 100644 modules/gdscript/tests/scripts/lsp/lambdas.gd delete mode 100644 modules/gdscript/tests/scripts/lsp/lambdas.notest.gd create mode 100644 modules/gdscript/tests/scripts/lsp/local_variables.gd delete mode 100644 modules/gdscript/tests/scripts/lsp/local_variables.notest.gd create mode 100644 modules/gdscript/tests/scripts/lsp/properties.gd delete mode 100644 modules/gdscript/tests/scripts/lsp/properties.notest.gd create mode 100644 modules/gdscript/tests/scripts/lsp/scopes.gd delete mode 100644 modules/gdscript/tests/scripts/lsp/scopes.notest.gd create mode 100644 modules/gdscript/tests/scripts/lsp/shadowing_initializer.gd delete mode 100644 modules/gdscript/tests/scripts/lsp/shadowing_initializer.notest.gd create mode 100644 modules/gdscript/tests/test_completion.h (limited to 'modules/gdscript/tests') diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index 361ca276bb..4d93a6fc18 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -266,7 +266,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) { while (!next.is_empty()) { if (dir->current_is_dir()) { - if (next == "." || next == "..") { + if (next == "." || next == ".." || next == "completion" || next == "lsp") { next = dir->get_next(); continue; } 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 new file mode 100644 index 0000000000..4edee46039 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg @@ -0,0 +1,4 @@ +[output] +expected=[ + {"display": "autoplay"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.gd b/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.gd new file mode 100644 index 0000000000..d41bbb970c --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.gd @@ -0,0 +1,6 @@ +extends Node + +var test: AnimationPlayer = $AnimationPlayer + +func _ready(): + test.➡ diff --git a/modules/gdscript/tests/scripts/lsp/class.gd b/modules/gdscript/tests/scripts/lsp/class.gd new file mode 100644 index 0000000000..53d0b14d72 --- /dev/null +++ b/modules/gdscript/tests/scripts/lsp/class.gd @@ -0,0 +1,132 @@ +extends Node + +class Inner1 extends Node: +# ^^^^^^ class1 -> class1 + var member1 := 42 + # ^^^^^^^ class1:member1 -> class1:member1 + var member2 : int = 13 + # ^^^^^^^ class1:member2 -> class1:member2 + var member3 = 1337 + # ^^^^^^^ class1:member3 -> class1:member3 + + signal changed(old, new) + # ^^^^^^^ class1:signal -> class1:signal + func my_func(arg1: int, arg2: String, arg3): + # | | | | | | ^^^^ class1:func:arg3 -> class1:func:arg3 + # | | | | ^^^^ class1:func:arg2 -> class1:func:arg2 + # | | ^^^^ class1:func:arg1 -> class1:func:arg1 + # ^^^^^^^ class1:func -> class1:func + print(arg1, arg2, arg3) + # | | | | ^^^^ -> class1:func:arg3 + # | | ^^^^ -> class1:func:arg2 + # ^^^^ -> class1:func:arg1 + changed.emit(arg1, arg3) + # | | | ^^^^ -> class1:func:arg3 + # | ^^^^ -> class1:func:arg1 + #<^^^^^ -> class1:signal + return arg1 + arg2.length() + arg3 + # | | | | ^^^^ -> class1:func:arg3 + # | | ^^^^ -> class1:func:arg2 + # ^^^^ -> class1:func:arg1 + +class Inner2: +# ^^^^^^ class2 -> class2 + var member1 := 42 + # ^^^^^^^ class2:member1 -> class2:member1 + var member2 : int = 13 + # ^^^^^^^ class2:member2 -> class2:member2 + var member3 = 1337 + # ^^^^^^^ class2:member3 -> class2:member3 + + signal changed(old, new) + # ^^^^^^^ class2:signal -> class2:signal + func my_func(arg1: int, arg2: String, arg3): + # | | | | | | ^^^^ class2:func:arg3 -> class2:func:arg3 + # | | | | ^^^^ class2:func:arg2 -> class2:func:arg2 + # | | ^^^^ class2:func:arg1 -> class2:func:arg1 + # ^^^^^^^ class2:func -> class2:func + print(arg1, arg2, arg3) + # | | | | ^^^^ -> class2:func:arg3 + # | | ^^^^ -> class2:func:arg2 + # ^^^^ -> class2:func:arg1 + changed.emit(arg1, arg3) + # | | | ^^^^ -> class2:func:arg3 + # | ^^^^ -> class2:func:arg1 + #<^^^^^ -> class2:signal + return arg1 + arg2.length() + arg3 + # | | | | ^^^^ -> class2:func:arg3 + # | | ^^^^ -> class2:func:arg2 + # ^^^^ -> class2:func:arg1 + +class Inner3 extends Inner2: +# | | ^^^^^^ -> class2 +# ^^^^^^ class3 -> class3 + var whatever = "foo" + # ^^^^^^^^ class3:whatever -> class3:whatever + + func _init(): + # ^^^^^ class3:init + # Note: no self-ref check here: resolves to `Object._init`. + # usages of `Inner3.new()` DO resolve to this `_init` + pass + + class NestedInInner3: + # ^^^^^^^^^^^^^^ class3:nested1 -> class3:nested1 + var some_value := 42 + # ^^^^^^^^^^ class3:nested1:some_value -> class3:nested1:some_value + + class AnotherNestedInInner3 extends NestedInInner3: + #! | | ^^^^^^^^^^^^^^ -> class3:nested1 + # ^^^^^^^^^^^^^^^^^^^^^ class3:nested2 -> class3:nested2 + var another_value := 13 + # ^^^^^^^^^^^^^ class3:nested2:another_value -> class3:nested2:another_value + +func _ready(): + var inner1 = Inner1.new() + # | | ^^^^^^ -> class1 + # ^^^^^^ func:class1 -> func:class1 + var value1 = inner1.my_func(1,"",3) + # | | | | ^^^^^^^ -> class1:func + # | | ^^^^^^ -> func:class1 + # ^^^^^^ func:class1:value1 -> func:class1:value1 + var value2 = inner1.member3 + # | | | | ^^^^^^^ -> class1:member3 + # | | ^^^^^^ -> func:class1 + # ^^^^^^ func:class1:value2 -> func:class1:value2 + print(value1, value2) + # | | ^^^^^^ -> func:class1:value2 + # ^^^^^^ -> func:class1:value1 + + var inner3 = Inner3.new() + # | | | | ^^^ -> class3:init + # | | ^^^^^^ -> class3 + # ^^^^^^ func:class3 -> func:class3 + print(inner3) + # ^^^^^^ -> func:class3 + + var nested1 = Inner3.NestedInInner3.new() + # | | | | ^^^^^^^^^^^^^^ -> class3:nested1 + # | | ^^^^^^ -> class3 + # ^^^^^^^ func:class3:nested1 -> func:class3:nested1 + var value_nested1 = nested1.some_value + # | | | | ^^^^^^^^^^ -> class3:nested1:some_value + # | | ^^^^^^^ -> func:class3:nested1 + # ^^^^^^^^^^^^^ func:class3:nested1:value + print(value_nested1) + # ^^^^^^^^^^^^^ -> func:class3:nested1:value + + var nested2 = Inner3.AnotherNestedInInner3.new() + # | | | | ^^^^^^^^^^^^^^^^^^^^^ -> class3:nested2 + # | | ^^^^^^ -> class3 + # ^^^^^^^ func:class3:nested2 -> func:class3:nested2 + var value_nested2 = nested2.some_value + # | | | | ^^^^^^^^^^ -> class3:nested1:some_value + # | | ^^^^^^^ -> func:class3:nested2 + # ^^^^^^^^^^^^^ func:class3:nested2:value + var another_value_nested2 = nested2.another_value + # | | | | ^^^^^^^^^^^^^ -> class3:nested2:another_value + # | | ^^^^^^^ -> func:class3:nested2 + # ^^^^^^^^^^^^^^^^^^^^^ func:class3:nested2:another_value_nested + print(value_nested2, another_value_nested2) + # | | ^^^^^^^^^^^^^^^^^^^^^ -> func:class3:nested2:another_value_nested + # ^^^^^^^^^^^^^ -> func:class3:nested2:value diff --git a/modules/gdscript/tests/scripts/lsp/class.notest.gd b/modules/gdscript/tests/scripts/lsp/class.notest.gd deleted file mode 100644 index 53d0b14d72..0000000000 --- a/modules/gdscript/tests/scripts/lsp/class.notest.gd +++ /dev/null @@ -1,132 +0,0 @@ -extends Node - -class Inner1 extends Node: -# ^^^^^^ class1 -> class1 - var member1 := 42 - # ^^^^^^^ class1:member1 -> class1:member1 - var member2 : int = 13 - # ^^^^^^^ class1:member2 -> class1:member2 - var member3 = 1337 - # ^^^^^^^ class1:member3 -> class1:member3 - - signal changed(old, new) - # ^^^^^^^ class1:signal -> class1:signal - func my_func(arg1: int, arg2: String, arg3): - # | | | | | | ^^^^ class1:func:arg3 -> class1:func:arg3 - # | | | | ^^^^ class1:func:arg2 -> class1:func:arg2 - # | | ^^^^ class1:func:arg1 -> class1:func:arg1 - # ^^^^^^^ class1:func -> class1:func - print(arg1, arg2, arg3) - # | | | | ^^^^ -> class1:func:arg3 - # | | ^^^^ -> class1:func:arg2 - # ^^^^ -> class1:func:arg1 - changed.emit(arg1, arg3) - # | | | ^^^^ -> class1:func:arg3 - # | ^^^^ -> class1:func:arg1 - #<^^^^^ -> class1:signal - return arg1 + arg2.length() + arg3 - # | | | | ^^^^ -> class1:func:arg3 - # | | ^^^^ -> class1:func:arg2 - # ^^^^ -> class1:func:arg1 - -class Inner2: -# ^^^^^^ class2 -> class2 - var member1 := 42 - # ^^^^^^^ class2:member1 -> class2:member1 - var member2 : int = 13 - # ^^^^^^^ class2:member2 -> class2:member2 - var member3 = 1337 - # ^^^^^^^ class2:member3 -> class2:member3 - - signal changed(old, new) - # ^^^^^^^ class2:signal -> class2:signal - func my_func(arg1: int, arg2: String, arg3): - # | | | | | | ^^^^ class2:func:arg3 -> class2:func:arg3 - # | | | | ^^^^ class2:func:arg2 -> class2:func:arg2 - # | | ^^^^ class2:func:arg1 -> class2:func:arg1 - # ^^^^^^^ class2:func -> class2:func - print(arg1, arg2, arg3) - # | | | | ^^^^ -> class2:func:arg3 - # | | ^^^^ -> class2:func:arg2 - # ^^^^ -> class2:func:arg1 - changed.emit(arg1, arg3) - # | | | ^^^^ -> class2:func:arg3 - # | ^^^^ -> class2:func:arg1 - #<^^^^^ -> class2:signal - return arg1 + arg2.length() + arg3 - # | | | | ^^^^ -> class2:func:arg3 - # | | ^^^^ -> class2:func:arg2 - # ^^^^ -> class2:func:arg1 - -class Inner3 extends Inner2: -# | | ^^^^^^ -> class2 -# ^^^^^^ class3 -> class3 - var whatever = "foo" - # ^^^^^^^^ class3:whatever -> class3:whatever - - func _init(): - # ^^^^^ class3:init - # Note: no self-ref check here: resolves to `Object._init`. - # usages of `Inner3.new()` DO resolve to this `_init` - pass - - class NestedInInner3: - # ^^^^^^^^^^^^^^ class3:nested1 -> class3:nested1 - var some_value := 42 - # ^^^^^^^^^^ class3:nested1:some_value -> class3:nested1:some_value - - class AnotherNestedInInner3 extends NestedInInner3: - #! | | ^^^^^^^^^^^^^^ -> class3:nested1 - # ^^^^^^^^^^^^^^^^^^^^^ class3:nested2 -> class3:nested2 - var another_value := 13 - # ^^^^^^^^^^^^^ class3:nested2:another_value -> class3:nested2:another_value - -func _ready(): - var inner1 = Inner1.new() - # | | ^^^^^^ -> class1 - # ^^^^^^ func:class1 -> func:class1 - var value1 = inner1.my_func(1,"",3) - # | | | | ^^^^^^^ -> class1:func - # | | ^^^^^^ -> func:class1 - # ^^^^^^ func:class1:value1 -> func:class1:value1 - var value2 = inner1.member3 - # | | | | ^^^^^^^ -> class1:member3 - # | | ^^^^^^ -> func:class1 - # ^^^^^^ func:class1:value2 -> func:class1:value2 - print(value1, value2) - # | | ^^^^^^ -> func:class1:value2 - # ^^^^^^ -> func:class1:value1 - - var inner3 = Inner3.new() - # | | | | ^^^ -> class3:init - # | | ^^^^^^ -> class3 - # ^^^^^^ func:class3 -> func:class3 - print(inner3) - # ^^^^^^ -> func:class3 - - var nested1 = Inner3.NestedInInner3.new() - # | | | | ^^^^^^^^^^^^^^ -> class3:nested1 - # | | ^^^^^^ -> class3 - # ^^^^^^^ func:class3:nested1 -> func:class3:nested1 - var value_nested1 = nested1.some_value - # | | | | ^^^^^^^^^^ -> class3:nested1:some_value - # | | ^^^^^^^ -> func:class3:nested1 - # ^^^^^^^^^^^^^ func:class3:nested1:value - print(value_nested1) - # ^^^^^^^^^^^^^ -> func:class3:nested1:value - - var nested2 = Inner3.AnotherNestedInInner3.new() - # | | | | ^^^^^^^^^^^^^^^^^^^^^ -> class3:nested2 - # | | ^^^^^^ -> class3 - # ^^^^^^^ func:class3:nested2 -> func:class3:nested2 - var value_nested2 = nested2.some_value - # | | | | ^^^^^^^^^^ -> class3:nested1:some_value - # | | ^^^^^^^ -> func:class3:nested2 - # ^^^^^^^^^^^^^ func:class3:nested2:value - var another_value_nested2 = nested2.another_value - # | | | | ^^^^^^^^^^^^^ -> class3:nested2:another_value - # | | ^^^^^^^ -> func:class3:nested2 - # ^^^^^^^^^^^^^^^^^^^^^ func:class3:nested2:another_value_nested - print(value_nested2, another_value_nested2) - # | | ^^^^^^^^^^^^^^^^^^^^^ -> func:class3:nested2:another_value_nested - # ^^^^^^^^^^^^^ -> func:class3:nested2:value diff --git a/modules/gdscript/tests/scripts/lsp/enums.gd b/modules/gdscript/tests/scripts/lsp/enums.gd new file mode 100644 index 0000000000..38b9ec110a --- /dev/null +++ b/modules/gdscript/tests/scripts/lsp/enums.gd @@ -0,0 +1,26 @@ +extends Node + +enum {UNIT_NEUTRAL, UNIT_ENEMY, UNIT_ALLY} +# | | | | ^^^^^^^^^ enum:unnamed:ally -> enum:unnamed:ally +# | | ^^^^^^^^^^ enum:unnamed:enemy -> enum:unnamed:enemy +# ^^^^^^^^^^^^ enum:unnamed:neutral -> enum:unnamed:neutral +enum Named {THING_1, THING_2, ANOTHER_THING = -1} +# | | | | | | ^^^^^^^^^^^^^ enum:named:thing3 -> enum:named:thing3 +# | | | | ^^^^^^^ enum:named:thing2 -> enum:named:thing2 +# | | ^^^^^^^ enum:named:thing1 -> enum:named:thing1 +# ^^^^^ enum:named -> enum:named + +func f(arg): + match arg: + UNIT_ENEMY: print(UNIT_ENEMY) + # | ^^^^^^^^^^ -> enum:unnamed:enemy + #<^^^^^^^^ -> enum:unnamed:enemy + Named.THING_2: print(Named.THING_2) + #! | | | | | ^^^^^^^ -> enum:named:thing2 + # | | | ^^^^^ -> enum:named + #! | ^^^^^^^ -> enum:named:thing2 + #<^^^ -> enum:named + _: print(UNIT_ENEMY, Named.ANOTHER_THING) + #! | | | | ^^^^^^^^^^^^^ -> enum:named:thing3 + # | | ^^^^^ -> enum:named + # ^^^^^^^^^^ -> enum:unnamed:enemy diff --git a/modules/gdscript/tests/scripts/lsp/enums.notest.gd b/modules/gdscript/tests/scripts/lsp/enums.notest.gd deleted file mode 100644 index 38b9ec110a..0000000000 --- a/modules/gdscript/tests/scripts/lsp/enums.notest.gd +++ /dev/null @@ -1,26 +0,0 @@ -extends Node - -enum {UNIT_NEUTRAL, UNIT_ENEMY, UNIT_ALLY} -# | | | | ^^^^^^^^^ enum:unnamed:ally -> enum:unnamed:ally -# | | ^^^^^^^^^^ enum:unnamed:enemy -> enum:unnamed:enemy -# ^^^^^^^^^^^^ enum:unnamed:neutral -> enum:unnamed:neutral -enum Named {THING_1, THING_2, ANOTHER_THING = -1} -# | | | | | | ^^^^^^^^^^^^^ enum:named:thing3 -> enum:named:thing3 -# | | | | ^^^^^^^ enum:named:thing2 -> enum:named:thing2 -# | | ^^^^^^^ enum:named:thing1 -> enum:named:thing1 -# ^^^^^ enum:named -> enum:named - -func f(arg): - match arg: - UNIT_ENEMY: print(UNIT_ENEMY) - # | ^^^^^^^^^^ -> enum:unnamed:enemy - #<^^^^^^^^ -> enum:unnamed:enemy - Named.THING_2: print(Named.THING_2) - #! | | | | | ^^^^^^^ -> enum:named:thing2 - # | | | ^^^^^ -> enum:named - #! | ^^^^^^^ -> enum:named:thing2 - #<^^^ -> enum:named - _: print(UNIT_ENEMY, Named.ANOTHER_THING) - #! | | | | ^^^^^^^^^^^^^ -> enum:named:thing3 - # | | ^^^^^ -> enum:named - # ^^^^^^^^^^ -> enum:unnamed:enemy diff --git a/modules/gdscript/tests/scripts/lsp/indentation.gd b/modules/gdscript/tests/scripts/lsp/indentation.gd new file mode 100644 index 0000000000..c25d73a719 --- /dev/null +++ b/modules/gdscript/tests/scripts/lsp/indentation.gd @@ -0,0 +1,28 @@ +extends Node + +var root = 0 +# ^^^^ 0_indent -> 0_indent + +func a(): + var alpha: int = root + 42 + # | | ^^^^ -> 0_indent + # ^^^^^ 1_indent -> 1_indent + if alpha > 42: + # ^^^^^ -> 1_indent + var beta := alpha + 13 + # | | ^^^^ -> 1_indent + # ^^^^ 2_indent -> 2_indent + if beta > alpha: + # | | ^^^^^ -> 1_indent + # ^^^^ -> 2_indent + var gamma = beta + 1 + # | | ^^^^ -> 2_indent + # ^^^^^ 3_indent -> 3_indent + print(gamma) + # ^^^^^ -> 3_indent + print(beta) + # ^^^^ -> 2_indent + print(alpha) + # ^^^^^ -> 1_indent + print(root) + # ^^^^ -> 0_indent diff --git a/modules/gdscript/tests/scripts/lsp/indentation.notest.gd b/modules/gdscript/tests/scripts/lsp/indentation.notest.gd deleted file mode 100644 index c25d73a719..0000000000 --- a/modules/gdscript/tests/scripts/lsp/indentation.notest.gd +++ /dev/null @@ -1,28 +0,0 @@ -extends Node - -var root = 0 -# ^^^^ 0_indent -> 0_indent - -func a(): - var alpha: int = root + 42 - # | | ^^^^ -> 0_indent - # ^^^^^ 1_indent -> 1_indent - if alpha > 42: - # ^^^^^ -> 1_indent - var beta := alpha + 13 - # | | ^^^^ -> 1_indent - # ^^^^ 2_indent -> 2_indent - if beta > alpha: - # | | ^^^^^ -> 1_indent - # ^^^^ -> 2_indent - var gamma = beta + 1 - # | | ^^^^ -> 2_indent - # ^^^^^ 3_indent -> 3_indent - print(gamma) - # ^^^^^ -> 3_indent - print(beta) - # ^^^^ -> 2_indent - print(alpha) - # ^^^^^ -> 1_indent - print(root) - # ^^^^ -> 0_indent diff --git a/modules/gdscript/tests/scripts/lsp/lambdas.gd b/modules/gdscript/tests/scripts/lsp/lambdas.gd new file mode 100644 index 0000000000..6f5d468eea --- /dev/null +++ b/modules/gdscript/tests/scripts/lsp/lambdas.gd @@ -0,0 +1,91 @@ +extends Node + +var lambda_member1 := func(alpha: int, beta): return alpha + beta +# | | | | | | | | ^^^^ -> \1:beta +# | | | | | | ^^^^^ -> \1:alpha +# | | | | ^^^^ \1:beta -> \1:beta +# | | ^^^^^ \1:alpha -> \1:alpha +# ^^^^^^^^^^^^^^ \1 -> \1 + +var lambda_member2 := func(alpha, beta: int) -> int: +# | | | | | | +# | | | | | | +# | | | | ^^^^ \2:beta -> \2:beta +# | | ^^^^^ \2:alpha -> \2:alpha +# ^^^^^^^^^^^^^^ \2 -> \2 + return alpha + beta + # | | ^^^^ -> \2:beta + # ^^^^^ -> \2:alpha + +var lambda_member3 := func add_values(alpha, beta): return alpha + beta +# | | | | | | | | ^^^^ -> \3:beta +# | | | | | | ^^^^^ -> \3:alpha +# | | | | ^^^^ \3:beta -> \3:beta +# | | ^^^^^ \3:alpha -> \3:alpha +# ^^^^^^^^^^^^^^ \3 -> \3 + +var lambda_multiline = func(alpha: int, beta: int) -> int: +# | | | | | | +# | | | | | | +# | | | | ^^^^ \multi:beta -> \multi:beta +# | | ^^^^^ \multi:alpha -> \multi:alpha +# ^^^^^^^^^^^^^^^^ \multi -> \multi + print(alpha + beta) + # | | ^^^^ -> \multi:beta + # ^^^^^ -> \multi:alpha + var tmp = alpha + beta + 42 + # | | | | ^^^^ -> \multi:beta + # | | ^^^^^ -> \multi:alpha + # ^^^ \multi:tmp -> \multi:tmp + print(tmp) + # ^^^ -> \multi:tmp + if tmp > 50: + # ^^^ -> \multi:tmp + tmp += alpha + # | ^^^^^ -> \multi:alpha + #<^ -> \multi:tmp + else: + tmp -= beta + # | ^^^^ -> \multi:beta + #<^ -> \multi:tmp + print(tmp) + # ^^^ -> \multi:tmp + return beta + tmp + alpha + # | | | | ^^^^^ -> \multi:alpha + # | | ^^^ -> \multi:tmp + # ^^^^ -> \multi:beta + + +var some_name := "foo bar" +# ^^^^^^^^^ member:some_name -> member:some_name + +func _ready() -> void: + var a = lambda_member1.call(1,2) + # ^^^^^^^^^^^^^^ -> \1 + var b = lambda_member2.call(1,2) + # ^^^^^^^^^^^^^^ -> \2 + var c = lambda_member3.call(1,2) + # ^^^^^^^^^^^^^^ -> \3 + var d = lambda_multiline.call(1,2) + # ^^^^^^^^^^^^^^^^ -> \multi + print(a,b,c,d) + + var lambda_local = func(alpha, beta): return alpha + beta + # | | | | | | | | ^^^^ -> \local:beta + # | | | | | | ^^^^^ -> \local:alpha + # | | | | ^^^^ \local:beta -> \local:beta + # | | ^^^^^ \local:alpha -> \local:alpha + # ^^^^^^^^^^^^ \local -> \local + + var value := 42 + # ^^^^^ local:value -> local:value + var lambda_capture = func(): return value + some_name.length() + # | | | | ^^^^^^^^^ -> member:some_name + # | | ^^^^^ -> local:value + # ^^^^^^^^^^^^^^ \capture -> \capture + + var z = lambda_local.call(1,2) + # ^^^^^^^^^^^^ -> \local + var x = lambda_capture.call() + # ^^^^^^^^^^^^^^ -> \capture + print(z,x) diff --git a/modules/gdscript/tests/scripts/lsp/lambdas.notest.gd b/modules/gdscript/tests/scripts/lsp/lambdas.notest.gd deleted file mode 100644 index 6f5d468eea..0000000000 --- a/modules/gdscript/tests/scripts/lsp/lambdas.notest.gd +++ /dev/null @@ -1,91 +0,0 @@ -extends Node - -var lambda_member1 := func(alpha: int, beta): return alpha + beta -# | | | | | | | | ^^^^ -> \1:beta -# | | | | | | ^^^^^ -> \1:alpha -# | | | | ^^^^ \1:beta -> \1:beta -# | | ^^^^^ \1:alpha -> \1:alpha -# ^^^^^^^^^^^^^^ \1 -> \1 - -var lambda_member2 := func(alpha, beta: int) -> int: -# | | | | | | -# | | | | | | -# | | | | ^^^^ \2:beta -> \2:beta -# | | ^^^^^ \2:alpha -> \2:alpha -# ^^^^^^^^^^^^^^ \2 -> \2 - return alpha + beta - # | | ^^^^ -> \2:beta - # ^^^^^ -> \2:alpha - -var lambda_member3 := func add_values(alpha, beta): return alpha + beta -# | | | | | | | | ^^^^ -> \3:beta -# | | | | | | ^^^^^ -> \3:alpha -# | | | | ^^^^ \3:beta -> \3:beta -# | | ^^^^^ \3:alpha -> \3:alpha -# ^^^^^^^^^^^^^^ \3 -> \3 - -var lambda_multiline = func(alpha: int, beta: int) -> int: -# | | | | | | -# | | | | | | -# | | | | ^^^^ \multi:beta -> \multi:beta -# | | ^^^^^ \multi:alpha -> \multi:alpha -# ^^^^^^^^^^^^^^^^ \multi -> \multi - print(alpha + beta) - # | | ^^^^ -> \multi:beta - # ^^^^^ -> \multi:alpha - var tmp = alpha + beta + 42 - # | | | | ^^^^ -> \multi:beta - # | | ^^^^^ -> \multi:alpha - # ^^^ \multi:tmp -> \multi:tmp - print(tmp) - # ^^^ -> \multi:tmp - if tmp > 50: - # ^^^ -> \multi:tmp - tmp += alpha - # | ^^^^^ -> \multi:alpha - #<^ -> \multi:tmp - else: - tmp -= beta - # | ^^^^ -> \multi:beta - #<^ -> \multi:tmp - print(tmp) - # ^^^ -> \multi:tmp - return beta + tmp + alpha - # | | | | ^^^^^ -> \multi:alpha - # | | ^^^ -> \multi:tmp - # ^^^^ -> \multi:beta - - -var some_name := "foo bar" -# ^^^^^^^^^ member:some_name -> member:some_name - -func _ready() -> void: - var a = lambda_member1.call(1,2) - # ^^^^^^^^^^^^^^ -> \1 - var b = lambda_member2.call(1,2) - # ^^^^^^^^^^^^^^ -> \2 - var c = lambda_member3.call(1,2) - # ^^^^^^^^^^^^^^ -> \3 - var d = lambda_multiline.call(1,2) - # ^^^^^^^^^^^^^^^^ -> \multi - print(a,b,c,d) - - var lambda_local = func(alpha, beta): return alpha + beta - # | | | | | | | | ^^^^ -> \local:beta - # | | | | | | ^^^^^ -> \local:alpha - # | | | | ^^^^ \local:beta -> \local:beta - # | | ^^^^^ \local:alpha -> \local:alpha - # ^^^^^^^^^^^^ \local -> \local - - var value := 42 - # ^^^^^ local:value -> local:value - var lambda_capture = func(): return value + some_name.length() - # | | | | ^^^^^^^^^ -> member:some_name - # | | ^^^^^ -> local:value - # ^^^^^^^^^^^^^^ \capture -> \capture - - var z = lambda_local.call(1,2) - # ^^^^^^^^^^^^ -> \local - var x = lambda_capture.call() - # ^^^^^^^^^^^^^^ -> \capture - print(z,x) diff --git a/modules/gdscript/tests/scripts/lsp/local_variables.gd b/modules/gdscript/tests/scripts/lsp/local_variables.gd new file mode 100644 index 0000000000..b6cc46f7da --- /dev/null +++ b/modules/gdscript/tests/scripts/lsp/local_variables.gd @@ -0,0 +1,25 @@ +extends Node + +var member := 2 +# ^^^^^^ member -> member + +func test_member() -> void: + var test := member + 42 + # | | ^^^^^^ -> member + # ^^^^ test -> test + test += 3 + #<^^ -> test + member += 5 + #<^^^^ -> member + test = return_arg(test) + # | ^^^^ -> test + #<^^ -> test + print(test) + # ^^^^ -> test + +func return_arg(arg: int) -> int: +# ^^^ arg -> arg + arg += 2 + #<^ -> arg + return arg + # ^^^ -> arg \ No newline at end of file diff --git a/modules/gdscript/tests/scripts/lsp/local_variables.notest.gd b/modules/gdscript/tests/scripts/lsp/local_variables.notest.gd deleted file mode 100644 index b6cc46f7da..0000000000 --- a/modules/gdscript/tests/scripts/lsp/local_variables.notest.gd +++ /dev/null @@ -1,25 +0,0 @@ -extends Node - -var member := 2 -# ^^^^^^ member -> member - -func test_member() -> void: - var test := member + 42 - # | | ^^^^^^ -> member - # ^^^^ test -> test - test += 3 - #<^^ -> test - member += 5 - #<^^^^ -> member - test = return_arg(test) - # | ^^^^ -> test - #<^^ -> test - print(test) - # ^^^^ -> test - -func return_arg(arg: int) -> int: -# ^^^ arg -> arg - arg += 2 - #<^ -> arg - return arg - # ^^^ -> arg \ No newline at end of file diff --git a/modules/gdscript/tests/scripts/lsp/properties.gd b/modules/gdscript/tests/scripts/lsp/properties.gd new file mode 100644 index 0000000000..8dfaee2e5b --- /dev/null +++ b/modules/gdscript/tests/scripts/lsp/properties.gd @@ -0,0 +1,65 @@ +extends Node + +var prop1 := 42 +# ^^^^^ prop1 -> prop1 +var prop2 : int = 42 +# ^^^^^ prop2 -> prop2 +var prop3 := 42: +# ^^^^^ prop3 -> prop3 + get: + return prop3 + 13 + # ^^^^^ -> prop3 + set(value): + # ^^^^^ prop3:value -> prop3:value + prop3 = value - 13 + # | ^^^^^ -> prop3:value + #<^^^ -> prop3 +var prop4: int: +# ^^^^^ prop4 -> prop4 + get: + return 42 +var prop5 := 42: +# ^^^^^ prop5 -> prop5 + set(value): + # ^^^^^ prop5:value -> prop5:value + prop5 = value - 13 + # | ^^^^^ -> prop5:value + #<^^^ -> prop5 + +var prop6: +# ^^^^^ prop6 -> prop6 + get = get_prop6, + # ^^^^^^^^^ -> get_prop6 + set = set_prop6 + # ^^^^^^^^^ -> set_prop6 +func get_prop6(): +# ^^^^^^^^^ get_prop6 -> get_prop6 + return 42 +func set_prop6(value): +# | | ^^^^^ set_prop6:value -> set_prop6:value +# ^^^^^^^^^ set_prop6 -> set_prop6 + print(value) + # ^^^^^ -> set_prop6:value + +var prop7: +# ^^^^^ prop7 -> prop7 + get = get_prop7 + # ^^^^^^^^^ -> get_prop7 +func get_prop7(): +# ^^^^^^^^^ get_prop7 -> get_prop7 + return 42 + +var prop8: +# ^^^^^ prop8 -> prop8 + set = set_prop8 + # ^^^^^^^^^ -> set_prop8 +func set_prop8(value): +# | | ^^^^^ set_prop8:value -> set_prop8:value +# ^^^^^^^^^ set_prop8 -> set_prop8 + print(value) + # ^^^^^ -> set_prop8:value + +const const_var := 42 +# ^^^^^^^^^ const_var -> const_var +static var static_var := 42 +# ^^^^^^^^^^ static_var -> static_var diff --git a/modules/gdscript/tests/scripts/lsp/properties.notest.gd b/modules/gdscript/tests/scripts/lsp/properties.notest.gd deleted file mode 100644 index 8dfaee2e5b..0000000000 --- a/modules/gdscript/tests/scripts/lsp/properties.notest.gd +++ /dev/null @@ -1,65 +0,0 @@ -extends Node - -var prop1 := 42 -# ^^^^^ prop1 -> prop1 -var prop2 : int = 42 -# ^^^^^ prop2 -> prop2 -var prop3 := 42: -# ^^^^^ prop3 -> prop3 - get: - return prop3 + 13 - # ^^^^^ -> prop3 - set(value): - # ^^^^^ prop3:value -> prop3:value - prop3 = value - 13 - # | ^^^^^ -> prop3:value - #<^^^ -> prop3 -var prop4: int: -# ^^^^^ prop4 -> prop4 - get: - return 42 -var prop5 := 42: -# ^^^^^ prop5 -> prop5 - set(value): - # ^^^^^ prop5:value -> prop5:value - prop5 = value - 13 - # | ^^^^^ -> prop5:value - #<^^^ -> prop5 - -var prop6: -# ^^^^^ prop6 -> prop6 - get = get_prop6, - # ^^^^^^^^^ -> get_prop6 - set = set_prop6 - # ^^^^^^^^^ -> set_prop6 -func get_prop6(): -# ^^^^^^^^^ get_prop6 -> get_prop6 - return 42 -func set_prop6(value): -# | | ^^^^^ set_prop6:value -> set_prop6:value -# ^^^^^^^^^ set_prop6 -> set_prop6 - print(value) - # ^^^^^ -> set_prop6:value - -var prop7: -# ^^^^^ prop7 -> prop7 - get = get_prop7 - # ^^^^^^^^^ -> get_prop7 -func get_prop7(): -# ^^^^^^^^^ get_prop7 -> get_prop7 - return 42 - -var prop8: -# ^^^^^ prop8 -> prop8 - set = set_prop8 - # ^^^^^^^^^ -> set_prop8 -func set_prop8(value): -# | | ^^^^^ set_prop8:value -> set_prop8:value -# ^^^^^^^^^ set_prop8 -> set_prop8 - print(value) - # ^^^^^ -> set_prop8:value - -const const_var := 42 -# ^^^^^^^^^ const_var -> const_var -static var static_var := 42 -# ^^^^^^^^^^ static_var -> static_var diff --git a/modules/gdscript/tests/scripts/lsp/scopes.gd b/modules/gdscript/tests/scripts/lsp/scopes.gd new file mode 100644 index 0000000000..20b8fb9bd7 --- /dev/null +++ b/modules/gdscript/tests/scripts/lsp/scopes.gd @@ -0,0 +1,106 @@ +extends Node + +var member := 2 +# ^^^^^^ public -> public + +signal some_changed(new_value) +# | | ^^^^^^^^^ signal:parameter -> signal:parameter +# ^^^^^^^^^^^^ signal -> signal +var some_value := 42: +# ^^^^^^^^^^ property -> property + get: + return some_value + # ^^^^^^^^^^ -> property + set(value): + # ^^^^^ property:set:value -> property:set:value + some_changed.emit(value) + # | ^^^^^ -> property:set:value + #<^^^^^^^^^^ -> signal + some_value = value + # | ^^^^^ -> property:set:value + #<^^^^^^^^ -> property + +func v(): + var value := member + 2 + # | | ^^^^^^ -> public + # ^^^^^ v:value -> v:value + print(value) + # ^^^^^ -> v:value + if value > 0: + # ^^^^^ -> v:value + var beta := value + 2 + # | | ^^^^^ -> v:value + # ^^^^ v:if:beta -> v:if:beta + print(beta) + # ^^^^ -> v:if:beta + + for counter in beta: + # | | ^^^^ -> v:if:beta + # ^^^^^^^ v:if:counter -> v:if:counter + print (counter) + # ^^^^^^^ -> v:if:counter + + else: + for counter in value: + # | | ^^^^^ -> v:value + # ^^^^^^^ v:else:counter -> v:else:counter + print(counter) + # ^^^^^^^ -> v:else:counter + +func f(): + var func1 = func(value): print(value + 13) + # | | | | ^^^^^ -> f:func1:value + # | | ^^^^^ f:func1:value -> f:func1:value + # ^^^^^ f:func1 -> f:func1 + var func2 = func(value): print(value + 42) + # | | | | ^^^^^ -> f:func2:value + # | | ^^^^^ f:func2:value -> f:func2:value + # ^^^^^ f:func2 -> f:func2 + + func1.call(1) + #<^^^ -> f:func1 + func2.call(2) + #<^^^ -> f:func2 + +func m(): + var value = 42 + # ^^^^^ m:value -> m:value + + match value: + # ^^^^^ -> m:value + 13: + print(value) + # ^^^^^ -> m:value + [var start, _, var end]: + # | | ^^^ m:match:array:end -> m:match:array:end + # ^^^^^ m:match:array:start -> m:match:array:start + print(start + end) + # | | ^^^ -> m:match:array:end + # ^^^^^ -> m:match:array:start + { "name": var name }: + # ^^^^ m:match:dict:var -> m:match:dict:var + print(name) + # ^^^^ -> m:match:dict:var + var whatever: + # ^^^^^^^^ m:match:var -> m:match:var + print(whatever) + # ^^^^^^^^ -> m:match:var + +func m2(): + var value = 42 + # ^^^^^ m2:value -> m2:value + + match value: + # ^^^^^ -> m2:value + { "name": var name }: + # ^^^^ m2:match:dict:var -> m2:match:dict:var + print(name) + # ^^^^ -> m2:match:dict:var + [var name, ..]: + # ^^^^ m2:match:array:var -> m2:match:array:var + print(name) + # ^^^^ -> m2:match:array:var + var name: + # ^^^^ m2:match:var -> m2:match:var + print(name) + # ^^^^ -> m2:match:var diff --git a/modules/gdscript/tests/scripts/lsp/scopes.notest.gd b/modules/gdscript/tests/scripts/lsp/scopes.notest.gd deleted file mode 100644 index 20b8fb9bd7..0000000000 --- a/modules/gdscript/tests/scripts/lsp/scopes.notest.gd +++ /dev/null @@ -1,106 +0,0 @@ -extends Node - -var member := 2 -# ^^^^^^ public -> public - -signal some_changed(new_value) -# | | ^^^^^^^^^ signal:parameter -> signal:parameter -# ^^^^^^^^^^^^ signal -> signal -var some_value := 42: -# ^^^^^^^^^^ property -> property - get: - return some_value - # ^^^^^^^^^^ -> property - set(value): - # ^^^^^ property:set:value -> property:set:value - some_changed.emit(value) - # | ^^^^^ -> property:set:value - #<^^^^^^^^^^ -> signal - some_value = value - # | ^^^^^ -> property:set:value - #<^^^^^^^^ -> property - -func v(): - var value := member + 2 - # | | ^^^^^^ -> public - # ^^^^^ v:value -> v:value - print(value) - # ^^^^^ -> v:value - if value > 0: - # ^^^^^ -> v:value - var beta := value + 2 - # | | ^^^^^ -> v:value - # ^^^^ v:if:beta -> v:if:beta - print(beta) - # ^^^^ -> v:if:beta - - for counter in beta: - # | | ^^^^ -> v:if:beta - # ^^^^^^^ v:if:counter -> v:if:counter - print (counter) - # ^^^^^^^ -> v:if:counter - - else: - for counter in value: - # | | ^^^^^ -> v:value - # ^^^^^^^ v:else:counter -> v:else:counter - print(counter) - # ^^^^^^^ -> v:else:counter - -func f(): - var func1 = func(value): print(value + 13) - # | | | | ^^^^^ -> f:func1:value - # | | ^^^^^ f:func1:value -> f:func1:value - # ^^^^^ f:func1 -> f:func1 - var func2 = func(value): print(value + 42) - # | | | | ^^^^^ -> f:func2:value - # | | ^^^^^ f:func2:value -> f:func2:value - # ^^^^^ f:func2 -> f:func2 - - func1.call(1) - #<^^^ -> f:func1 - func2.call(2) - #<^^^ -> f:func2 - -func m(): - var value = 42 - # ^^^^^ m:value -> m:value - - match value: - # ^^^^^ -> m:value - 13: - print(value) - # ^^^^^ -> m:value - [var start, _, var end]: - # | | ^^^ m:match:array:end -> m:match:array:end - # ^^^^^ m:match:array:start -> m:match:array:start - print(start + end) - # | | ^^^ -> m:match:array:end - # ^^^^^ -> m:match:array:start - { "name": var name }: - # ^^^^ m:match:dict:var -> m:match:dict:var - print(name) - # ^^^^ -> m:match:dict:var - var whatever: - # ^^^^^^^^ m:match:var -> m:match:var - print(whatever) - # ^^^^^^^^ -> m:match:var - -func m2(): - var value = 42 - # ^^^^^ m2:value -> m2:value - - match value: - # ^^^^^ -> m2:value - { "name": var name }: - # ^^^^ m2:match:dict:var -> m2:match:dict:var - print(name) - # ^^^^ -> m2:match:dict:var - [var name, ..]: - # ^^^^ m2:match:array:var -> m2:match:array:var - print(name) - # ^^^^ -> m2:match:array:var - var name: - # ^^^^ m2:match:var -> m2:match:var - print(name) - # ^^^^ -> m2:match:var diff --git a/modules/gdscript/tests/scripts/lsp/shadowing_initializer.gd b/modules/gdscript/tests/scripts/lsp/shadowing_initializer.gd new file mode 100644 index 0000000000..338000fa0e --- /dev/null +++ b/modules/gdscript/tests/scripts/lsp/shadowing_initializer.gd @@ -0,0 +1,56 @@ +extends Node + +var value := 42 +# ^^^^^ member:value -> member:value + +func variable(): + var value = value + 42 + #! | | ^^^^^ -> member:value + # ^^^^^ variable:value -> variable:value + print(value) + # ^^^^^ -> variable:value + +func array(): + var value = [1,value,3,value+4] + #! | | | | ^^^^^ -> member:value + #! | | ^^^^^ -> member:value + # ^^^^^ array:value -> array:value + print(value) + # ^^^^^ -> array:value + +func dictionary(): + var value = { + # ^^^^^ dictionary:value -> dictionary:value + "key1": value, + #! ^^^^^ -> member:value + "key2": 1 + value + 3, + #! ^^^^^ -> member:value + } + print(value) + # ^^^^^ -> dictionary:value + +func for_loop(): + for value in value: + # | | ^^^^^ -> member:value + # ^^^^^ for:value -> for:value + print(value) + # ^^^^^ -> for:value + +func for_range(): + for value in range(5, value): + # | | ^^^^^ -> member:value + # ^^^^^ for:range:value -> for:range:value + print(value) + # ^^^^^ -> for:range:value + +func matching(): + match value: + # ^^^^^ -> member:value + 42: print(value) + # ^^^^^ -> member:value + [var value, ..]: print(value) + # | | ^^^^^ -> match:array:value + # ^^^^^ match:array:value -> match:array:value + var value: print(value) + # | | ^^^^^ -> match:var:value + # ^^^^^ match:var:value -> match:var:value diff --git a/modules/gdscript/tests/scripts/lsp/shadowing_initializer.notest.gd b/modules/gdscript/tests/scripts/lsp/shadowing_initializer.notest.gd deleted file mode 100644 index 338000fa0e..0000000000 --- a/modules/gdscript/tests/scripts/lsp/shadowing_initializer.notest.gd +++ /dev/null @@ -1,56 +0,0 @@ -extends Node - -var value := 42 -# ^^^^^ member:value -> member:value - -func variable(): - var value = value + 42 - #! | | ^^^^^ -> member:value - # ^^^^^ variable:value -> variable:value - print(value) - # ^^^^^ -> variable:value - -func array(): - var value = [1,value,3,value+4] - #! | | | | ^^^^^ -> member:value - #! | | ^^^^^ -> member:value - # ^^^^^ array:value -> array:value - print(value) - # ^^^^^ -> array:value - -func dictionary(): - var value = { - # ^^^^^ dictionary:value -> dictionary:value - "key1": value, - #! ^^^^^ -> member:value - "key2": 1 + value + 3, - #! ^^^^^ -> member:value - } - print(value) - # ^^^^^ -> dictionary:value - -func for_loop(): - for value in value: - # | | ^^^^^ -> member:value - # ^^^^^ for:value -> for:value - print(value) - # ^^^^^ -> for:value - -func for_range(): - for value in range(5, value): - # | | ^^^^^ -> member:value - # ^^^^^ for:range:value -> for:range:value - print(value) - # ^^^^^ -> for:range:value - -func matching(): - match value: - # ^^^^^ -> member:value - 42: print(value) - # ^^^^^ -> member:value - [var value, ..]: print(value) - # | | ^^^^^ -> match:array:value - # ^^^^^ match:array:value -> match:array:value - var value: print(value) - # | | ^^^^^ -> match:var:value - # ^^^^^ match:var:value -> match:var:value diff --git a/modules/gdscript/tests/scripts/project.godot b/modules/gdscript/tests/scripts/project.godot index 25b49c0abd..c500ef443d 100644 --- a/modules/gdscript/tests/scripts/project.godot +++ b/modules/gdscript/tests/scripts/project.godot @@ -3,7 +3,7 @@ ; It also helps for opening Godot to edit the scripts, but please don't ; let the editor changes be saved. -config_version=4 +config_version=5 [application] diff --git a/modules/gdscript/tests/test_completion.h b/modules/gdscript/tests/test_completion.h new file mode 100644 index 0000000000..abc34bd4bf --- /dev/null +++ b/modules/gdscript/tests/test_completion.h @@ -0,0 +1,199 @@ +/**************************************************************************/ +/* test_completion.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_COMPLETION_H +#define TEST_COMPLETION_H + +#ifdef TOOLS_ENABLED + +#include "core/io/config_file.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" +#include "core/object/script_language.h" +#include "core/variant/dictionary.h" +#include "core/variant/variant.h" +#include "gdscript_test_runner.h" +#include "modules/modules_enabled.gen.h" // For mono. +#include "scene/resources/packed_scene.h" + +#include "../gdscript.h" +#include "tests/test_macros.h" + +#include "editor/editor_settings.h" +#include "scene/theme/theme_db.h" + +namespace GDScriptTests { + +static bool match_option(const Dictionary p_expected, const ScriptLanguage::CodeCompletionOption p_got) { + if (p_expected.get("display", p_got.display) != p_got.display) { + return false; + } + if (p_expected.get("insert_text", p_got.insert_text) != p_got.insert_text) { + return false; + } + if (p_expected.get("kind", p_got.kind) != Variant(p_got.kind)) { + return false; + } + if (p_expected.get("location", p_got.location) != Variant(p_got.location)) { + return false; + } + return true; +} + +static void to_dict_list(Variant p_variant, List &p_list) { + ERR_FAIL_COND(!p_variant.is_array()); + + Array arr = p_variant; + for (int i = 0; i < arr.size(); i++) { + if (arr[i].get_type() == Variant::DICTIONARY) { + p_list.push_back(arr[i]); + } + } +} + +static void test_directory(const String &p_dir) { + Error err = OK; + Ref dir = DirAccess::open(p_dir, &err); + + if (err != OK) { + FAIL("Invalid test directory."); + return; + } + + String path = dir->get_current_dir(); + + dir->list_dir_begin(); + String next = dir->get_next(); + + while (!next.is_empty()) { + if (dir->current_is_dir()) { + if (next == "." || next == "..") { + next = dir->get_next(); + continue; + } + test_directory(path.path_join(next)); + } else if (next.ends_with(".gd") && !next.ends_with(".notest.gd")) { + Ref acc = FileAccess::open(path.path_join(next), FileAccess::READ, &err); + + if (err != OK) { + next = dir->get_next(); + continue; + } + + String code = acc->get_as_utf8_string(); + // 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)); + // Require pointer sentinel char in scripts. + CHECK(code.find_char(0xFFFF) != -1); + + ConfigFile conf; + if (conf.load(path.path_join(next.get_basename() + ".cfg")) != OK) { + FAIL("No config file found."); + } + +#ifndef MODULE_MONO_ENABLED + if (conf.get_value("input", "cs", false)) { + next = dir->get_next(); + continue; + } +#endif + + EditorSettings::get_singleton()->set_setting("text_editor/completion/use_single_quotes", conf.get_value("input", "use_single_quotes", false)); + + List include; + to_dict_list(conf.get_value("result", "include", Array()), include); + + List exclude; + to_dict_list(conf.get_value("result", "exclude", Array()), exclude); + + List options; + String call_hint; + bool forced; + + Node *owner = nullptr; + if (dir->file_exists(next.get_basename() + ".tscn")) { + String project_path = "res://completion"; + Ref scene = ResourceLoader::load(project_path.path_join(next.get_basename() + ".tscn"), "PackedScene"); + if (scene.is_valid()) { + owner = scene->instantiate(); + } + } + + GDScriptLanguage::get_singleton()->complete_code(code, path.path_join(next), owner, &options, forced, call_hint); + String contains_excluded; + for (ScriptLanguage::CodeCompletionOption &option : options) { + for (const Dictionary &E : exclude) { + if (match_option(E, option)) { + contains_excluded = option.display; + break; + } + } + if (!contains_excluded.is_empty()) { + break; + } + + for (const Dictionary &E : include) { + if (match_option(E, option)) { + include.erase(E); + break; + } + } + } + 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); + + CHECK(expected_call_hint == call_hint); + CHECK(expected_forced == forced); + + if (owner) { + memdelete(owner); + } + } + next = dir->get_next(); + } +} + +TEST_SUITE("[Modules][GDScript][Completion]") { + TEST_CASE("[Editor] Check suggestion list") { + // Set all editor settings that code completion relies on. + EditorSettings::get_singleton()->set_setting("text_editor/completion/use_single_quotes", false); + init_language("modules/gdscript/tests/scripts"); + + test_directory("modules/gdscript/tests/scripts/completion"); + } +} +} // namespace GDScriptTests + +#endif + +#endif // TEST_COMPLETION_H diff --git a/modules/gdscript/tests/test_lsp.h b/modules/gdscript/tests/test_lsp.h index e57df00e2d..6192272f80 100644 --- a/modules/gdscript/tests/test_lsp.h +++ b/modules/gdscript/tests/test_lsp.h @@ -76,7 +76,7 @@ namespace GDScriptTests { // LSP GDScript test scripts are located inside project of other GDScript tests: // Cannot reset `ProjectSettings` (singleton) -> Cannot load another workspace and resources in there. // -> Reuse GDScript test project. LSP specific scripts are then placed inside `lsp` folder. -// Access via `res://lsp/my_script.notest.gd`. +// Access via `res://lsp/my_script.gd`. const String root = "modules/gdscript/tests/scripts/"; /* @@ -394,7 +394,7 @@ func f(): Ref workspace = GDScriptLanguageProtocol::get_singleton()->get_workspace(); { - String path = "res://lsp/local_variables.notest.gd"; + String path = "res://lsp/local_variables.gd"; assert_no_errors_in(path); String uri = workspace->get_file_uri(path); Vector all_test_data = read_tests(path); @@ -413,7 +413,7 @@ func f(): } SUBCASE("Can get correct ranges for indented variables") { - String path = "res://lsp/indentation.notest.gd"; + String path = "res://lsp/indentation.gd"; assert_no_errors_in(path); String uri = workspace->get_file_uri(path); Vector all_test_data = read_tests(path); @@ -421,7 +421,7 @@ func f(): } SUBCASE("Can get correct ranges for scopes") { - String path = "res://lsp/scopes.notest.gd"; + String path = "res://lsp/scopes.gd"; assert_no_errors_in(path); String uri = workspace->get_file_uri(path); Vector all_test_data = read_tests(path); @@ -429,7 +429,7 @@ func f(): } SUBCASE("Can get correct ranges for lambda") { - String path = "res://lsp/lambdas.notest.gd"; + String path = "res://lsp/lambdas.gd"; assert_no_errors_in(path); String uri = workspace->get_file_uri(path); Vector all_test_data = read_tests(path); @@ -437,7 +437,7 @@ func f(): } SUBCASE("Can get correct ranges for inner class") { - String path = "res://lsp/class.notest.gd"; + String path = "res://lsp/class.gd"; assert_no_errors_in(path); String uri = workspace->get_file_uri(path); Vector all_test_data = read_tests(path); @@ -445,7 +445,7 @@ func f(): } SUBCASE("Can get correct ranges for inner class") { - String path = "res://lsp/enums.notest.gd"; + String path = "res://lsp/enums.gd"; assert_no_errors_in(path); String uri = workspace->get_file_uri(path); Vector all_test_data = read_tests(path); @@ -453,7 +453,7 @@ func f(): } SUBCASE("Can get correct ranges for shadowing & shadowed variables") { - String path = "res://lsp/shadowing_initializer.notest.gd"; + String path = "res://lsp/shadowing_initializer.gd"; assert_no_errors_in(path); String uri = workspace->get_file_uri(path); Vector all_test_data = read_tests(path); @@ -461,7 +461,7 @@ func f(): } SUBCASE("Can get correct ranges for properties and getter/setter") { - String path = "res://lsp/properties.notest.gd"; + String path = "res://lsp/properties.gd"; assert_no_errors_in(path); String uri = workspace->get_file_uri(path); Vector all_test_data = read_tests(path); -- cgit v1.2.3