Doctest and qapplication - qt

I must integrate doctest lib to a QT core project (Qt5 exactly).
At a point, I need a qcoreapplication to run event loop.
But when I try implement my doctest main with a qcoreapplication it looks doctest context and qcoreapplication parasite themself.
Do there are some workarounds? like qeventloop without qcoreapplication? other ways?
Did someone have already encountered this kind of case with other test libs?
Thanks for answers ;)
Edit 1:
For confidentiality reason i can't share actual base code. But i have same issue with basic code.
At my actual point i fall in an infinite loop at the end of execution.
I may just miss something on QCoreApplication execution end.
#define DOCTEST_CONFIG_IMPLEMENT
#include <QDebug>
#include <QObject>
#include <QSignalSpy>
#include <QApplication>
#include <QEventLoop>
#include "../../Core/external/doctest/doctest.h"
TEST_CASE("Basic class") {
SUBCASE("2*2") {
qDebug()<<"2*2";
CHECK_EQ(2*2, 4);
}
SUBCASE("1+1") {
qDebug()<<"1+1";
CHECK_EQ(1+1, 2);
}
SUBCASE("Termination") {
qDebug()<<"End!!";
QCoreApplication::instance()->quit();
}
}
int main(int argc, char** argv) {
doctest::Context context;
// defaults
context.setOption("abort-after", 5);
context.setOption("order-by", "name");
QCoreApplication app (argc, argv);
context.applyCommandLine(argc, argv);
context.setOption("no-breaks", true);
int res = context.run();
if(context.shouldExit())
return res;
int client_stuff_return_code = 0;
return res + client_stuff_return_code + app.exec(); // the result from doctest is propagated here as well
}

Related

Is there a way to return current viewed page in QPrintPreviewDialog?

I know it is possible with QPrintPreviewWidget via currentPage() function, but is there a way to return current page in QPrintPreviewDialog? Since I like the default QPrintPreviewDialog's interface, and I don't feel confident enough to rebuild it myself, I would like to use QPrintPreviewDialog.
QPrintPreviewDialog is a QDialog that has a QPrintPreviewWidget as internal elements, so using findChild you can obtain that object.
#include <QApplication>
#include <QPrintPreviewDialog>
#include <QPrintPreviewWidget>
#include <QPrinter>
#include <QTimer>
#include <QTextCursor>
#include <QTextDocument>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPrintPreviewDialog previewDialog;
QObject::connect(&previewDialog, &QPrintPreviewDialog::paintRequested, &previewDialog, [&previewDialog](QPrinter *printer){
QTextDocument document;
QTextCursor cursor(&document);
QTextBlockFormat blockFormat;
for(int i=0; i < 10; i++){
cursor.insertBlock(blockFormat);
cursor.insertHtml(QString("<h1>This is the %1 page</h1>").arg(i+1));
blockFormat.setPageBreakPolicy(QTextFormat::PageBreak_AlwaysBefore);
}
document.print(printer);
if(QPrintPreviewWidget *previewWidget = previewDialog.findChild<QPrintPreviewWidget *>()){
qDebug() << previewWidget->currentPage();
// change page
QTimer::singleShot(100, previewWidget, [previewWidget](){
previewWidget->setCurrentPage(2);
});
}
});
previewDialog.exec();
}

SIGABRT in simple message box Qt program

Got an error running the following problem:
#include <QMessageBox>
#include <QApplication>
int main() {
QApplication app();
QMessageBox msgBox(QMessageBox::Critical,
QObject::tr("text1"),
QObject::tr("text2"),
QMessageBox::Ok);
msgBox.exec();
return 0;
}
The error is:
The program breaks at QMessageBox msgBox(...);
The call stack is:
EDIT: Even after i have added QApplication instance in XTerm window named qtcreator_process_stub i see the following:
QWidget: Must construct QApplication before a QWidget
The line
QApplication app();
doesn't create a QApplication object - it actually declares a function taking no arguments and returning a QApplication! This is sometimes known as the "most vexing parse".
To actually construct the application object, you need to provide the program's arguments:
QApplication app(argc, argv);
The full program is then
#include <QMessageBox>
#include <QApplication>
int main(int argc, char **argv) {
QApplication app(argc, argv);
QMessageBox msgBox(QMessageBox::Critical,
QObject::tr("text1"),
QObject::tr("text2"),
QMessageBox::Ok);
msgBox.exec();
return 0;
}

