You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdesdk/kunittest/runnergui.cpp

434 lines
15 KiB

/**
* Copyright (C) 2005 Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <tqmetaobject.h>
#include <tqregexp.h>
#include <tqpushbutton.h>
#include <tqtextedit.h>
#include <tqlabel.h>
#include <tqprogressbar.h>
#include <tqcombobox.h>
#include <dcopclient.h>
#include <dcopobject.h>
#include <kiconloader.h>
#include <kdebug.h>
#include <kmessagebox.h>
#include <kunittest/tester.h>
#include "dcopinterface.h"
#include "runnergui.h"
#include "testerwidget.h"
namespace KUnitTest
{
const int g_nameColumn = 0;
const int g_finishedColumn = 1;
const int g_skippedColumn = 2;
const int g_failedColumn = 3;
const int g_xfailedColumn = 4;
const int g_passedColumn = 5;
const int g_xpassedColumn = 6;
/*! The DCOP implementation for the RunnerGUI.
*/
class RunnerGUIDCOPImpl : virtual public DCOPInterface
{
public:
RunnerGUIDCOPImpl(RunnerGUI *rg) : m_rg(rg)
{
// set the DCOP object id
setObjId("Runner");
}
/*! This DCOP method adds debug info to a given test case.
* @param name The name of the test.
* @param info The debug info.
*/
bool addDebugInfo(const TQString &name, const TQString &info)
{
Tester *tester = Runner::self()->registry().find(name.local8Bit());
if ( tester == 0L ) return false;
tester->results()->addDebugInfo(info);
return true;
}
bool addSlotDebugInfo(const TQString &name, const TQString &slt, const TQString &info)
{
Tester *tester = Runner::self()->registry().find(name.local8Bit());
if ( tester == 0L ) return false;
if ( ! tester->inherits("KUnitTest::SlotTester") ) return false;
SlotTester *sltester = static_cast<SlotTester*>(tester);
sltester->results(slt.local8Bit())->addDebugInfo(info);
return true;
}
private:
RunnerGUI *m_rg;
};
RunnerGUI::RunnerGUI(TQWidget *parent) : TQHBox(parent)
{
m_dcop = new RunnerGUIDCOPImpl(this);
m_testerWidget = new TesterWidget(this);
setGeometry(0, 0, 700, 500);
// file the combo box
m_testerWidget->selectCombo()->insertItem("All suites/modules . . .");
m_testerWidget->selectCombo()->insertItem("Selected tests . . .");
RegistryIteratorType it(Runner::self()->registry());
TQStringList suites;
for ( ; it.current(); ++it )
{
addTester(it.currentKey(), it.current());
TQString test = it.currentKey();
int index = test.find("::");
if ( index != -1 ) test = test.left(index);
if ( suites.contains(test) == 0 )
suites.append(test);
}
for ( uint i = 0; i < suites.count(); ++i )
m_testerWidget->selectCombo()->insertItem(suites[i]);
// configure the resultslist
m_testerWidget->resultList()->setAllColumnsShowFocus(true);
m_testerWidget->resultList()->setSelectionMode(TQListView::Extended);
m_testerWidget->resultList()->setRootIsDecorated(true);
m_testerWidget->resultList()->setColumnAlignment(g_finishedColumn, TQt::AlignHCenter);
m_testerWidget->resultList()->setColumnAlignment(g_skippedColumn, TQt::AlignHCenter);
m_testerWidget->resultList()->setColumnAlignment(g_failedColumn, TQt::AlignHCenter);
m_testerWidget->resultList()->setColumnAlignment(g_xfailedColumn, TQt::AlignHCenter);
m_testerWidget->resultList()->setColumnAlignment(g_passedColumn, TQt::AlignHCenter);
m_testerWidget->resultList()->setColumnAlignment(g_xpassedColumn, TQt::AlignHCenter);
// set the text in the results label
fillResultsLabel();
// init the progress bar
configureProgressBar(Runner::self()->numberOfTestCases(), 0);
connect(Runner::self(), TQT_SIGNAL(finished(const char *, Tester *)), this, TQT_SLOT(addTestResult(const char *, Tester *)));
connect(m_testerWidget->resultList(), TQT_SIGNAL(clicked(TQListViewItem *)), this, TQT_SLOT(showDetails(TQListViewItem *)));
connect(m_testerWidget, TQT_SIGNAL(run()), this, TQT_SLOT(runSuite()));
connect(m_testerWidget->details(), TQT_SIGNAL(doubleClicked(int, int)), this, TQT_SLOT(doubleClickedOnDetails(int, int)));
}
RunnerGUI::~RunnerGUI()
{
delete m_dcop;
}
void RunnerGUI::configureProgressBar(int steps, int progress)
{
m_testerWidget->progressBar()->setTotalSteps(steps);
m_testerWidget->progressBar()->setProgress(progress);
}
void RunnerGUI::fillResultsLabel()
{
if ( Runner::self()->numberOfTests() > 0 )
m_testerWidget->resultsLabel()->setText(
TQString("Test cases: %1 | Tests performed: %5, Skipped: <font color=\"#f7a300\">%4</font> | Passed: <font color=\"#009900\">%2</font>, Failed: <font color=\"#990000\">%3</font>")
.arg(Runner::self()->numberOfTestCases())
.arg(Runner::self()->numberOfPassedTests())
.arg(Runner::self()->numberOfFailedTests())
.arg(Runner::self()->numberOfSkippedTests())
.arg(Runner::self()->numberOfTests()) );
else
m_testerWidget->resultsLabel()->setText(TQString("Test cases: %1").arg(Runner::self()->numberOfTestCases()));
}
void RunnerGUI::addTestResult(const char *name, Tester *test)
{
TQStringList scopes = TQStringList::split("::", name);
TQString suite = scopes[0];
// find the suite item
TQListViewItem *item = 0L;
for ( uint i = 0; i < scopes.count(); ++i )
item = getItem(scopes[i], item);
if ( test->inherits("KUnitTest::SlotTester") )
{
SlotTester *sltest = static_cast<SlotTester*>(test);
TestResultsListIteratorType it(sltest->resultsList());
TQListViewItem *slotItem = 0L;
for ( ; it.current(); ++it)
{
slotItem = getItem(it.currentKey(), item);
setSummary(slotItem, it.current());
}
}
else
setSummary(item, test->results());
fillResultsLabel();
m_testerWidget->progressBar()->setProgress(m_testerWidget->progressBar()->progress() + 1);
}
void RunnerGUI::addTester(const char *name, Tester *test)
{
TQStringList scopes = TQStringList::split("::", name);
TQString suite = scopes[0];
// find the suite item
TQListViewItem *item = 0L;
for ( uint i = 0; i < scopes.count(); ++i )
item = getItem(scopes[i], item);
if ( test->inherits("KUnitTest::SlotTester") )
{
TQStrList allSlots = test->metaObject()->slotNames();
for ( char *sl = allSlots.first(); sl; sl = allSlots.next() )
{
if ( TQString(sl).startsWith("test") )
getItem(sl, item);
}
}
}
TQListViewItem *RunnerGUI::getItem(const TQString &name, TQListViewItem *item /*= 0L*/)
{
TQListViewItem *parent = item;
if ( item == 0L ) item = m_testerWidget->resultList()->firstChild();
else item = item->firstChild();
while ( item && (item->text(g_nameColumn) != name) )
item = item->nextSibling();
// item not found, create it
if ( item == 0L )
{
if ( parent == 0L )
item = new TQListViewItem(m_testerWidget->resultList());
else
item = new TQListViewItem(parent);
item->setText(g_nameColumn, name);
}
return item;
}
void RunnerGUI::reset()
{
TQListViewItemIterator it( m_testerWidget->resultList() );
while ( it.current() )
{
TQListViewItem *item = it.current();
item->setText(g_finishedColumn, "0");
item->setText(g_skippedColumn, "0");
item->setText(g_failedColumn, "0");
item->setText(g_xfailedColumn, "0");
item->setText(g_passedColumn, "0");
item->setText(g_xpassedColumn, "0");
item->setPixmap(g_nameColumn, TQPixmap());
++it;
}
}
void RunnerGUI::setSummary(TQListViewItem *item, TestResults *res)
{
if ( item == 0L ) return;
bool ok;
int val = item->text(g_finishedColumn).toInt(&ok); if (!ok) val = 0;
item->setText(g_finishedColumn, TQString::number(val + res->testsFinished()));
val = item->text(g_skippedColumn).toInt(&ok); if (!ok) val = 0;
item->setText(g_skippedColumn, TQString::number(val + res->skipped()));
val = item->text(g_passedColumn).toInt(&ok); if (!ok) val = 0;
item->setText(g_passedColumn, TQString::number(val + res->passed()));
val = item->text(g_failedColumn).toInt(&ok); if (!ok) val = 0;
item->setText(g_failedColumn, TQString::number(val + res->errors()));
val = item->text(g_xfailedColumn).toInt(&ok); if (!ok) val = 0;
item->setText(g_xfailedColumn, TQString::number(val + res->xfails()));
val = item->text(g_xpassedColumn).toInt(&ok); if (!ok) val = 0;
item->setText(g_xpassedColumn, TQString::number(val + res->xpasses()));
bool passed = (item->text(g_failedColumn).toInt(&ok) + item->text(g_xfailedColumn).toInt(&ok)) == 0;
item->setPixmap(g_nameColumn, passed ? SmallIcon("button_ok") : SmallIcon("button_cancel") );
setSummary(item->parent(), res);
}
TQString RunnerGUI::fullName(TQListViewItem *item)
{
TQString name = item->text(g_nameColumn);
while ( (item = item->parent()) != 0L )
name = item->text(g_nameColumn) + "::" + name;
return name;
}
void RunnerGUI::runSuite()
{
Runner::self()->reset();
reset();
if ( m_testerWidget->selectCombo()->currentItem() == 0 )
{
configureProgressBar(Runner::self()->numberOfTestCases(), 0);
Runner::self()->runTests();
}
else if ( m_testerWidget->selectCombo()->currentItem() == 1 )
{
TQListViewItemIterator it( m_testerWidget->resultList() );
TQStringList prefixes;
while ( it.current() )
{
TQListViewItem *item = it.current();
if ( item->isSelected() )
{
TQString prefix = fullName(item);
if ( prefix.endsWith("()") )
{
int index = prefix.findRev("::");
prefix = prefix.left(index);
}
prefixes << prefix;
}
++it;
}
configureProgressBar(prefixes.count(), 0);
for ( uint i = 0; i < prefixes.count(); ++i )
Runner::self()->runMatchingTests(prefixes[i]);
}
else
{
TQString suite = m_testerWidget->selectCombo()->currentText();
TQStringList tests;
RegistryIteratorType it(Runner::self()->registry());
for ( ; it.current(); ++it )
if ( TQString(it.currentKey()).startsWith(suite) )
tests.append(it.currentKey());
configureProgressBar(tests.count(), 0);
for ( uint i = 0; i < tests.count(); ++i )
Runner::self()->runTest(tests[i].local8Bit());
}
showDetails(m_testerWidget->resultList()->currentItem());
}
void RunnerGUI::showDetails(TQListViewItem *item)
{
if ( item == 0L ) return;
TQString name = fullName(item);
if ( name.endsWith("()") ) name = fullName(item->parent());
Tester *tester = Runner::self()->registry().find(name.local8Bit());
if ( tester == 0L ) return;
TestResults *res = 0L;
if ( tester->inherits("KUnitTest::SlotTester") )
res = static_cast<SlotTester*>(tester)->results(item->text(g_nameColumn).local8Bit());
else
res = tester->results();
if ( tester == 0L )
m_testerWidget->details()->setText("No test found with name: " + fullName(item));
else
{
TQTextEdit *te = m_testerWidget->details();
te->clear();
te->append("<qt><a name=\"errors\"><font color=\"#990000\">Errors</font></a>:<br></qt>");
appendList(te, res->errorList());
te->append("<qt><br><hr><font color=\"#c2c939\">Expected to fail</font>:<br></qt>");
appendList(te, res->xfailList());
te->append("<qt><br><hr><font color=\"#BF00B5\">Unexpected Success</font>:<br></qt>");
appendList(te, res->xpassList());
te->append("<qt><br><hr><font color=\"#009900\">Success</font>:<br></qt>");
appendList(te, res->successList());
te->append("<qt><br><hr><font color=\"#F7A300\">Skipped</font>:<br></qt>");
appendList(te, res->skipList());
te->append("<qt><br><hr><font color=\"#000099\">Debug</font>:<br></qt>");
te->append(res->debugInfo());
te->scrollToAnchor("errors");
}
}
void RunnerGUI::appendList(TQTextEdit *te, const TQStringList &list)
{
for ( uint i = 0; i < list.count(); ++i )
te->append(list[i]);
}
void RunnerGUI::doubleClickedOnDetails(int para, int /*pos*/)
{
static TQRegExp reFileAndLine("^(.*)\\[([0-9]+)\\]:");
TQString line = m_testerWidget->details()->text(para);
m_testerWidget->details()->setSelection(para, 0, para, line.length()-1);
if ( reFileAndLine.search(line) != -1 )
{
DCOPClient client;
client.attach();
TQByteArray data;
TQDataStream arg(data, IO_WriteOnly);
bool ok;
arg << TQString(reFileAndLine.cap(1)) << (reFileAndLine.cap(2).toInt(&ok) - 1);
client.send("kdevelop-*", "KDevPartController", "editDocument(TQString,int)", data);
client.send("kdevelop-*", "MainWindow", "raise()", TQString(""));
client.detach();
}
}
}
#include "runnergui.moc"