aboutsummaryrefslogtreecommitdiff
path: root/src/stable/unitsuite.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/stable/unitsuite.cpp')
-rw-r--r--src/stable/unitsuite.cpp337
1 files changed, 255 insertions, 82 deletions
diff --git a/src/stable/unitsuite.cpp b/src/stable/unitsuite.cpp
index a38c77a..b2544f2 100644
--- a/src/stable/unitsuite.cpp
+++ b/src/stable/unitsuite.cpp
@@ -9,6 +9,7 @@
9#include "bu/file.h" 9#include "bu/file.h"
10#include "bu/sio.h" 10#include "bu/sio.h"
11#include "bu/optparser.h" 11#include "bu/optparser.h"
12#include "bu/json.h"
12#include <stdlib.h> 13#include <stdlib.h>
13#include <time.h> 14#include <time.h>
14 15
@@ -18,28 +19,33 @@ using namespace Bu;
18 19
19Bu::UnitSuite::UnitSuite() : 20Bu::UnitSuite::UnitSuite() :
20 iOptions( 0 ), 21 iOptions( 0 ),
21 iNameWidth( 0 ) 22 pReport( NULL )
22{ 23{
23} 24}
24 25
25Bu::UnitSuite::UnitSuite( int iOptions ) : 26Bu::UnitSuite::UnitSuite( int iOptions ) :
26 iOptions( iOptions ), 27 iOptions( iOptions )
27 iNameWidth( 0 )
28{ 28{
29} 29}
30 30
31Bu::UnitSuite::~UnitSuite() 31Bu::UnitSuite::~UnitSuite()
32{ 32{
33 delete pReport;
33} 34}
34 35
35int Bu::UnitSuite::run( int argc, char *argv[] ) 36int Bu::UnitSuite::run( int argc, char *argv[] )
36{ 37{
37 bool bCleanup = true; 38 bool bCleanup = true;
39 bool bInterop = false;
38 OptParser p; 40 OptParser p;
39 p.addOption( Bu::slot( this, &Bu::UnitSuite::onListCases ), 'l', "list", 41 p.addOption( Bu::slot( this, &Bu::UnitSuite::onListCases ), 'l', "list",
40 "List available test cases." ); 42 "List available test cases." );
43 p.addOption( Bu::slot( this, &Bu::UnitSuite::onPrintName ), "print-name",
44 "Print the internal name of this test suite.");
41 p.addOption( bCleanup, "no-cleanup", "Don't erase temp files."); 45 p.addOption( bCleanup, "no-cleanup", "Don't erase temp files.");
42 p.setOverride( "no-cleanup", false ); 46 p.setOverride( "no-cleanup", false );
47 p.addOption( bInterop, "interop", "Output machine parsable json.");
48 p.setOverride( "interop", true );
43 p.setNonOption( Bu::slot( this, &Bu::UnitSuite::onAddTest ) ); 49 p.setNonOption( Bu::slot( this, &Bu::UnitSuite::onAddTest ) );
44 p.addHelpOption(); 50 p.addHelpOption();
45 p.parse( argc, argv ); 51 p.parse( argc, argv );
@@ -56,108 +62,58 @@ int Bu::UnitSuite::run( int argc, char *argv[] )
56 lTests = lSub; 62 lTests = lSub;
57 } 63 }
58 64
59 int iEPass = 0; 65 if( bInterop )
60 int iEFail = 0; 66 pReport = new ReportJson();
61 int iUPass = 0; 67 else
62 int iUFail = 0; 68 pReport = new ReportConsole();
69 pReport->suiteStarting( *this, lTests );
70
63 for( TestList::iterator i = lTests.begin(); i != lTests.end(); i++ ) 71 for( TestList::iterator i = lTests.begin(); i != lTests.end(); i++ )
64 { 72 {
65 sio << Fmt( iNameWidth+3, Fmt::Left ).fill('.') << i->sName
66 << sio.flush;
67 try 73 try
68 { 74 {
69 iStepCount = -1; 75 iStepCount = -1;
70 iProgress = 0; 76 iProgress = 0;
77 if( pReport )
78 pReport->testStarting( *i );
71 (this->*(i->fTest))(); 79 (this->*(i->fTest))();
72 switch( i->eExpect ) 80 if( pReport )
73 { 81 pReport->testEnded( *i );
74 case expectPass:
75 sio << "pass." << sio.nl;
76 iEPass++;
77 break;
78
79 case expectFail:
80 sio << "unexpected pass." << sio.nl;
81 iUPass++;
82 break;
83 }
84 } 82 }
85 catch( Failed &e ) 83 catch( Failed &e )
86 { 84 {
87 switch( i->eExpect ) 85 if( pReport )
88 { 86 pReport->testEnded( *i, e );
89 case expectPass:
90 sio << "unexpected ";
91 iUFail++;
92 break;
93
94 case expectFail:
95 sio << "expected ";
96 iEFail++;
97 break;
98 }
99 if( e.bFile )
100 {
101 sio << "fail in unitTest(" << e.str << "). (" << e.sFile
102 << ":" << e.nLine << ")." << sio.nl;
103 }
104 else
105 {
106 sio << "fail in unitTest(" << e.str << ")." << sio.nl;
107 }
108 87
109 if( (iOptions & optStopOnError) ) 88 if( (iOptions & optStopOnError) )
89 {
110 return 0; 90 return 0;
91 }
111 } 92 }
112 catch( std::exception &e ) 93 catch( std::exception &e )
113 { 94 {
114 switch( i->eExpect ) 95 if( pReport )
115 { 96 pReport->testException( *i, e );
116 case expectPass:
117 sio << "unexpected ";
118 iUFail++;
119 break;
120
121 case expectFail:
122 sio << "expected ";
123 iEFail++;
124 break;
125 }
126 sio << "fail with unknown exception. what: " << e.what() << sio.nl;
127 97
128 if( (iOptions & optStopOnError) ) 98 if( (iOptions & optStopOnError) )
99 {
129 return 0; 100 return 0;
101 }
130 } 102 }
131 catch( ... ) 103 catch( ... )
132 { 104 {
133 switch( i->eExpect )
134 {
135 case expectPass:
136 sio << "unexpected ";
137 iUFail++;
138 break;
139
140 case expectFail:
141 sio << "expected ";
142 iEFail++;
143 break;
144 }
145 sio << "fail with external exception." << sio.nl; 105 sio << "fail with external exception." << sio.nl;
106 return -1;
146 107
147 if( (iOptions & optStopOnError) ) 108 if( (iOptions & optStopOnError) )
109 {
148 return 0; 110 return 0;
111 }
149 } 112 }
150 } 113 }
151 114
152 sio << sio.nl 115 if( pReport )
153 << "Report:" << sio.nl 116 pReport->suiteEnded();
154 << "\tTotal tests run: " << lTests.getSize() << sio.nl
155 << "\tExpected passes: " << iEPass << sio.nl
156 << "\tExpected failures: " << iEFail << sio.nl
157 << "\tUnexpected passes: " << iUPass << sio.nl
158 << "\tUnexpected failures: " << iUFail << sio.nl << sio.nl;
159 if( iUPass == 0 && iUFail == 0 )
160 sio << "\tNothing unexpected." << sio.nl << sio.nl;
161 117
162 if( bCleanup ) 118 if( bCleanup )
163 { 119 {
@@ -165,6 +121,8 @@ int Bu::UnitSuite::run( int argc, char *argv[] )
165 { 121 {
166 unlink( (*i).getStr() ); 122 unlink( (*i).getStr() );
167 } 123 }
124
125 cleanup();
168 } 126 }
169 127
170 return 0; 128 return 0;
@@ -191,8 +149,6 @@ void Bu::UnitSuite::add( Test fTest, const Bu::String &sName, Expect e )
191 } 149 }
192 ti.fTest = fTest; 150 ti.fTest = fTest;
193 lTests.append( ti ); 151 lTests.append( ti );
194 if( iNameWidth < ti.sName.getSize() )
195 iNameWidth = ti.sName.getSize();
196} 152}
197 153
198void Bu::UnitSuite::setName( const String &sName ) 154void Bu::UnitSuite::setName( const String &sName )
@@ -200,12 +156,21 @@ void Bu::UnitSuite::setName( const String &sName )
200 sSuiteName = sName; 156 sSuiteName = sName;
201} 157}
202 158
159Bu::String Bu::UnitSuite::getName() const
160{
161 return sSuiteName;
162}
163
164void Bu::UnitSuite::cleanup()
165{
166}
167
203void Bu::UnitSuite::dispProgress() 168void Bu::UnitSuite::dispProgress()
204{ 169{
205 if( tLastUpdate == time( NULL ) ) 170 if( tLastUpdate == time( NULL ) )
206 return; 171 return;
207 sio << Fmt(3) << (iProgress*100/iStepCount) << "%" << "\b\b\b\b" 172 if( pReport )
208 << sio.flush; 173 pReport->updateProgress( iProgress, iStepCount );
209 tLastUpdate = time( NULL ); 174 tLastUpdate = time( NULL );
210} 175}
211 176
@@ -251,6 +216,13 @@ int Bu::UnitSuite::onListCases( StrArray )
251 return 0; 216 return 0;
252} 217}
253 218
219int Bu::UnitSuite::onPrintName( StrArray )
220{
221 Bu::println("%1").arg( sSuiteName );
222 exit( 0 );
223 return 0;
224}
225
254int Bu::UnitSuite::onAddTest( StrArray aParam ) 226int Bu::UnitSuite::onAddTest( StrArray aParam )
255{ 227{
256 hSelTests.insert( aParam[0], true ); 228 hSelTests.insert( aParam[0], true );
@@ -262,12 +234,213 @@ Bu::Formatter &Bu::operator<<( Bu::Formatter &f, const Bu::UnitSuite::Expect &e
262 switch( e ) 234 switch( e )
263 { 235 {
264 case Bu::UnitSuite::expectPass: 236 case Bu::UnitSuite::expectPass:
265 return f << "expect pass"; 237 return f << "pass";
266 238
267 case Bu::UnitSuite::expectFail: 239 case Bu::UnitSuite::expectFail:
268 return f << "expect fail"; 240 return f << "fail";
269 } 241 }
270 242
271 return f << "**error**"; 243 return f << "**error**";
272} 244}
273 245
246/////////
247// Bu::UnitSuite::Report
248////
249
250Bu::UnitSuite::Report::Report()
251{
252}
253
254Bu::UnitSuite::Report::~Report()
255{
256}
257
258/////////
259// Bu::UnitSuite::ReportConsole
260////
261
262Bu::UnitSuite::ReportConsole::ReportConsole() :
263 iTestCount( 0 ),
264 iNameWidth( 0 ),
265 iEPass( 0 ),
266 iEFail( 0 ),
267 iUPass( 0 ),
268 iUFail( 0 )
269{
270}
271
272Bu::UnitSuite::ReportConsole::~ReportConsole()
273{
274}
275
276void Bu::UnitSuite::ReportConsole::suiteStarting( const UnitSuite & /*rSuite*/,
277 const TestList &lTests )
278{
279 iTestCount = lTests.getSize();
280 for( TestList::const_iterator i = lTests.begin(); i; i++ )
281 {
282 if( iNameWidth < i->sName.getSize() )
283 iNameWidth = i->sName.getSize();
284 }
285}
286
287void Bu::UnitSuite::ReportConsole::testStarting( const TestInfo &rTest )
288{
289 sio << Fmt( iNameWidth+3, Fmt::Left ).fill('.') << rTest.sName
290 << sio.flush;
291}
292
293void Bu::UnitSuite::ReportConsole::updateProgress( int iProgress,
294 int iStepCount )
295{
296 sio << Fmt(3) << (iProgress*100/iStepCount) << "%" << "\b\b\b\b"
297 << sio.flush;
298}
299
300void Bu::UnitSuite::ReportConsole::testEnded( const TestInfo &rTest )
301{
302 switch( rTest.eExpect )
303 {
304 case expectPass:
305 sio << "pass." << sio.nl;
306 iEPass++;
307 break;
308
309 case expectFail:
310 sio << "unexpected pass." << sio.nl;
311 iUPass++;
312 break;
313 }
314}
315
316void Bu::UnitSuite::ReportConsole::testEnded( const TestInfo &rTest,
317 const Bu::UnitSuite::Failed &rFail )
318{
319 switch( rTest.eExpect )
320 {
321 case expectPass:
322 sio << "unexpected ";
323 iUFail++;
324 break;
325
326 case expectFail:
327 sio << "expected ";
328 iEFail++;
329 break;
330 }
331 if( rFail.bFile )
332 {
333 sio << "fail in unitTest(" << rFail.str << "). (" << rFail.sFile
334 << ":" << rFail.nLine << ")." << sio.nl;
335 }
336 else
337 {
338 sio << "fail in unitTest(" << rFail.str << ")." << sio.nl;
339 }
340}
341
342void Bu::UnitSuite::ReportConsole::testException( const TestInfo &rTest,
343 std::exception &e )
344{
345 switch( rTest.eExpect )
346 {
347 case expectPass:
348 sio << "unexpected ";
349 iUFail++;
350 break;
351
352 case expectFail:
353 sio << "expected ";
354 iEFail++;
355 break;
356 }
357 sio << "fail with unknown exception. what: " << e.what() << sio.nl;
358}
359
360void Bu::UnitSuite::ReportConsole::suiteEnded()
361{
362 sio << sio.nl
363 << "Report:" << sio.nl
364 << "\tTotal tests run: " << iTestCount << sio.nl;
365
366 if( iEPass > 0 )
367 sio << "\tExpected passes: " << iEPass << sio.nl;
368 if( iEFail > 0 )
369 sio << "\tExpected failures: " << iEFail << sio.nl;
370 if( iUPass > 0 )
371 sio << "\tUnexpected passes: " << iUPass << sio.nl;
372 if( iUFail > 0 )
373 sio << "\tUnexpected failures: " << iUFail << sio.nl;
374 sio << sio.nl;
375 if( iUPass == 0 && iUFail == 0 )
376 sio << "\tNothing unexpected." << sio.nl << sio.nl;
377}
378
379
380/////////
381// Bu::UnitSuite::Report
382////
383
384Bu::UnitSuite::ReportJson::ReportJson() :
385 pReport( new Bu::Json( Bu::Json::Object ) )
386{
387}
388
389Bu::UnitSuite::ReportJson::~ReportJson()
390{
391 delete pReport;
392}
393
394void Bu::UnitSuite::ReportJson::suiteStarting( const UnitSuite &rSuite,
395 const TestList & /*lTests*/ )
396{
397 pReport->insert("type", "report");
398 pReport->insert("suite", rSuite.getName() );
399 pReport->insertArray("tests");
400}
401
402void Bu::UnitSuite::ReportJson::testStarting( const TestInfo & )
403{
404}
405
406void Bu::UnitSuite::ReportJson::updateProgress( int, int )
407{
408}
409
410void Bu::UnitSuite::ReportJson::testEnded( const TestInfo &rTest )
411{
412 Bu::Json &rOb = (*pReport)["tests"].appendObject();
413 rOb.insert("name", rTest.sName );
414 rOb.insert("expected", Bu::String("%1").arg( rTest.eExpect ) );
415 rOb.insert("result", "pass");
416}
417
418void Bu::UnitSuite::ReportJson::testEnded( const TestInfo &rTest,
419 const Bu::UnitSuite::Failed &rFail )
420{
421 Bu::Json &rOb = (*pReport)["tests"].appendObject();
422 rOb.insert("name", rTest.sName );
423 rOb.insert("expected", Bu::String("%1").arg( rTest.eExpect ) );
424 rOb.insert("result", "fail");
425 Bu::Json &rFailOb = rOb.insertObject("fail");
426 rFailOb.insert("action", rFail.str );
427 rFailOb.insert("file", rFail.sFile );
428 rFailOb.insert("line", (double)rFail.nLine );
429}
430
431void Bu::UnitSuite::ReportJson::testException( const TestInfo &rTest,
432 std::exception &e )
433{
434 Bu::Json &rOb = (*pReport)["tests"].appendObject();
435 rOb.insert("name", rTest.sName );
436 rOb.insert("expected", Bu::String("%1").arg( rTest.eExpect ) );
437 rOb.insert("result", "fail");
438 Bu::Json &rFail = rOb.insertObject("fail");
439 rFail.insert("what", e.what() );
440}
441
442void Bu::UnitSuite::ReportJson::suiteEnded()
443{
444 Bu::println("%1").arg( pReport->toString() );
445}
446