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