1 /*
2 * Created by Phil on 09/11/2010.
3 * Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
4 *
5 * Distributed under the Boost Software License, Version 1.0. (See accompanying
6 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 */
8
9 #include "catch.hpp"
10
11 #include <string>
12 #include <stdexcept>
13
14 #ifdef _MSC_VER
15 #pragma warning(disable:4702) // Unreachable code -- unconditional throws and so on
16 #endif
17 #ifdef __clang__
18 #pragma clang diagnostic push
19 #pragma clang diagnostic ignored "-Wweak-vtables"
20 #pragma clang diagnostic ignored "-Wmissing-noreturn"
21 #pragma clang diagnostic ignored "-Wunreachable-code"
22 #endif
23
24 #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
25 // Cannot use try/catch keywords with -fno-exceptions.
26 // Even if an exception was to be "thrown" it would just call std::terminate instead.
27
28 namespace { namespace ExceptionTests {
29
30 #ifndef EXCEPTION_TEST_HELPERS_INCLUDED // Don't compile this more than once per TU
31 #define EXCEPTION_TEST_HELPERS_INCLUDED
32
thisThrows()33 int thisThrows() {
34 throw std::domain_error( "expected exception" );
35 return 1;
36 }
37
thisDoesntThrow()38 int thisDoesntThrow() {
39 return 0;
40 }
41
42 class CustomException {
43 public:
CustomException(const std::string & msg)44 explicit CustomException( const std::string& msg )
45 : m_msg( msg )
46 {}
47
getMessage() const48 std::string getMessage() const {
49 return m_msg;
50 }
51
52 private:
53 std::string m_msg;
54 };
55
56 class CustomStdException : public std::exception {
57 public:
CustomStdException(const std::string & msg)58 explicit CustomStdException( const std::string& msg )
59 : m_msg( msg )
60 {}
~CustomStdException()61 ~CustomStdException() noexcept override {}
62
getMessage() const63 std::string getMessage() const {
64 return m_msg;
65 }
66
67 private:
68 std::string m_msg;
69 };
70
throwCustom()71 [[noreturn]] void throwCustom() {
72 throw CustomException( "custom exception - not std" );
73 }
74
75 #endif
76
77 TEST_CASE( "When checked exceptions are thrown they can be expected or unexpected", "[!throws]" ) {
78 REQUIRE_THROWS_AS( thisThrows(), std::domain_error );
79 REQUIRE_NOTHROW( thisDoesntThrow() );
80 REQUIRE_THROWS( thisThrows() );
81 }
82
83 TEST_CASE( "Expected exceptions that don't throw or unexpected exceptions fail the test", "[.][failing][!throws]" ) {
84 CHECK_THROWS_AS( thisThrows(), std::string );
85 CHECK_THROWS_AS( thisDoesntThrow(), std::domain_error );
86 CHECK_NOTHROW( thisThrows() );
87 }
88
89 TEST_CASE( "When unchecked exceptions are thrown directly they are always failures", "[.][failing][!throws]" ) {
90 throw std::domain_error( "unexpected exception" );
91 }
92
93 TEST_CASE( "An unchecked exception reports the line of the last assertion", "[.][failing][!throws]" ) {
94 CHECK( 1 == 1 );
95 throw std::domain_error( "unexpected exception" );
96 }
97
98 TEST_CASE( "When unchecked exceptions are thrown from sections they are always failures", "[.][failing][!throws]" ) {
99 SECTION( "section name" ) {
100 throw std::domain_error("unexpected exception");
101 }
102 }
103
104 TEST_CASE( "When unchecked exceptions are thrown from functions they are always failures", "[.][failing][!throws]" ) {
105 CHECK( thisThrows() == 0 );
106 }
107
108 TEST_CASE( "When unchecked exceptions are thrown during a REQUIRE the test should abort fail", "[.][failing][!throws]" ) {
109 REQUIRE( thisThrows() == 0 );
110 FAIL( "This should never happen" );
111 }
112
113 TEST_CASE( "When unchecked exceptions are thrown during a CHECK the test should continue", "[.][failing][!throws]" ) {
114 try {
115 CHECK(thisThrows() == 0);
116 }
117 catch(...) {
118 FAIL( "This should never happen" );
119 }
120 }
121
122 TEST_CASE( "When unchecked exceptions are thrown, but caught, they do not affect the test", "[!throws]" ) {
123 try {
124 throw std::domain_error( "unexpected exception" );
125 }
126 catch(...) {}
127 }
128
129
CATCH_TRANSLATE_EXCEPTION(CustomException & ex)130 CATCH_TRANSLATE_EXCEPTION( CustomException& ex ) {
131 return ex.getMessage();
132 }
133
CATCH_TRANSLATE_EXCEPTION(CustomStdException & ex)134 CATCH_TRANSLATE_EXCEPTION( CustomStdException& ex ) {
135 return ex.getMessage();
136 }
137
CATCH_TRANSLATE_EXCEPTION(double & ex)138 CATCH_TRANSLATE_EXCEPTION( double& ex ) {
139 return Catch::Detail::stringify( ex );
140 }
141
142 TEST_CASE("Non-std exceptions can be translated", "[.][failing][!throws]" ) {
143 throw CustomException( "custom exception" );
144 }
145
146 TEST_CASE("Custom std-exceptions can be custom translated", "[.][failing][!throws]" ) {
147 throw CustomException( "custom std exception" );
148 }
149
150 TEST_CASE( "Custom exceptions can be translated when testing for nothrow", "[.][failing][!throws]" ) {
151 REQUIRE_NOTHROW( throwCustom() );
152 }
153
154 TEST_CASE( "Custom exceptions can be translated when testing for throwing as something else", "[.][failing][!throws]" ) {
155 REQUIRE_THROWS_AS( throwCustom(), std::exception );
156 }
157
158 TEST_CASE( "Unexpected exceptions can be translated", "[.][failing][!throws]" ) {
159 throw double( 3.14 );
160 }
161
162 TEST_CASE("Thrown string literals are translated", "[.][failing][!throws]") {
163 throw "For some reason someone is throwing a string literal!";
164 }
165
166 TEST_CASE("thrown std::strings are translated", "[.][failing][!throws]") {
167 throw std::string{ "Why would you throw a std::string?" };
168 }
169
170
171 #ifndef CATCH_CONFIG_DISABLE_MATCHERS
172
173 TEST_CASE( "Exception messages can be tested for", "[!throws]" ) {
174 using namespace Catch::Matchers;
175 SECTION( "exact match" )
176 REQUIRE_THROWS_WITH( thisThrows(), "expected exception" );
177 SECTION( "different case" )
178 REQUIRE_THROWS_WITH( thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) );
179 SECTION( "wildcarded" ) {
180 REQUIRE_THROWS_WITH( thisThrows(), StartsWith( "expected" ) );
181 REQUIRE_THROWS_WITH( thisThrows(), EndsWith( "exception" ) );
182 REQUIRE_THROWS_WITH( thisThrows(), Contains( "except" ) );
183 REQUIRE_THROWS_WITH( thisThrows(), Contains( "exCept", Catch::CaseSensitive::No ) );
184 }
185 }
186
187 #endif
188
189 TEST_CASE( "Mismatching exception messages failing the test", "[.][failing][!throws]" ) {
190 REQUIRE_THROWS_WITH( thisThrows(), "expected exception" );
191 REQUIRE_THROWS_WITH( thisThrows(), "should fail" );
192 REQUIRE_THROWS_WITH( thisThrows(), "expected exception" );
193 }
194
195 TEST_CASE( "#748 - captures with unexpected exceptions", "[.][failing][!throws][!shouldfail]" ) {
196 int answer = 42;
197 CAPTURE( answer );
198 // the message should be printed on the first two sections but not on the third
199 SECTION( "outside assertions" ) {
200 thisThrows();
201 }
202 SECTION( "inside REQUIRE_NOTHROW" ) {
203 REQUIRE_NOTHROW( thisThrows() );
204 }
205 SECTION( "inside REQUIRE_THROWS" ) {
206 REQUIRE_THROWS( thisThrows() );
207 }
208 }
209
210 }} // namespace ExceptionTests
211
212 #endif // CATCH_CONFIG_USE_EXCEPTIONS
213
214 #ifdef __clang__
215 #pragma clang diagnostic pop
216 #endif
217