Files
qt5-legatus-legacy/Lts/Common/LtsUtils/LtsUtilsCore/promise_examples.cpp
T
2026-08-13 18:33:10 +02:00

167 lines
5.4 KiB
C++
Executable File

#include "promise_examples.h"
#include "promise.h"
#include <QTimer>
#include <QTest>
#include <QDebug>
namespace LtsUtils
{
// First Example
void PromiseExample1_Class::doSomethingAsync1()
{
QTimer::singleShot(200, this, [this]()
{
emit signalDone1(true);
});
}
void PromiseExample1_Class::doSomethingAsync2()
{
QTimer::singleShot(450, this, [this]()
{
emit signalDone2(true, 1234);
});
}
PromiseExample1::PromiseExample1(QObject *parent)
: QObject(parent)
, m_success(false)
{
/* We have to work with a class that works asynchronous and need many emits and we have to wait for some results to come in.
* But we want the developer to use this function without rewriting everything that could be handled by a Promise that could be provided. */
auto func = [this](ResultFunction resolve /* call this function if the promise was successful */
, ResultFunction reject /* call this function if the promise was not successful */)
{
// we create the class (or you could use it from somewhere else)
PromiseExample1_Class *c = new PromiseExample1_Class(this);
// we connect to the done signal for the first action (before actually calling the function that can return this signal)
connect(c, &PromiseExample1_Class::signalDone1,
this, [this, c, resolve, reject](bool didThisWork)
{
// did the first action not work?
if (!didThisWork)
{
// something went wrong and we have to exit here with a reject
reject(QStringLiteral("First Action did not succeed")); // .. did not work.. at least tell the enduser what happened (the reject function has to print the string, though) <= promise is done, but failed early
return;
}
else // yes, it worked! we can continue!
{
// after the first action succeeded, we can call the next action, that would otherwise be useless to call if the first call failed
// we do the same thing as with the last signal connect here
connect(c, &PromiseExample1_Class::signalDone2,
this, [resolve, reject](bool didThisWork, int someNumberThatReturns)
{
if (didThisWork) // did the secondary action succeed?
resolve(someNumberThatReturns); // .. then return the returned number to the resolve function <= this is the final point where the promise is done!
else
reject(QStringLiteral("Second Action did not succeed")); // .. did not work.. at least tell the enduser what happened (the reject function has to print the string, though) <= promise is done, but failed
// everything done!
});
c->doSomethingAsync2(); // now, finally, execute the second action - should call signalDone2 soon!
}
});
c->doSomethingAsync1(); // now, finally, execute this async stuff and then signalDone1 should be called soon!
};
Promise *p = new Promise(func, this);
// the promise was created, but will not execute until Qt is back into the event loop
// and to receive resolve(..) or reject(..) messages, we have to connect to them first (but note that this works without connects)
p->resolved([this](const QVariant &value)
{
// "someNumberThatReturns" is inside value
qDebug() << "example1 promise succeeded! 'someNumberThatReturns' was" << value;
m_success = true;
}).rejected([](const QVariant &value) // <= you can directly call rejected(..) on resolved(..) to save time, as resolved(..) returns the promise itself, just like in js
{
// one or both of the actions didn't work - tell the user where it failed
qDebug() << "example1 promise failed.." << value;
});
}
// End of First Example
// Second Example
PromiseExample2::PromiseExample2(QObject *parent)
: QObject(parent)
, m_success(false)
{
/* There is an asynchonous function inside the Promise that might not resolve because of some error.
* A timeout is set for the Promise to reject so it doesn't get stuck. */
Promise *p = new Promise([](ResultFunction , ResultFunction )
{
// never resolve for this test case
}, this);
p->setTimeout(1000);
p->resolved([](const QVariant &)
{
QFAIL("This test case's promise should never resolve");
});
p->rejected([this](const QVariant &val)
{
QVERIFY2(val == QStringLiteral("timeout"), "Promise didn't reject with string \"timeout\"");
qDebug() << "Promise rejected as expected";
m_success = true;
});
}
// End of Second Example
// 3rd Example
PromiseExample3::PromiseExample3(QObject *parent)
: QObject(parent)
, m_success(true)
, m_alreadyRejected(false)
{
/* The promise's function failed with a reject, additionally a timeout was set
* to reject a promise that might never resolve/reject. After the promise was rejected
* the timeout should never trigger (because the promise was already rejected). */
Promise *p = new Promise([](ResultFunction , ResultFunction reject)
{
reject(QString()); // immediately reject
}, this);
p->setTimeout(1000); // set timeout
p->resolved([](const QVariant &)
{
QFAIL("This test case's promise should never resolve");
});
p->rejected([this](const QVariant &val)
{
qDebug() << "rejected with val" << val;
QVERIFY2(val == QString(), "Promise didn't reject with an expected empty string.");
QVERIFY2(!m_alreadyRejected, "Promise rejected more than once");
m_alreadyRejected = true;
qDebug() << "Promise rejected as expected";
});
}
// End of 3rd Example
} // namespace LtsUtils