1 // 210-Evt-EventListeners.cpp
2 
3 // Contents:
4 // 1. Printing of listener data
5 // 2. My listener and registration
6 // 3. Test cases
7 
8 // main() provided in 000-CatchMain.cpp
9 
10 // Let Catch provide the required interfaces:
11 #define CATCH_CONFIG_EXTERNAL_INTERFACES
12 
13 #include <catch2/catch.hpp>
14 #include <iostream>
15 
16 // -----------------------------------------------------------------------
17 // 1. Printing of listener data:
18 //
19 
ws(int const level)20 std::string ws(int const level) {
21     return std::string( 2 * level, ' ' );
22 }
23 
24 template< typename T >
operator <<(std::ostream & os,std::vector<T> const & v)25 std::ostream& operator<<( std::ostream& os, std::vector<T> const& v ) {
26     os << "{ ";
27     for ( auto x : v )
28         os << x << ", ";
29     return os << "}";
30 }
31 
32 // struct SourceLineInfo {
33 //     char const* file;
34 //     std::size_t line;
35 // };
36 
print(std::ostream & os,int const level,std::string const & title,Catch::SourceLineInfo const & info)37 void print( std::ostream& os, int const level, std::string const& title, Catch::SourceLineInfo const& info ) {
38     os << ws(level  ) << title << ":\n"
39        << ws(level+1) << "- file: " << info.file << "\n"
40        << ws(level+1) << "- line: " << info.line << "\n";
41 }
42 
43 //struct MessageInfo {
44 //    std::string macroName;
45 //    std::string message;
46 //    SourceLineInfo lineInfo;
47 //    ResultWas::OfType type;
48 //    unsigned int sequence;
49 //};
50 
print(std::ostream & os,int const level,Catch::MessageInfo const & info)51 void print( std::ostream& os, int const level, Catch::MessageInfo const& info ) {
52     os << ws(level+1) << "- macroName: '" << info.macroName << "'\n"
53        << ws(level+1) << "- message '"    << info.message   << "'\n";
54     print( os,level+1  , "- lineInfo", info.lineInfo );
55     os << ws(level+1) << "- sequence "    << info.sequence  << "\n";
56 }
57 
print(std::ostream & os,int const level,std::string const & title,std::vector<Catch::MessageInfo> const & v)58 void print( std::ostream& os, int const level, std::string const& title, std::vector<Catch::MessageInfo> const& v ) {
59     os << ws(level  ) << title << ":\n";
60     for ( auto x : v )
61     {
62         os << ws(level+1) << "{\n";
63         print( os, level+2, x );
64         os << ws(level+1) << "}\n";
65     }
66 //    os << ws(level+1) << "\n";
67 }
68 
69 // struct TestRunInfo {
70 //     std::string name;
71 // };
72 
print(std::ostream & os,int const level,std::string const & title,Catch::TestRunInfo const & info)73 void print( std::ostream& os, int const level, std::string const& title, Catch::TestRunInfo const& info ) {
74     os << ws(level  ) << title << ":\n"
75        << ws(level+1) << "- name: " << info.name << "\n";
76 }
77 
78 // struct Counts {
79 //     std::size_t total() const;
80 //     bool allPassed() const;
81 //     bool allOk() const;
82 //
83 //     std::size_t passed = 0;
84 //     std::size_t failed = 0;
85 //     std::size_t failedButOk = 0;
86 // };
87 
print(std::ostream & os,int const level,std::string const & title,Catch::Counts const & info)88 void print( std::ostream& os, int const level, std::string const& title, Catch::Counts const& info ) {
89     os << ws(level  ) << title << ":\n"
90        << ws(level+1) << "- total(): "     << info.total()     << "\n"
91        << ws(level+1) << "- allPassed(): " << info.allPassed() << "\n"
92        << ws(level+1) << "- allOk(): "     << info.allOk()     << "\n"
93        << ws(level+1) << "- passed: "      << info.passed      << "\n"
94        << ws(level+1) << "- failed: "      << info.failed      << "\n"
95        << ws(level+1) << "- failedButOk: " << info.failedButOk << "\n";
96 }
97 
98 // struct Totals {
99 //     Counts assertions;
100 //     Counts testCases;
101 // };
102 
print(std::ostream & os,int const level,std::string const & title,Catch::Totals const & info)103 void print( std::ostream& os, int const level, std::string const& title, Catch::Totals const& info ) {
104     os << ws(level) << title << ":\n";
105     print( os, level+1, "- assertions", info.assertions );
106     print( os, level+1, "- testCases" , info.testCases  );
107 }
108 
109 // struct TestRunStats {
110 //     TestRunInfo runInfo;
111 //     Totals totals;
112 //     bool aborting;
113 // };
114 
print(std::ostream & os,int const level,std::string const & title,Catch::TestRunStats const & info)115 void print( std::ostream& os, int const level, std::string const& title, Catch::TestRunStats const& info ) {
116     os << ws(level) << title << ":\n";
117     print( os, level+1 , "- runInfo", info.runInfo );
118     print( os, level+1 , "- totals" , info.totals  );
119     os << ws(level+1) << "- aborting: " << info.aborting << "\n";
120 }
121 
122 // struct TestCaseInfo {
123 //     enum SpecialProperties{
124 //         None = 0,
125 //         IsHidden = 1 << 1,
126 //         ShouldFail = 1 << 2,
127 //         MayFail = 1 << 3,
128 //         Throws = 1 << 4,
129 //         NonPortable = 1 << 5,
130 //         Benchmark = 1 << 6
131 //     };
132 //
133 //     bool isHidden() const;
134 //     bool throws() const;
135 //     bool okToFail() const;
136 //     bool expectedToFail() const;
137 //
138 //     std::string tagsAsString() const;
139 //
140 //     std::string name;
141 //     std::string className;
142 //     std::string description;
143 //     std::vector<std::string> tags;
144 //     std::vector<std::string> lcaseTags;
145 //     SourceLineInfo lineInfo;
146 //     SpecialProperties properties;
147 // };
148 
print(std::ostream & os,int const level,std::string const & title,Catch::TestCaseInfo const & info)149 void print( std::ostream& os, int const level, std::string const& title, Catch::TestCaseInfo const& info ) {
150     os << ws(level  ) << title << ":\n"
151        << ws(level+1) << "- isHidden(): "       << info.isHidden() << "\n"
152        << ws(level+1) << "- throws(): "         << info.throws() << "\n"
153        << ws(level+1) << "- okToFail(): "       << info.okToFail() << "\n"
154        << ws(level+1) << "- expectedToFail(): " << info.expectedToFail() << "\n"
155        << ws(level+1) << "- tagsAsString(): '"  << info.tagsAsString() << "'\n"
156        << ws(level+1) << "- name: '"            << info.name << "'\n"
157        << ws(level+1) << "- className: '"       << info.className << "'\n"
158        << ws(level+1) << "- description: '"     << info.description << "'\n"
159        << ws(level+1) << "- tags: "             << info.tags << "\n"
160        << ws(level+1) << "- lcaseTags: "        << info.lcaseTags << "\n";
161     print( os, level+1 , "- lineInfo", info.lineInfo );
162     os << ws(level+1) << "- properties (flags): 0x" << std::hex << info.properties << std::dec << "\n";
163 }
164 
165 // struct TestCaseStats {
166 //     TestCaseInfo testInfo;
167 //     Totals totals;
168 //     std::string stdOut;
169 //     std::string stdErr;
170 //     bool aborting;
171 // };
172 
print(std::ostream & os,int const level,std::string const & title,Catch::TestCaseStats const & info)173 void print( std::ostream& os, int const level, std::string const& title, Catch::TestCaseStats const& info ) {
174     os << ws(level  ) << title << ":\n";
175     print( os, level+1 , "- testInfo", info.testInfo );
176     print( os, level+1 , "- totals"  , info.totals   );
177     os << ws(level+1) << "- stdOut: "   << info.stdOut << "\n"
178        << ws(level+1) << "- stdErr: "   << info.stdErr << "\n"
179        << ws(level+1) << "- aborting: " << info.aborting << "\n";
180 }
181 
182 // struct SectionInfo {
183 //     std::string name;
184 //     std::string description;
185 //     SourceLineInfo lineInfo;
186 // };
187 
print(std::ostream & os,int const level,std::string const & title,Catch::SectionInfo const & info)188 void print( std::ostream& os, int const level, std::string const& title, Catch::SectionInfo const& info ) {
189     os << ws(level  ) << title << ":\n"
190        << ws(level+1) << "- name: "         << info.name << "\n";
191     print( os, level+1 , "- lineInfo", info.lineInfo );
192 }
193 
194 // struct SectionStats {
195 //     SectionInfo sectionInfo;
196 //     Counts assertions;
197 //     double durationInSeconds;
198 //     bool missingAssertions;
199 // };
200 
print(std::ostream & os,int const level,std::string const & title,Catch::SectionStats const & info)201 void print( std::ostream& os, int const level, std::string const& title, Catch::SectionStats const& info ) {
202     os << ws(level  ) << title << ":\n";
203     print( os, level+1 , "- sectionInfo", info.sectionInfo );
204     print( os, level+1 , "- assertions" , info.assertions );
205     os << ws(level+1) << "- durationInSeconds: " << info.durationInSeconds << "\n"
206        << ws(level+1) << "- missingAssertions: " << info.missingAssertions << "\n";
207 }
208 
209 // struct AssertionInfo
210 // {
211 //     StringRef macroName;
212 //     SourceLineInfo lineInfo;
213 //     StringRef capturedExpression;
214 //     ResultDisposition::Flags resultDisposition;
215 // };
216 
print(std::ostream & os,int const level,std::string const & title,Catch::AssertionInfo const & info)217 void print( std::ostream& os, int const level, std::string const& title, Catch::AssertionInfo const& info ) {
218     os << ws(level  ) << title << ":\n"
219        << ws(level+1) << "- macroName: '"  << info.macroName << "'\n";
220     print( os, level+1 , "- lineInfo" , info.lineInfo );
221     os << ws(level+1) << "- capturedExpression: '" << info.capturedExpression << "'\n"
222        << ws(level+1) << "- resultDisposition (flags): 0x" << std::hex << info.resultDisposition  << std::dec << "\n";
223 }
224 
225 //struct AssertionResultData
226 //{
227 //    std::string reconstructExpression() const;
228 //
229 //    std::string message;
230 //    mutable std::string reconstructedExpression;
231 //    LazyExpression lazyExpression;
232 //    ResultWas::OfType resultType;
233 //};
234 
print(std::ostream & os,int const level,std::string const & title,Catch::AssertionResultData const & info)235 void print( std::ostream& os, int const level, std::string const& title, Catch::AssertionResultData const& info ) {
236     os << ws(level  ) << title << ":\n"
237        << ws(level+1) << "- reconstructExpression(): '" <<   info.reconstructExpression() << "'\n"
238        << ws(level+1) << "- message: '"                 <<   info.message << "'\n"
239        << ws(level+1) << "- lazyExpression: '"          << "(info.lazyExpression)" << "'\n"
240        << ws(level+1) << "- resultType: '"              <<   info.resultType << "'\n";
241 }
242 
243 //class AssertionResult {
244 //    bool isOk() const;
245 //    bool succeeded() const;
246 //    ResultWas::OfType getResultType() const;
247 //    bool hasExpression() const;
248 //    bool hasMessage() const;
249 //    std::string getExpression() const;
250 //    std::string getExpressionInMacro() const;
251 //    bool hasExpandedExpression() const;
252 //    std::string getExpandedExpression() const;
253 //    std::string getMessage() const;
254 //    SourceLineInfo getSourceInfo() const;
255 //    std::string getTestMacroName() const;
256 //
257 //    AssertionInfo m_info;
258 //    AssertionResultData m_resultData;
259 //};
260 
print(std::ostream & os,int const level,std::string const & title,Catch::AssertionResult const & info)261 void print( std::ostream& os, int const level, std::string const& title, Catch::AssertionResult const& info ) {
262     os << ws(level  ) << title << ":\n"
263        << ws(level+1) << "- isOk(): "  << info.isOk() << "\n"
264        << ws(level+1) << "- succeeded(): "  << info.succeeded() << "\n"
265        << ws(level+1) << "- getResultType(): "  << info.getResultType() << "\n"
266        << ws(level+1) << "- hasExpression(): "  << info.hasExpression() << "\n"
267        << ws(level+1) << "- hasMessage(): "  << info.hasMessage() << "\n"
268        << ws(level+1) << "- getExpression(): '"  << info.getExpression() << "'\n"
269        << ws(level+1) << "- getExpressionInMacro(): '"  << info.getExpressionInMacro()  << "'\n"
270        << ws(level+1) << "- hasExpandedExpression(): "  << info.hasExpandedExpression() << "\n"
271        << ws(level+1) << "- getExpandedExpression(): "  << info.getExpandedExpression() << "'\n"
272        << ws(level+1) << "- getMessage(): '"  << info.getMessage() << "'\n";
273     print( os, level+1 , "- getSourceInfo(): ", info.getSourceInfo() );
274     os << ws(level+1) << "- getTestMacroName(): '"  << info.getTestMacroName() << "'\n";
275 
276 //    print( os, level+1 , "- *** m_info (AssertionInfo)", info.m_info );
277 //    print( os, level+1 , "- *** m_resultData (AssertionResultData)", info.m_resultData );
278 }
279 
280 // struct AssertionStats {
281 //     AssertionResult assertionResult;
282 //     std::vector<MessageInfo> infoMessages;
283 //     Totals totals;
284 // };
285 
print(std::ostream & os,int const level,std::string const & title,Catch::AssertionStats const & info)286 void print( std::ostream& os, int const level, std::string const& title, Catch::AssertionStats const& info ) {
287     os << ws(level  ) << title << ":\n";
288     print( os, level+1 , "- assertionResult", info.assertionResult );
289     print( os, level+1 , "- infoMessages", info.infoMessages );
290     print( os, level+1 , "- totals", info.totals );
291 }
292 
293 // -----------------------------------------------------------------------
294 // 2. My listener and registration:
295 //
296 
297 char const * dashed_line =
298     "--------------------------------------------------------------------------";
299 
300 struct MyListener : Catch::TestEventListenerBase {
301 
302     using TestEventListenerBase::TestEventListenerBase; // inherit constructor
303 
304     // Get rid of Wweak-tables
305     ~MyListener();
306 
307     // The whole test run starting
testRunStartingMyListener308     virtual void testRunStarting( Catch::TestRunInfo const& testRunInfo ) override {
309         std::cout
310             << std::boolalpha
311             << "\nEvent: testRunStarting:\n";
312         print( std::cout, 1, "- testRunInfo", testRunInfo );
313     }
314 
315     // The whole test run ending
testRunEndedMyListener316     virtual void testRunEnded( Catch::TestRunStats const& testRunStats ) override {
317         std::cout
318             << dashed_line
319             << "\nEvent: testRunEnded:\n";
320         print( std::cout, 1, "- testRunStats", testRunStats );
321     }
322 
323     // A test is being skipped (because it is "hidden")
skipTestMyListener324     virtual void skipTest( Catch::TestCaseInfo const& testInfo ) override {
325         std::cout
326             << dashed_line
327             << "\nEvent: skipTest:\n";
328         print( std::cout, 1, "- testInfo", testInfo );
329     }
330 
331     // Test cases starting
testCaseStartingMyListener332     virtual void testCaseStarting( Catch::TestCaseInfo const& testInfo ) override {
333         std::cout
334             << dashed_line
335             << "\nEvent: testCaseStarting:\n";
336         print( std::cout, 1, "- testInfo", testInfo );
337     }
338 
339     // Test cases ending
testCaseEndedMyListener340     virtual void testCaseEnded( Catch::TestCaseStats const& testCaseStats ) override {
341         std::cout << "\nEvent: testCaseEnded:\n";
342         print( std::cout, 1, "testCaseStats", testCaseStats );
343     }
344 
345     // Sections starting
sectionStartingMyListener346     virtual void sectionStarting( Catch::SectionInfo const& sectionInfo ) override {
347         std::cout << "\nEvent: sectionStarting:\n";
348         print( std::cout, 1, "- sectionInfo", sectionInfo );
349     }
350 
351     // Sections ending
sectionEndedMyListener352     virtual void sectionEnded( Catch::SectionStats const& sectionStats ) override {
353         std::cout << "\nEvent: sectionEnded:\n";
354         print( std::cout, 1, "- sectionStats", sectionStats );
355     }
356 
357     // Assertions before/ after
assertionStartingMyListener358     virtual void assertionStarting( Catch::AssertionInfo const& assertionInfo ) override {
359         std::cout << "\nEvent: assertionStarting:\n";
360         print( std::cout, 1, "- assertionInfo", assertionInfo );
361     }
362 
assertionEndedMyListener363     virtual bool assertionEnded( Catch::AssertionStats const& assertionStats ) override {
364         std::cout << "\nEvent: assertionEnded:\n";
365         print( std::cout, 1, "- assertionStats", assertionStats );
366         return true;
367     }
368 };
369 
CATCH_REGISTER_LISTENER(MyListener)370 CATCH_REGISTER_LISTENER( MyListener )
371 
372 // Get rid of Wweak-tables
373 MyListener::~MyListener() {}
374 
375 
376 // -----------------------------------------------------------------------
377 // 3. Test cases:
378 //
379 
380 TEST_CASE( "1: Hidden testcase", "[.hidden]" ) {
381 }
382 
383 TEST_CASE( "2: Testcase with sections", "[tag-A][tag-B]" ) {
384 
385     int i = 42;
386 
387     REQUIRE( i == 42 );
388 
389     SECTION("Section 1") {
390         INFO("Section 1");
391         i = 7;
392         SECTION("Section 1.1") {
393             INFO("Section 1.1");
394             REQUIRE( i == 42 );
395         }
396     }
397 
398     SECTION("Section 2") {
399         INFO("Section 2");
400         REQUIRE( i == 42 );
401     }
402     WARN("At end of test case");
403 }
404 
405 struct Fixture {
fortytwoFixture406     int fortytwo() const {
407         return 42;
408     }
409 };
410 
411 TEST_CASE_METHOD( Fixture, "3: Testcase with class-based fixture", "[tag-C][tag-D]" ) {
412     REQUIRE( fortytwo() == 42 );
413 }
414 
415 // Compile & run:
416 // - g++ -std=c++11 -Wall -I$(CATCH_SINGLE_INCLUDE) -o 210-Evt-EventListeners 210-Evt-EventListeners.cpp 000-CatchMain.o && 210-Evt-EventListeners --success
417 // - cl -EHsc -I%CATCH_SINGLE_INCLUDE% 210-Evt-EventListeners.cpp 000-CatchMain.obj && 210-Evt-EventListeners --success
418 
419 // Expected compact output (all assertions):
420 //
421 // prompt> 210-Evt-EventListeners --reporter compact --success
422 // result omitted for brevity.
423