diff --git a/platform/android/java/app/src/androidTestInstrumented/java/com/godot/game/GodotAppTest.kt b/platform/android/java/app/src/androidTestInstrumented/java/com/godot/game/GodotAppTest.kt index a0333deccf..383154e75e 100644 --- a/platform/android/java/app/src/androidTestInstrumented/java/com/godot/game/GodotAppTest.kt +++ b/platform/android/java/app/src/androidTestInstrumented/java/com/godot/game/GodotAppTest.kt @@ -113,6 +113,28 @@ class GodotAppTest { } } + /** + * Runs test to validate android plugin signals. + */ + @Test + fun runPluginSignalTests() { + ActivityScenario.launch(GodotApp::class.java).use { scenario -> + scenario.onActivity { activity -> + val testPlugin = getTestPlugin() + assertNotNull(testPlugin) + + Log.d(TAG, "Waiting for the Godot main loop to start...") + testPlugin.waitForGodotMainLoopStarted() + + Log.d(TAG, "Running Android plugin signal tests...") + val result = testPlugin.runPluginSignalTests() + assertNotNull(result) + result.exceptionOrNull()?.let { throw it } + assertTrue(result.isSuccess) + } + } + } + /** * Test implicit launch of the Godot app, and validates this resolves to the `GodotAppLauncher` activity alias. */ diff --git a/platform/android/java/app/src/instrumented/AndroidManifest.xml b/platform/android/java/app/src/instrumented/AndroidManifest.xml index 863ec4c09f..23606f6a66 100644 --- a/platform/android/java/app/src/instrumented/AndroidManifest.xml +++ b/platform/android/java/app/src/instrumented/AndroidManifest.xml @@ -4,6 +4,10 @@ + + diff --git a/platform/android/java/app/src/instrumented/assets/.godot/global_script_class_cache.cfg b/platform/android/java/app/src/instrumented/assets/.godot/global_script_class_cache.cfg index 1f8f066232..080d225fc5 100644 --- a/platform/android/java/app/src/instrumented/assets/.godot/global_script_class_cache.cfg +++ b/platform/android/java/app/src/instrumented/assets/.godot/global_script_class_cache.cfg @@ -1,5 +1,21 @@ list=[{ "base": &"BaseTest", +"class": &"AndroidPluginSignalTests", +"icon": "", +"is_abstract": false, +"is_tool": false, +"language": &"GDScript", +"path": "res://test/android_plugin/signal_tests.gd" +}, { +"base": &"RefCounted", +"class": &"BaseTest", +"icon": "", +"is_abstract": true, +"is_tool": false, +"language": &"GDScript", +"path": "res://test/base_test.gd" +}, { +"base": &"BaseTest", "class": &"FileAccessTests", "icon": "", "is_abstract": false, @@ -14,12 +30,4 @@ list=[{ "is_tool": false, "language": &"GDScript", "path": "res://test/javaclasswrapper/java_class_wrapper_tests.gd" -}, { -"base": &"RefCounted", -"class": &"BaseTest", -"icon": "", -"is_abstract": true, -"is_tool": false, -"language": &"GDScript", -"path": "res://test/base_test.gd" }] diff --git a/platform/android/java/app/src/instrumented/assets/.godot/uid_cache.bin b/platform/android/java/app/src/instrumented/assets/.godot/uid_cache.bin index 9b97586fb9..44db24797c 100644 Binary files a/platform/android/java/app/src/instrumented/assets/.godot/uid_cache.bin and b/platform/android/java/app/src/instrumented/assets/.godot/uid_cache.bin differ diff --git a/platform/android/java/app/src/instrumented/assets/main.gd b/platform/android/java/app/src/instrumented/assets/main.gd index 54d8106edd..4b95069836 100644 --- a/platform/android/java/app/src/instrumented/assets/main.gd +++ b/platform/android/java/app/src/instrumented/assets/main.gd @@ -3,13 +3,22 @@ extends Node2D var _plugin_name = "GodotAppInstrumentedTestPlugin" var _android_plugin -func _ready(): +var _signal_test_plugin_name = "SignalTestPlugin" +var _signal_test_plugin + +func _init(): + # Verify plugin singleton in _init, since plugins should already be registered at this point. if Engine.has_singleton(_plugin_name): _android_plugin = Engine.get_singleton(_plugin_name) _android_plugin.connect("launch_tests", _launch_tests) _android_plugin.connect("update_quit_on_go_back", _update_quit_on_go_back) - else: - printerr("Couldn't find plugin " + _plugin_name) + + if Engine.has_singleton(_signal_test_plugin_name): + _signal_test_plugin = Engine.get_singleton(_signal_test_plugin_name) + +func _ready() -> void: + if not _android_plugin: + printerr("ERROR: Couldn't find plugin " + _plugin_name) get_tree().quit() func _launch_tests(test_label: String) -> void: @@ -19,10 +28,12 @@ func _launch_tests(test_label: String) -> void: test_instance = JavaClassWrapperTests.new() "file_access_tests": test_instance = FileAccessTests.new() + "android_plugin_signal_tests": + test_instance = AndroidPluginSignalTests.new(_signal_test_plugin) if test_instance: test_instance.__reset_tests() - test_instance.run_tests() + await test_instance.run_tests() var incomplete_tests = test_instance._test_started - test_instance._test_completed _android_plugin.onTestsCompleted(test_label, test_instance._test_completed, test_instance._test_assert_failures + incomplete_tests) else: diff --git a/platform/android/java/app/src/instrumented/assets/project.godot b/platform/android/java/app/src/instrumented/assets/project.godot index 68bc653c43..9d168beb45 100644 --- a/platform/android/java/app/src/instrumented/assets/project.godot +++ b/platform/android/java/app/src/instrumented/assets/project.godot @@ -16,7 +16,7 @@ compatibility/default_parent_skeleton_in_mesh_instance_3d=true config/name="Godot App Instrumentation Tests" run/main_scene="res://main.tscn" -config/features=PackedStringArray("4.6", "GL Compatibility") +config/features=PackedStringArray("4.7", "GL Compatibility") config/icon="res://icon.svg" [debug] diff --git a/platform/android/java/app/src/instrumented/assets/test/android_plugin/signal_tests.gd b/platform/android/java/app/src/instrumented/assets/test/android_plugin/signal_tests.gd new file mode 100644 index 0000000000..74f5b1bb76 --- /dev/null +++ b/platform/android/java/app/src/instrumented/assets/test/android_plugin/signal_tests.gd @@ -0,0 +1,60 @@ +class_name AndroidPluginSignalTests +extends BaseTest + +var _plugin: JNISingleton +const emission_test_signal = "emission_test_signal" +const launch_test_signal = "launch_tests" + +signal emission_test_signal_emitted + +func _init(plugin: JNISingleton) -> void: + _plugin = plugin + +func run_tests(): + print("Android plugin signal tests starting...") + + __exec_test(test_plugin_exists) + __exec_test(test_signal_registration) + await __exec_test(test_signal_emission) + + print("Android plugin signal tests completed.") + +func test_plugin_exists() -> bool: + if _plugin == null: + printerr("ERROR: Couldn't find SignalTestPlugin plugin; _plugin is null") + return false + + return true + +func test_signal_registration() -> bool: + var signal_registered = _plugin.has_signal(emission_test_signal) + assert_true(signal_registered) + + var launch_signal_registered = _plugin.has_signal(launch_test_signal) + assert_true(launch_signal_registered) + + return true + +func test_signal_emission() -> bool: + var err1 = _plugin.connect(emission_test_signal, _on_emission_test_signal_emitted) + assert_equal(err1, OK) + _plugin.triggerTestSignal1() + await emission_test_signal_emitted + + # Test case: Same signal name, but different type and number of parameters + # The "launch_tests" signal is registered by both GodotAppInstrumentedTestPlugin and SignalTestPlugin. + # SignalTestPlugin emits it with a boolean and a string arguments, while GodotAppInstrumentedTestPlugin emits it with one string. + var err2 = _plugin.connect(launch_test_signal, _on_launch_tests_emitted) + assert_equal(err2, OK) + _plugin.triggerLaunchTestSignal() + await emission_test_signal_emitted + + return true + +func _on_emission_test_signal_emitted() -> void: + emission_test_signal_emitted.emit() + +func _on_launch_tests_emitted(param1: bool, param2: String) -> void: + assert_true(param1) + assert_equal(param2, "second message") + emission_test_signal_emitted.emit() diff --git a/platform/android/java/app/src/instrumented/assets/test/android_plugin/signal_tests.gd.uid b/platform/android/java/app/src/instrumented/assets/test/android_plugin/signal_tests.gd.uid new file mode 100644 index 0000000000..74d8150d08 --- /dev/null +++ b/platform/android/java/app/src/instrumented/assets/test/android_plugin/signal_tests.gd.uid @@ -0,0 +1 @@ +uid://cq0mxqlbbug6r diff --git a/platform/android/java/app/src/instrumented/assets/test/base_test.gd b/platform/android/java/app/src/instrumented/assets/test/base_test.gd index d4d333505b..6c62263024 100644 --- a/platform/android/java/app/src/instrumented/assets/test/base_test.gd +++ b/platform/android/java/app/src/instrumented/assets/test/base_test.gd @@ -9,7 +9,7 @@ var _test_assert_failures := 0 func __exec_test(test_func: Callable): _test_started += 1 - var ret = test_func.call() + var ret = await test_func.call() if ret == true: _test_completed += 1 diff --git a/platform/android/java/app/src/instrumented/java/com/godot/game/test/GodotAppInstrumentedTestPlugin.kt b/platform/android/java/app/src/instrumented/java/com/godot/game/test/GodotAppInstrumentedTestPlugin.kt index c5c243e159..c92dbc8455 100644 --- a/platform/android/java/app/src/instrumented/java/com/godot/game/test/GodotAppInstrumentedTestPlugin.kt +++ b/platform/android/java/app/src/instrumented/java/com/godot/game/test/GodotAppInstrumentedTestPlugin.kt @@ -52,6 +52,7 @@ class GodotAppInstrumentedTestPlugin(godot: Godot) : GodotPlugin(godot) { private const val JAVACLASSWRAPPER_TESTS = "javaclasswrapper_tests" private const val FILE_ACCESS_TESTS = "file_access_tests" + private const val PLUGIN_SIGNAL_TESTS = "android_plugin_signal_tests" private val LAUNCH_TESTS_SIGNAL = SignalInfo("launch_tests", String::class.java) private val UPDATE_QUIT_ON_GO_BACK_SIGNAL = SignalInfo("update_quit_on_go_back", java.lang.Boolean::class.java) @@ -126,6 +127,10 @@ class GodotAppInstrumentedTestPlugin(godot: Godot) : GodotPlugin(godot) { return launchTests(FILE_ACCESS_TESTS) } + internal fun runPluginSignalTests(): Result? { + return launchTests(PLUGIN_SIGNAL_TESTS) + } + private fun launchTests(testLabel: String): Result? { val latch = latches.getOrPut(testLabel) { CountDownLatch(1) } emitSignal(LAUNCH_TESTS_SIGNAL, testLabel) diff --git a/platform/android/java/app/src/instrumented/java/com/godot/game/test/SignalTestPlugin.kt b/platform/android/java/app/src/instrumented/java/com/godot/game/test/SignalTestPlugin.kt new file mode 100644 index 0000000000..80e6aacd79 --- /dev/null +++ b/platform/android/java/app/src/instrumented/java/com/godot/game/test/SignalTestPlugin.kt @@ -0,0 +1,35 @@ +package com.godot.game.test + +import android.util.Log +import org.godotengine.godot.Dictionary +import org.godotengine.godot.Godot +import org.godotengine.godot.plugin.GodotPlugin +import org.godotengine.godot.plugin.SignalInfo +import org.godotengine.godot.plugin.UsedByGodot + +class SignalTestPlugin(godot: Godot) : GodotPlugin(godot) { + + companion object { + private val EMISSION_TEST_SIGNAL = SignalInfo("emission_test_signal") + private val LAUNCH_TESTS_SIGNAL = SignalInfo("launch_tests", java.lang.Boolean::class.java, String::class.java) + } + + override fun getPluginName() = "SignalTestPlugin" + + override fun getPluginSignals(): Set { + return setOf( + EMISSION_TEST_SIGNAL, + LAUNCH_TESTS_SIGNAL + ) + } + + @UsedByGodot + fun triggerTestSignal1() { + emitSignal(EMISSION_TEST_SIGNAL) + } + + @UsedByGodot + fun triggerLaunchTestSignal() { + emitSignal(LAUNCH_TESTS_SIGNAL, true, "second message") + } +}