1+ use std:: backtrace:: BacktraceStatus ;
12use std:: ops:: Deref ;
2- use std:: panic:: UnwindSafe ;
3+ use std:: panic:: { self , UnwindSafe } ;
4+ use std:: sync:: Once ;
35
46use libtest_mimic:: Failed ;
57
68use html5gum:: testutils:: OUTPUT ;
79
10+ /// Improved panic messages for the html5lib-tests test suite.
11+ ///
12+ /// This function catches panics, prepends the log message to the panic message, and captures
13+ /// stacktraces.
14+ ///
15+ /// libtest_mimic already catches panics but doesn't provide stacktraces for some reason.
16+ ///
17+ /// Because custom test harnesses in Rust do not support capturing of stdout, we have to implement
18+ /// our own "log buffer", and append it to the error message in case of test failure. OUTPUT is the
19+ /// log buffer -- it is bound in size and compiled out in release mode. Code can use the
20+ /// `crate::trace_log` macro to write lines to it.
821pub fn catch_unwind_and_report ( f : impl FnOnce ( ) + UnwindSafe ) -> Result < ( ) , Failed > {
22+ static PANIC_HOOK : Once = Once :: new ( ) ;
23+ PANIC_HOOK . call_once ( || {
24+ panic:: set_hook ( Box :: new ( |_info| {
25+ let backtrace = std:: backtrace:: Backtrace :: capture ( ) ;
26+ if backtrace. status ( ) != BacktraceStatus :: Captured {
27+ html5gum:: testutils:: trace_log (
28+ "PANIC BACKTRACE: did not capture, use RUST_BACKTRACE=1" ,
29+ ) ;
30+ } else {
31+ // clean up noisy frames from backtrace
32+ let mut backtrace_str = String :: new ( ) ;
33+ let mut seen_begin_unwind = false ;
34+ for line in format ! ( "{:#?}" , backtrace) . lines ( ) {
35+ if line. contains ( "\" std::panicking::try::do_call\" " ) {
36+ break ;
37+ } else if seen_begin_unwind {
38+ backtrace_str. push_str ( line) ;
39+ backtrace_str. push ( '\n' ) ;
40+ } else if line. contains ( "\" core::panicking::panic_fmt\" " ) {
41+ seen_begin_unwind = true ;
42+ }
43+ }
44+ html5gum:: testutils:: trace_log ( & format ! ( "\n PANIC BACKTRACE:\n {}" , backtrace_str) ) ;
45+ }
46+ } ) ) ;
47+ } ) ;
48+
949 let result = std:: panic:: catch_unwind ( f) ;
1050
1151 let mut msg = String :: new ( ) ;
@@ -28,6 +68,7 @@ pub fn catch_unwind_and_report(f: impl FnOnce() + UnwindSafe) -> Result<(), Fail
2868 // If that fails, try to turn it into a &'static str
2969 . or_else ( || e. downcast_ref :: < & ' static str > ( ) . map ( Deref :: deref) )
3070 {
71+ msg. push_str ( "PANIC: " ) ;
3172 msg. push_str ( s) ;
3273 }
3374
0 commit comments