1 /* 2 * Software License Agreement (BSD License) 3 * 4 * Copyright (c) 2018. Toyota Research Institute 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 * * Neither the name of Open Source Robotics Foundation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 // This code was taken from Drake. 36 // https://github.com/RobotLocomotion/drake/blob/master/common/test_utilities/expect_throws_message.h 37 38 #ifndef FCL_EXPECT_THROWS_MESSAGE_H 39 #define FCL_EXPECT_THROWS_MESSAGE_H 40 41 #include <regex> 42 #include <string> 43 44 #ifdef FCL_DOXYGEN_CXX 45 46 /** Unit test helper macro for "expecting" an exception to be thrown but also 47 testing the error message against a provided regular expression. This is 48 like GTest's `EXPECT_THROW` but is fussier about the particular error message. 49 Usage example: @code 50 FCL_EXPECT_THROWS_MESSAGE( 51 StatementUnderTest(), // You expect this statement to throw ... 52 std::logic_error, // ... this exception with ... 53 ".*some important.*phrases.*that must appear.*"); // ... this message. 54 @endcode 55 The regular expression must match the entire error message. If there is 56 boilerplate you don't care to match at the beginning and end, surround with 57 `.*` to ignore. 58 59 Following GTest's conventions, failure to perform as expected here is a 60 non-fatal test error. An `ASSERT` variant is provided to make it fatal. There 61 are also `*_IF_ARMED` variants. These require an exception in Debug builds. In 62 Release builds, the expression will pass if it _doesn't_ throw or if it throws 63 an exception that would pass the same test as in Debug builds. There is no 64 mechanism for testing _exclusive_ throwing behavior (i.e., only throws in 65 Debug). 66 @see FCL_ASSERT_THROWS_MESSAGE 67 @see FCL_EXPECT_THROWS_MESSAGE_IF_ARMED, FCL_ASSERT_THROWS_MESSAGE_IF_ARMED */ 68 #define FCL_EXPECT_THROWS_MESSAGE(expression, exception, regexp) 69 70 /** Fatal error version of `FCL_EXPECT_THROWS_MESSAGE`. 71 @see FCL_EXPECT_THROWS_MESSAGE */ 72 #define FCL_ASSERT_THROWS_MESSAGE(expression, exception, regexp) 73 74 /** Same as `FCL_EXPECT_THROWS_MESSAGE` in Debug builds, but doesn't require 75 a throw in Release builds. However, if the Release build does throw it must 76 throw the right message. More precisely, the thrown message is required 77 whenever `FCL_ENABLE_ASSERTS` is defined, which Debug builds do by default. 78 @see FCL_EXPECT_THROWS_MESSAGE */ 79 #define FCL_EXPECT_THROWS_MESSAGE_IF_ARMED(expression, exception, regexp) 80 81 /** Same as `FCL_ASSERT_THROWS_MESSAGE` in Debug builds, but doesn't require 82 a throw in Release builds. However, if the Release build does throw it must 83 throw the right message. More precisely, the thrown message is required 84 whenever `FCL_ENABLE_ASSERTS` is defined, which Debug builds do by default. 85 @see FCL_ASSERT_THROWS_MESSAGE */ 86 #define FCL_ASSERT_THROWS_MESSAGE_IF_ARMED(expression, exception, regexp) 87 88 #else // FCL_DOXYGEN_CXX 89 90 #define FCL_EXPECT_THROWS_MESSAGE_HELPER(expression, exception, regexp, \ 91 must_throw, fatal_failure) \ 92 try { \ 93 expression; \ 94 if (must_throw) { \ 95 if (fatal_failure) { \ 96 GTEST_FATAL_FAILURE_("\t" #expression " failed to throw " #exception); \ 97 } else { \ 98 GTEST_NONFATAL_FAILURE_("\t" #expression " failed to throw " #exception);\ 99 } \ 100 } \ 101 } catch (const exception& err) { \ 102 auto matcher = [](const char* s, const std::string& re) { \ 103 return std::regex_match(s, std::regex(re)); }; \ 104 if (fatal_failure) { \ 105 ASSERT_PRED2(matcher, err.what(), regexp); \ 106 } else { \ 107 EXPECT_PRED2(matcher, err.what(), regexp); \ 108 } \ 109 } 110 111 #define FCL_EXPECT_THROWS_MESSAGE(expression, exception, regexp) \ 112 FCL_EXPECT_THROWS_MESSAGE_HELPER(expression, exception, regexp, \ 113 true /*must_throw*/, false /*non-fatal*/) 114 115 #define FCL_ASSERT_THROWS_MESSAGE(expression, exception, regexp) \ 116 FCL_EXPECT_THROWS_MESSAGE_HELPER(expression, exception, regexp, \ 117 true /*must_throw*/, true /*fatal*/) 118 119 #ifdef NDEBUG 120 // Throwing the expected message is optional in this case. 121 122 #define FCL_EXPECT_THROWS_MESSAGE_IF_DEBUG(expression, exception, regexp) \ 123 FCL_EXPECT_THROWS_MESSAGE_HELPER(expression, exception, regexp, \ 124 false /*optional*/, false /*non-fatal*/) 125 126 #define FCL_ASSERT_THROWS_MESSAGE_IF_DEBUG(expression, exception, regexp) \ 127 FCL_EXPECT_THROWS_MESSAGE_HELPER(expression, exception, regexp, \ 128 false /*optional*/, true /*fatal*/) 129 130 #else // NDEBUG 131 // Throwing the expected message is required in this case. 132 133 #define FCL_EXPECT_THROWS_MESSAGE_IF_DEBUG(expression, exception, regexp) \ 134 FCL_EXPECT_THROWS_MESSAGE(expression, exception, regexp) 135 136 #define FCL_ASSERT_THROWS_MESSAGE_IF_DEBUG(expression, exception, regexp) \ 137 FCL_ASSERT_THROWS_MESSAGE(expression, exception, regexp) 138 139 #endif // NDEBUG 140 141 #endif // FCL_DOXYGEN_CXX 142 143 #endif // FCL_EXPECT_THROWS_MESSAGE_H 144