1use bitflags::bitflags;
7use dear_imgui_rs::{
8 Context, ContextAliveToken, ImGuiError, ImGuiResult, KeyChord, KeyMods, MouseButton, Ui,
9 with_scratch_txt, with_scratch_txt_two,
10};
11use dear_imgui_test_engine_sys as sys;
12use std::{marker::PhantomData, rc::Rc};
13
14pub use dear_imgui_test_engine_sys as raw;
15
16#[repr(i32)]
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum RunSpeed {
19 Fast = sys::ImGuiTestEngineRunSpeed_Fast as i32,
20 Normal = sys::ImGuiTestEngineRunSpeed_Normal as i32,
21 Cinematic = sys::ImGuiTestEngineRunSpeed_Cinematic as i32,
22}
23
24#[repr(i32)]
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum VerboseLevel {
27 Silent = sys::ImGuiTestEngineVerboseLevel_Silent as i32,
28 Error = sys::ImGuiTestEngineVerboseLevel_Error as i32,
29 Warning = sys::ImGuiTestEngineVerboseLevel_Warning as i32,
30 Info = sys::ImGuiTestEngineVerboseLevel_Info as i32,
31 Debug = sys::ImGuiTestEngineVerboseLevel_Debug as i32,
32 Trace = sys::ImGuiTestEngineVerboseLevel_Trace as i32,
33}
34
35#[repr(i32)]
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum InputMode {
38 Mouse = dear_imgui_rs::sys::ImGuiInputSource_Mouse as i32,
39 Keyboard = dear_imgui_rs::sys::ImGuiInputSource_Keyboard as i32,
40 Gamepad = dear_imgui_rs::sys::ImGuiInputSource_Gamepad as i32,
41}
42
43#[repr(i32)]
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub enum TestGroup {
46 Unknown = sys::ImGuiTestEngineGroup_Unknown,
47 Tests = sys::ImGuiTestEngineGroup_Tests,
48 Perfs = sys::ImGuiTestEngineGroup_Perfs,
49}
50
51bitflags! {
52 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
53 pub struct RunFlags: u32 {
54 const NONE = sys::ImGuiTestEngineRunFlags_None as u32;
55 const GUI_FUNC_DISABLE = sys::ImGuiTestEngineRunFlags_GuiFuncDisable as u32;
56 const GUI_FUNC_ONLY = sys::ImGuiTestEngineRunFlags_GuiFuncOnly as u32;
57 const NO_SUCCESS_MSG = sys::ImGuiTestEngineRunFlags_NoSuccessMsg as u32;
58 const ENABLE_RAW_INPUTS = sys::ImGuiTestEngineRunFlags_EnableRawInputs as u32;
59 const RUN_FROM_GUI = sys::ImGuiTestEngineRunFlags_RunFromGui as u32;
60 const RUN_FROM_COMMAND_LINE = sys::ImGuiTestEngineRunFlags_RunFromCommandLine as u32;
61 const NO_ERROR = sys::ImGuiTestEngineRunFlags_NoError as u32;
62 const SHARE_VARS = sys::ImGuiTestEngineRunFlags_ShareVars as u32;
63 const SHARE_TEST_CONTEXT = sys::ImGuiTestEngineRunFlags_ShareTestContext as u32;
64 }
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
68pub struct ResultSummary {
69 pub count_tested: i32,
70 pub count_success: i32,
71 pub count_in_queue: i32,
72}
73
74pub struct TestEngine {
78 raw: *mut sys::ImGuiTestEngine,
79 bound_imgui_ctx_raw: Option<*mut dear_imgui_rs::sys::ImGuiContext>,
80 bound_imgui_alive: Option<ContextAliveToken>,
81 _not_send_sync: PhantomData<Rc<()>>,
82}
83
84struct Script {
85 raw: *mut sys::ImGuiTestEngineScript,
86}
87
88impl Script {
89 fn create() -> ImGuiResult<Self> {
90 let raw = unsafe { sys::imgui_test_engine_script_create() };
91 if raw.is_null() {
92 return Err(ImGuiError::invalid_operation(
93 "imgui_test_engine_script_create returned null",
94 ));
95 }
96 Ok(Self { raw })
97 }
98
99 fn into_raw(mut self) -> *mut sys::ImGuiTestEngineScript {
100 let raw = self.raw;
101 self.raw = std::ptr::null_mut();
102 raw
103 }
104}
105
106impl Drop for Script {
107 fn drop(&mut self) {
108 if !self.raw.is_null() {
109 unsafe { sys::imgui_test_engine_script_destroy(self.raw) };
110 self.raw = std::ptr::null_mut();
111 }
112 }
113}
114
115pub struct ScriptTest<'a> {
116 script: &'a mut Script,
117}
118
119impl ScriptTest<'_> {
120 pub fn set_ref(&mut self, r#ref: &str) -> ImGuiResult<()> {
121 if r#ref.contains('\0') {
122 return Err(ImGuiError::invalid_operation(
123 "set_ref contained interior NUL",
124 ));
125 }
126 with_scratch_txt(r#ref, |ptr| unsafe {
127 sys::imgui_test_engine_script_set_ref(self.script.raw, ptr)
128 });
129 Ok(())
130 }
131
132 pub fn item_click(&mut self, r#ref: &str) -> ImGuiResult<()> {
133 if r#ref.contains('\0') {
134 return Err(ImGuiError::invalid_operation(
135 "item_click contained interior NUL",
136 ));
137 }
138 with_scratch_txt(r#ref, |ptr| unsafe {
139 sys::imgui_test_engine_script_item_click(self.script.raw, ptr)
140 });
141 Ok(())
142 }
143
144 pub fn item_click_with_button(&mut self, r#ref: &str, button: MouseButton) -> ImGuiResult<()> {
145 if r#ref.contains('\0') {
146 return Err(ImGuiError::invalid_operation(
147 "item_click_with_button contained interior NUL",
148 ));
149 }
150 let button = button as i32;
151 with_scratch_txt(r#ref, |ptr| unsafe {
152 sys::imgui_test_engine_script_item_click_with_button(self.script.raw, ptr, button)
153 });
154 Ok(())
155 }
156
157 pub fn item_double_click(&mut self, r#ref: &str) -> ImGuiResult<()> {
158 if r#ref.contains('\0') {
159 return Err(ImGuiError::invalid_operation(
160 "item_double_click contained interior NUL",
161 ));
162 }
163 with_scratch_txt(r#ref, |ptr| unsafe {
164 sys::imgui_test_engine_script_item_double_click(self.script.raw, ptr)
165 });
166 Ok(())
167 }
168
169 pub fn item_open(&mut self, r#ref: &str) -> ImGuiResult<()> {
170 if r#ref.contains('\0') {
171 return Err(ImGuiError::invalid_operation(
172 "item_open contained interior NUL",
173 ));
174 }
175 with_scratch_txt(r#ref, |ptr| unsafe {
176 sys::imgui_test_engine_script_item_open(self.script.raw, ptr)
177 });
178 Ok(())
179 }
180
181 pub fn item_close(&mut self, r#ref: &str) -> ImGuiResult<()> {
182 if r#ref.contains('\0') {
183 return Err(ImGuiError::invalid_operation(
184 "item_close contained interior NUL",
185 ));
186 }
187 with_scratch_txt(r#ref, |ptr| unsafe {
188 sys::imgui_test_engine_script_item_close(self.script.raw, ptr)
189 });
190 Ok(())
191 }
192
193 pub fn item_set_opened(&mut self, r#ref: &str, opened: bool) -> ImGuiResult<()> {
194 if opened {
195 self.item_open(r#ref)
196 } else {
197 self.item_close(r#ref)
198 }
199 }
200
201 pub fn item_check(&mut self, r#ref: &str) -> ImGuiResult<()> {
202 if r#ref.contains('\0') {
203 return Err(ImGuiError::invalid_operation(
204 "item_check contained interior NUL",
205 ));
206 }
207 with_scratch_txt(r#ref, |ptr| unsafe {
208 sys::imgui_test_engine_script_item_check(self.script.raw, ptr)
209 });
210 Ok(())
211 }
212
213 pub fn item_set_checked(&mut self, r#ref: &str, checked: bool) -> ImGuiResult<()> {
214 if checked {
215 self.item_check(r#ref)
216 } else {
217 self.item_uncheck(r#ref)
218 }
219 }
220
221 pub fn item_uncheck(&mut self, r#ref: &str) -> ImGuiResult<()> {
222 if r#ref.contains('\0') {
223 return Err(ImGuiError::invalid_operation(
224 "item_uncheck contained interior NUL",
225 ));
226 }
227 with_scratch_txt(r#ref, |ptr| unsafe {
228 sys::imgui_test_engine_script_item_uncheck(self.script.raw, ptr)
229 });
230 Ok(())
231 }
232
233 pub fn item_input_int(&mut self, r#ref: &str, v: i32) -> ImGuiResult<()> {
234 if r#ref.contains('\0') {
235 return Err(ImGuiError::invalid_operation(
236 "item_input_int contained interior NUL",
237 ));
238 }
239 with_scratch_txt(r#ref, |ptr| unsafe {
240 sys::imgui_test_engine_script_item_input_int(self.script.raw, ptr, v)
241 });
242 Ok(())
243 }
244
245 pub fn item_input_str(&mut self, r#ref: &str, v: &str) -> ImGuiResult<()> {
246 if r#ref.contains('\0') || v.contains('\0') {
247 return Err(ImGuiError::invalid_operation(
248 "item_input_str contained interior NUL",
249 ));
250 }
251 with_scratch_txt_two(r#ref, v, |ref_ptr, v_ptr| unsafe {
252 sys::imgui_test_engine_script_item_input_str(self.script.raw, ref_ptr, v_ptr)
253 });
254 Ok(())
255 }
256
257 pub fn mouse_move(&mut self, r#ref: &str) -> ImGuiResult<()> {
258 if r#ref.contains('\0') {
259 return Err(ImGuiError::invalid_operation(
260 "mouse_move contained interior NUL",
261 ));
262 }
263 with_scratch_txt(r#ref, |ptr| unsafe {
264 sys::imgui_test_engine_script_mouse_move(self.script.raw, ptr)
265 });
266 Ok(())
267 }
268
269 pub fn mouse_move_to_pos(&mut self, x: f32, y: f32) -> ImGuiResult<()> {
270 if !x.is_finite() || !y.is_finite() {
271 return Err(ImGuiError::invalid_operation(
272 "mouse_move_to_pos requires finite values",
273 ));
274 }
275 unsafe { sys::imgui_test_engine_script_mouse_move_to_pos(self.script.raw, x, y) };
276 Ok(())
277 }
278
279 pub fn mouse_teleport_to_pos(&mut self, x: f32, y: f32) -> ImGuiResult<()> {
280 if !x.is_finite() || !y.is_finite() {
281 return Err(ImGuiError::invalid_operation(
282 "mouse_teleport_to_pos requires finite values",
283 ));
284 }
285 unsafe { sys::imgui_test_engine_script_mouse_teleport_to_pos(self.script.raw, x, y) };
286 Ok(())
287 }
288
289 pub fn mouse_move_to_void(&mut self) {
290 unsafe { sys::imgui_test_engine_script_mouse_move_to_void(self.script.raw) };
291 }
292
293 pub fn mouse_click(&mut self, button: MouseButton) {
294 let button = button as i32;
295 unsafe { sys::imgui_test_engine_script_mouse_click(self.script.raw, button) };
296 }
297
298 pub fn mouse_click_multi(&mut self, button: MouseButton, count: i32) -> ImGuiResult<()> {
299 if count < 1 {
300 return Err(ImGuiError::invalid_operation(
301 "mouse_click_multi count must be >= 1",
302 ));
303 }
304 let button = button as i32;
305 unsafe { sys::imgui_test_engine_script_mouse_click_multi(self.script.raw, button, count) };
306 Ok(())
307 }
308
309 pub fn mouse_double_click(&mut self, button: MouseButton) {
310 let button = button as i32;
311 unsafe { sys::imgui_test_engine_script_mouse_double_click(self.script.raw, button) };
312 }
313
314 pub fn mouse_down(&mut self, button: MouseButton) {
315 let button = button as i32;
316 unsafe { sys::imgui_test_engine_script_mouse_down(self.script.raw, button) };
317 }
318
319 pub fn mouse_up(&mut self, button: MouseButton) {
320 let button = button as i32;
321 unsafe { sys::imgui_test_engine_script_mouse_up(self.script.raw, button) };
322 }
323
324 pub fn mouse_lift_drag_threshold(&mut self, button: MouseButton) {
325 let button = button as i32;
326 unsafe { sys::imgui_test_engine_script_mouse_lift_drag_threshold(self.script.raw, button) };
327 }
328
329 pub fn mouse_drag_with_delta(
330 &mut self,
331 dx: f32,
332 dy: f32,
333 button: MouseButton,
334 ) -> ImGuiResult<()> {
335 if !dx.is_finite() || !dy.is_finite() {
336 return Err(ImGuiError::invalid_operation(
337 "mouse_drag_with_delta requires finite values",
338 ));
339 }
340 let button = button as i32;
341 unsafe {
342 sys::imgui_test_engine_script_mouse_drag_with_delta(self.script.raw, dx, dy, button)
343 };
344 Ok(())
345 }
346
347 pub fn mouse_click_on_void(&mut self, button: i32, count: i32) -> ImGuiResult<()> {
348 if button < 0 {
349 return Err(ImGuiError::invalid_operation(
350 "mouse_click_on_void button must be >= 0",
351 ));
352 }
353 if count < 1 {
354 return Err(ImGuiError::invalid_operation(
355 "mouse_click_on_void count must be >= 1",
356 ));
357 }
358 unsafe {
359 sys::imgui_test_engine_script_mouse_click_on_void(self.script.raw, button, count)
360 };
361 Ok(())
362 }
363
364 pub fn mouse_wheel(&mut self, dx: f32, dy: f32) -> ImGuiResult<()> {
365 if !dx.is_finite() || !dy.is_finite() {
366 return Err(ImGuiError::invalid_operation(
367 "mouse_wheel requires finite values",
368 ));
369 }
370 unsafe { sys::imgui_test_engine_script_mouse_wheel(self.script.raw, dx, dy) };
371 Ok(())
372 }
373
374 pub fn key_down(&mut self, key_chord: KeyChord) {
375 unsafe { sys::imgui_test_engine_script_key_down(self.script.raw, key_chord.raw()) };
376 }
377
378 pub fn key_up(&mut self, key_chord: KeyChord) {
379 unsafe { sys::imgui_test_engine_script_key_up(self.script.raw, key_chord.raw()) };
380 }
381
382 pub fn key_press(&mut self, key_chord: KeyChord, count: i32) -> ImGuiResult<()> {
383 if count < 1 {
384 return Err(ImGuiError::invalid_operation(
385 "key_press count must be >= 1",
386 ));
387 }
388 unsafe { sys::imgui_test_engine_script_key_press(self.script.raw, key_chord.raw(), count) };
389 Ok(())
390 }
391
392 pub fn key_hold(&mut self, key_chord: KeyChord, seconds: f32) -> ImGuiResult<()> {
393 if !seconds.is_finite() || seconds < 0.0 {
394 return Err(ImGuiError::invalid_operation(
395 "key_hold requires a finite non-negative value",
396 ));
397 }
398 unsafe {
399 sys::imgui_test_engine_script_key_hold(self.script.raw, key_chord.raw(), seconds)
400 };
401 Ok(())
402 }
403
404 pub fn key_chars(&mut self, chars: &str) -> ImGuiResult<()> {
405 if chars.contains('\0') {
406 return Err(ImGuiError::invalid_operation(
407 "key_chars contained interior NUL",
408 ));
409 }
410 with_scratch_txt(chars, |ptr| unsafe {
411 sys::imgui_test_engine_script_key_chars(self.script.raw, ptr)
412 });
413 Ok(())
414 }
415
416 pub fn key_chars_append(&mut self, chars: &str) -> ImGuiResult<()> {
417 if chars.contains('\0') {
418 return Err(ImGuiError::invalid_operation(
419 "key_chars_append contained interior NUL",
420 ));
421 }
422 with_scratch_txt(chars, |ptr| unsafe {
423 sys::imgui_test_engine_script_key_chars_append(self.script.raw, ptr)
424 });
425 Ok(())
426 }
427
428 pub fn key_chars_append_enter(&mut self, chars: &str) -> ImGuiResult<()> {
429 if chars.contains('\0') {
430 return Err(ImGuiError::invalid_operation(
431 "key_chars_append_enter contained interior NUL",
432 ));
433 }
434 with_scratch_txt(chars, |ptr| unsafe {
435 sys::imgui_test_engine_script_key_chars_append_enter(self.script.raw, ptr)
436 });
437 Ok(())
438 }
439
440 pub fn key_chars_replace(&mut self, chars: &str) -> ImGuiResult<()> {
441 if chars.contains('\0') {
442 return Err(ImGuiError::invalid_operation(
443 "key_chars_replace contained interior NUL",
444 ));
445 }
446 with_scratch_txt(chars, |ptr| unsafe {
447 sys::imgui_test_engine_script_key_chars_replace(self.script.raw, ptr)
448 });
449 Ok(())
450 }
451
452 pub fn key_chars_replace_enter(&mut self, chars: &str) -> ImGuiResult<()> {
453 if chars.contains('\0') {
454 return Err(ImGuiError::invalid_operation(
455 "key_chars_replace_enter contained interior NUL",
456 ));
457 }
458 with_scratch_txt(chars, |ptr| unsafe {
459 sys::imgui_test_engine_script_key_chars_replace_enter(self.script.raw, ptr)
460 });
461 Ok(())
462 }
463
464 pub fn item_hold(&mut self, r#ref: &str, seconds: f32) -> ImGuiResult<()> {
465 if r#ref.contains('\0') {
466 return Err(ImGuiError::invalid_operation(
467 "item_hold contained interior NUL",
468 ));
469 }
470 if !seconds.is_finite() || seconds < 0.0 {
471 return Err(ImGuiError::invalid_operation(
472 "item_hold requires a finite non-negative value",
473 ));
474 }
475 with_scratch_txt(r#ref, |ptr| unsafe {
476 sys::imgui_test_engine_script_item_hold(self.script.raw, ptr, seconds)
477 });
478 Ok(())
479 }
480
481 pub fn item_hold_for_frames(&mut self, r#ref: &str, frames: i32) -> ImGuiResult<()> {
482 if r#ref.contains('\0') {
483 return Err(ImGuiError::invalid_operation(
484 "item_hold_for_frames contained interior NUL",
485 ));
486 }
487 if frames < 1 {
488 return Err(ImGuiError::invalid_operation(
489 "item_hold_for_frames frames must be >= 1",
490 ));
491 }
492 with_scratch_txt(r#ref, |ptr| unsafe {
493 sys::imgui_test_engine_script_item_hold_for_frames(self.script.raw, ptr, frames)
494 });
495 Ok(())
496 }
497
498 pub fn item_drag_over_and_hold(&mut self, src_ref: &str, dst_ref: &str) -> ImGuiResult<()> {
499 if src_ref.contains('\0') {
500 return Err(ImGuiError::invalid_operation(
501 "item_drag_over_and_hold src_ref contained interior NUL",
502 ));
503 }
504 if dst_ref.contains('\0') {
505 return Err(ImGuiError::invalid_operation(
506 "item_drag_over_and_hold dst_ref contained interior NUL",
507 ));
508 }
509 with_scratch_txt_two(src_ref, dst_ref, |src_ptr, dst_ptr| unsafe {
510 sys::imgui_test_engine_script_item_drag_over_and_hold(self.script.raw, src_ptr, dst_ptr)
511 });
512 Ok(())
513 }
514
515 pub fn item_drag_and_drop(
516 &mut self,
517 src_ref: &str,
518 dst_ref: &str,
519 button: MouseButton,
520 ) -> ImGuiResult<()> {
521 if src_ref.contains('\0') {
522 return Err(ImGuiError::invalid_operation(
523 "item_drag_and_drop src_ref contained interior NUL",
524 ));
525 }
526 if dst_ref.contains('\0') {
527 return Err(ImGuiError::invalid_operation(
528 "item_drag_and_drop dst_ref contained interior NUL",
529 ));
530 }
531 let button = button as i32;
532 with_scratch_txt_two(src_ref, dst_ref, |src_ptr, dst_ptr| unsafe {
533 sys::imgui_test_engine_script_item_drag_and_drop(
534 self.script.raw,
535 src_ptr,
536 dst_ptr,
537 button,
538 )
539 });
540 Ok(())
541 }
542
543 pub fn item_drag_with_delta(&mut self, r#ref: &str, dx: f32, dy: f32) -> ImGuiResult<()> {
544 if r#ref.contains('\0') {
545 return Err(ImGuiError::invalid_operation(
546 "item_drag_with_delta contained interior NUL",
547 ));
548 }
549 if !dx.is_finite() || !dy.is_finite() {
550 return Err(ImGuiError::invalid_operation(
551 "item_drag_with_delta requires finite values",
552 ));
553 }
554 with_scratch_txt(r#ref, |ptr| unsafe {
555 sys::imgui_test_engine_script_item_drag_with_delta(self.script.raw, ptr, dx, dy)
556 });
557 Ok(())
558 }
559
560 pub fn scroll_to_x(&mut self, r#ref: &str, scroll_x: f32) -> ImGuiResult<()> {
561 if r#ref.contains('\0') {
562 return Err(ImGuiError::invalid_operation(
563 "scroll_to_x contained interior NUL",
564 ));
565 }
566 if !scroll_x.is_finite() {
567 return Err(ImGuiError::invalid_operation(
568 "scroll_to_x requires a finite value",
569 ));
570 }
571 with_scratch_txt(r#ref, |ptr| unsafe {
572 sys::imgui_test_engine_script_scroll_to_x(self.script.raw, ptr, scroll_x)
573 });
574 Ok(())
575 }
576
577 pub fn scroll_to_y(&mut self, r#ref: &str, scroll_y: f32) -> ImGuiResult<()> {
578 if r#ref.contains('\0') {
579 return Err(ImGuiError::invalid_operation(
580 "scroll_to_y contained interior NUL",
581 ));
582 }
583 if !scroll_y.is_finite() {
584 return Err(ImGuiError::invalid_operation(
585 "scroll_to_y requires a finite value",
586 ));
587 }
588 with_scratch_txt(r#ref, |ptr| unsafe {
589 sys::imgui_test_engine_script_scroll_to_y(self.script.raw, ptr, scroll_y)
590 });
591 Ok(())
592 }
593
594 pub fn scroll_to_pos_x(&mut self, window_ref: &str, pos_x: f32) -> ImGuiResult<()> {
595 if window_ref.contains('\0') {
596 return Err(ImGuiError::invalid_operation(
597 "scroll_to_pos_x window_ref contained interior NUL",
598 ));
599 }
600 if !pos_x.is_finite() {
601 return Err(ImGuiError::invalid_operation(
602 "scroll_to_pos_x requires a finite value",
603 ));
604 }
605 with_scratch_txt(window_ref, |ptr| unsafe {
606 sys::imgui_test_engine_script_scroll_to_pos_x(self.script.raw, ptr, pos_x)
607 });
608 Ok(())
609 }
610
611 pub fn scroll_to_pos_y(&mut self, window_ref: &str, pos_y: f32) -> ImGuiResult<()> {
612 if window_ref.contains('\0') {
613 return Err(ImGuiError::invalid_operation(
614 "scroll_to_pos_y window_ref contained interior NUL",
615 ));
616 }
617 if !pos_y.is_finite() {
618 return Err(ImGuiError::invalid_operation(
619 "scroll_to_pos_y requires a finite value",
620 ));
621 }
622 with_scratch_txt(window_ref, |ptr| unsafe {
623 sys::imgui_test_engine_script_scroll_to_pos_y(self.script.raw, ptr, pos_y)
624 });
625 Ok(())
626 }
627
628 pub fn scroll_to_item_x(&mut self, r#ref: &str) -> ImGuiResult<()> {
629 if r#ref.contains('\0') {
630 return Err(ImGuiError::invalid_operation(
631 "scroll_to_item_x contained interior NUL",
632 ));
633 }
634 with_scratch_txt(r#ref, |ptr| unsafe {
635 sys::imgui_test_engine_script_scroll_to_item_x(self.script.raw, ptr)
636 });
637 Ok(())
638 }
639
640 pub fn scroll_to_item_y(&mut self, r#ref: &str) -> ImGuiResult<()> {
641 if r#ref.contains('\0') {
642 return Err(ImGuiError::invalid_operation(
643 "scroll_to_item_y contained interior NUL",
644 ));
645 }
646 with_scratch_txt(r#ref, |ptr| unsafe {
647 sys::imgui_test_engine_script_scroll_to_item_y(self.script.raw, ptr)
648 });
649 Ok(())
650 }
651
652 pub fn scroll_to_top(&mut self, r#ref: &str) -> ImGuiResult<()> {
653 if r#ref.contains('\0') {
654 return Err(ImGuiError::invalid_operation(
655 "scroll_to_top contained interior NUL",
656 ));
657 }
658 with_scratch_txt(r#ref, |ptr| unsafe {
659 sys::imgui_test_engine_script_scroll_to_top(self.script.raw, ptr)
660 });
661 Ok(())
662 }
663
664 pub fn scroll_to_bottom(&mut self, r#ref: &str) -> ImGuiResult<()> {
665 if r#ref.contains('\0') {
666 return Err(ImGuiError::invalid_operation(
667 "scroll_to_bottom contained interior NUL",
668 ));
669 }
670 with_scratch_txt(r#ref, |ptr| unsafe {
671 sys::imgui_test_engine_script_scroll_to_bottom(self.script.raw, ptr)
672 });
673 Ok(())
674 }
675
676 pub fn tab_close(&mut self, r#ref: &str) -> ImGuiResult<()> {
677 if r#ref.contains('\0') {
678 return Err(ImGuiError::invalid_operation(
679 "tab_close contained interior NUL",
680 ));
681 }
682 with_scratch_txt(r#ref, |ptr| unsafe {
683 sys::imgui_test_engine_script_tab_close(self.script.raw, ptr)
684 });
685 Ok(())
686 }
687
688 pub fn combo_click(&mut self, r#ref: &str) -> ImGuiResult<()> {
689 if r#ref.contains('\0') {
690 return Err(ImGuiError::invalid_operation(
691 "combo_click contained interior NUL",
692 ));
693 }
694 with_scratch_txt(r#ref, |ptr| unsafe {
695 sys::imgui_test_engine_script_combo_click(self.script.raw, ptr)
696 });
697 Ok(())
698 }
699
700 pub fn combo_click_all(&mut self, r#ref: &str) -> ImGuiResult<()> {
701 if r#ref.contains('\0') {
702 return Err(ImGuiError::invalid_operation(
703 "combo_click_all contained interior NUL",
704 ));
705 }
706 with_scratch_txt(r#ref, |ptr| unsafe {
707 sys::imgui_test_engine_script_combo_click_all(self.script.raw, ptr)
708 });
709 Ok(())
710 }
711
712 pub fn item_open_all(&mut self, parent_ref: &str, depth: i32, passes: i32) -> ImGuiResult<()> {
713 if parent_ref.contains('\0') {
714 return Err(ImGuiError::invalid_operation(
715 "item_open_all parent_ref contained interior NUL",
716 ));
717 }
718 with_scratch_txt(parent_ref, |ptr| unsafe {
719 sys::imgui_test_engine_script_item_open_all(self.script.raw, ptr, depth, passes)
720 });
721 Ok(())
722 }
723
724 pub fn item_close_all(&mut self, parent_ref: &str, depth: i32, passes: i32) -> ImGuiResult<()> {
725 if parent_ref.contains('\0') {
726 return Err(ImGuiError::invalid_operation(
727 "item_close_all parent_ref contained interior NUL",
728 ));
729 }
730 with_scratch_txt(parent_ref, |ptr| unsafe {
731 sys::imgui_test_engine_script_item_close_all(self.script.raw, ptr, depth, passes)
732 });
733 Ok(())
734 }
735
736 pub fn table_click_header(
737 &mut self,
738 table_ref: &str,
739 label: &str,
740 key_mods: KeyMods,
741 ) -> ImGuiResult<()> {
742 if table_ref.contains('\0') {
743 return Err(ImGuiError::invalid_operation(
744 "table_click_header table_ref contained interior NUL",
745 ));
746 }
747 if label.contains('\0') {
748 return Err(ImGuiError::invalid_operation(
749 "table_click_header label contained interior NUL",
750 ));
751 }
752 let key_mods = key_mods.bits();
753 with_scratch_txt_two(table_ref, label, |table_ptr, label_ptr| unsafe {
754 sys::imgui_test_engine_script_table_click_header(
755 self.script.raw,
756 table_ptr,
757 label_ptr,
758 key_mods,
759 )
760 });
761 Ok(())
762 }
763
764 pub fn table_open_context_menu(&mut self, table_ref: &str, column_n: i32) -> ImGuiResult<()> {
765 if table_ref.contains('\0') {
766 return Err(ImGuiError::invalid_operation(
767 "table_open_context_menu table_ref contained interior NUL",
768 ));
769 }
770 with_scratch_txt(table_ref, |ptr| unsafe {
771 sys::imgui_test_engine_script_table_open_context_menu(self.script.raw, ptr, column_n)
772 });
773 Ok(())
774 }
775
776 pub fn table_set_column_enabled(
777 &mut self,
778 table_ref: &str,
779 column_n: i32,
780 enabled: bool,
781 ) -> ImGuiResult<()> {
782 if table_ref.contains('\0') {
783 return Err(ImGuiError::invalid_operation(
784 "table_set_column_enabled table_ref contained interior NUL",
785 ));
786 }
787 with_scratch_txt(table_ref, |ptr| unsafe {
788 sys::imgui_test_engine_script_table_set_column_enabled(
789 self.script.raw,
790 ptr,
791 column_n,
792 enabled,
793 )
794 });
795 Ok(())
796 }
797
798 pub fn table_set_column_enabled_by_label(
799 &mut self,
800 table_ref: &str,
801 label: &str,
802 enabled: bool,
803 ) -> ImGuiResult<()> {
804 if table_ref.contains('\0') {
805 return Err(ImGuiError::invalid_operation(
806 "table_set_column_enabled_by_label table_ref contained interior NUL",
807 ));
808 }
809 if label.contains('\0') {
810 return Err(ImGuiError::invalid_operation(
811 "table_set_column_enabled_by_label label contained interior NUL",
812 ));
813 }
814 with_scratch_txt_two(table_ref, label, |table_ptr, label_ptr| unsafe {
815 sys::imgui_test_engine_script_table_set_column_enabled_by_label(
816 self.script.raw,
817 table_ptr,
818 label_ptr,
819 enabled,
820 )
821 });
822 Ok(())
823 }
824
825 pub fn table_resize_column(
826 &mut self,
827 table_ref: &str,
828 column_n: i32,
829 width: f32,
830 ) -> ImGuiResult<()> {
831 if table_ref.contains('\0') {
832 return Err(ImGuiError::invalid_operation(
833 "table_resize_column table_ref contained interior NUL",
834 ));
835 }
836 if !width.is_finite() || width < 0.0 {
837 return Err(ImGuiError::invalid_operation(
838 "table_resize_column requires a finite non-negative value",
839 ));
840 }
841 with_scratch_txt(table_ref, |ptr| unsafe {
842 sys::imgui_test_engine_script_table_resize_column(self.script.raw, ptr, column_n, width)
843 });
844 Ok(())
845 }
846
847 pub fn menu_click(&mut self, r#ref: &str) -> ImGuiResult<()> {
848 if r#ref.contains('\0') {
849 return Err(ImGuiError::invalid_operation(
850 "menu_click contained interior NUL",
851 ));
852 }
853 with_scratch_txt(r#ref, |ptr| unsafe {
854 sys::imgui_test_engine_script_menu_click(self.script.raw, ptr)
855 });
856 Ok(())
857 }
858
859 pub fn menu_check(&mut self, r#ref: &str) -> ImGuiResult<()> {
860 if r#ref.contains('\0') {
861 return Err(ImGuiError::invalid_operation(
862 "menu_check contained interior NUL",
863 ));
864 }
865 with_scratch_txt(r#ref, |ptr| unsafe {
866 sys::imgui_test_engine_script_menu_check(self.script.raw, ptr)
867 });
868 Ok(())
869 }
870
871 pub fn menu_uncheck(&mut self, r#ref: &str) -> ImGuiResult<()> {
872 if r#ref.contains('\0') {
873 return Err(ImGuiError::invalid_operation(
874 "menu_uncheck contained interior NUL",
875 ));
876 }
877 with_scratch_txt(r#ref, |ptr| unsafe {
878 sys::imgui_test_engine_script_menu_uncheck(self.script.raw, ptr)
879 });
880 Ok(())
881 }
882
883 pub fn menu_check_all(&mut self, parent_ref: &str) -> ImGuiResult<()> {
884 if parent_ref.contains('\0') {
885 return Err(ImGuiError::invalid_operation(
886 "menu_check_all parent_ref contained interior NUL",
887 ));
888 }
889 with_scratch_txt(parent_ref, |ptr| unsafe {
890 sys::imgui_test_engine_script_menu_check_all(self.script.raw, ptr)
891 });
892 Ok(())
893 }
894
895 pub fn menu_uncheck_all(&mut self, parent_ref: &str) -> ImGuiResult<()> {
896 if parent_ref.contains('\0') {
897 return Err(ImGuiError::invalid_operation(
898 "menu_uncheck_all parent_ref contained interior NUL",
899 ));
900 }
901 with_scratch_txt(parent_ref, |ptr| unsafe {
902 sys::imgui_test_engine_script_menu_uncheck_all(self.script.raw, ptr)
903 });
904 Ok(())
905 }
906
907 pub fn set_input_mode(&mut self, mode: InputMode) {
908 unsafe { sys::imgui_test_engine_script_set_input_mode(self.script.raw, mode as i32) };
909 }
910
911 pub fn nav_move_to(&mut self, r#ref: &str) -> ImGuiResult<()> {
912 if r#ref.contains('\0') {
913 return Err(ImGuiError::invalid_operation(
914 "nav_move_to contained interior NUL",
915 ));
916 }
917 with_scratch_txt(r#ref, |ptr| unsafe {
918 sys::imgui_test_engine_script_nav_move_to(self.script.raw, ptr)
919 });
920 Ok(())
921 }
922
923 pub fn nav_activate(&mut self) {
924 unsafe { sys::imgui_test_engine_script_nav_activate(self.script.raw) };
925 }
926
927 pub fn nav_input(&mut self) {
928 unsafe { sys::imgui_test_engine_script_nav_input(self.script.raw) };
929 }
930
931 pub fn window_close(&mut self, window_ref: &str) -> ImGuiResult<()> {
932 if window_ref.contains('\0') {
933 return Err(ImGuiError::invalid_operation(
934 "window_close window_ref contained interior NUL",
935 ));
936 }
937 with_scratch_txt(window_ref, |ptr| unsafe {
938 sys::imgui_test_engine_script_window_close(self.script.raw, ptr)
939 });
940 Ok(())
941 }
942
943 pub fn window_collapse(&mut self, window_ref: &str, collapsed: bool) -> ImGuiResult<()> {
944 if window_ref.contains('\0') {
945 return Err(ImGuiError::invalid_operation(
946 "window_collapse window_ref contained interior NUL",
947 ));
948 }
949 with_scratch_txt(window_ref, |ptr| unsafe {
950 sys::imgui_test_engine_script_window_collapse(self.script.raw, ptr, collapsed)
951 });
952 Ok(())
953 }
954
955 pub fn window_focus(&mut self, window_ref: &str) -> ImGuiResult<()> {
956 if window_ref.contains('\0') {
957 return Err(ImGuiError::invalid_operation(
958 "window_focus window_ref contained interior NUL",
959 ));
960 }
961 with_scratch_txt(window_ref, |ptr| unsafe {
962 sys::imgui_test_engine_script_window_focus(self.script.raw, ptr)
963 });
964 Ok(())
965 }
966
967 pub fn window_bring_to_front(&mut self, window_ref: &str) -> ImGuiResult<()> {
968 if window_ref.contains('\0') {
969 return Err(ImGuiError::invalid_operation(
970 "window_bring_to_front window_ref contained interior NUL",
971 ));
972 }
973 with_scratch_txt(window_ref, |ptr| unsafe {
974 sys::imgui_test_engine_script_window_bring_to_front(self.script.raw, ptr)
975 });
976 Ok(())
977 }
978
979 pub fn window_move(&mut self, window_ref: &str, x: f32, y: f32) -> ImGuiResult<()> {
980 if window_ref.contains('\0') {
981 return Err(ImGuiError::invalid_operation(
982 "window_move window_ref contained interior NUL",
983 ));
984 }
985 if !x.is_finite() || !y.is_finite() {
986 return Err(ImGuiError::invalid_operation(
987 "window_move requires finite values",
988 ));
989 }
990 with_scratch_txt(window_ref, |ptr| unsafe {
991 sys::imgui_test_engine_script_window_move(self.script.raw, ptr, x, y)
992 });
993 Ok(())
994 }
995
996 pub fn window_resize(&mut self, window_ref: &str, w: f32, h: f32) -> ImGuiResult<()> {
997 if window_ref.contains('\0') {
998 return Err(ImGuiError::invalid_operation(
999 "window_resize window_ref contained interior NUL",
1000 ));
1001 }
1002 if !w.is_finite() || !h.is_finite() || w < 0.0 || h < 0.0 {
1003 return Err(ImGuiError::invalid_operation(
1004 "window_resize requires finite non-negative values",
1005 ));
1006 }
1007 with_scratch_txt(window_ref, |ptr| unsafe {
1008 sys::imgui_test_engine_script_window_resize(self.script.raw, ptr, w, h)
1009 });
1010 Ok(())
1011 }
1012
1013 pub fn sleep_seconds(&mut self, seconds: f32) -> ImGuiResult<()> {
1014 if !seconds.is_finite() || seconds < 0.0 {
1015 return Err(ImGuiError::invalid_operation(
1016 "sleep_seconds requires a finite non-negative value",
1017 ));
1018 }
1019 unsafe { sys::imgui_test_engine_script_sleep(self.script.raw, seconds) };
1020 Ok(())
1021 }
1022
1023 pub fn assert_item_exists(&mut self, r#ref: &str) -> ImGuiResult<()> {
1024 if r#ref.contains('\0') {
1025 return Err(ImGuiError::invalid_operation(
1026 "assert_item_exists contained interior NUL",
1027 ));
1028 }
1029 with_scratch_txt(r#ref, |ptr| unsafe {
1030 sys::imgui_test_engine_script_assert_item_exists(self.script.raw, ptr)
1031 });
1032 Ok(())
1033 }
1034
1035 pub fn assert_item_visible(&mut self, r#ref: &str) -> ImGuiResult<()> {
1036 if r#ref.contains('\0') {
1037 return Err(ImGuiError::invalid_operation(
1038 "assert_item_visible contained interior NUL",
1039 ));
1040 }
1041 with_scratch_txt(r#ref, |ptr| unsafe {
1042 sys::imgui_test_engine_script_assert_item_visible(self.script.raw, ptr)
1043 });
1044 Ok(())
1045 }
1046
1047 pub fn assert_item_read_int_eq(&mut self, r#ref: &str, expected: i32) -> ImGuiResult<()> {
1048 if r#ref.contains('\0') {
1049 return Err(ImGuiError::invalid_operation(
1050 "assert_item_read_int_eq contained interior NUL",
1051 ));
1052 }
1053 with_scratch_txt(r#ref, |ptr| unsafe {
1054 sys::imgui_test_engine_script_assert_item_read_int_eq(self.script.raw, ptr, expected)
1055 });
1056 Ok(())
1057 }
1058
1059 pub fn assert_item_read_str_eq(&mut self, r#ref: &str, expected: &str) -> ImGuiResult<()> {
1060 if r#ref.contains('\0') || expected.contains('\0') {
1061 return Err(ImGuiError::invalid_operation(
1062 "assert_item_read_str_eq contained interior NUL",
1063 ));
1064 }
1065 with_scratch_txt_two(r#ref, expected, |ref_ptr, expected_ptr| unsafe {
1066 sys::imgui_test_engine_script_assert_item_read_str_eq(
1067 self.script.raw,
1068 ref_ptr,
1069 expected_ptr,
1070 )
1071 });
1072 Ok(())
1073 }
1074
1075 pub fn assert_item_read_float_eq(
1076 &mut self,
1077 r#ref: &str,
1078 expected: f32,
1079 epsilon: f32,
1080 ) -> ImGuiResult<()> {
1081 if r#ref.contains('\0') {
1082 return Err(ImGuiError::invalid_operation(
1083 "assert_item_read_float_eq contained interior NUL",
1084 ));
1085 }
1086 if !expected.is_finite() || !epsilon.is_finite() || epsilon < 0.0 {
1087 return Err(ImGuiError::invalid_operation(
1088 "assert_item_read_float_eq requires finite expected and finite non-negative epsilon",
1089 ));
1090 }
1091 with_scratch_txt(r#ref, |ptr| unsafe {
1092 sys::imgui_test_engine_script_assert_item_read_float_eq(
1093 self.script.raw,
1094 ptr,
1095 expected,
1096 epsilon,
1097 )
1098 });
1099 Ok(())
1100 }
1101
1102 pub fn assert_item_checked(&mut self, r#ref: &str) -> ImGuiResult<()> {
1103 if r#ref.contains('\0') {
1104 return Err(ImGuiError::invalid_operation(
1105 "assert_item_checked contained interior NUL",
1106 ));
1107 }
1108 with_scratch_txt(r#ref, |ptr| unsafe {
1109 sys::imgui_test_engine_script_assert_item_checked(self.script.raw, ptr)
1110 });
1111 Ok(())
1112 }
1113
1114 pub fn assert_item_opened(&mut self, r#ref: &str) -> ImGuiResult<()> {
1115 if r#ref.contains('\0') {
1116 return Err(ImGuiError::invalid_operation(
1117 "assert_item_opened contained interior NUL",
1118 ));
1119 }
1120 with_scratch_txt(r#ref, |ptr| unsafe {
1121 sys::imgui_test_engine_script_assert_item_opened(self.script.raw, ptr)
1122 });
1123 Ok(())
1124 }
1125
1126 pub fn wait_for_item(&mut self, r#ref: &str, max_frames: i32) -> ImGuiResult<()> {
1127 if r#ref.contains('\0') {
1128 return Err(ImGuiError::invalid_operation(
1129 "wait_for_item contained interior NUL",
1130 ));
1131 }
1132 if max_frames < 1 {
1133 return Err(ImGuiError::invalid_operation(
1134 "wait_for_item max_frames must be >= 1",
1135 ));
1136 }
1137 with_scratch_txt(r#ref, |ptr| unsafe {
1138 sys::imgui_test_engine_script_wait_for_item(self.script.raw, ptr, max_frames)
1139 });
1140 Ok(())
1141 }
1142
1143 pub fn wait_for_item_visible(&mut self, r#ref: &str, max_frames: i32) -> ImGuiResult<()> {
1144 if r#ref.contains('\0') {
1145 return Err(ImGuiError::invalid_operation(
1146 "wait_for_item_visible contained interior NUL",
1147 ));
1148 }
1149 if max_frames < 1 {
1150 return Err(ImGuiError::invalid_operation(
1151 "wait_for_item_visible max_frames must be >= 1",
1152 ));
1153 }
1154 with_scratch_txt(r#ref, |ptr| unsafe {
1155 sys::imgui_test_engine_script_wait_for_item_visible(self.script.raw, ptr, max_frames)
1156 });
1157 Ok(())
1158 }
1159
1160 pub fn wait_for_item_checked(&mut self, r#ref: &str, max_frames: i32) -> ImGuiResult<()> {
1161 if r#ref.contains('\0') {
1162 return Err(ImGuiError::invalid_operation(
1163 "wait_for_item_checked contained interior NUL",
1164 ));
1165 }
1166 if max_frames < 1 {
1167 return Err(ImGuiError::invalid_operation(
1168 "wait_for_item_checked max_frames must be >= 1",
1169 ));
1170 }
1171 with_scratch_txt(r#ref, |ptr| unsafe {
1172 sys::imgui_test_engine_script_wait_for_item_checked(self.script.raw, ptr, max_frames)
1173 });
1174 Ok(())
1175 }
1176
1177 pub fn wait_for_item_opened(&mut self, r#ref: &str, max_frames: i32) -> ImGuiResult<()> {
1178 if r#ref.contains('\0') {
1179 return Err(ImGuiError::invalid_operation(
1180 "wait_for_item_opened contained interior NUL",
1181 ));
1182 }
1183 if max_frames < 1 {
1184 return Err(ImGuiError::invalid_operation(
1185 "wait_for_item_opened max_frames must be >= 1",
1186 ));
1187 }
1188 with_scratch_txt(r#ref, |ptr| unsafe {
1189 sys::imgui_test_engine_script_wait_for_item_opened(self.script.raw, ptr, max_frames)
1190 });
1191 Ok(())
1192 }
1193
1194 pub fn input_text_replace(
1195 &mut self,
1196 r#ref: &str,
1197 text: &str,
1198 submit_enter: bool,
1199 ) -> ImGuiResult<()> {
1200 self.item_click(r#ref)?;
1201 if submit_enter {
1202 self.key_chars_replace_enter(text)?;
1203 } else {
1204 self.key_chars_replace(text)?;
1205 }
1206 Ok(())
1207 }
1208
1209 pub fn yield_frames(&mut self, frames: i32) {
1210 unsafe { sys::imgui_test_engine_script_yield(self.script.raw, frames) };
1211 }
1212}
1213
1214impl TestEngine {
1215 pub fn try_create() -> ImGuiResult<Self> {
1217 let raw = unsafe { sys::imgui_test_engine_create_context() };
1218 if raw.is_null() {
1219 return Err(ImGuiError::context_creation(
1220 "imgui_test_engine_create_context returned null",
1221 ));
1222 }
1223 Ok(Self {
1224 raw,
1225 bound_imgui_ctx_raw: None,
1226 bound_imgui_alive: None,
1227 _not_send_sync: PhantomData,
1228 })
1229 }
1230
1231 pub fn create() -> Self {
1236 Self::try_create().expect("Failed to create Dear ImGui Test Engine context")
1237 }
1238
1239 pub fn as_raw(&self) -> *mut sys::ImGuiTestEngine {
1240 self.raw
1241 }
1242
1243 pub fn is_bound(&self) -> bool {
1244 unsafe { sys::imgui_test_engine_is_bound(self.raw) }
1245 }
1246
1247 pub fn is_started(&self) -> bool {
1248 unsafe { sys::imgui_test_engine_is_started(self.raw) }
1249 }
1250
1251 fn ui_context_target(&self) -> *mut dear_imgui_rs::sys::ImGuiContext {
1252 unsafe { sys::imgui_test_engine_get_ui_context_target(self.raw) }
1253 }
1254
1255 pub fn try_start(&mut self, imgui_ctx: &Context) -> ImGuiResult<()> {
1262 let ctx = imgui_ctx.as_raw();
1263 if ctx.is_null() {
1264 return Err(ImGuiError::invalid_operation(
1265 "TestEngine::try_start() called with a null ImGui context",
1266 ));
1267 }
1268
1269 let bound = self.ui_context_target();
1270 if !bound.is_null() {
1271 if bound == ctx {
1272 if self.is_started() {
1273 return Ok(());
1274 }
1275 return Err(ImGuiError::invalid_operation(
1276 "TestEngine::try_start() called but the engine is already bound (and not started). \
1277 Call TestEngine::shutdown() to detach, then start again.",
1278 ));
1279 }
1280 return Err(ImGuiError::invalid_operation(
1281 "TestEngine::try_start() called while already bound to a different ImGui context",
1282 ));
1283 }
1284
1285 unsafe { sys::imgui_test_engine_start(self.raw, ctx) };
1286 self.bound_imgui_ctx_raw = Some(ctx);
1287 self.bound_imgui_alive = Some(imgui_ctx.alive_token());
1288 Ok(())
1289 }
1290
1291 pub fn start(&mut self, imgui_ctx: &Context) {
1298 self.try_start(imgui_ctx)
1299 .expect("Failed to start Dear ImGui Test Engine context");
1300 }
1301
1302 pub fn stop(&mut self) {
1304 unsafe { sys::imgui_test_engine_stop(self.raw) };
1305 }
1306
1307 pub fn shutdown(&mut self) {
1312 if let Some(alive) = &self.bound_imgui_alive {
1313 assert!(
1314 alive.is_alive(),
1315 "dear-imgui-test-engine: ImGui context has been dropped"
1316 );
1317 }
1318 unsafe { sys::imgui_test_engine_unbind(self.raw) };
1319 self.bound_imgui_ctx_raw = None;
1320 self.bound_imgui_alive = None;
1321 }
1322
1323 pub fn post_swap(&mut self) {
1324 unsafe { sys::imgui_test_engine_post_swap(self.raw) };
1325 }
1326
1327 pub fn show_windows(&mut self, _ui: &Ui, opened: Option<&mut bool>) {
1328 let ptr = opened.map_or(std::ptr::null_mut(), |b| b as *mut bool);
1329 unsafe { sys::imgui_test_engine_show_windows(self.raw, ptr) };
1330 }
1331
1332 pub fn register_default_tests(&mut self) {
1334 unsafe { sys::imgui_test_engine_register_default_tests(self.raw) };
1335 }
1336
1337 pub fn add_script_test<F>(&mut self, category: &str, name: &str, build: F) -> ImGuiResult<()>
1341 where
1342 F: FnOnce(&mut ScriptTest<'_>) -> ImGuiResult<()>,
1343 {
1344 if category.contains('\0') {
1345 return Err(ImGuiError::invalid_operation(
1346 "add_script_test category contained interior NUL",
1347 ));
1348 }
1349 if name.contains('\0') {
1350 return Err(ImGuiError::invalid_operation(
1351 "add_script_test name contained interior NUL",
1352 ));
1353 }
1354
1355 let mut script = Script::create()?;
1356 build(&mut ScriptTest {
1357 script: &mut script,
1358 })?;
1359 let script_raw = script.into_raw();
1360
1361 with_scratch_txt_two(category, name, |cat_ptr, name_ptr| unsafe {
1362 sys::imgui_test_engine_register_script_test(self.raw, cat_ptr, name_ptr, script_raw)
1363 });
1364
1365 Ok(())
1366 }
1367
1368 pub fn queue_tests(
1369 &mut self,
1370 group: TestGroup,
1371 filter: Option<&str>,
1372 run_flags: RunFlags,
1373 ) -> ImGuiResult<()> {
1374 if let Some(filter) = filter {
1375 if filter.contains('\0') {
1376 return Err(ImGuiError::invalid_operation(
1377 "queue_tests filter contained interior NUL",
1378 ));
1379 }
1380 with_scratch_txt(filter, |ptr| unsafe {
1381 sys::imgui_test_engine_queue_tests(
1382 self.raw,
1383 group as sys::ImGuiTestEngineGroup,
1384 ptr,
1385 run_flags.bits() as i32,
1386 )
1387 });
1388 return Ok(());
1389 }
1390
1391 unsafe {
1392 sys::imgui_test_engine_queue_tests(
1393 self.raw,
1394 group as sys::ImGuiTestEngineGroup,
1395 std::ptr::null(),
1396 run_flags.bits() as i32,
1397 )
1398 };
1399 Ok(())
1400 }
1401
1402 pub fn queue_all_tests(&mut self) {
1403 let _ = self.queue_tests(TestGroup::Tests, None, RunFlags::NONE);
1404 }
1405
1406 pub fn result_summary(&self) -> ResultSummary {
1411 let mut raw = sys::ImGuiTestEngineResultSummary_c {
1412 CountTested: 0,
1413 CountSuccess: 0,
1414 CountInQueue: 0,
1415 };
1416 unsafe { sys::imgui_test_engine_get_result_summary(self.raw, &mut raw) };
1417 ResultSummary {
1418 count_tested: raw.CountTested,
1419 count_success: raw.CountSuccess,
1420 count_in_queue: raw.CountInQueue,
1421 }
1422 }
1423
1424 pub fn is_test_queue_empty(&self) -> bool {
1425 unsafe { sys::imgui_test_engine_is_test_queue_empty(self.raw) }
1426 }
1427
1428 pub fn is_running_tests(&self) -> bool {
1429 unsafe { sys::imgui_test_engine_is_running_tests(self.raw) }
1430 }
1431
1432 pub fn is_requesting_max_app_speed(&self) -> bool {
1433 unsafe { sys::imgui_test_engine_is_requesting_max_app_speed(self.raw) }
1434 }
1435
1436 pub fn try_abort_engine(&mut self) -> bool {
1437 unsafe { sys::imgui_test_engine_try_abort_engine(self.raw) }
1438 }
1439
1440 pub fn abort_current_test(&mut self) {
1441 unsafe { sys::imgui_test_engine_abort_current_test(self.raw) };
1442 }
1443
1444 pub fn set_run_speed(&mut self, speed: RunSpeed) {
1445 unsafe {
1446 sys::imgui_test_engine_set_run_speed(self.raw, speed as sys::ImGuiTestEngineRunSpeed)
1447 };
1448 }
1449
1450 pub fn set_verbose_level(&mut self, level: VerboseLevel) {
1451 unsafe {
1452 sys::imgui_test_engine_set_verbose_level(
1453 self.raw,
1454 level as sys::ImGuiTestEngineVerboseLevel,
1455 )
1456 };
1457 }
1458
1459 pub fn set_capture_enabled(&mut self, enabled: bool) {
1460 unsafe { sys::imgui_test_engine_set_capture_enabled(self.raw, enabled) };
1461 }
1462
1463 pub fn install_default_crash_handler() {
1464 unsafe { sys::imgui_test_engine_install_default_crash_handler() };
1465 }
1466}
1467
1468impl Drop for TestEngine {
1469 fn drop(&mut self) {
1470 if !self.raw.is_null() {
1471 if let Some(alive) = &self.bound_imgui_alive {
1472 if !alive.is_alive() {
1473 return;
1476 }
1477 }
1478 if self.ui_context_target().is_null() {
1479 self.bound_imgui_ctx_raw = None;
1480 self.bound_imgui_alive = None;
1481 }
1482 if !self.ui_context_target().is_null() {
1483 if let Some(bound) = self.bound_imgui_ctx_raw {
1484 unsafe {
1485 let prev = dear_imgui_rs::sys::igGetCurrentContext();
1486 dear_imgui_rs::sys::igSetCurrentContext(bound);
1487 sys::imgui_test_engine_unbind(self.raw);
1488 dear_imgui_rs::sys::igSetCurrentContext(prev);
1489 }
1490 } else {
1491 unsafe { sys::imgui_test_engine_unbind(self.raw) };
1492 }
1493 }
1494 unsafe { sys::imgui_test_engine_destroy_context(self.raw) };
1495 self.raw = std::ptr::null_mut();
1496 }
1497 }
1498}