diff --git a/composer.json b/composer.json index 59ab550..9ae4d63 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,8 @@ "react/promise": "^3.0", "webmozart/assert": "^1.11", "pocketmine/callback-validator": "^1.0", - "respect/stringifier": "^2.0" + "respect/stringifier": "^2.0", + "sof3/await-generator": "^3.6" }, "require-dev": { "friendsofphp/php-cs-fixer": "*", diff --git a/composer.lock b/composer.lock index 5d4b342..af599f9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7b5f4e1266e7d9399e625d908d181825", + "content-hash": "1994377e97761798b10b62742de353e3", "packages": [ { "name": "pocketmine/callback-validator", @@ -187,6 +187,59 @@ }, "time": "2023-04-22T19:23:24+00:00" }, + { + "name": "sof3/await-generator", + "version": "3.6.1", + "source": { + "type": "git", + "url": "https://github.com/SOF3/await-generator.git", + "reference": "90f4dda776eaf9bcb4693599c61c42e4c584a73f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SOF3/await-generator/zipball/90f4dda776eaf9bcb4693599c61c42e4c584a73f", + "reference": "90f4dda776eaf9bcb4693599c61c42e4c584a73f", + "shasum": "" + }, + "require": { + "ext-bcmath": "*", + "php": "^8.0" + }, + "require-dev": { + "composer/package-versions-deprecated": "1.11.99.1", + "infection/infection": "^0.18.2 || ^0.20.2 || ^0.26.0", + "phpstan/phpstan": "^0.12.84", + "phpunit/phpunit": "^9" + }, + "type": "library", + "extra": { + "virion": { + "spec": "3.0", + "namespace-root": "SOFe\\AwaitGenerator" + } + }, + "autoload": { + "psr-0": { + "SOFe\\AwaitGenerator\\": "await-generator/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "apache-2.0" + ], + "authors": [ + { + "name": "SOFe", + "email": "sofe2038@gmail.com" + } + ], + "description": "Use async/await in PHP using generators", + "support": { + "issues": "https://github.com/SOF3/await-generator/issues", + "source": "https://github.com/SOF3/await-generator/tree/3.6.1" + }, + "time": "2023-07-27T09:45:08+00:00" + }, { "name": "webmozart/assert", "version": "1.11.0", diff --git a/src/PmmpUnit.php b/src/PmmpUnit.php index 22f7650..56e191d 100644 --- a/src/PmmpUnit.php +++ b/src/PmmpUnit.php @@ -134,7 +134,7 @@ private function finish(bool $close = true) : void { $this->getLogger()->error("Fatal errors occurred during unit test:"); $i = 0; foreach ($fatalErrors as $error) { - $this->getLogger()->error(++$i . ") " . $error->test->__toString() . ": " . str_replace("§", "&", $error->throwable->getMessage())); + $this->getLogger()->error(++$i . ") " . $error->test->__toString() . ": " . str_replace("§", "&", $error->throwable->getMessage()) . " (line: " . $error->throwable->getLine() . ")"); $this->getLogger()->logException($error->throwable); } } @@ -143,7 +143,7 @@ private function finish(bool $close = true) : void { $this->getLogger()->emergency("Failed tests:"); $i = 0; foreach ($failedTests as $error) { - $this->getLogger()->emergency(++$i . ") " . $error->test->__toString() . ": " . str_replace("§", "&", $error->throwable->getMessage())); + $this->getLogger()->emergency(++$i . ") " . $error->test->__toString() . ": " . str_replace("§", "&", $error->throwable->getMessage()) . " (line: " . $error->throwable->getLine() . ")"); } } diff --git a/src/utils/AwaitGeneratorDecorator.php b/src/utils/AwaitGeneratorDecorator.php new file mode 100644 index 0000000..73c7b62 --- /dev/null +++ b/src/utils/AwaitGeneratorDecorator.php @@ -0,0 +1,63 @@ +delegate = new Deferred(); + + if ($generateGenerator instanceof Closure) { + $type = new CallbackType(new ReturnType('Generator')); + $type->isSatisfiedBy($generateGenerator); + } + + try { + Await::f2c(function () use ($generateGenerator) { + if ($generateGenerator instanceof Closure) { + $generateGenerator = $generateGenerator(); + } + $result = yield from $generateGenerator; + $this->delegate->resolve($result); + }); + } catch (Throwable $e) { + $this->delegate->reject($e); + } + } + + public function then(?callable $onFulfilled = null, ?callable $onRejected = null) : PromiseInterface { + return $this->delegate->promise()->then($onFulfilled, $onRejected); + } + + public function catch(callable $onRejected) : PromiseInterface { + return $this->delegate->promise()->catch($onRejected); + } + + public function finally(callable $onFulfilledOrRejected) : PromiseInterface { + return $this->delegate->promise()->finally($onFulfilledOrRejected); + } + + public function cancel() : void { + $this->delegate->promise()->cancel(); + } + + public function otherwise(callable $onRejected) : PromiseInterface { + return $this->delegate->promise()->otherwise($onRejected); + } + + public function always(callable $onFulfilledOrRejected) : PromiseInterface { + return $this->delegate->promise()->always($onFulfilledOrRejected); + } +} diff --git a/tests/pmmpunit/suitetest/normal/tests/AwaitGeneratorDecoratorTest.php b/tests/pmmpunit/suitetest/normal/tests/AwaitGeneratorDecoratorTest.php new file mode 100644 index 0000000..f793461 --- /dev/null +++ b/tests/pmmpunit/suitetest/normal/tests/AwaitGeneratorDecoratorTest.php @@ -0,0 +1,59 @@ +sleep(); + }); + + return $decorator->then(function () use ($start) : void { + $this->assertTrue(microtime(true) - $start >= 0.9); + }); + } + + public function testGeneratorCallback() : PromiseInterface { + $start = microtime(true); + + $decorator = new AwaitGeneratorDecorator($this->sleep()); + + return $decorator->then(function () use ($start) : void { + $this->assertTrue(microtime(true) - $start >= 0.9); + }); + } + + private function sleep() : Generator { + yield from Await::promise(function ($resolve, $reject) { + $task = new class($resolve, $reject) extends Task { + private $resolve; + private $reject; + + public function __construct($resolve, $reject) { + $this->resolve = $resolve; + $this->reject = $reject; + } + + public function onRun() : void { + ($this->resolve)(); + } + + public function onCancel() : void { + ($this->reject)(new Exception("Task cancelled")); + } + }; + PmmpUnit::getInstance()->getScheduler()->scheduleDelayedTask($task, 20); + }); + } +}