Skip to content

Commit

Permalink
Make LazyAssertion open for extension
Browse files Browse the repository at this point in the history
  • Loading branch information
DannyvdSluijs committed Aug 9, 2019
1 parent ad2c8a7 commit 49aef74
Show file tree
Hide file tree
Showing 8 changed files with 245 additions and 11 deletions.
15 changes: 14 additions & 1 deletion lib/Assert/Assert.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

namespace Assert;

use LogicException;

/**
* AssertionChain factory.
*/
Expand All @@ -25,6 +27,9 @@ abstract class Assert
/** @var string */
protected static $assertionClass = Assertion::class;

/** @var string */
protected static $lazyAssertionClass = LazyAssertion::class;

/**
* Start validation on a value, returns {@link AssertionChain}.
*
Expand Down Expand Up @@ -87,7 +92,15 @@ public static function thatNullOr($value, $defaultMessage = null, $defaultProper
*/
public static function lazy()
{
$lazyAssertion = new LazyAssertion();
if (LazyAssertion::class !== static::$lazyAssertionClass
&& !\is_subclass_of(static::$lazyAssertionClass, LazyAssertion::class)
) {
throw new LogicException(static::$lazyAssertionClass.' is not (a subclass of) '.LazyAssertion::class);
}

$lazyAssertionClass = static::$lazyAssertionClass;
/** @var LazyAssertion $lazyAssertion */
$lazyAssertion = new $lazyAssertionClass();

return $lazyAssertion
->setAssertClass(\get_called_class())
Expand Down
17 changes: 7 additions & 10 deletions lib/Assert/LazyAssertion.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,17 +114,17 @@
*/
class LazyAssertion
{
private $currentChainFailed = false;
private $alwaysTryAll = false;
private $thisChainTryAll = false;
private $currentChain;
private $errors = [];
protected $currentChainFailed = false;
protected $alwaysTryAll = false;
protected $thisChainTryAll = false;
protected $currentChain;
protected $errors = [];

/** @var string The class to use as AssertionChain factory */
private $assertClass = Assert::class;
protected $assertClass = Assert::class;

/** @var string|LazyAssertionException The class to use for exceptions */
private $exceptionClass = LazyAssertionException::class;
protected $exceptionClass = LazyAssertionException::class;

/**
* @return $this
Expand All @@ -139,9 +139,6 @@ public function that($value, $propertyPath, $defaultMessage = null)
return $this;
}

/**
* @return $this
*/
public function tryAll()
{
if (!$this->currentChain) {
Expand Down
46 changes: 46 additions & 0 deletions tests/Assert/Tests/ContextAwareLazyAssertion.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

/**
* Assert
*
* LICENSE
*
* This source file is subject to the MIT license that is bundled
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to [email protected] so I can send you a copy immediately.
*/

namespace Assert\Tests;

use Assert\LazyAssertionException;
use Assert\Tests\Fixtures\ContextAware\Assert;
use Assert\Tests\Fixtures\ContextAware\InvalidArgumentException;
use Assert\Tests\Fixtures\ContextAware\LazyAssertion;
use PHPUnit\Framework\TestCase;

class ContextAwareLazyAssertion extends TestCase
{
public function testContextIsPassedThroughToExceptions()
{
$context = ['method' => __FUNCTION__, 'class' => __CLASS__];
/** @var LazyAssertion $assertion */
$assertion = Assert::lazy();
$assertion->tryAll()
->that(true, '', null, $context)
->false()
->null();

try {
$assertion->verifyNow();
} catch (LazyAssertionException $e) {
self::assertCount(2, $e->getErrorExceptions());

foreach ($e->getErrorExceptions() as $error) {
self::assertInstanceOf(InvalidArgumentException::class, $error);
self::assertSame($context, $error->getContext());
}
}
}
}
33 changes: 33 additions & 0 deletions tests/Assert/Tests/Fixtures/ContextAware/Assert.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

/**
* Assert
*
* LICENSE
*
* This source file is subject to the MIT license that is bundled
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to [email protected] so I can send you a copy immediately.
*/

namespace Assert\Tests\Fixtures\ContextAware;

use Assert\Assert as BaseAssert;

class Assert extends BaseAssert
{
/** @var string */
protected static $assertionClass = Assertion::class;

/** @var string */
protected static $lazyAssertionClass = LazyAssertion::class;

public static function that($value, $defaultMessage = null, $defaultPropertyPath = null, array $context = [])
{
$assertionChain = new AssertionChain($value, $defaultMessage, $defaultPropertyPath, $context);

return $assertionChain->setAssertionClassName(static::$assertionClass);
}
}
23 changes: 23 additions & 0 deletions tests/Assert/Tests/Fixtures/ContextAware/Assertion.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

/**
* Assert
*
* LICENSE
*
* This source file is subject to the MIT license that is bundled
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to [email protected] so I can send you a copy immediately.
*/

namespace Assert\Tests\Fixtures\ContextAware;

use Assert\Assertion as BaseAssertion;

class Assertion extends BaseAssertion
{
/** @var string */
protected static $exceptionClass = InvalidArgumentException::class;
}
34 changes: 34 additions & 0 deletions tests/Assert/Tests/Fixtures/ContextAware/AssertionChain.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

/**
* Assert
*
* LICENSE
*
* This source file is subject to the MIT license that is bundled
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to [email protected] so I can send you a copy immediately.
*/

namespace Assert\Tests\Fixtures\ContextAware;

use Assert\AssertionChain as BaseAssertionChain;

class AssertionChain extends BaseAssertionChain
{
/** @var array */
private $context;

public function __construct($value, $defaultMessage = null, $defaultPropertyPath = null, array $context = [])
{
parent::__construct($value, $defaultMessage, $defaultPropertyPath);
$this->context = $context;
}

public function getContext(): array
{
return $this->context;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

/**
* Assert
*
* LICENSE
*
* This source file is subject to the MIT license that is bundled
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to [email protected] so I can send you a copy immediately.
*/

namespace Assert\Tests\Fixtures\ContextAware;

use Assert\InvalidArgumentException as BaseInvalidArgumentException;

class InvalidArgumentException extends BaseInvalidArgumentException
{
/** @var array */
private $context;

public function getContext(): array
{
return $this->context;
}

public function setContext(array $context): self
{
$this->context = $context;

return $this;
}
}
53 changes: 53 additions & 0 deletions tests/Assert/Tests/Fixtures/ContextAware/LazyAssertion.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

/**
* Assert
*
* LICENSE
*
* This source file is subject to the MIT license that is bundled
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to [email protected] so I can send you a copy immediately.
*/

namespace Assert\Tests\Fixtures\ContextAware;

use Assert\LazyAssertion as BaseLazyAssertion;

class LazyAssertion extends BaseLazyAssertion
{
/** @var string The class to use as AssertionChain factory */
protected $assertClass = Assert::class;
/** @var AssertionChain */
protected $currentChain;

public function that($value, $propertyPath, $defaultMessage = null, array $context = [])
{
$this->currentChainFailed = false;
$this->thisChainTryAll = false;
$assertClass = $this->assertClass;
$this->currentChain = $assertClass::that($value, $defaultMessage, $propertyPath, $context);

return $this;
}

public function __call($method, $args)
{
$errorKeys = \array_keys($this->errors);

parent::__call($method, $args);

$additions = \array_diff(\array_keys($this->errors), $errorKeys);

foreach ($additions as $addition) {
$error = $this->errors[$addition];
if ($error instanceof InvalidArgumentException) {
$this->errors[$addition] = $error->setContext($this->currentChain->getContext());
}
}

return $this;
}
}

0 comments on commit 49aef74

Please sign in to comment.