Skip to content

Commit e47936e

Browse files
authored
Merge pull request #899 from godot-rust/qol/test-behavior
Unicode `ClassName::new_cached()`; adjust test
2 parents 3d053d7 + 0140dd7 commit e47936e

File tree

4 files changed

+49
-10
lines changed

4 files changed

+49
-10
lines changed

godot-core/src/meta/class_name.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,15 +102,15 @@ pub struct ClassName {
102102
}
103103

104104
impl ClassName {
105-
/// Construct a new ASCII class name.
105+
/// Construct a new class name.
106106
///
107107
/// This is expensive the first time it called for a given `T`, but will be cached for subsequent calls.
108108
///
109109
/// It is not specified when exactly `init_fn` is invoked. However, it must return the same value for the same `T`. Generally, we expect
110110
/// to keep the invocations limited, so you can use more expensive construction in the closure.
111111
///
112112
/// # Panics
113-
/// If the string is not ASCII.
113+
/// If the string is not ASCII and the Godot version is older than 4.4. From Godot 4.4 onwards, class names can be Unicode.
114114
pub fn new_cached<T: GodotClass>(init_fn: impl FnOnce() -> String) -> Self {
115115
// Check if class name exists.
116116
let type_id = TypeId::of::<T>();
@@ -119,7 +119,12 @@ impl ClassName {
119119
// Insert into linear vector. Note: this doesn't check for overlaps of TypeId between static and dynamic class names.
120120
let global_index = *map.entry(type_id).or_insert_with(|| {
121121
let name = init_fn();
122-
debug_assert!(name.is_ascii(), "Class name must be ASCII: '{name}'");
122+
123+
#[cfg(before_api = "4.4")]
124+
assert!(
125+
name.is_ascii(),
126+
"In Godot < 4.4, class name must be ASCII: '{name}'"
127+
);
123128

124129
insert_class(ClassNameSource::Owned(name))
125130
});

itest/rust/src/builtin_tests/containers/callable_test.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ pub mod custom_callable {
165165
use super::*;
166166
use crate::framework::assert_eq_self;
167167
use godot::builtin::{Dictionary, RustCallable};
168+
use godot::sys::GdextBuild;
168169
use std::fmt;
169170
use std::hash::Hash;
170171
use std::sync::{Arc, Mutex};
@@ -285,8 +286,12 @@ pub mod custom_callable {
285286
dict.set(b, "hi");
286287
assert_eq!(hash_count(&at), 1, "hash for a untouched if b is inserted");
287288
assert_eq!(hash_count(&bt), 1, "hash needed for b dict key");
288-
assert_eq!(eq_count(&at), 1, "hash collision, eq for a needed");
289-
assert_eq!(eq_count(&bt), 1, "hash collision, eq for b needed");
289+
290+
// Introduced in https://github.com/godotengine/godot/pull/96797.
291+
let eq = if GdextBuild::since_api("4.4") { 2 } else { 1 };
292+
293+
assert_eq!(eq_count(&at), eq, "hash collision, eq for a needed");
294+
assert_eq!(eq_count(&bt), eq, "hash collision, eq for b needed");
290295
}
291296

292297
#[itest]

itest/rust/src/object_tests/class_name_test.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ use godot::sys;
1313
use std::borrow::Cow;
1414

1515
struct A;
16+
struct U;
1617

1718
implement_godot_bounds!(A);
19+
implement_godot_bounds!(U);
1820

1921
impl GodotClass for A {
2022
type Base = godot::classes::Object;
@@ -24,6 +26,14 @@ impl GodotClass for A {
2426
}
2527
}
2628

29+
impl GodotClass for U {
30+
type Base = godot::classes::Object;
31+
32+
fn class_name() -> ClassName {
33+
ClassName::new_cached::<U>(|| "统一码".to_string())
34+
}
35+
}
36+
2737
#[itest]
2838
fn class_name_dynamic() {
2939
let a = A::class_name();
@@ -37,3 +47,27 @@ fn class_name_dynamic() {
3747
assert_eq!(a.to_string_name(), StringName::from("A"));
3848
assert_eq!(a.to_cow_str(), Cow::<'static, str>::Owned("A".to_string()));
3949
}
50+
51+
#[cfg(since_api = "4.4")]
52+
#[itest]
53+
fn class_name_dynamic_unicode() {
54+
let a = U::class_name();
55+
let b = U::class_name();
56+
57+
assert_eq!(a, b);
58+
assert_eq!(sys::hash_value(&a), sys::hash_value(&b));
59+
60+
assert_eq!(a.to_string(), "统一码");
61+
assert_eq!(a.to_gstring(), GString::from("统一码"));
62+
assert_eq!(a.to_string_name(), StringName::from("统一码"));
63+
assert_eq!(
64+
a.to_cow_str(),
65+
Cow::<'static, str>::Owned("统一码".to_string())
66+
);
67+
}
68+
69+
// Test Unicode proc-macro support for ClassName.
70+
#[cfg(since_api = "4.4")]
71+
#[derive(godot::register::GodotClass)]
72+
#[class(no_init)]
73+
struct 统一码 {}

itest/rust/src/register_tests/naming_tests.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,3 @@ impl IEditorExportPlugin for KeywordParameterEditorExportPlugin {
2626
fn get_customization_configuration_hash(&self) -> u64 { unreachable!() }
2727
fn get_name(&self) -> GString { unreachable!() }
2828
}
29-
30-
#[cfg(since_api = "4.4")]
31-
#[derive(GodotClass)]
32-
#[class(no_init)]
33-
struct 统一码 {}

0 commit comments

Comments
 (0)