@@ -3,6 +3,8 @@ use colored::Colorize;
3
3
use std:: sync:: { Arc , Mutex } ;
4
4
use test_rpc:: logging:: { LogOutput , Output } ;
5
5
6
+ use crate :: summary;
7
+
6
8
/// Logger that optionally supports logging records to a buffer
7
9
#[ derive( Clone ) ]
8
10
pub struct Logger {
@@ -109,25 +111,94 @@ impl log::Log for Logger {
109
111
fn flush ( & self ) { }
110
112
}
111
113
114
+ /// Encapsulate caught unwound panics, such that we can catch tests that panic and differentiate
115
+ /// them from tests that just fail.
112
116
#[ derive( Debug , thiserror:: Error ) ]
113
- #[ error( "Test panic: {0}" ) ]
114
- pub struct PanicMessage ( String ) ;
117
+ #[ error( "Test panic: {}" , self . as_string( ) ) ]
118
+ pub struct Panic ( Box < dyn std:: any:: Any + Send + ' static > ) ;
119
+
120
+ impl Panic {
121
+ /// Create a new [`Panic`] from a caught unwound panic.
122
+ pub fn new ( result : Box < dyn std:: any:: Any + Send + ' static > ) -> Self {
123
+ Self ( result)
124
+ }
125
+
126
+ /// Convert this panic to a [`String`] representation.
127
+ pub fn as_string ( & self ) -> String {
128
+ if let Some ( result) = self . 0 . downcast_ref :: < String > ( ) {
129
+ return result. clone ( ) ;
130
+ }
131
+ match self . 0 . downcast_ref :: < & str > ( ) {
132
+ Some ( s) => String :: from ( * s) ,
133
+ None => String :: from ( "unknown message" ) ,
134
+ }
135
+ }
136
+ }
115
137
116
138
pub struct TestOutput {
117
139
pub error_messages : Vec < Output > ,
118
140
pub test_name : & ' static str ,
119
- pub result : Result < Result < ( ) , Error > , PanicMessage > ,
141
+ pub result : TestResult ,
120
142
pub log_output : Option < LogOutput > ,
121
143
}
122
144
145
+ // Convert this unwieldy return type to a workable `TestResult`.
146
+ // What we are converting from is the acutal return type of the test execution.
147
+ impl From < Result < Result < ( ) , Error > , Panic > > for TestResult {
148
+ fn from ( value : Result < Result < ( ) , Error > , Panic > ) -> Self {
149
+ match value {
150
+ Ok ( Ok ( ( ) ) ) => TestResult :: Pass ,
151
+ Ok ( Err ( e) ) => TestResult :: Fail ( e) ,
152
+ Err ( e) => TestResult :: Panic ( e) ,
153
+ }
154
+ }
155
+ }
156
+
157
+ /// Result from a test execution. This may carry information in case the test failed during
158
+ /// execution.
159
+ pub enum TestResult {
160
+ /// Test passed.
161
+ Pass ,
162
+ /// Test failed during execution. Contains the source error which caused the test to fail.
163
+ Fail ( Error ) ,
164
+ /// Test panicked during execution. Contains the caught unwound panic.
165
+ Panic ( Panic ) ,
166
+ }
167
+
168
+ impl TestResult {
169
+ /// Returns `true` if test failed or panicked, i.e. when `TestResult` is `Fail` or `Panic`.
170
+ pub const fn failure ( & self ) -> bool {
171
+ matches ! ( self , TestResult :: Fail ( _) | TestResult :: Panic ( _) )
172
+ }
173
+
174
+ /// Convert `self` to a [`summary::TestResult`], which is used for creating fancy exports of
175
+ /// the results for a test run.
176
+ pub const fn summary ( & self ) -> summary:: TestResult {
177
+ match self {
178
+ TestResult :: Pass => summary:: TestResult :: Pass ,
179
+ TestResult :: Fail ( _) | TestResult :: Panic ( _) => summary:: TestResult :: Fail ,
180
+ }
181
+ }
182
+
183
+ /// Consume `self` and convert into a [`Result`] where [`TestResult::Pass`] is mapped to [`Ok`]
184
+ /// while [`TestResult::Fail`] & [`TestResult::Panic`] is mapped to [`Err`].
185
+ pub fn anyhow ( self ) -> anyhow:: Result < ( ) > {
186
+ match self {
187
+ TestResult :: Pass => Ok ( ( ) ) ,
188
+ TestResult :: Fail ( error) => anyhow:: bail!( error) ,
189
+ TestResult :: Panic ( error) => anyhow:: bail!( error. to_string( ) ) ,
190
+ }
191
+ }
192
+ }
193
+
123
194
impl TestOutput {
124
195
pub fn print ( & self ) {
125
196
match & self . result {
126
- Ok ( Ok ( _ ) ) => {
197
+ TestResult :: Pass => {
127
198
println ! ( "{}" , format!( "TEST {} SUCCEEDED!" , self . test_name) . green( ) ) ;
128
199
return ;
129
200
}
130
- Ok ( Err ( e ) ) => {
201
+ TestResult :: Fail ( e ) => {
131
202
println ! (
132
203
"{}" ,
133
204
format!(
@@ -138,13 +209,13 @@ impl TestOutput {
138
209
. red( )
139
210
) ;
140
211
}
141
- Err ( panic_msg) => {
212
+ TestResult :: Panic ( panic_msg) => {
142
213
println ! (
143
214
"{}" ,
144
215
format!(
145
216
"TEST {} PANICKED WITH MESSAGE: {}" ,
146
217
self . test_name,
147
- panic_msg. 0 . bold( )
218
+ panic_msg. as_string ( ) . bold( )
148
219
)
149
220
. red( )
150
221
) ;
@@ -191,13 +262,3 @@ impl TestOutput {
191
262
println ! ( "{}" , format!( "TEST {} END OF OUTPUT" , self . test_name) . red( ) ) ;
192
263
}
193
264
}
194
-
195
- pub fn panic_as_string ( error : Box < dyn std:: any:: Any + Send + ' static > ) -> PanicMessage {
196
- if let Some ( result) = error. downcast_ref :: < String > ( ) {
197
- return PanicMessage ( result. clone ( ) ) ;
198
- }
199
- match error. downcast_ref :: < & str > ( ) {
200
- Some ( s) => PanicMessage ( String :: from ( * s) ) ,
201
- None => PanicMessage ( String :: from ( "unknown message" ) ) ,
202
- }
203
- }
0 commit comments