mirror of
https://github.com/danog/endtoend-test-psl.git
synced 2025-01-21 04:47:48 +01:00
[Result] Add proceed and map with helper functions (#65)
This commit is contained in:
parent
ed0cae6421
commit
fbc60c93bb
18
src/Psl/Fun/passthrough.php
Normal file
18
src/Psl/Fun/passthrough.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Psl\Fun;
|
||||
|
||||
/**
|
||||
* This method creates a callback that returns the value passed as argument.
|
||||
* It can e.g. be used as a success callback.
|
||||
*
|
||||
* @template T
|
||||
* @psalm-return callable(T): T
|
||||
* @psalm-pure
|
||||
*/
|
||||
function passthrough(): callable
|
||||
{
|
||||
return static fn ($result) => $result;
|
||||
}
|
21
src/Psl/Fun/rethrow.php
Normal file
21
src/Psl/Fun/rethrow.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Psl\Fun;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* This method creates a callback that throws the exception passed as argument.
|
||||
* It can e.g. be used as a failure callback.
|
||||
*
|
||||
* @psalm-return callable(Exception): no-return
|
||||
* @psalm-pure
|
||||
*/
|
||||
function rethrow(): callable
|
||||
{
|
||||
return static function (Exception $exception): void {
|
||||
throw $exception;
|
||||
};
|
||||
}
|
@ -96,7 +96,9 @@ final class Loader
|
||||
'Psl\Arr\map_keys',
|
||||
'Psl\Arr\map_with_key',
|
||||
'Psl\Fun\after',
|
||||
'Psl\Fun\passthrough',
|
||||
'Psl\Fun\pipe',
|
||||
'Psl\Fun\rethrow',
|
||||
'Psl\Internal\boolean',
|
||||
'Psl\Internal\type',
|
||||
'Psl\Internal\validate_offset',
|
||||
|
@ -65,4 +65,25 @@ final class Failure implements ResultInterface
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwrapping and transforming a result can be done by using the proceed method.
|
||||
* Since this is a failed result wrapper, the `$on_failure` callback will be triggered.
|
||||
* The callback will receive the Exception as an argument, so that you can transform it to anything you want.
|
||||
*/
|
||||
public function proceed(callable $on_success, callable $on_failure)
|
||||
{
|
||||
return $on_failure($this->exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* The method can be used to transform a result into another result.
|
||||
* Since this is a failure result wrapper, the `$on_failure` callback will be triggered.
|
||||
* The callback will receive the Exception as an argument,
|
||||
* so that you can use it to create a success result or rethrow the Exception.
|
||||
*/
|
||||
public function then(callable $on_success, callable $on_failure): ResultInterface
|
||||
{
|
||||
return wrap(fn () => $on_failure($this->exception));
|
||||
}
|
||||
}
|
||||
|
@ -55,4 +55,38 @@ interface ResultInterface
|
||||
* @return bool - `true` if the operation failed; `false` otherwise
|
||||
*/
|
||||
public function isFailed(): bool;
|
||||
|
||||
/**
|
||||
* Unwrapping and transforming a result can be done by using the proceed method.
|
||||
* The implementation will either run the `$on_success` or `$on_failure` callback.
|
||||
* The callback will receive the result or Exception as an argument,
|
||||
* so that you can transform it to anything you want.
|
||||
*
|
||||
* @template R
|
||||
*
|
||||
* @psalm-param callable(T): R $on_success
|
||||
* @psalm-param callable(Exception): R $on_failure
|
||||
*
|
||||
* @psalm-return R
|
||||
*/
|
||||
public function proceed(callable $on_success, callable $on_failure);
|
||||
|
||||
/**
|
||||
* The method can be used to transform a result into another result.
|
||||
* The implementation will either run the `$on_success` or `$on_failure` callback.
|
||||
* The callback will receive the result value or Exception as an argument,
|
||||
* so that you can transform use it to build a new result.
|
||||
*
|
||||
* This method is compatible with the `PromiseInterface::then()` function from `reactphp/promise`.
|
||||
* You can use it in an async context as long as the package you are using is compatible with reactphp promises.
|
||||
*
|
||||
* @link https://github.com/reactphp/promise#promiseinterfacethen
|
||||
*
|
||||
* @template R
|
||||
* @psalm-param callable(T): R $on_success
|
||||
* @psalm-param callable(Exception): R $on_failure
|
||||
*
|
||||
* @psalm-return ResultInterface<R>
|
||||
*/
|
||||
public function then(callable $on_success, callable $on_failure): ResultInterface;
|
||||
}
|
||||
|
@ -73,4 +73,24 @@ final class Success implements ResultInterface
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwrapping and transforming a result can be done by using the proceed method.
|
||||
* Since this is a success result wrapper, the `$on_success` callback will be triggered.
|
||||
* The callback will receive the result value as an argument, so that you can transform it to anything you want.
|
||||
*/
|
||||
public function proceed(callable $on_success, callable $on_failure)
|
||||
{
|
||||
return $on_success($this->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The method can be used to transform a result into another result.
|
||||
* Since this is a success result wrapper, the `$on_success` callback will be triggered.
|
||||
* The callback will receive the result value as an argument, so that you can use it to create a new result.
|
||||
*/
|
||||
public function then(callable $on_success, callable $on_failure): ResultInterface
|
||||
{
|
||||
return wrap(fn () => $on_success($this->value));
|
||||
}
|
||||
}
|
||||
|
19
tests/Psl/Fun/PassthroughTest.php
Normal file
19
tests/Psl/Fun/PassthroughTest.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Psl\Tests\Fun;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psl\Fun;
|
||||
|
||||
class PassthroughTest extends TestCase
|
||||
{
|
||||
public function testPassthrough(): void
|
||||
{
|
||||
$expected = 'x';
|
||||
$passthrough = Fun\passthrough();
|
||||
|
||||
self::assertSame($expected, $passthrough($expected));
|
||||
}
|
||||
}
|
20
tests/Psl/Fun/RethrowTest.php
Normal file
20
tests/Psl/Fun/RethrowTest.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Psl\Tests\Fun;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psl\Fun;
|
||||
|
||||
class RethrowTest extends TestCase
|
||||
{
|
||||
public function testRethrow(): void
|
||||
{
|
||||
$exception = new \Exception('foo');
|
||||
$rethrow = Fun\rethrow();
|
||||
|
||||
$this->expectExceptionObject($exception);
|
||||
$rethrow($exception);
|
||||
}
|
||||
}
|
@ -4,26 +4,29 @@ declare(strict_types=1);
|
||||
|
||||
namespace Psl\Tests\Result;
|
||||
|
||||
use Exception;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psl\Fun;
|
||||
use Psl\Result\Failure;
|
||||
use stdClass;
|
||||
|
||||
class FailureTest extends TestCase
|
||||
{
|
||||
public function testIsSucceeded(): void
|
||||
{
|
||||
$wrapper = new Failure(new \Exception('foo'));
|
||||
$wrapper = new Failure(new Exception('foo'));
|
||||
self::assertFalse($wrapper->isSucceeded());
|
||||
}
|
||||
|
||||
public function testIsFailed(): void
|
||||
{
|
||||
$wrapper = new Failure(new \Exception('foo'));
|
||||
$wrapper = new Failure(new Exception('foo'));
|
||||
self::assertTrue($wrapper->isFailed());
|
||||
}
|
||||
|
||||
public function testGetResult(): void
|
||||
{
|
||||
$exception = new \Exception('bar');
|
||||
$exception = new Exception('bar');
|
||||
$wrapper = new Failure($exception);
|
||||
|
||||
$this->expectExceptionObject($exception);
|
||||
@ -32,9 +35,51 @@ class FailureTest extends TestCase
|
||||
|
||||
public function testGetException(): void
|
||||
{
|
||||
$exception = new \Exception('bar');
|
||||
$exception = new Exception('bar');
|
||||
$wrapper = new Failure($exception);
|
||||
$e = $wrapper->getException();
|
||||
self::assertSame($exception, $e);
|
||||
}
|
||||
|
||||
public function testProceed(): void
|
||||
{
|
||||
$exception = new Exception('bar');
|
||||
$wrapper = new Failure($exception);
|
||||
$actual = $wrapper->proceed(
|
||||
static fn (string $result): int => 200,
|
||||
static fn (Exception $exception): int => 404
|
||||
);
|
||||
|
||||
self::assertSame(404, $actual);
|
||||
}
|
||||
|
||||
public function testThenToSuccess(): void
|
||||
{
|
||||
$exception = new Exception('bar');
|
||||
$wrapper = new Failure($exception);
|
||||
$actual = $wrapper->then(
|
||||
static function () {
|
||||
throw new \Exception('Dont call us, we\'ll call you!');
|
||||
},
|
||||
static fn (Exception $exception): string => $exception->getMessage()
|
||||
);
|
||||
|
||||
self::assertTrue($actual->isSucceeded());
|
||||
self::assertSame($actual->getResult(), 'bar');
|
||||
}
|
||||
|
||||
public function testThenToFailure(): void
|
||||
{
|
||||
$exception = new Exception('bar');
|
||||
$wrapper = new Failure($exception);
|
||||
$actual = $wrapper->then(
|
||||
static function () {
|
||||
throw new \Exception('Dont call us, we\'ll call you!');
|
||||
},
|
||||
Fun\rethrow()
|
||||
);
|
||||
|
||||
self::assertFalse($actual->isSucceeded());
|
||||
self::assertSame($actual->getException(), $exception);
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace Psl\Tests\Result;
|
||||
|
||||
use Exception;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psl\Fun;
|
||||
use Psl\Result\Success;
|
||||
use Psl\Exception\InvariantViolationException;
|
||||
use stdClass;
|
||||
|
||||
class SuccessTest extends TestCase
|
||||
{
|
||||
@ -37,4 +40,43 @@ class SuccessTest extends TestCase
|
||||
|
||||
$wrapper->getException();
|
||||
}
|
||||
|
||||
public function testProceed(): void
|
||||
{
|
||||
$wrapper = new Success('hello');
|
||||
$actual = $wrapper->proceed(
|
||||
static fn (string $result): int => 200,
|
||||
static fn (Exception $exception): int => 404
|
||||
);
|
||||
|
||||
self::assertSame(200, $actual);
|
||||
}
|
||||
|
||||
public function testThenToSuccess(): void
|
||||
{
|
||||
$wrapper = new Success('hello');
|
||||
$actual = $wrapper->then(
|
||||
Fun\passthrough(),
|
||||
Fun\rethrow()
|
||||
);
|
||||
|
||||
self::assertNotSame($wrapper, $actual);
|
||||
self::assertTrue($actual->isSucceeded());
|
||||
self::assertSame('hello', $actual->getResult());
|
||||
}
|
||||
|
||||
public function testThenToFailure(): void
|
||||
{
|
||||
$exception = new Exception('bar');
|
||||
$wrapper = new Success('hello');
|
||||
$actual = $wrapper->then(
|
||||
static function () use ($exception) {
|
||||
throw $exception;
|
||||
},
|
||||
Fun\rethrow()
|
||||
);
|
||||
|
||||
self::assertFalse($actual->isSucceeded());
|
||||
self::assertSame($actual->getException(), $exception);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user