Skip to content

Commit e280b64

Browse files
committed
Add basic test for Coroutine
1 parent 7e2d38e commit e280b64

File tree

9 files changed

+131
-86
lines changed

9 files changed

+131
-86
lines changed

harness/tests/Spatial.tscn

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,27 @@
22

33
[ext_resource type="Script" path="res://scripts/godot/tests/Invocation.gdj" id="1"]
44

5-
[sub_resource type="NavigationMesh" id="NavigationMesh_prd4u"]
5+
[sub_resource type="NavigationMesh" id="NavigationMesh_1ex3u"]
66

7-
[sub_resource type="NavigationMesh" id="NavigationMesh_tuyoa"]
7+
[sub_resource type="NavigationMesh" id="NavigationMesh_q3pqa"]
88

9-
[sub_resource type="NavigationMesh" id="NavigationMesh_bh4po"]
9+
[sub_resource type="NavigationMesh" id="NavigationMesh_hn8kg"]
1010

11-
[sub_resource type="NavigationMesh" id="NavigationMesh_bdc7j"]
11+
[sub_resource type="NavigationMesh" id="NavigationMesh_87cay"]
1212

13-
[sub_resource type="NavigationMesh" id="NavigationMesh_abcao"]
13+
[sub_resource type="NavigationMesh" id="NavigationMesh_b12lh"]
1414

15-
[node name="Spatial" type="Node3D" node_paths=PackedStringArray("button")]
15+
[node name="Spatial" type="Node3D"]
1616
script = ExtResource("1")
17-
button = NodePath("CanvasLayer/Button")
18-
nullable_long = 2
19-
lateinit_string = "works also from inspector"
20-
resource_test = SubResource("NavigationMesh_prd4u")
21-
jvm_id = 319061373
22-
nav_meshes = Array[NavigationMesh]([SubResource("NavigationMesh_tuyoa")])
23-
nullable_array = Array[NavigationMesh]([SubResource("NavigationMesh_bh4po"), null])
17+
resource_test = SubResource("NavigationMesh_1ex3u")
18+
jvm_id = 780172372
19+
nav_meshes = Array[NavigationMesh]([SubResource("NavigationMesh_q3pqa")])
20+
nullable_array = Array[NavigationMesh]([SubResource("NavigationMesh_hn8kg"), null])
2421
nav_meshes_dictionary = {
25-
"AwesomeNavmesh": SubResource("NavigationMesh_bdc7j")
22+
"AwesomeNavmesh": SubResource("NavigationMesh_87cay")
2623
}
2724
nullable_dictionary = {
28-
"notnull": SubResource("NavigationMesh_abcao"),
25+
"notnull": SubResource("NavigationMesh_b12lh"),
2926
"null": null
3027
}
3128

