Skip to content

Commit 0fcde42

Browse files
feat: Add buffered GoogleTest event listener (#25)
1 parent 4c05418 commit 0fcde42

3 files changed

Lines changed: 122 additions & 0 deletions

File tree

tests/cpp/test_testing.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,16 @@ namespace {
6666
return false;
6767
}
6868
};
69+
70+
class TestableBufferedTestEventListener: public BufferedTestEventListener {
71+
public:
72+
using BufferedTestEventListener::clearBufferedTestOutput;
73+
using BufferedTestEventListener::logTestEvent;
74+
75+
[[nodiscard]] std::string output() const {
76+
return bufferedTestOutput();
77+
}
78+
};
6979
} // namespace
7080

7181
TEST(TestingSupportTest, DefaultTestMacroUsesBaseFixture) {
@@ -107,6 +117,17 @@ TEST_F(TestableBaseTest, HelpersAreAvailableOnDerivedFixtures) {
107117
EXPECT_FALSE(isSystemTest());
108118
}
109119

120+
TEST(TestingSupportTest, BufferedEventListenerOutputCanBeCustomized) {
121+
TestableBufferedTestEventListener listener;
122+
123+
listener.logTestEvent("first line");
124+
listener.logTestEvent("second line");
125+
EXPECT_EQ(listener.output(), "first line\nsecond line\n");
126+
127+
listener.clearBufferedTestOutput();
128+
EXPECT_TRUE(listener.output().empty());
129+
}
130+
110131
TEST_F(LinuxTest, SkipsOrRunsLinuxFixture) {
111132
#if defined(__linux__)
112133
SUCCEED();

tests/support/include/lizardbyte/common/testing.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,51 @@ namespace lizardbyte::common::testing {
132132
*/
133133
void SetUp() override;
134134
};
135+
136+
/**
137+
* @brief GoogleTest event listener that buffers test log output until a test fails.
138+
*/
139+
class BufferedTestEventListener: public ::testing::EmptyTestEventListener {
140+
public:
141+
/**
142+
* @brief Handle the start of a test.
143+
* @param test_info GoogleTest test information.
144+
*/
145+
void OnTestStart(const ::testing::TestInfo &test_info) override;
146+
147+
/**
148+
* @brief Handle a test assertion result.
149+
* @param test_part_result GoogleTest assertion result.
150+
*/
151+
void OnTestPartResult(const ::testing::TestPartResult &test_part_result) override;
152+
153+
/**
154+
* @brief Handle the end of a test.
155+
* @param test_info GoogleTest test information.
156+
*/
157+
void OnTestEnd(const ::testing::TestInfo &test_info) override;
158+
159+
protected:
160+
/**
161+
* @brief Add a test event line to the buffer.
162+
* @param message Message to buffer.
163+
*/
164+
virtual void logTestEvent(const std::string &message);
165+
166+
/**
167+
* @brief Get buffered test output.
168+
* @return Buffered output.
169+
*/
170+
[[nodiscard]] virtual std::string bufferedTestOutput() const;
171+
172+
/**
173+
* @brief Clear buffered test output.
174+
*/
175+
virtual void clearBufferedTestOutput();
176+
177+
private:
178+
std::stringstream event_buffer_; /**< Stores event log output while tests run. */
179+
};
135180
} // namespace lizardbyte::common::testing
136181

137182
#if !defined(LIZARDBYTE_COMMON_TESTING_NO_GLOBAL_ALIASES)
@@ -154,6 +199,11 @@ using MacOSTest = ::lizardbyte::common::testing::MacOSTest;
154199
* @brief Global compatibility alias for the shared Windows-only test fixture.
155200
*/
156201
using WindowsTest = ::lizardbyte::common::testing::WindowsTest;
202+
203+
/**
204+
* @brief Global compatibility alias for the shared buffered test event listener.
205+
*/
206+
using BufferedTestEventListener = ::lizardbyte::common::testing::BufferedTestEventListener;
157207
#endif
158208

159209
#if !defined(LIZARDBYTE_COMMON_TESTING_KEEP_GTEST_TEST)

tests/support/testing.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,4 +148,55 @@ namespace lizardbyte::common::testing {
148148
BaseTest::SetUp();
149149
#endif
150150
}
151+
152+
void BufferedTestEventListener::OnTestStart(const ::testing::TestInfo &test_info) {
153+
const std::string file {test_info.file() == nullptr ? "" : test_info.file()};
154+
logTestEvent("From " + file + ":" + std::to_string(test_info.line()));
155+
logTestEvent(" " + std::string {test_info.test_suite_name()} + "/" + test_info.name() + " started");
156+
}
157+
158+
void BufferedTestEventListener::OnTestPartResult(const ::testing::TestPartResult &test_part_result) {
159+
const std::string file {test_part_result.file_name() == nullptr ? "" : test_part_result.file_name()};
160+
logTestEvent("At " + file + ":" + std::to_string(test_part_result.line_number()));
161+
162+
const std::string result_text {
163+
test_part_result.passed() ? "Success" :
164+
test_part_result.nonfatally_failed() ? "Non-fatal failure" :
165+
test_part_result.fatally_failed() ? "Failure" :
166+
"Skip"
167+
};
168+
169+
const std::string summary {test_part_result.summary()};
170+
const std::string message {test_part_result.message()};
171+
logTestEvent(" " + result_text + ": " + summary);
172+
if (message != summary) {
173+
logTestEvent(" " + message);
174+
}
175+
}
176+
177+
void BufferedTestEventListener::OnTestEnd(const ::testing::TestInfo &test_info) {
178+
const auto &result {*test_info.result()};
179+
const std::string result_text {result.Passed() ? "passed" : result.Skipped() ? "skipped" :
180+
"failed"};
181+
logTestEvent(std::string {test_info.test_suite_name()} + "/" + test_info.name() + " " + result_text);
182+
183+
if (result.Failed()) {
184+
std::cout << bufferedTestOutput();
185+
}
186+
187+
clearBufferedTestOutput();
188+
}
189+
190+
void BufferedTestEventListener::logTestEvent(const std::string &message) {
191+
event_buffer_ << message << std::endl;
192+
}
193+
194+
std::string BufferedTestEventListener::bufferedTestOutput() const {
195+
return event_buffer_.str();
196+
}
197+
198+
void BufferedTestEventListener::clearBufferedTestOutput() {
199+
event_buffer_.str({});
200+
event_buffer_.clear();
201+
}
151202
} // namespace lizardbyte::common::testing

0 commit comments

Comments
 (0)