tester.h
Go to the documentation of this file.
00001 /* 00002 * tester.h 00003 * 00004 * Copyright (C) 2004 Zack Rusin <zack@kde.org> 00005 * Copyright (C) 2005 Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net> 00006 * 00007 * Redistribution and use in source and binary forms, with or without 00008 * modification, are permitted provided that the following conditions 00009 * are met: 00010 * 00011 * 1. Redistributions of source code must retain the above copyright 00012 * notice, this list of conditions and the following disclaimer. 00013 * 2. Redistributions in binary form must reproduce the above copyright 00014 * notice, this list of conditions and the following disclaimer in the 00015 * documentation and/or other materials provided with the distribution. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00018 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00019 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 00020 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 00021 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 00022 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00023 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00024 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00025 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 00026 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00027 */ 00028 00029 #ifndef TESTER_H 00030 #define TESTER_H 00031 00325 #include <iostream> 00326 using namespace std; 00327 00328 #include <qobject.h> 00329 #include <qstringlist.h> 00330 #include <qasciidict.h> 00331 00332 #include <kdelibs_export.h> 00333 00339 #define CHECK( x, y ) check( __FILE__, __LINE__, #x, x, y, false ) 00340 00342 #define COMPARE CHECK 00343 00345 #define VERIFY( x ) CHECK( x, true ) 00346 00355 #define XFAIL( x, y ) check( __FILE__, __LINE__, #x, x, y, true ) 00356 00362 #define SKIP( x ) skip( __FILE__, __LINE__, QString::fromLatin1(#x)) 00363 00371 #define CHECK_EXCEPTION(exceptionCatch, expression) \ 00372 try \ 00373 { \ 00374 expression; \ 00375 } \ 00376 catch(exceptionCatch) \ 00377 { \ 00378 setExceptionRaised(true); \ 00379 } \ 00380 if(exceptionRaised()) \ 00381 { \ 00382 success(QString(__FILE__) + "[" + QString::number(__LINE__) + "]: passed " + #expression); \ 00383 } \ 00384 else \ 00385 { \ 00386 failure(QString(__FILE__) + "[" + QString::number(__LINE__) + QString("]: failed to throw " \ 00387 "an exception on: ") + #expression); \ 00388 } \ 00389 setExceptionRaised(false); 00390 00395 #define XFAIL_EXCEPTION(exceptionCatch, expression) \ 00396 try \ 00397 { \ 00398 expression; \ 00399 } \ 00400 catch(exceptionCatch) \ 00401 { \ 00402 setExceptionRaised(true); \ 00403 } \ 00404 if(exceptionRaised()) \ 00405 { \ 00406 unexpectedSuccess(QString(__FILE__) + "[" + QString::number(__LINE__) + "]: unexpectedly threw an exception and passed: " + #expression); \ 00407 }\ 00408 else \ 00409 { \ 00410 expectedFailure(QString(__FILE__) + "[" + QString::number(__LINE__) + QString("]: failed to throw an exception on: ") + #expression); \ 00411 } \ 00412 setExceptionRaised(false); 00413 00419 #define SKIP_EXCEPTION(exceptionCatch, expression) \ 00420 skip( __FILE__, __LINE__, QString("Exception catch: ")\ 00421 .arg(QString(#exceptionCatch)).arg(QString(" Test expression: ")).arg(QString(#expression))) 00422 00426 namespace KUnitTest 00427 { 00432 class KUNITTEST_EXPORT TestResults 00433 { 00434 friend class Tester; 00435 00436 public: 00437 TestResults() : m_tests( 0 ) {} 00438 00439 virtual ~TestResults() {} 00440 00443 virtual void clear() 00444 { 00445 m_errorList.clear(); 00446 m_xfailList.clear(); 00447 m_xpassList.clear(); 00448 m_skipList.clear(); 00449 m_successList.clear(); 00450 m_debug = ""; 00451 m_tests = 0; 00452 } 00453 00457 virtual void addDebugInfo(const QString &debug) 00458 { 00459 m_debug += debug; 00460 } 00461 00464 QString debugInfo() const { return m_debug; } 00465 00467 int testsFinished() const { return m_tests; } 00468 00470 int errors() const { return m_errorList.count(); } 00471 00473 int xfails() const { return m_xfailList.count(); } 00474 00476 int xpasses() const { return m_xpassList.count(); } 00477 00479 int skipped() const { return m_skipList.count(); } 00480 00482 int passed() const { return m_successList.count(); } 00483 00485 QStringList errorList() const { return m_errorList; } 00486 00488 QStringList xfailList() const { return m_xfailList; } 00489 00491 QStringList xpassList() const { return m_xpassList; } 00492 00494 QStringList skipList() const { return m_skipList; } 00495 00497 QStringList successList() const { return m_successList; } 00498 00499 private: 00500 QStringList m_errorList; 00501 QStringList m_xfailList; 00502 QStringList m_xpassList; 00503 QStringList m_skipList; 00504 QStringList m_successList; 00505 QString m_debug; 00506 int m_tests; 00507 }; 00508 00509 typedef QAsciiDict<TestResults> TestResultsListType; 00510 00512 typedef QAsciiDictIterator<TestResults> TestResultsListIteratorType; 00513 00522 class KUNITTEST_EXPORT Tester : public QObject 00523 { 00524 public: 00525 Tester(const char *name = 0L) 00526 : QObject(0L, name), m_results(new TestResults()), m_exceptionState(false) 00527 {} 00528 00529 virtual ~Tester() { delete m_results; } 00530 00531 public: 00534 virtual void allTests() = 0; 00535 00536 public: 00539 virtual TestResults *results() { return m_results; } 00540 00541 protected: 00547 void skip( const char *file, int line, QString msg ) 00548 { 00549 QString skipEntry; 00550 QTextStream ts( &skipEntry, IO_WriteOnly ); 00551 ts << file << "["<< line <<"]: " << msg; 00552 skipTest( skipEntry ); 00553 } 00554 00563 template<typename T> 00564 void check( const char *file, int line, const char *str, 00565 const T &result, const T &expectedResult, 00566 bool expectedFail ) 00567 { 00568 cout << "check: " << file << "["<< line <<"]" << endl; 00569 00570 if ( result != expectedResult ) 00571 { 00572 QString error; 00573 QTextStream ts( &error, IO_WriteOnly ); 00574 ts << file << "["<< line <<"]: failed on \"" << str 00575 <<"\" result = '" << result << "' expected = '" << expectedResult << "'"; 00576 00577 if ( expectedFail ) 00578 expectedFailure( error ); 00579 else 00580 failure( error ); 00581 00582 } 00583 else 00584 { 00585 // then the test passed, but we want to record it if 00586 // we were expecting a failure 00587 if (expectedFail) 00588 { 00589 QString err; 00590 QTextStream ts( &err, IO_WriteOnly ); 00591 ts << file << "["<< line <<"]: " 00592 <<" unexpectedly passed on \"" 00593 << str <<"\""; 00594 unexpectedSuccess( err ); 00595 } 00596 else 00597 { 00598 QString succ; 00599 QTextStream ts( &succ, IO_WriteOnly ); 00600 ts << file << "["<< line <<"]: " 00601 <<" passed \"" 00602 << str <<"\""; 00603 success( succ ); 00604 } 00605 } 00606 00607 ++m_results->m_tests; 00608 } 00609 00617 void success(const QString &message) { m_results->m_successList.append(message); } 00618 00626 void failure(const QString &message) { m_results->m_errorList.append(message); } 00627 00635 void expectedFailure(const QString &message) { m_results->m_xfailList.append(message); } 00636 00644 void unexpectedSuccess(const QString &message) { m_results->m_xpassList.append(message); } 00645 00653 void skipTest(const QString &message) { m_results->m_skipList.append(message); } 00654 00662 void setExceptionRaised(bool state) { m_exceptionState = state; } 00663 00669 bool exceptionRaised() const 00670 { 00671 return m_exceptionState; 00672 } 00673 00674 protected: 00675 TestResults *m_results; 00676 00677 private: 00678 00679 bool m_exceptionState; 00680 }; 00681 00686 class KUNITTEST_EXPORT SlotTester : public Tester 00687 { 00688 Q_OBJECT 00689 00690 public: 00691 SlotTester(const char *name = 0L); 00692 00693 void allTests(); 00694 00695 TestResults *results(const char *sl); 00696 00697 TestResultsListType &resultsList() { return m_resultsList; } 00698 00699 signals: 00700 void invoke(); 00701 00702 private: 00703 void invokeMember(const QString &str); 00704 00705 TestResultsListType m_resultsList; 00706 TestResults *m_total; 00707 }; 00708 } 00709 00710 KUNITTEST_EXPORT QTextStream& operator<<( QTextStream& str, const QRect& r ); 00711 00712 KUNITTEST_EXPORT QTextStream& operator<<( QTextStream& str, const QPoint& r ); 00713 00714 KUNITTEST_EXPORT QTextStream& operator<<( QTextStream& str, const QSize& r ); 00715 00716 #endif