xref: /aosp_15_r20/external/fmtlib/test/gtest-extra.cc (revision 5c90c05cd622c0a81b57953a4d343e0e489f2e08)
1 // Formatting library for C++ - custom Google Test assertions
2 //
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
5 //
6 // For the license information refer to format.h.
7 
8 #include "gtest-extra.h"
9 
10 #if FMT_USE_FCNTL
11 
12 using fmt::file;
13 
output_redirect(FILE * f,bool flush)14 output_redirect::output_redirect(FILE* f, bool flush) : file_(f) {
15   if (flush) this->flush();
16   int fd = FMT_POSIX(fileno(f));
17   // Create a file object referring to the original file.
18   original_ = file::dup(fd);
19   // Create a pipe.
20   auto pipe = fmt::pipe();
21   read_end_ = std::move(pipe.read_end);
22   // Connect the passed FILE object to the write end of the pipe.
23   pipe.write_end.dup2(fd);
24 }
25 
~output_redirect()26 output_redirect::~output_redirect() noexcept {
27   try {
28     restore();
29   } catch (const std::exception& e) {
30     std::fputs(e.what(), stderr);
31   }
32 }
33 
flush()34 void output_redirect::flush() {
35   int result = 0;
36   do {
37     result = fflush(file_);
38   } while (result == EOF && errno == EINTR);
39   if (result != 0) throw fmt::system_error(errno, "cannot flush stream");
40 }
41 
restore()42 void output_redirect::restore() {
43   if (original_.descriptor() == -1) return;  // Already restored.
44   flush();
45   // Restore the original file.
46   original_.dup2(FMT_POSIX(fileno(file_)));
47   original_.close();
48 }
49 
restore_and_read()50 std::string output_redirect::restore_and_read() {
51   // Restore output.
52   restore();
53 
54   // Read everything from the pipe.
55   std::string content;
56   if (read_end_.descriptor() == -1) return content;  // Already read.
57   enum { BUFFER_SIZE = 4096 };
58   char buffer[BUFFER_SIZE];
59   size_t count = 0;
60   do {
61     count = read_end_.read(buffer, BUFFER_SIZE);
62     content.append(buffer, count);
63   } while (count != 0);
64   read_end_.close();
65   return content;
66 }
67 
read(file & f,size_t count)68 std::string read(file& f, size_t count) {
69   std::string buffer(count, '\0');
70   size_t n = 0, offset = 0;
71   do {
72     n = f.read(&buffer[offset], count - offset);
73     // We can't read more than size_t bytes since count has type size_t.
74     offset += n;
75   } while (offset < count && n != 0);
76   buffer.resize(offset);
77   return buffer;
78 }
79 
80 #endif  // FMT_USE_FCNTL
81