harness/tests/src/main/kotlin/godot/tests/Invocation.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ import godot.core.Vector3
4040
import godot.core.asStringName
4141
import godot.core.dictionaryOf
4242
import godot.core.variantArrayOf
43+
import godot.coroutines.GodotCoroutine
44+
import godot.coroutines.await
4345
import godot.extensions.getNodeAs
4446
import godot.registration.Range
4547
import godot.signals.connect
@@ -392,6 +394,12 @@ class Invocation : Node3D() {
392394

393395
@RegisterFunction
394396
override fun _ready() {
397+
GodotCoroutine{
398+
println("Before")
399+
signalWithMultipleTargets.await()
400+
println("After")
401+
}
402+
395403
val formerName = name
396404
println("Name is: $name")
397405
name = "TestName".asStringName()

harness/tests/test/GutTests.gd

Lines changed: 67 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -21,53 +21,53 @@ var _current_test_name = null
2121

2222

2323
func _ready():
24-
simple_setup()
25-
# complex_setup()
24+
simple_setup()
25+
# complex_setup()
2626

2727

2828
func simple_setup():
29-
# You must load a gut config file to use this control. Here we are loading
30-
# the default config file used by the command line. You can use any config
31-
# file you have created. Use the "save as" button in the Settings subpanel
32-
# to create a config file, or write your own.
33-
#
34-
# Some settings may not work. For example, the exit flags do not have any
35-
# effect.
36-
#
37-
# Settings are not saved, so any changes will be lost. The idea is that you
38-
# want to deploy the settings and users should not be able to save them. If
39-
# you want to save changes, you can call:
40-
# _gut_control.get_config().write_options(path).
41-
# Note that you cannot to write to res:// on mobile platforms, so you will
42-
# have to juggle the initial loading from res:// or user:// and save to
43-
# user://.
44-
_gut_control.load_config_file('res://.gutconfig.json')
45-
46-
# That's it. Just get a reference to the control you added to the scene and
47-
# give it a config. The rest of the stuff in this script optional.
29+
# You must load a gut config file to use this control. Here we are loading
30+
# the default config file used by the command line. You can use any config
31+
# file you have created. Use the "save as" button in the Settings subpanel
32+
# to create a config file, or write your own.
33+
#
34+
# Some settings may not work. For example, the exit flags do not have any
35+
# effect.
36+
#
37+
# Settings are not saved, so any changes will be lost. The idea is that you
38+
# want to deploy the settings and users should not be able to save them. If
39+
# you want to save changes, you can call:
40+
# _gut_control.get_config().write_options(path).
41+
# Note that you cannot to write to res:// on mobile platforms, so you will
42+
# have to juggle the initial loading from res:// or user:// and save to
43+
# user://.
44+
_gut_control.load_config_file('res://.gutconfig.json')
45+
46+
# That's it. Just get a reference to the control you added to the scene and
47+
# give it a config. The rest of the stuff in this script optional.
4848

4949

5050

5151
func complex_setup():
52-
# See simple setup
53-
_gut_control.load_config_file('res://.gutconfig.json')
52+
# See simple setup
53+
_gut_control.load_config_file('res://.gutconfig.json')
5454

55-
# Returns a gut_config.gd instance.
56-
var config = _gut_control.get_config()
55+
# Returns a gut_config.gd instance.
56+
var config = _gut_control.get_config()
5757

58-
# Override specific values for the purposes of this scene. You can see all
59-
# the options available in the default_options dictionary in gut_config.gd.
60-
# Changing settings AFTER _ready will not have any effect.
61-
config.options.should_exit = false
62-
config.options.should_exit_on_success = false
63-
config.options.compact_mode = false
64-
# Note that if you are exporting xml results you may want to set the path to
65-
# a file in user:// instead of an absolute path. Your game may not have
66-
# permissions to save files elsewhere when running on a mobile device.
67-
config.options.junit_xml_file = 'user://deployed_results.xml'
58+
# Override specific values for the purposes of this scene. You can see all
59+
# the options available in the default_options dictionary in gut_config.gd.
60+
# Changing settings AFTER _ready will not have any effect.
61+
config.options.should_exit = false
62+
config.options.should_exit_on_success = false
63+
config.options.compact_mode = false
64+
# Note that if you are exporting xml results you may want to set the path to
65+
# a file in user:// instead of an absolute path. Your game may not have
66+
# permissions to save files elsewhere when running on a mobile device.
67+
config.options.junit_xml_file = 'user://deployed_results.xml'
6868

69-
# Some actions cannot be done until after _ready has finished in all objects
70-
_post_ready_setup.call_deferred()
69+
# Some actions cannot be done until after _ready has finished in all objects
70+
_post_ready_setup.call_deferred()
7171

7272

7373

@@ -76,63 +76,63 @@ func complex_setup():
7676
# so after _ready. This is an example of getting a reference to gut and all
7777
# of the signals it provides.
7878
func _post_ready_setup():
79-
var gut = _gut_control.get_gut()
80-
gut.start_run.connect(_on_gut_run_start)
79+
var gut = _gut_control.get_gut()
80+
gut.start_run.connect(_on_gut_run_start)
8181

82-
gut.start_script.connect(_on_gut_start_script)
83-
gut.end_script.connect(_on_gut_end_script)
82+
gut.start_script.connect(_on_gut_start_script)
83+
gut.end_script.connect(_on_gut_end_script)
8484

85-
gut.start_test.connect(_on_gut_start_test)
86-
gut.end_test.connect(_on_gut_end_test)
85+
gut.start_test.connect(_on_gut_start_test)
86+
gut.end_test.connect(_on_gut_end_test)
8787

88-
gut.end_run.connect(_on_gut_run_end)
88+
gut.end_run.connect(_on_gut_run_end)
8989

9090

9191
# -----------------------
9292
# Events
9393
# -----------------------
9494
func _on_gut_run_start():
95-
print('Starting tests')
95+
print('Starting tests')
9696

9797

9898
# This signal passes a TestCollector.gd/TestScript instance
9999
func _on_gut_start_script(script_obj):
100-
print(script_obj.get_full_name(), ' has ', script_obj.tests.size(), ' tests')
101-
_current_script_object = script_obj
100+
print(script_obj.get_full_name(), ' has ', script_obj.tests.size(), ' tests')
101+
_current_script_object = script_obj
102102

103103

104104
func _on_gut_end_script():
105-
var pass_count = 0
106-
for test in _current_script_object.tests:
107-
if(test.did_pass()):
108-
pass_count += 1
109-
print(pass_count, '/', _current_script_object.tests.size(), " passed\n")
110-
_current_script_object = null
105+
var pass_count = 0
106+
for test in _current_script_object.tests:
107+
if(test.did_pass()):
108+
pass_count += 1
109+
print(pass_count, '/', _current_script_object.tests.size(), " passed\n")
110+
_current_script_object = null
111111

112112

113113
func _on_gut_start_test(test_name):
114-
_current_test_name = test_name
115-
print(' ', test_name)
114+
_current_test_name = test_name
115+
print(' ', test_name)
116116

117117

118118
func _on_gut_end_test():
119-
# get_test_named returns a TestCollector.gd/Test instance for the name
120-
# passed in.
121-
var test_object = _current_script_object.get_test_named(_current_test_name)
122-
var status = "failed"
123-
if(test_object.did_pass()):
124-
status = "passed"
125-
elif(test_object.pending):
126-
status = "pending"
119+
# get_test_named returns a TestCollector.gd/Test instance for the name
120+
# passed in.
121+
var test_object = _current_script_object.get_test_named(_current_test_name)
122+
var status = "failed"
123+
if(test_object.did_pass()):
124+
status = "passed"
125+
elif(test_object.pending):
126+
status = "pending"
127127

128-
print(' ', status)
129-
_current_test_name = null
128+
print(' ', status)
129+
_current_test_name = null
130130

131131

132132
func _on_gut_run_end():
133-
print('Tests Done')
133+
print('Tests Done')
134134

135135

136136
# You can kick of the tests via code if you want.
137137
func _on_run_gut_tests_button_pressed():
138-
_gut_control.run_tests()
138+
_gut_control.run_tests()

harness/tests/test/GutTests.tscn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ script = ExtResource("1_on71t")
99
[node name="GutControl" parent="." instance=ExtResource("1_qrxmy")]
1010
offset_right = 1171.0
1111
offset_bottom = 639.0
12+
bg_color = Color(0, 0, 0, 1)

kt/godot-coroutine-library/build.gradle.kts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,9 @@ java {
2626
}
2727

2828
dependencies {
29-
// added here as a transitive dependency so the user can use reflection
30-
// we need to add it here so reflection is available where the code is loaded (Bootstrap.kt) otherwise it will not work
31-
api(kotlin("reflect", version = libs.versions.kotlin.get()))
29+
compileOnly(project(":godot-library"))
3230
implementation("com.utopia-rise:tools-common:$fullGodotKotlinJvmVersion")
33-
testImplementation("junit", "junit", "4.12")
31+
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:${libs.versions.kotlinCoroutine.get()}")
3432
}
3533

3634
val targetSuffix = if (isRelease) "release" else "debug"
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package godot.coroutines
2+
3+
import kotlin.coroutines.Continuation
4+
import kotlin.coroutines.CoroutineContext
5+
6+
class GodotContinuation(override val context: CoroutineContext): Continuation<Unit> {
7+
8+
override fun resumeWith(result: Result<Unit>) {
9+
TODO("Not yet implemented")
10+
}
11+
12+
13+
private object Bridge {
14+
external fun engine_call_constructor(): VoidPtr
15+
}
16+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package godot.coroutines
2+
3+
import kotlinx.coroutines.CoroutineScope
4+
import kotlinx.coroutines.CoroutineStart
5+
import kotlinx.coroutines.Dispatchers
6+
import kotlinx.coroutines.launch
7+
import kotlin.coroutines.EmptyCoroutineContext
8+
9+
object GodotCoroutine {
10+
private val scope = CoroutineScope(EmptyCoroutineContext)
11+
12+
operator fun invoke( block: suspend CoroutineScope.() -> Unit) {
13+
scope.launch(Dispatchers.Default, CoroutineStart.DEFAULT, block)
14+
}
15+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package godot.coroutines
2+
3+
import godot.signals.Signal
4+
import kotlinx.coroutines.delay
5+
6+
suspend fun Signal.await() {
7+
delay(1000)
8+
}
9+

kt/gradle/libs.versions.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
godotKotlinJvm = "0.9.1"
44
kotlin = "2.0.0"
5+
kotlinCoroutine = "1.8.1"
56
godot = "4.2.2"
67

78
shadowJar = "8.1.1" # https://github.com/johnrengelman/shadow/releases

0 commit comments

Comments
 (0)