Add 'engine/' from commit 'a8e37fc010'
git-subtree-dir: engine git-subtree-mainline:b74841629egit-subtree-split:a8e37fc010
This commit is contained in:
commit
c3f9669b10
14113 changed files with 7458101 additions and 0 deletions
|
|
@ -0,0 +1,172 @@
|
|||
/**************************************************************************/
|
||||
/* 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.content.ComponentName
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import androidx.test.core.app.ActivityScenario
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.godot.game.test.GodotAppInstrumentedTestPlugin
|
||||
import org.godotengine.godot.GodotActivity.Companion.EXTRA_COMMAND_LINE_PARAMS
|
||||
import org.godotengine.godot.plugin.GodotPluginRegistry
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
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
|
||||
|
||||
private const val GODOT_APP_LAUNCHER_CLASS_NAME = "com.godot.game.GodotAppLauncher"
|
||||
private const val GODOT_APP_CLASS_NAME = "com.godot.game.GodotApp"
|
||||
|
||||
private val TEST_COMMAND_LINE_PARAMS = arrayOf("This is a test")
|
||||
}
|
||||
|
||||
private fun getTestPlugin(): GodotAppInstrumentedTestPlugin? {
|
||||
return GodotPluginRegistry.getPluginRegistry()
|
||||
.getPlugin("GodotAppInstrumentedTestPlugin") as GodotAppInstrumentedTestPlugin?
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the JavaClassWrapper tests via the GodotAppInstrumentedTestPlugin.
|
||||
*/
|
||||
@Test
|
||||
fun runJavaClassWrapperTests() {
|
||||
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 JavaClassWrapper tests...")
|
||||
val result = testPlugin.runJavaClassWrapperTests()
|
||||
assertNotNull(result)
|
||||
result.exceptionOrNull()?.let { throw it }
|
||||
assertTrue(result.isSuccess)
|
||||
Log.d(TAG, "Passed ${result.getOrNull()} tests")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs file access related tests.
|
||||
*/
|
||||
@Test
|
||||
fun runFileAccessTests() {
|
||||
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 FileAccess tests...")
|
||||
val result = testPlugin.runFileAccessTests()
|
||||
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.
|
||||
*/
|
||||
@Test
|
||||
fun testImplicitGodotAppLauncherLaunch() {
|
||||
val implicitLaunchIntent = Intent().apply {
|
||||
setPackage(BuildConfig.APPLICATION_ID)
|
||||
action = Intent.ACTION_MAIN
|
||||
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
putExtra(EXTRA_COMMAND_LINE_PARAMS, TEST_COMMAND_LINE_PARAMS)
|
||||
}
|
||||
ActivityScenario.launch<GodotApp>(implicitLaunchIntent).use { scenario ->
|
||||
scenario.onActivity { activity ->
|
||||
assertEquals(activity.intent.component?.className, GODOT_APP_LAUNCHER_CLASS_NAME)
|
||||
|
||||
val commandLineParams = activity.intent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
|
||||
assertNull(commandLineParams)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test explicit launch of the Godot app via its activity-alias launcher, and validates it resolves properly.
|
||||
*/
|
||||
@Test
|
||||
fun testExplicitGodotAppLauncherLaunch() {
|
||||
val explicitIntent = Intent().apply {
|
||||
component = ComponentName(BuildConfig.APPLICATION_ID, GODOT_APP_LAUNCHER_CLASS_NAME)
|
||||
putExtra(EXTRA_COMMAND_LINE_PARAMS, TEST_COMMAND_LINE_PARAMS)
|
||||
}
|
||||
ActivityScenario.launch<GodotApp>(explicitIntent).use { scenario ->
|
||||
scenario.onActivity { activity ->
|
||||
assertEquals(activity.intent.component?.className, GODOT_APP_LAUNCHER_CLASS_NAME)
|
||||
|
||||
val commandLineParams = activity.intent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
|
||||
assertNull(commandLineParams)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test explicit launch of the `GodotApp` activity.
|
||||
*/
|
||||
@Test
|
||||
fun testExplicitGodotAppLaunch() {
|
||||
val explicitIntent = Intent().apply {
|
||||
component = ComponentName(BuildConfig.APPLICATION_ID, GODOT_APP_CLASS_NAME)
|
||||
putExtra(EXTRA_COMMAND_LINE_PARAMS, TEST_COMMAND_LINE_PARAMS)
|
||||
}
|
||||
ActivityScenario.launch<GodotApp>(explicitIntent).use { scenario ->
|
||||
scenario.onActivity { activity ->
|
||||
assertEquals(activity.intent.component?.className, GODOT_APP_CLASS_NAME)
|
||||
|
||||
val commandLineParams = activity.intent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
|
||||
assertNotNull(commandLineParams)
|
||||
assertTrue(commandLineParams.contentEquals(TEST_COMMAND_LINE_PARAMS))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
engine/platform/android/java/app/src/instrumented/assets/.gitattributes
vendored
Normal file
2
engine/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
engine/platform/android/java/app/src/instrumented/assets/.gitignore
vendored
Normal file
3
engine/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,25 @@
|
|||
list=[{
|
||||
"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,
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://test/file_access/file_access_tests.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
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
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()
|
||||
"file_access_tests":
|
||||
test_instance = FileAccessTests.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
|
||||
|
|
@ -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,52 @@
|
|||
@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
|
||||
var ret = test_func.call()
|
||||
if ret == true:
|
||||
_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])
|
||||
|
||||
func assert_true(value):
|
||||
if value:
|
||||
__assert_pass()
|
||||
else:
|
||||
__assert_fail()
|
||||
print (" |-> Expected '%s' to be truthy" % value)
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://mofa8j0d801f
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
class_name FileAccessTests
|
||||
extends BaseTest
|
||||
|
||||
const FILE_CONTENT = "This is a test for reading / writing to the "
|
||||
|
||||
func run_tests():
|
||||
print("FileAccess tests starting...")
|
||||
__exec_test(test_obb_dir_access)
|
||||
__exec_test(test_internal_app_dir_access)
|
||||
__exec_test(test_internal_cache_dir_access)
|
||||
__exec_test(test_external_app_dir_access)
|
||||
|
||||
# Scoped storage: Testing access to Downloads and Documents directory.
|
||||
var version = JavaClassWrapper.wrap("android.os.Build$VERSION")
|
||||
if version.SDK_INT >= 29:
|
||||
__exec_test(test_downloads_dir_access)
|
||||
__exec_test(test_documents_dir_access)
|
||||
|
||||
func _test_dir_access(dir_path: String, data_file_content: String) -> bool:
|
||||
print("Testing access to " + dir_path)
|
||||
var data_file_path = dir_path.path_join("data.dat")
|
||||
|
||||
var data_file = FileAccess.open(data_file_path, FileAccess.WRITE)
|
||||
assert_true(data_file != null)
|
||||
assert_true(data_file.store_string(data_file_content))
|
||||
data_file.close()
|
||||
|
||||
data_file = FileAccess.open(data_file_path, FileAccess.READ)
|
||||
assert_true(data_file != null)
|
||||
var file_content = data_file.get_as_text()
|
||||
assert_equal(file_content, data_file_content)
|
||||
data_file.close()
|
||||
|
||||
var deletion_result = DirAccess.remove_absolute(data_file_path)
|
||||
assert_equal(deletion_result, OK)
|
||||
return true
|
||||
|
||||
func test_obb_dir_access() -> bool:
|
||||
var android_runtime = Engine.get_singleton("AndroidRuntime")
|
||||
assert_true(android_runtime != null)
|
||||
|
||||
var app_context = android_runtime.getApplicationContext()
|
||||
var obb_dir: String = app_context.getObbDir().getCanonicalPath()
|
||||
_test_dir_access(obb_dir, FILE_CONTENT + "obb dir.")
|
||||
return true
|
||||
|
||||
func test_internal_app_dir_access() -> bool:
|
||||
var android_runtime = Engine.get_singleton("AndroidRuntime")
|
||||
assert_true(android_runtime != null)
|
||||
|
||||
var app_context = android_runtime.getApplicationContext()
|
||||
var internal_app_dir: String = app_context.getFilesDir().getCanonicalPath()
|
||||
_test_dir_access(internal_app_dir, FILE_CONTENT + "internal app dir.")
|
||||
return true
|
||||
|
||||
func test_internal_cache_dir_access() -> bool:
|
||||
var android_runtime = Engine.get_singleton("AndroidRuntime")
|
||||
assert_true(android_runtime != null)
|
||||
|
||||
var app_context = android_runtime.getApplicationContext()
|
||||
var internal_cache_dir: String = app_context.getCacheDir().getCanonicalPath()
|
||||
_test_dir_access(internal_cache_dir, FILE_CONTENT + "internal cache dir.")
|
||||
return true
|
||||
|
||||
func test_external_app_dir_access() -> bool:
|
||||
var android_runtime = Engine.get_singleton("AndroidRuntime")
|
||||
assert_true(android_runtime != null)
|
||||
|
||||
var app_context = android_runtime.getApplicationContext()
|
||||
var external_app_dir: String = app_context.getExternalFilesDir("").getCanonicalPath()
|
||||
_test_dir_access(external_app_dir, FILE_CONTENT + "external app dir.")
|
||||
return true
|
||||
|
||||
func test_downloads_dir_access() -> bool:
|
||||
var EnvironmentClass = JavaClassWrapper.wrap("android.os.Environment")
|
||||
var downloads_dir = EnvironmentClass.getExternalStoragePublicDirectory(EnvironmentClass.DIRECTORY_DOWNLOADS).getCanonicalPath()
|
||||
_test_dir_access(downloads_dir, FILE_CONTENT + "downloads dir.")
|
||||
return true
|
||||
|
||||
func test_documents_dir_access() -> bool:
|
||||
var EnvironmentClass = JavaClassWrapper.wrap("android.os.Environment")
|
||||
var documents_dir = EnvironmentClass.getExternalStoragePublicDirectory(EnvironmentClass.DIRECTORY_DOCUMENTS).getCanonicalPath()
|
||||
_test_dir_access(documents_dir, FILE_CONTENT + "documents dir.")
|
||||
return true
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://b1o8wj1s4vghn
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
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)
|
||||
|
||||
__exec_test(test_big_integers)
|
||||
|
||||
__exec_test(test_callable)
|
||||
|
||||
print("JavaClassWrapper tests finished.")
|
||||
print("Tests started: " + str(_test_started))
|
||||
print("Tests completed: " + str(_test_completed))
|
||||
|
||||
|
||||
func test_exceptions() -> bool:
|
||||
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)
|
||||
|
||||
return true
|
||||
|
||||
func test_multiple_signatures() -> bool:
|
||||
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")
|
||||
|
||||
return true
|
||||
|
||||
func test_array_arguments() -> bool:
|
||||
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]")
|
||||
|
||||
return true
|
||||
|
||||
func test_array_return() -> bool:
|
||||
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"]))
|
||||
|
||||
return true
|
||||
|
||||
func test_dictionary() -> bool:
|
||||
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}")
|
||||
return true
|
||||
|
||||
func test_object_overload() -> bool:
|
||||
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]")
|
||||
return true
|
||||
|
||||
func test_variant_conversion_safe_from_stack_overflow() -> bool:
|
||||
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)
|
||||
return true
|
||||
|
||||
func test_big_integers() -> bool:
|
||||
var TestClass: JavaClass = JavaClassWrapper.wrap('com.godot.game.test.javaclasswrapper.TestClass')
|
||||
assert_equal(TestClass.testArgLong(4242424242), "4242424242")
|
||||
assert_equal(TestClass.testArgLong(-4242424242), "-4242424242")
|
||||
assert_equal(TestClass.testDictionary({a = 4242424242, b = -4242424242}), "{a=4242424242, b=-4242424242}")
|
||||
return true
|
||||
|
||||
func test_callable() -> bool:
|
||||
var android_runtime = Engine.get_singleton("AndroidRuntime")
|
||||
assert_true(android_runtime != null)
|
||||
|
||||
var cb1_data := {called = false}
|
||||
var cb1 = func():
|
||||
cb1_data['called'] = true
|
||||
return null
|
||||
android_runtime.createRunnableFromGodotCallable(cb1).run()
|
||||
assert_equal(cb1_data['called'], true)
|
||||
|
||||
return true
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://3ql82ggk41xc
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
/**************************************************************************/
|
||||
/* 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 const val FILE_ACCESS_TESTS = "file_access_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)
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches the FileAccess tests, and wait until the tests are complete before returning.
|
||||
*/
|
||||
internal fun runFileAccessTests(): Result<Any>? {
|
||||
return launchTests(FILE_ACCESS_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,266 @@
|
|||
/**************************************************************************/
|
||||
/* 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 testArgLong(a: Long): String {
|
||||
return "${a}"
|
||||
}
|
||||
|
||||
@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>
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0"
|
||||
android:installLocation="auto" >
|
||||
|
||||
<supports-screens
|
||||
android:smallScreens="true"
|
||||
android:normalScreens="true"
|
||||
android:largeScreens="true"
|
||||
android:xlargeScreens="true" />
|
||||
|
||||
<uses-feature
|
||||
android:glEsVersion="0x00030000"
|
||||
android:required="true" />
|
||||
|
||||
<application
|
||||
android:label="@string/godot_project_name_string"
|
||||
android:allowBackup="false"
|
||||
android:icon="@mipmap/icon"
|
||||
android:appCategory="game"
|
||||
android:isGame="true"
|
||||
android:hasFragileUserData="false"
|
||||
android:requestLegacyExternalStorage="false"
|
||||
tools:ignore="GoogleAppIndexingWarning" >
|
||||
<profileable
|
||||
android:shell="true"
|
||||
android:enabled="true"
|
||||
tools:targetApi="29" />
|
||||
|
||||
<activity
|
||||
android:name=".GodotApp"
|
||||
android:theme="@style/GodotAppSplashTheme"
|
||||
android:launchMode="singleInstancePerTask"
|
||||
android:excludeFromRecents="false"
|
||||
android:exported="false"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:screenOrientation="landscape"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:configChanges="layoutDirection|locale|orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
|
||||
android:resizeableActivity="false"
|
||||
tools:ignore="UnusedAttribute" />
|
||||
<activity-alias
|
||||
android:name=".GodotAppLauncher"
|
||||
android:targetActivity=".GodotApp"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
2
engine/platform/android/java/app/src/main/assets/.gitignore
vendored
Normal file
2
engine/platform/android/java/app/src/main/assets/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/**************************************************************************/
|
||||
/* GodotApp.java */
|
||||
/**************************************************************************/
|
||||
/* 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 org.godotengine.godot.Godot;
|
||||
import org.godotengine.godot.GodotActivity;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.activity.EdgeToEdge;
|
||||
import androidx.core.splashscreen.SplashScreen;
|
||||
|
||||
/**
|
||||
* Template activity for Godot Android builds.
|
||||
* Feel free to extend and modify this class for your custom logic.
|
||||
*/
|
||||
public class GodotApp extends GodotActivity {
|
||||
static {
|
||||
// .NET libraries.
|
||||
if (BuildConfig.FLAVOR.equals("mono")) {
|
||||
try {
|
||||
Log.v("GODOT", "Loading System.Security.Cryptography.Native.Android library");
|
||||
System.loadLibrary("System.Security.Cryptography.Native.Android");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
Log.e("GODOT", "Unable to load System.Security.Cryptography.Native.Android library");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final Runnable updateWindowAppearance = () -> {
|
||||
Godot godot = getGodot();
|
||||
if (godot != null) {
|
||||
godot.enableImmersiveMode(godot.isInImmersiveMode(), true);
|
||||
godot.enableEdgeToEdge(godot.isInEdgeToEdgeMode(), true);
|
||||
godot.setSystemBarsAppearance();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
SplashScreen.installSplashScreen(this);
|
||||
EdgeToEdge.enable(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
updateWindowAppearance.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGodotMainLoopStarted() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPiPEnabled() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue