|
7 | 7 |
|
8 | 8 | #![cfg(since_api = "4.2")]
|
9 | 9 |
|
10 |
| -use crate::framework::{expect_debug_panic_or_release_ok, itest}; |
| 10 | +use crate::framework::{expect_debug_panic_or_release_ok, expect_panic, itest}; |
11 | 11 | use godot::{
|
12 | 12 | builtin::{Callable, Signal},
|
13 | 13 | classes::Object,
|
@@ -152,10 +152,14 @@ fn handle_recognizes_direct_object_disconnect() {
|
152 | 152 | })
|
153 | 153 | }
|
154 | 154 |
|
155 |
| -#[itest(skip)] |
156 |
| -fn handle_recognizes_freed_object() { |
157 |
| - // TODO |
158 |
| - // We should define what happens when either the broadcasting object or (potential) receiving object is freed. |
| 155 | +#[itest] |
| 156 | +fn test_handle_after_freeing_broadcaster() { |
| 157 | + test_freed_nodes(true); |
| 158 | +} |
| 159 | + |
| 160 | +#[itest] |
| 161 | +fn test_handle_after_freeing_receiver() { |
| 162 | + test_freed_nodes(false); |
159 | 163 | }
|
160 | 164 |
|
161 | 165 | // Helper functions:
|
@@ -229,6 +233,47 @@ fn test_handle_recognizes_non_valid_state(disconnect_function: impl FnOnce(&mut
|
229 | 233 | obj.free();
|
230 | 234 | }
|
231 | 235 |
|
| 236 | +fn test_freed_nodes(free_broadcaster_first: bool) { |
| 237 | + let broadcaster = SignalDisc::new_alloc(); |
| 238 | + let receiver = SignalDisc::new_alloc(); |
| 239 | + |
| 240 | + let handle = broadcaster |
| 241 | + .signals() |
| 242 | + .my_signal() |
| 243 | + .connect_other(&receiver, |r| { |
| 244 | + r.increment_self(); |
| 245 | + }); |
| 246 | + |
| 247 | + let (to_free, other) = if free_broadcaster_first { |
| 248 | + (broadcaster, receiver) |
| 249 | + } else { |
| 250 | + (receiver, broadcaster) |
| 251 | + }; |
| 252 | + |
| 253 | + // Free one of the nodes, and check if the handle thinks the objects are connected. |
| 254 | + // If the broadcaster is freed, its signals to other objects is implicitly freed as well. Thus, the handle should not be connected. |
| 255 | + // If the receiver is freed, the connection between the valid broadcaster and the non-valid freed object still exists. |
| 256 | + // In the latter case, the connection can - and probably should - be freed with disconnect(). |
| 257 | + to_free.free(); |
| 258 | + let is_connected = handle.is_connected(); |
| 259 | + assert_ne!( |
| 260 | + free_broadcaster_first, is_connected, |
| 261 | + "Handle should only return false if broadcasting is freed!" |
| 262 | + ); |
| 263 | + |
| 264 | + // It should be possible to disconnect a connection between a valid broadcaster and a non-valid receiver. |
| 265 | + // If the connection is not valid (e.g. because of freed broadcaster), calling disconnect() should panic. |
| 266 | + if is_connected { |
| 267 | + handle.disconnect(); |
| 268 | + } else { |
| 269 | + expect_panic("Disconnected invalid handle!", || { |
| 270 | + handle.disconnect(); |
| 271 | + }); |
| 272 | + } |
| 273 | + |
| 274 | + other.free(); |
| 275 | +} |
| 276 | + |
232 | 277 | fn has_connections(obj: &Gd<SignalDisc>) -> bool {
|
233 | 278 | !obj.get_signal_connection_list("my_signal").is_empty()
|
234 | 279 | }
|
0 commit comments