PluginProbe
StockPack – Stock photos and AI images from Unsplash, Adobe Stock, Freepik and more / 2.6.1
StockPack – Stock photos and AI images from Unsplash, Adobe Stock, Freepik and more v2.6.1
3.7.2 3.7.1 3.7.0 3.6.0 3.6.1 3.5.2 trunk 2.0 2.1 2.2 2.3 2.4 2.4.1 2.4.2 2.4.3 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.6.0 2.6.1 All 73 releases
stockpack / vendor / guzzlehttp / promises / tests / functionsTest.php

functionsTest.php in StockPack – Stock photos and AI images from Unsplash, Adobe Stock, Freepik and more 2.6.1, at vendor/guzzlehttp/promises/tests/functionsTest.php

717 lines 22.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace GuzzleHttp\Promise\Tests;
3
4 use GuzzleHttp\Promise as P;
5 use GuzzleHttp\Promise\AggregateException;
6 use GuzzleHttp\Promise\FulfilledPromise;
7 use GuzzleHttp\Promise\Promise;
8 use GuzzleHttp\Promise\PromiseInterface;
9 use GuzzleHttp\Promise\RejectedPromise;
10 use GuzzleHttp\Promise\RejectionException;
11 use GuzzleHttp\Promise\TaskQueue;
12 use PHPUnit\Framework\TestCase;
13
14 class FunctionsTest extends TestCase
15 {
16 public function testCreatesPromiseForValue()
17 {
18 $p = P\promise_for('foo');
19 $this->assertInstanceOf(FulfilledPromise::class, $p);
20 }
21
22 public function testReturnsPromiseForPromise()
23 {
24 $p = new Promise();
25 $this->assertSame($p, P\promise_for($p));
26 }
27
28 public function testReturnsPromiseForThennable()
29 {
30 $p = new Thennable();
31 $wrapped = P\promise_for($p);
32 $this->assertNotSame($p, $wrapped);
33 $this->assertInstanceOf(PromiseInterface::class, $wrapped);
34 $p->resolve('foo');
35 P\queue()->run();
36 $this->assertEquals('foo', $wrapped->wait());
37 }
38
39 public function testReturnsRejection()
40 {
41 $p = P\rejection_for('fail');
42 $this->assertInstanceOf(RejectedPromise::class, $p);
43 $this->assertEquals('fail', $this->readAttribute($p, 'reason'));
44 }
45
46 public function testReturnsPromisesAsIsInRejectionFor()
47 {
48 $a = new Promise();
49 $b = P\rejection_for($a);
50 $this->assertSame($a, $b);
51 }
52
53 public function testWaitsOnAllPromisesIntoArray()
54 {
55 $e = new \Exception();
56 $a = new Promise(function () use (&$a) { $a->resolve('a'); });
57 $b = new Promise(function () use (&$b) { $b->reject('b'); });
58 $c = new Promise(function () use (&$c, $e) { $c->reject($e); });
59 $results = P\inspect_all([$a, $b, $c]);
60 $this->assertEquals([
61 ['state' => 'fulfilled', 'value' => 'a'],
62 ['state' => 'rejected', 'reason' => 'b'],
63 ['state' => 'rejected', 'reason' => $e]
64 ], $results);
65 }
66
67 /**
68 * @expectedException \GuzzleHttp\Promise\RejectionException
69 */
70 public function testUnwrapsPromisesWithNoDefaultAndFailure()
71 {
72 $promises = [new FulfilledPromise('a'), new Promise()];
73 P\unwrap($promises);
74 }
75
76 public function testUnwrapsPromisesWithNoDefault()
77 {
78 $promises = [new FulfilledPromise('a')];
79 $this->assertEquals(['a'], P\unwrap($promises));
80 }
81
82 public function testUnwrapsPromisesWithKeys()
83 {
84 $promises = [
85 'foo' => new FulfilledPromise('a'),
86 'bar' => new FulfilledPromise('b'),
87 ];
88 $this->assertEquals([
89 'foo' => 'a',
90 'bar' => 'b'
91 ], P\unwrap($promises));
92 }
93
94 public function testAllAggregatesSortedArray()
95 {
96 $a = new Promise();
97 $b = new Promise();
98 $c = new Promise();
99 $d = P\all([$a, $b, $c]);
100 $b->resolve('b');
101 $a->resolve('a');
102 $c->resolve('c');
103 $d->then(
104 function ($value) use (&$result) { $result = $value; },
105 function ($reason) use (&$result) { $result = $reason; }
106 );
107 P\queue()->run();
108 $this->assertEquals(['a', 'b', 'c'], $result);
109 }
110
111 public function testPromisesDynamicallyAddedToStack()
112 {
113 $promises = new \ArrayIterator();
114 $counter = 0;
115 $promises['a'] = new FulfilledPromise('a');
116 $promises['b'] = $promise = new Promise(function () use (&$promise, &$promises, &$counter) {
117 $counter++; // Make sure the wait function is called only once
118 $promise->resolve('b');
119 $promises['c'] = $subPromise = new Promise(function () use (&$subPromise) {
120 $subPromise->resolve('c');
121 });
122 });
123 $result = P\all($promises, true)->wait();
124 $this->assertCount(3, $promises);
125 $this->assertCount(3, $result);
126 $this->assertEquals($result['c'], 'c');
127 $this->assertSame(1, $counter);
128 }
129
130 public function testAllThrowsWhenAnyRejected()
131 {
132 $a = new Promise();
133 $b = new Promise();
134 $c = new Promise();
135 $d = P\all([$a, $b, $c]);
136 $b->resolve('b');
137 $a->reject('fail');
138 $c->resolve('c');
139 $d->then(
140 function ($value) use (&$result) { $result = $value; },
141 function ($reason) use (&$result) { $result = $reason; }
142 );
143 P\queue()->run();
144 $this->assertEquals('fail', $result);
145 }
146
147 public function testSomeAggregatesSortedArrayWithMax()
148 {
149 $a = new Promise();
150 $b = new Promise();
151 $c = new Promise();
152 $d = P\some(2, [$a, $b, $c]);
153 $b->resolve('b');
154 $c->resolve('c');
155 $a->resolve('a');
156 $d->then(function ($value) use (&$result) { $result = $value; });
157 P\queue()->run();
158 $this->assertEquals(['b', 'c'], $result);
159 }
160
161 public function testSomeRejectsWhenTooManyRejections()
162 {
163 $a = new Promise();
164 $b = new Promise();
165 $d = P\some(2, [$a, $b]);
166 $a->reject('bad');
167 $b->resolve('good');
168 P\queue()->run();
169 $this->assertEquals($a::REJECTED, $d->getState());
170 $d->then(null, function ($reason) use (&$called) {
171 $called = $reason;
172 });
173 P\queue()->run();
174 $this->assertInstanceOf(AggregateException::class, $called);
175 $this->assertContains('bad', $called->getReason());
176 }
177
178 public function testCanWaitUntilSomeCountIsSatisfied()
179 {
180 $a = new Promise(function () use (&$a) { $a->resolve('a'); });
181 $b = new Promise(function () use (&$b) { $b->resolve('b'); });
182 $c = new Promise(function () use (&$c) { $c->resolve('c'); });
183 $d = P\some(2, [$a, $b, $c]);
184 $this->assertEquals(['a', 'b'], $d->wait());
185 }
186
187 /**
188 * @expectedException \GuzzleHttp\Promise\AggregateException
189 * @expectedExceptionMessage Not enough promises to fulfill count
190 */
191 public function testThrowsIfImpossibleToWaitForSomeCount()
192 {
193 $a = new Promise(function () use (&$a) { $a->resolve('a'); });
194 $d = P\some(2, [$a]);
195 $d->wait();
196 }
197
198 /**
199 * @expectedException \GuzzleHttp\Promise\AggregateException
200 * @expectedExceptionMessage Not enough promises to fulfill count
201 */
202 public function testThrowsIfResolvedWithoutCountTotalResults()
203 {
204 $a = new Promise();
205 $b = new Promise();
206 $d = P\some(3, [$a, $b]);
207 $a->resolve('a');
208 $b->resolve('b');
209 $d->wait();
210 }
211
212 public function testAnyReturnsFirstMatch()
213 {
214 $a = new Promise();
215 $b = new Promise();
216 $c = P\any([$a, $b]);
217 $b->resolve('b');
218 $a->resolve('a');
219 //P\queue()->run();
220 //$this->assertEquals('fulfilled', $c->getState());
221 $c->then(function ($value) use (&$result) { $result = $value; });
222 P\queue()->run();
223 $this->assertEquals('b', $result);
224 }
225
226 public function testSettleFulfillsWithFulfilledAndRejected()
227 {
228 $a = new Promise();
229 $b = new Promise();
230 $c = new Promise();
231 $d = P\settle([$a, $b, $c]);
232 $b->resolve('b');
233 $c->resolve('c');
234 $a->reject('a');
235 P\queue()->run();
236 $this->assertEquals('fulfilled', $d->getState());
237 $d->then(function ($value) use (&$result) { $result = $value; });
238 P\queue()->run();
239 $this->assertEquals([
240 ['state' => 'rejected', 'reason' => 'a'],
241 ['state' => 'fulfilled', 'value' => 'b'],
242 ['state' => 'fulfilled', 'value' => 'c']
243 ], $result);
244 }
245
246 public function testCanInspectFulfilledPromise()
247 {
248 $p = new FulfilledPromise('foo');
249 $this->assertEquals([
250 'state' => 'fulfilled',
251 'value' => 'foo'
252 ], P\inspect($p));
253 }
254
255 public function testCanInspectRejectedPromise()
256 {
257 $p = new RejectedPromise('foo');
258 $this->assertEquals([
259 'state' => 'rejected',
260 'reason' => 'foo'
261 ], P\inspect($p));
262 }
263
264 public function testCanInspectRejectedPromiseWithNormalException()
265 {
266 $e = new \Exception('foo');
267 $p = new RejectedPromise($e);
268 $this->assertEquals([
269 'state' => 'rejected',
270 'reason' => $e
271 ], P\inspect($p));
272 }
273
274 public function testCallsEachLimit()
275 {
276 $p = new Promise();
277 $aggregate = P\each_limit($p, 2);
278 $p->resolve('a');
279 P\queue()->run();
280 $this->assertEquals($p::FULFILLED, $aggregate->getState());
281 }
282
283 public function testEachLimitAllRejectsOnFailure()
284 {
285 $p = [new FulfilledPromise('a'), new RejectedPromise('b')];
286 $aggregate = P\each_limit_all($p, 2);
287 P\queue()->run();
288 $this->assertEquals(PromiseInterface::REJECTED, $aggregate->getState());
289 $result = P\inspect($aggregate);
290 $this->assertEquals('b', $result['reason']);
291 }
292
293 public function testIterForReturnsIterator()
294 {
295 $iter = new \ArrayIterator();
296 $this->assertSame($iter, P\iter_for($iter));
297 }
298
299 public function testKnowsIfFulfilled()
300 {
301 $p = new FulfilledPromise(null);
302 $this->assertTrue(P\is_fulfilled($p));
303 $this->assertFalse(P\is_rejected($p));
304 }
305
306 public function testKnowsIfRejected()
307 {
308 $p = new RejectedPromise(null);
309 $this->assertTrue(P\is_rejected($p));
310 $this->assertFalse(P\is_fulfilled($p));
311 }
312
313 public function testKnowsIfSettled()
314 {
315 $p = new RejectedPromise(null);
316 $this->assertTrue(P\is_settled($p));
317 $p = new Promise();
318 $this->assertFalse(P\is_settled($p));
319 }
320
321 public function testReturnsTrampoline()
322 {
323 $this->assertInstanceOf(TaskQueue::class, P\queue());
324 $this->assertSame(P\queue(), P\queue());
325 }
326
327 public function testCanScheduleThunk()
328 {
329 $tramp = P\queue();
330 $promise = P\task(function () { return 'Hi!'; });
331 $c = null;
332 $promise->then(function ($v) use (&$c) { $c = $v; });
333 $this->assertNull($c);
334 $tramp->run();
335 $this->assertEquals('Hi!', $c);
336 }
337
338 public function testCanScheduleThunkWithRejection()
339 {
340 $tramp = P\queue();
341 $promise = P\task(function () { throw new \Exception('Hi!'); });
342 $c = null;
343 $promise->otherwise(function ($v) use (&$c) { $c = $v; });
344 $this->assertNull($c);
345 $tramp->run();
346 $this->assertEquals('Hi!', $c->getMessage());
347 }
348
349 public function testCanScheduleThunkWithWait()
350 {
351 $tramp = P\queue();
352 $promise = P\task(function () { return 'a'; });
353 $this->assertEquals('a', $promise->wait());
354 $tramp->run();
355 }
356
357 public function testYieldsFromCoroutine()
358 {
359 $promise = P\coroutine(function () {
360 $value = (yield new FulfilledPromise('a'));
361 yield $value . 'b';
362 });
363 $promise->then(function ($value) use (&$result) { $result = $value; });
364 P\queue()->run();
365 $this->assertEquals('ab', $result);
366 }
367
368 public function testCanCatchExceptionsInCoroutine()
369 {
370 $promise = P\coroutine(function () {
371 try {
372 yield new RejectedPromise('a');
373 $this->fail('Should have thrown into the coroutine!');
374 } catch (RejectionException $e) {
375 $value = (yield new FulfilledPromise($e->getReason()));
376 yield $value . 'b';
377 }
378 });
379 $promise->then(function ($value) use (&$result) { $result = $value; });
380 P\queue()->run();
381 $this->assertEquals(PromiseInterface::FULFILLED, $promise->getState());
382 $this->assertEquals('ab', $result);
383 }
384
385 public function testRejectsParentExceptionWhenException()
386 {
387 $promise = P\coroutine(function () {
388 yield new FulfilledPromise(0);
389 throw new \Exception('a');
390 });
391 $promise->then(
392 function () { $this->fail(); },
393 function ($reason) use (&$result) { $result = $reason; }
394 );
395 P\queue()->run();
396 $this->assertInstanceOf(\Exception::class, $result);
397 $this->assertEquals('a', $result->getMessage());
398 }
399
400 public function testCanRejectFromRejectionCallback()
401 {
402 $promise = P\coroutine(function () {
403 yield new FulfilledPromise(0);
404 yield new RejectedPromise('no!');
405 });
406 $promise->then(
407 function () { $this->fail(); },
408 function ($reason) use (&$result) { $result = $reason; }
409 );
410 P\queue()->run();
411 $this->assertInstanceOf(RejectionException::class, $result);
412 $this->assertEquals('no!', $result->getReason());
413 }
414
415 public function testCanAsyncReject()
416 {
417 $rej = new Promise();
418 $promise = P\coroutine(function () use ($rej) {
419 yield new FulfilledPromise(0);
420 yield $rej;
421 });
422 $promise->then(
423 function () { $this->fail(); },
424 function ($reason) use (&$result) { $result = $reason; }
425 );
426 $rej->reject('no!');
427 P\queue()->run();
428 $this->assertInstanceOf(RejectionException::class, $result);
429 $this->assertEquals('no!', $result->getReason());
430 }
431
432 public function testCanCatchAndThrowOtherException()
433 {
434 $promise = P\coroutine(function () {
435 try {
436 yield new RejectedPromise('a');
437 $this->fail('Should have thrown into the coroutine!');
438 } catch (RejectionException $e) {
439 throw new \Exception('foo');
440 }
441 });
442 $promise->otherwise(function ($value) use (&$result) { $result = $value; });
443 P\queue()->run();
444 $this->assertEquals(PromiseInterface::REJECTED, $promise->getState());
445 $this->assertContains('foo', $result->getMessage());
446 }
447
448 public function testCanCatchAndYieldOtherException()
449 {
450 $promise = P\coroutine(function () {
451 try {
452 yield new RejectedPromise('a');
453 $this->fail('Should have thrown into the coroutine!');
454 } catch (RejectionException $e) {
455 yield new RejectedPromise('foo');
456 }
457 });
458 $promise->otherwise(function ($value) use (&$result) { $result = $value; });
459 P\queue()->run();
460 $this->assertEquals(PromiseInterface::REJECTED, $promise->getState());
461 $this->assertContains('foo', $result->getMessage());
462 }
463
464 public function createLotsOfSynchronousPromise()
465 {
466 return P\coroutine(function () {
467 $value = 0;
468 for ($i = 0; $i < 1000; $i++) {
469 $value = (yield new FulfilledPromise($i));
470 }
471 yield $value;
472 });
473 }
474
475 public function testLotsOfSynchronousDoesNotBlowStack()
476 {
477 $promise = $this->createLotsOfSynchronousPromise();
478 $promise->then(function ($v) use (&$r) { $r = $v; });
479 P\queue()->run();
480 $this->assertEquals(999, $r);
481 }
482
483 public function testLotsOfSynchronousWaitDoesNotBlowStack()
484 {
485 $promise = $this->createLotsOfSynchronousPromise();
486 $promise->then(function ($v) use (&$r) { $r = $v; });
487 $this->assertEquals(999, $promise->wait());
488 $this->assertEquals(999, $r);
489 }
490
491 private function createLotsOfFlappingPromise()
492 {
493 return P\coroutine(function () {
494 $value = 0;
495 for ($i = 0; $i < 1000; $i++) {
496 try {
497 if ($i % 2) {
498 $value = (yield new FulfilledPromise($i));
499 } else {
500 $value = (yield new RejectedPromise($i));
501 }
502 } catch (\Exception $e) {
503 $value = (yield new FulfilledPromise($i));
504 }
505 }
506 yield $value;
507 });
508 }
509
510 public function testLotsOfTryCatchingDoesNotBlowStack()
511 {
512 $promise = $this->createLotsOfFlappingPromise();
513 $promise->then(function ($v) use (&$r) { $r = $v; });
514 P\queue()->run();
515 $this->assertEquals(999, $r);
516 }
517
518 public function testLotsOfTryCatchingWaitingDoesNotBlowStack()
519 {
520 $promise = $this->createLotsOfFlappingPromise();
521 $promise->then(function ($v) use (&$r) { $r = $v; });
522 $this->assertEquals(999, $promise->wait());
523 $this->assertEquals(999, $r);
524 }
525
526 public function testAsyncPromisesWithCorrectlyYieldedValues()
527 {
528 $promises = [
529 new Promise(),
530 new Promise(),
531 new Promise()
532 ];
533
534 $promise = P\coroutine(function () use ($promises) {
535 $this->assertEquals('skip', (yield new FulfilledPromise('skip')));
536 foreach ($promises as $idx => $p) {
537 $this->assertEquals($idx, (yield $p));
538 $this->assertEquals('skip', (yield new FulfilledPromise('skip')));
539 }
540 $this->assertEquals('skip', (yield new FulfilledPromise('skip')));
541 yield 2;
542 });
543
544 $promises[0]->resolve(0);
545 $promises[1]->resolve(1);
546 $promises[2]->resolve(2);
547
548 $promise->then(function ($v) use (&$r) { $r = $v; });
549 P\queue()->run();
550 $this->assertEquals(2, $r);
551 }
552
553 public function testYieldFinalWaitablePromise()
554 {
555 $p1 = new Promise(function () use (&$p1) {
556 $p1->resolve('skip me');
557 });
558 $p2 = new Promise(function () use (&$p2) {
559 $p2->resolve('hello!');
560 });
561 $co = P\coroutine(function() use ($p1, $p2) {
562 yield $p1;
563 yield $p2;
564 });
565 P\queue()->run();
566 $this->assertEquals('hello!', $co->wait());
567 }
568
569 public function testCanYieldFinalPendingPromise()
570 {
571 $p1 = new Promise();
572 $p2 = new Promise();
573 $co = P\coroutine(function() use ($p1, $p2) {
574 yield $p1;
575 yield $p2;
576 });
577 $p1->resolve('a');
578 $p2->resolve('b');
579 $co->then(function ($value) use (&$result) { $result = $value; });
580 P\queue()->run();
581 $this->assertEquals('b', $result);
582 }
583
584 public function testCanNestYieldsAndFailures()
585 {
586 $p1 = new Promise();
587 $p2 = new Promise();
588 $p3 = new Promise();
589 $p4 = new Promise();
590 $p5 = new Promise();
591 $co = P\coroutine(function() use ($p1, $p2, $p3, $p4, $p5) {
592 try {
593 yield $p1;
594 } catch (\Exception $e) {
595 yield $p2;
596 try {
597 yield $p3;
598 yield $p4;
599 } catch (\Exception $e) {
600 yield $p5;
601 }
602 }
603 });
604 $p1->reject('a');
605 $p2->resolve('b');
606 $p3->resolve('c');
607 $p4->reject('d');
608 $p5->resolve('e');
609 $co->then(function ($value) use (&$result) { $result = $value; });
610 P\queue()->run();
611 $this->assertEquals('e', $result);
612 }
613
614 public function testCanYieldErrorsAndSuccessesWithoutRecursion()
615 {
616 $promises = [];
617 for ($i = 0; $i < 20; $i++) {
618 $promises[] = new Promise();
619 }
620
621 $co = P\coroutine(function() use ($promises) {
622 for ($i = 0; $i < 20; $i += 4) {
623 try {
624 yield $promises[$i];
625 yield $promises[$i + 1];
626 } catch (\Exception $e) {
627 yield $promises[$i + 2];
628 yield $promises[$i + 3];
629 }
630 }
631 });
632
633 for ($i = 0; $i < 20; $i += 4) {
634 $promises[$i]->resolve($i);
635 $promises[$i + 1]->reject($i + 1);
636 $promises[$i + 2]->resolve($i + 2);
637 $promises[$i + 3]->resolve($i + 3);
638 }
639
640 $co->then(function ($value) use (&$result) { $result = $value; });
641 P\queue()->run();
642 $this->assertEquals('19', $result);
643 }
644
645 public function testCanWaitOnPromiseAfterFulfilled()
646 {
647 $f = function () {
648 static $i = 0;
649 $i++;
650 return $p = new Promise(function () use (&$p, $i) {
651 $p->resolve($i . '-bar');
652 });
653 };
654
655 $promises = [];
656 for ($i = 0; $i < 20; $i++) {
657 $promises[] = $f();
658 }
659
660 $p = P\coroutine(function () use ($promises) {
661 yield new FulfilledPromise('foo!');
662 foreach ($promises as $promise) {
663 yield $promise;
664 }
665 });
666
667 $this->assertEquals('20-bar', $p->wait());
668 }
669
670 public function testCanWaitOnErroredPromises()
671 {
672 $p1 = new Promise(function () use (&$p1) { $p1->reject('a'); });
673 $p2 = new Promise(function () use (&$p2) { $p2->resolve('b'); });
674 $p3 = new Promise(function () use (&$p3) { $p3->resolve('c'); });
675 $p4 = new Promise(function () use (&$p4) { $p4->reject('d'); });
676 $p5 = new Promise(function () use (&$p5) { $p5->resolve('e'); });
677 $p6 = new Promise(function () use (&$p6) { $p6->reject('f'); });
678
679 $co = P\coroutine(function() use ($p1, $p2, $p3, $p4, $p5, $p6) {
680 try {
681 yield $p1;
682 } catch (\Exception $e) {
683 yield $p2;
684 try {
685 yield $p3;
686 yield $p4;
687 } catch (\Exception $e) {
688 yield $p5;
689 yield $p6;
690 }
691 }
692 });
693
694 $res = P\inspect($co);
695 $this->assertEquals('f', $res['reason']);
696 }
697
698 public function testCoroutineOtherwiseIntegrationTest()
699 {
700 $a = new Promise();
701 $b = new Promise();
702 $promise = P\coroutine(function () use ($a, $b) {
703 // Execute the pool of commands concurrently, and process errors.
704 yield $a;
705 yield $b;
706 })->otherwise(function (\Exception $e) {
707 // Throw errors from the operations as a specific Multipart error.
708 throw new \OutOfBoundsException('a', 0, $e);
709 });
710 $a->resolve('a');
711 $b->reject('b');
712 $reason = P\inspect($promise)['reason'];
713 $this->assertInstanceOf(\OutOfBoundsException::class, $reason);
714 $this->assertInstanceOf(RejectionException::class, $reason->getPrevious());
715 }
716 }
717