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