Add automated tests that run a GDExtension (rather than just building it)

This commit is contained in:
David Snopek
2023-04-29 11:56:33 -05:00
parent 1c18413de0
commit 1fd3f82d3a
17 changed files with 274 additions and 120 deletions

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>libgdexample.template_debug</string>
<key>CFBundleIdentifier</key>
<string>org.godotengine.libgdexample</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>libgdexample.macos.template_debug</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>CFBundleVersion</key>
<string>1.0.0</string>
<key>LSMinimumSystemVersion</key>
<string>10.12</string>
</dict>
</plist>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>libgdexample.template_release</string>
<key>CFBundleIdentifier</key>
<string>org.godotengine.libgdexample</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>libgdexample.macos.template_release</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>CFBundleVersion</key>
<string>1.0.0</string>
<key>LSMinimumSystemVersion</key>
<string>10.12</string>
</dict>
</plist>

View File

@@ -0,0 +1,7 @@
[gd_resource type="Environment" load_steps=2 format=3 uid="uid://dtd3q2x2ulcsi"]
[sub_resource type="Sky" id="1"]
[resource]
background_mode = 2
sky = SubResource("1")

View File

@@ -0,0 +1,23 @@
[configuration]
entry_symbol = "example_library_init"
compatibility_minimum = 4.1
[libraries]
macos.debug = "res://bin/libgdexample.macos.template_debug.framework"
macos.release = "res://bin/libgdexample.macos.template_release.framework"
windows.debug.x86_32 = "res://bin/libgdexample.windows.template_debug.x86_32.dll"
windows.release.x86_32 = "res://bin/libgdexample.windows.template_release.x86_32.dll"
windows.debug.x86_64 = "res://bin/libgdexample.windows.template_debug.x86_64.dll"
windows.release.x86_64 = "res://bin/libgdexample.windows.template_release.x86_64.dll"
linux.debug.x86_64 = "res://bin/libgdexample.linux.template_debug.x86_64.so"
linux.release.x86_64 = "res://bin/libgdexample.linux.template_release.x86_64.so"
linux.debug.arm64 = "res://bin/libgdexample.linux.template_debug.arm64.so"
linux.release.arm64 = "res://bin/libgdexample.linux.template_release.arm64.so"
linux.debug.rv64 = "res://bin/libgdexample.linux.template_debug.rv64.so"
linux.release.rv64 = "res://bin/libgdexample.linux.template_release.rv64.so"
android.debug.x86_64 = "res://bin/libgdexample.android.template_debug.x86_64.so"
android.release.x86_64 = "res://bin/libgdexample.android.template_release.x86_64.so"
android.debug.arm64 = "res://bin/libgdexample.android.template_debug.arm64.so"
android.release.arm64 = "res://bin/libgdexample.android.template_release.arm64.so"

BIN
test/project/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cswr8vy4lt7dt"
path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon.png"
dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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

102
test/project/main.gd Normal file
View File

