mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-31 03:07:36 +02:00
Fix test. More comments.
This commit is contained in:
@ -248,8 +248,9 @@ TEST(FileTest, DtorCloseError) {
|
|||||||
File *f = new File(".travis.yml", File::RDONLY);
|
File *f = new File(".travis.yml", File::RDONLY);
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
// The close function must be called inside EXPECT_STDERR, otherwise
|
// The close function must be called inside EXPECT_STDERR, otherwise
|
||||||
// the system may allocate freed file descriptor when redirecting the
|
// the system may recycle closed file descriptor when redirecting the
|
||||||
// output in EXPECT_STDERR.
|
// output in EXPECT_STDERR and the second close will break output
|
||||||
|
// redirection.
|
||||||
EXPECT_STDERR(FMT_POSIX(close(f->descriptor())); delete f,
|
EXPECT_STDERR(FMT_POSIX(close(f->descriptor())); delete f,
|
||||||
FormatSystemErrorMessage(EBADF, "cannot close file") + "\n");
|
FormatSystemErrorMessage(EBADF, "cannot close file") + "\n");
|
||||||
#else
|
#else
|
||||||
@ -269,14 +270,25 @@ TEST(FileTest, Close) {
|
|||||||
|
|
||||||
TEST(FileTest, CloseError) {
|
TEST(FileTest, CloseError) {
|
||||||
File *f = new File(".travis.yml", File::RDONLY);
|
File *f = new File(".travis.yml", File::RDONLY);
|
||||||
|
#ifndef _WIN32
|
||||||
fmt::SystemError error("", 0);
|
fmt::SystemError error("", 0);
|
||||||
std::string message = FormatSystemErrorMessage(EBADF, "cannot close file");
|
std::string message = FormatSystemErrorMessage(EBADF, "cannot close file");
|
||||||
|
// The close function must be called inside EXPECT_STDERR, otherwise
|
||||||
|
// the system may recycle closed file descriptor when redirecting the
|
||||||
|
// output in EXPECT_STDERR and the second close will break output
|
||||||
|
// redirection.
|
||||||
EXPECT_STDERR(
|
EXPECT_STDERR(
|
||||||
close(f->descriptor());
|
close(f->descriptor());
|
||||||
try { f->close(); } catch (const fmt::SystemError &e) { error = e; }
|
try { f->close(); } catch (const fmt::SystemError &e) { error = e; }
|
||||||
delete f,
|
delete f,
|
||||||
message + "\n");
|
message + "\n");
|
||||||
EXPECT_EQ(message, error.what());
|
EXPECT_EQ(message, error.what());
|
||||||
|
#else
|
||||||
|
close(f->descriptor());
|
||||||
|
// Closing file twice causes death on Windows.
|
||||||
|
f->close();
|
||||||
|
delete f;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempts to read count characters from a file.
|
// Attempts to read count characters from a file.
|
||||||
@ -382,11 +394,10 @@ TEST(FileTest, Pipe) {
|
|||||||
EXPECT_READ(read_end, "test");
|
EXPECT_READ(read_end, "test");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test pipe
|
|
||||||
|
|
||||||
// TODO: compile both with C++11 & C++98 mode
|
// TODO: compile both with C++11 & C++98 mode
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// TODO: test OutputRedirector
|
// TODO: test OutputRedirector
|
||||||
|
// TODO: test EXPECT_STDOUT and EXPECT_STDERR
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -146,26 +146,33 @@ OutputRedirector::OutputRedirector(FILE *file) : file_(file) {
|
|||||||
if (std::fflush(file) != 0)
|
if (std::fflush(file) != 0)
|
||||||
fmt::ThrowSystemError(errno, "cannot flush stream");
|
fmt::ThrowSystemError(errno, "cannot flush stream");
|
||||||
int fd = FMT_POSIX(fileno(file));
|
int fd = FMT_POSIX(fileno(file));
|
||||||
saved_ = File::dup(fd);
|
// Save the original file.
|
||||||
|
original_ = File::dup(fd);
|
||||||
|
// Create a pipe.
|
||||||
File write_end;
|
File write_end;
|
||||||
File::pipe(read_end_, write_end);
|
File::pipe(read_end_, write_end);
|
||||||
|
// Connect the write end to the passed FILE object.
|
||||||
write_end.dup2(fd);
|
write_end.dup2(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputRedirector::~OutputRedirector() {
|
OutputRedirector::~OutputRedirector() FMT_NOEXCEPT(true) {
|
||||||
|
try {
|
||||||
|
Restore();
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
// TODO: report
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutputRedirector::Restore() {
|
||||||
if (std::fflush(file_) != 0)
|
if (std::fflush(file_) != 0)
|
||||||
fmt::ReportSystemError(errno, "cannot flush stream");
|
fmt::ThrowSystemError(errno, "cannot flush stream");
|
||||||
ErrorCode ec;
|
// Restore the original file.
|
||||||
saved_.dup2(FMT_POSIX(fileno(file_)), ec);
|
original_.dup2(FMT_POSIX(fileno(file_)));
|
||||||
if (ec.get())
|
|
||||||
fmt::ReportSystemError(errno, "cannot restore output");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string OutputRedirector::Read() {
|
std::string OutputRedirector::Read() {
|
||||||
// Restore output.
|
// Restore output.
|
||||||
if (std::fflush(file_) != 0)
|
Restore();
|
||||||
fmt::ThrowSystemError(errno, "cannot flush stream");
|
|
||||||
saved_.dup2(FMT_POSIX(fileno(file_)));
|
|
||||||
|
|
||||||
// Read everything from the pipe.
|
// Read everything from the pipe.
|
||||||
std::string content;
|
std::string content;
|
||||||
@ -179,6 +186,4 @@ std::string OutputRedirector::Read() {
|
|||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test EXPECT_STDOUT and EXPECT_STDERR
|
|
||||||
|
|
||||||
#endif // FMT_USE_FILE_DESCRIPTORS
|
#endif // FMT_USE_FILE_DESCRIPTORS
|
||||||
|
@ -224,19 +224,24 @@ inline File &move(File &f) { return f; }
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Redirect file output to a pipe.
|
// Captures file output by redirecting it to a pipe.
|
||||||
|
// The output it can handle is limited by the pipe capacity.
|
||||||
class OutputRedirector {
|
class OutputRedirector {
|
||||||
private:
|
private:
|
||||||
FILE *file_;
|
FILE *file_;
|
||||||
File saved_; // Saved file created with dup.
|
File original_; // Original file passed to redirector.
|
||||||
File read_end_; // Read end of the pipe where the output is redirected.
|
File read_end_; // Read end of the pipe where the output is redirected.
|
||||||
|
|
||||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(OutputRedirector);
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(OutputRedirector);
|
||||||
|
|
||||||
|
void Restore();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit OutputRedirector(FILE *file);
|
explicit OutputRedirector(FILE *file);
|
||||||
~OutputRedirector();
|
~OutputRedirector() FMT_NOEXCEPT(true);
|
||||||
|
|
||||||
|
// Restores the original file, reads output from the pipe into a string
|
||||||
|
// and returns it.
|
||||||
std::string Read();
|
std::string Read();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user