@@ -40,6 +40,32 @@ use syn::{parse_macro_input, Attribute, ItemFn, ReturnType};
4040/// }
4141/// ```
4242///
43+ /// This macro can be used with `#[should_panic]` to indicate that the test is
44+ /// expected to panic. For example:
45+ ///
46+ /// ```ignore
47+ /// #[googletest::test]
48+ /// #[should_panic]
49+ /// fn passes_due_to_should_panic() {
50+ /// let value = 2;
51+ /// expect_that!(value, gt(0));
52+ /// panic!("This panics");
53+ /// }
54+ /// ```
55+ ///
56+ /// Using `#[should_panic]` modifies the behaviour of `#[googletest::test]` so
57+ /// that the test panics (and passes) if any non-fatal assertion occurs.
58+ /// For example, the following test passes:
59+ ///
60+ /// ```ignore
61+ /// #[googletest::test]
62+ /// #[should_panic]
63+ /// fn passes_due_to_should_panic_and_failing_assertion() {
64+ /// let value = 2;
65+ /// expect_that!(value, eq(0));
66+ /// }
67+ /// ```
68+ ///
4369/// [`googletest::Result`]: type.Result.html
4470#[ proc_macro_attribute]
4571pub fn test (
@@ -49,6 +75,15 @@ pub fn test(
4975 let mut parsed_fn = parse_macro_input ! ( input as ItemFn ) ;
5076 let attrs = parsed_fn. attrs . drain ( ..) . collect :: < Vec < _ > > ( ) ;
5177 let ( mut sig, block) = ( parsed_fn. sig , parsed_fn. block ) ;
78+ let ( outer_return_type, trailer) =
79+ if attrs. iter ( ) . any ( |attr| attr. path ( ) . is_ident ( "should_panic" ) ) {
80+ ( quote ! { ( ) } , quote ! { . unwrap( ) ; } )
81+ } else {
82+ (
83+ quote ! { std:: result:: Result <( ) , googletest:: internal:: test_outcome:: TestFailure > } ,
84+ quote ! { } ,
85+ )
86+ } ;
5287 let output_type = match sig. output . clone ( ) {
5388 ReturnType :: Type ( _, output_type) => Some ( output_type) ,
5489 ReturnType :: Default => None ,
@@ -81,23 +116,25 @@ pub fn test(
81116 let function = if let Some ( output_type) = output_type {
82117 quote ! {
83118 #( #attrs) *
84- #sig -> std :: result :: Result < ( ) , googletest :: internal :: test_outcome :: TestFailure > {
119+ #sig -> #outer_return_type {
85120 #maybe_closure
86121 use googletest:: internal:: test_outcome:: TestOutcome ;
87122 TestOutcome :: init_current_test_outcome( ) ;
88123 let result: #output_type = #invocation;
89124 TestOutcome :: close_current_test_outcome( result)
125+ #trailer
90126 }
91127 }
92128 } else {
93129 quote ! {
94130 #( #attrs) *
95- #sig -> std :: result :: Result < ( ) , googletest :: internal :: test_outcome :: TestFailure > {
131+ #sig -> #outer_return_type {
96132 #maybe_closure
97133 use googletest:: internal:: test_outcome:: TestOutcome ;
98134 TestOutcome :: init_current_test_outcome( ) ;
99135 #invocation;
100136 TestOutcome :: close_current_test_outcome( googletest:: Result :: Ok ( ( ) ) )
137+ #trailer
101138 }
102139 }
103140 } ;
0 commit comments