mirror of
https://github.com/simonbrunel/qtpromise.git
synced 2025-07-01 23:11:47 +08:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
22faef4ac3 | |||
eebcb4f364 | |||
051fed5fbc | |||
f610826ef0 | |||
4fa7a37750 | |||
69c07855f4 | |||
4cfe2e54f4 | |||
54d88f16a3 | |||
bdf3619469 | |||
8da467e9da | |||
efb6001b9d |
22
.appveyor.yml
Normal file
22
.appveyor.yml
Normal file
@ -0,0 +1,22 @@
|
||||
image: Visual Studio 2015
|
||||
|
||||
init:
|
||||
- cmd: call "C:\Program Files (x86)\Microsoft Visual Studio "%VSVER%".0\VC\vcvarsall.bat" %ARCH%
|
||||
|
||||
environment:
|
||||
PATH: '%PATH%;%QTDIR%\bin'
|
||||
matrix:
|
||||
- QTDIR: C:\Qt\5.6\msvc2013
|
||||
VSVER: 12
|
||||
ARCH: x86
|
||||
- QTDIR: C:\Qt\5.9\msvc2013_64
|
||||
VSVER: 12
|
||||
ARCH: x64
|
||||
|
||||
build_script:
|
||||
- cmd: qmake qtpromise.pro
|
||||
- cmd: nmake
|
||||
|
||||
test_script:
|
||||
- cmd: nmake check
|
||||
|
11
.travis.yml
11
.travis.yml
@ -4,12 +4,15 @@ language: cpp
|
||||
compiler: gcc
|
||||
|
||||
before_install:
|
||||
- sudo add-apt-repository -y ppa:beineri/opt-qt542-trusty
|
||||
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
- sudo add-apt-repository -y ppa:beineri/opt-qt563-trusty
|
||||
- sudo apt-get update -qq
|
||||
|
||||
install:
|
||||
- sudo apt-get install -qq qt54base
|
||||
- source /opt/qt54/bin/qt54-env.sh
|
||||
- sudo apt-get install -qq gcc-4.9 g++-4.9
|
||||
- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 60 --slave /usr/bin/g++ g++ /usr/bin/g++-4.9
|
||||
- sudo apt-get install -qq qt56base
|
||||
- source /opt/qt56/bin/qt56-env.sh
|
||||
- wget http://archive.ubuntu.com/ubuntu/pool/universe/l/lcov/lcov_1.13.orig.tar.gz
|
||||
- tar xf lcov_1.13.orig.tar.gz
|
||||
- cd lcov-1.13/
|
||||
@ -19,7 +22,7 @@ install:
|
||||
before_script:
|
||||
- qmake --version
|
||||
- lcov --version
|
||||
- gcc --version
|
||||
- gcc --version && g++ --version
|
||||
|
||||
script:
|
||||
- qmake qtpromise.pro CONFIG+=coverage
|
||||
|
12
README.md
12
README.md
@ -1,18 +1,20 @@
|
||||
<a href="https://promisesaplus.com/" title="Promises/A+ 1.1"><img src="https://promisesaplus.com/assets/logo-small.png" alt="Promises/A+" align="right"/></a>
|
||||
|
||||
# QtPromise
|
||||
|
||||
[](https://www.qpm.io/packages/com.github.simonbrunel.qtpromise/index.html) [](https://travis-ci.org/simonbrunel/qtpromise) [](https://codecov.io/gh/simonbrunel/qtpromise)
|
||||
|
||||
[Promises/A+](https://promisesaplus.com/) implementation for [Qt/C++](https://www.qt.io/).
|
||||
|
||||
Requires [Qt 5.4](https://www.qt.io/download/) (or later) with [C++11 support enabled](https://wiki.qt.io/How_to_use_C++11_in_your_Qt_Projects).
|
||||
Requires [Qt 5.6](https://www.qt.io/download/) (or later) with [C++11 support enabled](https://wiki.qt.io/How_to_use_C++11_in_your_Qt_Projects).
|
||||
|
||||
## Documentation
|
||||
|
||||
* [Getting Started](https://qtpromise.netlify.com/qtpromise/getting-started)
|
||||
* [Thread-Safety](https://qtpromise.netlify.com/qtpromise/thread-safety)
|
||||
* [QtConcurrent](https://qtpromise.netlify.com/qtpromise/qtconcurrent)
|
||||
* [API Reference](https://qtpromise.netlify.com/qtpromise/api-reference)
|
||||
* [Getting Started](https://qtpromise.netlify.com/qtpromise/getting-started.html)
|
||||
* [QtConcurrent](https://qtpromise.netlify.com/qtpromise/qtconcurrent.html)
|
||||
* [Thread-Safety](https://qtpromise.netlify.com/qtpromise/thread-safety.html)
|
||||
* [API Reference](https://qtpromise.netlify.com/qtpromise/api-reference.html)
|
||||
|
||||
## License
|
||||
|
||||
QtPromise is available under the [MIT license](LICENSE).
|
||||
|
40
book.json
40
book.json
@ -1,40 +0,0 @@
|
||||
{
|
||||
"title": "QtPromise",
|
||||
"description": "Promises/A+ implementation for Qt/C++",
|
||||
"author": "Simon Brunel",
|
||||
"gitbook": "3.2.3",
|
||||
"root": "docs",
|
||||
"plugins": [
|
||||
"-lunr",
|
||||
"-search",
|
||||
"search-plus",
|
||||
"anchorjs",
|
||||
"edit-link",
|
||||
"expand-active-chapter",
|
||||
"ga",
|
||||
"github"
|
||||
],
|
||||
"pluginsConfig": {
|
||||
"anchorjs": {
|
||||
"icon": "#",
|
||||
"placement": "left",
|
||||
"visible": "always"
|
||||
},
|
||||
"edit-link": {
|
||||
"base": "https://github.com/simonbrunel/qtpromise/edit/master/docs"
|
||||
},
|
||||
"ga": {
|
||||
"token": "UA-113899811-1",
|
||||
"configuration": "auto"
|
||||
},
|
||||
"github": {
|
||||
"url": "https://github.com/simonbrunel/qtpromise"
|
||||
},
|
||||
"theme-default": {
|
||||
"showLevel": false,
|
||||
"styles": {
|
||||
"website": "assets/style.css"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
54
docs/.vuepress/config.js
Normal file
54
docs/.vuepress/config.js
Normal file
@ -0,0 +1,54 @@
|
||||
module.exports = {
|
||||
title: 'QtPromise',
|
||||
description: 'Promises/A+ implementation for Qt/C++',
|
||||
ga: 'UA-113899811-1',
|
||||
head: [
|
||||
['link', { rel: 'icon', href: `/favicon.png` }],
|
||||
],
|
||||
themeConfig: {
|
||||
repo: 'simonbrunel/qtpromise',
|
||||
lastUpdated: 'Last Updated',
|
||||
editLinks: true,
|
||||
docsDir: 'docs',
|
||||
sidebar: [
|
||||
'qtpromise/getting-started',
|
||||
'qtpromise/qtconcurrent',
|
||||
'qtpromise/thread-safety',
|
||||
'qtpromise/api-reference',
|
||||
{
|
||||
title: 'QPromise',
|
||||
children: [
|
||||
'qtpromise/qpromise/constructor',
|
||||
'qtpromise/qpromise/delay',
|
||||
'qtpromise/qpromise/each',
|
||||
'qtpromise/qpromise/fail',
|
||||
'qtpromise/qpromise/filter',
|
||||
'qtpromise/qpromise/finally',
|
||||
'qtpromise/qpromise/isfulfilled',
|
||||
'qtpromise/qpromise/ispending',
|
||||
'qtpromise/qpromise/isrejected',
|
||||
'qtpromise/qpromise/map',
|
||||
'qtpromise/qpromise/tap',
|
||||
'qtpromise/qpromise/tapfail',
|
||||
'qtpromise/qpromise/then',
|
||||
'qtpromise/qpromise/timeout',
|
||||
'qtpromise/qpromise/wait',
|
||||
'qtpromise/qpromise/all.md',
|
||||
'qtpromise/qpromise/reject.md',
|
||||
'qtpromise/qpromise/resolve.md'
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Helpers',
|
||||
children: [
|
||||
'qtpromise/helpers/attempt',
|
||||
'qtpromise/helpers/each',
|
||||
'qtpromise/helpers/filter',
|
||||
'qtpromise/helpers/map',
|
||||
'qtpromise/helpers/qpromise',
|
||||
'qtpromise/helpers/qpromiseall'
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
2
docs/.vuepress/override.styl
Normal file
2
docs/.vuepress/override.styl
Normal file
@ -0,0 +1,2 @@
|
||||
$accentColor = #23b223
|
||||
$textColor = #404244
|
BIN
docs/.vuepress/public/favicon.ico
Normal file
BIN
docs/.vuepress/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
BIN
docs/.vuepress/public/favicon.png
Normal file
BIN
docs/.vuepress/public/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
4
docs/.vuepress/style.styl
Normal file
4
docs/.vuepress/style.styl
Normal file
@ -0,0 +1,4 @@
|
||||
@import 'override.styl'
|
||||
|
||||
.content a code
|
||||
color: $accentColor
|
@ -3,13 +3,7 @@
|
||||
# QtPromise
|
||||
[Promises/A+](https://promisesaplus.com/) implementation for [Qt/C++](https://www.qt.io/).
|
||||
|
||||
Requires [Qt 5.4](https://www.qt.io/download/) (or later) with [C++11 support enabled](https://wiki.qt.io/How_to_use_C++11_in_your_Qt_Projects).
|
||||
|
||||
## QtPromise for C++
|
||||
* [Getting Started](qtpromise/getting-started.md)
|
||||
* [Thread-Safety](qtpromise/thread-safety.md)
|
||||
* [QtConcurrent](qtpromise/qtconcurrent.md)
|
||||
* [API Reference](qtpromise/api-reference.md)
|
||||
Requires [Qt 5.6](https://www.qt.io/download/) (or later) with [C++11 support enabled](https://wiki.qt.io/How_to_use_C++11_in_your_Qt_Projects).
|
||||
|
||||
## License
|
||||
QtPromise is available under the [MIT license](https://github.com/simonbrunel/qtpromise/blob/master/LICENSE).
|
||||
|
@ -1,22 +0,0 @@
|
||||
### QtPromise for C++
|
||||
* [Getting Started](qtpromise/getting-started.md)
|
||||
* [QtConcurrent](qtpromise/qtconcurrent.md)
|
||||
* [Thread-Safety](qtpromise/thread-safety.md)
|
||||
* [API Reference](qtpromise/api-reference.md)
|
||||
* [QPromise](qtpromise/qpromise/constructor.md)
|
||||
* [.delay](qtpromise/qpromise/delay.md)
|
||||
* [.fail](qtpromise/qpromise/fail.md)
|
||||
* [.finally](qtpromise/qpromise/finally.md)
|
||||
* [.isFulfilled](qtpromise/qpromise/isfulfilled.md)
|
||||
* [.isPending](qtpromise/qpromise/ispending.md)
|
||||
* [.isRejected](qtpromise/qpromise/isrejected.md)
|
||||
* [.tap](qtpromise/qpromise/tap.md)
|
||||
* [.tapFail](qtpromise/qpromise/tapfail.md)
|
||||
* [.then](qtpromise/qpromise/then.md)
|
||||
* [.timeout](qtpromise/qpromise/timeout.md)
|
||||
* [.wait](qtpromise/qpromise/wait.md)
|
||||
* [::all (static)](qtpromise/qpromise/all.md)
|
||||
* [::reject (static)](qtpromise/qpromise/reject.md)
|
||||
* [::resolve (static)](qtpromise/qpromise/resolve.md)
|
||||
* [qPromise](qtpromise/helpers/qpromise.md)
|
||||
* [qPromiseAll](qtpromise/helpers/qpromiseall.md)
|
@ -1,15 +0,0 @@
|
||||
a.anchorjs-link {
|
||||
color: rgba(65, 131, 196, 0.1);
|
||||
font-weight: 400;
|
||||
text-decoration: none;
|
||||
transition: color 100ms ease-out;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
a.anchorjs-link:hover {
|
||||
color: rgba(65, 131, 196, 1);
|
||||
}
|
||||
|
||||
sup {
|
||||
font-size: 0.75em !important;
|
||||
}
|
@ -1,21 +1,24 @@
|
||||
## QPromise
|
||||
# API Reference
|
||||
|
||||
### Public Members
|
||||
## Functions
|
||||
|
||||
* [`QPromise<T>::QPromise`](qpromise/constructor.md)
|
||||
* [`QPromise<T>::delay`](qpromise/delay.md)
|
||||
* [`QPromise<T>::each`](qpromise/each.md)
|
||||
* [`QPromise<T>::fail`](qpromise/fail.md)
|
||||
* [`QPromise<T>::filter`](qpromise/filter.md)
|
||||
* [`QPromise<T>::finally`](qpromise/finally.md)
|
||||
* [`QPromise<T>::isFulfilled`](qpromise/isfulfilled.md)
|
||||
* [`QPromise<T>::isPending`](qpromise/ispending.md)
|
||||
* [`QPromise<T>::isRejected`](qpromise/isrejected.md)
|
||||
* [`QPromise<T>::map`](qpromise/map.md)
|
||||
* [`QPromise<T>::tap`](qpromise/tap.md)
|
||||
* [`QPromise<T>::tapFail`](qpromise/tapfail.md)
|
||||
* [`QPromise<T>::then`](qpromise/then.md)
|
||||
* [`QPromise<T>::timeout`](qpromise/timeout.md)
|
||||
* [`QPromise<T>::wait`](qpromise/wait.md)
|
||||
|
||||
### Public Static Members
|
||||
## Static Functions
|
||||
|
||||
* [`[static] QPromise<T>::all`](qpromise/all.md)
|
||||
* [`[static] QPromise<T>::reject`](qpromise/reject.md)
|
||||
@ -23,5 +26,9 @@
|
||||
|
||||
## Helpers
|
||||
|
||||
* [`QtPromise::attempt`](helpers/attempt.md)
|
||||
* [`QtPromise::each`](helpers/each.md)
|
||||
* [`QtPromise::filter`](helpers/filter.md)
|
||||
* [`QtPromise::map`](helpers/map.md)
|
||||
* [`qPromise`](helpers/qpromise.md)
|
||||
* [`qPromiseAll`](helpers/qpromiseall.md)
|
||||
|
@ -1,8 +1,10 @@
|
||||
# Getting Started
|
||||
|
||||
## Installation
|
||||
|
||||
QtPromise is a [header-only](https://en.wikipedia.org/wiki/Header-only) library, simply download the [latest release](https://github.com/simonbrunel/qtpromise/releases/latest) (or [`git submodule`](https://git-scm.com/docs/git-submodule)) and include `qtpromise.pri` from your project `.pro`.
|
||||
|
||||
## qpm
|
||||
### qpm
|
||||
|
||||
Alternatively and **only** if your project relies on [qpm](https://www.qpm.io/), you can install QtPromise as follow:
|
||||
|
||||
|
47
docs/qtpromise/helpers/attempt.md
Normal file
47
docs/qtpromise/helpers/attempt.md
Normal file
@ -0,0 +1,47 @@
|
||||
---
|
||||
title: attempt
|
||||
---
|
||||
|
||||
# QtPromise::attempt
|
||||
|
||||
*Since: 0.4.0*
|
||||
|
||||
```cpp
|
||||
QtPromise::attempt(Functor functor, Args...) -> QPromise<R>
|
||||
|
||||
// With:
|
||||
// - Functor: Function(Args...) -> R | QPromise<R>
|
||||
```
|
||||
|
||||
Calls `functor` immediately and returns a promise fulfilled with the value returned by
|
||||
`functor`. Any synchronous exceptions will be turned into rejections on the returned
|
||||
promise. This is a convenient method that can be used instead of handling both synchronous
|
||||
and asynchronous exception flows.
|
||||
|
||||
The type `R` of the `output` promise depends on the type returned by the `functor` function.
|
||||
If `functor` returns a promise (or `QFuture`), the `output` promise is delayed and will be
|
||||
resolved by the returned promise.
|
||||
|
||||
```cpp
|
||||
QPromise<QByteArray> download(const QUrl& url);
|
||||
|
||||
QPromise<QByteArray> process(const QUrl& url)
|
||||
{
|
||||
return QtPromise::attempt([&]() {
|
||||
if (!url.isValid()) {
|
||||
throw InvalidUrlException();
|
||||
}
|
||||
|
||||
return download(url);
|
||||
}
|
||||
}
|
||||
|
||||
auto output = process(url);
|
||||
|
||||
// 'output' type: QPromise<QByteArray>
|
||||
output.then([](const QByteArray& res) {
|
||||
// {...}
|
||||
}).fail([](const InvalidUrlException& err) {
|
||||
// {...}
|
||||
});
|
||||
```
|
45
docs/qtpromise/helpers/each.md
Normal file
45
docs/qtpromise/helpers/each.md
Normal file
@ -0,0 +1,45 @@
|
||||
---
|
||||
title: each
|
||||
---
|
||||
|
||||
# QtPromise::each
|
||||
|
||||
*Since: 0.4.0*
|
||||
|
||||
```cpp
|
||||
QtPromise::each(Sequence<T> values, Functor functor) -> QPromise<Sequence<T>>
|
||||
|
||||
// With:
|
||||
// - Sequence: STL compatible container (e.g. QVector, etc.)
|
||||
// - Functor: Function(T value, int index) -> void | QPromise<void>
|
||||
```
|
||||
|
||||
Calls the given `functor` on each element in `values` then resolves to the original sequence
|
||||
unmodified. If `functor` throws, `output` is rejected with the new exception.
|
||||
|
||||
If `functor` returns a promise (or `QFuture`), the `output` promise is delayed until all the
|
||||
promises are resolved. If any of the promises fail, `output` immediately rejects with the error
|
||||
of the promise that rejected, whether or not the other promises are resolved.
|
||||
|
||||
|
||||
```cpp
|
||||
auto output = QtPromise::each(QVector<QUrl>{
|
||||
QUrl("http://a..."),
|
||||
QUrl("http://b..."),
|
||||
QUrl("http://c...")
|
||||
}, [](const QUrl& url, ...) {
|
||||
return QPromise<void>([&](auto resolve, auto reject) {
|
||||
// process url asynchronously ...
|
||||
})
|
||||
});
|
||||
|
||||
// `output` resolves as soon as all promises returned by
|
||||
// `functor` are fulfilled or at least one is rejected.
|
||||
|
||||
// output type: QPromise<QVector<QUrl>>
|
||||
output.then([](const QVector<QUrl>& res) {
|
||||
// 'res' contains the original values
|
||||
});
|
||||
```
|
||||
|
||||
See also: [`QPromise<T>::each`](../qpromise/each.md)
|
52
docs/qtpromise/helpers/filter.md
Normal file
52
docs/qtpromise/helpers/filter.md
Normal file
@ -0,0 +1,52 @@
|
||||
---
|
||||
title: filter
|
||||
---
|
||||
|
||||
# QtPromise::filter
|
||||
|
||||
*Since: 0.4.0*
|
||||
|
||||
```cpp
|
||||
QtPromise::filter(Sequence<T> values, Filterer filterer) -> QPromise<Sequence<T>>
|
||||
|
||||
// With:
|
||||
// - Sequence: STL compatible container (e.g. QVector, etc.)
|
||||
// - Filterer: Function(T value, int index) -> bool
|
||||
```
|
||||
|
||||
Iterates over `values` and [filters the sequence](https://en.wikipedia.org/wiki/Filter_%28higher-order_function%29)
|
||||
to another using the given `filterer` function. If `filterer` returns `true`, a copy of the item
|
||||
is put in the `output` sequence, otherwise, the item will not appear in `output`. If `filterer`
|
||||
throws, `output` is rejected with the new exception.
|
||||
|
||||
If `filterer` returns a promise (or `QFuture`), the `output` promise is delayed until all the
|
||||
promises are resolved. If any of the promises fail, `output` immediately rejects with the error
|
||||
of the promise that rejected, whether or not the other promises are resolved.
|
||||
|
||||
```cpp
|
||||
auto output = QtPromise::filter(QVector{
|
||||
QUrl("http://a..."),
|
||||
QUrl("http://b..."),
|
||||
QUrl("http://c...")
|
||||
}, [](const QUrl& url, ...) {
|
||||
return QPromise<bool>([&](auto resolve, auto reject) {
|
||||
// resolve(true) if 'url' is reachable, else resolve(false)
|
||||
// {...}
|
||||
});
|
||||
});
|
||||
|
||||
// 'output' resolves as soon as all promises returned by
|
||||
// 'filterer' are fulfilled or at least one is rejected.
|
||||
|
||||
// 'output' type: QPromise<QVector<QUrl>>
|
||||
output.then([](const QVector<QUrl>& res) {
|
||||
// 'res' contains only reachable URLs
|
||||
});
|
||||
```
|
||||
|
||||
::: tip NOTE
|
||||
The order of the output sequence values is guarantee to be the same as the original
|
||||
sequence, regardless of completion order of the promises returned by `filterer`.
|
||||
:::
|
||||
|
||||
See also: [`QPromise<T>::filter`](../qpromise/filter.md)
|
51
docs/qtpromise/helpers/map.md
Normal file
51
docs/qtpromise/helpers/map.md
Normal file
@ -0,0 +1,51 @@
|
||||
---
|
||||
title: map
|
||||
---
|
||||
|
||||
# QtPromise::map
|
||||
|
||||
*Since: 0.4.0*
|
||||
|
||||
```cpp
|
||||
QtPromise::map(Sequence<T> values, Mapper mapper) -> QPromise<QVector<R>>
|
||||
|
||||
// With:
|
||||
// - Sequence: STL compatible container (e.g. QVector, etc.)
|
||||
// - Mapper: Function(T value, int index) -> R | QPromise<R>
|
||||
```
|
||||
|
||||
Iterates over `values` and [maps the sequence](https://en.wikipedia.org/wiki/Map_%28higher-order_function%29)
|
||||
to another using the given `mapper` function. The type returned by `mapper` determines the type
|
||||
of the `output` promise. If `mapper` throws, `output` is rejected with the new exception.
|
||||
|
||||
If `mapper` returns a promise (or `QFuture`), the `output` promise is delayed until all the
|
||||
promises are resolved. If any of the promises fails, `output` immediately rejects with the
|
||||
error of the promise that rejected, whether or not the other promises are resolved.
|
||||
|
||||
```cpp
|
||||
auto output = QtPromise::map(QVector{
|
||||
QUrl("http://a..."),
|
||||
QUrl("http://b..."),
|
||||
QUrl("http://c...")
|
||||
}, [](const QUrl& url, ...) {
|
||||
return QPromise<QByteArray>([&](auto resolve, auto reject) {
|
||||
// download content at url and resolve
|
||||
// {...}
|
||||
});
|
||||
});
|
||||
|
||||
// 'output' resolves as soon as all promises returned by
|
||||
// 'mapper' are fulfilled or at least one is rejected.
|
||||
|
||||
// 'output' type: QPromise<QVector<QByteArray>>
|
||||
output.then([](const QVector<QByteArray>& res) {
|
||||
// {...}
|
||||
});
|
||||
```
|
||||
|
||||
::: tip NOTE
|
||||
The order of the output sequence values is guarantee to be the same as the original
|
||||
sequence, regardless of completion order of the promises returned by `mapper`.
|
||||
:::
|
||||
|
||||
See also: [`QPromise<T>::map`](../qpromise/map.md)
|
@ -1,4 +1,10 @@
|
||||
## `qPromise`
|
||||
---
|
||||
title: qPromise
|
||||
---
|
||||
|
||||
# qPromise
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```
|
||||
qPromise(T value) -> QPromise<R>
|
||||
|
@ -1,4 +1,10 @@
|
||||
## `qPromiseAll`
|
||||
---
|
||||
title: qPromiseAll
|
||||
---
|
||||
|
||||
# qPromiseAll
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```
|
||||
qPromiseAll(Sequence<QPromise<T>> promises) -> QPromise<QVector<T>>
|
||||
|
@ -1,4 +1,10 @@
|
||||
## `[static] QPromise<T>::all`
|
||||
---
|
||||
title: ::all [static]
|
||||
---
|
||||
|
||||
# QPromise::all [static]
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```
|
||||
[static] QPromise<T>::all(Sequence<QPromise<T>> promises) -> QPromise<QVector<T>>
|
||||
|
@ -1,6 +1,12 @@
|
||||
## `QPromise<T>::QPromise`
|
||||
---
|
||||
title: constructor
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::QPromise
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::QPromise(Function resolver)
|
||||
```
|
||||
|
||||
@ -18,7 +24,9 @@ QPromise<int> promise([](const QPromiseResolve<int>& resolve, const QPromiseReje
|
||||
});
|
||||
```
|
||||
|
||||
> **Note:** `QPromise<void>` is specialized to not contain any value, meaning that the `resolve` callback takes no argument.
|
||||
::: tip NOTE
|
||||
`QPromise<void>` is specialized to not contain any value, meaning that the `resolve` callback takes no argument.
|
||||
:::
|
||||
|
||||
**C++14**
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
## `QPromise<T>::delay`
|
||||
---
|
||||
title: .delay
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::delay
|
||||
|
||||
*Since: 0.2.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::delay(int msec) -> QPromise<T>
|
||||
```
|
||||
|
||||
|
56
docs/qtpromise/qpromise/each.md
Normal file
56
docs/qtpromise/qpromise/each.md
Normal file
@ -0,0 +1,56 @@
|
||||
---
|
||||
title: .each
|
||||
---
|
||||
|
||||
# QPromise::each
|
||||
|
||||
*Since: 0.4.0*
|
||||
|
||||
```cpp
|
||||
QPromise<Sequence<T>>::each(Functor functor) -> QPromise<Sequence<T>>
|
||||
|
||||
// With:
|
||||
// - Sequence: STL compatible container
|
||||
// - Functor: Function(T value, int index) -> any
|
||||
```
|
||||
|
||||
::: warning IMPORTANT
|
||||
This method only applies to promise with sequence value.
|
||||
:::
|
||||
|
||||
Calls the given `functor` on each element in the promise value (i.e. `Sequence<T>`), then resolves to the original sequence unmodified. If `functor` throws, `output` is rejected with the new exception.
|
||||
|
||||
```cpp
|
||||
QPromise<QList<QByteArray>> input = {...}
|
||||
|
||||
auto output = input.each([](const QByteArray& value, int index) {
|
||||
// process value ...
|
||||
});
|
||||
|
||||
// output type: QPromise<QList<QByteArray>>
|
||||
output.then([](const QList<QByteArray>& res) {
|
||||
// 'res' contains the original values
|
||||
});
|
||||
```
|
||||
|
||||
If `functor` returns a promise (or `QFuture`), the `output` promise is delayed until all the promises are resolved. If any of the promises fail, `output` immediately rejects with the error of the promise that rejected, whether or not the other promises are resolved.
|
||||
|
||||
```cpp
|
||||
QPromise<QList<QUrl>> input = {...}
|
||||
|
||||
auto output = input.each([](const QUrl& url, ...) {
|
||||
return QPromise<void>([&](auto resolve, auto reject) {
|
||||
// process url asynchronously ...
|
||||
})
|
||||
});
|
||||
|
||||
// `output` resolves as soon as all promises returned by
|
||||
// `functor` are fulfilled or at least one is rejected.
|
||||
|
||||
// output type: QPromise<QList<QUrl>>
|
||||
output.then([](const QList<QUrl>& res) {
|
||||
// 'res' contains the original values
|
||||
});
|
||||
```
|
||||
|
||||
See also: [`QtPromise::each`](../helpers/each.md)
|
@ -1,6 +1,12 @@
|
||||
## `QPromise<T>::fail`
|
||||
---
|
||||
title: .fail
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::fail
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::fail(Function onRejected) -> QPromise<T>
|
||||
```
|
||||
|
||||
|
55
docs/qtpromise/qpromise/filter.md
Normal file
55
docs/qtpromise/qpromise/filter.md
Normal file
@ -0,0 +1,55 @@
|
||||
---
|
||||
title: .filter
|
||||
---
|
||||
|
||||
# QPromise::filter
|
||||
|
||||
*Since: 0.4.0*
|
||||
|
||||
```cpp
|
||||
QPromise<Sequence<T>>::filter(Filter filterer) -> QPromise<Sequence<T>>
|
||||
|
||||
// With:
|
||||
// - Sequence: STL compatible container (e.g. QVector, etc.)
|
||||
// - Filterer: Function(T value, int index) -> bool
|
||||
```
|
||||
|
||||
::: warning IMPORTANT
|
||||
This method only applies to promise with sequence value.
|
||||
:::
|
||||
|
||||
Iterates over all the promise values (i.e. `Sequence<T>`) and [filters the sequence](https://en.wikipedia.org/wiki/Filter_%28higher-order_function%29)
|
||||
to another using the given `filterer` function. If `filterer` returns `true`, a copy of the item
|
||||
is put in the `output` sequence, otherwise, the item will not appear in `output`. If `filterer`
|
||||
throws, `output` is rejected with the new exception.
|
||||
|
||||
If `filterer` returns a promise (or `QFuture`), the `output` promise is delayed until all the
|
||||
promises are resolved. If any of the promises fail, `output` immediately rejects with the error
|
||||
of the promise that rejected, whether or not the other promises are resolved.
|
||||
|
||||
```cpp
|
||||
QPromise<QList<QUrl>> input = {...}
|
||||
|
||||
auto output = input.filter([](const QUrl& url, ...) {
|
||||
return url.isValid(); // Keep only valid URLs
|
||||
}).filter([](const QUrl& url, ...) {
|
||||
return QPromise<bool>([&](auto resolve, auto reject) {
|
||||
// resolve(true) if `url` is reachable, else resolve(false)
|
||||
});
|
||||
});
|
||||
|
||||
// 'output' resolves as soon as all promises returned by
|
||||
// 'filterer' are fulfilled or at least one is rejected.
|
||||
|
||||
// 'output' type: QPromise<QList<QUrl>>
|
||||
output.then([](const QList<QUrl>& res) {
|
||||
// 'res' contains only reachable URLs
|
||||
});
|
||||
```
|
||||
|
||||
::: tip NOTE
|
||||
The order of the output sequence values is guarantee to be the same as the original
|
||||
sequence, regardless of completion order of the promises returned by `filterer`.
|
||||
:::
|
||||
|
||||
See also: [`QtPromise::filter`](../helpers/filter.md)
|
@ -1,6 +1,12 @@
|
||||
## `QPromise<T>::finally`
|
||||
---
|
||||
title: .finally
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::finally
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::finally(Function handler) -> QPromise<T>
|
||||
```
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
# `QPromise<T>::isFulfilled`
|
||||
---
|
||||
title: .isFulfilled
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::isFulfilled
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::isFulfilled() -> bool
|
||||
```
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
# `QPromise<T>::isPending`
|
||||
---
|
||||
title: .isPending
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::isPending
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::isPending() -> bool
|
||||
```
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
# `QPromise<T>::isRejected`
|
||||
---
|
||||
title: .isRejected
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::isRejected
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::isRejected() -> bool
|
||||
```
|
||||
|
||||
|
67
docs/qtpromise/qpromise/map.md
Normal file
67
docs/qtpromise/qpromise/map.md
Normal file
@ -0,0 +1,67 @@
|
||||
---
|
||||
title: .map
|
||||
---
|
||||
|
||||
# QPromise::map
|
||||
|
||||
*Since: 0.4.0*
|
||||
|
||||
```cpp
|
||||
QPromise<Sequence<T>>::map(Mapper mapper) -> QPromise<QVector<R>>
|
||||
|
||||
// With:
|
||||
// - Sequence: STL compatible container (e.g. QVector, etc.)
|
||||
// - Mapper: Function(T value, int index) -> R | QPromise<R>
|
||||
```
|
||||
|
||||
::: warning IMPORTANT
|
||||
This method only applies to promise with sequence value.
|
||||
:::
|
||||
|
||||
Iterates over all the promise values (i.e. `Sequence<T>`) and [maps the sequence](https://en.wikipedia.org/wiki/Map_%28higher-order_function%29)
|
||||
to another using the given `mapper` function. The type returned by `mapper` determines the type
|
||||
of the `output` promise. If `mapper` throws, `output` is rejected with the new exception.
|
||||
|
||||
If `mapper` returns a promise (or `QFuture`), the `output` promise is delayed until all the
|
||||
promises are resolved. If any of the promises fails, `output` immediately rejects with the
|
||||
error of the promise that rejected, whether or not the other promises are resolved.
|
||||
|
||||
```cpp
|
||||
QPromise<QList<QUrl>> input = {...}
|
||||
|
||||
auto output = input.map([](const QUrl& url, int index) {
|
||||
return QPromise<QByteArray>([&](auto resolve, auto reject) {
|
||||
// download content at 'url' and resolve
|
||||
// {...}
|
||||
});
|
||||
}).map([](const QByteArray& value, ...) {
|
||||
// process the downloaded QByteArray
|
||||
// {...}
|
||||
return DownloadResult(value);
|
||||
});
|
||||
|
||||
// 'output' resolves as soon as all promises returned by
|
||||
// 'mapper' are fulfilled or at least one is rejected.
|
||||
|
||||
// 'output' type: QPromise<QVector<DownloadResult>>
|
||||
output.then([](const QVector<DownloadResult>& res) {
|
||||
// {...}
|
||||
});
|
||||
```
|
||||
|
||||
::: tip NOTE
|
||||
The order of the output sequence values is guarantee to be the same as the original
|
||||
sequence, regardless of completion order of the promises returned by `mapper`.
|
||||
:::
|
||||
|
||||
This function is provided for convenience and is similar to:
|
||||
|
||||
```cpp
|
||||
promise.then([](const Sequence<T>& values) {
|
||||
return QtPromise::map(values, [](const T& value, int index) {
|
||||
return // {...}
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
See also: [`QtPromise::map`](../helpers/map.md)
|
@ -1,6 +1,12 @@
|
||||
## `[static] QPromise<T>::reject`
|
||||
---
|
||||
title: ::reject [static]
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::reject [static]
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```cpp
|
||||
[static] QPromise<T>::reject(any reason) -> QPromise<T>
|
||||
```
|
||||
|
||||
|
@ -1,4 +1,10 @@
|
||||
## `[static] QPromise<T>::resolve`
|
||||
---
|
||||
title: ::resolve [static]
|
||||
---
|
||||
|
||||
# QPromise::resolve [static]
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```
|
||||
[static] QPromise<T>::resolve(T value) -> QPromise<T>
|
||||
|
@ -1,6 +1,12 @@
|
||||
## `QPromise<T>::tap`
|
||||
---
|
||||
title: .tap
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::tap
|
||||
|
||||
*Since: 0.2.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::tap(Function handler) -> QPromise<T>
|
||||
```
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
## `QPromise<T>::tapFail`
|
||||
---
|
||||
title: .tapFail
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::tapFail
|
||||
|
||||
*Since: 0.4.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::tapFail(Function handler) -> QPromise<T>
|
||||
```
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
## `QPromise<T>::then`
|
||||
---
|
||||
title: .then
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::then
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::then(Function onFulfilled, Function onRejected) -> QPromise<R>
|
||||
QPromise<T>::then(Function onFulfilled) -> QPromise<R>
|
||||
```
|
||||
@ -17,9 +23,11 @@ auto output = input.then([](int res) {
|
||||
});
|
||||
```
|
||||
|
||||
> **Note**: `onRejected` handler is optional, `output` will be rejected with the same reason as `input`.
|
||||
|
||||
> **Note**: it's recommended to use the [`fail`](fail.md) shorthand to handle errors.
|
||||
::: tip NOTE
|
||||
`onRejected` handler is optional, in which case `output` will be rejected with
|
||||
the same reason as `input`. Also note that it's recommended to use the
|
||||
[`fail`](fail.md) shorthand to handle errors.
|
||||
:::
|
||||
|
||||
The type `<R>` of the `output` promise depends on the return type of the `onFulfilled` handler:
|
||||
|
||||
@ -35,7 +43,11 @@ output.then([](const QString& res) {
|
||||
});
|
||||
```
|
||||
|
||||
> **Note**: only `onFulfilled` can change the promise type, `onRejected` **must** return the same type as `onFulfilled`. That also means if `onFulfilled` is `nullptr`, `onRejected` must return the same type as the `input` promise.
|
||||
::: tip NOTE
|
||||
Only `onFulfilled` can change the promise type, `onRejected` **must** return the
|
||||
same type as `onFulfilled`. That also means if `onFulfilled` is `nullptr`,
|
||||
`onRejected` must return the same type as the `input` promise.
|
||||
:::
|
||||
|
||||
```cpp
|
||||
QPromise<int> input = ...
|
||||
|
@ -1,6 +1,12 @@
|
||||
## `QPromise<T>::timeout`
|
||||
---
|
||||
title: .timeout
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::timeout
|
||||
|
||||
*Since: 0.2.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::timeout(int msec, any error = QPromiseTimeoutException) -> QPromise<T>
|
||||
```
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
## `QPromise<T>::wait`
|
||||
---
|
||||
title: .wait
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::wait
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::wait() -> QPromise<T>
|
||||
```
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
## QtConcurrent
|
||||
# QtConcurrent
|
||||
|
||||
QtPromise integrates with [QtConcurrent](https://doc.qt.io/qt-5/qtconcurrent-index.html) to make easy chaining QFuture with QPromise.
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
## Thread-Safety
|
||||
# Thread-Safety
|
||||
|
||||
QPromise is thread-safe and can be copied and accessed across different threads. QPromise relies on [explicitly data sharing](https://doc.qt.io/qt-5/qexplicitlyshareddatapointer.html#details) and thus `auto p2 = p1` represents the same promise: when `p1` resolves, handlers registered on `p1` and `p2` are called, the fulfilled value being shared between both instances.
|
||||
|
||||
> **Note:** while it's safe to access the resolved value from different threads using [`then`](qpromise/then.md), QPromise provides no guarantee about the object being pointed to. Thread-safety and reentrancy rules for that object still apply.
|
||||
::: warning IMPORTANT
|
||||
While it's safe to access the resolved value from different threads using [`then`](qpromise/then.md), QPromise provides no guarantee about the object being pointed to. Thread-safety and reentrancy rules for that object still apply.
|
||||
:::
|
||||
|
4
qpm.json
4
qpm.json
@ -10,9 +10,9 @@
|
||||
"url": "https://github.com/simonbrunel/qtpromise.git"
|
||||
},
|
||||
"version": {
|
||||
"label": "0.3.0"
|
||||
"label": "0.4.0"
|
||||
},
|
||||
"license": "MIT",
|
||||
"pri_filename": "qtpromise.pri",
|
||||
"webpage": "https://github.com/simonbrunel/qtpromise"
|
||||
"webpage": "https://qtpromise.netlify.com"
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "qpromise_p.h"
|
||||
#include "qpromiseerror.h"
|
||||
#include "qpromiseglobal.h"
|
||||
#include "qpromiseresolver.h"
|
||||
|
||||
// Qt
|
||||
#include <QExplicitlySharedDataPointer>
|
||||
@ -23,9 +24,6 @@ public:
|
||||
template <typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count != 1, int>::type = 0>
|
||||
inline QPromiseBase(F resolver);
|
||||
|
||||
template <typename U>
|
||||
inline QPromiseBase(const QPromise<U>& other);
|
||||
|
||||
QPromiseBase(const QPromiseBase<T>& other): m_d(other.m_d) {}
|
||||
QPromiseBase(const QPromise<T>& other): m_d(other.m_d) {}
|
||||
QPromiseBase(QPromiseBase<T>&& other) Q_DECL_NOEXCEPT { swap(other); }
|
||||
@ -90,6 +88,16 @@ public:
|
||||
template <typename F>
|
||||
QPromise(F&& resolver): QPromiseBase<T>(std::forward<F>(resolver)) { }
|
||||
|
||||
template <typename Functor>
|
||||
inline QPromise<T> each(Functor fn);
|
||||
|
||||
template <typename Functor>
|
||||
inline QPromise<T> filter(Functor fn);
|
||||
|
||||
template <typename Functor>
|
||||
inline typename QtPromisePrivate::PromiseMapper<T, Functor>::PromiseType
|
||||
map(Functor fn);
|
||||
|
||||
public: // STATIC
|
||||
template <template <typename, typename...> class Sequence = QVector, typename ...Args>
|
||||
inline static QPromise<QVector<T>> all(const Sequence<QPromise<T>, Args...>& promises);
|
||||
@ -97,9 +105,6 @@ public: // STATIC
|
||||
inline static QPromise<T> resolve(const T& value);
|
||||
inline static QPromise<T> resolve(T&& value);
|
||||
|
||||
template <typename U>
|
||||
operator QPromise<U>();
|
||||
|
||||
private:
|
||||
friend class QPromiseBase<T>;
|
||||
};
|
||||
@ -111,9 +116,6 @@ public:
|
||||
template <typename F>
|
||||
QPromise(F&& resolver): QPromiseBase<void>(std::forward<F>(resolver)) { }
|
||||
|
||||
template <typename T>
|
||||
QPromise(const QPromise<T>& other);
|
||||
|
||||
public: // STATIC
|
||||
template <template <typename, typename...> class Sequence = QVector, typename ...Args>
|
||||
inline static QPromise<void> all(const Sequence<QPromise<void>, Args...>& promises);
|
||||
|
@ -1,3 +1,6 @@
|
||||
#include "qpromise.h"
|
||||
#include "qpromisehelpers.h"
|
||||
|
||||
// Qt
|
||||
#include <QCoreApplication>
|
||||
#include <QSharedPointer>
|
||||
@ -5,47 +8,6 @@
|
||||
|
||||
namespace QtPromise {
|
||||
|
||||
template <class T>
|
||||
class QPromiseResolve
|
||||
{
|
||||
public:
|
||||
QPromiseResolve(QtPromisePrivate::PromiseResolver<T> resolver)
|
||||
: m_resolver(std::move(resolver))
|
||||
{ }
|
||||
|
||||
template <typename V>
|
||||
void operator()(V&& value) const
|
||||
{
|
||||
m_resolver.resolve(std::forward<V>(value));
|
||||
}
|
||||
|
||||
void operator()() const
|
||||
{
|
||||
m_resolver.resolve();
|
||||
}
|
||||
|
||||
private:
|
||||
mutable QtPromisePrivate::PromiseResolver<T> m_resolver;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class QPromiseReject
|
||||
{
|
||||
public:
|
||||
QPromiseReject(QtPromisePrivate::PromiseResolver<T> resolver)
|
||||
: m_resolver(std::move(resolver))
|
||||
{ }
|
||||
|
||||
template <typename E>
|
||||
void operator()(E&& error) const
|
||||
{
|
||||
m_resolver.reject(std::forward<E>(error));
|
||||
}
|
||||
|
||||
private:
|
||||
mutable QtPromisePrivate::PromiseResolver<T> m_resolver;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
template <typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count == 1, int>::type>
|
||||
inline QPromiseBase<T>::QPromiseBase(F callback)
|
||||
@ -74,19 +36,6 @@ inline QPromiseBase<T>::QPromiseBase(F callback)
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U>
|
||||
inline QPromiseBase<T>::QPromiseBase(const QPromise<U>& other)
|
||||
: m_d(new QtPromisePrivate::PromiseData<T>())
|
||||
{
|
||||
using namespace QtPromisePrivate;
|
||||
|
||||
QPromiseResolve<T> resolve(*this);
|
||||
QPromiseReject<T> reject(*this);
|
||||
|
||||
PromiseFulfill<QPromise<U> >::call(other, PromiseCast<U, T>::apply(resolve), reject);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename TFulfilled, typename TRejected>
|
||||
inline typename QtPromisePrivate::PromiseHandler<T, TFulfilled>::Promise
|
||||
@ -206,6 +155,48 @@ inline QPromise<T> QPromiseBase<T>::reject(E&& error)
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename Functor>
|
||||
inline QPromise<T> QPromise<T>::each(Functor fn)
|
||||
{
|
||||
return this->tap([=](const T& values) {
|
||||
int i = 0;
|
||||
|
||||
std::vector<QPromise<void>> promises;
|
||||
for (const auto& v : values) {
|
||||
promises.push_back(
|
||||
QtPromise::attempt(fn, v, i)
|
||||
.then([]() {
|
||||
// Cast to void in case fn returns a non promise value.
|
||||
// TODO remove when implicit cast is implemented.
|
||||
}));
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return QPromise<void>::all(promises);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename Functor>
|
||||
inline QPromise<T> QPromise<T>::filter(Functor fn)
|
||||
{
|
||||
return this->then([=](const T& values) {
|
||||
return QtPromise::filter(values, fn);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename Functor>
|
||||
inline typename QtPromisePrivate::PromiseMapper<T, Functor>::PromiseType
|
||||
QPromise<T>::map(Functor fn)
|
||||
{
|
||||
return this->then([=](const T& values) {
|
||||
return QtPromise::map(values, fn);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <template <typename, typename...> class Sequence, typename ...Args>
|
||||
inline QPromise<QVector<T>> QPromise<T>::all(const Sequence<QPromise<T>, Args...>& promises)
|
||||
@ -257,21 +248,6 @@ inline QPromise<T> QPromise<T>::resolve(T&& value)
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U>
|
||||
QPromise<T>::operator QPromise<U>()
|
||||
{
|
||||
return QPromise<U>::resolve(U());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
QPromise<void>::QPromise(const QPromise<T>& other)
|
||||
: QPromiseBase<void>([&](const QPromiseResolve<void>& resolve, const QPromiseReject<void>& reject) {
|
||||
QtPromisePrivate::PromiseFulfill<QPromise<T> >::call(other, resolve, reject);
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
template <template <typename, typename...> class Sequence, typename ...Args>
|
||||
inline QPromise<void> QPromise<void>::all(const Sequence<QPromise<void>, Args...>& promises)
|
||||
{
|
||||
|
@ -119,11 +119,20 @@ struct PromiseDeduce<QtPromise::QPromise<T>>
|
||||
: public PromiseDeduce<T>
|
||||
{ };
|
||||
|
||||
template <typename Functor, typename... Args>
|
||||
struct PromiseFunctor
|
||||
{
|
||||
using ResultType = typename std::result_of<Functor(Args...)>::type;
|
||||
using PromiseType = typename PromiseDeduce<ResultType>::Type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PromiseFulfill
|
||||
{
|
||||
template <typename TResolve, typename TReject>
|
||||
static void call(T&& value, const TResolve& resolve, const TReject&)
|
||||
static void call(
|
||||
T&& value,
|
||||
const QtPromise::QPromiseResolve<T>& resolve,
|
||||
const QtPromise::QPromiseReject<T>&)
|
||||
{
|
||||
resolve(std::move(value));
|
||||
}
|
||||
@ -132,11 +141,10 @@ struct PromiseFulfill
|
||||
template <typename T>
|
||||
struct PromiseFulfill<QtPromise::QPromise<T>>
|
||||
{
|
||||
template <typename TResolve, typename TReject>
|
||||
static void call(
|
||||
const QtPromise::QPromise<T>& promise,
|
||||
const TResolve& resolve,
|
||||
const TReject& reject)
|
||||
const QtPromise::QPromiseResolve<T>& resolve,
|
||||
const QtPromise::QPromiseReject<T>& reject)
|
||||
{
|
||||
if (promise.isFulfilled()) {
|
||||
resolve(promise.m_d->value());
|
||||
@ -155,9 +163,9 @@ struct PromiseFulfill<QtPromise::QPromise<T>>
|
||||
template <>
|
||||
struct PromiseFulfill<QtPromise::QPromise<void>>
|
||||
{
|
||||
template <typename TResolve, typename TReject>
|
||||
template <typename TPromise, typename TResolve, typename TReject>
|
||||
static void call(
|
||||
const QtPromise::QPromise<void>& promise,
|
||||
const TPromise& promise,
|
||||
const TResolve& resolve,
|
||||
const TReject& reject)
|
||||
{
|
||||
@ -175,51 +183,17 @@ struct PromiseFulfill<QtPromise::QPromise<void>>
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename TRes>
|
||||
template <typename Result>
|
||||
struct PromiseDispatch
|
||||
{
|
||||
using Promise = typename PromiseDeduce<TRes>::Type;
|
||||
using ResType = Unqualified<TRes>;
|
||||
|
||||
template <typename THandler, typename TResolve, typename TReject>
|
||||
static void call(const T& value, THandler handler, const TResolve& resolve, const TReject& reject)
|
||||
template <typename Resolve, typename Reject, typename Functor, typename... Args>
|
||||
static void call(const Resolve& resolve, const Reject& reject, Functor fn, Args&&... args)
|
||||
{
|
||||
try {
|
||||
PromiseFulfill<ResType>::call(handler(value), resolve, reject);
|
||||
} catch (...) {
|
||||
reject(std::current_exception());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PromiseDispatch<T, void>
|
||||
{
|
||||
using Promise = QtPromise::QPromise<void>;
|
||||
|
||||
template <typename THandler, typename TResolve, typename TReject>
|
||||
static void call(const T& value, THandler handler, const TResolve& resolve, const TReject& reject)
|
||||
{
|
||||
try {
|
||||
handler(value);
|
||||
resolve();
|
||||
} catch (...) {
|
||||
reject(std::current_exception());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TRes>
|
||||
struct PromiseDispatch<void, TRes>
|
||||
{
|
||||
using Promise = typename PromiseDeduce<TRes>::Type;
|
||||
using ResType = Unqualified<TRes>;
|
||||
|
||||
template <typename THandler, typename TResolve, typename TReject>
|
||||
static void call(THandler handler, const TResolve& resolve, const TReject& reject)
|
||||
{
|
||||
try {
|
||||
PromiseFulfill<ResType>::call(handler(), resolve, reject);
|
||||
PromiseFulfill<Unqualified<Result>>::call(
|
||||
fn(std::forward<Args>(args)...),
|
||||
resolve,
|
||||
reject);
|
||||
} catch (...) {
|
||||
reject(std::current_exception());
|
||||
}
|
||||
@ -227,15 +201,13 @@ struct PromiseDispatch<void, TRes>
|
||||
};
|
||||
|
||||
template <>
|
||||
struct PromiseDispatch<void, void>
|
||||
struct PromiseDispatch<void>
|
||||
{
|
||||
using Promise = QtPromise::QPromise<void>;
|
||||
|
||||
template <typename THandler, typename TResolve, typename TReject>
|
||||
static void call(THandler handler, const TResolve& resolve, const TReject& reject)
|
||||
template <typename Resolve, typename Reject, typename Functor, typename... Args>
|
||||
static void call(const Resolve& resolve, const Reject& reject, Functor fn, Args&&... args)
|
||||
{
|
||||
try {
|
||||
handler();
|
||||
fn(std::forward<Args>(args)...);
|
||||
resolve();
|
||||
} catch (...) {
|
||||
reject(std::current_exception());
|
||||
@ -247,7 +219,7 @@ template <typename T, typename THandler, typename TArg = typename ArgsOf<THandle
|
||||
struct PromiseHandler
|
||||
{
|
||||
using ResType = typename std::result_of<THandler(T)>::type;
|
||||
using Promise = typename PromiseDispatch<T, ResType>::Promise;
|
||||
using Promise = typename PromiseDeduce<ResType>::Type;
|
||||
|
||||
template <typename TResolve, typename TReject>
|
||||
static std::function<void(const T&)> create(
|
||||
@ -256,7 +228,7 @@ struct PromiseHandler
|
||||
const TReject& reject)
|
||||
{
|
||||
return [=](const T& value) {
|
||||
PromiseDispatch<T, ResType>::call(value, std::move(handler), resolve, reject);
|
||||
PromiseDispatch<ResType>::call(resolve, reject, handler, value);
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -265,7 +237,7 @@ template <typename T, typename THandler>
|
||||
struct PromiseHandler<T, THandler, void>
|
||||
{
|
||||
using ResType = typename std::result_of<THandler()>::type;
|
||||
using Promise = typename PromiseDispatch<T, ResType>::Promise;
|
||||
using Promise = typename PromiseDeduce<ResType>::Type;
|
||||
|
||||
template <typename TResolve, typename TReject>
|
||||
static std::function<void(const T&)> create(
|
||||
@ -274,7 +246,7 @@ struct PromiseHandler<T, THandler, void>
|
||||
const TReject& reject)
|
||||
{
|
||||
return [=](const T&) {
|
||||
PromiseDispatch<void, ResType>::call(handler, resolve, reject);
|
||||
PromiseDispatch<ResType>::call(resolve, reject, handler);
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -283,7 +255,7 @@ template <typename THandler>
|
||||
struct PromiseHandler<void, THandler, void>
|
||||
{
|
||||
using ResType = typename std::result_of<THandler()>::type;
|
||||
using Promise = typename PromiseDispatch<void, ResType>::Promise;
|
||||
using Promise = typename PromiseDeduce<ResType>::Type;
|
||||
|
||||
template <typename TResolve, typename TReject>
|
||||
static std::function<void()> create(
|
||||
@ -292,7 +264,7 @@ struct PromiseHandler<void, THandler, void>
|
||||
const TReject& reject)
|
||||
{
|
||||
return [=]() {
|
||||
PromiseDispatch<void, ResType>::call(handler, resolve, reject);
|
||||
PromiseDispatch<ResType>::call(resolve, reject, handler);
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -350,7 +322,7 @@ struct PromiseCatcher
|
||||
try {
|
||||
error.rethrow();
|
||||
} catch (const TArg& error) {
|
||||
PromiseDispatch<TArg, ResType>::call(error, handler, resolve, reject);
|
||||
PromiseDispatch<ResType>::call(resolve, reject, handler, error);
|
||||
} catch (...) {
|
||||
reject(std::current_exception());
|
||||
}
|
||||
@ -373,7 +345,7 @@ struct PromiseCatcher<T, THandler, void>
|
||||
try {
|
||||
error.rethrow();
|
||||
} catch (...) {
|
||||
PromiseDispatch<void, ResType>::call(handler, resolve, reject);
|
||||
PromiseDispatch<ResType>::call(resolve, reject, handler);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -396,66 +368,17 @@ struct PromiseCatcher<T, std::nullptr_t, void>
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
struct PromiseCast
|
||||
{
|
||||
template <typename F>
|
||||
static auto apply(const F& resolve)
|
||||
{
|
||||
return [=](const QSharedPointer<T>& value) {
|
||||
resolve(static_cast<T>(*value));
|
||||
};
|
||||
}
|
||||
};
|
||||
template <typename T, typename F>
|
||||
struct PromiseMapper
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct PromiseCast<T, void>
|
||||
template <typename T, typename F, template <typename, typename...> class Sequence, typename ...Args>
|
||||
struct PromiseMapper<Sequence<T, Args...>, F>
|
||||
{
|
||||
template <typename F>
|
||||
static auto apply(const F& resolve)
|
||||
{
|
||||
return [=](const QSharedPointer<T>&) {
|
||||
resolve();
|
||||
using ReturnType = typename std::result_of<F(T, int)>::type;
|
||||
using ResultType = QVector<typename PromiseDeduce<ReturnType>::Type::Type>;
|
||||
using PromiseType = QtPromise::QPromise<ResultType>;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
template <typename T>
|
||||
struct PromiseCast<T, QVariant>
|
||||
{
|
||||
static QtPromise::QPromise<QVariant> cast(
|
||||
const QtPromise::QPromiseBase<T>& input)
|
||||
{
|
||||
return input.then([](const T& res) {
|
||||
return QVariant::fromValue(res);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
template <typename U>
|
||||
struct PromiseCast<QVariant, U>
|
||||
{
|
||||
static QtPromise::QPromise<U> cast(
|
||||
const QtPromise::QPromiseBase<QVariant>& input)
|
||||
{
|
||||
return input.then([](const QVariant& res) {
|
||||
return res.value<U>();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct PromiseCast<void, QVariant>
|
||||
{
|
||||
static QtPromise::QPromise<void> cast(
|
||||
const QtPromise::QPromiseBase<QVariant>& input)
|
||||
{
|
||||
return input.then([]() {
|
||||
});
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
template <typename T> class PromiseData;
|
||||
|
||||
@ -622,68 +545,6 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class PromiseResolver
|
||||
{
|
||||
public:
|
||||
PromiseResolver(QtPromise::QPromise<T> promise)
|
||||
: m_d(new Data())
|
||||
{
|
||||
m_d->promise = new QtPromise::QPromise<T>(std::move(promise));
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void reject(E&& error)
|
||||
{
|
||||
auto promise = m_d->promise;
|
||||
if (promise) {
|
||||
Q_ASSERT(promise->isPending());
|
||||
promise->m_d->reject(std::forward<E>(error));
|
||||
promise->m_d->dispatch();
|
||||
release();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
void resolve(V&& value)
|
||||
{
|
||||
auto promise = m_d->promise;
|
||||
if (promise) {
|
||||
Q_ASSERT(promise->isPending());
|
||||
promise->m_d->resolve(std::forward<V>(value));
|
||||
promise->m_d->dispatch();
|
||||
release();
|
||||
}
|
||||
}
|
||||
|
||||
void resolve()
|
||||
{
|
||||
auto promise = m_d->promise;
|
||||
if (promise) {
|
||||
Q_ASSERT(promise->isPending());
|
||||
promise->m_d->resolve();
|
||||
promise->m_d->dispatch();
|
||||
release();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct Data : public QSharedData
|
||||
{
|
||||
QtPromise::QPromise<T>* promise = nullptr;
|
||||
};
|
||||
|
||||
QExplicitlySharedDataPointer<Data> m_d;
|
||||
|
||||
void release()
|
||||
{
|
||||
Q_ASSERT(m_d->promise);
|
||||
Q_ASSERT(!m_d->promise->isPending());
|
||||
delete m_d->promise;
|
||||
m_d->promise = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace QtPromise
|
||||
|
||||
#endif // ifndef QTPROMISE_QPROMISE_P_H
|
||||
#endif // ifndef QTPROMISE_QPROMISE_H
|
||||
|
@ -38,6 +38,83 @@ static inline QPromise<void> qPromiseAll(const Sequence<QPromise<void>, Args...>
|
||||
return QPromise<void>::all(promises);
|
||||
}
|
||||
|
||||
template <typename Functor, typename... Args>
|
||||
static inline typename QtPromisePrivate::PromiseFunctor<Functor, Args...>::PromiseType
|
||||
attempt(Functor&& fn, Args&&... args)
|
||||
{
|
||||
using namespace QtPromisePrivate;
|
||||
using FunctorType = PromiseFunctor<Functor, Args...>;
|
||||
using PromiseType = typename FunctorType::PromiseType;
|
||||
using ValueType = typename PromiseType::Type;
|
||||
|
||||
// NOTE: std::forward<T<U>>: MSVC 2013 fails when forwarding
|
||||
// template type (error: "expects 4 arguments - 0 provided").
|
||||
// However it succeeds with type alias.
|
||||
// TODO: should we expose QPromise::ResolveType & RejectType?
|
||||
using ResolveType = QPromiseResolve<ValueType>;
|
||||
using RejectType = QPromiseReject<ValueType>;
|
||||
|
||||
return PromiseType(
|
||||
[&](ResolveType&& resolve, RejectType&& reject) {
|
||||
PromiseDispatch<typename FunctorType::ResultType>::call(
|
||||
std::forward<ResolveType>(resolve),
|
||||
std::forward<RejectType>(reject),
|
||||
std::forward<Functor>(fn),
|
||||
std::forward<Args>(args)...);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Sequence, typename Functor>
|
||||
static inline QPromise<Sequence> each(const Sequence& values, Functor&& fn)
|
||||
{
|
||||
return QPromise<Sequence>::resolve(values).each(std::forward<Functor>(fn));
|
||||
}
|
||||
|
||||
template <typename Sequence, typename Functor>
|
||||
static inline typename QtPromisePrivate::PromiseMapper<Sequence, Functor>::PromiseType
|
||||
map(const Sequence& values, Functor fn)
|
||||
{
|
||||
using namespace QtPromisePrivate;
|
||||
using MapperType = PromiseMapper<Sequence, Functor>;
|
||||
using ResType = typename MapperType::ResultType::value_type;
|
||||
using RetType = typename MapperType::ReturnType;
|
||||
|
||||
int i = 0;
|
||||
|
||||
std::vector<QPromise<ResType>> promises;
|
||||
for (const auto& v : values) {
|
||||
promises.push_back(QPromise<ResType>([&](
|
||||
const QPromiseResolve<ResType>& resolve,
|
||||
const QPromiseReject<ResType>& reject) {
|
||||
PromiseFulfill<RetType>::call(fn(v, i), resolve, reject);
|
||||
}));
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return QPromise<ResType>::all(promises);
|
||||
}
|
||||
|
||||
template <typename Sequence, typename Functor>
|
||||
static inline QPromise<Sequence> filter(const Sequence& values, Functor fn)
|
||||
{
|
||||
return QtPromise::map(values, fn)
|
||||
.then([=](const QVector<bool>& filters) {
|
||||
Sequence filtered;
|
||||
|
||||
auto filter = filters.begin();
|
||||
for (auto& value : values) {
|
||||
if (*filter) {
|
||||
filtered.push_back(std::move(value));
|
||||
}
|
||||
|
||||
filter++;
|
||||
}
|
||||
|
||||
return filtered;
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace QtPromise
|
||||
|
||||
#endif // QTPROMISE_QPROMISEHELPERS_H
|
||||
|
124
src/qtpromise/qpromiseresolver.h
Normal file
124
src/qtpromise/qpromiseresolver.h
Normal file
@ -0,0 +1,124 @@
|
||||
#ifndef QTPROMISE_QPROMISERESOLVER_H
|
||||
#define QTPROMISE_QPROMISERESOLVER_H
|
||||
|
||||
// Qt
|
||||
#include <QExplicitlySharedDataPointer>
|
||||
|
||||
namespace QtPromise {
|
||||
|
||||
template <typename T> class QPromise;
|
||||
|
||||
} // namespace QtPromise
|
||||
|
||||
namespace QtPromisePrivate {
|
||||
|
||||
template <typename T>
|
||||
class PromiseResolver
|
||||
{
|
||||
public:
|
||||
PromiseResolver(QtPromise::QPromise<T> promise)
|
||||
: m_d(new Data())
|
||||
{
|
||||
m_d->promise = new QtPromise::QPromise<T>(std::move(promise));
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void reject(E&& error)
|
||||
{
|
||||
auto promise = m_d->promise;
|
||||
if (promise) {
|
||||
Q_ASSERT(promise->isPending());
|
||||
promise->m_d->reject(std::forward<E>(error));
|
||||
promise->m_d->dispatch();
|
||||
release();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
void resolve(V&& value)
|
||||
{
|
||||
auto promise = m_d->promise;
|
||||
if (promise) {
|
||||
Q_ASSERT(promise->isPending());
|
||||
promise->m_d->resolve(std::forward<V>(value));
|
||||
promise->m_d->dispatch();
|
||||
release();
|
||||
}
|
||||
}
|
||||
|
||||
void resolve()
|
||||
{
|
||||
auto promise = m_d->promise;
|
||||
if (promise) {
|
||||
Q_ASSERT(promise->isPending());
|
||||
promise->m_d->resolve();
|
||||
promise->m_d->dispatch();
|
||||
release();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct Data : public QSharedData
|
||||
{
|
||||
QtPromise::QPromise<T>* promise = nullptr;
|
||||
};
|
||||
|
||||
QExplicitlySharedDataPointer<Data> m_d;
|
||||
|
||||
void release()
|
||||
{
|
||||
Q_ASSERT(m_d->promise);
|
||||
Q_ASSERT(!m_d->promise->isPending());
|
||||
delete m_d->promise;
|
||||
m_d->promise = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
} // QtPromisePrivate
|
||||
|
||||
namespace QtPromise {
|
||||
|
||||
template <class T>
|
||||
class QPromiseResolve
|
||||
{
|
||||
public:
|
||||
QPromiseResolve(QtPromisePrivate::PromiseResolver<T> resolver)
|
||||
: m_resolver(std::move(resolver))
|
||||
{ }
|
||||
|
||||
template <typename V>
|
||||
void operator()(V&& value) const
|
||||
{
|
||||
m_resolver.resolve(std::forward<V>(value));
|
||||
}
|
||||
|
||||
void operator()() const
|
||||
{
|
||||
m_resolver.resolve();
|
||||
}
|
||||
|
||||
private:
|
||||
mutable QtPromisePrivate::PromiseResolver<T> m_resolver;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class QPromiseReject
|
||||
{
|
||||
public:
|
||||
QPromiseReject(QtPromisePrivate::PromiseResolver<T> resolver)
|
||||
: m_resolver(std::move(resolver))
|
||||
{ }
|
||||
|
||||
template <typename E>
|
||||
void operator()(E&& error) const
|
||||
{
|
||||
m_resolver.reject(std::forward<E>(error));
|
||||
}
|
||||
|
||||
private:
|
||||
mutable QtPromisePrivate::PromiseResolver<T> m_resolver;
|
||||
};
|
||||
|
||||
} // namespace QtPromise
|
||||
|
||||
#endif // QTPROMISE_QPROMISERESOLVER_H
|
@ -5,4 +5,5 @@ HEADERS += \
|
||||
$$PWD/qpromiseerror.h \
|
||||
$$PWD/qpromisefuture.h \
|
||||
$$PWD/qpromiseglobal.h \
|
||||
$$PWD/qpromisehelpers.h
|
||||
$$PWD/qpromisehelpers.h \
|
||||
$$PWD/qpromiseresolver.h
|
||||
|
@ -1,4 +1,4 @@
|
||||
TARGET = tst_qpromise_all
|
||||
TARGET = tst_helpers_all
|
||||
SOURCES += $$PWD/tst_all.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
221
tests/auto/qtpromise/helpers/all/tst_all.cpp
Normal file
221
tests/auto/qtpromise/helpers/all/tst_all.cpp
Normal file
@ -0,0 +1,221 @@
|
||||
// Tests
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_helpers_all : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void emptySequence();
|
||||
void emptySequence_void();
|
||||
void allPromisesSucceed();
|
||||
void allPromisesSucceed_void();
|
||||
void atLeastOnePromiseReject();
|
||||
void atLeastOnePromiseReject_void();
|
||||
void preserveOrder();
|
||||
void sequenceTypes();
|
||||
void sequenceTypes_void();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_helpers_all)
|
||||
#include "tst_all.moc"
|
||||
|
||||
namespace {
|
||||
|
||||
template <class Sequence>
|
||||
struct SequenceTester
|
||||
{
|
||||
Q_STATIC_ASSERT((std::is_same<typename Sequence::value_type, QPromise<int>>::value));
|
||||
|
||||
static void exec()
|
||||
{
|
||||
Sequence promises{
|
||||
QtPromise::qPromise(42),
|
||||
QtPromise::qPromise(43),
|
||||
QtPromise::qPromise(44)
|
||||
};
|
||||
|
||||
promises.push_back(QtPromise::qPromise(45));
|
||||
promises.insert(++promises.begin(), QtPromise::qPromise(46));
|
||||
promises.pop_back();
|
||||
|
||||
auto p = QtPromise::qPromiseAll(promises);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 46, 43, 44}));
|
||||
}
|
||||
};
|
||||
|
||||
template <template <typename, typename...> class Sequence, typename ...Args>
|
||||
struct SequenceTester<Sequence<QPromise<void>, Args...>>
|
||||
{
|
||||
static void exec()
|
||||
{
|
||||
Sequence<QPromise<void>, Args...> promises{
|
||||
QtPromise::qPromise(),
|
||||
QtPromise::qPromise(),
|
||||
QtPromise::qPromise()
|
||||
};
|
||||
|
||||
promises.push_back(QtPromise::qPromise());
|
||||
promises.insert(++promises.begin(), QtPromise::qPromise());
|
||||
promises.pop_back();
|
||||
|
||||
auto p = QtPromise::qPromiseAll(promises);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void tst_helpers_all::emptySequence()
|
||||
{
|
||||
auto p = QtPromise::qPromiseAll(QVector<QPromise<int>>());
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({}));
|
||||
}
|
||||
|
||||
void tst_helpers_all::emptySequence_void()
|
||||
{
|
||||
auto p = QtPromise::qPromiseAll(QVector<QPromise<void>>());
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
}
|
||||
|
||||
void tst_helpers_all::allPromisesSucceed()
|
||||
{
|
||||
auto p0 = QtPromise::qPromise(42);
|
||||
auto p1 = QtPromise::qPromise(44);
|
||||
auto p2 = QPromise<int>([](const QPromiseResolve<int>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
resolve(43);
|
||||
});
|
||||
});
|
||||
|
||||
auto p = QtPromise::qPromiseAll(QVector<QPromise<int>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 43, 44}));
|
||||
QCOMPARE(p2.isFulfilled(), true);
|
||||
}
|
||||
|
||||
void tst_helpers_all::allPromisesSucceed_void()
|
||||
{
|
||||
auto p0 = QtPromise::qPromise();
|
||||
auto p1 = QtPromise::qPromise();
|
||||
auto p2 = QPromise<void>([](const QPromiseResolve<void>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
auto p = QtPromise::qPromiseAll(QVector<QPromise<void>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
QCOMPARE(p2.isFulfilled(), true);
|
||||
}
|
||||
|
||||
void tst_helpers_all::atLeastOnePromiseReject()
|
||||
{
|
||||
auto p0 = QtPromise::qPromise(42);
|
||||
auto p1 = QtPromise::qPromise(44);
|
||||
auto p2 = QPromise<int>([](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
reject(QString("foo"));
|
||||
});
|
||||
});
|
||||
|
||||
auto p = QtPromise::qPromiseAll(QVector<QPromise<int>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
QCOMPARE(p2.isRejected(), true);
|
||||
}
|
||||
|
||||
void tst_helpers_all::atLeastOnePromiseReject_void()
|
||||
{
|
||||
auto p0 = QtPromise::qPromise();
|
||||
auto p1 = QtPromise::qPromise();
|
||||
auto p2 = QPromise<void>([](const QPromiseResolve<void>&, const QPromiseReject<void>& reject) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
reject(QString("foo"));
|
||||
});
|
||||
});
|
||||
|
||||
auto p = QtPromise::qPromiseAll(QVector<QPromise<void>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
QCOMPARE(p2.isRejected(), true);
|
||||
}
|
||||
|
||||
void tst_helpers_all::preserveOrder()
|
||||
{
|
||||
auto p0 = QtPromise::qPromise(42).delay(500);
|
||||
auto p1 = QtPromise::qPromise(43).delay(100);
|
||||
auto p2 = QtPromise::qPromise(44).delay(250);
|
||||
|
||||
auto p = QtPromise::qPromiseAll(QVector<QPromise<int>>{p0, p1, p2});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(p0.isPending(), true);
|
||||
QCOMPARE(p1.isPending(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 43, 44}));
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isFulfilled(), true);
|
||||
}
|
||||
|
||||
// QVector::push_back/append isn't supported since it requires a default
|
||||
// constructor (see https://github.com/simonbrunel/qtpromise/issues/3)
|
||||
|
||||
void tst_helpers_all::sequenceTypes()
|
||||
{
|
||||
SequenceTester<QList<QPromise<int>>>::exec();
|
||||
//SequenceTester<QVector<QPromise<int>>>::exec();
|
||||
SequenceTester<std::list<QPromise<int>>>::exec();
|
||||
SequenceTester<std::vector<QPromise<int>>>::exec();
|
||||
}
|
||||
|
||||
void tst_helpers_all::sequenceTypes_void()
|
||||
{
|
||||
SequenceTester<QList<QPromise<void>>>::exec();
|
||||
//SequenceTester<QVector<QPromise<void>>>::exec();
|
||||
SequenceTester<std::list<QPromise<void>>>::exec();
|
||||
SequenceTester<std::vector<QPromise<void>>>::exec();
|
||||
}
|
5
tests/auto/qtpromise/helpers/attempt/attempt.pro
Normal file
5
tests/auto/qtpromise/helpers/attempt/attempt.pro
Normal file
@ -0,0 +1,5 @@
|
||||
QT += concurrent
|
||||
TARGET = tst_helpers_attempt
|
||||
SOURCES += $$PWD/tst_attempt.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
99
tests/auto/qtpromise/helpers/attempt/tst_attempt.cpp
Normal file
99
tests/auto/qtpromise/helpers/attempt/tst_attempt.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
// Tests
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtConcurrent>
|
||||
#include <QtTest>
|
||||
|
||||
// STL
|
||||
#include <memory>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_helpers_attempt : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void voidResult();
|
||||
void typedResult();
|
||||
void futureResult();
|
||||
void promiseResult();
|
||||
void functorThrows();
|
||||
void callWithParams();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_helpers_attempt)
|
||||
#include "tst_attempt.moc"
|
||||
|
||||
void tst_helpers_attempt::voidResult()
|
||||
{
|
||||
auto p = QtPromise::attempt([]() {});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
}
|
||||
|
||||
void tst_helpers_attempt::typedResult()
|
||||
{
|
||||
auto p = QtPromise::attempt([]() {
|
||||
return QString("foo");
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(waitForValue(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
void tst_helpers_attempt::futureResult()
|
||||
{
|
||||
auto p = QtPromise::attempt([]() {
|
||||
return QtConcurrent::run([]() {
|
||||
return QString("foo");
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
void tst_helpers_attempt::promiseResult()
|
||||
{
|
||||
auto p = QtPromise::attempt([]() {
|
||||
return QtPromise::qPromise(42).delay(200);
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, -1), 42);
|
||||
}
|
||||
|
||||
void tst_helpers_attempt::functorThrows()
|
||||
{
|
||||
auto p = QtPromise::attempt([]() {
|
||||
if (true) {
|
||||
throw QString("bar");
|
||||
}
|
||||
return 42;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
QCOMPARE(waitForError(p, QString()), QString("bar"));
|
||||
}
|
||||
|
||||
void tst_helpers_attempt::callWithParams()
|
||||
{
|
||||
auto p = QtPromise::attempt([&](int i, const QString& s) {
|
||||
return QString("%1:%2").arg(i).arg(s);
|
||||
}, 42, "foo");
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(waitForValue(p, QString()), QString("42:foo"));
|
||||
}
|
4
tests/auto/qtpromise/helpers/each/each.pro
Normal file
4
tests/auto/qtpromise/helpers/each/each.pro
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = tst_qpromise_each
|
||||
SOURCES += $$PWD/tst_each.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
154
tests/auto/qtpromise/helpers/each/tst_each.cpp
Normal file
154
tests/auto/qtpromise/helpers/each/tst_each.cpp
Normal file
@ -0,0 +1,154 @@
|
||||
// Tests
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_helpers_each : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void emptySequence();
|
||||
void preserveValues();
|
||||
void ignoreResult();
|
||||
void delayedFulfilled();
|
||||
void delayedRejected();
|
||||
void functorThrows();
|
||||
void functorArguments();
|
||||
void sequenceTypes();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_helpers_each)
|
||||
#include "tst_each.moc"
|
||||
|
||||
namespace {
|
||||
|
||||
template <class Sequence>
|
||||
struct SequenceTester
|
||||
{
|
||||
static void exec()
|
||||
{
|
||||
QVector<int> values;
|
||||
auto p = QtPromise::each(Sequence{42, 43, 44}, [&](int v, int i) {
|
||||
values << i << v;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Sequence>>::value));
|
||||
QCOMPARE(waitForValue(p, Sequence()), Sequence({42, 43, 44}));
|
||||
QCOMPARE(values, QVector<int>({0, 42, 1, 43, 2, 44}));
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void tst_helpers_each::emptySequence()
|
||||
{
|
||||
QVector<int> values;
|
||||
auto p = QtPromise::each(QVector<int>{}, [&](int v, ...) {
|
||||
values << v;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>());
|
||||
QCOMPARE(values, QVector<int>({}));
|
||||
}
|
||||
|
||||
void tst_helpers_each::preserveValues()
|
||||
{
|
||||
QVector<int> values;
|
||||
auto p = QtPromise::each(QVector<int>{42, 43, 44}, [&](int v, ...) {
|
||||
values << v + 1;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 43, 44}));
|
||||
QCOMPARE(values, QVector<int>({43, 44, 45}));
|
||||
}
|
||||
|
||||
void tst_helpers_each::ignoreResult()
|
||||
{
|
||||
QVector<int> values;
|
||||
auto p = QtPromise::each(QVector<int>{42, 43, 44}, [&](int v, ...) {
|
||||
values << v + 1;
|
||||
return "Foo";
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 43, 44}));
|
||||
QCOMPARE(values, QVector<int>({43, 44, 45}));
|
||||
}
|
||||
|
||||
void tst_helpers_each::delayedFulfilled()
|
||||
{
|
||||
QMap<int, int> values;
|
||||
auto p = QtPromise::each(QVector<int>{42, 43, 44}, [&](int v, int index) {
|
||||
return QPromise<int>([&](const QPromiseResolve<int>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=, &values]() {
|
||||
values[v] = index;
|
||||
resolve(42);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 43, 44}));
|
||||
QMap<int, int> expected{{42, 0}, {43, 1}, {44, 2}};
|
||||
QCOMPARE(values, expected);
|
||||
}
|
||||
|
||||
void tst_helpers_each::delayedRejected()
|
||||
{
|
||||
auto p = QtPromise::each(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||
return QPromise<int>([&](
|
||||
const QPromiseResolve<int>& resolve,
|
||||
const QPromiseReject<int>& reject) {
|
||||
QtPromisePrivate::qtpromise_defer([=]() {
|
||||
if (v == 43) {
|
||||
reject(QString("foo"));
|
||||
}
|
||||
resolve(v);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
void tst_helpers_each::functorThrows()
|
||||
{
|
||||
auto p = QtPromise::each(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||
if (v == 44) {
|
||||
throw QString("foo");
|
||||
}
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
void tst_helpers_each::functorArguments()
|
||||
{
|
||||
QVector<int> values;
|
||||
auto p = QtPromise::each(QVector<int>{42, 43, 44}, [&](int v, int i) {
|
||||
values << i << v;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 43, 44}));
|
||||
QCOMPARE(values, QVector<int>({0, 42, 1, 43, 2, 44}));
|
||||
}
|
||||
|
||||
void tst_helpers_each::sequenceTypes()
|
||||
{
|
||||
SequenceTester<QList<int>>::exec();
|
||||
SequenceTester<QVector<int>>::exec();
|
||||
SequenceTester<std::list<int>>::exec();
|
||||
SequenceTester<std::vector<int>>::exec();
|
||||
}
|
4
tests/auto/qtpromise/helpers/filter/filter.pro
Normal file
4
tests/auto/qtpromise/helpers/filter/filter.pro
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = tst_helpers_filter
|
||||
SOURCES += $$PWD/tst_filter.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
147
tests/auto/qtpromise/helpers/filter/tst_filter.cpp
Normal file
147
tests/auto/qtpromise/helpers/filter/tst_filter.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
// Tests
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_helpers_filter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void emptySequence();
|
||||
void filterValues();
|
||||
void delayedFulfilled();
|
||||
void delayedRejected();
|
||||
void functorThrows();
|
||||
void functorArguments();
|
||||
void preserveOrder();
|
||||
void sequenceTypes();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_helpers_filter)
|
||||
#include "tst_filter.moc"
|
||||
|
||||
namespace {
|
||||
|
||||
template <class Sequence>
|
||||
struct SequenceTester
|
||||
{
|
||||
static void exec()
|
||||
{
|
||||
auto inputs = Sequence{42, 43, 44, 45, 46, 47, 48, 49, 50, 51};
|
||||
auto p = QtPromise::filter(inputs, [](int v, ...) {
|
||||
return v % 3 == 0;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Sequence>>::value));
|
||||
QCOMPARE(waitForValue(p, Sequence()), Sequence({42, 45, 48, 51}));
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
void tst_helpers_filter::emptySequence()
|
||||
{
|
||||
auto p = QtPromise::filter(QVector<int>{}, [](int v, ...) {
|
||||
return v % 2 == 0;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>{});
|
||||
}
|
||||
|
||||
void tst_helpers_filter::filterValues()
|
||||
{
|
||||
auto p = QtPromise::filter(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||
return v % 2 == 0;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 44}));
|
||||
}
|
||||
|
||||
void tst_helpers_filter::delayedFulfilled()
|
||||
{
|
||||
auto p = QtPromise::filter(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||
return QPromise<bool>([&](const QPromiseResolve<bool>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=]() {
|
||||
resolve(v % 2 == 0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 44}));
|
||||
}
|
||||
|
||||
void tst_helpers_filter::delayedRejected()
|
||||
{
|
||||
auto p = QtPromise::filter(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||
return QPromise<bool>([&](
|
||||
const QPromiseResolve<bool>& resolve,
|
||||
const QPromiseReject<bool>& reject) {
|
||||
QtPromisePrivate::qtpromise_defer([=]() {
|
||||
if (v == 44) {
|
||||
reject(QString("foo"));
|
||||
}
|
||||
resolve(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
void tst_helpers_filter::functorThrows()
|
||||
{
|
||||
auto p = QtPromise::filter(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||
if (v == 44) {
|
||||
throw QString("foo");
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
void tst_helpers_filter::functorArguments()
|
||||
{
|
||||
QMap<int, int> args;
|
||||
auto p = QtPromise::filter(QVector<int>{42, 43, 44}, [&](int v, int i) {
|
||||
args[v] = i;
|
||||
return i % 2 == 0;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 44}));
|
||||
QMap<int, int> expected{{42, 0}, {43, 1}, {44, 2}};
|
||||
QCOMPARE(args, expected);
|
||||
}
|
||||
|
||||
void tst_helpers_filter::preserveOrder()
|
||||
{
|
||||
auto p = QtPromise::filter(QVector<int>{500, 100, 300, 250, 400}, [](int v, ...) {
|
||||
return QPromise<bool>::resolve(v > 200).delay(v);
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({500, 300, 250, 400}));
|
||||
}
|
||||
|
||||
void tst_helpers_filter::sequenceTypes()
|
||||
{
|
||||
SequenceTester<QList<int>>::exec();
|
||||
SequenceTester<QVector<int>>::exec();
|
||||
SequenceTester<std::list<int>>::exec();
|
||||
SequenceTester<std::vector<int>>::exec();
|
||||
}
|
@ -1,4 +1,9 @@
|
||||
TARGET = tst_helpers
|
||||
SOURCES += $$PWD/tst_helpers.cpp
|
||||
|
||||
include(../qtpromise.pri)
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS += \
|
||||
all \
|
||||
attempt \
|
||||
each \
|
||||
filter \
|
||||
map \
|
||||
reject \
|
||||
resolve
|
||||
|
4
tests/auto/qtpromise/helpers/map/map.pro
Normal file
4
tests/auto/qtpromise/helpers/map/map.pro
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = tst_helpers_map
|
||||
SOURCES += $$PWD/tst_map.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
151
tests/auto/qtpromise/helpers/map/tst_map.cpp
Normal file
151
tests/auto/qtpromise/helpers/map/tst_map.cpp
Normal file
@ -0,0 +1,151 @@
|
||||
// Tests
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_helpers_map : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void emptySequence();
|
||||
void modifyValues();
|
||||
void convertValues();
|
||||
void delayedFulfilled();
|
||||
void delayedRejected();
|
||||
void functorThrows();
|
||||
void functorArguments();
|
||||
void preserveOrder();
|
||||
void sequenceTypes();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_helpers_map)
|
||||
#include "tst_map.moc"
|
||||
|
||||
namespace {
|
||||
|
||||
template <class Sequence>
|
||||
struct SequenceTester
|
||||
{
|
||||
static void exec()
|
||||
{
|
||||
auto p = QtPromise::map(Sequence{42, 43, 44}, [](int v, ...) {
|
||||
return QString::number(v + 1);
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<QString>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<QString>()), QVector<QString>({"43", "44", "45"}));
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void tst_helpers_map::emptySequence()
|
||||
{
|
||||
auto p = QtPromise::map(QVector<int>{}, [](int v, ...) {
|
||||
return v + 1;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({}));
|
||||
}
|
||||
|
||||
void tst_helpers_map::modifyValues()
|
||||
{
|
||||
auto p = QtPromise::map(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||
return v + 1;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({43, 44, 45}));
|
||||
}
|
||||
|
||||
void tst_helpers_map::convertValues()
|
||||
{
|
||||
auto p = QtPromise::map(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||
return QString::number(v + 1);
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<QString>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<QString>()), QVector<QString>({"43", "44", "45"}));
|
||||
}
|
||||
|
||||
void tst_helpers_map::delayedFulfilled()
|
||||
{
|
||||
auto p = QtPromise::map(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||
return QPromise<int>([&](const QPromiseResolve<int>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=]() {
|
||||
resolve(v + 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({43, 44, 45}));
|
||||
}
|
||||
|
||||
void tst_helpers_map::delayedRejected()
|
||||
{
|
||||
auto p = QtPromise::map(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||
return QPromise<int>([&](
|
||||
const QPromiseResolve<int>& resolve,
|
||||
const QPromiseReject<int>& reject) {
|
||||
QtPromisePrivate::qtpromise_defer([=]() {
|
||||
if (v == 43) {
|
||||
reject(QString("foo"));
|
||||
}
|
||||
resolve(v);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
void tst_helpers_map::functorThrows()
|
||||
{
|
||||
auto p = QtPromise::map(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||
if (v == 43) {
|
||||
throw QString("foo");
|
||||
}
|
||||
return v + 1;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
void tst_helpers_map::functorArguments()
|
||||
{
|
||||
auto p = QtPromise::map(QVector<int>{42, 42, 42}, [](int v, int i) {
|
||||
return v * i;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({0, 42, 84}));
|
||||
}
|
||||
|
||||
void tst_helpers_map::preserveOrder()
|
||||
{
|
||||
auto p = QtPromise::map(QVector<int>{500, 100, 250}, [](int v, ...) {
|
||||
return QPromise<int>::resolve(v + 1).delay(v);
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({501, 101, 251}));
|
||||
}
|
||||
|
||||
void tst_helpers_map::sequenceTypes()
|
||||
{
|
||||
SequenceTester<QList<int>>::exec();
|
||||
SequenceTester<QVector<int>>::exec();
|
||||
SequenceTester<std::list<int>>::exec();
|
||||
SequenceTester<std::vector<int>>::exec();
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
TARGET = tst_qpromise_reject
|
||||
TARGET = tst_helpers_reject
|
||||
SOURCES += $$PWD/tst_reject.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
@ -12,7 +12,7 @@
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_qpromise_reject : public QObject
|
||||
class tst_helpers_reject : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -22,10 +22,10 @@ private Q_SLOTS:
|
||||
void rejectWithStdSharedPtr();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_qpromise_reject)
|
||||
QTEST_MAIN(tst_helpers_reject)
|
||||
#include "tst_reject.moc"
|
||||
|
||||
void tst_qpromise_reject::rejectWithValue()
|
||||
void tst_helpers_reject::rejectWithValue()
|
||||
{
|
||||
auto p = QPromise<int>::reject(42);
|
||||
|
||||
@ -34,7 +34,7 @@ void tst_qpromise_reject::rejectWithValue()
|
||||
}
|
||||
|
||||
// https://github.com/simonbrunel/qtpromise/issues/6
|
||||
void tst_qpromise_reject::rejectWithQSharedPtr()
|
||||
void tst_helpers_reject::rejectWithQSharedPtr()
|
||||
{
|
||||
QWeakPointer<int> wptr;
|
||||
|
||||
@ -54,7 +54,7 @@ void tst_qpromise_reject::rejectWithQSharedPtr()
|
||||
}
|
||||
|
||||
// https://github.com/simonbrunel/qtpromise/issues/6
|
||||
void tst_qpromise_reject::rejectWithStdSharedPtr()
|
||||
void tst_helpers_reject::rejectWithStdSharedPtr()
|
||||
{
|
||||
std::weak_ptr<int> wptr;
|
||||
|
@ -1,4 +1,4 @@
|
||||
TARGET = tst_qpromise_resolve
|
||||
TARGET = tst_helpers_resolve
|
||||
SOURCES += $$PWD/tst_resolve.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
@ -12,41 +12,80 @@
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_qpromise_resolve : public QObject
|
||||
class tst_helpers_resolve : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void resolveWithValue();
|
||||
void resolveWithNoValue();
|
||||
void resolveWithTypedPromise();
|
||||
void resolveWithVoidPromise();
|
||||
void resolveWithQSharedPtr();
|
||||
void resolveWithStdSharedPtr();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_qpromise_resolve)
|
||||
QTEST_MAIN(tst_helpers_resolve)
|
||||
#include "tst_resolve.moc"
|
||||
|
||||
void tst_qpromise_resolve::resolveWithValue()
|
||||
void tst_helpers_resolve::resolveWithValue()
|
||||
{
|
||||
const int value = 42;
|
||||
auto p0 = QPromise<int>::resolve(value);
|
||||
auto p1 = QPromise<int>::resolve(43);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(waitForValue(p0, -1), 42);
|
||||
QCOMPARE(waitForValue(p1, -1), 43);
|
||||
}
|
||||
|
||||
void tst_qpromise_resolve::resolveWithNoValue()
|
||||
void tst_helpers_resolve::resolveWithNoValue()
|
||||
{
|
||||
auto p = QPromise<void>::resolve();
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
}
|
||||
|
||||
void tst_helpers_resolve::resolveWithTypedPromise()
|
||||
{
|
||||
auto p = QtPromise::qPromise(
|
||||
QPromise<QString>([](const QPromiseResolve<QString>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
resolve("foo");
|
||||
});
|
||||
}));
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
void tst_helpers_resolve::resolveWithVoidPromise()
|
||||
{
|
||||
int check;
|
||||
auto p = QtPromise::qPromise(
|
||||
QPromise<void>([&](const QPromiseResolve<void>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=, &check](){
|
||||
check = 8;
|
||||
resolve();
|
||||
});
|
||||
}));
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
QCOMPARE(check, 8);
|
||||
}
|
||||
|
||||
// https://github.com/simonbrunel/qtpromise/issues/6
|
||||
void tst_qpromise_resolve::resolveWithQSharedPtr()
|
||||
void tst_helpers_resolve::resolveWithQSharedPtr()
|
||||
{
|
||||
QWeakPointer<int> wptr;
|
||||
|
||||
@ -66,7 +105,7 @@ void tst_qpromise_resolve::resolveWithQSharedPtr()
|
||||
}
|
||||
|
||||
// https://github.com/simonbrunel/qtpromise/issues/6
|
||||
void tst_qpromise_resolve::resolveWithStdSharedPtr()
|
||||
void tst_helpers_resolve::resolveWithStdSharedPtr()
|
||||
{
|
||||
std::weak_ptr<int> wptr;
|
||||
|
@ -1,244 +0,0 @@
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_helpers : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void resolve();
|
||||
void resolve_void();
|
||||
void resolve_promise();
|
||||
void resolve_promise_void();
|
||||
|
||||
void allFulfilled();
|
||||
void allFulfilled_void();
|
||||
void allRejected();
|
||||
void allRejected_void();
|
||||
void allEmpty();
|
||||
void allEmpty_void();
|
||||
|
||||
}; // class tst_helpers
|
||||
|
||||
QTEST_MAIN(tst_helpers)
|
||||
#include "tst_helpers.moc"
|
||||
|
||||
void tst_helpers::resolve()
|
||||
{
|
||||
int value = -1;
|
||||
auto p = QtPromise::qPromise(42);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
|
||||
p.then([&](int res) {
|
||||
value = res;
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(value, 42);
|
||||
}
|
||||
|
||||
void tst_helpers::resolve_void()
|
||||
{
|
||||
int value = -1;
|
||||
auto p = QtPromise::qPromise();
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
|
||||
p.then([&]() {
|
||||
value = 42;
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(value, 42);
|
||||
}
|
||||
|
||||
void tst_helpers::resolve_promise()
|
||||
{
|
||||
QString value;
|
||||
auto p = QtPromise::qPromise(
|
||||
QPromise<QString>([](const QPromiseResolve<QString>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
resolve("foo");
|
||||
});
|
||||
}));
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
|
||||
p.then([&](const QString& res) {
|
||||
value = res;
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(value, QString("foo"));
|
||||
}
|
||||
|
||||
void tst_helpers::resolve_promise_void()
|
||||
{
|
||||
QList<int> values;
|
||||
auto p = QtPromise::qPromise(
|
||||
QPromise<void>([&](const QPromiseResolve<void>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=, &values](){
|
||||
values << 42;
|
||||
resolve();
|
||||
});
|
||||
}));
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
|
||||
p.then([&]() {
|
||||
values << 43;
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(values, QList<int>({42, 43}));
|
||||
}
|
||||
|
||||
void tst_helpers::allFulfilled()
|
||||
{
|
||||
auto p0 = QtPromise::qPromise(42);
|
||||
auto p1 = QtPromise::qPromise(44);
|
||||
auto p2 = QPromise<int>([](const QPromiseResolve<int>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
resolve(43);
|
||||
});
|
||||
});
|
||||
|
||||
auto p = qPromiseAll(QVector<QPromise<int>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
|
||||
QVector<int> values;
|
||||
p.then([&](const QVector<int>& res) {
|
||||
values = res;
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(p2.isFulfilled(), true);
|
||||
QCOMPARE(values, QVector<int>({42, 43, 44}));
|
||||
}
|
||||
|
||||
void tst_helpers::allFulfilled_void()
|
||||
{
|
||||
auto p0 = QtPromise::qPromise();
|
||||
auto p1 = QtPromise::qPromise();
|
||||
auto p2 = QPromise<void>([](const QPromiseResolve<void>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
auto p = qPromiseAll(QVector<QPromise<void>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
|
||||
p.wait();
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(p2.isFulfilled(), true);
|
||||
}
|
||||
|
||||
void tst_helpers::allRejected()
|
||||
{
|
||||
auto p0 = QtPromise::qPromise(42);
|
||||
auto p1 = QtPromise::qPromise(44);
|
||||
auto p2 = QPromise<int>([](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
reject(QString("foo"));
|
||||
});
|
||||
});
|
||||
|
||||
auto p = qPromiseAll(QVector<QPromise<int>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
|
||||
QString error;
|
||||
p.fail([&](const QString& err) {
|
||||
error = err;
|
||||
return QVector<int>();
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
QCOMPARE(p2.isRejected(), true);
|
||||
QCOMPARE(error, QString("foo"));
|
||||
}
|
||||
|
||||
void tst_helpers::allRejected_void()
|
||||
{
|
||||
auto p0 = QtPromise::qPromise();
|
||||
auto p1 = QtPromise::qPromise();
|
||||
auto p2 = QPromise<void>([](const QPromiseResolve<void>&, const QPromiseReject<void>& reject) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
reject(QString("foo"));
|
||||
});
|
||||
});
|
||||
|
||||
auto p = qPromiseAll(QVector<QPromise<void>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
|
||||
QString error;
|
||||
p.fail([&](const QString& err) {
|
||||
error = err;
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
QCOMPARE(p2.isRejected(), true);
|
||||
QCOMPARE(error, QString("foo"));
|
||||
}
|
||||
|
||||
void tst_helpers::allEmpty()
|
||||
{
|
||||
auto p = qPromiseAll(QVector<QPromise<int>>());
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
|
||||
QVector<int> values;
|
||||
p.then([&](const QVector<int>& res) {
|
||||
values = res;
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(values, QVector<int>());
|
||||
}
|
||||
|
||||
void tst_helpers::allEmpty_void()
|
||||
{
|
||||
auto p = qPromiseAll(QVector<QPromise<void>>());
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
// Tests
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_qpromise_all : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void qList();
|
||||
//void qVector();
|
||||
void stdList();
|
||||
void stdVector();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_qpromise_all)
|
||||
#include "tst_all.moc"
|
||||
|
||||
namespace {
|
||||
|
||||
template <class Sequence>
|
||||
struct SequenceTester
|
||||
{
|
||||
};
|
||||
|
||||
template <template <typename, typename...> class Sequence, typename ...Args>
|
||||
struct SequenceTester<Sequence<QPromise<int>, Args...>>
|
||||
{
|
||||
static void exec()
|
||||
{
|
||||
Sequence<QPromise<int>, Args...> promises{
|
||||
QPromise<int>::resolve(42),
|
||||
QPromise<int>::resolve(43),
|
||||
QPromise<int>::resolve(44)
|
||||
};
|
||||
|
||||
promises.push_back(QPromise<int>::resolve(45));
|
||||
promises.insert(++promises.begin(), QPromise<int>::resolve(46));
|
||||
promises.pop_back();
|
||||
|
||||
auto p = QPromise<int>::all(promises);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 46, 43, 44}));
|
||||
}
|
||||
};
|
||||
|
||||
template <template <typename, typename...> class Sequence, typename ...Args>
|
||||
struct SequenceTester<Sequence<QPromise<void>, Args...>>
|
||||
{
|
||||
static void exec()
|
||||
{
|
||||
Sequence<QPromise<void>, Args...> promises{
|
||||
QPromise<void>::resolve(),
|
||||
QPromise<void>::resolve(),
|
||||
QPromise<void>::resolve()
|
||||
};
|
||||
|
||||
promises.push_back(QPromise<void>::resolve());
|
||||
promises.insert(++promises.begin(), QPromise<void>::resolve());
|
||||
promises.pop_back();
|
||||
|
||||
auto p = QPromise<void>::all(promises);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void tst_qpromise_all::qList()
|
||||
{
|
||||
SequenceTester<QList<QPromise<int>>>::exec();
|
||||
SequenceTester<QList<QPromise<void>>>::exec();
|
||||
}
|
||||
|
||||
// QVector::push_back/append isn't supported since it requires a default
|
||||
// constructor (see https://github.com/simonbrunel/qtpromise/issues/3)
|
||||
//void tst_qpromise_all::qVector()
|
||||
//{
|
||||
// SequenceTester<QVector<QPromise<int>>>::exec();
|
||||
// SequenceTester<QVector<QPromise<void>>>::exec();
|
||||
//}
|
||||
|
||||
void tst_qpromise_all::stdList()
|
||||
{
|
||||
SequenceTester<std::list<QPromise<int>>>::exec();
|
||||
SequenceTester<std::list<QPromise<void>>>::exec();
|
||||
}
|
||||
|
||||
void tst_qpromise_all::stdVector()
|
||||
{
|
||||
SequenceTester<std::vector<QPromise<int>>>::exec();
|
||||
SequenceTester<std::vector<QPromise<void>>>::exec();
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
TARGET = tst_qpromise_cast
|
||||
SOURCES += $$PWD/tst_cast.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
@ -1,135 +0,0 @@
|
||||
// Tests
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_qpromise_cast : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void typeToVoid();
|
||||
|
||||
|
||||
//void castToVoidOperator();
|
||||
//void typeToVariant(); // QPromise<T>.cast<QVariant>()
|
||||
//void variantToType();
|
||||
//void voidToVariant(); // QPromise<void>.cast<QVariant>()
|
||||
//void variantToVoid();
|
||||
|
||||
//void jsonValueToJsonObject();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_qpromise_cast)
|
||||
#include "tst_cast.moc"
|
||||
|
||||
void tst_qpromise_cast::typeToVoid()
|
||||
{
|
||||
QPromise<void> p0 = QPromise<int>::resolve(42);
|
||||
QPromise<void> p1 = QPromise<QString>::resolve(QString("foo"));
|
||||
QVERIFY(p0.isFulfilled());
|
||||
QVERIFY(p1.isFulfilled());
|
||||
}
|
||||
|
||||
//void tst_qpromise_cast::castToVoidOperator()
|
||||
//{
|
||||
//auto p0 = QPromise<int>::resolve(42);
|
||||
//QPromise<double> p1(p0);
|
||||
//QPromise<void> p2(p0);
|
||||
//auto p4 = QPromise<QString>::resolve("foo");
|
||||
//
|
||||
//p0.then([](int res) { qDebug() << res; });
|
||||
//p1.then([](double res) { qDebug() << res; });
|
||||
//p2.then([]() { qDebug() << "done"; });
|
||||
//
|
||||
//foo().then([]() {
|
||||
// qDebug() << "done";
|
||||
//}).wait();
|
||||
//
|
||||
//QPromise<QVariant>::all({p0, p1, p4}).then([](const QVector<QVariant>& res) {
|
||||
// qDebug() << "all done!" << res;
|
||||
//}).wait();
|
||||
//}
|
||||
|
||||
/*
|
||||
namespace {
|
||||
|
||||
template <typename T, typename U>
|
||||
void test_qpromise_cast(const T& t, const U& u)
|
||||
{
|
||||
auto p = QPromise<T>::resolve(t).cast<U>();
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<U> >::value));
|
||||
QCOMPARE(waitForValue(p, U()), u);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
void test_qpromise_cast(const U& u)
|
||||
{
|
||||
auto p = QPromise<void>::resolve().cast<U>();
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<U> >::value));
|
||||
QCOMPARE(waitForValue(p, U()), u);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
void tst_qpromise_cast::typeToVariant()
|
||||
{
|
||||
test_qpromise_cast(42, QVariant(42));
|
||||
test_qpromise_cast(4.2, QVariant(4.2));
|
||||
test_qpromise_cast(true, QVariant(true));
|
||||
test_qpromise_cast(QString("foo"), QVariant(QString("foo")));
|
||||
test_qpromise_cast(QUrl("http://x.y.z"), QVariant(QUrl("http://x.y.z")));
|
||||
test_qpromise_cast(QSize(128, 256), QVariant(QSize(128, 256)));
|
||||
test_qpromise_cast(QDate(2018, 1, 1), QVariant(QDate(2018, 1, 1)));
|
||||
test_qpromise_cast(QJsonValue("foo"), QVariant(QJsonValue("foo")));
|
||||
test_qpromise_cast(QStringList{"foo", "bar"}, QVariant(QStringList{"foo", "bar"}));
|
||||
test_qpromise_cast(QList<QVariant>{"foo", 42}, QVariant(QList<QVariant>{"foo", 42}));
|
||||
test_qpromise_cast(QMap<QString, QVariant>{{"foo", 42}}, QVariant(QVariantMap{{"foo", 42}}));
|
||||
}
|
||||
|
||||
void tst_qpromise_cast::voidToVariant()
|
||||
{
|
||||
test_qpromise_cast(QVariant());
|
||||
}
|
||||
|
||||
void tst_qpromise_cast::variantToType()
|
||||
{
|
||||
// invalid
|
||||
// int
|
||||
// QString
|
||||
// QColor
|
||||
// QList
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
void tst_qpromise_cast::jsonValueToJsonObject()
|
||||
{
|
||||
{ // QJsonValue(Null) -> QJsonObject
|
||||
auto p = QPromise<QJsonValue>::resolve(QJsonValue()).cast<QJsonObject>();
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QJsonObject> >::value));
|
||||
const QJsonObject res = waitForValue(p, QJsonObject());
|
||||
QVERIFY(res.isEmpty());
|
||||
}
|
||||
{ // QJsonValue(int) -> QJsonObject
|
||||
auto p = QPromise<QJsonValue>::resolve(QJsonValue(42)).cast<QJsonObject>();
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QJsonObject> >::value));
|
||||
const QJsonObject res = waitForValue(p, QJsonObject());
|
||||
QVERIFY(res.isEmpty());
|
||||
}
|
||||
{ // QJsonValue(QJsonObject) -> QJsonObject
|
||||
const QJsonObject object{{"magic", 42}};
|
||||
auto p = QPromise<QJsonValue>::resolve(QJsonValue(object)).cast<QJsonObject>();
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QJsonObject> >::value));
|
||||
const QJsonObject res = waitForValue(p, QJsonObject());
|
||||
QCOMPARE(res.value("magic"), 42);
|
||||
}
|
||||
}
|
||||
*/
|
@ -34,8 +34,12 @@ void tst_qpromise_delay::fulfilled()
|
||||
|
||||
QCOMPARE(waitForValue(p, -1), 42);
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QVERIFY(elapsed >= 1000 * 0.95); // Qt::CoarseTimer (default) Coarse timers try to
|
||||
QVERIFY(elapsed <= 1000 * 1.05); // keep accuracy within 5% of the desired interval.
|
||||
|
||||
// Qt::CoarseTimer (default) Coarse timers try to
|
||||
// keep accuracy within 5% of the desired interval.
|
||||
// Require accuracy within 6% for passing the test.
|
||||
QVERIFY(elapsed >= 1000 * 0.94);
|
||||
QVERIFY(elapsed <= 1000 * 1.06);
|
||||
}
|
||||
|
||||
void tst_qpromise_delay::rejected()
|
||||
@ -51,5 +55,5 @@ void tst_qpromise_delay::rejected()
|
||||
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
QVERIFY(elapsed < 5);
|
||||
QVERIFY(elapsed <= 10);
|
||||
}
|
||||
|
4
tests/auto/qtpromise/qpromise/each/each.pro
Normal file
4
tests/auto/qtpromise/qpromise/each/each.pro
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = tst_qpromise_each
|
||||
SOURCES += $$PWD/tst_each.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
170
tests/auto/qtpromise/qpromise/each/tst_each.cpp
Normal file
170
tests/auto/qtpromise/qpromise/each/tst_each.cpp
Normal file
@ -0,0 +1,170 @@
|
||||
// Tests
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_qpromise_each : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void emptySequence();
|
||||
void preserveValues();
|
||||
void ignoreResult();
|
||||
void delayedFulfilled();
|
||||
void delayedRejected();
|
||||
void functorThrows();
|
||||
void functorArguments();
|
||||
void sequenceTypes();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_qpromise_each)
|
||||
#include "tst_each.moc"
|
||||
|
||||
namespace {
|
||||
|
||||
template <class Sequence>
|
||||
struct SequenceTester
|
||||
{
|
||||
static void exec()
|
||||
{
|
||||
QVector<int> values;
|
||||
auto p = QtPromise::qPromise(Sequence{42, 43, 44}).each([&](int v, int i) {
|
||||
values << i << v;
|
||||
}).each([&](int v, ...) {
|
||||
values << v;
|
||||
return QString("foo");
|
||||
}).each([&](int v, ...) {
|
||||
values << v + 1;
|
||||
return QPromise<QString>::resolve(QString("foo")).then([&](){
|
||||
values << -1;
|
||||
});
|
||||
}).each([&](int v, ...) {
|
||||
values << v + 2;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Sequence>>::value));
|
||||
QCOMPARE(waitForValue(p, Sequence()), Sequence({42, 43, 44}));
|
||||
|
||||
QVector<int> expected{
|
||||
0, 42, 1, 43, 2, 44,
|
||||
42, 43, 44,
|
||||
43, 44, 45,
|
||||
-1, -1, -1,
|
||||
44, 45, 46
|
||||
};
|
||||
QCOMPARE(values, expected);
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void tst_qpromise_each::emptySequence()
|
||||
{
|
||||
QVector<int> values;
|
||||
auto p = QPromise<QVector<int>>::resolve({}).each([&](int v, ...) {
|
||||
values << v;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>());
|
||||
QCOMPARE(values, QVector<int>({}));
|
||||
}
|
||||
|
||||
void tst_qpromise_each::preserveValues()
|
||||
{
|
||||
QVector<int> values;
|
||||
auto p = QPromise<QVector<int>>::resolve({42, 43, 44}).each([&](int v, ...) {
|
||||
values << v + 1;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 43, 44}));
|
||||
QCOMPARE(values, QVector<int>({43, 44, 45}));
|
||||
}
|
||||
|
||||
void tst_qpromise_each::ignoreResult()
|
||||
{
|
||||
QVector<int> values;
|
||||
auto p = QPromise<QVector<int>>::resolve({42, 43, 44}).each([&](int v, ...) {
|
||||
values << v + 1;
|
||||
return "Foo";
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 43, 44}));
|
||||
QCOMPARE(values, QVector<int>({43, 44, 45}));
|
||||
}
|
||||
|
||||
void tst_qpromise_each::delayedFulfilled()
|
||||
{
|
||||
QMap<int, int> values;
|
||||
auto p = QPromise<QVector<int>>::resolve({42, 43, 44}).each([&](int v, int index) {
|
||||
return QPromise<void>::resolve().delay(250).then([=, &values]() {
|
||||
values[v] = index;
|
||||
return 42;
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 43, 44}));
|
||||
QMap<int, int> expected{{42, 0}, {43, 1}, {44, 2}};
|
||||
QCOMPARE(values, expected);
|
||||
}
|
||||
|
||||
void tst_qpromise_each::delayedRejected()
|
||||
{
|
||||
auto p = QPromise<QVector<int>>::resolve({42, 43, 44}).each([](int v, ...) {
|
||||
return QPromise<int>([&](
|
||||
const QPromiseResolve<int>& resolve,
|
||||
const QPromiseReject<int>& reject) {
|
||||
QtPromisePrivate::qtpromise_defer([=]() {
|
||||
if (v == 44) {
|
||||
reject(QString("foo"));
|
||||
}
|
||||
resolve(v);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
void tst_qpromise_each::functorThrows()
|
||||
{
|
||||
auto p = QPromise<QVector<int>>::resolve({42, 43, 44}).each([](int v, ...) {
|
||||
if (v == 44) {
|
||||
throw QString("foo");
|
||||
}
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
void tst_qpromise_each::functorArguments()
|
||||
{
|
||||
QVector<int> values;
|
||||
auto p = QPromise<QVector<int>>::resolve({42, 43, 44}).each([&](int v, int i) {
|
||||
values << i << v;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 43, 44}));
|
||||
QCOMPARE(values, QVector<int>({0, 42, 1, 43, 2, 44}));
|
||||
}
|
||||
|
||||
void tst_qpromise_each::sequenceTypes()
|
||||
{
|
||||
SequenceTester<QList<int>>::exec();
|
||||
SequenceTester<QVector<int>>::exec();
|
||||
SequenceTester<std::list<int>>::exec();
|
||||
SequenceTester<std::vector<int>>::exec();
|
||||
}
|
4
tests/auto/qtpromise/qpromise/filter/filter.pro
Normal file
4
tests/auto/qtpromise/qpromise/filter/filter.pro
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = tst_qpromise_filter
|
||||
SOURCES += $$PWD/tst_filter.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
152
tests/auto/qtpromise/qpromise/filter/tst_filter.cpp
Normal file
152
tests/auto/qtpromise/qpromise/filter/tst_filter.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
// Tests
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_qpromise_filter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void emptySequence();
|
||||
void filterValues();
|
||||
void delayedFulfilled();
|
||||
void delayedRejected();
|
||||
void functorThrows();
|
||||
void functorArguments();
|
||||
void preserveOrder();
|
||||
void sequenceTypes();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_qpromise_filter)
|
||||
#include "tst_filter.moc"
|
||||
|
||||
namespace {
|
||||
|
||||
template <class Sequence>
|
||||
struct SequenceTester
|
||||
{
|
||||
static void exec()
|
||||
{
|
||||
auto p = QtPromise::qPromise(Sequence{
|
||||
42, 43, 44, 45, 46, 47, 48, 49, 50, 51
|
||||
}).filter([](int v, ...) {
|
||||
return v > 42 && v < 51;
|
||||
}).filter([](int, int i) {
|
||||
return QPromise<bool>::resolve(i % 2 == 0);
|
||||
}).filter([](int v, ...) {
|
||||
return v != 45;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Sequence>>::value));
|
||||
QCOMPARE(waitForValue(p, Sequence()), Sequence({43, 47, 49}));
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
void tst_qpromise_filter::emptySequence()
|
||||
{
|
||||
auto p = QPromise<QVector<int>>::resolve({}).filter([](int v, ...) {
|
||||
return v % 2 == 0;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>{});
|
||||
}
|
||||
|
||||
void tst_qpromise_filter::filterValues()
|
||||
{
|
||||
auto p = QPromise<QVector<int>>::resolve({42, 43, 44}).filter([](int v, ...) {
|
||||
return v % 2 == 0;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 44}));
|
||||
}
|
||||
|
||||
void tst_qpromise_filter::delayedFulfilled()
|
||||
{
|
||||
auto p = QPromise<QVector<int>>::resolve({42, 43, 44}).filter([](int v, ...) {
|
||||
return QPromise<bool>([&](const QPromiseResolve<bool>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=]() {
|
||||
resolve(v % 2 == 0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 44}));
|
||||
}
|
||||
|
||||
void tst_qpromise_filter::delayedRejected()
|
||||
{
|
||||
auto p = QPromise<QVector<int>>::resolve({42, 43, 44}).filter([](int v, ...) {
|
||||
return QPromise<bool>([&](
|
||||
const QPromiseResolve<bool>& resolve,
|
||||
const QPromiseReject<bool>& reject) {
|
||||
QtPromisePrivate::qtpromise_defer([=]() {
|
||||
if (v == 43) {
|
||||
reject(QString("foo"));
|
||||
}
|
||||
resolve(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
void tst_qpromise_filter::functorThrows()
|
||||
{
|
||||
auto p = QPromise<QVector<int>>::resolve({42, 43, 44}).filter([](int v, ...) {
|
||||
if (v == 43) {
|
||||
throw QString("foo");
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
void tst_qpromise_filter::functorArguments()
|
||||
{
|
||||
QMap<int, int> args;
|
||||
auto p = QPromise<QVector<int>>::resolve({42, 43, 44}).filter([&](int v, int i) {
|
||||
args[v] = i;
|
||||
return i % 2 == 0;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 44}));
|
||||
QMap<int, int> expected{{42, 0}, {43, 1}, {44, 2}};
|
||||
QCOMPARE(args, expected);
|
||||
}
|
||||
|
||||
void tst_qpromise_filter::preserveOrder()
|
||||
{
|
||||
auto p = QPromise<QVector<int>>::resolve({250, 50, 100, 400, 300}).filter([](int v, ...) {
|
||||
return QPromise<bool>::resolve(v > 200).delay(v);
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({250, 400, 300}));
|
||||
}
|
||||
|
||||
void tst_qpromise_filter::sequenceTypes()
|
||||
{
|
||||
SequenceTester<QList<int>>::exec();
|
||||
SequenceTester<QVector<int>>::exec();
|
||||
SequenceTester<std::list<int>>::exec();
|
||||
SequenceTester<std::vector<int>>::exec();
|
||||
}
|
4
tests/auto/qtpromise/qpromise/map/map.pro
Normal file
4
tests/auto/qtpromise/qpromise/map/map.pro
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = tst_qpromise_map
|
||||
SOURCES += $$PWD/tst_map.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
157
tests/auto/qtpromise/qpromise/map/tst_map.cpp
Normal file
157
tests/auto/qtpromise/qpromise/map/tst_map.cpp
Normal file
@ -0,0 +1,157 @@
|
||||
// Tests
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_qpromise_map : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void emptySequence();
|
||||
void modifyValues();
|
||||
void convertValues();
|
||||
void delayedFulfilled();
|
||||
void delayedRejected();
|
||||
void functorThrows();
|
||||
void functorArguments();
|
||||
void preserveOrder();
|
||||
void sequenceTypes();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_qpromise_map)
|
||||
#include "tst_map.moc"
|
||||
|
||||
namespace {
|
||||
|
||||
template <class Sequence>
|
||||
struct SequenceTester
|
||||
{
|
||||
static void exec()
|
||||
{
|
||||
auto p = QtPromise::qPromise(Sequence{42, 43, 44}).map([](int v, ...) {
|
||||
return QString::number(v + 1);
|
||||
}).map([](const QString& v, int i) {
|
||||
return QtPromise::qPromise(QString("%1:%2").arg(i).arg(v));
|
||||
}).map([](const QString& v, ...) {
|
||||
return QtPromise::qPromise((v + "!").toUtf8());
|
||||
}).map([](const QByteArray& v, ...) {
|
||||
return QString::fromUtf8(v);
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<QString>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<QString>()), QVector<QString>({"0:43!", "1:44!", "2:45!"}));
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void tst_qpromise_map::emptySequence()
|
||||
{
|
||||
auto p = QtPromise::qPromise(QVector<int>{}).map([](int v, ...) {
|
||||
return v + 1;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({}));
|
||||
}
|
||||
|
||||
void tst_qpromise_map::modifyValues()
|
||||
{
|
||||
auto p = QtPromise::qPromise(QVector<int>{42, 43, 44}).map([](int v, ...) {
|
||||
return v + 1;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({43, 44, 45}));
|
||||
}
|
||||
|
||||
void tst_qpromise_map::convertValues()
|
||||
{
|
||||
auto p = QtPromise::qPromise(QVector<int>{42, 43, 44}).map([](int v, ...) {
|
||||
return QString::number(v + 1);
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<QString>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<QString>()), QVector<QString>({"43", "44", "45"}));
|
||||
}
|
||||
|
||||
void tst_qpromise_map::delayedFulfilled()
|
||||
{
|
||||
auto p = QtPromise::qPromise(QVector<int>{42, 43, 44}).map([](int v, ...) {
|
||||
return QPromise<int>([&](const QPromiseResolve<int>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=]() {
|
||||
resolve(v + 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({43, 44, 45}));
|
||||
}
|
||||
|
||||
void tst_qpromise_map::delayedRejected()
|
||||
{
|
||||
auto p = QtPromise::qPromise(QVector<int>{42, 43, 44}).map([](int v, ...) {
|
||||
return QPromise<int>([&](
|
||||
const QPromiseResolve<int>& resolve,
|
||||
const QPromiseReject<int>& reject) {
|
||||
QtPromisePrivate::qtpromise_defer([=]() {
|
||||
if (v == 43) {
|
||||
reject(QString("foo"));
|
||||
}
|
||||
resolve(v);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
void tst_qpromise_map::functorThrows()
|
||||
{
|
||||
auto p = QtPromise::qPromise(QVector<int>{42, 43, 44}).map([](int v, ...) {
|
||||
if (v == 43) {
|
||||
throw QString("foo");
|
||||
}
|
||||
return v + 1;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
void tst_qpromise_map::functorArguments()
|
||||
{
|
||||
auto p1 = QtPromise::qPromise(QVector<int>{42, 42, 42}).map([](int v, int i) {
|
||||
return v * i;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p1, QVector<int>()), QVector<int>({0, 42, 84}));
|
||||
}
|
||||
|
||||
void tst_qpromise_map::preserveOrder()
|
||||
{
|
||||
auto p = QtPromise::qPromise(QVector<int>{250, 500, 100}).map([](int v, ...) {
|
||||
return QtPromise::qPromise(v + 1).delay(v);
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({251, 501, 101}));
|
||||
}
|
||||
|
||||
void tst_qpromise_map::sequenceTypes()
|
||||
{
|
||||
SequenceTester<QList<int>>::exec();
|
||||
SequenceTester<QVector<int>>::exec();
|
||||
SequenceTester<std::list<int>>::exec();
|
||||
SequenceTester<std::vector<int>>::exec();
|
||||
}
|
@ -1,14 +1,13 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS += \
|
||||
all \
|
||||
cast \
|
||||
construct \
|
||||
delay \
|
||||
each \
|
||||
fail \
|
||||
filter \
|
||||
finally \
|
||||
map \
|
||||
operators \
|
||||
reject \
|
||||
resolve \
|
||||
tap \
|
||||
tapfail \
|
||||
then \
|
||||
|
@ -87,6 +87,10 @@ void tst_qpromise_timeout::timeout()
|
||||
QCOMPARE(waitForValue(p, -1), -1);
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
QCOMPARE(failed, true);
|
||||
QVERIFY(elapsed >= 2000 * 0.95); // Qt::CoarseTimer (default) Coarse timers try to
|
||||
QVERIFY(elapsed <= 2000 * 1.05); // keep accuracy within 5% of the desired interval.
|
||||
|
||||
// Qt::CoarseTimer (default) Coarse timers try to
|
||||
// keep accuracy within 5% of the desired interval.
|
||||
// Require accuracy within 6% for passing the test.
|
||||
QVERIFY(elapsed >= 2000 * 0.94);
|
||||
QVERIFY(elapsed <= 2000 * 1.06);
|
||||
}
|
||||
|
Reference in New Issue
Block a user