#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[allow(dead_code)] pub enum PanicCause {
ExplicitPanic,
BoundsCheck,
ArithmeticOverflow(String),
ShiftOverflow(String),
DivisionByZero,
UnwrapNone,
UnwrapErr,
ExpectNone,
ExpectErr,
AssertFailed,
Unreachable,
Unimplemented,
Todo,
PanicInDrop,
CannotUnwind,
FormattingError,
CapacityOverflow,
OutOfMemory,
StringSliceError,
InvalidEnum,
MisalignedPointer,
KeyNotFound,
Unknown,
}
impl PanicCause {
pub fn id(&self) -> &'static str {
match self {
PanicCause::ExplicitPanic => "panic",
PanicCause::BoundsCheck => "bounds",
PanicCause::ArithmeticOverflow(op) => match op.as_str() {
"division" => "div_overflow",
"remainder" => "rem_overflow",
_ => "overflow",
},
PanicCause::ShiftOverflow(_) => "shift_overflow",
PanicCause::DivisionByZero => "div_zero",
PanicCause::UnwrapNone => "unwrap",
PanicCause::UnwrapErr => "unwrap",
PanicCause::ExpectNone => "expect",
PanicCause::ExpectErr => "expect",
PanicCause::AssertFailed => "assert",
PanicCause::Unreachable => "unreachable",
PanicCause::Unimplemented => "unimplemented",
PanicCause::Todo => "todo",
PanicCause::PanicInDrop => "drop",
PanicCause::CannotUnwind => "unwind",
PanicCause::FormattingError => "format",
PanicCause::CapacityOverflow => "capacity",
PanicCause::OutOfMemory => "oom",
PanicCause::StringSliceError => "str_slice",
PanicCause::InvalidEnum => "invalid_enum",
PanicCause::MisalignedPointer => "misaligned_ptr",
PanicCause::KeyNotFound => "key_not_found",
PanicCause::Unknown => "unknown",
}
}
pub fn parent_id(&self) -> Option<&'static str> {
match self {
PanicCause::ArithmeticOverflow(_) => Some("overflow"),
PanicCause::ShiftOverflow(_) => Some("overflow"),
_ => None,
}
}
pub fn all_ids() -> &'static [&'static str] {
&[
"panic",
"bounds",
"overflow", "div_overflow", "rem_overflow", "shift_overflow", "div_zero",
"unwrap",
"expect",
"assert",
"unreachable",
"unimplemented",
"todo",
"drop",
"unwind",
"format",
"capacity",
"oom",
"str_slice",
"invalid_enum",
"misaligned_ptr",
"key_not_found",
"unknown",
]
}
pub fn description(&self) -> &'static str {
match self {
PanicCause::ExplicitPanic => "explicit panic!() call",
PanicCause::BoundsCheck => "index out of bounds",
PanicCause::ArithmeticOverflow(_) => "arithmetic overflow",
PanicCause::ShiftOverflow(_) => "shift overflow",
PanicCause::DivisionByZero => "division by zero",
PanicCause::UnwrapNone => "unwrap() on None",
PanicCause::UnwrapErr => "unwrap() on Err",
PanicCause::ExpectNone => "expect() on None",
PanicCause::ExpectErr => "expect() on Err",
PanicCause::AssertFailed => "assertion failed",
PanicCause::Unreachable => "unreachable!() reached",
PanicCause::Unimplemented => "unimplemented!() reached",
PanicCause::Todo => "todo!() reached",
PanicCause::PanicInDrop => "panic during drop",
PanicCause::CannotUnwind => "panic in no-unwind context",
PanicCause::FormattingError => "formatting error",
PanicCause::CapacityOverflow => "capacity overflow",
PanicCause::OutOfMemory => "out of memory",
PanicCause::StringSliceError => "string/slice error",
PanicCause::InvalidEnum => "invalid enum discriminant",
PanicCause::MisalignedPointer => "misaligned pointer dereference",
PanicCause::KeyNotFound => "key not found in map",
PanicCause::Unknown => "unknown cause",
}
}
pub fn suggestion(&self, is_direct: bool) -> &'static str {
if is_direct {
self.direct_suggestion()
} else {
self.indirect_suggestion()
}
}
fn direct_suggestion(&self) -> &'static str {
match self {
PanicCause::ExplicitPanic => "Review if panic is intentional or add error handling",
PanicCause::BoundsCheck => "Use .get() for safe access or validate index before use",
PanicCause::ArithmeticOverflow(_) => {
"Use checked_*, saturating_*, or wrapping_* methods"
}
PanicCause::ShiftOverflow(_) => "Validate shift amount is within valid range",
PanicCause::DivisionByZero => "Check divisor is non-zero before division",
PanicCause::UnwrapNone => "Use if let, match, unwrap_or, or ? operator instead",
PanicCause::UnwrapErr => "Use if let, match, unwrap_or, or ? operator instead",
PanicCause::ExpectNone => "Use if let, match, unwrap_or, or ? operator instead",
PanicCause::ExpectErr => "Use if let, match, unwrap_or, or ? operator instead",
PanicCause::AssertFailed => "Review assertion condition",
PanicCause::Unreachable => "Ensure code path is truly unreachable",
PanicCause::Unimplemented => "Implement the missing functionality",
PanicCause::Todo => "Complete the TODO implementation",
PanicCause::PanicInDrop => {
"Avoid panicking in Drop implementations; use catch_unwind or log errors instead"
}
PanicCause::CannotUnwind => {
"Avoid panicking in extern functions; use catch_unwind at FFI boundaries"
}
PanicCause::FormattingError => {
"Ensure Display/Debug impls don't panic; validate format arguments"
}
PanicCause::CapacityOverflow => {
"Check collection size before allocation; use try_reserve for fallible allocation"
}
PanicCause::OutOfMemory => {
"Handle allocation failures; consider system memory limits or fallible allocation"
}
PanicCause::StringSliceError => {
"Use str::get() for safe slicing; validate UTF-8 boundaries"
}
PanicCause::InvalidEnum => {
"Check for memory corruption or unsafe enum transmutes; validate enum discriminants"
}
PanicCause::MisalignedPointer => {
"Ensure pointer alignment requirements are met; review unsafe pointer casts"
}
PanicCause::KeyNotFound => {
"Use .get() to safely look up keys; returns None instead of panicking"
}
PanicCause::Unknown => {
"Jonesy detected a panic path but couldn't identify the cause. Use --tree to investigate"
}
}
}
fn indirect_suggestion(&self) -> &'static str {
match self {
PanicCause::ExplicitPanic => {
"This calls a function that may panic. Review the called function or handle errors"
}
PanicCause::BoundsCheck => {
"This calls a function that may panic on bounds check. Validate inputs or use a fallible alternative"
}
PanicCause::ArithmeticOverflow(_) => {
"This calls a function that may overflow. Validate inputs or use checked arithmetic"
}
PanicCause::ShiftOverflow(_) => {
"This calls a function that may overflow on shift. Validate inputs"
}
PanicCause::DivisionByZero => {
"This calls a function that may divide by zero. Validate inputs"
}
PanicCause::UnwrapNone | PanicCause::UnwrapErr => {
"This calls a function that may call unwrap(). Consider a fallible alternative (e.g., try_*)"
}
PanicCause::ExpectNone | PanicCause::ExpectErr => {
"This calls a function that may call expect(). Consider a fallible alternative (e.g., try_*)"
}
PanicCause::AssertFailed => {
"This calls a function with an assertion. Review preconditions"
}
PanicCause::Unreachable => {
"This calls a function that may reach unreachable code. Review control flow"
}
PanicCause::Unimplemented => "This calls a function with unimplemented!() code paths",
PanicCause::Todo => "This calls a function with todo!() code paths",
PanicCause::PanicInDrop => "This calls a function that may panic during drop",
PanicCause::CannotUnwind => {
"This calls a function that may panic in a no-unwind context"
}
PanicCause::FormattingError => "This calls a function that may panic during formatting",
PanicCause::CapacityOverflow => {
"This calls a function that may overflow capacity. Consider fallible allocation (try_reserve)"
}
PanicCause::OutOfMemory => "This calls a function that may fail to allocate memory",
PanicCause::StringSliceError => {
"This calls a function that may fail on string/slice operations"
}
PanicCause::InvalidEnum => {
"This calls a function that may encounter an invalid enum discriminant"
}
PanicCause::MisalignedPointer => {
"This calls a function that may dereference a misaligned pointer"
}
PanicCause::KeyNotFound => {
"This calls a function that indexes a map. Use .get() instead of [] for safe lookup"
}
PanicCause::Unknown => {
"This calls a function that may panic. Use --tree to investigate the call chain"
}
}
}
pub fn format_suggestion(&self, is_direct: bool, called_function: Option<&str>) -> String {
if is_direct || called_function.is_none() {
return self.suggestion(is_direct).to_string();
}
let func = called_function.unwrap();
let short_func = func.rsplit("::").next().unwrap_or(func);
match self {
PanicCause::ExplicitPanic => {
format!("This calls `{func}` which may panic. Review `{func}` or handle errors")
}
PanicCause::BoundsCheck => {
format!(
"This calls `{func}` which may panic on bounds check. Validate inputs or use a fallible alternative"
)
}
PanicCause::ArithmeticOverflow(_) => {
format!(
"This calls `{func}` which may overflow. Validate inputs or use checked arithmetic"
)
}
PanicCause::ShiftOverflow(_) => {
format!("This calls `{func}` which may overflow on shift. Validate inputs")
}
PanicCause::DivisionByZero => {
format!("This calls `{func}` which may divide by zero. Validate inputs")
}
PanicCause::UnwrapNone | PanicCause::UnwrapErr => {
format!(
"This calls `{func}` which may call unwrap(). Consider a fallible alternative (e.g., try_{short_func})"
)
}
PanicCause::ExpectNone | PanicCause::ExpectErr => {
format!(
"This calls `{func}` which may call expect(). Consider a fallible alternative (e.g., try_{short_func})"
)
}
PanicCause::AssertFailed => {
format!("This calls `{func}` which has an assertion. Review preconditions")
}
PanicCause::Unreachable => {
format!("This calls `{func}` which may reach unreachable code. Review control flow")
}
PanicCause::Unimplemented => {
format!("This calls `{func}` which has unimplemented!() code paths")
}
PanicCause::Todo => format!("This calls `{func}` which has todo!() code paths"),
PanicCause::PanicInDrop => {
format!("This calls `{func}` which may panic during drop")
}
PanicCause::CannotUnwind => {
format!("This calls `{func}` which may panic in a no-unwind context")
}
PanicCause::FormattingError => {
format!("This calls `{func}` which may panic during formatting")
}
PanicCause::CapacityOverflow => {
format!(
"This calls `{func}` which may overflow capacity. Consider fallible allocation (try_reserve)"
)
}
PanicCause::OutOfMemory => {
format!(
"This calls `{func}` which may fail on allocation. Consider fallible allocation"
)
}
PanicCause::StringSliceError => {
format!("This calls `{func}` which may fail on string/slice operations")
}
PanicCause::InvalidEnum => {
format!("This calls `{func}` which may encounter an invalid enum discriminant")
}
PanicCause::MisalignedPointer => {
format!("This calls `{func}` which may dereference a misaligned pointer")
}
PanicCause::KeyNotFound => {
format!(
"This calls `{func}` which indexes a map. Use .get() instead of [] for safe lookup"
)
}
PanicCause::Unknown => {
format!("This calls `{func}` which may panic. Use --tree to investigate")
}
}
}
pub fn error_code(&self) -> &'static str {
match self {
PanicCause::ExplicitPanic => "JP001",
PanicCause::BoundsCheck => "JP002",
PanicCause::ArithmeticOverflow(_) => "JP003",
PanicCause::ShiftOverflow(_) => "JP004",
PanicCause::DivisionByZero => "JP005",
PanicCause::UnwrapNone => "JP006",
PanicCause::UnwrapErr => "JP007",
PanicCause::ExpectNone => "JP008",
PanicCause::ExpectErr => "JP009",
PanicCause::AssertFailed => "JP010",
PanicCause::Unreachable => "JP012",
PanicCause::Unimplemented => "JP013",
PanicCause::Todo => "JP014",
PanicCause::PanicInDrop => "JP015",
PanicCause::CannotUnwind => "JP016",
PanicCause::FormattingError => "JP017",
PanicCause::CapacityOverflow => "JP018",
PanicCause::OutOfMemory => "JP019",
PanicCause::StringSliceError => "JP020",
PanicCause::InvalidEnum => "JP021",
PanicCause::MisalignedPointer => "JP022",
PanicCause::KeyNotFound => "JP023",
PanicCause::Unknown => "JP000",
}
}
pub fn docs_slug(&self) -> &'static str {
match self {
PanicCause::ExplicitPanic => "JP001-explicit-panic",
PanicCause::BoundsCheck => "JP002-bounds-check",
PanicCause::ArithmeticOverflow(_) => "JP003-arithmetic-overflow",
PanicCause::ShiftOverflow(_) => "JP004-shift-overflow",
PanicCause::DivisionByZero => "JP005-division-by-zero",
PanicCause::UnwrapNone => "JP006-unwrap-none",
PanicCause::UnwrapErr => "JP007-unwrap-err",
PanicCause::ExpectNone => "JP008-expect-none",
PanicCause::ExpectErr => "JP009-expect-err",
PanicCause::AssertFailed => "JP010-assert-failed",
PanicCause::Unreachable => "JP012-unreachable",
PanicCause::Unimplemented => "JP013-unimplemented",
PanicCause::Todo => "JP014-todo",
PanicCause::PanicInDrop => "JP015-panic-in-drop",
PanicCause::CannotUnwind => "JP016-cannot-unwind",
PanicCause::FormattingError => "JP017-formatting-error",
PanicCause::CapacityOverflow => "JP018-capacity-overflow",
PanicCause::OutOfMemory => "JP019-out-of-memory",
PanicCause::StringSliceError => "JP020-string-slice-error",
PanicCause::InvalidEnum => "JP021-invalid-enum",
PanicCause::MisalignedPointer => "JP022-misaligned-pointer",
PanicCause::KeyNotFound => "JP023-key-not-found",
PanicCause::Unknown => "",
}
}
pub fn docs_url(&self) -> String {
const BASE_URL: &str = "https://jonesy.mackenzie-serres.net/panics";
let slug = self.docs_slug();
if slug.is_empty() {
format!("{}/", BASE_URL)
} else {
format!("{}/{}", BASE_URL, slug)
}
}
#[allow(dead_code)] pub fn is_debug_only(&self) -> bool {
matches!(
self,
PanicCause::ArithmeticOverflow(_) | PanicCause::ShiftOverflow(_)
)
}
pub fn release_warning(&self) -> Option<&'static str> {
match self {
PanicCause::ArithmeticOverflow(_) | PanicCause::ShiftOverflow(_) => {
Some("With default release settings (overflow-checks=false), this wraps silently")
}
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_panic_cause_id() {
assert_eq!(PanicCause::ExplicitPanic.id(), "panic");
assert_eq!(PanicCause::BoundsCheck.id(), "bounds");
assert_eq!(PanicCause::UnwrapNone.id(), "unwrap");
assert_eq!(PanicCause::UnwrapErr.id(), "unwrap");
assert_eq!(PanicCause::ExpectNone.id(), "expect");
assert_eq!(PanicCause::ExpectErr.id(), "expect");
assert_eq!(PanicCause::DivisionByZero.id(), "div_zero");
assert_eq!(
PanicCause::ArithmeticOverflow("addition".to_string()).id(),
"overflow"
);
assert_eq!(
PanicCause::ArithmeticOverflow("division".to_string()).id(),
"div_overflow"
);
assert_eq!(
PanicCause::ArithmeticOverflow("remainder".to_string()).id(),
"rem_overflow"
);
assert_eq!(
PanicCause::ShiftOverflow("left".to_string()).id(),
"shift_overflow"
);
}
#[test]
fn test_panic_cause_parent_id() {
assert_eq!(
PanicCause::ArithmeticOverflow("add".to_string()).parent_id(),
Some("overflow")
);
assert_eq!(
PanicCause::ShiftOverflow("left".to_string()).parent_id(),
Some("overflow")
);
assert_eq!(PanicCause::AssertFailed.parent_id(), None);
assert_eq!(PanicCause::ExplicitPanic.parent_id(), None);
assert_eq!(PanicCause::BoundsCheck.parent_id(), None);
}
#[test]
fn test_panic_cause_description() {
assert_eq!(
PanicCause::ExplicitPanic.description(),
"explicit panic!() call"
);
assert_eq!(PanicCause::BoundsCheck.description(), "index out of bounds");
assert_eq!(PanicCause::UnwrapNone.description(), "unwrap() on None");
assert_eq!(PanicCause::UnwrapErr.description(), "unwrap() on Err");
assert_eq!(PanicCause::Todo.description(), "todo!() reached");
assert_eq!(
PanicCause::Unreachable.description(),
"unreachable!() reached"
);
}
#[test]
fn test_panic_cause_error_code() {
assert_eq!(PanicCause::ExplicitPanic.error_code(), "JP001");
assert_eq!(PanicCause::BoundsCheck.error_code(), "JP002");
assert_eq!(
PanicCause::ArithmeticOverflow("add".to_string()).error_code(),
"JP003"
);
assert_eq!(PanicCause::UnwrapNone.error_code(), "JP006");
assert_eq!(PanicCause::UnwrapErr.error_code(), "JP007");
assert_eq!(PanicCause::Unknown.error_code(), "JP000");
}
#[test]
fn test_panic_cause_docs_slug() {
assert_eq!(
PanicCause::ExplicitPanic.docs_slug(),
"JP001-explicit-panic"
);
assert_eq!(PanicCause::BoundsCheck.docs_slug(), "JP002-bounds-check");
assert_eq!(PanicCause::UnwrapNone.docs_slug(), "JP006-unwrap-none");
assert_eq!(PanicCause::Unknown.docs_slug(), "");
}
#[test]
fn test_panic_cause_docs_url() {
assert_eq!(
PanicCause::ExplicitPanic.docs_url(),
"https://jonesy.mackenzie-serres.net/panics/JP001-explicit-panic"
);
assert_eq!(
PanicCause::Unknown.docs_url(),
"https://jonesy.mackenzie-serres.net/panics/"
);
}
#[test]
fn test_panic_cause_is_debug_only() {
assert!(PanicCause::ArithmeticOverflow("add".to_string()).is_debug_only());
assert!(PanicCause::ShiftOverflow("left".to_string()).is_debug_only());
assert!(!PanicCause::AssertFailed.is_debug_only());
assert!(!PanicCause::BoundsCheck.is_debug_only());
assert!(!PanicCause::DivisionByZero.is_debug_only());
assert!(!PanicCause::UnwrapNone.is_debug_only());
}
#[test]
fn test_panic_cause_release_warning() {
assert!(
PanicCause::ArithmeticOverflow("add".to_string())
.release_warning()
.is_some()
);
assert!(
PanicCause::ShiftOverflow("left".to_string())
.release_warning()
.is_some()
);
assert!(PanicCause::AssertFailed.release_warning().is_none());
assert!(PanicCause::BoundsCheck.release_warning().is_none());
assert!(PanicCause::UnwrapNone.release_warning().is_none());
}
#[test]
fn test_panic_cause_suggestion_direct() {
let suggestion = PanicCause::UnwrapNone.suggestion(true);
assert!(suggestion.contains("if let") || suggestion.contains("match"));
}
#[test]
fn test_panic_cause_suggestion_indirect() {
let suggestion = PanicCause::UnwrapNone.suggestion(false);
assert!(suggestion.contains("calls a function"));
}
#[test]
fn test_panic_cause_format_suggestion_with_function() {
let suggestion = PanicCause::UnwrapNone.format_suggestion(false, Some("parse_config"));
assert!(suggestion.contains("parse_config"));
}
#[test]
fn test_panic_cause_format_suggestion_direct() {
let suggestion = PanicCause::UnwrapNone.format_suggestion(true, Some("ignored"));
assert!(!suggestion.contains("ignored"));
}
#[test]
fn test_all_ids_contains_expected() {
let ids = PanicCause::all_ids();
assert!(ids.contains(&"panic"));
assert!(ids.contains(&"bounds"));
assert!(ids.contains(&"overflow"));
assert!(ids.contains(&"div_overflow"));
assert!(ids.contains(&"rem_overflow"));
assert!(ids.contains(&"unwrap"));
assert!(ids.contains(&"expect"));
}
#[test]
fn test_all_panic_cause_descriptions() {
let variants = vec![
PanicCause::ExplicitPanic,
PanicCause::BoundsCheck,
PanicCause::ArithmeticOverflow("add".to_string()),
PanicCause::ShiftOverflow("left".to_string()),
PanicCause::DivisionByZero,
PanicCause::UnwrapNone,
PanicCause::UnwrapErr,
PanicCause::ExpectNone,
PanicCause::ExpectErr,
PanicCause::AssertFailed,
PanicCause::Unreachable,
PanicCause::Unimplemented,
PanicCause::Todo,
PanicCause::PanicInDrop,
PanicCause::CannotUnwind,
PanicCause::FormattingError,
PanicCause::CapacityOverflow,
PanicCause::OutOfMemory,
PanicCause::StringSliceError,
PanicCause::InvalidEnum,
PanicCause::MisalignedPointer,
PanicCause::Unknown,
];
for variant in &variants {
assert!(
!variant.description().is_empty(),
"{:?} has empty description",
variant
);
assert!(
!variant.error_code().is_empty(),
"{:?} has empty error code",
variant
);
assert!(
!variant.suggestion(true).is_empty(),
"{:?} has empty direct suggestion",
variant
);
assert!(
!variant.suggestion(false).is_empty(),
"{:?} has empty indirect suggestion",
variant
);
}
}
#[test]
fn test_direct_suggestions() {
assert!(
PanicCause::ExplicitPanic
.direct_suggestion()
.contains("Review")
);
assert!(
PanicCause::BoundsCheck
.direct_suggestion()
.contains(".get()")
);
assert!(
PanicCause::ArithmeticOverflow("add".to_string())
.direct_suggestion()
.contains("checked_")
);
assert!(
PanicCause::ShiftOverflow("left".to_string())
.direct_suggestion()
.contains("Validate")
);
assert!(
PanicCause::DivisionByZero
.direct_suggestion()
.contains("divisor")
);
assert!(
PanicCause::AssertFailed
.direct_suggestion()
.contains("assertion")
);
assert!(
PanicCause::Unreachable
.direct_suggestion()
.contains("unreachable")
);
assert!(
PanicCause::Unimplemented
.direct_suggestion()
.contains("Implement")
);
assert!(PanicCause::Todo.direct_suggestion().contains("TODO"));
assert!(PanicCause::PanicInDrop.direct_suggestion().contains("Drop"));
assert!(
PanicCause::CannotUnwind
.direct_suggestion()
.contains("extern")
);
assert!(
PanicCause::FormattingError
.direct_suggestion()
.contains("Display")
);
assert!(
PanicCause::CapacityOverflow
.direct_suggestion()
.contains("try_reserve")
);
assert!(
PanicCause::OutOfMemory
.direct_suggestion()
.contains("allocation")
);
assert!(
PanicCause::StringSliceError
.direct_suggestion()
.contains("str::get()")
);
assert!(PanicCause::InvalidEnum.direct_suggestion().contains("enum"));
assert!(
PanicCause::MisalignedPointer
.direct_suggestion()
.contains("alignment")
);
assert!(PanicCause::Unknown.direct_suggestion().contains("--tree"));
}
#[test]
fn test_indirect_suggestions() {
assert!(
PanicCause::ExplicitPanic
.indirect_suggestion()
.contains("calls a function")
);
assert!(
PanicCause::BoundsCheck
.indirect_suggestion()
.contains("bounds check")
);
assert!(
PanicCause::ArithmeticOverflow("add".to_string())
.indirect_suggestion()
.contains("overflow")
);
assert!(
PanicCause::ShiftOverflow("left".to_string())
.indirect_suggestion()
.contains("shift")
);
assert!(
PanicCause::DivisionByZero
.indirect_suggestion()
.contains("divide by zero")
);
assert!(
PanicCause::UnwrapNone
.indirect_suggestion()
.contains("unwrap()")
);
assert!(
PanicCause::UnwrapErr
.indirect_suggestion()
.contains("unwrap()")
);
assert!(
PanicCause::ExpectNone
.indirect_suggestion()
.contains("expect()")
);
assert!(
PanicCause::ExpectErr
.indirect_suggestion()
.contains("expect()")
);
assert!(
PanicCause::AssertFailed
.indirect_suggestion()
.contains("assertion")
);
assert!(
PanicCause::Unreachable
.indirect_suggestion()
.contains("unreachable")
);
assert!(
PanicCause::Unimplemented
.indirect_suggestion()
.contains("unimplemented!()")
);
assert!(PanicCause::Todo.indirect_suggestion().contains("todo!()"));
assert!(
PanicCause::PanicInDrop
.indirect_suggestion()
.contains("drop")
);
assert!(
PanicCause::CannotUnwind
.indirect_suggestion()
.contains("no-unwind")
);
assert!(
PanicCause::FormattingError
.indirect_suggestion()
.contains("formatting")
);
assert!(
PanicCause::CapacityOverflow
.indirect_suggestion()
.contains("capacity")
);
assert!(
PanicCause::OutOfMemory
.indirect_suggestion()
.contains("allocate")
);
assert!(
PanicCause::StringSliceError
.indirect_suggestion()
.contains("string/slice")
);
assert!(
PanicCause::InvalidEnum
.indirect_suggestion()
.contains("enum")
);
assert!(
PanicCause::MisalignedPointer
.indirect_suggestion()
.contains("misaligned")
);
assert!(PanicCause::Unknown.indirect_suggestion().contains("--tree"));
}
#[test]
fn test_format_suggestion_all_variants() {
let variants = vec![
PanicCause::ExplicitPanic,
PanicCause::BoundsCheck,
PanicCause::ArithmeticOverflow("add".to_string()),
PanicCause::ShiftOverflow("left".to_string()),
PanicCause::DivisionByZero,
PanicCause::UnwrapNone,
PanicCause::UnwrapErr,
PanicCause::ExpectNone,
PanicCause::ExpectErr,
PanicCause::AssertFailed,
PanicCause::Unreachable,
PanicCause::Unimplemented,
PanicCause::Todo,
PanicCause::PanicInDrop,
PanicCause::CannotUnwind,
PanicCause::FormattingError,
PanicCause::CapacityOverflow,
PanicCause::OutOfMemory,
PanicCause::StringSliceError,
PanicCause::InvalidEnum,
PanicCause::MisalignedPointer,
PanicCause::Unknown,
];
for variant in &variants {
let with_func = variant.format_suggestion(false, Some("test_func"));
assert!(
with_func.contains("test_func"),
"{:?} format_suggestion doesn't include function name: {}",
variant,
with_func
);
}
}
#[test]
fn test_all_docs_slugs() {
assert_eq!(PanicCause::BoundsCheck.docs_slug(), "JP002-bounds-check");
assert_eq!(
PanicCause::ArithmeticOverflow("add".to_string()).docs_slug(),
"JP003-arithmetic-overflow"
);
assert_eq!(
PanicCause::ShiftOverflow("left".to_string()).docs_slug(),
"JP004-shift-overflow"
);
assert_eq!(
PanicCause::DivisionByZero.docs_slug(),
"JP005-division-by-zero"
);
assert_eq!(PanicCause::ExpectNone.docs_slug(), "JP008-expect-none");
assert_eq!(PanicCause::ExpectErr.docs_slug(), "JP009-expect-err");
assert_eq!(PanicCause::AssertFailed.docs_slug(), "JP010-assert-failed");
assert_eq!(PanicCause::Unreachable.docs_slug(), "JP012-unreachable");
assert_eq!(PanicCause::Unimplemented.docs_slug(), "JP013-unimplemented");
assert_eq!(PanicCause::Todo.docs_slug(), "JP014-todo");
assert_eq!(PanicCause::PanicInDrop.docs_slug(), "JP015-panic-in-drop");
assert_eq!(PanicCause::CannotUnwind.docs_slug(), "JP016-cannot-unwind");
assert_eq!(
PanicCause::FormattingError.docs_slug(),
"JP017-formatting-error"
);
assert_eq!(
PanicCause::CapacityOverflow.docs_slug(),
"JP018-capacity-overflow"
);
assert_eq!(PanicCause::OutOfMemory.docs_slug(), "JP019-out-of-memory");
assert_eq!(
PanicCause::StringSliceError.docs_slug(),
"JP020-string-slice-error"
);
assert_eq!(PanicCause::InvalidEnum.docs_slug(), "JP021-invalid-enum");
assert_eq!(
PanicCause::MisalignedPointer.docs_slug(),
"JP022-misaligned-pointer"
);
}
}