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