mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 20:27:11 +01:00 
			
		
		
		
	Added signal handlers (and placeholder for SEH handlers)
- based on PR 232 (https://github.com/philsquared/Catch/pull/232 - thanks Lukasz Forynski) - Writes to reporter, so gets all the usual context, but then exits directly (since the stack cannot be resumed) so no summary - On Windows does nothing, as yet.
This commit is contained in:
		
							
								
								
									
										78
									
								
								include/internal/catch_fatal_condition.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								include/internal/catch_fatal_condition.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| /* | ||||
|  *  Created by Phil on 21/08/2014 | ||||
|  *  Copyright 2014 Two Blue Cubes Ltd. All rights reserved. | ||||
|  * | ||||
|  *  Distributed under the Boost Software License, Version 1.0. (See accompanying | ||||
|  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||
|  * | ||||
|  */ | ||||
| #ifndef TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED | ||||
| #define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED | ||||
|  | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     // Report the error condition then exit the process | ||||
|     inline void fatal( std::string const& message, int exitCode ) { | ||||
|         IContext& context = Catch::getCurrentContext(); | ||||
|         IResultCapture* resultCapture = context.getResultCapture(); | ||||
|         ResultBuilder resultBuilder = resultCapture->makeUnexpectedResultBuilder(); | ||||
|         resultBuilder.setResultType( ResultWas::FatalErrorCondition ); | ||||
|         resultBuilder << message; | ||||
|         resultBuilder.captureExpression(); | ||||
|          | ||||
| 		if( Catch::alwaysTrue() ) // avoids "no return" warnings | ||||
|             exit( exitCode ); | ||||
|     } | ||||
|  | ||||
| } // namespace Catch | ||||
|  | ||||
| #if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     struct FatalConditionHandler {}; | ||||
|  | ||||
| } // namespace Catch | ||||
|  | ||||
| #else // Not Windows - assumed to be POSIX compatible ////////////////////////// | ||||
|  | ||||
| #include <signal.h> | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     struct SignalDefs { int id; const char* name; }; | ||||
|     extern SignalDefs signalDefs[]; | ||||
|     SignalDefs signalDefs[] = { | ||||
|             { SIGINT,  "SIGINT - Terminal interrupt signal" }, | ||||
|             { SIGILL,  "SIGILL - Illegal instruction signal" }, | ||||
|             { SIGFPE,  "SIGFPE - Floating point error signal" }, | ||||
|             { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, | ||||
|             { SIGTERM, "SIGTERM - Termination request signal" }, | ||||
|             { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } | ||||
|         }; | ||||
|  | ||||
|     struct FatalConditionHandler { | ||||
|  | ||||
|         static void handleSignal( int sig ) { | ||||
|             for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) | ||||
|                 if( sig == signalDefs[i].id ) | ||||
|                     fatal( signalDefs[i].name, -sig ); | ||||
|             fatal( "<unknown signal>", -sig ); | ||||
|         } | ||||
|  | ||||
|         FatalConditionHandler() { | ||||
|             for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) | ||||
|                 signal( signalDefs[i].id, handleSignal ); | ||||
|         } | ||||
|         ~FatalConditionHandler() { | ||||
|             for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) | ||||
|                 signal( signalDefs[i].id, SIG_DFL ); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
| } // namespace Catch | ||||
|  | ||||
| #endif // not Windows | ||||
|  | ||||
| #endif // TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED | ||||
| @@ -21,6 +21,7 @@ namespace Catch { | ||||
|     struct MessageInfo; | ||||
|     class ScopedMessageBuilder; | ||||
|     struct Counts; | ||||
|     class ResultBuilder; | ||||
|  | ||||
|     struct IResultCapture { | ||||
|  | ||||
| @@ -35,6 +36,8 @@ namespace Catch { | ||||
|  | ||||
|         virtual std::string getCurrentTestName() const = 0; | ||||
|         virtual const AssertionResult* getLastResult() const = 0; | ||||
|  | ||||
|         virtual ResultBuilder makeUnexpectedResultBuilder() const = 0; | ||||
|     }; | ||||
|  | ||||
|     IResultCapture& getResultCapture(); | ||||
|   | ||||
| @@ -25,7 +25,9 @@ namespace Catch { | ||||
|         Exception = 0x100 | FailureBit, | ||||
|  | ||||
|         ThrewException = Exception | 1, | ||||
|         DidntThrowException = Exception | 2 | ||||
|         DidntThrowException = Exception | 2, | ||||
|  | ||||
|         FatalErrorCondition = 0x200 | FailureBit | ||||
|  | ||||
|     }; }; | ||||
|  | ||||
|   | ||||
| @@ -20,6 +20,7 @@ | ||||
| #include "catch_test_case_tracker.hpp" | ||||
| #include "catch_timer.h" | ||||
| #include "catch_result_builder.h" | ||||
| #include "catch_fatal_condition.hpp" | ||||
|  | ||||
| #include <set> | ||||
| #include <string> | ||||
| @@ -215,6 +216,13 @@ namespace Catch { | ||||
|             return m_totals.assertions.failed == static_cast<std::size_t>( m_config->abortAfter() ); | ||||
|         } | ||||
|  | ||||
|         virtual ResultBuilder makeUnexpectedResultBuilder() const { | ||||
|             return ResultBuilder(   m_lastAssertionInfo.macroName.c_str(), | ||||
|                                     m_lastAssertionInfo.lineInfo, | ||||
|                                     m_lastAssertionInfo.capturedExpression.c_str(), | ||||
|                                     m_lastAssertionInfo.resultDisposition ); | ||||
|         } | ||||
|  | ||||
|     private: | ||||
|  | ||||
|         void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { | ||||
| @@ -232,10 +240,10 @@ namespace Catch { | ||||
|                 if( m_reporter->getPreferences().shouldRedirectStdOut ) { | ||||
|                     StreamRedirect coutRedir( std::cout, redirectedCout ); | ||||
|                     StreamRedirect cerrRedir( std::cerr, redirectedCerr ); | ||||
|                     m_activeTestCase->invoke(); | ||||
|                     invokeActiveTestCase(); | ||||
|                 } | ||||
|                 else { | ||||
|                     m_activeTestCase->invoke(); | ||||
|                     invokeActiveTestCase(); | ||||
|                 } | ||||
|                 duration = timer.getElapsedSeconds(); | ||||
|             } | ||||
| @@ -243,11 +251,7 @@ namespace Catch { | ||||
|                 // This just means the test was aborted due to failure | ||||
|             } | ||||
|             catch(...) { | ||||
|                 ResultBuilder exResult( m_lastAssertionInfo.macroName.c_str(), | ||||
|                                         m_lastAssertionInfo.lineInfo, | ||||
|                                         m_lastAssertionInfo.capturedExpression.c_str(), | ||||
|                                         m_lastAssertionInfo.resultDisposition ); | ||||
|                 exResult.useActiveException(); | ||||
|                 makeUnexpectedResultBuilder().useActiveException(); | ||||
|             } | ||||
|             // If sections ended prematurely due to an exception we stored their | ||||
|             // infos here so we can tear them down outside the unwind process. | ||||
| @@ -272,6 +276,11 @@ namespace Catch { | ||||
|             m_reporter->sectionEnded( testCaseSectionStats ); | ||||
|         } | ||||
|  | ||||
|         void invokeActiveTestCase() { | ||||
|             FatalConditionHandler fatalConditionHandler; // Handle signals | ||||
|             m_activeTestCase->invoke(); | ||||
|         } | ||||
|  | ||||
|     private: | ||||
|         struct UnfinishedSections { | ||||
|             UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds ) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Phil Nash
					Phil Nash