From 0aacd0cf6d01cd58c8fa4d49eeaf79d9a87ed38c Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 5 May 2014 08:35:59 -0700 Subject: [PATCH] Replace EXPECT_STDOUT and EXPECT_STDERR with a single macro EXPECT_WRITE. --- test/format-test.cc | 3 +- test/gtest-extra-test.cc | 62 ++++++++++++++++++++++++++++------------ test/gtest-extra.h | 12 +++----- 3 files changed, 48 insertions(+), 29 deletions(-) diff --git a/test/format-test.cc b/test/format-test.cc index ea6f5af8..fe7ebb03 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1815,8 +1815,7 @@ TEST(FormatIntTest, FormatDec) { #ifdef FMT_USE_FILE_DESCRIPTORS TEST(FormatTest, PrintColored) { - EXPECT_STDOUT( - fmt::PrintColored(fmt::RED, "Hello, {}!\n") << "world", + EXPECT_WRITE(stdout, fmt::PrintColored(fmt::RED, "Hello, {}!\n") << "world", "\x1b[31mHello, world!\n\x1b[0m"); } diff --git a/test/gtest-extra-test.cc b/test/gtest-extra-test.cc index de69265d..6595d3d4 100644 --- a/test/gtest-extra-test.cc +++ b/test/gtest-extra-test.cc @@ -83,17 +83,20 @@ class SingleEvaluationTest : public ::testing::Test { SingleEvaluationTest() { p_ = s_; a_ = 0; + b_ = 0; } static const char* const s_; static const char* p_; static int a_; + static int b_; }; const char* const SingleEvaluationTest::s_ = "01234"; const char* SingleEvaluationTest::p_; int SingleEvaluationTest::a_; +int SingleEvaluationTest::b_; void ThrowNothing() {} @@ -109,10 +112,11 @@ TEST_F(SingleEvaluationTest, FailedEXPECT_THROW_MSG) { EXPECT_EQ(s_ + 1, p_); } -// Tests that when EXPECT_STDOUT fails, it evaluates its message argument +// Tests that when EXPECT_WRITE fails, it evaluates its message argument // exactly once. -TEST_F(SingleEvaluationTest, FailedEXPECT_STDOUT) { - EXPECT_NONFATAL_FAILURE(EXPECT_STDOUT(std::printf("test"), p_++), "01234"); +TEST_F(SingleEvaluationTest, FailedEXPECT_WRITE) { + EXPECT_NONFATAL_FAILURE( + EXPECT_WRITE(stdout, std::printf("test"), p_++), "01234"); EXPECT_EQ(s_ + 1, p_); } @@ -122,29 +126,55 @@ TEST_F(SingleEvaluationTest, ExceptionTests) { EXPECT_THROW_MSG({ // NOLINT a_++; ThrowException(); - }, std::exception, "test"); + }, std::exception, (b_++, "test")); EXPECT_EQ(1, a_); + EXPECT_EQ(1, b_); // failed EXPECT_THROW_MSG, throws different type EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG({ // NOLINT a_++; ThrowException(); - }, std::logic_error, "test"), "throws a different type"); + }, std::logic_error, (b_++, "test")), "throws a different type"); EXPECT_EQ(2, a_); + EXPECT_EQ(2, b_); // failed EXPECT_THROW_MSG, throws an exception with different message EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG({ // NOLINT a_++; ThrowException(); - }, std::exception, "other"), "throws an exception with a different message"); + }, std::exception, (b_++, "other")), + "throws an exception with a different message"); EXPECT_EQ(3, a_); + EXPECT_EQ(3, b_); // failed EXPECT_THROW_MSG, throws nothing EXPECT_NONFATAL_FAILURE( - EXPECT_THROW_MSG(a_++, std::exception, "test"), "throws nothing"); + EXPECT_THROW_MSG(a_++, std::exception, (b_++, "test")), "throws nothing"); EXPECT_EQ(4, a_); + EXPECT_EQ(4, b_); } +// Tests that assertion arguments are evaluated exactly once. +TEST_F(SingleEvaluationTest, WriteTests) { + // successful EXPECT_WRITE + EXPECT_WRITE(stdout, { // NOLINT + a_++; + std::printf("test"); + }, (b_++, "test")); + EXPECT_EQ(1, a_); + EXPECT_EQ(1, b_); + + // failed EXPECT_WRITE + EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, { // NOLINT + a_++; + std::printf("test"); + }, (b_++, "other")), "Actual: test"); + EXPECT_EQ(2, a_); + EXPECT_EQ(2, b_); +} + +// TODO: test EXPECT_STD* + // Tests that the compiler will not complain about unreachable code in the // EXPECT_THROW_MSG macro. TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) { @@ -291,11 +321,11 @@ TEST_F(BufferedFileTest, CloseFileInDtor) { TEST_F(BufferedFileTest, CloseErrorInDtor) { BufferedFile *f = new BufferedFile(OpenFile(".travis.yml")); - // The close function must be called inside EXPECT_STDERR, otherwise + // The close function must be called inside EXPECT_WRITE, 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(close(fileno(f->get())); delete f, + EXPECT_WRITE(stderr, close(fileno(f->get())); delete f, FormatSystemErrorMessage(EBADF, "cannot close file") + "\n"); } @@ -380,11 +410,11 @@ TEST(FileTest, CloseFileInDtor) { TEST(FileTest, CloseErrorInDtor) { File *f = new File(".travis.yml", File::RDONLY); #ifndef _WIN32 - // The close function must be called inside EXPECT_STDERR, otherwise + // The close function must be called inside EXPECT_WRITE, 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(FMT_POSIX(close(f->descriptor())); delete f, + EXPECT_WRITE(stderr, FMT_POSIX(close(f->descriptor())); delete f, FormatSystemErrorMessage(EBADF, "cannot close file") + "\n"); #else close(f->descriptor()); @@ -404,10 +434,6 @@ TEST(FileTest, Close) { TEST(FileTest, CloseError) { File f(".travis.yml", File::RDONLY); #ifndef _WIN32 - // 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. close(f.descriptor()); EXPECT_SYSTEM_ERROR(f.close(), EBADF, "cannot close file"); EXPECT_EQ(-1, f.descriptor()); @@ -615,11 +641,11 @@ TEST(OutputRedirectTest, ErrorInDtor) { // Put a character in a file buffer. EXPECT_EQ('x', fputc('x', f.get())); #ifndef _WIN32 - // The close function must be called inside EXPECT_STDERR, otherwise + // The close function must be called inside EXPECT_WRITE, 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(close(write_fd); delete redir, + EXPECT_WRITE(stderr, close(write_fd); delete redir, FormatSystemErrorMessage(EBADF, "cannot flush stream")); #else close(write_fd); @@ -628,8 +654,6 @@ TEST(OutputRedirectTest, ErrorInDtor) { write_dup.dup2(write_fd); // "undo" close or dtor of BufferedFile will fail } -// TODO: test EXPECT_STDOUT and EXPECT_STDERR - // TODO: compile both in C++11 & C++98 mode #endif diff --git a/test/gtest-extra.h b/test/gtest-extra.h index badfc6ba..052a3cee 100644 --- a/test/gtest-extra.h +++ b/test/gtest-extra.h @@ -337,7 +337,7 @@ class OutputRedirect { std::string RestoreAndRead(); }; -#define FMT_TEST_PRINT_(statement, expected_output, file, fail) \ +#define FMT_TEST_WRITE_(statement, expected_output, file, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \ std::string gtest_expected_output = expected_output; \ @@ -355,13 +355,9 @@ class OutputRedirect { GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ fail(gtest_ar.failure_message()) -// Tests that the statement prints the expected output to stdout. -#define EXPECT_STDOUT(statement, expected_output) \ - FMT_TEST_PRINT_(statement, expected_output, stdout, GTEST_NONFATAL_FAILURE_) - -// Tests that the statement prints the expected output to stderr. -#define EXPECT_STDERR(statement, expected_output) \ - FMT_TEST_PRINT_(statement, expected_output, stderr, GTEST_NONFATAL_FAILURE_) +// Tests that the statement writes the expected output to file. +#define EXPECT_WRITE(file, statement, expected_output) \ + FMT_TEST_WRITE_(statement, expected_output, file, GTEST_NONFATAL_FAILURE_) #endif // FMT_USE_FILE_DESCRIPTORS