Qt connect - object emits signal before connect is issued

I have following main.cpp:
#include <QtQml>
#include <QApplication>
#include <QQmlApplicationEngine>
#include "database/uepeoplemodel.h"
#include "core/uestatus.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
UeStatus* ueApplicationStatus=new UeStatus(qApp);
UePeopleModel* uePeopleModel=new UePeopleModel(qApp);
QObject::connect(uePeopleModel,
SIGNAL(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)),
ueApplicationStatus,
SLOT(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)));
engine.rootContext()->setContextProperty("uePeopleModel",
uePeopleModel);
engine.rootContext()->setContextProperty("ueApplicationStatus",
ueApplicationStatus);
engine.addImageProvider(QLatin1String("uePeopleModel"),
uePeopleModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
Now, inside main.cpp I create two objects from classes:
UeStatus* ueApplicationStatus=new UeStatus(qApp);
UePeopleModel* uePeopleModel=new UePeopleModel(qApp);
and I connect signal from UePeopleModel to slot in ueApplicationStatus:
QObject::connect(uePeopleModel,
SIGNAL(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)),
ueApplicationStatus,
SLOT(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)));
The problem is when uePeopleModel is created, the signal is emmited inside constructor:
UePeopleModel::UePeopleModel(QObject* parent)
: QSqlQueryModel(parent),
QQuickImageProvider(QQmlImageProviderBase::Image,
QQmlImageProviderBase::ForceAsynchronousImageLoading)
{
if(!QSqlDatabase::connectionNames().contains(UePosDatabase::UeDatabaseConnectionNames::DATABASE_CONNECTION_NAME_PEOPLE,
Qt::CaseInsensitive))
{
this->ueSetDatabase(QSqlDatabase::addDatabase(UePosDatabase::DATABASE_DRIVER,
UePosDatabase::UeDatabaseConnectionNames::DATABASE_CONNECTION_NAME_PEOPLE));
} // if
this->ueDatabase().setHostName(/*this->uePosSettings()->ueDbHostname()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_HOSTNAME);
this->ueDatabase().setDatabaseName(/*this->uePosSettings()->ueDbName()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_NAME);
this->ueDatabase().setUserName(/*this->uePosSettings()->ueDbUser()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_USERNAME);
this->ueDatabase().setPassword(/*this->uePosSettings()->ueDbPassword()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_PASSWORD);
if(this->ueDatabase().open())
{
emit this->ueSignalDatabaseConnectionChanged(CONNECTED);
this->setQuery(UePosDatabase::UeSqlQueries::UeTablePeople::SQL_QUERY_GET_ALL_PEOPLE,
this->ueDatabase());
/*
if(this->lastError().isValid())
qDebug() << this->lastError();
*/
}
else
{
emit this->ueSignalDatabaseConnectionChanged(NOT_CONNECTED);
// qDebug() << this->ueDatabase().lastError();
}
// qDebug() << this->ueDatabase().connectionNames();
} // default constructor
before connect is issued and therfore ueApplicationStatus object does not catch is with slot. Does anyone has idea how to get rid of this situation?
You shouldn't use the constructor to open the connection with the database.
Use the constructor only to instantiate other classes, initialize variables, allocate memory and so on.
In your case, your constructor should be used to initialize the database, but you could create another method with:
if(this->ueDatabase().open())
{
emit this->ueSignalDatabaseConnectionChanged(CONNECTED);
this->setQuery(UePosDatabase::UeSqlQueries::UeTablePeople::SQL_QUERY_GET_ALL_PEOPLE,
this->ueDatabase());
}
else
{
emit this->ueSignalDatabaseConnectionChanged(NOT_CONNECTED);
}
This method would be called after the connect you have in your main.cpp.
I've solved the problem by adding method void ueConnectToDatabase() and moved the content of constructor into it and redefined main.cpp as:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
UeStatus* ueApplicationStatus=new UeStatus(qApp);
UePeopleModel* uePeopleModel=new UePeopleModel(qApp);
QObject::connect(uePeopleModel,
SIGNAL(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)),
ueApplicationStatus,
SLOT(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)));
uePeopleModel->ueConnectToDatabase();
engine.rootContext()->setContextProperty("uePeopleModel",
uePeopleModel);
engine.rootContext()->setContextProperty("ueApplicationStatus",
ueApplicationStatus);
engine.addImageProvider(QLatin1String("uePeopleModel"),
uePeopleModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
Now the object is created, signal and slot connected and AFTER this the connection to database occurs.

QDialog exec() can not exit process

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QDialog dlg;
dlg.exec();
return a.exec();
}
That's all my code, but when I close the window, The process isn't exit, it seems that drop in the loop a.exec().
Generally speaking, calling any exec is a bad idea, other than QCoreApplication::exec() or QDrag::exec(). The presence of exec() and waitForXxx() methods is an enticing trap for the unwary. Those methods are "easy" to use, but that ease comes at a price of hard to track bugs. Don't use them.
You should simply show the dialog:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMessageBox msg;
msg.setText("Hello");
msg.addButton(QMessageBox::Close);
msg.show();
return a.exec();
}
If you wish to wait for the dialog to be accepted or rejected, you should use the dialog's clickedButton slot. QMessageBox has a long-standing bug that makes the accepted and rejected signals useless :(
// https://github.com/KubaO/stackoverflown/tree/master/questions/messagebox-show-25545652
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif
#include <functional>
[...]
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMessageBox msg;
msg.setText("Continue?");
msg.addButton(QMessageBox::Yes);
msg.addButton(QMessageBox::No);
auto onClick = [&msg]() {
auto role = msg.buttonRole(msg.clickedButton());
if (role == QMessageBox::NoRole)
QApplication::quit();
if (role == QMessageBox::YesRole) {
auto label = new QLabel("I'm running");
label->setAttribute(Qt::WA_DeleteOnClose);
label->show();
}
};
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
QObject::connect(&msg, &QMessageBox::buttonClicked, onClick);
#else
QObject::connect(&msg, SIGNAL(buttonClicked(QAbstractButton*)),
new FunctorSlot{onClick, &msg}, SLOT(call()));
#endif
msg.show();
return app.exec();
}
#include "main.moc"
For Qt 4, you need the following helper:
// Qt 4 only
struct FunctorSlot : public QObject {
Q_OBJECT
public:
std::function<void()> callable;
template <typename Fun>
FunctorSlot(Fun && fun, QObject * parent = {}) :
QObject{parent}, callable{std::forward<Fun>(fun)} {}
Q_SLOT void call() {
callable();
}
};
Possible solution:
QApplication a(argc, argv);
QDialog dlg;
QTimer::singleShot( &dlg, 0, SLOT(exec()) );
return a.exec();
It will work well. First - application event loop will be started. Then dialog event loop will be executed. After closing of dialog, both dialog and application loop will be finished. Application loop will be terminated automatically (by default), when last window is closed.
But, as noted by #thuga - there are no reason to call exec(). It is enough to call show() method.

