diff --git a/test/format-test.cc b/test/format-test.cc index fe7ebb03..db5d6a29 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1587,7 +1587,7 @@ TEST(FormatterTest, FormatExamples) { EXPECT_THROW({ const char *filename = "nonexistent"; - FILE *f = fopen(filename, "r"); + FILE *f = std::fopen(filename, "r"); if (!f) fmt::ThrowSystemError(errno, "Cannot open file '{}'") << filename; }, fmt::SystemError); @@ -1669,26 +1669,34 @@ TEST(FormatterTest, OutputNotWrittenOnError) { EXPECT_EQ(0, num_writes); } +#if FMT_USE_FILE_DESCRIPTORS + TEST(FormatterTest, FileSink) { - FILE *f = std::fopen("out", "w"); - fmt::FileSink fs(f); - fs(Writer() << "test"); - std::fclose(f); - EXPECT_EQ("test", ReadFile("out")); + File read_end, write_end; + File::pipe(read_end, write_end); + BufferedFile f = write_end.fdopen("w"); + EXPECT_WRITE(f.get(), { + fmt::FileSink fs(f.get()); + fs(Writer() << "test"); + }, "test"); } TEST(FormatterTest, FileSinkWriteError) { - FILE *f = std::fopen("out", "r"); - fmt::FileSink fs(f); - int result = std::fwrite(" ", 1, 1, f); + File read_end, write_end; + File::pipe(read_end, write_end); + BufferedFile f = read_end.fdopen("r"); + fmt::FileSink fs(f.get()); + int result = std::fwrite(" ", 1, 1, f.get()); int error_code = errno; EXPECT_EQ(0, result); - std::string error_message = - str(Format("{}: {}") << "cannot write to file" << strerror(error_code)); - EXPECT_THROW_MSG(fs(Writer() << "test"), fmt::SystemError, error_message); - std::fclose(f); + EXPECT_SYSTEM_ERROR( + fs(Writer() << "test"), error_code, "cannot write to file"); } +#else +# pragma message "warning: some tests are disabled" +#endif + // The test doesn't compile on older compilers which follow C++03 and // require an accessible copy constructor when binding a temporary to // a const reference. @@ -1812,7 +1820,7 @@ TEST(FormatIntTest, FormatDec) { EXPECT_EQ("42", FormatDec(42ull)); } -#ifdef FMT_USE_FILE_DESCRIPTORS +#if FMT_USE_FILE_DESCRIPTORS TEST(FormatTest, PrintColored) { EXPECT_WRITE(stdout, fmt::PrintColored(fmt::RED, "Hello, {}!\n") << "world", diff --git a/test/gtest-extra-test.cc b/test/gtest-extra-test.cc index 56701c06..a2a5d63e 100644 --- a/test/gtest-extra-test.cc +++ b/test/gtest-extra-test.cc @@ -39,12 +39,6 @@ namespace { -std::string FormatSystemErrorMessage(int error_code, fmt::StringRef message) { - fmt::Writer out; - fmt::internal::FormatSystemErrorMessage(out, error_code, message); - return str(out); -} - // Suppresses Windows assertions on invalid file descriptors, making // POSIX functions return proper error codes instead of crashing on Windows. class SuppressAssert { @@ -70,26 +64,9 @@ class SuppressAssert { #define SUPPRESS_ASSERT(statement) { SuppressAssert sa; statement; } -#define EXPECT_SYSTEM_ERROR(statement, error_code, message) \ - EXPECT_THROW_MSG(statement, fmt::SystemError, \ - FormatSystemErrorMessage(error_code, message)) - #define EXPECT_SYSTEM_ERROR_NOASSERT(statement, error_code, message) \ EXPECT_SYSTEM_ERROR(SUPPRESS_ASSERT(statement), error_code, message) -// Checks if the file is open by reading one character from it. -bool IsOpen(int fd) { - char buffer; - return FMT_POSIX(read(fd, &buffer, 1)) == 1; -} - -bool IsClosed(int fd) { - char buffer; - std::streamsize result = 0; - SUPPRESS_ASSERT(result = FMT_POSIX(read(fd, &buffer, 1))); - return result == -1 && errno == EBADF; -} - // Tests that assertion macros evaluate their arguments exactly once. class SingleEvaluationTest : public ::testing::Test { protected: @@ -265,6 +242,19 @@ TEST(StreamingAssertionsTest, EXPECT_WRITE) { #if FMT_USE_FILE_DESCRIPTORS +// Checks if the file is open by reading one character from it. +bool IsOpen(int fd) { + char buffer; + return FMT_POSIX(read(fd, &buffer, 1)) == 1; +} + +bool IsClosed(int fd) { + char buffer; + std::streamsize result = 0; + SUPPRESS_ASSERT(result = FMT_POSIX(read(fd, &buffer, 1))); + return result == -1 && errno == EBADF; +} + TEST(ErrorCodeTest, Ctor) { EXPECT_EQ(0, ErrorCode().get()); EXPECT_EQ(42, ErrorCode(42).get()); @@ -671,6 +661,7 @@ TEST(OutputRedirectTest, ErrorInDtor) { write_dup.dup2(write_fd); // "undo" close or dtor of BufferedFile will fail } +// TODO: test EXPECT_SYSTEM_ERROR // TODO: test retry on EINTR #endif // FMT_USE_FILE_DESCRIPTORS diff --git a/test/gtest-extra.cc b/test/gtest-extra.cc index 503a9cb4..c0f28e6a 100644 --- a/test/gtest-extra.cc +++ b/test/gtest-extra.cc @@ -78,7 +78,7 @@ File::File(const char *path, int oflag) { } File::~File() FMT_NOEXCEPT(true) { - // Don't need to retry close in case of EINTR. + // Don't retry close in case of EINTR! // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html if (fd_ != -1 && ::FMT_POSIX(close(fd_)) != 0) fmt::ReportSystemError(errno, "cannot close file"); @@ -158,7 +158,7 @@ void File::pipe(File &read_end, File &write_end) { } BufferedFile File::fdopen(const char *mode) { - BufferedFile f(::fdopen(fd_, mode)); + BufferedFile f(::FMT_POSIX(fdopen(fd_, mode))); fd_ = -1; return f; } @@ -222,3 +222,9 @@ std::string OutputRedirect::RestoreAndRead() { } #endif // FMT_USE_FILE_DESCRIPTORS + +std::string FormatSystemErrorMessage(int error_code, fmt::StringRef message) { + fmt::Writer out; + fmt::internal::FormatSystemErrorMessage(out, error_code, message); + return str(out); +} diff --git a/test/gtest-extra.h b/test/gtest-extra.h index ee9512f6..05818d05 100644 --- a/test/gtest-extra.h +++ b/test/gtest-extra.h @@ -81,6 +81,12 @@ FMT_TEST_THROW_(statement, expected_exception, \ expected_message, GTEST_NONFATAL_FAILURE_) +std::string FormatSystemErrorMessage(int error_code, fmt::StringRef message); + +#define EXPECT_SYSTEM_ERROR(statement, error_code, message) \ + EXPECT_THROW_MSG(statement, fmt::SystemError, \ + FormatSystemErrorMessage(error_code, message)) + #ifndef FMT_USE_FILE_DESCRIPTORS # define FMT_USE_FILE_DESCRIPTORS 0 #endif