mirror of
https://github.com/simonbrunel/qtpromise.git
synced 2024-11-22 02:34:30 +08:00
Fix support for std::function as continuation handler
This commit is contained in:
parent
58738a5604
commit
78417b5813
@ -27,7 +27,7 @@ public:
|
||||
template <typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count == 1, int>::type = 0>
|
||||
inline QPromiseBase(F resolver);
|
||||
|
||||
template <typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count != 1, int>::type = 0>
|
||||
template <typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count == 2, int>::type = 0>
|
||||
inline QPromiseBase(F resolver);
|
||||
|
||||
QPromiseBase(const QPromiseBase<T>& other): m_d(other.m_d) {}
|
||||
|
@ -30,7 +30,7 @@ inline QPromiseBase<T>::QPromiseBase(F callback)
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count != 1, int>::type>
|
||||
template <typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count == 2, int>::type>
|
||||
inline QPromiseBase<T>::QPromiseBase(F callback)
|
||||
: m_d(new QtPromisePrivate::PromiseData<T>())
|
||||
{
|
||||
|
@ -28,12 +28,8 @@ using Unqualified = typename std::remove_cv<typename std::remove_reference<T>::t
|
||||
template <typename T>
|
||||
struct HasCallOperator
|
||||
{
|
||||
template <typename U>
|
||||
static char check(decltype(&U::operator(), char(0)));
|
||||
|
||||
template <typename U>
|
||||
static char (&check(...))[2];
|
||||
|
||||
template <typename U> static char check(decltype(&U::operator(), char(0)));
|
||||
template <typename U> static char (&check(...))[2];
|
||||
static const bool value = (sizeof(check<T>(0)) == 1);
|
||||
};
|
||||
|
||||
@ -58,73 +54,57 @@ struct ArgsTraits<>
|
||||
static const size_t count = 0;
|
||||
};
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct ArgsOf : public ArgsTraits<>
|
||||
// Fallback implementation (type not supported).
|
||||
template <typename T, typename Enabled = void>
|
||||
struct ArgsOf
|
||||
{ };
|
||||
|
||||
// Partial specialization for null function.
|
||||
template <>
|
||||
struct ArgsOf<std::nullptr_t> : public ArgsTraits<>
|
||||
{ };
|
||||
|
||||
// Partial specialization for type with a non-overloaded operator().
|
||||
// This applies to lambda, std::function but not to std::bind result.
|
||||
template <typename T>
|
||||
struct ArgsOf<T, typename std::enable_if<HasCallOperator<T>::value>::type>
|
||||
: public ArgsOf<decltype(&T::operator())>
|
||||
{ };
|
||||
|
||||
template <typename TReturn, typename... Args>
|
||||
struct ArgsOf<TReturn(Args...)> : public ArgsTraits<Args...>
|
||||
{ };
|
||||
|
||||
template <typename TReturn, typename... Args>
|
||||
struct ArgsOf<TReturn(*)(Args...)> : public ArgsTraits<Args...>
|
||||
{ };
|
||||
|
||||
template <typename T, typename TReturn, typename... Args>
|
||||
struct ArgsOf<TReturn(T::*)(Args...)> : public ArgsTraits<Args...>
|
||||
{ };
|
||||
|
||||
template <typename T, typename TReturn, typename... Args>
|
||||
struct ArgsOf<TReturn(T::*)(Args...) const> : public ArgsTraits<Args...>
|
||||
{ };
|
||||
|
||||
template <typename T, typename TReturn, typename... Args>
|
||||
struct ArgsOf<TReturn(T::*)(Args...) volatile> : public ArgsTraits<Args...>
|
||||
{ };
|
||||
|
||||
template <typename T, typename TReturn, typename... Args>
|
||||
struct ArgsOf<TReturn(T::*)(Args...) const volatile> : public ArgsTraits<Args...>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct ArgsOf<std::function<T>> : public ArgsOf<T>
|
||||
{ };
|
||||
|
||||
// Partial specialization to remove reference and rvalue (e.g. lambda, std::function, etc.).
|
||||
template <typename T>
|
||||
struct ArgsOf<T&> : public ArgsOf<T>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct ArgsOf<const T&> : public ArgsOf<T>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct ArgsOf<volatile T&> : public ArgsOf<T>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct ArgsOf<const volatile T&> : public ArgsOf<T>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct ArgsOf<T&&> : public ArgsOf<T>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct ArgsOf<const T&&> : public ArgsOf<T>
|
||||
// Partial specialization for function type.
|
||||
template <typename R, typename... Args>
|
||||
struct ArgsOf<R(Args...)> : public ArgsTraits<Args...>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct ArgsOf<volatile T&&> : public ArgsOf<T>
|
||||
// Partial specialization for function pointer.
|
||||
template <typename R, typename... Args>
|
||||
struct ArgsOf<R(*)(Args...)> : public ArgsTraits<Args...>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct ArgsOf<const volatile T&&> : public ArgsOf<T>
|
||||
// Partial specialization for pointer-to-member-function (i.e. operator()'s).
|
||||
template <typename R, typename T, typename... Args>
|
||||
struct ArgsOf<R(T::*)(Args...)> : public ArgsTraits<Args...>
|
||||
{ };
|
||||
|
||||
template <typename R, typename T, typename... Args>
|
||||
struct ArgsOf<R(T::*)(Args...) const> : public ArgsTraits<Args...>
|
||||
{ };
|
||||
|
||||
template <typename R, typename T, typename... Args>
|
||||
struct ArgsOf<R(T::*)(Args...) volatile> : public ArgsTraits<Args...>
|
||||
{ };
|
||||
|
||||
template <typename R, typename T, typename... Args>
|
||||
struct ArgsOf<R(T::*)(Args...) const volatile> : public ArgsTraits<Args...>
|
||||
{ };
|
||||
|
||||
} // namespace QtPromisePrivate
|
||||
|
@ -5,6 +5,7 @@ add_subdirectory(deprecations)
|
||||
add_subdirectory(exceptions)
|
||||
add_subdirectory(future)
|
||||
add_subdirectory(helpers)
|
||||
add_subdirectory(internals)
|
||||
add_subdirectory(qpromise)
|
||||
add_subdirectory(qpromiseconnections)
|
||||
add_subdirectory(requirements)
|
||||
|
4
tests/auto/qtpromise/internals/CMakeLists.txt
Normal file
4
tests/auto/qtpromise/internals/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
qtpromise_add_test(internals_argsof
|
||||
SOURCES
|
||||
tst_argsof.cpp
|
||||
)
|
139
tests/auto/qtpromise/internals/tst_argsof.cpp
Normal file
139
tests/auto/qtpromise/internals/tst_argsof.cpp
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) Simon Brunel, https://github.com/simonbrunel
|
||||
*
|
||||
* This source code is licensed under the MIT license found in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromisePrivate;
|
||||
|
||||
class tst_internals_argsof : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void nullFunction();
|
||||
void basicFunction();
|
||||
void callOperator();
|
||||
void stdFunction();
|
||||
void lambda();
|
||||
|
||||
}; // class tst_argsof
|
||||
|
||||
QTEST_MAIN(tst_internals_argsof)
|
||||
#include "tst_argsof.moc"
|
||||
|
||||
#define TEST_ARGS_FOR_TYPE(T, E) \
|
||||
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<T>::first, E>::value)); \
|
||||
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<T&>::first, E>::value)); \
|
||||
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<T&&>::first, E>::value)); \
|
||||
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<const T>::first, E>::value)); \
|
||||
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<const T&>::first, E>::value)); \
|
||||
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<const T&&>::first, E>::value)); \
|
||||
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<volatile T>::first, E>::value)); \
|
||||
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<volatile T&>::first, E>::value)); \
|
||||
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<volatile T&&>::first, E>::value)); \
|
||||
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<const volatile T>::first, E>::value)); \
|
||||
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<const volatile T&>::first, E>::value)); \
|
||||
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<const volatile T&&>::first, E>::value));
|
||||
|
||||
namespace {
|
||||
|
||||
const float kRes = 0.42f;
|
||||
|
||||
float fnNoArg() { return kRes; }
|
||||
float fnOneArg(float v) { return v; }
|
||||
float fnManyArgs(const float& v0, int, char*) { return v0; }
|
||||
|
||||
struct OpNoArg { float operator()() { return kRes; } };
|
||||
struct OpOneArg { float operator()(float v) { return v; } };
|
||||
struct OpManyArgs { float operator()(const float& v, int, char*) { return v; } };
|
||||
|
||||
struct OpCNoArg { float operator()() const { return kRes; } };
|
||||
struct OpCOneArg { float operator()(float v) const { return v; } };
|
||||
struct OpCManyArgs { float operator()(const float& v, int, char*) const { return v; } };
|
||||
|
||||
struct OpVNoArg { float operator()() volatile { return kRes; } };
|
||||
struct OpVOneArg { float operator()(float v) volatile { return v; } };
|
||||
struct OpVManyArgs { float operator()(const float& v, int, char*) volatile { return v; } };
|
||||
|
||||
struct OpCVNoArg { float operator()() const volatile { return kRes; } };
|
||||
struct OpCVOneArg { float operator()(float v) const volatile { return v; } };
|
||||
struct OpCVManyArgs { float operator()(const float& v, int, char*) const volatile { return v; } };
|
||||
|
||||
} // namespace
|
||||
|
||||
void tst_internals_argsof::initTestCase()
|
||||
{
|
||||
Q_UNUSED(fnNoArg())
|
||||
Q_UNUSED(fnOneArg(42))
|
||||
Q_UNUSED(fnManyArgs(42, 42, nullptr))
|
||||
}
|
||||
|
||||
void tst_internals_argsof::nullFunction()
|
||||
{
|
||||
Q_STATIC_ASSERT((std::is_same<ArgsOf<std::nullptr_t>::first, void>::value));
|
||||
}
|
||||
|
||||
void tst_internals_argsof::basicFunction()
|
||||
{
|
||||
// Function type.
|
||||
Q_STATIC_ASSERT((std::is_same<ArgsOf<decltype(fnNoArg)>::first, void>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<ArgsOf<decltype(fnOneArg)>::first, float>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<ArgsOf<decltype(fnManyArgs)>::first, const float&>::value));
|
||||
|
||||
// Function pointer type.
|
||||
Q_STATIC_ASSERT((std::is_same<ArgsOf<decltype(&fnNoArg)>::first, void>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<ArgsOf<decltype(&fnOneArg)>::first, float>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<ArgsOf<decltype(&fnManyArgs)>::first, const float&>::value));
|
||||
}
|
||||
|
||||
void tst_internals_argsof::callOperator()
|
||||
{
|
||||
// non-const
|
||||
TEST_ARGS_FOR_TYPE(OpNoArg, void);
|
||||
TEST_ARGS_FOR_TYPE(OpOneArg, float);
|
||||
TEST_ARGS_FOR_TYPE(OpManyArgs, const float&);
|
||||
|
||||
// const
|
||||
TEST_ARGS_FOR_TYPE(OpCNoArg, void);
|
||||
TEST_ARGS_FOR_TYPE(OpCOneArg, float);
|
||||
TEST_ARGS_FOR_TYPE(OpCManyArgs, const float&);
|
||||
|
||||
// volatile
|
||||
TEST_ARGS_FOR_TYPE(OpVNoArg, void);
|
||||
TEST_ARGS_FOR_TYPE(OpVOneArg, float);
|
||||
TEST_ARGS_FOR_TYPE(OpVManyArgs, const float&);
|
||||
|
||||
// const volatile
|
||||
TEST_ARGS_FOR_TYPE(OpCVNoArg, void);
|
||||
TEST_ARGS_FOR_TYPE(OpCVOneArg, float);
|
||||
TEST_ARGS_FOR_TYPE(OpCVManyArgs, const float&);
|
||||
}
|
||||
|
||||
void tst_internals_argsof::stdFunction()
|
||||
{
|
||||
TEST_ARGS_FOR_TYPE(std::function<void()>, void);
|
||||
TEST_ARGS_FOR_TYPE(std::function<void(float)>, float);
|
||||
TEST_ARGS_FOR_TYPE(std::function<void(const float&, int, char**)>, const float&);
|
||||
}
|
||||
|
||||
void tst_internals_argsof::lambda()
|
||||
{
|
||||
auto lNoArg = []() {};
|
||||
auto lOneArg = [](float) {};
|
||||
auto lManyArgs = [](const float&, int, char**) {};
|
||||
auto lMutable = [](const float&, int, char**) mutable {};
|
||||
|
||||
TEST_ARGS_FOR_TYPE(decltype(lNoArg), void);
|
||||
TEST_ARGS_FOR_TYPE(decltype(lOneArg), float);
|
||||
TEST_ARGS_FOR_TYPE(decltype(lManyArgs), const float&);
|
||||
TEST_ARGS_FOR_TYPE(decltype(lMutable), const float&);
|
||||
}
|
@ -24,11 +24,44 @@ private Q_SLOTS:
|
||||
void baseClass();
|
||||
void catchAll();
|
||||
// TODO: sync / async
|
||||
void functionPtrHandlers();
|
||||
void stdFunctionHandlers();
|
||||
void stdBindHandlers();
|
||||
void lambdaHandlers();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_qpromise_fail)
|
||||
#include "tst_fail.moc"
|
||||
|
||||
namespace {
|
||||
|
||||
const QString kErr = "0.42";
|
||||
const float kRes = 0.42f;
|
||||
const float kFail = -1.f;
|
||||
|
||||
float fnNoArg() { return kErr.toFloat(); }
|
||||
float fnArgByVal(QString e) { return e.toFloat(); }
|
||||
float fnArgByRef(const QString& e) { return e.toFloat(); }
|
||||
|
||||
class Klass {
|
||||
public: // STATICS
|
||||
static float kFnNoArg() { return kErr.toFloat(); }
|
||||
static float kFnArgByVal(QString e) { return e.toFloat(); }
|
||||
static float kFnArgByRef(const QString& e) { return e.toFloat(); }
|
||||
|
||||
public:
|
||||
Klass(float v) : m_v{v} {}
|
||||
|
||||
float fnNoArg() const { return m_v; }
|
||||
float fnArgByVal(QString v) const { return v.toFloat() + m_v; }
|
||||
float fnArgByRef(const QString& v) const { return v.toFloat() + m_v; }
|
||||
|
||||
private:
|
||||
const float m_v;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void tst_qpromise_fail::sameType()
|
||||
{
|
||||
// http://en.cppreference.com/w/cpp/error/exception
|
||||
@ -87,3 +120,125 @@ void tst_qpromise_fail::catchAll()
|
||||
|
||||
QCOMPARE(error, QString("bar"));
|
||||
}
|
||||
|
||||
void tst_qpromise_fail::functionPtrHandlers()
|
||||
{
|
||||
{ // Global functions.
|
||||
auto p0 = QPromise<float>::reject(kErr).fail(&fnNoArg);
|
||||
auto p1 = QPromise<float>::reject(kErr).fail(&fnArgByVal);
|
||||
auto p2 = QPromise<float>::reject(kErr).fail(&fnArgByRef);
|
||||
|
||||
QCOMPARE(waitForValue(p0, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p1, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p2, kFail), kRes);
|
||||
}
|
||||
{ // Static member functions.
|
||||
auto p0 = QPromise<float>::reject(kErr).fail(&Klass::kFnNoArg);
|
||||
auto p1 = QPromise<float>::reject(kErr).fail(&Klass::kFnArgByVal);
|
||||
auto p2 = QPromise<float>::reject(kErr).fail(&Klass::kFnArgByRef);
|
||||
|
||||
QCOMPARE(waitForValue(p0, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p1, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p2, kFail), kRes);
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/simonbrunel/qtpromise/issues/29
|
||||
void tst_qpromise_fail::stdFunctionHandlers()
|
||||
{
|
||||
{ // lvalue.
|
||||
std::function<float()> stdFnNoArg = fnNoArg;
|
||||
std::function<float(QString)> stdFnArgByVal = fnArgByVal;
|
||||
std::function<float(const QString&)> stdFnArgByRef = fnArgByRef;
|
||||
|
||||
auto p0 = QPromise<float>::reject(kErr).fail(stdFnNoArg);
|
||||
auto p1 = QPromise<float>::reject(kErr).fail(stdFnArgByVal);
|
||||
auto p2 = QPromise<float>::reject(kErr).fail(stdFnArgByRef);
|
||||
|
||||
QCOMPARE(waitForValue(p0, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p1, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p2, kFail), kRes);
|
||||
}
|
||||
{ // const lvalue.
|
||||
const std::function<float()> stdFnNoArg = fnNoArg;
|
||||
const std::function<float(QString)> stdFnArgByVal = fnArgByVal;
|
||||
const std::function<float(const QString&)> stdFnArgByRef = fnArgByRef;
|
||||
|
||||
auto p0 = QPromise<float>::reject(kErr).fail(stdFnNoArg);
|
||||
auto p1 = QPromise<float>::reject(kErr).fail(stdFnArgByVal);
|
||||
auto p2 = QPromise<float>::reject(kErr).fail(stdFnArgByRef);
|
||||
|
||||
QCOMPARE(waitForValue(p0, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p1, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p2, kFail), kRes);
|
||||
}
|
||||
{ // rvalue.
|
||||
auto p0 = QPromise<float>::reject(kErr).fail(std::function<float()>{fnNoArg});
|
||||
auto p1 = QPromise<float>::reject(kErr).fail(std::function<float(QString)>{fnArgByVal});
|
||||
auto p2 = QPromise<float>::reject(kErr).fail(std::function<float(const QString&)>{fnArgByRef});
|
||||
|
||||
QCOMPARE(waitForValue(p0, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p1, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p2, kFail), kRes);
|
||||
}
|
||||
}
|
||||
|
||||
//// https://github.com/simonbrunel/qtpromise/issues/29
|
||||
void tst_qpromise_fail::stdBindHandlers()
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
|
||||
const float val{42.f};
|
||||
const Klass obj{val};
|
||||
|
||||
const std::function<float()> bindNoArg = std::bind(&Klass::fnNoArg, &obj);
|
||||
const std::function<float(QString)> bindArgByVal = std::bind(&Klass::fnArgByVal, &obj, _1);
|
||||
const std::function<float(const QString&)> bindArgByRef = std::bind(&Klass::fnArgByRef, &obj, _1);
|
||||
|
||||
auto p0 = QPromise<float>::reject(kErr).fail(bindNoArg);
|
||||
auto p1 = QPromise<float>::reject(kErr).fail(bindArgByVal);
|
||||
auto p2 = QPromise<float>::reject(kErr).fail(bindArgByRef);
|
||||
|
||||
QCOMPARE(waitForValue(p0, kFail), val);
|
||||
QCOMPARE(waitForValue(p1, kFail), val + kRes);
|
||||
QCOMPARE(waitForValue(p2, kFail), val + kRes);
|
||||
}
|
||||
|
||||
void tst_qpromise_fail::lambdaHandlers()
|
||||
{
|
||||
{ // lvalue.
|
||||
auto lambdaNoArg = []() { return kRes; };
|
||||
auto lambdaArgByVal = [](QString v) { return v.toFloat(); };
|
||||
auto lambdaArgByRef = [](const QString& v) { return v.toFloat(); };
|
||||
|
||||
auto p0 = QPromise<float>::reject(kErr).fail(lambdaNoArg);
|
||||
auto p1 = QPromise<float>::reject(kErr).fail(lambdaArgByVal);
|
||||
auto p2 = QPromise<float>::reject(kErr).fail(lambdaArgByRef);
|
||||
|
||||
QCOMPARE(waitForValue(p0, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p1, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p2, kFail), kRes);
|
||||
}
|
||||
{ // const lvalue.
|
||||
const auto lambdaNoArg = []() { return kRes; };
|
||||
const auto lambdaArgByVal = [](QString v) { return v.toFloat(); };
|
||||
const auto lambdaArgByRef = [](const QString& v) { return v.toFloat(); };
|
||||
|
||||
auto p0 = QPromise<float>::reject(kErr).fail(lambdaNoArg);
|
||||
auto p1 = QPromise<float>::reject(kErr).fail(lambdaArgByVal);
|
||||
auto p2 = QPromise<float>::reject(kErr).fail(lambdaArgByRef);
|
||||
|
||||
QCOMPARE(waitForValue(p0, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p1, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p2, kFail), kRes);
|
||||
}
|
||||
{ // rvalue.
|
||||
auto p0 = QPromise<float>::reject(kErr).fail([]() { return kRes; });
|
||||
auto p1 = QPromise<float>::reject(kErr).fail([](QString v) { return v.toFloat(); });
|
||||
auto p2 = QPromise<float>::reject(kErr).fail([](const QString& v) { return v.toFloat(); });
|
||||
|
||||
QCOMPARE(waitForValue(p0, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p1, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p2, kFail), kRes);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
@ -25,12 +27,44 @@ private Q_SLOTS:
|
||||
void rejectSync();
|
||||
void rejectAsync();
|
||||
void skipResult();
|
||||
void noHandler();
|
||||
void nullHandler();
|
||||
void functionPtrHandlers();
|
||||
void stdFunctionHandlers();
|
||||
void stdBindHandlers();
|
||||
void lambdaHandlers();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_qpromise_then)
|
||||
#include "tst_then.moc"
|
||||
|
||||
namespace {
|
||||
|
||||
const float kRes = 0.42f;
|
||||
const float kFail = -1.f;
|
||||
|
||||
float fnNoArg() { return kRes; }
|
||||
float fnArgByVal(float v) { return v; }
|
||||
float fnArgByRef(const float& v) { return v; }
|
||||
|
||||
class Klass {
|
||||
public: // STATICS
|
||||
static float kFnNoArg() { return kRes; }
|
||||
static float kFnArgByVal(float v) { return v; }
|
||||
static float kFnArgByRef(const float& v) { return v; }
|
||||
|
||||
public:
|
||||
Klass(float v) : m_v{v} {}
|
||||
|
||||
float fnNoArg() const { return m_v; }
|
||||
float fnArgByVal(float v) const { return v + m_v; }
|
||||
float fnArgByRef(const float& v) const { return v + m_v; }
|
||||
|
||||
private:
|
||||
const float m_v;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void tst_qpromise_then::resolveSync()
|
||||
{
|
||||
QVariantList values;
|
||||
@ -115,7 +149,7 @@ void tst_qpromise_then::skipResult()
|
||||
QCOMPARE(value, 43);
|
||||
}
|
||||
|
||||
void tst_qpromise_then::noHandler()
|
||||
void tst_qpromise_then::nullHandler()
|
||||
{
|
||||
{ // resolved
|
||||
auto p = QPromise<int>::resolve(42).then(nullptr);
|
||||
@ -130,3 +164,125 @@ void tst_qpromise_then::noHandler()
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_qpromise_then::functionPtrHandlers()
|
||||
{
|
||||
{ // Global functions.
|
||||
auto p0 = QtPromise::resolve().then(&fnNoArg);
|
||||
auto p1 = QtPromise::resolve(kRes).then(&fnArgByVal);
|
||||
auto p2 = QtPromise::resolve(kRes).then(&fnArgByRef);
|
||||
|
||||
QCOMPARE(waitForValue(p0, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p1, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p2, kFail), kRes);
|
||||
}
|
||||
{ // Static member functions.
|
||||
auto p0 = QtPromise::resolve().then(&Klass::kFnNoArg);
|
||||
auto p1 = QtPromise::resolve(kRes).then(&Klass::kFnArgByVal);
|
||||
auto p2 = QtPromise::resolve(kRes).then(&Klass::kFnArgByRef);
|
||||
|
||||
QCOMPARE(waitForValue(p0, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p1, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p2, kFail), kRes);
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/simonbrunel/qtpromise/issues/29
|
||||
void tst_qpromise_then::stdFunctionHandlers()
|
||||
{
|
||||
{ // lvalue.
|
||||
std::function<float()> stdFnNoArg = fnNoArg;
|
||||
std::function<float(float)> stdFnArgByVal = fnArgByVal;
|
||||
std::function<float(const float&)> stdFnArgByRef = fnArgByRef;
|
||||
|
||||
auto p0 = QtPromise::resolve().then(stdFnNoArg);
|
||||
auto p1 = QtPromise::resolve(kRes).then(stdFnArgByVal);
|
||||
auto p2 = QtPromise::resolve(kRes).then(stdFnArgByRef);
|
||||
|
||||
QCOMPARE(waitForValue(p0, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p1, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p2, kFail), kRes);
|
||||
}
|
||||
{ // const lvalue.
|
||||
const std::function<float()> stdFnNoArg = fnNoArg;
|
||||
const std::function<float(float)> stdFnArgByVal = fnArgByVal;
|
||||
const std::function<float(const float&)> stdFnArgByRef = fnArgByRef;
|
||||
|
||||
auto p0 = QtPromise::resolve().then(stdFnNoArg);
|
||||
auto p1 = QtPromise::resolve(kRes).then(stdFnArgByVal);
|
||||
auto p2 = QtPromise::resolve(kRes).then(stdFnArgByRef);
|
||||
|
||||
QCOMPARE(waitForValue(p0, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p1, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p2, kFail), kRes);
|
||||
}
|
||||
{ // rvalue.
|
||||
auto p0 = QtPromise::resolve().then(std::function<float()>{fnNoArg});
|
||||
auto p1 = QtPromise::resolve(kRes).then(std::function<float(float)>{fnArgByVal});
|
||||
auto p2 = QtPromise::resolve(kRes).then(std::function<float(const float&)>{fnArgByRef});
|
||||
|
||||
QCOMPARE(waitForValue(p0, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p1, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p2, kFail), kRes);
|
||||
}
|
||||
}
|
||||
|
||||
//// https://github.com/simonbrunel/qtpromise/issues/29
|
||||
void tst_qpromise_then::stdBindHandlers()
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
|
||||
const float val{42.f};
|
||||
const Klass obj{val};
|
||||
|
||||
const std::function<float()> bindNoArg = std::bind(&Klass::fnNoArg, &obj);
|
||||
const std::function<float(float)> bindArgByVal = std::bind(&Klass::fnArgByVal, &obj, _1);
|
||||
const std::function<float(const float&)> bindArgByRef = std::bind(&Klass::fnArgByRef, &obj, _1);
|
||||
|
||||
auto p0 = QtPromise::resolve().then(bindNoArg);
|
||||
auto p1 = QtPromise::resolve(kRes).then(bindArgByVal);
|
||||
auto p2 = QtPromise::resolve(kRes).then(bindArgByRef);
|
||||
|
||||
QCOMPARE(waitForValue(p0, kFail), val);
|
||||
QCOMPARE(waitForValue(p1, kFail), val + kRes);
|
||||
QCOMPARE(waitForValue(p2, kFail), val + kRes);
|
||||
}
|
||||
|
||||
void tst_qpromise_then::lambdaHandlers()
|
||||
{
|
||||
{ // lvalue.
|
||||
auto lambdaNoArg = []() { return kRes; };
|
||||
auto lambdaArgByVal = [](float v) { return v; };
|
||||
auto lambdaArgByRef = [](const float& v) { return v; };
|
||||
|
||||
auto p0 = QtPromise::resolve().then(lambdaNoArg);
|
||||
auto p1 = QtPromise::resolve(kRes).then(lambdaArgByVal);
|
||||
auto p2 = QtPromise::resolve(kRes).then(lambdaArgByRef);
|
||||
|
||||
QCOMPARE(waitForValue(p0, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p1, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p2, kFail), kRes);
|
||||
}
|
||||
{ // const lvalue.
|
||||
const auto lambdaNoArg = []() { return kRes; };
|
||||
const auto lambdaArgByVal = [](float v) { return v; };
|
||||
const auto lambdaArgByRef = [](const float& v) { return v; };
|
||||
|
||||
auto p0 = QtPromise::resolve().then(lambdaNoArg);
|
||||
auto p1 = QtPromise::resolve(kRes).then(lambdaArgByVal);
|
||||
auto p2 = QtPromise::resolve(kRes).then(lambdaArgByRef);
|
||||
|
||||
QCOMPARE(waitForValue(p0, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p1, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p2, kFail), kRes);
|
||||
}
|
||||
{ // rvalue.
|
||||
auto p0 = QtPromise::resolve().then([]() { return kRes; });
|
||||
auto p1 = QtPromise::resolve(kRes).then([](float v) { return v; });
|
||||
auto p2 = QtPromise::resolve(kRes).then([](const float& v) { return v; });
|
||||
|
||||
QCOMPARE(waitForValue(p0, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p1, kFail), kRes);
|
||||
QCOMPARE(waitForValue(p2, kFail), kRes);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user