Problems with function QTimer::singleShot

I am trying to record sound by QAudioInput. According to the doc in this website QAudioInput. But when I ran, it exported an empty-raw file. After checking, It seems like the function QTimer::singleShot didn't working ( I added statement qWarning << "Done" in void stopRecording() and It didn't display "Done" so I thought it had some mistake in QTimer::singleShot function ).
This is my code used to check function QTimer::singleShot
----Check.pro----
QT += core
QT -= gui
TARGET = Check
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
HEADERS += test.h
-----test.h------
#ifndef TEST_H
#define TEST_H
#include <QCoreApplication>
#include <QTimer>
#include <iostream>
#include <QObject>
#include <test.h>
#include <QDebug>
using namespace std;
class Object: public QObject {
Q_OBJECT
private slots:
void func() { cout << "Hello"; }
};
#endif // TEST_H
----main.cpp----
#include <QCoreApplication>
#include <QTimer>
#include <iostream>
#include <QObject>
#include <test.h>
#include <QDebug>
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Object *o = new Object;
QTimer::singleShot(10000, o, SLOT(func()));
return 0;
}
And this code doesn't working, too. Can anyone explain me? I am newbie at Qt-programming.
Your program exits right after it's set the timer - it has no time to fire.
For the timer to work, you need an event loop running. Without the event loop, no events get processed.
Change the last line of your main to
return a.exec();
Also change your test slot by adding << std::endl or flush std::cout otherwise you might see no output on the console.
Your program should then work as expected (except it won't ever finish since nothing will cause the event loop to stop - just interrupt it).

Resources