tst_reduce.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /*
  2. * Copyright (c) Simon Brunel, https://github.com/simonbrunel
  3. *
  4. * This source code is licensed under the MIT license found in
  5. * the LICENSE file in the root directory of this source tree.
  6. */
  7. #include "../shared/data.h"
  8. #include "../shared/utils.h"
  9. #include <QtPromise>
  10. #include <QtTest>
  11. class tst_helpers_reduce : public QObject
  12. {
  13. Q_OBJECT
  14. private Q_SLOTS:
  15. void emptySequence();
  16. void regularValues();
  17. void promiseValues();
  18. void convertResultType();
  19. void delayedInitialValue();
  20. void delayedFulfilled();
  21. void delayedRejected();
  22. void functorThrows();
  23. void sequenceTypes();
  24. };
  25. QTEST_MAIN(tst_helpers_reduce)
  26. #include "tst_reduce.moc"
  27. namespace {
  28. template<class Sequence>
  29. struct SequenceTester
  30. {
  31. static void exec()
  32. {
  33. Sequence inputs{QtPromise::resolve(4).delay(400),
  34. QtPromise::resolve(6).delay(300),
  35. QtPromise::resolve(8).delay(200)};
  36. QVector<int> v0;
  37. QVector<int> v1;
  38. auto p0 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
  39. v0 << acc << cur << idx;
  40. return acc + cur + idx;
  41. });
  42. auto p1 = QtPromise::reduce(
  43. inputs,
  44. [&](int acc, int cur, int idx) {
  45. v1 << acc << cur << idx;
  46. return acc + cur + idx;
  47. },
  48. QtPromise::resolve(2).delay(100));
  49. Q_STATIC_ASSERT((std::is_same<decltype(p0), QtPromise::QPromise<int>>::value));
  50. Q_STATIC_ASSERT((std::is_same<decltype(p1), QtPromise::QPromise<int>>::value));
  51. QCOMPARE(p0.isPending(), true);
  52. QCOMPARE(p1.isPending(), true);
  53. QCOMPARE(waitForValue(p0, -1), 21);
  54. QCOMPARE(waitForValue(p1, -1), 23);
  55. QCOMPARE(v0, (QVector<int>{4, 6, 1, 11, 8, 2}));
  56. QCOMPARE(v1, (QVector<int>{2, 4, 0, 6, 6, 1, 13, 8, 2}));
  57. }
  58. };
  59. } // anonymous namespace
  60. void tst_helpers_reduce::emptySequence()
  61. {
  62. bool called = false;
  63. auto p = QtPromise::reduce(
  64. QVector<int>{},
  65. [&](...) {
  66. called = true;
  67. return 43;
  68. },
  69. 42);
  70. // NOTE(SB): reduce() on an empty sequence without an initial value is an error!
  71. Q_STATIC_ASSERT((std::is_same<decltype(p), QtPromise::QPromise<int>>::value));
  72. QCOMPARE(waitForValue(p, -1), 42);
  73. QCOMPARE(called, false);
  74. }
  75. void tst_helpers_reduce::regularValues()
  76. {
  77. QVector<int> inputs{4, 6, 8};
  78. QVector<int> v0;
  79. QVector<int> v1;
  80. auto p0 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
  81. v0 << acc << cur << idx;
  82. return acc + cur + idx;
  83. });
  84. auto p1 = QtPromise::reduce(
  85. inputs,
  86. [&](int acc, int cur, int idx) {
  87. v1 << acc << cur << idx;
  88. return acc + cur + idx;
  89. },
  90. 2);
  91. Q_STATIC_ASSERT((std::is_same<decltype(p0), QtPromise::QPromise<int>>::value));
  92. Q_STATIC_ASSERT((std::is_same<decltype(p1), QtPromise::QPromise<int>>::value));
  93. QCOMPARE(p0.isPending(), true);
  94. QCOMPARE(p1.isPending(), true);
  95. QCOMPARE(waitForValue(p0, -1), 21);
  96. QCOMPARE(waitForValue(p1, -1), 23);
  97. QCOMPARE(v0, (QVector<int>{4, 6, 1, 11, 8, 2}));
  98. QCOMPARE(v1, (QVector<int>{2, 4, 0, 6, 6, 1, 13, 8, 2}));
  99. }
  100. void tst_helpers_reduce::promiseValues()
  101. {
  102. QVector<QtPromise::QPromise<int>> inputs{QtPromise::resolve(4).delay(400),
  103. QtPromise::resolve(6).delay(300),
  104. QtPromise::resolve(8).delay(200)};
  105. QVector<int> v0;
  106. QVector<int> v1;
  107. auto p0 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
  108. v0 << acc << cur << idx;
  109. return acc + cur + idx;
  110. });
  111. auto p1 = QtPromise::reduce(
  112. inputs,
  113. [&](int acc, int cur, int idx) {
  114. v1 << acc << cur << idx;
  115. return acc + cur + idx;
  116. },
  117. 2);
  118. Q_STATIC_ASSERT((std::is_same<decltype(p0), QtPromise::QPromise<int>>::value));
  119. Q_STATIC_ASSERT((std::is_same<decltype(p1), QtPromise::QPromise<int>>::value));
  120. QCOMPARE(p0.isPending(), true);
  121. QCOMPARE(p1.isPending(), true);
  122. QCOMPARE(waitForValue(p0, -1), 21);
  123. QCOMPARE(waitForValue(p1, -1), 23);
  124. QCOMPARE(v0, (QVector<int>{4, 6, 1, 11, 8, 2}));
  125. QCOMPARE(v1, (QVector<int>{2, 4, 0, 6, 6, 1, 13, 8, 2}));
  126. }
  127. void tst_helpers_reduce::convertResultType()
  128. {
  129. QVector<int> inputs{4, 6, 8};
  130. auto p = QtPromise::reduce(
  131. inputs,
  132. [&](const QString& acc, int cur, int idx) {
  133. return QString{"%1:%2:%3"}.arg(acc).arg(cur).arg(idx);
  134. },
  135. QString{"foo"});
  136. // NOTE(SB): when no initial value is given, the result type is the sequence type.
  137. Q_STATIC_ASSERT((std::is_same<decltype(p), QtPromise::QPromise<QString>>::value));
  138. QCOMPARE(p.isPending(), true);
  139. QCOMPARE(waitForValue(p, QString{}), QString{"foo:4:0:6:1:8:2"});
  140. }
  141. void tst_helpers_reduce::delayedInitialValue()
  142. {
  143. QVector<int> values;
  144. auto p = QtPromise::reduce(
  145. QVector<int>{4, 6, 8},
  146. [&](int acc, int cur, int idx) {
  147. values << acc << cur << idx;
  148. return acc + cur + idx;
  149. },
  150. QtPromise::resolve(2).delay(100));
  151. Q_STATIC_ASSERT((std::is_same<decltype(p), QtPromise::QPromise<int>>::value));
  152. QCOMPARE(p.isPending(), true);
  153. QCOMPARE(waitForValue(p, -1), 23);
  154. QCOMPARE(values, (QVector<int>{2, 4, 0, 6, 6, 1, 13, 8, 2}));
  155. }
  156. void tst_helpers_reduce::delayedFulfilled()
  157. {
  158. QVector<int> inputs{4, 6, 8};
  159. QVector<int> v0;
  160. QVector<int> v1;
  161. auto p0 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
  162. v0 << acc << cur << idx;
  163. return QtPromise::resolve(acc + cur + idx).delay(100);
  164. });
  165. auto p1 = QtPromise::reduce(
  166. inputs,
  167. [&](int acc, int cur, int idx) {
  168. v1 << acc << cur << idx;
  169. return QtPromise::resolve(acc + cur + idx).delay(100);
  170. },
  171. 2);
  172. Q_STATIC_ASSERT((std::is_same<decltype(p0), QtPromise::QPromise<int>>::value));
  173. Q_STATIC_ASSERT((std::is_same<decltype(p1), QtPromise::QPromise<int>>::value));
  174. QCOMPARE(p0.isPending(), true);
  175. QCOMPARE(p1.isPending(), true);
  176. QCOMPARE(waitForValue(p0, -1), 21);
  177. QCOMPARE(waitForValue(p1, -1), 23);
  178. QCOMPARE(v0, (QVector<int>{4, 6, 1, 11, 8, 2}));
  179. QCOMPARE(v1, (QVector<int>{2, 4, 0, 6, 6, 1, 13, 8, 2}));
  180. }
  181. void tst_helpers_reduce::delayedRejected()
  182. {
  183. QVector<int> inputs{4, 6, 8};
  184. QVector<int> v0;
  185. QVector<int> v1;
  186. auto p0 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
  187. v0 << acc << cur << idx;
  188. if (cur == 6) {
  189. return QtPromise::QPromise<int>::reject(QString{"foo"});
  190. }
  191. return QtPromise::resolve(acc + cur + idx);
  192. });
  193. auto p1 = QtPromise::reduce(
  194. inputs,
  195. [&](int acc, int cur, int idx) {
  196. v1 << acc << cur << idx;
  197. if (cur == 6) {
  198. return QtPromise::QPromise<int>::reject(QString{"bar"});
  199. }
  200. return QtPromise::resolve(acc + cur + idx);
  201. },
  202. 2);
  203. Q_STATIC_ASSERT((std::is_same<decltype(p0), QtPromise::QPromise<int>>::value));
  204. Q_STATIC_ASSERT((std::is_same<decltype(p1), QtPromise::QPromise<int>>::value));
  205. QCOMPARE(p0.isPending(), true);
  206. QCOMPARE(p1.isPending(), true);
  207. QCOMPARE(waitForError(p0, QString{}), QString{"foo"});
  208. QCOMPARE(waitForError(p1, QString{}), QString{"bar"});
  209. QCOMPARE(v0, (QVector<int>{4, 6, 1}));
  210. QCOMPARE(v1, (QVector<int>{2, 4, 0, 6, 6, 1}));
  211. }
  212. void tst_helpers_reduce::functorThrows()
  213. {
  214. QVector<int> inputs{4, 6, 8};
  215. QVector<int> v0;
  216. QVector<int> v1;
  217. auto p0 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
  218. v0 << acc << cur << idx;
  219. if (cur == 6) {
  220. throw QString{"foo"};
  221. }
  222. return acc + cur + idx;
  223. });
  224. auto p1 = QtPromise::reduce(
  225. inputs,
  226. [&](int acc, int cur, int idx) {
  227. v1 << acc << cur << idx;
  228. if (cur == 6) {
  229. throw QString{"bar"};
  230. }
  231. return acc + cur + idx;
  232. },
  233. 2);
  234. Q_STATIC_ASSERT((std::is_same<decltype(p0), QtPromise::QPromise<int>>::value));
  235. Q_STATIC_ASSERT((std::is_same<decltype(p1), QtPromise::QPromise<int>>::value));
  236. QCOMPARE(p0.isPending(), true);
  237. QCOMPARE(p1.isPending(), true);
  238. QCOMPARE(waitForError(p0, QString{}), QString{"foo"});
  239. QCOMPARE(waitForError(p1, QString{}), QString{"bar"});
  240. QCOMPARE(v0, (QVector<int>{4, 6, 1}));
  241. QCOMPARE(v1, (QVector<int>{2, 4, 0, 6, 6, 1}));
  242. }
  243. void tst_helpers_reduce::sequenceTypes()
  244. {
  245. #if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
  246. // QLinkedList is deprecated since Qt 5.15.
  247. SequenceTester<QLinkedList<QtPromise::QPromise<int>>>::exec();
  248. #endif
  249. SequenceTester<QList<QtPromise::QPromise<int>>>::exec();
  250. SequenceTester<QVector<QtPromise::QPromise<int>>>::exec();
  251. SequenceTester<std::list<QtPromise::QPromise<int>>>::exec();
  252. SequenceTester<std::vector<QtPromise::QPromise<int>>>::exec();
  253. }