Valinor/tests/Integration/IntegrationTest.php

88 lines
2.1 KiB
PHP
Raw Normal View History

2021-11-28 17:43:02 +01:00
<?php
declare(strict_types=1);
namespace CuyZ\Valinor\Tests\Integration;
use CuyZ\Valinor\Mapper\MappingError;
feat!: add access to root node when error occurs during mapping When an error occurs during mapping, the root instance of `Node` can now be accessed from the exception. This recursive object allows retrieving all needed information through the whole mapping tree: path, values, types and messages, including the issues that caused the exception. It can be used like the following: ```php try { (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map(SomeClass::class, [/* ... */]); } catch (\CuyZ\Valinor\Mapper\MappingError $error) { // Do something with `$error->node()` // See README for more information } ``` This change removes the method `MappingError::describe()` which provided a flattened view of messages of all the errors that were encountered during the mapping. The same behaviour can still be retrieved, see the example below: ```php use CuyZ\Valinor\Mapper\Tree\Message\Message; use CuyZ\Valinor\Mapper\Tree\Node; /** * @implements \IteratorAggregate<string, array<\Throwable&Message>> */ final class MappingErrorList implements \IteratorAggregate { private Node $node; public function __construct(Node $node) { $this->node = $node; } /** * @return \Traversable<string, array<\Throwable&Message>> */ public function getIterator(): \Traversable { yield from $this->errors($this->node); } /** * @return \Traversable<string, array<\Throwable&Message>> */ private function errors(Node $node): \Traversable { $errors = array_filter( $node->messages(), static fn (Message $m) => $m instanceof \Throwable ); if (! empty($errors)) { yield $node->path() => array_values($errors); } foreach ($node->children() as $child) { yield from $this->errors($child); } } } try { (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map(SomeClass::class, [/* ... */]); } catch (\CuyZ\Valinor\Mapper\MappingError $error) { $errors = iterator_to_array(new MappingErrorList($error->node())); } ``` The class `CannotMapObject` is deleted, as it does not provide any value; this means that `MappingError` which was previously an interface becomes a class.
2021-12-16 00:00:45 +01:00
use CuyZ\Valinor\Mapper\Tree\Node;
2021-11-28 17:43:02 +01:00
use CuyZ\Valinor\MapperBuilder;
use FilesystemIterator;
use PHPUnit\Framework\TestCase;
use function implode;
2021-12-28 22:22:42 +01:00
use function is_dir;
feat!: add access to root node when error occurs during mapping When an error occurs during mapping, the root instance of `Node` can now be accessed from the exception. This recursive object allows retrieving all needed information through the whole mapping tree: path, values, types and messages, including the issues that caused the exception. It can be used like the following: ```php try { (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map(SomeClass::class, [/* ... */]); } catch (\CuyZ\Valinor\Mapper\MappingError $error) { // Do something with `$error->node()` // See README for more information } ``` This change removes the method `MappingError::describe()` which provided a flattened view of messages of all the errors that were encountered during the mapping. The same behaviour can still be retrieved, see the example below: ```php use CuyZ\Valinor\Mapper\Tree\Message\Message; use CuyZ\Valinor\Mapper\Tree\Node; /** * @implements \IteratorAggregate<string, array<\Throwable&Message>> */ final class MappingErrorList implements \IteratorAggregate { private Node $node; public function __construct(Node $node) { $this->node = $node; } /** * @return \Traversable<string, array<\Throwable&Message>> */ public function getIterator(): \Traversable { yield from $this->errors($this->node); } /** * @return \Traversable<string, array<\Throwable&Message>> */ private function errors(Node $node): \Traversable { $errors = array_filter( $node->messages(), static fn (Message $m) => $m instanceof \Throwable ); if (! empty($errors)) { yield $node->path() => array_values($errors); } foreach ($node->children() as $child) { yield from $this->errors($child); } } } try { (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map(SomeClass::class, [/* ... */]); } catch (\CuyZ\Valinor\Mapper\MappingError $error) { $errors = iterator_to_array(new MappingErrorList($error->node())); } ``` The class `CannotMapObject` is deleted, as it does not provide any value; this means that `MappingError` which was previously an interface becomes a class.
2021-12-16 00:00:45 +01:00
use function iterator_to_array;
2021-11-28 17:43:02 +01:00
abstract class IntegrationTest extends TestCase
{
protected MapperBuilder $mapperBuilder;
private string $cacheDir;
protected function setUp(): void
{
parent::setUp();
$this->cacheDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'valinor-integration-test' . DIRECTORY_SEPARATOR . uniqid();
$this->mapperBuilder = (new MapperBuilder())->withCacheDir($this->cacheDir);
}
protected function tearDown(): void
{
parent::tearDown();
2021-12-28 22:22:42 +01:00
if (! is_dir($this->cacheDir)) {
return;
}
2021-11-28 17:43:02 +01:00
/** @var FilesystemIterator $file */
foreach (new FilesystemIterator($this->cacheDir) as $file) {
/** @var string $path */
$path = $file->getRealPath();
if ($file->isFile()) {
unlink($path);
}
if ($file->isDir()) {
rmdir($path);
}
2021-11-28 17:43:02 +01:00
}
rmdir($this->cacheDir);
}
/**
* @return never-return
*/
protected function mappingFail(MappingError $error)
{
feat!: add access to root node when error occurs during mapping When an error occurs during mapping, the root instance of `Node` can now be accessed from the exception. This recursive object allows retrieving all needed information through the whole mapping tree: path, values, types and messages, including the issues that caused the exception. It can be used like the following: ```php try { (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map(SomeClass::class, [/* ... */]); } catch (\CuyZ\Valinor\Mapper\MappingError $error) { // Do something with `$error->node()` // See README for more information } ``` This change removes the method `MappingError::describe()` which provided a flattened view of messages of all the errors that were encountered during the mapping. The same behaviour can still be retrieved, see the example below: ```php use CuyZ\Valinor\Mapper\Tree\Message\Message; use CuyZ\Valinor\Mapper\Tree\Node; /** * @implements \IteratorAggregate<string, array<\Throwable&Message>> */ final class MappingErrorList implements \IteratorAggregate { private Node $node; public function __construct(Node $node) { $this->node = $node; } /** * @return \Traversable<string, array<\Throwable&Message>> */ public function getIterator(): \Traversable { yield from $this->errors($this->node); } /** * @return \Traversable<string, array<\Throwable&Message>> */ private function errors(Node $node): \Traversable { $errors = array_filter( $node->messages(), static fn (Message $m) => $m instanceof \Throwable ); if (! empty($errors)) { yield $node->path() => array_values($errors); } foreach ($node->children() as $child) { yield from $this->errors($child); } } } try { (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map(SomeClass::class, [/* ... */]); } catch (\CuyZ\Valinor\Mapper\MappingError $error) { $errors = iterator_to_array(new MappingErrorList($error->node())); } ``` The class `CannotMapObject` is deleted, as it does not provide any value; this means that `MappingError` which was previously an interface becomes a class.
2021-12-16 00:00:45 +01:00
$errorFinder = static function (Node $node, callable $errorFinder) {
if ($node->isValid()) {
return;
}
2021-11-28 17:43:02 +01:00
feat!: add access to root node when error occurs during mapping When an error occurs during mapping, the root instance of `Node` can now be accessed from the exception. This recursive object allows retrieving all needed information through the whole mapping tree: path, values, types and messages, including the issues that caused the exception. It can be used like the following: ```php try { (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map(SomeClass::class, [/* ... */]); } catch (\CuyZ\Valinor\Mapper\MappingError $error) { // Do something with `$error->node()` // See README for more information } ``` This change removes the method `MappingError::describe()` which provided a flattened view of messages of all the errors that were encountered during the mapping. The same behaviour can still be retrieved, see the example below: ```php use CuyZ\Valinor\Mapper\Tree\Message\Message; use CuyZ\Valinor\Mapper\Tree\Node; /** * @implements \IteratorAggregate<string, array<\Throwable&Message>> */ final class MappingErrorList implements \IteratorAggregate { private Node $node; public function __construct(Node $node) { $this->node = $node; } /** * @return \Traversable<string, array<\Throwable&Message>> */ public function getIterator(): \Traversable { yield from $this->errors($this->node); } /** * @return \Traversable<string, array<\Throwable&Message>> */ private function errors(Node $node): \Traversable { $errors = array_filter( $node->messages(), static fn (Message $m) => $m instanceof \Throwable ); if (! empty($errors)) { yield $node->path() => array_values($errors); } foreach ($node->children() as $child) { yield from $this->errors($child); } } } try { (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map(SomeClass::class, [/* ... */]); } catch (\CuyZ\Valinor\Mapper\MappingError $error) { $errors = iterator_to_array(new MappingErrorList($error->node())); } ``` The class `CannotMapObject` is deleted, as it does not provide any value; this means that `MappingError` which was previously an interface becomes a class.
2021-12-16 00:00:45 +01:00
$errors = [];
2021-11-28 17:43:02 +01:00
feat!: add access to root node when error occurs during mapping When an error occurs during mapping, the root instance of `Node` can now be accessed from the exception. This recursive object allows retrieving all needed information through the whole mapping tree: path, values, types and messages, including the issues that caused the exception. It can be used like the following: ```php try { (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map(SomeClass::class, [/* ... */]); } catch (\CuyZ\Valinor\Mapper\MappingError $error) { // Do something with `$error->node()` // See README for more information } ``` This change removes the method `MappingError::describe()` which provided a flattened view of messages of all the errors that were encountered during the mapping. The same behaviour can still be retrieved, see the example below: ```php use CuyZ\Valinor\Mapper\Tree\Message\Message; use CuyZ\Valinor\Mapper\Tree\Node; /** * @implements \IteratorAggregate<string, array<\Throwable&Message>> */ final class MappingErrorList implements \IteratorAggregate { private Node $node; public function __construct(Node $node) { $this->node = $node; } /** * @return \Traversable<string, array<\Throwable&Message>> */ public function getIterator(): \Traversable { yield from $this->errors($this->node); } /** * @return \Traversable<string, array<\Throwable&Message>> */ private function errors(Node $node): \Traversable { $errors = array_filter( $node->messages(), static fn (Message $m) => $m instanceof \Throwable ); if (! empty($errors)) { yield $node->path() => array_values($errors); } foreach ($node->children() as $child) { yield from $this->errors($child); } } } try { (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map(SomeClass::class, [/* ... */]); } catch (\CuyZ\Valinor\Mapper\MappingError $error) { $errors = iterator_to_array(new MappingErrorList($error->node())); } ``` The class `CannotMapObject` is deleted, as it does not provide any value; this means that `MappingError` which was previously an interface becomes a class.
2021-12-16 00:00:45 +01:00
foreach ($node->messages() as $message) {
if ($message->isError()) {
$errors[] = (string)$message;
feat!: add access to root node when error occurs during mapping When an error occurs during mapping, the root instance of `Node` can now be accessed from the exception. This recursive object allows retrieving all needed information through the whole mapping tree: path, values, types and messages, including the issues that caused the exception. It can be used like the following: ```php try { (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map(SomeClass::class, [/* ... */]); } catch (\CuyZ\Valinor\Mapper\MappingError $error) { // Do something with `$error->node()` // See README for more information } ``` This change removes the method `MappingError::describe()` which provided a flattened view of messages of all the errors that were encountered during the mapping. The same behaviour can still be retrieved, see the example below: ```php use CuyZ\Valinor\Mapper\Tree\Message\Message; use CuyZ\Valinor\Mapper\Tree\Node; /** * @implements \IteratorAggregate<string, array<\Throwable&Message>> */ final class MappingErrorList implements \IteratorAggregate { private Node $node; public function __construct(Node $node) { $this->node = $node; } /** * @return \Traversable<string, array<\Throwable&Message>> */ public function getIterator(): \Traversable { yield from $this->errors($this->node); } /** * @return \Traversable<string, array<\Throwable&Message>> */ private function errors(Node $node): \Traversable { $errors = array_filter( $node->messages(), static fn (Message $m) => $m instanceof \Throwable ); if (! empty($errors)) { yield $node->path() => array_values($errors); } foreach ($node->children() as $child) { yield from $this->errors($child); } } } try { (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map(SomeClass::class, [/* ... */]); } catch (\CuyZ\Valinor\Mapper\MappingError $error) { $errors = iterator_to_array(new MappingErrorList($error->node())); } ``` The class `CannotMapObject` is deleted, as it does not provide any value; this means that `MappingError` which was previously an interface becomes a class.
2021-12-16 00:00:45 +01:00
}
}
if (count($errors) > 0) {
yield $node->path() => "{$node->path()}: " . implode(' / ', $errors);
}
foreach ($node->children() as $child) {
yield from $errorFinder($child, $errorFinder);
}
};
$list = iterator_to_array($errorFinder($error->node(), $errorFinder));
2021-11-28 17:43:02 +01:00
feat!: add access to root node when error occurs during mapping When an error occurs during mapping, the root instance of `Node` can now be accessed from the exception. This recursive object allows retrieving all needed information through the whole mapping tree: path, values, types and messages, including the issues that caused the exception. It can be used like the following: ```php try { (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map(SomeClass::class, [/* ... */]); } catch (\CuyZ\Valinor\Mapper\MappingError $error) { // Do something with `$error->node()` // See README for more information } ``` This change removes the method `MappingError::describe()` which provided a flattened view of messages of all the errors that were encountered during the mapping. The same behaviour can still be retrieved, see the example below: ```php use CuyZ\Valinor\Mapper\Tree\Message\Message; use CuyZ\Valinor\Mapper\Tree\Node; /** * @implements \IteratorAggregate<string, array<\Throwable&Message>> */ final class MappingErrorList implements \IteratorAggregate { private Node $node; public function __construct(Node $node) { $this->node = $node; } /** * @return \Traversable<string, array<\Throwable&Message>> */ public function getIterator(): \Traversable { yield from $this->errors($this->node); } /** * @return \Traversable<string, array<\Throwable&Message>> */ private function errors(Node $node): \Traversable { $errors = array_filter( $node->messages(), static fn (Message $m) => $m instanceof \Throwable ); if (! empty($errors)) { yield $node->path() => array_values($errors); } foreach ($node->children() as $child) { yield from $this->errors($child); } } } try { (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map(SomeClass::class, [/* ... */]); } catch (\CuyZ\Valinor\Mapper\MappingError $error) { $errors = iterator_to_array(new MappingErrorList($error->node())); } ``` The class `CannotMapObject` is deleted, as it does not provide any value; this means that `MappingError` which was previously an interface becomes a class.
2021-12-16 00:00:45 +01:00
self::fail(implode(' — ', $list));
2021-11-28 17:43:02 +01:00
}
}