3 * Copyright (C) 2004 Zack Rusin <zack@kde.org>
4 * Copyright (C) 2005 Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include <QtCore/QRegExp>
35 #include <QtCore/QDir>
36 #include <QtCore/QMetaEnum>
39 #include <klibloader.h>
41 #include <kstandarddirs.h>
47 Runner
*Runner::s_self
= 0L;
48 bool Runner::s_debugCapturingEnabled
= false;
50 void Runner::registerTester(const char *name
, Tester
*test
)
52 Runner::self()->m_registry
.insert(name
, test
);
55 void Runner::loadModules(const QString
&folder
, const QString
&query
)
57 QRegExp
reQuery(query
);
58 QDir
dir(folder
, "kunittest_*.la");
60 // Add the folder to the "module" resource such that the KLibLoader can
61 // find the modules in this folder.
62 KGlobal::dirs()->addResourceDir("module", folder
);
63 kDebug() << "Looking in folder: " << dir
.absolutePath();
65 // Get a list of all modules.
66 QStringList modules
= dir
.entryList();
68 for ( int i
= 0; i
< modules
.count(); ++i
)
70 QString module
= modules
[i
];
71 kDebug() << "Module: " << dir
.absolutePath() + '/' + module
;
73 if ( reQuery
.indexIn(module
) != -1 )
75 // strip the .la extension
76 module
.truncate(module
.length()-3);
77 KPluginLoader
loader(module
.toLocal8Bit());
78 KPluginFactory
*factory
= loader
.factory();
80 factory
->create
<QObject
>();
82 kWarning() << "\tError loading " << module
<< " : " << loader
.errorString();
87 kDebug() << "\tModule doesn't match.";
91 void Runner::setDebugCapturingEnabled(bool enabled
)
93 s_debugCapturingEnabled
= enabled
;
96 //RegistryType &Runner::registry()
97 Registry
&Runner::registry()
102 int Runner::numberOfTestCases()
104 return m_registry
.count();
107 Runner
*Runner::self()
110 s_self
= new Runner();
121 int Runner::numberOfTests() const
126 int Runner::numberOfPassedTests() const
131 int Runner::numberOfFailedTests() const
136 int Runner::numberOfExpectedFailures() const
141 int Runner::numberOfSkippedTests() const
143 return globalSkipped
;
156 int Runner::runTests()
165 cout
<< "# Running normal tests... #" << endl
<< endl
;
167 Registry::const_iterator it
= m_registry
.constBegin();
168 for( ; it
!= m_registry
.constEnd(); ++it
)
169 runTest( it
.key( ) );
171 #if 0 // very thorough, but not very readable
172 cout
<< "# Done with normal tests:" << endl
;
173 cout
<< " Total test cases: " << m_registry
.count() << endl
;
174 cout
<< " Total test steps : " << globalSteps
<< endl
;
175 cout
<< " Total passed test steps (including unexpected) : " << globalPasses
<< endl
;
176 cout
<< " Total unexpected passed test steps : " << globalXPasses
<< endl
;
177 cout
<< " Total failed test steps (including expected) : " << globalFails
<< endl
;
178 cout
<< " Total expected failed test steps : " << globalXFails
<< endl
;
179 cout
<< " Total skipped test steps : " << globalSkipped
<< endl
;
181 unsigned int numTests
= m_registry
.count(); // should this be globalSteps instead?
183 if ( globalFails
== 0 )
184 if ( globalXFails
== 0 )
185 str
= QString( "All %1 tests passed" ).arg( numTests
);
187 str
= QString( "All %1 tests behaved as expected (%2 expected failures)" ).arg( numTests
).arg( globalXFails
);
189 if ( globalXPasses
== 0 )
190 str
= QString( "%1 of %2 tests failed" ).arg( globalFails
).arg( numTests
);
192 str
= QString( "%1 of %2 tests did not behave as expected (%1 unexpected passes)" ).arg( globalFails
).arg( numTests
).arg( globalXPasses
);
194 str
+= QString( " (%1 tests skipped)" ).arg( globalSkipped
);
195 cout
<< str
.toLocal8Bit().constData() << endl
;
198 return m_registry
.count();
201 void Runner::runMatchingTests(const QString
&prefix
)
203 Registry::const_iterator it
= m_registry
.constBegin();
204 for( ; it
!= m_registry
.constEnd(); ++it
)
205 if ( QString( it
.key() ).startsWith(prefix
) )
209 void Runner::runTest(const char *name
)
211 Tester
*test
= m_registry
.value( name
);
214 if ( s_debugCapturingEnabled
)
216 cout
<< "KUnitTest_Debug_Start[" << name
<< "]" << endl
;
219 test
->results()->clear();
222 if ( s_debugCapturingEnabled
)
224 cout
<< "KUnitTest_Debug_End[" << name
<< "]" << endl
<< endl
<< flush
;
233 if ( test
->inherits("KUnitTest::SlotTester") )
235 SlotTester
*sltest
= static_cast<SlotTester
*>(test
);
236 foreach( TestResults
* res
, sltest
->resultsList() )
238 numPass
+= res
->passed() + res
->xpasses();
239 numFail
+= res
->errors() + res
->xfails();
240 numXFail
+= res
->xfails();
241 numXPass
+= res
->xpasses();
242 numSkip
+= res
->skipped();
243 globalSteps
+= res
->testsFinished();
248 numPass
= test
->results()->passed() + test
->results()->xpasses();
249 numFail
= test
->results()->errors() + test
->results()->xfails();
250 numXFail
= test
->results()->xfails();
251 numXPass
= test
->results()->xpasses();
252 numSkip
= test
->results()->skipped();
253 globalSteps
+= test
->results()->testsFinished();
257 globalPasses
+= numPass
;
258 globalFails
+= numFail
;
259 globalXFails
+= numXFail
;
260 globalXPasses
+= numXPass
;
261 globalSkipped
+= numSkip
;
263 cout
<< name
<< " - ";
264 cout
<< numPass
<< " test" << ( ( 1 == numPass
)?"":"s") << " passed";
265 if ( 0 < test
->results()->xpassList().count() ) {
266 cout
<< " (" << numXPass
<< " unexpected pass" << ( ( 1 == numXPass
)?"":"es") << ")";
268 cout
<< ", " << numFail
<< " test" << ( ( 1 == numFail
)?"":"s") << " failed";
269 if ( 0 < numXFail
) {
270 cout
<< " (" << numXFail
<< " expected failure" << ( ( 1 == numXFail
)?"":"s") << ")";
273 cout
<< "; also " << numSkip
<< " skipped";
277 if ( 0 < numXPass
) {
278 cout
<< " Unexpected pass" << ( ( 1 == numXPass
)?"":"es") << ":" << endl
;
279 QStringList list
= test
->results()->xpassList();
280 for ( QStringList::Iterator itr
= list
.begin(); itr
!= list
.end(); ++itr
) {
281 cout
<< "\t" << (*itr
).toLatin1().constData() << endl
;
284 if ( 0 < (numFail
- numXFail
) ) {
285 cout
<< " Unexpected failure" << ( ( 1 == numFail
)?"":"s") << ":" << endl
;
286 QStringList list
= test
->results()->errorList();
287 for ( QStringList::Iterator itr
= list
.begin(); itr
!= list
.end(); ++itr
) {
288 cout
<< "\t" << (*itr
).toLatin1().constData() << endl
;
291 if ( 0 < numXFail
) {
292 cout
<< " Expected failure" << ( ( 1 == numXFail
)?"":"s") << ":" << endl
;
293 QStringList list
= test
->results()->xfailList();
294 for ( QStringList::Iterator itr
= list
.begin(); itr
!= list
.end(); ++itr
) {
295 cout
<< "\t" << (*itr
).toLatin1().constData() << endl
;
299 cout
<< " Skipped test" << ( ( 1 == numSkip
)?"":"s") << ":" << endl
;
300 QStringList list
= test
->results()->skipList();
301 for ( QStringList::Iterator itr
= list
.begin(); itr
!= list
.end(); ++itr
) {
302 cout
<< "\t" << (*itr
).toLatin1().constData() << endl
;
307 emit
finished(name
, test
);
311 #include "runner.moc"