1 /* 2 * Created by Martin on 28/04/2018. 3 * 4 * Distributed under the Boost Software License, Version 1.0. (See accompanying 5 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 */ 7 #ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H 8 #define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H 9 10 #include "catch_platform.h" 11 #include "catch_stream.h" 12 13 #include <cstdio> 14 #include <iosfwd> 15 #include <string> 16 17 namespace Catch { 18 19 class RedirectedStream { 20 std::ostream& m_originalStream; 21 std::ostream& m_redirectionStream; 22 std::streambuf* m_prevBuf; 23 24 public: 25 RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ); 26 ~RedirectedStream(); 27 }; 28 29 class RedirectedStdOut { 30 ReusableStringStream m_rss; 31 RedirectedStream m_cout; 32 public: 33 RedirectedStdOut(); 34 auto str() const -> std::string; 35 }; 36 37 // StdErr has two constituent streams in C++, std::cerr and std::clog 38 // This means that we need to redirect 2 streams into 1 to keep proper 39 // order of writes 40 class RedirectedStdErr { 41 ReusableStringStream m_rss; 42 RedirectedStream m_cerr; 43 RedirectedStream m_clog; 44 public: 45 RedirectedStdErr(); 46 auto str() const -> std::string; 47 }; 48 49 class RedirectedStreams { 50 public: 51 RedirectedStreams(RedirectedStreams const&) = delete; 52 RedirectedStreams& operator=(RedirectedStreams const&) = delete; 53 RedirectedStreams(RedirectedStreams&&) = delete; 54 RedirectedStreams& operator=(RedirectedStreams&&) = delete; 55 56 RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr); 57 ~RedirectedStreams(); 58 private: 59 std::string& m_redirectedCout; 60 std::string& m_redirectedCerr; 61 RedirectedStdOut m_redirectedStdOut; 62 RedirectedStdErr m_redirectedStdErr; 63 }; 64 65 #if defined(CATCH_CONFIG_NEW_CAPTURE) 66 67 // Windows's implementation of std::tmpfile is terrible (it tries 68 // to create a file inside system folder, thus requiring elevated 69 // privileges for the binary), so we have to use tmpnam(_s) and 70 // create the file ourselves there. 71 class TempFile { 72 public: 73 TempFile(TempFile const&) = delete; 74 TempFile& operator=(TempFile const&) = delete; 75 TempFile(TempFile&&) = delete; 76 TempFile& operator=(TempFile&&) = delete; 77 78 TempFile(); 79 ~TempFile(); 80 81 std::FILE* getFile(); 82 std::string getContents(); 83 84 private: 85 std::FILE* m_file = nullptr; 86 #if defined(_MSC_VER) 87 char m_buffer[L_tmpnam] = { 0 }; 88 #endif 89 }; 90 91 92 class OutputRedirect { 93 public: 94 OutputRedirect(OutputRedirect const&) = delete; 95 OutputRedirect& operator=(OutputRedirect const&) = delete; 96 OutputRedirect(OutputRedirect&&) = delete; 97 OutputRedirect& operator=(OutputRedirect&&) = delete; 98 99 100 OutputRedirect(std::string& stdout_dest, std::string& stderr_dest); 101 ~OutputRedirect(); 102 103 private: 104 int m_originalStdout = -1; 105 int m_originalStderr = -1; 106 TempFile m_stdoutFile; 107 TempFile m_stderrFile; 108 std::string& m_stdoutDest; 109 std::string& m_stderrDest; 110 }; 111 112 #endif 113 114 } // end namespace Catch 115 116 #endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H 117