mirror of
https://github.com/simonbrunel/qtpromise.git
synced 2024-11-22 02:34:30 +08:00
Implement QPromise<T>::convert<U>() (#41)
Converts the resolved value of `QPromise<T>` to the type `U`. Depending on types `T` and `U`, it performs a static cast, calls a converting constructor or tries to convert using `QVariant`.
This commit is contained in:
parent
60b36e7a70
commit
0c3955cca5
@ -40,6 +40,7 @@ module.exports = {
|
|||||||
title: 'QPromise',
|
title: 'QPromise',
|
||||||
children: [
|
children: [
|
||||||
'/qtpromise/qpromise/constructor',
|
'/qtpromise/qpromise/constructor',
|
||||||
|
'/qtpromise/qpromise/convert',
|
||||||
'/qtpromise/qpromise/delay',
|
'/qtpromise/qpromise/delay',
|
||||||
'/qtpromise/qpromise/each',
|
'/qtpromise/qpromise/each',
|
||||||
'/qtpromise/qpromise/fail',
|
'/qtpromise/qpromise/fail',
|
||||||
@ -77,6 +78,7 @@ module.exports = {
|
|||||||
children: [
|
children: [
|
||||||
'/qtpromise/exceptions/canceled',
|
'/qtpromise/exceptions/canceled',
|
||||||
'/qtpromise/exceptions/context',
|
'/qtpromise/exceptions/context',
|
||||||
|
'/qtpromise/exceptions/conversion',
|
||||||
'/qtpromise/exceptions/timeout',
|
'/qtpromise/exceptions/timeout',
|
||||||
'/qtpromise/exceptions/undefined'
|
'/qtpromise/exceptions/undefined'
|
||||||
]
|
]
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
## Functions
|
## Functions
|
||||||
|
|
||||||
- [`QPromise<T>::QPromise`](qpromise/constructor.md)
|
- [`QPromise<T>::QPromise`](qpromise/constructor.md)
|
||||||
|
- [`QPromise<T>::convert`](qpromise/convert.md)
|
||||||
- [`QPromise<T>::delay`](qpromise/delay.md)
|
- [`QPromise<T>::delay`](qpromise/delay.md)
|
||||||
- [`QPromise<T>::each`](qpromise/each.md)
|
- [`QPromise<T>::each`](qpromise/each.md)
|
||||||
- [`QPromise<T>::fail`](qpromise/fail.md)
|
- [`QPromise<T>::fail`](qpromise/fail.md)
|
||||||
@ -39,6 +40,7 @@
|
|||||||
|
|
||||||
- [`QPromiseCanceledException`](exceptions/canceled.md)
|
- [`QPromiseCanceledException`](exceptions/canceled.md)
|
||||||
- [`QPromiseContextException`](exceptions/context.md)
|
- [`QPromiseContextException`](exceptions/context.md)
|
||||||
|
- [`QPromiseConversionException`](exceptions/conversion.md)
|
||||||
- [`QPromiseTimeoutException`](exceptions/timeout.md)
|
- [`QPromiseTimeoutException`](exceptions/timeout.md)
|
||||||
- [`QPromiseUndefinedException`](exceptions/undefined.md)
|
- [`QPromiseUndefinedException`](exceptions/undefined.md)
|
||||||
|
|
||||||
|
13
docs/qtpromise/exceptions/conversion.md
Normal file
13
docs/qtpromise/exceptions/conversion.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# QPromiseConversionException
|
||||||
|
|
||||||
|
*Since: 0.7.0*
|
||||||
|
|
||||||
|
This exception is thrown whenever a promise result conversion fails, for example:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
QPromise<QVariant> input = {...};
|
||||||
|
auto output = input.convert<int>()
|
||||||
|
.fail([](const QPromiseconversionException& e) {
|
||||||
|
// conversion may fail because input could not be converted to number
|
||||||
|
});
|
||||||
|
```
|
124
docs/qtpromise/qpromise/convert.md
Normal file
124
docs/qtpromise/qpromise/convert.md
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
---
|
||||||
|
title: .convert
|
||||||
|
---
|
||||||
|
|
||||||
|
# QPromise::convert
|
||||||
|
|
||||||
|
*Since: 0.7.0*
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
QPromise<T>::convert<U>() -> QPromise<U>
|
||||||
|
```
|
||||||
|
|
||||||
|
This method converts the resolved value of `QPromise<T>` to the type `U`. Depending on types `T`
|
||||||
|
and `U`, it performs a [static cast](https://en.cppreference.com/w/cpp/language/static_cast),
|
||||||
|
calls a [converting constructor](https://en.cppreference.com/w/cpp/language/converting_constructor),
|
||||||
|
or tries to convert using [QVariant](https://doc.qt.io/qt-5/qvariant.html).
|
||||||
|
|
||||||
|
If `T` and `U` are [fundamental types](https://en.cppreference.com/w/cpp/language/types) or
|
||||||
|
[enumerations](https://en.cppreference.com/w/cpp/language/enum), the result of the conversion is
|
||||||
|
the same as calling `static_cast<U>` for type `T`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
QPromise<int> input = {...}
|
||||||
|
|
||||||
|
// output type: QPromise<double>
|
||||||
|
auto output = input.convert<double>();
|
||||||
|
|
||||||
|
output.then([](double value) {
|
||||||
|
// the value has been converted using static_cast
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
If `U` has a [converting constructor](https://en.cppreference.com/w/cpp/language/converting_constructor)
|
||||||
|
from `T`, i.e., a non-explicit constructor with a single argument accepting `T`, it is used to
|
||||||
|
convert the value:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
QPromise<QByteArray> input = {...}
|
||||||
|
|
||||||
|
// output type: QPromise<QString>
|
||||||
|
auto output = input.convert<QString>();
|
||||||
|
|
||||||
|
output.then([](const QString& value) {
|
||||||
|
// the value has been converted using static_cast that effectively calls QString(QByteArray)
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
::: tip NOTE
|
||||||
|
When using this method to convert to your own classes, make sure that the constructor meeting the
|
||||||
|
converting constructor criteria actually performs conversion.
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: tip NOTE
|
||||||
|
If `U` is `void`, the resolved value of `QPromise<T>` is dropped.
|
||||||
|
:::
|
||||||
|
|
||||||
|
Calling this method for `QPromise<QVariant>` tries to convert the resolved `QVariant` to type `U`
|
||||||
|
using the `QVariant` [conversion algorithm](https://doc.qt.io/qt-5/qvariant.html#using-canconvert-and-convert-consecutively).
|
||||||
|
For example, this allows to convert a string contained in `QVariant` to number. If such a
|
||||||
|
conversion fails, the promise is rejected with
|
||||||
|
[`QPromiseConversionException`](../exceptions/conversion.md).
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// resolves to QVariant(int, 42) or QVariant(string, "foo")
|
||||||
|
QPromise<QVariant> input = {...};
|
||||||
|
|
||||||
|
auto output = input.convert<int>();
|
||||||
|
|
||||||
|
// output type: QPromise<int>
|
||||||
|
output.then([](int value) {
|
||||||
|
// input was QVariant(int, 42), value is 42
|
||||||
|
})
|
||||||
|
.fail(const QPromiseConversionException& e) {
|
||||||
|
// input was QVariant(string, "foo")
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Conversion of `T` to `QVariant` using this method effectively calls `QVariant::fromValue<T>()`.
|
||||||
|
All custom types must be registered with
|
||||||
|
[`Q_DECLARE_METATYPE`](https://doc.qt.io/qt-5/qmetatype.html#Q_DECLARE_METATYPE) for this
|
||||||
|
conversion to work:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct Foo {};
|
||||||
|
Q_DECLARE_METATYPE(Foo);
|
||||||
|
|
||||||
|
QPromise<Foo> input = {...}
|
||||||
|
|
||||||
|
auto output = input.convert<QVariant>();
|
||||||
|
|
||||||
|
// output type: QPromise<QVariant>
|
||||||
|
output.then([](const QVariant& value) {
|
||||||
|
// value contains an instance of Foo
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
All other combinations of `T` and `U` are converted via `QVariant`. All non-Qt types should provide
|
||||||
|
a [conversion function](https://doc.qt.io/qt-5/qmetatype.html#registerConverter), otherwise the
|
||||||
|
promise is rejected with [`QPromiseConversionException`](../exceptions/conversion.md):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct Foo {};
|
||||||
|
Q_DECLARE_METATYPE(Foo);
|
||||||
|
|
||||||
|
QMetaType::registerConverter<Foo, QString>([](const Foo& foo) {
|
||||||
|
return QString{...};
|
||||||
|
});
|
||||||
|
|
||||||
|
QPromise<Foo> input = {...}
|
||||||
|
|
||||||
|
auto output = input.convert<QVariant>();
|
||||||
|
|
||||||
|
// output type: QPromise<QString>
|
||||||
|
output.then([](const QString& value) {
|
||||||
|
// value contains a result produced by the custom converter
|
||||||
|
})
|
||||||
|
.fail([](const QPromiseConversionException& e) {
|
||||||
|
// QVariant was unable to convert Foo to QString
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
::: warning IMPORTANT
|
||||||
|
Calling this method for `QPromise<void>` is not supported.
|
||||||
|
:::
|
@ -111,6 +111,9 @@ public:
|
|||||||
QPromise(F&& resolver) : QPromiseBase<T>(std::forward<F>(resolver))
|
QPromise(F&& resolver) : QPromiseBase<T>(std::forward<F>(resolver))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
inline QPromise<U> convert() const;
|
||||||
|
|
||||||
template<typename Functor>
|
template<typename Functor>
|
||||||
inline QPromise<T> each(Functor fn);
|
inline QPromise<T> each(Functor fn);
|
||||||
|
|
||||||
|
@ -242,6 +242,13 @@ inline QPromise<QVector<T>> QPromise<T>::all(const Sequence<QPromise<T>, Args...
|
|||||||
return QtPromise::all(promises);
|
return QtPromise::all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
template<typename U>
|
||||||
|
inline QPromise<U> QPromise<T>::convert() const
|
||||||
|
{
|
||||||
|
return QPromiseBase<T>::then(QtPromisePrivate::PromiseConverter<T, U>::create());
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline QPromise<T> QPromise<T>::resolve(const T& value)
|
inline QPromise<T> QPromise<T>::resolve(const T& value)
|
||||||
{
|
{
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <QtCore/QSharedData>
|
#include <QtCore/QSharedData>
|
||||||
#include <QtCore/QSharedPointer>
|
#include <QtCore/QSharedPointer>
|
||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
|
#include <QtCore/QVariant>
|
||||||
#include <QtCore/QVector>
|
#include <QtCore/QVector>
|
||||||
|
|
||||||
namespace QtPromise {
|
namespace QtPromise {
|
||||||
@ -30,6 +31,8 @@ class QPromiseResolve;
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
class QPromiseReject;
|
class QPromiseReject;
|
||||||
|
|
||||||
|
class QPromiseConversionException;
|
||||||
|
|
||||||
} // namespace QtPromise
|
} // namespace QtPromise
|
||||||
|
|
||||||
namespace QtPromisePrivate {
|
namespace QtPromisePrivate {
|
||||||
@ -553,6 +556,63 @@ struct PromiseInspect
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T, typename U, bool IsConvertibleViaStaticCast>
|
||||||
|
struct PromiseConverterBase;
|
||||||
|
|
||||||
|
template<typename T, typename U>
|
||||||
|
struct PromiseConverterBase<T, U, true>
|
||||||
|
{
|
||||||
|
static std::function<U(const T&)> create()
|
||||||
|
{
|
||||||
|
return [](const T& value) {
|
||||||
|
return static_cast<U>(value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename U>
|
||||||
|
struct PromiseConverterBase<T, U, false>
|
||||||
|
{
|
||||||
|
static std::function<U(const T&)> create()
|
||||||
|
{
|
||||||
|
return [](const T& value) {
|
||||||
|
auto tmp = QVariant::fromValue(value);
|
||||||
|
|
||||||
|
// https://doc.qt.io/qt-5/qvariant.html#using-canconvert-and-convert-consecutively
|
||||||
|
if (tmp.canConvert(qMetaTypeId<U>()) && tmp.convert(qMetaTypeId<U>())) {
|
||||||
|
return qvariant_cast<U>(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw QtPromise::QPromiseConversionException{};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct PromiseConverterBase<T, QVariant, false>
|
||||||
|
{
|
||||||
|
static std::function<QVariant(const T&)> create()
|
||||||
|
{
|
||||||
|
return [](const T& value) {
|
||||||
|
return QVariant::fromValue(value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename U>
|
||||||
|
struct PromiseConverter
|
||||||
|
: PromiseConverterBase<T,
|
||||||
|
U,
|
||||||
|
// Fundamental types and converting constructors.
|
||||||
|
std::is_convertible<T, U>::value ||
|
||||||
|
// Conversion to void.
|
||||||
|
std::is_same<U, void>::value ||
|
||||||
|
// Conversion between enums and arithmetic types.
|
||||||
|
((std::is_enum<T>::value && std::is_arithmetic<U>::value)
|
||||||
|
|| (std::is_arithmetic<T>::value && std::is_enum<U>::value)
|
||||||
|
|| (std::is_enum<T>::value && std::is_enum<U>::value))>
|
||||||
|
{ };
|
||||||
|
|
||||||
} // namespace QtPromisePrivate
|
} // namespace QtPromisePrivate
|
||||||
|
|
||||||
#endif // QTPROMISE_QPROMISE_H
|
#endif // QTPROMISE_QPROMISE_H
|
||||||
|
@ -35,6 +35,16 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class QPromiseConversionException : public QException
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void raise() const Q_DECL_OVERRIDE { throw *this; }
|
||||||
|
QPromiseConversionException* clone() const Q_DECL_OVERRIDE
|
||||||
|
{
|
||||||
|
return new QPromiseConversionException{*this};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class QPromiseTimeoutException : public QException
|
class QPromiseTimeoutException : public QException
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -20,6 +20,7 @@ class tst_exceptions : public QObject
|
|||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void canceled();
|
void canceled();
|
||||||
void context();
|
void context();
|
||||||
|
void conversion();
|
||||||
void timeout();
|
void timeout();
|
||||||
void undefined();
|
void undefined();
|
||||||
|
|
||||||
@ -53,6 +54,11 @@ void tst_exceptions::context()
|
|||||||
verify<QPromiseContextException>();
|
verify<QPromiseContextException>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_exceptions::conversion()
|
||||||
|
{
|
||||||
|
verify<QPromiseConversionException>();
|
||||||
|
}
|
||||||
|
|
||||||
void tst_exceptions::timeout()
|
void tst_exceptions::timeout()
|
||||||
{
|
{
|
||||||
verify<QPromiseTimeoutException>();
|
verify<QPromiseTimeoutException>();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
qtpromise_add_tests(qpromise
|
qtpromise_add_tests(qpromise
|
||||||
SOURCES
|
SOURCES
|
||||||
tst_construct.cpp
|
tst_construct.cpp
|
||||||
|
tst_convert.cpp
|
||||||
tst_delay.cpp
|
tst_delay.cpp
|
||||||
tst_each.cpp
|
tst_each.cpp
|
||||||
tst_fail.cpp
|
tst_fail.cpp
|
||||||
|
266
tests/auto/qtpromise/qpromise/tst_convert.cpp
Normal file
266
tests/auto/qtpromise/qpromise/tst_convert.cpp
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../shared/utils.h"
|
||||||
|
|
||||||
|
#include <QtPromise>
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
using namespace QtPromise;
|
||||||
|
|
||||||
|
class tst_qpromise_convert : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void initTestCase();
|
||||||
|
|
||||||
|
void fulfillTAsU();
|
||||||
|
void fulfillTAsVoid();
|
||||||
|
void fulfillTAsQVariant();
|
||||||
|
void fulfillQVariantAsU();
|
||||||
|
void fulfillQVariantAsVoid();
|
||||||
|
|
||||||
|
void rejectUnconvertibleTypes();
|
||||||
|
};
|
||||||
|
|
||||||
|
QTEST_MAIN(tst_qpromise_convert)
|
||||||
|
#include "tst_convert.moc"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct Foo
|
||||||
|
{
|
||||||
|
Foo() = default;
|
||||||
|
Foo(int foo) : m_foo{foo} { }
|
||||||
|
|
||||||
|
bool operator==(const Foo& rhs) const { return m_foo == rhs.m_foo; }
|
||||||
|
|
||||||
|
int m_foo{-1};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Bar
|
||||||
|
{
|
||||||
|
Bar() = default;
|
||||||
|
Bar(const Foo& other) : m_bar{other.m_foo} { }
|
||||||
|
|
||||||
|
bool operator==(const Bar& rhs) const { return m_bar == rhs.m_bar; }
|
||||||
|
|
||||||
|
int m_bar{-1};
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Enum1 { Value0, Value1, Value2 };
|
||||||
|
enum class Enum2 { Value0, Value1, Value2 };
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(Foo)
|
||||||
|
Q_DECLARE_METATYPE(Bar)
|
||||||
|
|
||||||
|
void tst_qpromise_convert::initTestCase()
|
||||||
|
{
|
||||||
|
// Register converter used by QVariant.
|
||||||
|
// https://doc.qt.io/qt-5/qmetatype.html#registerConverter
|
||||||
|
QMetaType::registerConverter<Foo, QString>([](const Foo& foo) {
|
||||||
|
return QString{"Foo{%1}"}.arg(foo.m_foo);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_convert::fulfillTAsU()
|
||||||
|
{
|
||||||
|
// Static cast between primitive types.
|
||||||
|
{
|
||||||
|
auto p = QtPromise::resolve(42.13).convert<int>();
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(waitForValue(p, -1), 42);
|
||||||
|
QVERIFY(p.isFulfilled());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert enum class to int.
|
||||||
|
{
|
||||||
|
auto p = QtPromise::resolve(Enum1::Value1).convert<int>();
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(waitForValue(p, -1), 1);
|
||||||
|
QVERIFY(p.isFulfilled());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert int to enum class.
|
||||||
|
{
|
||||||
|
auto p = QtPromise::resolve(1).convert<Enum1>();
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Enum1>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(waitForValue(p, Enum1::Value0), Enum1::Value1);
|
||||||
|
QVERIFY(p.isFulfilled());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert between enums
|
||||||
|
{
|
||||||
|
auto p = QtPromise::resolve(Enum1::Value1).convert<Enum2>();
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Enum2>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(waitForValue(p, Enum2::Value0), Enum2::Value1);
|
||||||
|
QVERIFY(p.isFulfilled());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converting constructor for Qt types.
|
||||||
|
// https://en.cppreference.com/w/cpp/language/converting_constructor
|
||||||
|
{
|
||||||
|
auto p = QtPromise::resolve(QByteArray{"foo"}).convert<QString>();
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(waitForValue(p, QString{}), QString{"foo"});
|
||||||
|
QVERIFY(p.isFulfilled());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converting constructor for non-Qt types.
|
||||||
|
// https://en.cppreference.com/w/cpp/language/converting_constructor
|
||||||
|
{
|
||||||
|
auto p = QtPromise::resolve(Foo{42}).convert<Bar>();
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Bar>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(waitForValue(p, Bar{}), Bar{42});
|
||||||
|
QVERIFY(p.isFulfilled());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversion of types Qt is aware of via QVariant.
|
||||||
|
{
|
||||||
|
auto p = QtPromise::resolve(42).convert<QString>();
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(waitForValue(p, QString{}), QString{"42"});
|
||||||
|
QVERIFY(p.isFulfilled());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversion of a non-Qt type via QVariant.
|
||||||
|
// https://doc.qt.io/qt-5/qmetatype.html#registerConverter
|
||||||
|
{
|
||||||
|
auto p = QtPromise::resolve(Foo{42}).convert<QString>();
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(waitForValue(p, QString{}), QString{"Foo{42}"});
|
||||||
|
QVERIFY(p.isFulfilled());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_convert::fulfillTAsVoid()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::resolve(42).convert<void>();
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||||
|
QVERIFY(p.isFulfilled());
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_convert::fulfillTAsQVariant()
|
||||||
|
{
|
||||||
|
// Primitive type to QVariant.
|
||||||
|
{
|
||||||
|
auto p = QtPromise::resolve(42).convert<QVariant>();
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVariant>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(waitForValue(p, QVariant{}), QVariant{42});
|
||||||
|
QVERIFY(p.isFulfilled());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-Qt user-defined type to QVariant.
|
||||||
|
{
|
||||||
|
auto p = QtPromise::resolve(Foo{42}).convert<QVariant>();
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVariant>>::value));
|
||||||
|
|
||||||
|
QVariant value = waitForValue(p, QVariant{});
|
||||||
|
QCOMPARE(value, QVariant::fromValue(Foo{42}));
|
||||||
|
QCOMPARE(value.value<Foo>().m_foo, 42);
|
||||||
|
QVERIFY(p.isFulfilled());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_convert::fulfillQVariantAsU()
|
||||||
|
{
|
||||||
|
// Test whether a directly stored value can be extracted.
|
||||||
|
{
|
||||||
|
auto p = QtPromise::resolve(QVariant{42}).convert<int>();
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(waitForValue(p, -1), 42);
|
||||||
|
QVERIFY(p.isFulfilled());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test automatic conversion from string performed by QVariant.
|
||||||
|
// https://doc.qt.io/qt-5/qvariant.html#toInt
|
||||||
|
{
|
||||||
|
auto p = QtPromise::resolve(QVariant{"42"}).convert<int>();
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(waitForValue(p, -1), 42);
|
||||||
|
QVERIFY(p.isFulfilled());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-Qt user-defined type
|
||||||
|
{
|
||||||
|
auto p = QtPromise::resolve(QVariant::fromValue(Foo{42})).convert<Foo>();
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Foo>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(waitForValue(p, Foo{}), Foo{42});
|
||||||
|
QVERIFY(p.isFulfilled());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_convert::fulfillQVariantAsVoid()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::resolve(QVariant{42}).convert<void>();
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||||
|
QVERIFY(p.isFulfilled());
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_convert::rejectUnconvertibleTypes()
|
||||||
|
{
|
||||||
|
// A string incompatible with int due to its value.
|
||||||
|
{
|
||||||
|
auto p = QtPromise::resolve(QString{"42foo"}).convert<int>();
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QVERIFY(waitForRejected<QPromiseConversionException>(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
// A user-defined type unconvertible to string because there is no converter.
|
||||||
|
{
|
||||||
|
auto p = QtPromise::resolve(QVariant::fromValue(Bar{42})).convert<QString>();
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
|
||||||
|
|
||||||
|
QVERIFY(waitForRejected<QPromiseConversionException>(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
// A standard library type unconvertible to a primitive type because there is no converter.
|
||||||
|
{
|
||||||
|
auto p = QtPromise::resolve(std::vector<int>{42, -42}).convert<int>();
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QVERIFY(waitForRejected<QPromiseConversionException>(p));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user