Skip to main content

ic_testkit/pic/
startup.rs

1use std::panic::{AssertUnwindSafe, catch_unwind};
2
3use pocket_ic::{PocketIc, PocketIcBuilder};
4
5use super::transport;
6
7/// A panic raised while PocketIC constructs an instance.
8#[derive(Clone, Debug, Eq, PartialEq)]
9pub struct PocketIcStartupError {
10    message: String,
11}
12
13/// Fallible construction at PocketIC's currently panicking builder boundary.
14pub trait PocketIcBuilderExt {
15    /// Build one PocketIC instance while capturing an upstream startup panic.
16    ///
17    /// This method deliberately does not classify panic text. It exists so a
18    /// test harness can apply its own bounded retry policy until PocketIC
19    /// provides a native fallible builder API.
20    fn try_build(self) -> Result<PocketIc, PocketIcStartupError>;
21}
22
23impl PocketIcBuilderExt for PocketIcBuilder {
24    fn try_build(self) -> Result<PocketIc, PocketIcStartupError> {
25        catch_unwind(AssertUnwindSafe(|| self.build()))
26            .map_err(|payload| PocketIcStartupError::from_panic(payload.as_ref()))
27    }
28}
29
30impl PocketIcStartupError {
31    fn from_panic(payload: &(dyn std::any::Any + Send)) -> Self {
32        Self {
33            message: transport::panic_payload_to_string(payload),
34        }
35    }
36
37    /// Read the unclassified upstream panic message.
38    #[must_use]
39    pub fn message(&self) -> &str {
40        &self.message
41    }
42}
43
44impl std::fmt::Display for PocketIcStartupError {
45    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        write!(formatter, "PocketIC startup panicked: {}", self.message)
47    }
48}
49
50impl std::error::Error for PocketIcStartupError {}
51
52#[cfg(test)]
53mod tests {
54    use super::PocketIcStartupError;
55
56    #[test]
57    fn startup_error_preserves_string_panic_message() {
58        let error = PocketIcStartupError::from_panic(&"startup failed");
59
60        assert_eq!(error.message(), "startup failed");
61        assert_eq!(
62            error.to_string(),
63            "PocketIC startup panicked: startup failed"
64        );
65    }
66}