File: expect_throws_message.h

package info (click to toggle)
fcl 0.7.0-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 28,724 kB
  • sloc: xml: 188,729; cpp: 55,417; ansic: 22,921; sh: 41; makefile: 23
file content (143 lines) | stat: -rw-r--r-- 6,333 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2018. Toyota Research Institute
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Open Source Robotics Foundation nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

// This code was taken from Drake.
// https://github.com/RobotLocomotion/drake/blob/master/common/test_utilities/expect_throws_message.h

#ifndef FCL_EXPECT_THROWS_MESSAGE_H
#define FCL_EXPECT_THROWS_MESSAGE_H

#include <regex>
#include <string>

#ifdef FCL_DOXYGEN_CXX

/** Unit test helper macro for "expecting" an exception to be thrown but also
testing the error message against a provided regular expression. This is
like GTest's `EXPECT_THROW` but is fussier about the particular error message.
Usage example: @code
  FCL_EXPECT_THROWS_MESSAGE(
      StatementUnderTest(), // You expect this statement to throw ...
      std::logic_error,     // ... this exception with ...
      ".*some important.*phrases.*that must appear.*");  // ... this message.
@endcode
The regular expression must match the entire error message. If there is
boilerplate you don't care to match at the beginning and end, surround with
`.*` to ignore.

Following GTest's conventions, failure to perform as expected here is a
non-fatal test error. An `ASSERT` variant is provided to make it fatal. There
are also `*_IF_ARMED` variants. These require an exception in Debug builds. In
Release builds, the expression will pass if it _doesn't_ throw or if it throws
an exception that would pass the same test as in Debug builds. There is no
mechanism for testing _exclusive_ throwing behavior (i.e., only throws in
Debug).
@see FCL_ASSERT_THROWS_MESSAGE
@see FCL_EXPECT_THROWS_MESSAGE_IF_ARMED, FCL_ASSERT_THROWS_MESSAGE_IF_ARMED */
#define FCL_EXPECT_THROWS_MESSAGE(expression, exception, regexp)

/** Fatal error version of `FCL_EXPECT_THROWS_MESSAGE`.
@see FCL_EXPECT_THROWS_MESSAGE */
#define FCL_ASSERT_THROWS_MESSAGE(expression, exception, regexp)

/** Same as `FCL_EXPECT_THROWS_MESSAGE` in Debug builds, but doesn't require
a throw in Release builds. However, if the Release build does throw it must
throw the right message. More precisely, the thrown message is required
whenever `FCL_ENABLE_ASSERTS` is defined, which Debug builds do by default.
@see FCL_EXPECT_THROWS_MESSAGE */
#define FCL_EXPECT_THROWS_MESSAGE_IF_ARMED(expression, exception, regexp)

/** Same as `FCL_ASSERT_THROWS_MESSAGE` in Debug builds, but doesn't require
a throw in Release builds. However, if the Release build does throw it must
throw the right message. More precisely, the thrown message is required
whenever `FCL_ENABLE_ASSERTS` is defined, which Debug builds do by default.
@see FCL_ASSERT_THROWS_MESSAGE */
#define FCL_ASSERT_THROWS_MESSAGE_IF_ARMED(expression, exception, regexp)

#else  // FCL_DOXYGEN_CXX

#define FCL_EXPECT_THROWS_MESSAGE_HELPER(expression, exception, regexp, \
                                         must_throw, fatal_failure) \
try { \
  expression; \
  if (must_throw) { \
    if (fatal_failure) { \
      GTEST_FATAL_FAILURE_("\t" #expression " failed to throw " #exception); \
    } else { \
      GTEST_NONFATAL_FAILURE_("\t" #expression " failed to throw " #exception);\
    } \
  } \
} catch (const exception& err) { \
  auto matcher = [](const char* s, const std::string& re) { \
    return std::regex_match(s, std::regex(re)); }; \
  if (fatal_failure) { \
    ASSERT_PRED2(matcher, err.what(), regexp); \
  } else { \
    EXPECT_PRED2(matcher, err.what(), regexp); \
  } \
}

#define FCL_EXPECT_THROWS_MESSAGE(expression, exception, regexp) \
  FCL_EXPECT_THROWS_MESSAGE_HELPER(expression, exception, regexp, \
                                     true /*must_throw*/, false /*non-fatal*/)

#define FCL_ASSERT_THROWS_MESSAGE(expression, exception, regexp) \
  FCL_EXPECT_THROWS_MESSAGE_HELPER(expression, exception, regexp, \
                                   true /*must_throw*/, true /*fatal*/)

#ifdef NDEBUG
// Throwing the expected message is optional in this case.

#define FCL_EXPECT_THROWS_MESSAGE_IF_DEBUG(expression, exception, regexp) \
  FCL_EXPECT_THROWS_MESSAGE_HELPER(expression, exception, regexp, \
                                   false /*optional*/, false /*non-fatal*/)

#define FCL_ASSERT_THROWS_MESSAGE_IF_DEBUG(expression, exception, regexp) \
  FCL_EXPECT_THROWS_MESSAGE_HELPER(expression, exception, regexp, \
                                   false /*optional*/, true /*fatal*/)

#else  // NDEBUG
// Throwing the expected message is required in this case.

#define FCL_EXPECT_THROWS_MESSAGE_IF_DEBUG(expression, exception, regexp) \
  FCL_EXPECT_THROWS_MESSAGE(expression, exception, regexp)

#define FCL_ASSERT_THROWS_MESSAGE_IF_DEBUG(expression, exception, regexp) \
  FCL_ASSERT_THROWS_MESSAGE(expression, exception, regexp)

#endif  // NDEBUG

#endif  // FCL_DOXYGEN_CXX

#endif  // FCL_EXPECT_THROWS_MESSAGE_H