Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from
May 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ jobs:
platform: linux
artifact-name: godot-cpp-linux-glibc2.27-x86_64-release
artifact-path: bin/libgodot-cpp.linux.template_release.x86_64.a
run-tests: true
cache-name: linux-x86_64

- name: 🐧 Linux (GCC, Double Precision)
Expand All @@ -30,13 +31,15 @@ jobs:
artifact-name: godot-cpp-linux-glibc2.27-x86_64-double-release
artifact-path: bin/libgodot-cpp.linux.template_release.double.x86_64.a
flags: precision=double
run-tests: false
cache-name: linux-x86_64-f64

- name: 🏁 Windows (x86_64, MSVC)
os: windows-2019
platform: windows
artifact-name: godot-cpp-windows-msvc2019-x86_64-release
artifact-path: bin/libgodot-cpp.windows.template_release.x86_64.lib
run-tests: false
cache-name: windows-x86_64-msvc

- name: 🏁 Windows (x86_64, MinGW)
Expand All @@ -45,6 +48,7 @@ jobs:
artifact-name: godot-cpp-linux-mingw-x86_64-release
artifact-path: bin/libgodot-cpp.windows.template_release.x86_64.a
flags: use_mingw=yes
run-tests: false
cache-name: windows-x86_64-mingw

- name: 🍎 macOS (universal)
Expand All @@ -53,6 +57,7 @@ jobs:
artifact-name: godot-cpp-macos-universal-release
artifact-path: bin/libgodot-cpp.macos.template_release.universal.a
flags: arch=universal
run-tests: false
cache-name: macos-universal

- name: 🤖 Android (arm64)
Expand All @@ -61,6 +66,7 @@ jobs:
artifact-name: godot-cpp-android-arm64-release
artifact-path: bin/libgodot-cpp.android.template_release.arm64.a
flags: ANDROID_NDK_ROOT=$ANDROID_NDK_LATEST_HOME arch=arm64
run-tests: false
cache-name: android-arm64

- name: 🍏 iOS (arm64)
Expand All @@ -69,6 +75,7 @@ jobs:
artifact-name: godot-cpp-ios-arm64-release
artifact-path: bin/libgodot-cpp.ios.template_release.arm64.a
flags: arch=arm64
run-tests: false
cache-name: ios-arm64

env:
Expand Down Expand Up @@ -124,6 +131,31 @@ jobs:
cd test
scons platform=${{ matrix.platform }} target=template_release ${{ matrix.flags }}

- name: Download latest Godot artifacts
uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9
if: ${{ matrix.run-tests }}
with:
repo: godotengine/godot
branch: master
event: push
workflow: linux_builds.yml
workflow_conclusion: success
name: linux-editor-mono
search_artifacts: true
check_artifacts: true
ensure_latest: true
path: godot-artifacts

- name: Run tests
if: ${{ matrix.run-tests }}
run: |
chmod +x ./godot-artifacts/godot.linuxbsd.editor.x86_64.mono
./godot-artifacts/godot.linuxbsd.editor.x86_64.mono --headless --version
cd test
# Need to run the editor so .godot is generated... but it crashes! Ignore that :-)
(cd project && (../../godot-artifacts/godot.linuxbsd.editor.x86_64.mono --editor --headless --quit >/dev/null 2>&1 || true))
GODOT=../godot-artifacts/godot.linuxbsd.editor.x86_64.mono ./run-tests.sh

- name: Upload artifact
uses: actions/upload-artifact@v3
with:
Expand Down
5 changes: 1 addition & 4 deletions test/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
# godot-cpp example / integration test
# godot-cpp integration test

This project is used to perform integration testing of the godot-cpp
extension, to validate PRs and implemented APIs.

It can also be used as a quick example of how to set up a godot-cpp
project, both on the C++ side and in the Godot project itself.

## License

This is free and unencumbered software released into the public domain.
Expand Down
4 changes: 2 additions & 2 deletions test/SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ sources = Glob("src/*.cpp")

if env["platform"] == "macos":
library = env.SharedLibrary(
"demo/bin/libgdexample.{}.{}.framework/libgdexample.{}.{}".format(
"project/bin/libgdexample.{}.{}.framework/libgdexample.{}.{}".format(
env["platform"], env["target"], env["platform"], env["target"]
),
source=sources,
)
else:
library = env.SharedLibrary(
"demo/bin/libgdexample{}{}".format(env["suffix"], env["SHLIBSUFFIX"]),
"project/bin/libgdexample{}{}".format(env["suffix"], env["SHLIBSUFFIX"]),
source=sources,
)

Expand Down
80 changes: 0 additions & 80 deletions test/demo/main.gd

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

[resource]
background_mode = 2
sky = SubResource( "1" )
sky = SubResource("1")
File renamed without changes.
File renamed without changes
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.cte
[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/bptc_ldr=0
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
Expand Down
102 changes: 102 additions & 0 deletions test/project/main.gd
Original file line number Diff line number Diff line change
@@ -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]
File renamed without changes.
File renamed without changes.
59 changes: 59 additions & 0 deletions test/project/test_base.gd
Original file line number Diff line number Diff line change
@@ -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)
Loading