diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 8cecea8..64db5f7 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -29,7 +29,6 @@ 'increment_style' => ['style' => 'pre'], 'single_quote' => true, 'trim_array_spaces' => true, - 'single_blank_line_before_namespace' => true, 'yoda_style' => false, 'global_namespace_import' => [ 'import_classes' => false, diff --git a/composer.json b/composer.json index cb37fbc..5b18fbb 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.2", - "phpstan/phpstan": "^0.12.69", + "phpstan/phpstan": "^1.10", "phpunit/phpunit": "^9.5" }, "autoload": { diff --git a/src/Await.php b/src/Await.php index 71443f1..8abac46 100644 --- a/src/Await.php +++ b/src/Await.php @@ -48,4 +48,27 @@ public function until(callable $condition): void } } } + + /** + * @template T + * + * @param callable(): T $closure + * + * @return T + */ + public function on(callable $closure) + { + $start = microtime(true); + while (true) { + usleep($this->pollInterval); + try { + return $closure(); + } catch (\Throwable $throwable) { + } + + if (Duration::seconds(microtime(true) - $start) > $this->waitTime) { + throw new TimeoutException('Closure was not able to return value in the specified wait time'); + } + } + } } diff --git a/tests/AwaitTest.php b/tests/AwaitTest.php index 67fed5d..f9c45b0 100644 --- a/tests/AwaitTest.php +++ b/tests/AwaitTest.php @@ -5,6 +5,7 @@ namespace Akondas\Exspecto\Tests; use function Akondas\Exspecto\await; + use Akondas\Exspecto\Duration; use Akondas\Exspecto\Exception\TimeoutException; use PHPUnit\Framework\TestCase; @@ -37,4 +38,33 @@ public function testAwaitTimeout(): void return false; }); } + + public function testReturnValue(): void + { + $iterations = 5; + $start = microtime(true); + + $value = await()->atMost(1)->pollInterval(10)->on(function () use (&$iterations): string { + if (--$iterations === 0) { + return 'success'; + } + + throw new \RuntimeException('not yet'); + }); + + $duration = Duration::seconds(microtime(true) - $start); + + self::assertSame('success', $value); + self::assertGreaterThanOrEqual(Duration::milliseconds(50), $duration); + self::assertLessThanOrEqual(Duration::milliseconds(60), $duration); + } + + public function testReturnValueTimeout(): void + { + $this->expectException(TimeoutException::class); + + await()->atMost(100, Duration::MILLISECONDS)->pollInterval(30)->on(function (): string { + throw new \RuntimeException('not yet'); + }); + } } diff --git a/tests/DurationTest.php b/tests/DurationTest.php index dc2693b..2844388 100644 --- a/tests/DurationTest.php +++ b/tests/DurationTest.php @@ -11,6 +11,7 @@ class DurationTest extends TestCase { /** * @param int|float $duration + * * @dataProvider durationsProvider */ public function testFromUnit($duration, string $unit, int $expected): void