PromiseFulfilledTestTrait.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. <?php
  2. namespace React\Promise\PromiseTest;
  3. use Exception;
  4. use React\Promise\PromiseAdapter\PromiseAdapterInterface;
  5. use React\Promise\PromiseInterface;
  6. use stdClass;
  7. use function React\Promise\reject;
  8. use function React\Promise\resolve;
  9. trait PromiseFulfilledTestTrait
  10. {
  11. abstract public function getPromiseTestAdapter(callable $canceller = null): PromiseAdapterInterface;
  12. /** @test */
  13. public function fulfilledPromiseShouldBeImmutable(): void
  14. {
  15. $adapter = $this->getPromiseTestAdapter();
  16. $mock = $this->createCallableMock();
  17. $mock
  18. ->expects($this->once())
  19. ->method('__invoke')
  20. ->with($this->identicalTo(1));
  21. $adapter->resolve(1);
  22. $adapter->resolve(2);
  23. $adapter->promise()
  24. ->then(
  25. $mock,
  26. $this->expectCallableNever()
  27. );
  28. }
  29. /** @test */
  30. public function fulfilledPromiseShouldInvokeNewlyAddedCallback(): void
  31. {
  32. $adapter = $this->getPromiseTestAdapter();
  33. $adapter->resolve(1);
  34. $mock = $this->createCallableMock();
  35. $mock
  36. ->expects($this->once())
  37. ->method('__invoke')
  38. ->with($this->identicalTo(1));
  39. $adapter->promise()
  40. ->then($mock, $this->expectCallableNever());
  41. }
  42. /** @test */
  43. public function thenShouldForwardResultWhenCallbackIsNull(): void
  44. {
  45. $adapter = $this->getPromiseTestAdapter();
  46. $mock = $this->createCallableMock();
  47. $mock
  48. ->expects($this->once())
  49. ->method('__invoke')
  50. ->with($this->identicalTo(1));
  51. $adapter->resolve(1);
  52. $adapter->promise()
  53. ->then(
  54. null,
  55. $this->expectCallableNever()
  56. )
  57. ->then(
  58. $mock,
  59. $this->expectCallableNever()
  60. );
  61. }
  62. /** @test */
  63. public function thenShouldForwardCallbackResultToNextCallback(): void
  64. {
  65. $adapter = $this->getPromiseTestAdapter();
  66. $mock = $this->createCallableMock();
  67. $mock
  68. ->expects($this->once())
  69. ->method('__invoke')
  70. ->with($this->identicalTo(2));
  71. $adapter->resolve(1);
  72. $adapter->promise()
  73. ->then(
  74. function ($val) {
  75. return $val + 1;
  76. },
  77. $this->expectCallableNever()
  78. )
  79. ->then(
  80. $mock,
  81. $this->expectCallableNever()
  82. );
  83. }
  84. /** @test */
  85. public function thenShouldForwardPromisedCallbackResultValueToNextCallback(): void
  86. {
  87. $adapter = $this->getPromiseTestAdapter();
  88. $mock = $this->createCallableMock();
  89. $mock
  90. ->expects($this->once())
  91. ->method('__invoke')
  92. ->with($this->identicalTo(2));
  93. $adapter->resolve(1);
  94. $adapter->promise()
  95. ->then(
  96. function ($val) {
  97. return resolve($val + 1);
  98. },
  99. $this->expectCallableNever()
  100. )
  101. ->then(
  102. $mock,
  103. $this->expectCallableNever()
  104. );
  105. }
  106. /** @test */
  107. public function thenShouldSwitchFromCallbacksToErrbacksWhenCallbackReturnsARejection(): void
  108. {
  109. $adapter = $this->getPromiseTestAdapter();
  110. $exception = new Exception();
  111. $mock = $this->createCallableMock();
  112. $mock
  113. ->expects($this->once())
  114. ->method('__invoke')
  115. ->with($this->identicalTo($exception));
  116. $adapter->resolve(1);
  117. $adapter->promise()
  118. ->then(
  119. function () use ($exception) {
  120. return reject($exception);
  121. },
  122. $this->expectCallableNever()
  123. )
  124. ->then(
  125. $this->expectCallableNever(),
  126. $mock
  127. );
  128. }
  129. /** @test */
  130. public function thenShouldSwitchFromCallbacksToErrbacksWhenCallbackThrows(): void
  131. {
  132. $adapter = $this->getPromiseTestAdapter();
  133. $exception = new Exception();
  134. $mock = $this->createCallableMock();
  135. $mock
  136. ->expects($this->once())
  137. ->method('__invoke')
  138. ->will($this->throwException($exception));
  139. $mock2 = $this->createCallableMock();
  140. $mock2
  141. ->expects($this->once())
  142. ->method('__invoke')
  143. ->with($this->identicalTo($exception));
  144. $adapter->resolve(1);
  145. $adapter->promise()
  146. ->then(
  147. $mock,
  148. $this->expectCallableNever()
  149. )
  150. ->then(
  151. $this->expectCallableNever(),
  152. $mock2
  153. );
  154. }
  155. /**
  156. * @test
  157. * @requires PHP 8.1
  158. */
  159. public function thenShouldContinueToExecuteCallbacksWhenPriorCallbackSuspendsFiber(): void
  160. {
  161. /** @var PromiseAdapterInterface<int> $adapter */
  162. $adapter = $this->getPromiseTestAdapter();
  163. $adapter->resolve(42);
  164. $fiber = new \Fiber(function () use ($adapter) {
  165. $adapter->promise()->then(function (int $value) {
  166. \Fiber::suspend($value);
  167. });
  168. });
  169. $ret = $fiber->start();
  170. $this->assertEquals(42, $ret);
  171. $mock = $this->createCallableMock();
  172. $mock
  173. ->expects($this->once())
  174. ->method('__invoke')
  175. ->with($this->identicalTo(42));
  176. $adapter->promise()->then($mock);
  177. }
  178. /** @test */
  179. public function cancelShouldHaveNoEffectForFulfilledPromise(): void
  180. {
  181. $adapter = $this->getPromiseTestAdapter($this->expectCallableNever());
  182. $adapter->resolve(null);
  183. $adapter->promise()->cancel();
  184. }
  185. /** @test */
  186. public function catchShouldNotInvokeRejectionHandlerForFulfilledPromise(): void
  187. {
  188. $adapter = $this->getPromiseTestAdapter();
  189. $adapter->resolve(1);
  190. $adapter->promise()->catch($this->expectCallableNever());
  191. }
  192. /** @test */
  193. public function finallyShouldNotSuppressValueForFulfilledPromise(): void
  194. {
  195. $adapter = $this->getPromiseTestAdapter();
  196. $value = new stdClass();
  197. $mock = $this->createCallableMock();
  198. $mock
  199. ->expects($this->once())
  200. ->method('__invoke')
  201. ->with($this->identicalTo($value));
  202. $adapter->resolve($value);
  203. $adapter->promise()
  204. ->finally(function () {})
  205. ->then($mock);
  206. }
  207. /** @test */
  208. public function finallyShouldNotSuppressValueWhenHandlerReturnsANonPromiseForFulfilledPromise(): void
  209. {
  210. $adapter = $this->getPromiseTestAdapter();
  211. $value = new stdClass();
  212. $mock = $this->createCallableMock();
  213. $mock
  214. ->expects($this->once())
  215. ->method('__invoke')
  216. ->with($this->identicalTo($value));
  217. $adapter->resolve($value);
  218. $adapter->promise()
  219. ->finally(function (): int { // @phpstan-ignore-line
  220. return 1;
  221. })
  222. ->then($mock);
  223. }
  224. /** @test */
  225. public function finallyShouldNotSuppressValueWhenHandlerReturnsAPromiseForFulfilledPromise(): void
  226. {
  227. $adapter = $this->getPromiseTestAdapter();
  228. $value = new stdClass();
  229. $mock = $this->createCallableMock();
  230. $mock
  231. ->expects($this->once())
  232. ->method('__invoke')
  233. ->with($this->identicalTo($value));
  234. $adapter->resolve($value);
  235. $adapter->promise()
  236. ->finally(function (): PromiseInterface { // @phpstan-ignore-line
  237. return resolve(1);
  238. })
  239. ->then($mock);
  240. }
  241. /** @test */
  242. public function finallyShouldRejectWhenHandlerThrowsForFulfilledPromise(): void
  243. {
  244. $adapter = $this->getPromiseTestAdapter();
  245. $exception = new Exception();
  246. $mock = $this->createCallableMock();
  247. $mock
  248. ->expects($this->once())
  249. ->method('__invoke')
  250. ->with($this->identicalTo($exception));
  251. $adapter->resolve(1);
  252. $adapter->promise()
  253. ->finally(function () use ($exception) {
  254. throw $exception;
  255. })
  256. ->then(null, $mock);
  257. }
  258. /** @test */
  259. public function finallyShouldRejectWhenHandlerRejectsForFulfilledPromise(): void
  260. {
  261. $adapter = $this->getPromiseTestAdapter();
  262. $exception = new Exception();
  263. $mock = $this->createCallableMock();
  264. $mock
  265. ->expects($this->once())
  266. ->method('__invoke')
  267. ->with($this->identicalTo($exception));
  268. $adapter->resolve(1);
  269. $adapter->promise()
  270. ->finally(function () use ($exception) {
  271. return reject($exception);
  272. })
  273. ->then(null, $mock);
  274. }
  275. /**
  276. * @test
  277. * @deprecated
  278. */
  279. public function otherwiseShouldNotInvokeRejectionHandlerForFulfilledPromise(): void
  280. {
  281. $adapter = $this->getPromiseTestAdapter();
  282. $adapter->resolve(1);
  283. $adapter->promise()->otherwise($this->expectCallableNever());
  284. }
  285. /**
  286. * @test
  287. * @deprecated
  288. */
  289. public function alwaysShouldNotSuppressValueForFulfilledPromise(): void
  290. {
  291. $adapter = $this->getPromiseTestAdapter();
  292. $value = new stdClass();
  293. $mock = $this->createCallableMock();
  294. $mock
  295. ->expects($this->once())
  296. ->method('__invoke')
  297. ->with($this->identicalTo($value));
  298. $adapter->resolve($value);
  299. $adapter->promise()
  300. ->always(function () {})
  301. ->then($mock);
  302. }
  303. /**
  304. * @test
  305. * @deprecated
  306. */
  307. public function alwaysShouldNotSuppressValueWhenHandlerReturnsANonPromiseForFulfilledPromise(): void
  308. {
  309. $adapter = $this->getPromiseTestAdapter();
  310. $value = new stdClass();
  311. $mock = $this->createCallableMock();
  312. $mock
  313. ->expects($this->once())
  314. ->method('__invoke')
  315. ->with($this->identicalTo($value));
  316. $adapter->resolve($value);
  317. $adapter->promise()
  318. ->always(function (): int { // @phpstan-ignore-line
  319. return 1;
  320. })
  321. ->then($mock);
  322. }
  323. /**
  324. * @test
  325. * @deprecated
  326. */
  327. public function alwaysShouldNotSuppressValueWhenHandlerReturnsAPromiseForFulfilledPromise(): void
  328. {
  329. $adapter = $this->getPromiseTestAdapter();
  330. $value = new stdClass();
  331. $mock = $this->createCallableMock();
  332. $mock
  333. ->expects($this->once())
  334. ->method('__invoke')
  335. ->with($this->identicalTo($value));
  336. $adapter->resolve($value);
  337. $adapter->promise()
  338. ->always(function (): PromiseInterface { // @phpstan-ignore-line
  339. return resolve(1);
  340. })
  341. ->then($mock);
  342. }
  343. /**
  344. * @test
  345. * @deprecated
  346. */
  347. public function alwaysShouldRejectWhenHandlerThrowsForFulfilledPromise(): void
  348. {
  349. $adapter = $this->getPromiseTestAdapter();
  350. $exception = new Exception();
  351. $mock = $this->createCallableMock();
  352. $mock
  353. ->expects($this->once())
  354. ->method('__invoke')
  355. ->with($this->identicalTo($exception));
  356. $adapter->resolve(1);
  357. $adapter->promise()
  358. ->always(function () use ($exception) {
  359. throw $exception;
  360. })
  361. ->then(null, $mock);
  362. }
  363. /**
  364. * @test
  365. * @deprecated
  366. */
  367. public function alwaysShouldRejectWhenHandlerRejectsForFulfilledPromise(): void
  368. {
  369. $adapter = $this->getPromiseTestAdapter();
  370. $exception = new Exception();
  371. $mock = $this->createCallableMock();
  372. $mock
  373. ->expects($this->once())
  374. ->method('__invoke')
  375. ->with($this->identicalTo($exception));
  376. $adapter->resolve(1);
  377. $adapter->promise()
  378. ->always(function () use ($exception) {
  379. return reject($exception);
  380. })
  381. ->then(null, $mock);
  382. }
  383. }