wdext 0.1.0

A DbgEng wrapper framework
// SPDX-FileCopyrightText: 2026 takubokudori
// SPDX-License-Identifier: MIT OR Apache-2.0
#[cfg(test)]
pub mod tests {
    use crate::tests::util::local_debug2;
    use std::{
        cell::{Cell, RefCell},
        rc::Rc,
    };
    use wdext::{
        callbacks::WdCallbacksErrorPolicy,
        dbgeng::{DebugControl, callbacks::DebugInputCallbacksHandler},
    };
    use windy::traits::ToWString;
    use windy_macros::wstr;

    mod util;

    const INPUT_TEXT: &str = "from TestInputCallbacks";

    struct TestInputCallbacks {
        responder: DebugControl,
        start_count: Cell<usize>,
        end_count: Cell<usize>,
        buffer_sizes: RefCell<Vec<u32>>,
        call_order: RefCell<Vec<&'static str>>,
    }

    impl TestInputCallbacks {
        fn new(responder: DebugControl) -> Self {
            Self {
                responder,
                start_count: Cell::new(0),
                end_count: Cell::new(0),
                buffer_sizes: RefCell::new(Vec::new()),
                call_order: RefCell::new(Vec::new()),
            }
        }
    }

    impl DebugInputCallbacksHandler for TestInputCallbacks {
        fn start_input(&self, buffer_size: u32) -> windows::core::Result<()> {
            self.start_count.set(self.start_count.get() + 1);
            self.buffer_sizes.borrow_mut().push(buffer_size);
            self.call_order.borrow_mut().push("start");

            self.responder
                .return_input_wide(wstr!("from TestInputCallbacks"))
        }

        fn end_input(&self) -> windows::core::Result<()> {
            self.end_count.set(self.end_count.get() + 1);
            self.call_order.borrow_mut().push("end");
            Ok(())
        }
    }

    #[test]
    fn test_input_callbacks() {
        let ctx = local_debug2();

        let client = ctx.client();

        let responder_client = client.create_client().unwrap();
        let responder =
            DebugControl::from_interface(responder_client.as_interface())
                .unwrap();
        let callbacks = Rc::new(TestInputCallbacks::new(responder));

        assert!(client.get_input_callbacks().unwrap().is_none());

        let _guard = client
            .set_forward_input_callbacks(
                callbacks.clone(),
                WdCallbacksErrorPolicy::ForwardError,
            )
            .unwrap();

        assert!(client.get_input_callbacks().unwrap().is_some());

        let input = ctx.control().input().unwrap();

        assert_eq!(input.to_string(), INPUT_TEXT);
        assert_eq!(callbacks.start_count.get(), 1);
        assert_eq!(callbacks.end_count.get(), 1);
        assert_eq!(callbacks.call_order.borrow().as_slice(), ["start", "end"]);

        let buffer_sizes = callbacks.buffer_sizes.borrow();
        assert_eq!(buffer_sizes.len(), 1);
        assert!(
            buffer_sizes[0] > INPUT_TEXT.to_wstring().as_bytes().len() as u32,
            "DbgEng requested a buffer too small for the returned input"
        );

        client.clear_all_input_callbacks().unwrap();
        assert!(client.get_input_callbacks().unwrap().is_none());
    }
}