future_ut.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. #include "future.h"
  2. #include <library/cpp/testing/unittest/registar.h>
  3. #include <list>
  4. #include <type_traits>
  5. namespace NThreading {
  6. namespace {
  7. class TCopyCounter {
  8. public:
  9. TCopyCounter(size_t* numCopies)
  10. : NumCopies(numCopies)
  11. {}
  12. TCopyCounter(const TCopyCounter& that)
  13. : NumCopies(that.NumCopies)
  14. {
  15. ++*NumCopies;
  16. }
  17. TCopyCounter& operator=(const TCopyCounter& that) {
  18. NumCopies = that.NumCopies;
  19. ++*NumCopies;
  20. return *this;
  21. }
  22. TCopyCounter(TCopyCounter&& that) = default;
  23. TCopyCounter& operator=(TCopyCounter&& that) = default;
  24. private:
  25. size_t* NumCopies = nullptr;
  26. };
  27. template <typename T>
  28. auto MakePromise() {
  29. if constexpr (std::is_same_v<T, void>) {
  30. return NewPromise();
  31. }
  32. return NewPromise<T>();
  33. }
  34. template <typename T>
  35. void TestFutureStateId() {
  36. TFuture<T> empty;
  37. UNIT_ASSERT(!empty.StateId().Defined());
  38. auto promise1 = MakePromise<T>();
  39. auto future11 = promise1.GetFuture();
  40. UNIT_ASSERT(future11.StateId().Defined());
  41. auto future12 = promise1.GetFuture();
  42. UNIT_ASSERT_EQUAL(future11.StateId(), future11.StateId()); // same result for subsequent invocations
  43. UNIT_ASSERT_EQUAL(future11.StateId(), future12.StateId()); // same result for different futures with the same state
  44. auto promise2 = MakePromise<T>();
  45. auto future2 = promise2.GetFuture();
  46. UNIT_ASSERT(future2.StateId().Defined());
  47. UNIT_ASSERT_UNEQUAL(future11.StateId(), future2.StateId()); // different results for futures with different states
  48. }
  49. }
  50. ////////////////////////////////////////////////////////////////////////////////
  51. Y_UNIT_TEST_SUITE(TFutureTest) {
  52. Y_UNIT_TEST(ShouldInitiallyHasNoValue) {
  53. TPromise<int> promise;
  54. UNIT_ASSERT(!promise.HasValue());
  55. promise = NewPromise<int>();
  56. UNIT_ASSERT(!promise.HasValue());
  57. TFuture<int> future;
  58. UNIT_ASSERT(!future.HasValue());
  59. future = promise.GetFuture();
  60. UNIT_ASSERT(!future.HasValue());
  61. }
  62. Y_UNIT_TEST(ShouldInitiallyHasNoValueVoid) {
  63. TPromise<void> promise;
  64. UNIT_ASSERT(!promise.HasValue());
  65. promise = NewPromise();
  66. UNIT_ASSERT(!promise.HasValue());
  67. TFuture<void> future;
  68. UNIT_ASSERT(!future.HasValue());
  69. future = promise.GetFuture();
  70. UNIT_ASSERT(!future.HasValue());
  71. }
  72. Y_UNIT_TEST(ShouldStoreValue) {
  73. TPromise<int> promise = NewPromise<int>();
  74. promise.SetValue(123);
  75. UNIT_ASSERT(promise.HasValue());
  76. UNIT_ASSERT_EQUAL(promise.GetValue(), 123);
  77. TFuture<int> future = promise.GetFuture();
  78. UNIT_ASSERT(future.HasValue());
  79. UNIT_ASSERT_EQUAL(future.GetValue(), 123);
  80. future = MakeFuture(345);
  81. UNIT_ASSERT(future.HasValue());
  82. UNIT_ASSERT_EQUAL(future.GetValue(), 345);
  83. }
  84. Y_UNIT_TEST(ShouldStoreValueVoid) {
  85. TPromise<void> promise = NewPromise();
  86. promise.SetValue();
  87. UNIT_ASSERT(promise.HasValue());
  88. TFuture<void> future = promise.GetFuture();
  89. UNIT_ASSERT(future.HasValue());
  90. future = MakeFuture();
  91. UNIT_ASSERT(future.HasValue());
  92. }
  93. struct TTestCallback {
  94. int Value;
  95. TTestCallback(int value)
  96. : Value(value)
  97. {
  98. }
  99. void Callback(const TFuture<int>& future) {
  100. Value += future.GetValue();
  101. }
  102. int Func(const TFuture<int>& future) {
  103. return (Value += future.GetValue());
  104. }
  105. void VoidFunc(const TFuture<int>& future) {
  106. future.GetValue();
  107. }
  108. TFuture<int> FutureFunc(const TFuture<int>& future) {
  109. return MakeFuture(Value += future.GetValue());
  110. }
  111. TPromise<void> Signal = NewPromise();
  112. TFuture<void> FutureVoidFunc(const TFuture<int>& future) {
  113. future.GetValue();
  114. return Signal;
  115. }
  116. };
  117. Y_UNIT_TEST(ShouldInvokeCallback) {
  118. TPromise<int> promise = NewPromise<int>();
  119. TTestCallback callback(123);
  120. TFuture<int> future = promise.GetFuture()
  121. .Subscribe([&](const TFuture<int>& theFuture) { return callback.Callback(theFuture); });
  122. promise.SetValue(456);
  123. UNIT_ASSERT_EQUAL(future.GetValue(), 456);
  124. UNIT_ASSERT_EQUAL(callback.Value, 123 + 456);
  125. }
  126. Y_UNIT_TEST(ShouldApplyFunc) {
  127. TPromise<int> promise = NewPromise<int>();
  128. TTestCallback callback(123);
  129. TFuture<int> future = promise.GetFuture()
  130. .Apply([&](const auto& theFuture) { return callback.Func(theFuture); });
  131. promise.SetValue(456);
  132. UNIT_ASSERT_EQUAL(future.GetValue(), 123 + 456);
  133. UNIT_ASSERT_EQUAL(callback.Value, 123 + 456);
  134. }
  135. Y_UNIT_TEST(ShouldApplyVoidFunc) {
  136. TPromise<int> promise = NewPromise<int>();
  137. TTestCallback callback(123);
  138. TFuture<void> future = promise.GetFuture()
  139. .Apply([&](const auto& theFuture) { return callback.VoidFunc(theFuture); });
  140. promise.SetValue(456);
  141. UNIT_ASSERT(future.HasValue());
  142. }
  143. Y_UNIT_TEST(ShouldApplyFutureFunc) {
  144. TPromise<int> promise = NewPromise<int>();
  145. TTestCallback callback(123);
  146. TFuture<int> future = promise.GetFuture()
  147. .Apply([&](const auto& theFuture) { return callback.FutureFunc(theFuture); });
  148. promise.SetValue(456);
  149. UNIT_ASSERT_EQUAL(future.GetValue(), 123 + 456);
  150. UNIT_ASSERT_EQUAL(callback.Value, 123 + 456);
  151. }
  152. Y_UNIT_TEST(ShouldApplyFutureVoidFunc) {
  153. TPromise<int> promise = NewPromise<int>();
  154. TTestCallback callback(123);
  155. TFuture<void> future = promise.GetFuture()
  156. .Apply([&](const auto& theFuture) { return callback.FutureVoidFunc(theFuture); });
  157. promise.SetValue(456);
  158. UNIT_ASSERT(!future.HasValue());
  159. callback.Signal.SetValue();
  160. UNIT_ASSERT(future.HasValue());
  161. }
  162. Y_UNIT_TEST(ShouldIgnoreResultIfAsked) {
  163. TPromise<int> promise = NewPromise<int>();
  164. TTestCallback callback(123);
  165. TFuture<int> future = promise.GetFuture().IgnoreResult().Return(42);
  166. promise.SetValue(456);
  167. UNIT_ASSERT_EQUAL(future.GetValue(), 42);
  168. }
  169. class TCustomException: public yexception {
  170. };
  171. Y_UNIT_TEST(ShouldRethrowException) {
  172. TPromise<int> promise = NewPromise<int>();
  173. try {
  174. ythrow TCustomException();
  175. } catch (...) {
  176. promise.SetException(std::current_exception());
  177. }
  178. UNIT_ASSERT(!promise.HasValue());
  179. UNIT_ASSERT(promise.HasException());
  180. UNIT_ASSERT_EXCEPTION(promise.GetValue(), TCustomException);
  181. UNIT_ASSERT_EXCEPTION(promise.TryRethrow(), TCustomException);
  182. }
  183. Y_UNIT_TEST(ShouldRethrowCallbackException) {
  184. TPromise<int> promise = NewPromise<int>();
  185. TFuture<int> future = promise.GetFuture();
  186. future.Subscribe([](const TFuture<int>&) {
  187. throw TCustomException();
  188. });
  189. UNIT_ASSERT_EXCEPTION(promise.SetValue(123), TCustomException);
  190. }
  191. Y_UNIT_TEST(ShouldRethrowCallbackExceptionIgnoreResult) {
  192. TPromise<int> promise = NewPromise<int>();
  193. TFuture<void> future = promise.GetFuture().IgnoreResult();
  194. future.Subscribe([](const TFuture<void>&) {
  195. throw TCustomException();
  196. });
  197. UNIT_ASSERT_EXCEPTION(promise.SetValue(123), TCustomException);
  198. }
  199. Y_UNIT_TEST(ShouldWaitExceptionOrAll) {
  200. TPromise<void> promise1 = NewPromise();
  201. TPromise<void> promise2 = NewPromise();
  202. TFuture<void> future = WaitExceptionOrAll(promise1, promise2);
  203. UNIT_ASSERT(!future.HasValue());
  204. promise1.SetValue();
  205. UNIT_ASSERT(!future.HasValue());
  206. promise2.SetValue();
  207. UNIT_ASSERT(future.HasValue());
  208. }
  209. Y_UNIT_TEST(ShouldWaitExceptionOrAllVector) {
  210. TPromise<void> promise1 = NewPromise();
  211. TPromise<void> promise2 = NewPromise();
  212. TVector<TFuture<void>> promises;
  213. promises.push_back(promise1);
  214. promises.push_back(promise2);
  215. TFuture<void> future = WaitExceptionOrAll(promises);
  216. UNIT_ASSERT(!future.HasValue());
  217. promise1.SetValue();
  218. UNIT_ASSERT(!future.HasValue());
  219. promise2.SetValue();
  220. UNIT_ASSERT(future.HasValue());
  221. }
  222. Y_UNIT_TEST(ShouldWaitExceptionOrAllVectorWithValueType) {
  223. TPromise<int> promise1 = NewPromise<int>();
  224. TPromise<int> promise2 = NewPromise<int>();
  225. TVector<TFuture<int>> promises;
  226. promises.push_back(promise1);
  227. promises.push_back(promise2);
  228. TFuture<void> future = WaitExceptionOrAll(promises);
  229. UNIT_ASSERT(!future.HasValue());
  230. promise1.SetValue(0);
  231. UNIT_ASSERT(!future.HasValue());
  232. promise2.SetValue(0);
  233. UNIT_ASSERT(future.HasValue());
  234. }
  235. Y_UNIT_TEST(ShouldWaitExceptionOrAllList) {
  236. TPromise<void> promise1 = NewPromise();
  237. TPromise<void> promise2 = NewPromise();
  238. std::list<TFuture<void>> promises;
  239. promises.push_back(promise1);
  240. promises.push_back(promise2);
  241. TFuture<void> future = WaitExceptionOrAll(promises);
  242. UNIT_ASSERT(!future.HasValue());
  243. promise1.SetValue();
  244. UNIT_ASSERT(!future.HasValue());
  245. promise2.SetValue();
  246. UNIT_ASSERT(future.HasValue());
  247. }
  248. Y_UNIT_TEST(ShouldWaitExceptionOrAllVectorEmpty) {
  249. TVector<TFuture<void>> promises;
  250. TFuture<void> future = WaitExceptionOrAll(promises);
  251. UNIT_ASSERT(future.HasValue());
  252. }
  253. Y_UNIT_TEST(ShouldWaitAnyVector) {
  254. TPromise<void> promise1 = NewPromise();
  255. TPromise<void> promise2 = NewPromise();
  256. TVector<TFuture<void>> promises;
  257. promises.push_back(promise1);
  258. promises.push_back(promise2);
  259. TFuture<void> future = WaitAny(promises);
  260. UNIT_ASSERT(!future.HasValue());
  261. promise1.SetValue();
  262. UNIT_ASSERT(future.HasValue());
  263. promise2.SetValue();
  264. UNIT_ASSERT(future.HasValue());
  265. }
  266. Y_UNIT_TEST(ShouldWaitAnyVectorWithValueType) {
  267. TPromise<int> promise1 = NewPromise<int>();
  268. TPromise<int> promise2 = NewPromise<int>();
  269. TVector<TFuture<int>> promises;
  270. promises.push_back(promise1);
  271. promises.push_back(promise2);
  272. TFuture<void> future = WaitAny(promises);
  273. UNIT_ASSERT(!future.HasValue());
  274. promise1.SetValue(0);
  275. UNIT_ASSERT(future.HasValue());
  276. promise2.SetValue(0);
  277. UNIT_ASSERT(future.HasValue());
  278. }
  279. Y_UNIT_TEST(ShouldWaitAnyList) {
  280. TPromise<void> promise1 = NewPromise();
  281. TPromise<void> promise2 = NewPromise();
  282. std::list<TFuture<void>> promises;
  283. promises.push_back(promise1);
  284. promises.push_back(promise2);
  285. TFuture<void> future = WaitAny(promises);
  286. UNIT_ASSERT(!future.HasValue());
  287. promise1.SetValue();
  288. UNIT_ASSERT(future.HasValue());
  289. promise2.SetValue();
  290. UNIT_ASSERT(future.HasValue());
  291. }
  292. Y_UNIT_TEST(ShouldWaitAnyVectorEmpty) {
  293. TVector<TFuture<void>> promises;
  294. TFuture<void> future = WaitAny(promises);
  295. UNIT_ASSERT(future.HasValue());
  296. }
  297. Y_UNIT_TEST(ShouldWaitAny) {
  298. TPromise<void> promise1 = NewPromise();
  299. TPromise<void> promise2 = NewPromise();
  300. TFuture<void> future = WaitAny(promise1, promise2);
  301. UNIT_ASSERT(!future.HasValue());
  302. promise1.SetValue();
  303. UNIT_ASSERT(future.HasValue());
  304. promise2.SetValue();
  305. UNIT_ASSERT(future.HasValue());
  306. }
  307. Y_UNIT_TEST(ShouldStoreTypesWithoutDefaultConstructor) {
  308. // compileability test
  309. struct TRec {
  310. explicit TRec(int) {
  311. }
  312. };
  313. auto promise = NewPromise<TRec>();
  314. promise.SetValue(TRec(1));
  315. auto future = MakeFuture(TRec(1));
  316. const auto& rec = future.GetValue();
  317. Y_UNUSED(rec);
  318. }
  319. Y_UNIT_TEST(ShouldStoreMovableTypes) {
  320. // compileability test
  321. struct TRec : TMoveOnly {
  322. explicit TRec(int) {
  323. }
  324. };
  325. auto promise = NewPromise<TRec>();
  326. promise.SetValue(TRec(1));
  327. auto future = MakeFuture(TRec(1));
  328. const auto& rec = future.GetValue();
  329. Y_UNUSED(rec);
  330. }
  331. Y_UNIT_TEST(ShouldMoveMovableTypes) {
  332. // compileability test
  333. struct TRec : TMoveOnly {
  334. explicit TRec(int) {
  335. }
  336. };
  337. auto promise = NewPromise<TRec>();
  338. promise.SetValue(TRec(1));
  339. auto future = MakeFuture(TRec(1));
  340. auto rec = future.ExtractValue();
  341. Y_UNUSED(rec);
  342. }
  343. Y_UNIT_TEST(ShouldNotExtractAfterGet) {
  344. TPromise<int> promise = NewPromise<int>();
  345. promise.SetValue(123);
  346. UNIT_ASSERT(promise.HasValue());
  347. UNIT_ASSERT_EQUAL(promise.GetValue(), 123);
  348. UNIT_CHECK_GENERATED_EXCEPTION(promise.ExtractValue(), TFutureException);
  349. }
  350. Y_UNIT_TEST(ShouldNotGetAfterExtract) {
  351. TPromise<int> promise = NewPromise<int>();
  352. promise.SetValue(123);
  353. UNIT_ASSERT(promise.HasValue());
  354. UNIT_ASSERT_EQUAL(promise.ExtractValue(), 123);
  355. UNIT_CHECK_GENERATED_EXCEPTION(promise.GetValue(), TFutureException);
  356. }
  357. Y_UNIT_TEST(ShouldNotExtractAfterExtract) {
  358. TPromise<int> promise = NewPromise<int>();
  359. promise.SetValue(123);
  360. UNIT_ASSERT(promise.HasValue());
  361. UNIT_ASSERT_EQUAL(promise.ExtractValue(), 123);
  362. UNIT_CHECK_GENERATED_EXCEPTION(promise.ExtractValue(), TFutureException);
  363. }
  364. Y_UNIT_TEST(ShouldNotExtractFromSharedDefault) {
  365. UNIT_CHECK_GENERATED_EXCEPTION(MakeFuture<int>().ExtractValue(), TFutureException);
  366. struct TStorage {
  367. TString String = TString(100, 'a');
  368. };
  369. try {
  370. TString s = MakeFuture<TStorage>().ExtractValue().String;
  371. Y_UNUSED(s);
  372. } catch (TFutureException) {
  373. // pass
  374. }
  375. UNIT_ASSERT_VALUES_EQUAL(MakeFuture<TStorage>().GetValue().String, TString(100, 'a'));
  376. }
  377. Y_UNIT_TEST(HandlingRepetitiveSet) {
  378. TPromise<int> promise = NewPromise<int>();
  379. promise.SetValue(42);
  380. UNIT_CHECK_GENERATED_EXCEPTION(promise.SetValue(42), TFutureException);
  381. }
  382. Y_UNIT_TEST(HandlingRepetitiveTrySet) {
  383. TPromise<int> promise = NewPromise<int>();
  384. UNIT_ASSERT(promise.TrySetValue(42));
  385. UNIT_ASSERT(!promise.TrySetValue(42));
  386. }
  387. Y_UNIT_TEST(HandlingRepetitiveSetException) {
  388. TPromise<int> promise = NewPromise<int>();
  389. promise.SetException("test");
  390. UNIT_CHECK_GENERATED_EXCEPTION(promise.SetException("test"), TFutureException);
  391. }
  392. Y_UNIT_TEST(HandlingRepetitiveTrySetException) {
  393. TPromise<int> promise = NewPromise<int>();
  394. UNIT_ASSERT(promise.TrySetException(std::make_exception_ptr("test")));
  395. UNIT_ASSERT(!promise.TrySetException(std::make_exception_ptr("test")));
  396. }
  397. Y_UNIT_TEST(ShouldAllowToMakeFutureWithException)
  398. {
  399. auto future1 = MakeErrorFuture<void>(std::make_exception_ptr(TFutureException()));
  400. UNIT_ASSERT(future1.HasException());
  401. UNIT_CHECK_GENERATED_EXCEPTION(future1.GetValue(), TFutureException);
  402. auto future2 = MakeErrorFuture<int>(std::make_exception_ptr(TFutureException()));
  403. UNIT_ASSERT(future2.HasException());
  404. UNIT_CHECK_GENERATED_EXCEPTION(future2.GetValue(), TFutureException);
  405. auto future3 = MakeFuture<std::exception_ptr>(std::make_exception_ptr(TFutureException()));
  406. UNIT_ASSERT(future3.HasValue());
  407. UNIT_CHECK_GENERATED_NO_EXCEPTION(future3.GetValue(), TFutureException);
  408. auto future4 = MakeFuture<std::unique_ptr<int>>(nullptr);
  409. UNIT_ASSERT(future4.HasValue());
  410. UNIT_CHECK_GENERATED_NO_EXCEPTION(future4.GetValue(), TFutureException);
  411. }
  412. Y_UNIT_TEST(WaitAllowsExtract) {
  413. auto future = MakeFuture<int>(42);
  414. TVector vec{future, future, future};
  415. WaitExceptionOrAll(vec).GetValue();
  416. WaitAny(vec).GetValue();
  417. UNIT_ASSERT_EQUAL(future.ExtractValue(), 42);
  418. }
  419. Y_UNIT_TEST(IgnoreAllowsExtract) {
  420. auto future = MakeFuture<int>(42);
  421. future.IgnoreResult().GetValue();
  422. UNIT_ASSERT_EQUAL(future.ExtractValue(), 42);
  423. }
  424. Y_UNIT_TEST(WaitExceptionOrAllException) {
  425. auto promise1 = NewPromise();
  426. auto promise2 = NewPromise();
  427. auto future1 = promise1.GetFuture();
  428. auto future2 = promise2.GetFuture();
  429. auto wait = WaitExceptionOrAll(future1, future2);
  430. promise2.SetException("foo-exception");
  431. wait.Wait();
  432. UNIT_ASSERT(future2.HasException());
  433. UNIT_ASSERT(!future1.HasValue() && !future1.HasException());
  434. }
  435. Y_UNIT_TEST(WaitAllException) {
  436. auto promise1 = NewPromise();
  437. auto promise2 = NewPromise();
  438. auto future1 = promise1.GetFuture();
  439. auto future2 = promise2.GetFuture();
  440. auto wait = WaitAll(future1, future2);
  441. promise2.SetException("foo-exception");
  442. UNIT_ASSERT(!wait.HasValue() && !wait.HasException());
  443. promise1.SetValue();
  444. UNIT_ASSERT_EXCEPTION_CONTAINS(wait.GetValueSync(), yexception, "foo-exception");
  445. }
  446. Y_UNIT_TEST(FutureStateId) {
  447. TestFutureStateId<void>();
  448. TestFutureStateId<int>();
  449. }
  450. template <typename T>
  451. void TestApplyNoRvalueCopyImpl() {
  452. size_t numCopies = 0;
  453. TCopyCounter copyCounter(&numCopies);
  454. auto promise = MakePromise<T>();
  455. const auto future = promise.GetFuture().Apply(
  456. [copyCounter = std::move(copyCounter)] (const auto&) {}
  457. );
  458. if constexpr (std::is_same_v<T, void>) {
  459. promise.SetValue();
  460. } else {
  461. promise.SetValue(T());
  462. }
  463. future.GetValueSync();
  464. UNIT_ASSERT_VALUES_EQUAL(numCopies, 0);
  465. }
  466. Y_UNIT_TEST(ApplyNoRvalueCopy) {
  467. TestApplyNoRvalueCopyImpl<void>();
  468. TestApplyNoRvalueCopyImpl<int>();
  469. }
  470. template <typename T>
  471. void TestApplyLvalueCopyImpl() {
  472. size_t numCopies = 0;
  473. TCopyCounter copyCounter(&numCopies);
  474. auto promise = MakePromise<T>();
  475. auto func = [copyCounter = std::move(copyCounter)] (const auto&) {};
  476. const auto future = promise.GetFuture().Apply(func);
  477. if constexpr (std::is_same_v<T, void>) {
  478. promise.SetValue();
  479. } else {
  480. promise.SetValue(T());
  481. }
  482. future.GetValueSync();
  483. UNIT_ASSERT_VALUES_EQUAL(numCopies, 1);
  484. }
  485. Y_UNIT_TEST(ApplyLvalueCopy) {
  486. TestApplyLvalueCopyImpl<void>();
  487. TestApplyLvalueCopyImpl<int>();
  488. }
  489. Y_UNIT_TEST(ReturnForwardingTypeDeduction) {
  490. const TString e = TString(80, 'a');
  491. TString l = TString(80, 'a');
  492. TFuture<TString> futureL = MakeFuture().Return(l);
  493. UNIT_ASSERT_VALUES_EQUAL(futureL.GetValue(), e);
  494. UNIT_ASSERT_VALUES_EQUAL(l, e);
  495. TFuture<TString> futureR = MakeFuture().Return(std::move(l));
  496. UNIT_ASSERT_VALUES_EQUAL(futureR.GetValue(), e);
  497. }
  498. Y_UNIT_TEST(ReturnForwardingCopiesCount) {
  499. size_t numCopies = 0;
  500. TCopyCounter copyCounter(&numCopies);
  501. auto returnedCounter = MakeFuture().Return(std::move(copyCounter)).ExtractValueSync();
  502. Y_DO_NOT_OPTIMIZE_AWAY(returnedCounter);
  503. UNIT_ASSERT_VALUES_EQUAL(numCopies, 0);
  504. }
  505. }
  506. }