FreeCAD / src /Mod /Test /Gui /UnitTestImp.cpp
AbdulElahGwaith's picture
Upload folder using huggingface_hub
985c397 verified
/***************************************************************************
* Copyright (c) 2006 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "FCGlobal.h"
#include <QFontMetrics>
#include <QMessageBox>
#include <QClipboard>
#include <QApplication>
#include <Base/Interpreter.h>
#include <Gui/MainWindow.h>
#include "UnitTestImp.h"
#include "ui_UnitTest.h"
using namespace TestGui;
/* TRANSLATOR TestGui::UnitTestDialog */
UnitTestDialog* UnitTestDialog::_instance = nullptr;
/**
* Creates and returns the one and only instance of this dialog.
*/
UnitTestDialog* UnitTestDialog::instance()
{
// not initialized?
if (!_instance) {
_instance = new UnitTestDialog(Gui::getMainWindow());
}
return _instance;
}
/**
* Destructs the instance of this dialog.
*/
void UnitTestDialog::destruct()
{
if (_instance) {
UnitTestDialog* pTmp = _instance;
_instance = nullptr;
delete pTmp;
}
}
/**
* Returns \a true if an instance of this dialog exists, \a false otherwise.
*/
bool UnitTestDialog::hasInstance()
{
return _instance != nullptr;
}
/**
* Constructs a TestGui::UnitTestDialog as a child of 'parent', with the
* name 'name' and widget flags set to 'f'.
*
* The dialog will by default be modeless, unless you set 'modal' to
* true to construct a modal dialog.
*/
UnitTestDialog::UnitTestDialog(QWidget* parent, Qt::WindowFlags f)
: QDialog(parent, f)
, ui(new Ui_UnitTest)
{
ui->setupUi(this);
setupConnections();
setProgressColor(QColor(40, 210, 43)); // a darker green
ui->progressBar->setAlignment(Qt::AlignCenter);
// red items
QPalette palette;
palette.setColor(ui->treeViewFailure->foregroundRole(), Qt::red);
ui->treeViewFailure->setPalette(palette);
}
/**
* Destroys the object and frees any allocated resources
*/
UnitTestDialog::~UnitTestDialog() = default;
void UnitTestDialog::setupConnections()
{
connect(
ui->treeViewFailure,
&QTreeWidget::itemDoubleClicked,
this,
&UnitTestDialog::onTreeViewFailureItemDoubleClicked
);
connect(ui->helpButton, &QPushButton::clicked, this, &UnitTestDialog::onHelpButtonClicked);
connect(ui->aboutButton, &QPushButton::clicked, this, &UnitTestDialog::onAboutButtonClicked);
connect(ui->copyButton, &QPushButton::clicked, this, &UnitTestDialog::onCopyButtonClicked);
connect(ui->startButton, &QPushButton::clicked, this, &UnitTestDialog::onStartButtonClicked);
}
/**
* Sets the color to the progressbar to \a col.
*/
void UnitTestDialog::setProgressColor(const QColor& col)
{
QString qss = QStringLiteral(
"QProgressBar {\n"
" border: 2px solid grey;\n"
" border-radius: 5px;\n"
"}\n"
"\n"
"QProgressBar::chunk {\n"
" background-color: %1;\n"
"}"
)
.arg(col.name());
ui->progressBar->setStyleSheet(qss);
}
/**
* Opens a dialog to display a detailed description about the error.
*/
void UnitTestDialog::onTreeViewFailureItemDoubleClicked(QTreeWidgetItem* item, int column)
{
Q_UNUSED(column);
QString text = item->data(0, Qt::UserRole).toString();
QMessageBox msgBox(this);
msgBox.setIcon(QMessageBox::Information);
msgBox.setWindowTitle(item->text(0));
msgBox.setDetailedText(text);
// truncate the visible text when it's too long
if (text.count(QLatin1Char('\n')) > 20) {
QStringList lines = text.split(QLatin1Char('\n'));
lines.erase(lines.begin() + 20, lines.end());
text = lines.join(QLatin1String("\n"));
}
if (text.size() > 1000) {
text = text.left(1000);
}
msgBox.setText(text);
msgBox.exec();
}
/**
* Shows the help dialog.
*/
void UnitTestDialog::onHelpButtonClicked()
{
QMessageBox::information(
this,
tr("Help"),
tr("Enter the name of a callable object which, when called, will return a TestCase.\n"
"Click 'start', and the test thus produced will be run.\n\n"
"Double click on an error in the tree view to see more information about it, "
"including the stack trace.")
);
}
/**
* Shows the about dialog.
*/
void UnitTestDialog::onAboutButtonClicked()
{
QMessageBox::information(
this,
tr("About FreeCAD UnitTest"),
tr("Copyright (c) Werner Mayer\n\n"
"FreeCAD UnitTest is part of FreeCAD and supports writing Unit Tests for "
"ones own modules.")
);
}
void UnitTestDialog::onCopyButtonClicked()
{
QString text;
QTreeWidgetItemIterator it(ui->treeViewFailure);
while (*it) {
text += (*it)->data(0, Qt::UserRole).toString() + QStringLiteral("\n\n");
++it;
}
if (text.isEmpty()) {
return;
}
QApplication::clipboard()->setText(text);
setStatusText(tr("Errors copied to clipboard"));
}
/**
* Runs the unit tests.
*/
void UnitTestDialog::onStartButtonClicked()
{
reset();
setProgressColor(QColor(40, 210, 43)); // a darker green
ui->startButton->setDisabled(true);
try {
Base::Interpreter().runString(
"import qtunittest, gc\n"
"__qt_test__=qtunittest.QtTestRunner(0,\"\")\n"
"__qt_test__.runClicked()\n"
"del __qt_test__\n"
"gc.collect()\n"
);
}
catch (const Base::PyException& e) {
std::string msg = e.what();
msg += "\n\n";
msg += e.getStackTrace();
showErrorDialog("Exception", msg.c_str());
}
catch (const Base::Exception& e) {
showErrorDialog("Exception", e.what());
}
catch (const std::exception& e) {
showErrorDialog("C++ standard exception", e.what());
}
catch (...) {
showErrorDialog("Unknown exception", "Unknown exception raised");
}
ui->startButton->setEnabled(true);
}
/**
* Shows an error dialog with \a title and \a message.
*/
void UnitTestDialog::showErrorDialog(const char* title, const char* message)
{
QMessageBox::critical(this, QString::fromLatin1(title), QString::fromLatin1(message));
}
/**
* Closes and resets this dialog.
*/
void UnitTestDialog::reject()
{
reset();
QDialog::reject();
}
/**
* Resets this dialog.
*/
void UnitTestDialog::reset()
{
ui->progressBar->reset();
ui->treeViewFailure->clear();
ui->textLabelRunCt->setText(QStringLiteral("<font color=\"#0000ff\">0</font>"));
ui->textLabelFailCt->setText(QStringLiteral("<font color=\"#0000ff\">0</font>"));
ui->textLabelErrCt->setText(QStringLiteral("<font color=\"#0000ff\">0</font>"));
ui->textLabelRemCt->setText(QStringLiteral("<font color=\"#0000ff\">0</font>"));
}
/**
* Adds a unit test. If a test with name \a unit already is added then nothing happens.
*/
void UnitTestDialog::addUnitTest(const QString& unit)
{
int ct = ui->comboTests->count();
for (int i = 0; i < ct; i++) {
if (ui->comboTests->itemText(i) == unit) {
return;
}
}
ui->comboTests->addItem(unit);
}
/**
* Sets the unit test. If the item is not there yet it gets added.
*/
void UnitTestDialog::setUnitTest(const QString& unit)
{
addUnitTest(unit);
for (int i = 0; i < ui->comboTests->count(); i++) {
if (ui->comboTests->itemText(i) == unit) {
ui->comboTests->setCurrentIndex(i);
break;
}
}
}
/**
* Clears the unit tests.
*/
void UnitTestDialog::clearUnitTests()
{
ui->comboTests->clear();
}
/**
* Returns the unit test.
*/
QString UnitTestDialog::getUnitTest() const
{
return ui->comboTests->currentText();
}
/**
* Runs the currently selected test and closes the dialog afterwards.
* It returns true if all tests have passed and false otherwise.
*/
bool UnitTestDialog::runCurrentTest()
{
clearErrorList();
onStartButtonClicked();
int count = ui->treeViewFailure->topLevelItemCount();
reject();
return (count == 0);
}
/**
* Sets the text in the status bar.
*/
void UnitTestDialog::setStatusText(const QString& text)
{
QFontMetrics fm(font());
int labelWidth = ui->textLabelStatus->width() - 10;
ui->textLabelStatus->setText(fm.elidedText(text, Qt::ElideMiddle, labelWidth));
}
/**
* Sets the progress of the progress bar whereas fraction is in between 0.0 and 1.0.
* It also sets the color of the progress bar to red if a failure or error in the unit
* test occurred.
*/
void UnitTestDialog::setProgressFraction(float fraction, const QString& color)
{
if (fraction == 0.0f) {
ui->progressBar->setRange(0, 100);
}
else {
if (color == QLatin1String("red")) {
setProgressColor(Qt::red);
}
ui->progressBar->setValue((int)(100 * fraction));
}
}
/**
* Empties the error listview.
*/
void UnitTestDialog::clearErrorList()
{
ui->treeViewFailure->clear();
}
/**
* Inserts an item with text \a failure to the listview. \a details will be shown
* when double-clicking on the matching listitem.
*/
void UnitTestDialog::insertError(const QString& failure, const QString& details)
{
QTreeWidgetItem* item = new QTreeWidgetItem(ui->treeViewFailure);
item->setText(0, failure);
item->setForeground(0, Qt::red);
item->setData(0, Qt::UserRole, QVariant(details));
}
/**
* Sets the number of performed tests to \a ct.
*/
void UnitTestDialog::setRunCount(int ct)
{
ui->textLabelRunCt->setText(QStringLiteral("<font color=\"#0000ff\">%1</font>").arg(ct));
}
/**
* Sets the number of failed tests to \a ct.
*/
void UnitTestDialog::setFailCount(int ct)
{
ui->textLabelFailCt->setText(QStringLiteral("<font color=\"#0000ff\">%1</font>").arg(ct));
}
/**
* Sets the number of faulty tests to \a ct.
*/
void UnitTestDialog::setErrorCount(int ct)
{
ui->textLabelErrCt->setText(QStringLiteral("<font color=\"#0000ff\">%1</font>").arg(ct));
}
/**
* Sets the number of remaining tests to \a ct.
*/
void UnitTestDialog::setRemainCount(int ct)
{
ui->textLabelRemCt->setText(QStringLiteral("<font color=\"#0000ff\">%1</font>").arg(ct));
}
#include "moc_UnitTestImp.cpp"