@@ -0,0 +1,102 @@
extends "res://test_base.gd"
var custom_signal_emitted = null
func _ready():
# Signal.
$Example.emit_custom_signal("Button", 42)
assert_equal(custom_signal_emitted, ["Button", 42])
# To string.
assert_equal($Example.to_string(),'Example:[ GDExtension::Example <--> Instance ID:%s ]' % $Example.get_instance_id())
# It appears there's a bug with instance ids :-(
#assert_equal($Example/ExampleMin.to_string(), 'ExampleMin:[Wrapped:%s]' % $Example/ExampleMin.get_instance_id())
# Call static methods.
assert_equal($Example.test_static(9, 100), 109);
# It's void and static, so all we know is that it didn't crash.
$Example.test_static2()
# Property list.
$Example.property_from_list = Vector3(100, 200, 300)
assert_equal($Example.property_from_list, Vector3(100, 200, 300))
# Call simple methods.
$Example.simple_func()
assert_equal(custom_signal_emitted, ['simple_func', 3])
($Example as Example).simple_const_func() # Force use of ptrcall
assert_equal(custom_signal_emitted, ['simple_const_func', 4])
# Pass custom reference.
assert_equal($Example.custom_ref_func(null), -1)
var ref1 = ExampleRef.new()
ref1.id = 27
assert_equal($Example.custom_ref_func(ref1), 27)
ref1.id += 1;
assert_equal($Example.custom_const_ref_func(ref1), 28)
# Pass core reference.
assert_equal($Example.image_ref_func(null), "invalid")
assert_equal($Example.image_const_ref_func(null), "invalid")
var image = Image.new()
assert_equal($Example.image_ref_func(image), "valid")
assert_equal($Example.image_const_ref_func(image), "valid")
# Return values.
assert_equal($Example.return_something("some string"), "some string42")
assert_equal($Example.return_something_const(), get_viewport())
var null_ref = $Example.return_empty_ref()
assert_equal(null_ref, null)
var ret_ref = $Example.return_extended_ref()
assert_not_equal(ret_ref.get_instance_id(), 0)
assert_equal(ret_ref.get_id(), 0)
assert_equal($Example.get_v4(), Vector4(1.2, 3.4, 5.6, 7.8))
assert_equal($Example.test_node_argument($Example), $Example)
# VarArg method calls.
var var_ref = ExampleRef.new()
assert_not_equal($Example.extended_ref_checks(var_ref).get_instance_id(), var_ref.get_instance_id())
assert_equal($Example.varargs_func("some", "arguments", "to", "test"), 4)
assert_equal($Example.varargs_func_nv("some", "arguments", "to", "test"), 46)
$Example.varargs_func_void("some", "arguments", "to", "test")
assert_equal(custom_signal_emitted, ["varargs_func_void", 5])
# Method calls with default values.
assert_equal($Example.def_args(), 300)
assert_equal($Example.def_args(50), 250)
assert_equal($Example.def_args(50, 100), 150)
# Array and Dictionary
assert_equal($Example.test_array(), [1, 2])
assert_equal($Example.test_tarray(), [ Vector2(1, 2), Vector2(2, 3) ])
assert_equal($Example.test_dictionary(), {"hello": "world", "foo": "bar"})
var array: Array[int] = [1, 2, 3]
assert_equal($Example.test_tarray_arg(array), 6)
# String += operator
assert_equal($Example.test_string_ops(), "ABCĎE")
# PackedArray iterators
assert_equal($Example.test_vector_ops(), 105)
# Properties.
assert_equal($Example.group_subgroup_custom_position, Vector2(0, 0))
$Example.group_subgroup_custom_position = Vector2(50, 50)
assert_equal($Example.group_subgroup_custom_position, Vector2(50, 50))
# Constants.
assert_equal($Example.FIRST, 0)
assert_equal($Example.ANSWER_TO_EVERYTHING, 42)
assert_equal($Example.CONSTANT_WITHOUT_ENUM, 314)
# BitFields.
assert_equal(Example.FLAG_ONE, 1)
assert_equal(Example.FLAG_TWO, 2)
assert_equal($Example.test_bitfield(0), 0)
assert_equal($Example.test_bitfield(Example.FLAG_ONE | Example.FLAG_TWO), 3)
exit_with_status()
func _on_Example_custom_signal(signal_name, value):
custom_signal_emitted = [signal_name, value]

25
test/project/main.tscn Normal file
View File

@@ -0,0 +1,25 @@
[gd_scene load_steps=2 format=3 uid="uid://dmx2xuigcpvt4"]
[ext_resource type="Script" path="res://main.gd" id="1_c326s"]
[node name="Node" type="Node"]
script = ExtResource("1_c326s")
[node name="Example" type="Example" parent="."]
[node name="ExampleMin" type="ExampleMin" parent="Example"]
layout_mode = 0
[node name="Label" type="Label" parent="Example"]
layout_mode = 0
offset_left = 194.0
offset_top = -2.0
offset_right = 234.0
offset_bottom = 21.0
[node name="Button" type="Button" parent="."]
offset_right = 79.0
offset_bottom = 29.0
text = "Click me!"
[connection signal="custom_signal" from="Example" to="." method="_on_Example_custom_signal"]

View File

@@ -0,0 +1,24 @@
; 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="GDExtension Test Project"
run/main_scene="res://main.tscn"
config/features=PackedStringArray("4.0")
config/icon="res://icon.png"
[native_extensions]
paths=["res://example.gdextension"]
[rendering]
environment/defaults/default_environment="res://default_env.tres"

59
test/project/test_base.gd Normal file
View File

@@ -0,0 +1,59 @@
extends Node
var test_passes := 0
var test_failures := 0
func __get_stack_frame():
var me = get_script()
for s in get_stack():
if s.source == me.resource_path:
return s
return null
func __assert_pass():
test_passes += 1
func __assert_fail():
test_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(v):
assert_equal(v, true)
func assert_false(v):
assert_equal(v, false)
func assert_not_equal(actual, expected):
if actual != expected:
__assert_pass()
else:
__assert_fail()
print (" |-> Expected '%s' NOT to equal '%s'" % [expected, actual])
func exit_with_status() -> void:
var success: bool = (test_failures == 0)
print ("")
print_rich ("[color=%s] ==== TESTS FINISHED ==== [/color]" % ("green" if success else "red"))
print ("")
print_rich (" PASSES: [color=green]%s[/color]" % test_passes)
print_rich (" FAILURES: [color=red]%s[/color]" % test_failures)
print ("")
if success:
print_rich("[color=green] ******** PASSED ******** [/color]")
else:
print_rich("[color=red] ******** FAILED ********[/color]")
print("")
get_tree().quit(0 if success else 1)