Skip to content

Commit 55c4d3a

Browse files
bors[bot]Bromeon
andauthored
Merge #142
142: Rework integration tests: self-registering `#[itest]`, Rust runner r=Bromeon a=Bromeon Main changes: * `#[itest]` is now self-registering, just like Rust's `#[test]`. * No more `ok &= test_xy();` shenanigans. When declared, it runs. * A large part of the runner logic is moved from GDScript to Rust. * Unifies printing, statistics and time measurement. * Significantly speeds up test execution, from around 0.28s to 0.13s on my machine. Not that this matters much at the moment, but it may once we have more tests, or tests are generated at larger scale. * No longer prints the panic and stack trace during `expect_panic`, reducing the stdout spam during integration tests. And unrelated to testing, but needed for this PR: * New `Variant::call()` method * .gitignore fixes Co-authored-by: Jan Haller <[email protected]>
2 parents 72870d1 + 5d6218f commit 55c4d3a

36 files changed

+426
-474
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ target
88
Cargo.lock
99

1010
# Godot
11-
**/.import/
11+
# .godot needs to be a pattern like this and not a directory, otherwise the negative statements below don't apply
1212
**/.godot/**
13+
*.import
14+
1315
# Needed to run projects without having to open the editor first.
1416
!**/.godot/extension_list.cfg
1517
!**/.godot/global_script_class_cache.cfg

examples/dodge-the-creeps/godot/.gitignore

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
list=[]

