producer_tests.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. // This file is part of Desktop App Toolkit,
  2. // a set of libraries for developing nice desktop applications.
  3. //
  4. // For license and copyright information please follow this link:
  5. // https://github.com/desktop-app/legal/blob/master/LEGAL
  6. //
  7. #include <catch.hpp>
  8. #include <rpl/producer.h>
  9. #include <rpl/event_stream.h>
  10. using namespace rpl;
  11. class OnDestructor {
  12. public:
  13. OnDestructor(std::function<void()> callback)
  14. : _callback(std::move(callback)) {
  15. }
  16. ~OnDestructor() {
  17. if (_callback) {
  18. _callback();
  19. }
  20. }
  21. private:
  22. std::function<void()> _callback;
  23. };
  24. TEST_CASE("basic producer tests", "[rpl::producer]") {
  25. SECTION("producer next, done and lifetime end test") {
  26. auto lifetimeEnded = std::make_shared<bool>(false);
  27. auto sum = std::make_shared<int>(0);
  28. auto doneGenerated = std::make_shared<bool>(false);
  29. auto destroyed = std::make_shared<bool>(false);
  30. {
  31. auto destroyCaller = std::make_shared<OnDestructor>([=] {
  32. *destroyed = true;
  33. });
  34. {
  35. auto alive = make_producer<int>([=](auto &&consumer) {
  36. (void)destroyCaller;
  37. consumer.put_next(1);
  38. consumer.put_next(2);
  39. consumer.put_next(3);
  40. consumer.put_done();
  41. return [=] {
  42. (void)destroyCaller;
  43. *lifetimeEnded = true;
  44. };
  45. }).start([=](int value) {
  46. (void)destroyCaller;
  47. *sum += value;
  48. }, [=](no_error) {
  49. (void)destroyCaller;
  50. }, [=]() {
  51. (void)destroyCaller;
  52. *doneGenerated = true;
  53. });
  54. }
  55. }
  56. REQUIRE(*sum == 1 + 2 + 3);
  57. REQUIRE(*doneGenerated);
  58. REQUIRE(*lifetimeEnded);
  59. REQUIRE(*destroyed);
  60. }
  61. SECTION("producer error test") {
  62. auto errorGenerated = std::make_shared<bool>(false);
  63. {
  64. auto alive = make_producer<no_value, bool>([=](auto &&consumer) {
  65. consumer.put_error(true);
  66. return lifetime();
  67. }).start([=](no_value) {
  68. }, [=](bool error) {
  69. *errorGenerated = error;
  70. }, [=]() {
  71. });
  72. }
  73. REQUIRE(*errorGenerated);
  74. }
  75. SECTION("nested lifetimes test") {
  76. auto lifetimeEndCount = std::make_shared<int>(0);
  77. {
  78. auto lifetimes = lifetime();
  79. {
  80. auto testProducer = make_producer<no_value>([=](auto &&consumer) {
  81. return [=] {
  82. ++*lifetimeEndCount;
  83. };
  84. });
  85. testProducer.start_copy([=](no_value) {
  86. }, [=](no_error) {
  87. }, [=] {
  88. }, lifetimes);
  89. std::move(testProducer).start([=](no_value) {
  90. }, [=](no_error) {
  91. }, [=] {
  92. }, lifetimes);
  93. }
  94. REQUIRE(*lifetimeEndCount == 0);
  95. }
  96. REQUIRE(*lifetimeEndCount == 2);
  97. }
  98. SECTION("nested producers test") {
  99. auto sum = std::make_shared<int>(0);
  100. auto lifetimeEndCount = std::make_shared<int>(0);
  101. auto saved = lifetime();
  102. {
  103. make_producer<int>([=](auto &&consumer) {
  104. auto inner = make_producer<int>([=](auto &&consumer) {
  105. consumer.put_next(1);
  106. consumer.put_next(2);
  107. consumer.put_next(3);
  108. return [=] {
  109. ++*lifetimeEndCount;
  110. };
  111. });
  112. auto result = lifetime([=] {
  113. ++*lifetimeEndCount;
  114. });
  115. inner.start_copy([=](int value) {
  116. consumer.put_next_copy(value);
  117. }, [=](no_error) {
  118. }, [=] {
  119. }, result);
  120. std::move(inner).start([=](int value) {
  121. consumer.put_next_copy(value);
  122. }, [=](no_error) {
  123. }, [=] {
  124. }, result);
  125. return result;
  126. }).start([=](int value) {
  127. *sum += value;
  128. }, [=](no_error) {
  129. }, [=] {
  130. }, saved);
  131. }
  132. REQUIRE(*sum == 1 + 2 + 3 + 1 + 2 + 3);
  133. REQUIRE(*lifetimeEndCount == 0);
  134. saved.destroy();
  135. REQUIRE(*lifetimeEndCount == 3);
  136. }
  137. SECTION("tuple producer test") {
  138. auto result = std::make_shared<int>(0);
  139. {
  140. auto alive = make_producer<std::tuple<int, double>>([=](
  141. auto &&consumer) {
  142. consumer.put_next(std::make_tuple(1, 2.));
  143. return lifetime();
  144. }).start([=](int a, double b) {
  145. *result = a + int(b);
  146. }, [=](no_error error) {
  147. }, [=]() {
  148. });
  149. }
  150. REQUIRE(*result == 3);
  151. }
  152. }
  153. TEST_CASE("basic event_streams tests", "[rpl::event_stream]") {
  154. SECTION("event_stream basic test") {
  155. auto sum = std::make_shared<int>(0);
  156. event_stream<int> stream;
  157. stream.fire(1);
  158. stream.fire(2);
  159. stream.fire(3);
  160. {
  161. auto saved = lifetime();
  162. stream.events().start([=](int value) {
  163. *sum += value;
  164. }, [=](no_error) {
  165. }, [=] {
  166. }, saved);
  167. stream.fire(11);
  168. stream.fire(12);
  169. stream.fire(13);
  170. }
  171. stream.fire(21);
  172. stream.fire(22);
  173. stream.fire(23);
  174. REQUIRE(11 + 12 + 13);
  175. }
  176. SECTION("event_stream add in handler test") {
  177. auto sum = std::make_shared<int>(0);
  178. event_stream<int> stream;
  179. {
  180. auto composite = lifetime();
  181. stream.events().start([=, &stream, &composite](int value) {
  182. *sum += value;
  183. stream.events().start([=](int value) {
  184. *sum += value;
  185. }, [=](no_error) {
  186. }, [=] {
  187. }, composite);
  188. }, [=](no_error) {
  189. }, [=] {
  190. }, composite);
  191. {
  192. auto inner = lifetime();
  193. stream.events().start([=, &stream, &inner](int value) {
  194. *sum += value;
  195. stream.events().start([=](int value) {
  196. *sum += value;
  197. }, [=](no_error) {
  198. }, [=] {
  199. }, inner);
  200. }, [=](no_error) {
  201. }, [=] {
  202. }, inner);
  203. stream.fire(1);
  204. stream.fire(2);
  205. stream.fire(3);
  206. }
  207. stream.fire(11);
  208. stream.fire(12);
  209. stream.fire(13);
  210. }
  211. stream.fire(21);
  212. stream.fire(22);
  213. stream.fire(23);
  214. REQUIRE(*sum ==
  215. (1 + 1) +
  216. ((2 + 2) + (2 + 2)) +
  217. ((3 + 3 + 3) + (3 + 3 + 3)) +
  218. (11 + 11 + 11 + 11) +
  219. (12 + 12 + 12 + 12 + 12) +
  220. (13 + 13 + 13 + 13 + 13 + 13));
  221. }
  222. SECTION("event_stream add and remove in handler test") {
  223. auto sum = std::make_shared<int>(0);
  224. event_stream<int> stream;
  225. {
  226. auto composite = lifetime();
  227. stream.events().start([=, &stream, &composite](int value) {
  228. *sum += value;
  229. composite.destroy();
  230. stream.events().start([=](int value) {
  231. *sum += value;
  232. }, [=](no_error) {
  233. }, [=] {
  234. }, composite);
  235. }, [=](no_error) {
  236. }, [=] {
  237. }, composite);
  238. {
  239. auto inner = lifetime();
  240. stream.events().start([=, &stream, &inner](int value) {
  241. *sum += value;
  242. inner.destroy();
  243. stream.events().start([=](int value) {
  244. *sum += value;
  245. }, [=](no_error) {
  246. }, [=] {
  247. }, inner);
  248. }, [=](no_error) {
  249. }, [=] {
  250. }, inner);
  251. stream.fire(1);
  252. stream.fire(2);
  253. stream.fire(3);
  254. }
  255. stream.fire(11);
  256. stream.fire(12);
  257. stream.fire(13);
  258. }
  259. stream.fire(21);
  260. stream.fire(22);
  261. stream.fire(23);
  262. REQUIRE(*sum ==
  263. (1 + 1) +
  264. (2 + 2) +
  265. (3 + 3) +
  266. (11) +
  267. (12) +
  268. (13));
  269. }
  270. SECTION("event_stream ends before handler lifetime") {
  271. auto sum = std::make_shared<int>(0);
  272. lifetime extended;
  273. {
  274. event_stream<int> stream;
  275. stream.events().start([=](int value) {
  276. *sum += value;
  277. }, [=](no_error) {
  278. }, [=] {
  279. }, extended);
  280. stream.fire(1);
  281. stream.fire(2);
  282. stream.fire(3);
  283. }
  284. REQUIRE(*sum == 1 + 2 + 3);
  285. }
  286. SECTION("event_stream move test") {
  287. auto sum = std::make_shared<int>(0);
  288. lifetime extended;
  289. {
  290. event_stream<int> stream;
  291. stream.events()
  292. | start_with_next([=](int value) {
  293. *sum += value;
  294. }, extended);
  295. stream.fire(1);
  296. stream.fire(2);
  297. auto movedStream = std::move(stream);
  298. movedStream.fire(3);
  299. movedStream.fire(4);
  300. }
  301. REQUIRE(*sum == 1 + 2 + 3 + 4);
  302. }
  303. }
  304. TEST_CASE("basic piping tests", "[rpl::producer]") {
  305. SECTION("start_with_*") {
  306. auto sum = std::make_shared<int>(0);
  307. auto dones = std::make_shared<int>(0);
  308. {
  309. auto alive = lifetime();
  310. make_producer<int, int>([=](auto &&consumer) {
  311. consumer.put_next(1);
  312. consumer.put_done();
  313. return lifetime();
  314. }) | start_with_next([=](int value) {
  315. *sum += value;
  316. }, alive);
  317. make_producer<int, int>([=](auto &&consumer) {
  318. consumer.put_next(11);
  319. consumer.put_error(111);
  320. return lifetime();
  321. }) | start_with_error([=](int value) {
  322. *sum += value;
  323. }, alive);
  324. make_producer<int, int>([=](auto &&consumer) {
  325. consumer.put_next(1111);
  326. consumer.put_done();
  327. return lifetime();
  328. }) | start_with_done([=]() {
  329. *dones += 1;
  330. }, alive);
  331. make_producer<int, int>([=](auto &&consumer) {
  332. consumer.put_next(11111);
  333. consumer.put_next(11112);
  334. consumer.put_next(11113);
  335. consumer.put_error(11114);
  336. return lifetime();
  337. }) | start_with_next_error([=](int value) {
  338. *sum += value;
  339. }, [=](int value) {
  340. *sum += value;
  341. }, alive);
  342. }
  343. auto alive = lifetime();
  344. make_producer<int, int>([=](auto &&consumer) {
  345. consumer.put_next(111111);
  346. consumer.put_next(111112);
  347. consumer.put_next(111113);
  348. consumer.put_done();
  349. return lifetime();
  350. }) | start_with_next_done([=](int value) {
  351. *sum += value;
  352. }, [=]() {
  353. *dones += 11;
  354. }, alive);
  355. make_producer<int, int>([=](auto &&consumer) {
  356. consumer.put_error(1111111);
  357. return lifetime();
  358. }) | start_with_error_done([=](int value) {
  359. *sum += value;
  360. }, [=]() {
  361. *dones = 0;
  362. }, alive);
  363. make_producer<int, int>([=](auto &&consumer) {
  364. consumer.put_next(11111111);
  365. consumer.put_next(11111112);
  366. consumer.put_next(11111113);
  367. consumer.put_error(11111114);
  368. return lifetime();
  369. }) | start_with_next_error_done([=](int value) {
  370. *sum += value;
  371. }, [=](int value) {
  372. *sum += value;
  373. }, [=]() {
  374. *dones = 0;
  375. }, alive);
  376. REQUIRE(*sum ==
  377. 1 +
  378. 111 +
  379. 11111 + 11112 + 11113 + 11114 +
  380. 111111 + 111112 + 111113 +
  381. 1111111 +
  382. 11111111 + 11111112 + 11111113 + 11111114);
  383. REQUIRE(*dones == 1 + 11);
  384. }
  385. SECTION("start_with_next should copy its callback") {
  386. auto sum = std::make_shared<int>(0);
  387. {
  388. auto next = [=](int value) {
  389. REQUIRE(sum != nullptr);
  390. *sum += value;
  391. };
  392. for (int i = 0; i != 3; ++i) {
  393. auto alive = lifetime();
  394. make_producer<int, int>([=](auto &&consumer) {
  395. consumer.put_next(1);
  396. consumer.put_done();
  397. return lifetime();
  398. }) | start_with_next(next, alive);
  399. }
  400. }
  401. REQUIRE(*sum == 3);
  402. }
  403. }