1
//! Debug / E2E server, ported into `azul-layout` from the DLL's
2
//! `desktop::shell2::common::debug_server`.
3
//!
4
//! The whole module is gated behind the `e2e-server` feature (declared NOT in
5
//! `default`), so the lean published crate is byte-for-byte unaffected. The
6
//! ~12k-line op-dispatch implementation lives verbatim in [`full`]:
7
//! `process_debug_event` (the op dispatcher), the `DebugEvent` enum, the `E2e*`
8
//! JSON schema types and the scenario runner (`resume_e2e_continuation`).
9
//!
10
//! ONE call site in [`full`] is injected through [`hooks`] so the core dispatch
11
//! stays host-agnostic: the native window screenshot. The DLL installs the real
12
//! implementation via [`hooks::set_host_hooks`]; headless callers (the
13
//! `e2e_json` test, [`run_e2e_test`]) get the `None` default, which ERRORS
14
//! rather than pretending a screenshot was taken.
15
//!
16
//! The `DebugRequest` plumbing (spmc channel + `handle_event_request` + the
17
//! server statics) is gated behind the `e2e-server-http` sub-feature; it is not
18
//! needed by the library API path. The pieces that CANNOT live here at all —
19
//! the TCP listener that serves the debugger UI out of the DLL build script's
20
//! `OUT_DIR`, and `register_debug_timer(&mut dyn PlatformWindow)` — live in the
21
//! DLL's `debug_server::platform` and call back into this module.
22

            
23
mod full;
24
pub use full::*;
25

            
26
mod cpu_backend;
27

            
28
mod runner;
29
pub use runner::run_e2e_test;
30

            
31
mod report;
32
pub use report::{load_e2e_tests, render_report, E2eVerdict};
33

            
34
pub mod hooks {
35
    //! Dependency-injection seam for the three host-coupled call sites in
36
    //! [`super::full`]. See the module docs above.
37

            
38
    use std::sync::RwLock;
39

            
40
    use azul_layout::callbacks::CallbackInfo;
41

            
42
    /// Host-supplied implementations for the call sites the layout crate cannot
43
    /// satisfy on its own. Each is optional: `None` selects the headless
44
    /// default (error / no-op / `None`).
45
    #[derive(Clone, Copy, Debug)]
46
    pub struct E2eHostHooks {
47
        /// Grab a real window screenshot as a base64 data-URI. `None` (headless)
48
        /// makes the `screenshot` op return an error.
49
        pub take_native_screenshot_base64:
50
            Option<fn(&mut CallbackInfo) -> Result<String, String>>,
51
    }
52

            
53
    impl E2eHostHooks {
54
        /// All-headless defaults.
55
        pub const NONE: Self = Self {
56
            take_native_screenshot_base64: None,
57
        };
58
    }
59

            
60
    impl Default for E2eHostHooks {
61
        fn default() -> Self {
62
            Self::NONE
63
        }
64
    }
65

            
66
    static HOST_HOOKS: RwLock<E2eHostHooks> = RwLock::new(E2eHostHooks::NONE);
67

            
68
    /// Install host hooks. Called once by the DLL at startup; a headless caller
69
    /// may call it to override individual seams (e.g. capture screenshots).
70
    pub fn set_host_hooks(hooks: E2eHostHooks) {
71
        if let Ok(mut h) = HOST_HOOKS.write() {
72
            *h = hooks;
73
        }
74
    }
75

            
76
    fn get() -> E2eHostHooks {
77
        HOST_HOOKS.read().map(|h| *h).unwrap_or(E2eHostHooks::NONE)
78
    }
79

            
80
    /// Screenshot seam (`screenshot` op). Errors headlessly.
81
    pub(crate) fn take_native_screenshot_base64(
82
        ci: &mut CallbackInfo,
83
    ) -> Result<String, String> {
84
        match get().take_native_screenshot_base64 {
85
            Some(f) => f(ci),
86
            None => Err(
87
                "native screenshot unavailable (no e2e host hook installed)".to_string(),
88
            ),
89
        }
90
    }
91
}