godot-codegen/src/class_generator.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,7 @@ fn make_return(
851851
let variant = Variant::#from_sys_init_method(|return_ptr| {
852852
let mut __err = sys::default_call_error();
853853
#varcall_invocation
854-
assert_eq!(__err.error, sys::GDEXTENSION_CALL_OK);
854+
sys::panic_on_call_error(&__err);
855855
});
856856
#return_expr
857857
}
@@ -863,7 +863,7 @@ fn make_return(
863863
let mut __err = sys::default_call_error();
864864
let return_ptr = std::ptr::null_mut();
865865
#varcall_invocation
866-
assert_eq!(__err.error, sys::GDEXTENSION_CALL_OK);
866+
sys::panic_on_call_error(&__err);
867867
}
868868
}
869869
(None, Some(RustTy::EngineClass { tokens, .. })) => {

godot-codegen/src/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ fn test_pascal_conversion() {
5656
fn test_snake_conversion() {
5757
// More in line with Rust identifiers, and eases recognition of other automation (like enumerator mapping).
5858
#[rustfmt::skip]
59-
let mappings = [
59+
let mappings = [
6060
("AABB", "aabb"),
6161
("AESContext", "aes_context"),
6262
("AStar3D", "a_star_3d"),

godot-core/src/builtin/variant/mod.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
55
*/
66

7-
use crate::builtin::GodotString;
7+
use crate::builtin::{GodotString, StringName};
88
use godot_ffi as sys;
99
use godot_ffi::GodotFfi;
1010
use std::{fmt, ptr};
@@ -91,12 +91,46 @@ impl Variant {
9191
}
9292
}
9393

94-
// TODO test
95-
#[allow(unused_mut)]
94+
/// ⚠️ Calls the specified `method` with the given `args`.
95+
///
96+
/// Supports `Object` as well as built-ins with methods (e.g. `Array`, `Vector3`, `GodotString`, etc).
97+
///
98+
/// # Panics
99+
/// * If `self` is not a variant type which supports method calls.
100+
/// * If the method does not exist or the signature is not compatible with the passed arguments.
101+
/// * If the call causes an error.
102+
#[inline]
103+
pub fn call(&self, method: impl Into<StringName>, args: &[Variant]) -> Variant {
104+
self.call_inner(method.into(), args)
105+
}
106+
107+
fn call_inner(&self, method: StringName, args: &[Variant]) -> Variant {
108+
let args_sys: Vec<_> = args.iter().map(|v| v.var_sys_const()).collect();
109+
let mut error = sys::default_call_error();
110+
111+
#[allow(unused_mut)]
112+
let mut result = Variant::nil();
113+
114+
unsafe {
115+
interface_fn!(variant_call)(
116+
self.var_sys(),
117+
method.string_sys(),
118+
args_sys.as_ptr(),
119+
args_sys.len() as i64,
120+
result.var_sys(),
121+
ptr::addr_of_mut!(error),
122+
)
123+
};
124+
125+
sys::panic_on_call_error(&error);
126+
result
127+
}
128+
96129
pub fn evaluate(&self, rhs: &Variant, op: VariantOperator) -> Option<Variant> {
97130
let op_sys = op.sys();
98131
let mut is_valid = false as u8;
99132

133+
#[allow(unused_mut)]
100134
let mut result = Variant::nil();
101135
unsafe {
102136
interface_fn!(variant_evaluate)(

godot-core/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pub mod private {
4242

4343
use crate::{log, sys};
4444

45-
sys::plugin_registry!(__GODOT_PLUGIN_REGISTRY: ClassPlugin);
45+
sys::plugin_registry!(pub __GODOT_PLUGIN_REGISTRY: ClassPlugin);
4646

4747
pub(crate) fn iterate_plugins(mut visitor: impl FnMut(&ClassPlugin)) {
4848
sys::plugin_foreach!(__GODOT_PLUGIN_REGISTRY; visitor);

godot-ffi/src/lib.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ unsafe fn unwrap_ref_unchecked_mut<T>(opt: &mut Option<T>) -> &mut T {
140140
}
141141

142142
#[doc(hidden)]
143+
#[inline]
143144
pub fn default_call_error() -> GDExtensionCallError {
144145
GDExtensionCallError {
145146
error: GDEXTENSION_CALL_OK,
@@ -148,6 +149,32 @@ pub fn default_call_error() -> GDExtensionCallError {
148149
}
149150
}
150151

152+
#[doc(hidden)]
153+
#[inline]
154+
pub fn panic_on_call_error(err: &GDExtensionCallError) {
155+
let actual = err.error;
156+
157+
assert_eq!(
158+
actual,
159+
GDEXTENSION_CALL_OK,
160+
"encountered Godot error code {}",
161+
call_error_to_string(actual)
162+
);
163+
}
164+
165+
fn call_error_to_string(err: GDExtensionCallErrorType) -> &'static str {
166+
match err {
167+
GDEXTENSION_CALL_OK => "OK",
168+
GDEXTENSION_CALL_ERROR_INVALID_METHOD => "ERROR_INVALID_METHOD",
169+
GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT => "ERROR_INVALID_ARGUMENT",
170+
GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS => "ERROR_TOO_MANY_ARGUMENTS",
171+
GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS => "ERROR_TOO_FEW_ARGUMENTS",
172+
GDEXTENSION_CALL_ERROR_INSTANCE_IS_NULL => "ERROR_INSTANCE_IS_NULL",
173+
GDEXTENSION_CALL_ERROR_METHOD_NOT_CONST => "ERROR_METHOD_NOT_CONST",
174+
_ => "(unknown)",
175+
}
176+
}
177+
151178
#[macro_export]
152179
#[doc(hidden)]
153180
macro_rules! builtin_fn {

godot-ffi/src/plugins.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
#[doc(hidden)]
1616
#[macro_export]
1717
macro_rules! plugin_registry {
18-
($registry:ident: $Type:ty) => {
18+
($vis:vis $registry:ident: $Type:ty) => {
1919
$crate::paste::paste! {
2020
#[used]
2121
#[allow(non_upper_case_globals)]
2222
#[doc(hidden)]
23-
pub static [< __godot_rust_plugin_ $registry >]:
23+
$vis static [< __godot_rust_plugin_ $registry >]:
2424
std::sync::Mutex<Vec<$Type>> = std::sync::Mutex::new(Vec::new());
2525
}
2626
};

godot-macros/src/itest.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,11 @@ pub fn transform(input: TokenStream) -> Result<TokenStream, Error> {
3030
}
3131

3232
let test_name = &func.name;
33-
let init_msg = format!(" -- {test_name}");
34-
let error_msg = format!(" !! Test {test_name} failed");
33+
let test_name_str = func.name.to_string();
3534
let body = &func.body;
3635

3736
Ok(quote! {
38-
#[doc(hidden)]
37+
/*#[doc(hidden)]
3938
#[must_use]
4039
pub fn #test_name() -> bool {
4140
println!(#init_msg);
@@ -47,6 +46,18 @@ pub fn transform(input: TokenStream) -> Result<TokenStream, Error> {
4746
);
4847
4948
success.is_some()
49+
}*/
50+
51+
pub fn #test_name() {
52+
#body
5053
}
54+
55+
::godot::sys::plugin_add!(__GODOT_ITEST in crate; crate::RustTestCase {
56+
name: #test_name_str,
57+
skipped: false,
58+
file: std::file!(),
59+
line: std::line!(),
60+
function: #test_name,
61+
});
5162
})
5263
}

0 commit comments

Comments
 (0)