You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-04 12:00:25 +00:00
Add Android instrumented tests to the app module
This builds on the work from @dsnopek in https://github.com/dsnopek/javaclasswrapper-test, by importing the set of JavaClassWrapper tests from that repo within the Godot core repo in order to bootstrap and standardize how we write and run Android instrumented tests. The approach used here should serve as a base to build upon to expand the set of instrumented tests used to validate the project's stability. Co-authored-by: David Snopek <dsnopek@gmail.com>
This commit is contained in:
@@ -34,6 +34,11 @@ configurations {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Android instrumented test dependencies
|
||||
androidTestImplementation "androidx.test.ext:junit:1.3.0"
|
||||
androidTestImplementation "androidx.test.espresso:espresso-core:3.7.0"
|
||||
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:1.3.11"
|
||||
|
||||
implementation "androidx.fragment:fragment:$versions.fragmentVersion"
|
||||
implementation "androidx.core:core-splashscreen:$versions.splashscreenVersion"
|
||||
|
||||
@@ -114,6 +119,8 @@ android {
|
||||
targetSdkVersion getExportTargetSdkVersion()
|
||||
|
||||
missingDimensionStrategy 'products', 'template'
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
@@ -214,10 +221,19 @@ android {
|
||||
flavorDimensions 'edition'
|
||||
|
||||
productFlavors {
|
||||
// Product flavor for the standard (no .net support) builds.
|
||||
standard {
|
||||
getIsDefault().set(true)
|
||||
}
|
||||
|
||||
// Product flavor for the Mono (.net) builds.
|
||||
mono {}
|
||||
|
||||
// Product flavor used for running instrumented tests.
|
||||
instrumented {
|
||||
applicationIdSuffix ".instrumented"
|
||||
versionNameSuffix "-instrumented"
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/**************************************************************************/
|
||||
/* GodotAppTest.kt */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
package com.godot.game
|
||||
|
||||
import android.util.Log
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.godot.game.test.GodotAppInstrumentedTestPlugin
|
||||
import org.godotengine.godot.plugin.GodotPluginRegistry
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
/**
|
||||
* This instrumented test will launch the `instrumented` version of GodotApp and run a set of tests against it.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class GodotAppTest {
|
||||
|
||||
companion object {
|
||||
private val TAG = GodotAppTest::class.java.simpleName
|
||||
}
|
||||
|
||||
@get:Rule
|
||||
val godotAppRule = ActivityScenarioRule(GodotApp::class.java)
|
||||
|
||||
/**
|
||||
* Runs the JavaClassWrapper tests via the GodotAppInstrumentedTestPlugin.
|
||||
*/
|
||||
@Test
|
||||
fun runJavaClassWrapperTests() {
|
||||
val testPlugin = GodotPluginRegistry.getPluginRegistry()
|
||||
.getPlugin("GodotAppInstrumentedTestPlugin") as GodotAppInstrumentedTestPlugin?
|
||||
assertNotNull(testPlugin)
|
||||
|
||||
Log.d(TAG, "Waiting for the Godot main loop to start...")
|
||||
testPlugin.waitForGodotMainLoopStarted()
|
||||
|
||||
Log.d(TAG, "Running JavaClassWrapper tests...")
|
||||
val result = testPlugin.runJavaClassWrapperTests()
|
||||
assertNotNull(result)
|
||||
result.exceptionOrNull()?.let { throw it }
|
||||
assertTrue(result.isSuccess)
|
||||
Log.d(TAG, "Passed ${result.getOrNull()} tests")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application>
|
||||
<meta-data
|
||||
android:name="org.godotengine.plugin.v2.GodotAppInstrumentedTestPlugin"
|
||||
android:value="com.godot.game.test.GodotAppInstrumentedTestPlugin"/>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
2
platform/android/java/app/src/instrumented/assets/.gitattributes
vendored
Normal file
2
platform/android/java/app/src/instrumented/assets/.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Normalize EOL for all files that Git considers text files.
|
||||
* text=auto eol=lf
|
||||
3
platform/android/java/app/src/instrumented/assets/.gitignore
vendored
Normal file
3
platform/android/java/app/src/instrumented/assets/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Godot 4+ specific ignores
|
||||
/android/
|
||||
/.godot/editor
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
list=[{
|
||||
"base": &"RefCounted",
|
||||
"class": &"BaseTest",
|
||||
"icon": "",
|
||||
"is_abstract": true,
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://test/base_test.gd"
|
||||
}, {
|
||||
"base": &"BaseTest",
|
||||
"class": &"JavaClassWrapperTests",
|
||||
"icon": "",
|
||||
"is_abstract": false,
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://test/javaclasswrapper/java_class_wrapper_tests.gd"
|
||||
}]
|
||||
Binary file not shown.
@@ -0,0 +1,2 @@
|
||||
source_md5="4cdc64b13a9af63279c486903c9b54cc"
|
||||
dest_md5="ddbdfc47e6405ad8d8e9e6a88a32824e"
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 813 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H447l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c3 34 55 34 58 0v-86c-3-34-55-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>
|
||||
|
After Width: | Height: | Size: 996 B |
@@ -0,0 +1,43 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://srnrli5m8won"
|
||||
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://icon.svg"
|
||||
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
60
platform/android/java/app/src/instrumented/assets/main.gd
Normal file
60
platform/android/java/app/src/instrumented/assets/main.gd
Normal file
@@ -0,0 +1,60 @@
|
||||
extends Node2D
|
||||
|
||||
var _plugin_name = "GodotAppInstrumentedTestPlugin"
|
||||
var _android_plugin
|
||||
|
||||
func _ready():
|
||||
if Engine.has_singleton(_plugin_name):
|
||||
_android_plugin = Engine.get_singleton(_plugin_name)
|
||||
_android_plugin.connect("launch_tests", _launch_tests)
|
||||
else:
|
||||
printerr("Couldn't find plugin " + _plugin_name)
|
||||
get_tree().quit()
|
||||
|
||||
func _launch_tests(test_label: String) -> void:
|
||||
var test_instance: BaseTest = null
|
||||
match test_label:
|
||||
"javaclasswrapper_tests":
|
||||
test_instance = JavaClassWrapperTests.new()
|
||||
|
||||
if test_instance:
|
||||
test_instance.__reset_tests()
|
||||
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:
|
||||
_android_plugin.onTestsFailed(test_label, "Unable to launch tests")
|
||||
|
||||
|
||||
func _on_plugin_toast_button_pressed() -> void:
|
||||
if _android_plugin:
|
||||
_android_plugin.helloWorld()
|
||||
|
||||
func _on_vibration_button_pressed() -> void:
|
||||
var android_runtime = Engine.get_singleton("AndroidRuntime")
|
||||
if android_runtime:
|
||||
print("Checking if the device supports vibration")
|
||||
var vibrator_service = android_runtime.getApplicationContext().getSystemService("vibrator")
|
||||
if vibrator_service:
|
||||
if vibrator_service.hasVibrator():
|
||||
print("Vibration is supported on device! Vibrating now...")
|
||||
var VibrationEffect = JavaClassWrapper.wrap("android.os.VibrationEffect")
|
||||
var effect = VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE)
|
||||
vibrator_service.vibrate(effect)
|
||||
else:
|
||||
printerr("Vibration is not supported on device")
|
||||
else:
|
||||
printerr("Unable to retrieve the vibrator service")
|
||||
else:
|
||||
printerr("Couldn't find AndroidRuntime singleton")
|
||||
|
||||
func _on_gd_script_toast_button_pressed() -> void:
|
||||
var android_runtime = Engine.get_singleton("AndroidRuntime")
|
||||
if android_runtime:
|
||||
var activity = android_runtime.getActivity()
|
||||
|
||||
var toastCallable = func ():
|
||||
var ToastClass = JavaClassWrapper.wrap("android.widget.Toast")
|
||||
ToastClass.makeText(activity, "Toast from GDScript", ToastClass.LENGTH_LONG).show()
|
||||
|
||||
activity.runOnUiThread(android_runtime.createRunnableFromGodotCallable(toastCallable))
|
||||
@@ -0,0 +1 @@
|
||||
uid://bv6y7in6otgcm
|
||||
34
platform/android/java/app/src/instrumented/assets/main.tscn
Normal file
34
platform/android/java/app/src/instrumented/assets/main.tscn
Normal file
@@ -0,0 +1,34 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://cg3hylang5fxn"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bv6y7in6otgcm" path="res://main.gd" id="1_j0gfq"]
|
||||
|
||||
[node name="Main" type="Node2D"]
|
||||
script = ExtResource("1_j0gfq")
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
offset_left = 68.0
|
||||
offset_top = 102.0
|
||||
offset_right = 506.0
|
||||
offset_bottom = 408.0
|
||||
theme_override_constants/separation = 25
|
||||
|
||||
[node name="PluginToastButton" type="Button" parent="VBoxContainer"]
|
||||
custom_minimum_size = Vector2(0, 50)
|
||||
layout_mode = 2
|
||||
text = "Plugin Toast
|
||||
"
|
||||
|
||||
[node name="VibrationButton" type="Button" parent="VBoxContainer"]
|
||||
custom_minimum_size = Vector2(0, 50)
|
||||
layout_mode = 2
|
||||
text = "Vibration"
|
||||
|
||||
[node name="GDScriptToastButton" type="Button" parent="VBoxContainer"]
|
||||
custom_minimum_size = Vector2(0, 50)
|
||||
layout_mode = 2
|
||||
text = "GDScript Toast
|
||||
"
|
||||
|
||||
[connection signal="pressed" from="VBoxContainer/PluginToastButton" to="." method="_on_plugin_toast_button_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/VibrationButton" to="." method="_on_vibration_button_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/GDScriptToastButton" to="." method="_on_gd_script_toast_button_pressed"]
|
||||
@@ -0,0 +1,26 @@
|
||||
; Engine configuration file.
|
||||
; It's best edited using the editor UI and not directly,
|
||||
; since the parameters that go here are not all obvious.
|
||||
;
|
||||
; Format:
|
||||
; [section] ; section goes between []
|
||||
; param=value ; assign values to parameters
|
||||
|
||||
config_version=5
|
||||
|
||||
[application]
|
||||
|
||||
config/name="Godot App Instrumentation Tests"
|
||||
run/main_scene="res://main.tscn"
|
||||
config/features=PackedStringArray("4.5", "GL Compatibility")
|
||||
config/icon="res://icon.svg"
|
||||
|
||||
[debug]
|
||||
|
||||
settings/stdout/verbose_stdout=true
|
||||
|
||||
[rendering]
|
||||
|
||||
renderer/rendering_method="gl_compatibility"
|
||||
renderer/rendering_method.mobile="gl_compatibility"
|
||||
textures/vram_compression/import_etc2_astc=true
|
||||
@@ -0,0 +1,44 @@
|
||||
@abstract class_name BaseTest
|
||||
|
||||
var _test_started := 0
|
||||
var _test_completed := 0
|
||||
var _test_assert_passes := 0
|
||||
var _test_assert_failures := 0
|
||||
|
||||
@abstract func run_tests()
|
||||
|
||||
func __exec_test(test_func: Callable):
|
||||
_test_started += 1
|
||||
test_func.call()
|
||||
_test_completed += 1
|
||||
|
||||
func __reset_tests():
|
||||
_test_started = 0
|
||||
_test_completed = 0
|
||||
_test_assert_passes = 0
|
||||
_test_assert_failures = 0
|
||||
|
||||
func __get_stack_frame():
|
||||
for s in get_stack():
|
||||
if not s.function.begins_with('__') and s.function != "assert_equal":
|
||||
return s
|
||||
return null
|
||||
|
||||
func __assert_pass():
|
||||
_test_assert_passes += 1
|
||||
pass
|
||||
|
||||
func __assert_fail():
|
||||
_test_assert_failures += 1
|
||||
var s = __get_stack_frame()
|
||||
if s != null:
|
||||
print_rich ("[color=red] == FAILURE: In function %s() from '%s' on line %s[/color]" % [s.function, s.source, s.line])
|
||||
else:
|
||||
print_rich ("[color=red] == FAILURE (run with --debug to get more information!) ==[/color]")
|
||||
|
||||
func assert_equal(actual, expected):
|
||||
if actual == expected:
|
||||
__assert_pass()
|
||||
else:
|
||||
__assert_fail()
|
||||
print (" |-> Expected '%s' but got '%s'" % [expected, actual])
|
||||
@@ -0,0 +1 @@
|
||||
uid://mofa8j0d801f
|
||||
@@ -0,0 +1,136 @@
|
||||
class_name JavaClassWrapperTests
|
||||
extends BaseTest
|
||||
|
||||
func run_tests():
|
||||
print("JavaClassWrapper tests starting..")
|
||||
|
||||
__exec_test(test_exceptions)
|
||||
|
||||
__exec_test(test_multiple_signatures)
|
||||
__exec_test(test_array_arguments)
|
||||
__exec_test(test_array_return)
|
||||
|
||||
__exec_test(test_dictionary)
|
||||
|
||||
__exec_test(test_object_overload)
|
||||
|
||||
__exec_test(test_variant_conversion_safe_from_stack_overflow)
|
||||
|
||||
print("JavaClassWrapper tests finished.")
|
||||
print("Tests started: " + str(_test_started))
|
||||
print("Tests completed: " + str(_test_completed))
|
||||
|
||||
|
||||
func test_exceptions() -> void:
|
||||
var TestClass: JavaClass = JavaClassWrapper.wrap('com.godot.game.test.javaclasswrapper.TestClass')
|
||||
#print(TestClass.get_java_method_list())
|
||||
|
||||
assert_equal(JavaClassWrapper.get_exception(), null)
|
||||
|
||||
assert_equal(TestClass.testExc(27), 0)
|
||||
assert_equal(str(JavaClassWrapper.get_exception()), '<JavaObject:java.lang.NullPointerException "java.lang.NullPointerException">')
|
||||
|
||||
assert_equal(JavaClassWrapper.get_exception(), null)
|
||||
|
||||
func test_multiple_signatures() -> void:
|
||||
var TestClass: JavaClass = JavaClassWrapper.wrap('com.godot.game.test.javaclasswrapper.TestClass')
|
||||
|
||||
var ai := [1, 2]
|
||||
assert_equal(TestClass.testMethod(1, ai), "IntArray: [1, 2]")
|
||||
|
||||
var astr := ["abc"]
|
||||
assert_equal(TestClass.testMethod(2, astr), "IntArray: [0]")
|
||||
|
||||
var atstr: Array[String] = ["abc"]
|
||||
assert_equal(TestClass.testMethod(3, atstr), "StringArray: [abc]")
|
||||
|
||||
var TestClass2: JavaClass = JavaClassWrapper.wrap('com.godot.game.test.javaclasswrapper.TestClass2')
|
||||
var aobjl: Array[Object] = [
|
||||
TestClass2.TestClass2(27),
|
||||
TestClass2.TestClass2(135),
|
||||
]
|
||||
assert_equal(TestClass.testMethod(3, aobjl), "testObjects: 27 135")
|
||||
|
||||
func test_array_arguments() -> void:
|
||||
var TestClass: JavaClass = JavaClassWrapper.wrap('com.godot.game.test.javaclasswrapper.TestClass')
|
||||
|
||||
assert_equal(TestClass.testArgBoolArray([true, false, true]), "[true, false, true]")
|
||||
assert_equal(TestClass.testArgByteArray(PackedByteArray([1, 2, 3])), "[1, 2, 3]")
|
||||
assert_equal(TestClass.testArgCharArray("abc".to_utf16_buffer()), "abc");
|
||||
assert_equal(TestClass.testArgShortArray(PackedInt32Array([27, 28, 29])), "[27, 28, 29]")
|
||||
assert_equal(TestClass.testArgShortArray([27, 28, 29]), "[27, 28, 29]")
|
||||
assert_equal(TestClass.testArgIntArray(PackedInt32Array([7, 8, 9])), "[7, 8, 9]")
|
||||
assert_equal(TestClass.testArgIntArray([7, 8, 9]), "[7, 8, 9]")
|
||||
assert_equal(TestClass.testArgLongArray(PackedInt64Array([17, 18, 19])), "[17, 18, 19]")
|
||||
assert_equal(TestClass.testArgLongArray([17, 18, 19]), "[17, 18, 19]")
|
||||
assert_equal(TestClass.testArgFloatArray(PackedFloat32Array([17.1, 18.2, 19.3])), "[17.1, 18.2, 19.3]")
|
||||
assert_equal(TestClass.testArgFloatArray([17.1, 18.2, 19.3]), "[17.1, 18.2, 19.3]")
|
||||
assert_equal(TestClass.testArgDoubleArray(PackedFloat64Array([37.1, 38.2, 39.3])), "[37.1, 38.2, 39.3]")
|
||||
assert_equal(TestClass.testArgDoubleArray([37.1, 38.2, 39.3]), "[37.1, 38.2, 39.3]")
|
||||
|
||||
func test_array_return() -> void:
|
||||
var TestClass: JavaClass = JavaClassWrapper.wrap('com.godot.game.test.javaclasswrapper.TestClass')
|
||||
#print(TestClass.get_java_method_list())
|
||||
|
||||
assert_equal(TestClass.testRetBoolArray(), [true, false, true])
|
||||
assert_equal(TestClass.testRetWrappedBoolArray(), [true, false, true])
|
||||
|
||||
assert_equal(TestClass.testRetByteArray(), PackedByteArray([1, 2, 3]))
|
||||
assert_equal(TestClass.testRetWrappedByteArray(), PackedByteArray([1, 2, 3]))
|
||||
|
||||
assert_equal(TestClass.testRetCharArray().get_string_from_utf16(), "abc")
|
||||
assert_equal(TestClass.testRetWrappedCharArray().get_string_from_utf16(), "abc")
|
||||
|
||||
assert_equal(TestClass.testRetShortArray(), PackedInt32Array([11, 12, 13]))
|
||||
assert_equal(TestClass.testRetWrappedShortArray(), PackedInt32Array([11, 12, 13]))
|
||||
|
||||
assert_equal(TestClass.testRetIntArray(), PackedInt32Array([21, 22, 23]))
|
||||
assert_equal(TestClass.testRetWrappedIntArray(), PackedInt32Array([21, 22, 23]))
|
||||
|
||||
assert_equal(TestClass.testRetLongArray(), PackedInt64Array([41, 42, 43]))
|
||||
assert_equal(TestClass.testRetWrappedLongArray(), PackedInt64Array([41, 42, 43]))
|
||||
|
||||
assert_equal(TestClass.testRetFloatArray(), PackedFloat32Array([31.1, 32.2, 33.3]))
|
||||
assert_equal(TestClass.testRetWrappedFloatArray(), PackedFloat32Array([31.1, 32.2, 33.3]))
|
||||
|
||||
assert_equal(TestClass.testRetDoubleArray(), PackedFloat64Array([41.1, 42.2, 43.3]))
|
||||
assert_equal(TestClass.testRetWrappedDoubleArray(), PackedFloat64Array([41.1, 42.2, 43.3]))
|
||||
|
||||
var obj_array = TestClass.testRetObjectArray()
|
||||
assert_equal(str(obj_array[0]), '<JavaObject:com.godot.game.test.javaclasswrapper.TestClass2 "51">')
|
||||
assert_equal(str(obj_array[1]), '<JavaObject:com.godot.game.test.javaclasswrapper.TestClass2 "52">')
|
||||
|
||||
assert_equal(TestClass.testRetStringArray(), PackedStringArray(["I", "am", "String"]))
|
||||
assert_equal(TestClass.testRetCharSequenceArray(), PackedStringArray(["I", "am", "CharSequence"]))
|
||||
|
||||
func test_dictionary():
|
||||
var TestClass: JavaClass = JavaClassWrapper.wrap('com.godot.game.test.javaclasswrapper.TestClass')
|
||||
assert_equal(TestClass.testDictionary({a = 1, b = 2}), "{a=1, b=2}")
|
||||
assert_equal(TestClass.testRetDictionary(), {a = 1, b = 2})
|
||||
assert_equal(TestClass.testRetDictionaryArray(), [{a = 1, b = 2}])
|
||||
assert_equal(TestClass.testDictionaryNested({a = 1, b = [2, 3], c = 4}), "{a: 1, b: [2, 3], c: 4}")
|
||||
|
||||
func test_object_overload():
|
||||
var TestClass: JavaClass = JavaClassWrapper.wrap('com.godot.game.test.javaclasswrapper.TestClass')
|
||||
var TestClass2: JavaClass = JavaClassWrapper.wrap('com.godot.game.test.javaclasswrapper.TestClass2')
|
||||
var TestClass3: JavaClass = JavaClassWrapper.wrap('com.godot.game.test.javaclasswrapper.TestClass3')
|
||||
|
||||
var t2 = TestClass2.TestClass2(33)
|
||||
var t3 = TestClass3.TestClass3("thirty three")
|
||||
|
||||
assert_equal(TestClass.testObjectOverload(t2), "TestClass2: 33")
|
||||
assert_equal(TestClass.testObjectOverload(t3), "TestClass3: thirty three")
|
||||
|
||||
var arr_of_t2 = [t2, TestClass2.TestClass2(34)]
|
||||
var arr_of_t3 = [t3, TestClass3.TestClass3("thirty four")]
|
||||
|
||||
assert_equal(TestClass.testObjectOverloadArray(arr_of_t2), "TestClass2: [33, 34]")
|
||||
assert_equal(TestClass.testObjectOverloadArray(arr_of_t3), "TestClass3: [thirty three, thirty four]")
|
||||
|
||||
func test_variant_conversion_safe_from_stack_overflow():
|
||||
var TestClass: JavaClass = JavaClassWrapper.wrap('com.godot.game.test.javaclasswrapper.TestClass')
|
||||
var arr: Array = [42]
|
||||
var dict: Dictionary = {"arr": arr}
|
||||
arr.append(dict)
|
||||
# The following line will crash with stack overflow if not handled property:
|
||||
TestClass.testDictionary(dict)
|
||||
@@ -0,0 +1 @@
|
||||
uid://3ql82ggk41xc
|
||||
@@ -0,0 +1,144 @@
|
||||
/**************************************************************************/
|
||||
/* GodotAppInstrumentedTestPlugin.kt */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
package com.godot.game.test
|
||||
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import org.godotengine.godot.Godot
|
||||
import org.godotengine.godot.plugin.GodotPlugin
|
||||
import org.godotengine.godot.plugin.UsedByGodot
|
||||
import org.godotengine.godot.plugin.SignalInfo
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
/**
|
||||
* [GodotPlugin] used to drive instrumented tests.
|
||||
*/
|
||||
class GodotAppInstrumentedTestPlugin(godot: Godot) : GodotPlugin(godot) {
|
||||
|
||||
companion object {
|
||||
private val TAG = GodotAppInstrumentedTestPlugin::class.java.simpleName
|
||||
private const val MAIN_LOOP_STARTED_LATCH_KEY = "main_loop_started_latch"
|
||||
|
||||
private const val JAVACLASSWRAPPER_TESTS = "javaclasswrapper_tests"
|
||||
|
||||
private val LAUNCH_TESTS_SIGNAL = SignalInfo("launch_tests", String::class.java)
|
||||
|
||||
private val SIGNALS = setOf(
|
||||
LAUNCH_TESTS_SIGNAL
|
||||
)
|
||||
}
|
||||
|
||||
private val testResults = ConcurrentHashMap<String, Result<Any>>()
|
||||
private val latches = ConcurrentHashMap<String, CountDownLatch>()
|
||||
|
||||
init {
|
||||
// Add a countdown latch that is triggered when `onGodotMainLoopStarted` is fired.
|
||||
// This will be used by tests to wait until the engine is ready.
|
||||
latches[MAIN_LOOP_STARTED_LATCH_KEY] = CountDownLatch(1)
|
||||
}
|
||||
|
||||
override fun getPluginName() = "GodotAppInstrumentedTestPlugin"
|
||||
|
||||
override fun getPluginSignals() = SIGNALS
|
||||
|
||||
override fun onGodotMainLoopStarted() {
|
||||
super.onGodotMainLoopStarted()
|
||||
latches.remove(MAIN_LOOP_STARTED_LATCH_KEY)?.countDown()
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the instrumented test to wait until the Godot main loop is up and running.
|
||||
*/
|
||||
internal fun waitForGodotMainLoopStarted() {
|
||||
// Wait on the CountDownLatch for `onGodotMainLoopStarted`
|
||||
try {
|
||||
latches[MAIN_LOOP_STARTED_LATCH_KEY]?.await()
|
||||
} catch (e: InterruptedException) {
|
||||
Log.e(TAG, "Unable to wait for Godot main loop started event.", e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This launches the JavaClassWrapper tests, and wait until the tests are complete before returning.
|
||||
*/
|
||||
internal fun runJavaClassWrapperTests(): Result<Any>? {
|
||||
return launchTests(JAVACLASSWRAPPER_TESTS)
|
||||
}
|
||||
|
||||
private fun launchTests(testLabel: String): Result<Any>? {
|
||||
val latch = latches.getOrPut(testLabel) { CountDownLatch(1) }
|
||||
emitSignal(LAUNCH_TESTS_SIGNAL.name, testLabel)
|
||||
return try {
|
||||
latch.await()
|
||||
val result = testResults.remove(testLabel)
|
||||
result
|
||||
} catch (e: InterruptedException) {
|
||||
Log.e(TAG, "Unable to wait for completion for $testLabel", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked from gdscript when the tests are completed.
|
||||
*/
|
||||
@UsedByGodot
|
||||
fun onTestsCompleted(testLabel: String, passes: Int, failures: Int) {
|
||||
Log.d(TAG, "$testLabel tests completed")
|
||||
val result = if (failures == 0) {
|
||||
Result.success(passes)
|
||||
} else {
|
||||
Result.failure(AssertionError("$failures tests failed!"))
|
||||
}
|
||||
|
||||
completeTest(testLabel, result)
|
||||
}
|
||||
|
||||
@UsedByGodot
|
||||
fun onTestsFailed(testLabel: String, failureMessage: String) {
|
||||
Log.d(TAG, "$testLabel tests failed")
|
||||
val result: Result<Any> = Result.failure(AssertionError(failureMessage))
|
||||
completeTest(testLabel, result)
|
||||
}
|
||||
|
||||
private fun completeTest(testKey: String, result: Result<Any>) {
|
||||
testResults[testKey] = result
|
||||
latches.remove(testKey)?.countDown()
|
||||
}
|
||||
|
||||
@UsedByGodot
|
||||
fun helloWorld() {
|
||||
runOnHostThread {
|
||||
Toast.makeText(activity, "Toast from Android plugin", Toast.LENGTH_LONG).show()
|
||||
Log.v(pluginName, "Hello World")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
/**************************************************************************/
|
||||
/* TestClass.kt */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
package com.godot.game.test.javaclasswrapper
|
||||
|
||||
import org.godotengine.godot.Dictionary
|
||||
import kotlin.collections.contentToString
|
||||
import kotlin.collections.joinToString
|
||||
|
||||
class TestClass {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun stringify(value: Any?): String {
|
||||
return when (value) {
|
||||
null -> "null"
|
||||
is Map<*, *> -> {
|
||||
val entries = value.entries.joinToString(", ") { (k, v) -> "${stringify(k)}: ${stringify(v)}" }
|
||||
"{$entries}"
|
||||
}
|
||||
|
||||
is List<*> -> value.joinToString(prefix = "[", postfix = "]") { stringify(it) }
|
||||
is Array<*> -> value.joinToString(prefix = "[", postfix = "]") { stringify(it) }
|
||||
is IntArray -> value.joinToString(prefix = "[", postfix = "]")
|
||||
is LongArray -> value.joinToString(prefix = "[", postfix = "]")
|
||||
is FloatArray -> value.joinToString(prefix = "[", postfix = "]")
|
||||
is DoubleArray -> value.joinToString(prefix = "[", postfix = "]")
|
||||
is BooleanArray -> value.joinToString(prefix = "[", postfix = "]")
|
||||
is CharArray -> value.joinToString(prefix = "[", postfix = "]")
|
||||
else -> value.toString()
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testDictionary(d: Dictionary): String {
|
||||
return d.toString()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testDictionaryNested(d: Dictionary): String {
|
||||
return stringify(d)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetDictionary(): Dictionary {
|
||||
var d = Dictionary()
|
||||
d.putAll(mapOf("a" to 1, "b" to 2))
|
||||
return d
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetDictionaryArray(): Array<Dictionary> {
|
||||
var d = Dictionary()
|
||||
d.putAll(mapOf("a" to 1, "b" to 2))
|
||||
return arrayOf(d)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testMethod(int: Int, array: IntArray): String {
|
||||
return "IntArray: " + array.contentToString()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testMethod(int: Int, vararg args: String): String {
|
||||
return "StringArray: " + args.contentToString()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testMethod(int: Int, objects: Array<TestClass2>): String {
|
||||
return "testObjects: " + objects.joinToString(separator = " ") { it.getValue().toString() }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testExc(i: Int): Int {
|
||||
val s: String? = null
|
||||
s!!.length
|
||||
return i
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testArgBoolArray(a: BooleanArray): String {
|
||||
return a.contentToString();
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testArgByteArray(a: ByteArray): String {
|
||||
return a.contentToString();
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testArgCharArray(a: CharArray): String {
|
||||
return a.joinToString("")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testArgShortArray(a: ShortArray): String {
|
||||
return a.contentToString();
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testArgIntArray(a: IntArray): String {
|
||||
return a.contentToString();
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testArgLongArray(a: LongArray): String {
|
||||
return a.contentToString();
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testArgFloatArray(a: FloatArray): String {
|
||||
return a.contentToString();
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testArgDoubleArray(a: DoubleArray): String {
|
||||
return a.contentToString();
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetBoolArray(): BooleanArray {
|
||||
return booleanArrayOf(true, false, true)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetByteArray(): ByteArray {
|
||||
return byteArrayOf(1, 2, 3)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetCharArray(): CharArray {
|
||||
return "abc".toCharArray()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetShortArray(): ShortArray {
|
||||
return shortArrayOf(11, 12, 13)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetIntArray(): IntArray {
|
||||
return intArrayOf(21, 22, 23)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetLongArray(): LongArray {
|
||||
return longArrayOf(41, 42, 43)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetFloatArray(): FloatArray {
|
||||
return floatArrayOf(31.1f, 32.2f, 33.3f)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetDoubleArray(): DoubleArray {
|
||||
return doubleArrayOf(41.1, 42.2, 43.3)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetWrappedBoolArray(): Array<Boolean> {
|
||||
return arrayOf(true, false, true)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetWrappedByteArray(): Array<Byte> {
|
||||
return arrayOf(1, 2, 3)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetWrappedCharArray(): Array<Char> {
|
||||
return arrayOf('a', 'b', 'c')
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetWrappedShortArray(): Array<Short> {
|
||||
return arrayOf(11, 12, 13)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetWrappedIntArray(): Array<Int> {
|
||||
return arrayOf(21, 22, 23)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetWrappedLongArray(): Array<Long> {
|
||||
return arrayOf(41, 42, 43)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetWrappedFloatArray(): Array<Float> {
|
||||
return arrayOf(31.1f, 32.2f, 33.3f)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetWrappedDoubleArray(): Array<Double> {
|
||||
return arrayOf(41.1, 42.2, 43.3)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetObjectArray(): Array<TestClass2> {
|
||||
return arrayOf(TestClass2(51), TestClass2(52));
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetStringArray(): Array<String> {
|
||||
return arrayOf("I", "am", "String")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testRetCharSequenceArray(): Array<CharSequence> {
|
||||
return arrayOf("I", "am", "CharSequence")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testObjectOverload(a: TestClass2): String {
|
||||
return "TestClass2: $a"
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testObjectOverload(a: TestClass3): String {
|
||||
return "TestClass3: $a"
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testObjectOverloadArray(a: Array<TestClass2>): String {
|
||||
return "TestClass2: " + a.contentToString()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testObjectOverloadArray(a: Array<TestClass3>): String {
|
||||
return "TestClass3: " + a.contentToString()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**************************************************************************/
|
||||
/* TestClass2.kt */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
package com.godot.game.test.javaclasswrapper
|
||||
|
||||
class TestClass2(private val value: Int) {
|
||||
fun getValue(): Int {
|
||||
return value
|
||||
}
|
||||
override fun toString(): String {
|
||||
return value.toString()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**************************************************************************/
|
||||
/* TestClass3.kt */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
package com.godot.game.test.javaclasswrapper
|
||||
|
||||
class TestClass3(private val value: String) {
|
||||
fun getValue(): String {
|
||||
return value
|
||||
}
|
||||
override fun toString(): String {
|
||||
return value
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="godot_project_name_string">Godot App Instrumented Tests</string>
|
||||
</resources>
|
||||
@@ -83,4 +83,13 @@ public class GodotApp extends GodotActivity {
|
||||
super.onGodotMainLoopStarted();
|
||||
runOnUiThread(updateWindowAppearance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGodotForceQuit(Godot instance) {
|
||||
if (!BuildConfig.FLAVOR.equals("instrumented")) {
|
||||
// For instrumented builds, we disable force-quitting to allow the instrumented tests to complete
|
||||
// successfully, otherwise they fail when the process crashes.
|
||||
super.onGodotForceQuit(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user