Skip to content

Commit

Permalink
Merge pull request #30989 from laravel/testbench
Browse files Browse the repository at this point in the history
[6.x] Bring in array subset code directly
  • Loading branch information
taylorotwell committed Dec 31, 2019
2 parents aa38173 + a1c4e7d commit e949315
Show file tree
Hide file tree
Showing 3 changed files with 306 additions and 39 deletions.
2 changes: 0 additions & 2 deletions composer.json
Expand Up @@ -80,7 +80,6 @@
"aws/aws-sdk-php": "^3.0",
"doctrine/dbal": "^2.6",
"filp/whoops": "^2.4",
"graham-campbell/testbench-core": "^3.1",
"guzzlehttp/guzzle": "^6.3",
"league/flysystem-cached-adapter": "^1.0",
"mockery/mockery": "^1.3.1",
Expand Down Expand Up @@ -123,7 +122,6 @@
"doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6).",
"filp/whoops": "Required for friendly error pages in development (^2.4).",
"fzaninotto/faker": "Required to use the eloquent factory builder (^1.4).",
"graham-campbell/testbench-core": "Required to use the foundation testing component with PHPUnit 9 (^3.1).",
"guzzlehttp/guzzle": "Required to use the Mailgun mail driver and the ping methods on schedules (^6.0).",
"laravel/tinker": "Required to use the tinker console command (^1.0).",
"league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^1.0).",
Expand Down
64 changes: 27 additions & 37 deletions src/Illuminate/Foundation/Testing/Assert.php
Expand Up @@ -3,55 +3,45 @@
namespace Illuminate\Foundation\Testing;

use ArrayAccess;
use Exception;
use GrahamCampbell\TestBenchCore\ArraySubsetTrait;
use Illuminate\Foundation\Testing\Constraints\ArraySubset;
use PHPUnit\Framework\Assert as PHPUnit;
use PHPUnit\Framework\Constraint\ArraySubset;
use PHPUnit\Runner\Version;
use PHPUnit\Framework\InvalidArgumentException;
use PHPUnit\Util\InvalidArgumentHelper;

if (trait_exists(ArraySubsetTrait::class)) {
/**
* @internal This class is not meant to be used or overwritten outside the framework itself.
*/
abstract class Assert extends PHPUnit
{
/**
* @internal This class is not meant to be used or overwritten outside the framework itself.
* Asserts that an array has a specified subset.
*
* @param \ArrayAccess|array $subset
* @param \ArrayAccess|array $array
* @param bool $checkForIdentity
* @param string $msg
* @return void
*/
abstract class Assert extends PHPUnit
public static function assertArraySubset($subset, $array, bool $checkForIdentity = false, string $msg = ''): void
{
use ArraySubsetTrait;
}
} else {
/**
* @internal This class is not meant to be used or overwritten outside the framework itself.
*/
abstract class Assert extends PHPUnit
{
/**
* Asserts that an array has a specified subset.
*
* This method was taken over from PHPUnit where it was deprecated. See link for more info.
*
* @param \ArrayAccess|array $subset
* @param \ArrayAccess|array $array
* @param bool $checkForObjectIdentity
* @param string $message
* @return void
*/
public static function assertArraySubset($subset, $array, bool $checkForObjectIdentity = false, string $message = ''): void
{
if ((int) Version::series()[0] > 8) {
throw new Exception('For PHPUnit 9 support, please install graham-campbell/testbench-core:"^3.1".');
}

if (! (is_array($subset) || $subset instanceof ArrayAccess)) {
if (! (is_array($subset) || $subset instanceof ArrayAccess)) {
if (class_exists(InvalidArgumentException::class)) {
throw InvalidArgumentException::create(1, 'array or ArrayAccess');
} else {
throw InvalidArgumentHelper::factory(1, 'array or ArrayAccess');
}
}

if (! (is_array($array) || $array instanceof ArrayAccess)) {
if (! (is_array($array) || $array instanceof ArrayAccess)) {
if (class_exists(InvalidArgumentException::class)) {
throw InvalidArgumentException::create(2, 'array or ArrayAccess');
} else {
throw InvalidArgumentHelper::factory(2, 'array or ArrayAccess');
}
}

$constraint = new ArraySubset($subset, $checkForObjectIdentity);
$constraint = new ArraySubset($subset, $checkForIdentity);

static::assertThat($array, $constraint, $message);
}
PHPUnit::assertThat($array, $constraint, $msg);
}
}
279 changes: 279 additions & 0 deletions src/Illuminate/Foundation/Testing/Constraints/ArraySubset.php
@@ -0,0 +1,279 @@
<?php

namespace Illuminate\Foundation\Testing\Constraints;

use ArrayObject;
use PHPUnit\Framework\Constraint\Constraint;
use PHPUnit\Runner\Version;
use SebastianBergmann\Comparator\ComparisonFailure;
use Traversable;

if (class_exists(Version::class) && (int) Version::series()[0] >= 9) {
/**
* @internal This class is not meant to be used or overwritten outside the framework itself.
*/
final class ArraySubset extends Constraint
{
/**
* @var iterable
*/
private $subset;

/**
* @var bool
*/
private $strict;

/**
* Create a new array subset constraint instance.
*
* @param iterable $subset
* @param bool $strict
* @return void
*/
public function __construct(iterable $subset, bool $strict = false)
{
$this->strict = $strict;
$this->subset = $subset;
}

/**
* Evaluates the constraint for parameter $other.
*
* If $returnResult is set to false (the default), an exception is thrown
* in case of a failure. null is returned otherwise.
*
* If $returnResult is true, the result of the evaluation is returned as
* a boolean value instead: true in case of success, false in case of a
* failure.
*
* @param mixed $other
* @param string $description
* @param bool $returnResult
* @return bool|null
*
* @throws \PHPUnit\Framework\ExpectationFailedException
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
public function evaluate($other, string $description = '', bool $returnResult = false): ?bool
{
// type cast $other & $this->subset as an array to allow
// support in standard array functions.
$other = $this->toArray($other);
$this->subset = $this->toArray($this->subset);

$patched = array_replace_recursive($other, $this->subset);

if ($this->strict) {
$result = $other === $patched;
} else {
$result = $other == $patched;
}

if ($returnResult) {
return $result;
}

if (! $result) {
$f = new ComparisonFailure(
$patched,
$other,
var_export($patched, true),
var_export($other, true)
);

$this->fail($other, $description, $f);
}

return null;
}

/**
* Returns a string representation of the constraint.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*
* @return string
*/
public function toString(): string
{
return 'has the subset '.$this->exporter()->export($this->subset);
}

/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other
* @return string
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
protected function failureDescription($other): string
{
return 'an array '.$this->toString();
}

/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param iterable $other
* @return array
*/
private function toArray(iterable $other): array
{
if (is_array($other)) {
return $other;
}

if ($other instanceof ArrayObject) {
return $other->getArrayCopy();
}

if ($other instanceof Traversable) {
return iterator_to_array($other);
}

// Keep BC even if we know that array would not be the expected one
return (array) $other;
}
}
} else {
/**
* @internal This class is not meant to be used or overwritten outside the framework itself.
*/
final class ArraySubset extends Constraint
{
/**
* @var iterable
*/
private $subset;

/**
* @var bool
*/
private $strict;

/**
* Create a new array subset constraint instance.
*
* @param iterable $subset
* @param bool $strict
* @return void
*/
public function __construct(iterable $subset, bool $strict = false)
{
$this->strict = $strict;
$this->subset = $subset;
}

/**
* Evaluates the constraint for parameter $other.
*
* If $returnResult is set to false (the default), an exception is thrown
* in case of a failure. null is returned otherwise.
*
* If $returnResult is true, the result of the evaluation is returned as
* a boolean value instead: true in case of success, false in case of a
* failure.
*
* @param mixed $other
* @param string $description
* @param bool $returnResult
* @return bool|null
*
* @throws \PHPUnit\Framework\ExpectationFailedException
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
public function evaluate($other, string $description = '', bool $returnResult = false)
{
// type cast $other & $this->subset as an array to allow
// support in standard array functions.
$other = $this->toArray($other);
$this->subset = $this->toArray($this->subset);

$patched = array_replace_recursive($other, $this->subset);

if ($this->strict) {
$result = $other === $patched;
} else {
$result = $other == $patched;
}

if ($returnResult) {
return $result;
}

if (! $result) {
$f = new ComparisonFailure(
$patched,
$other,
var_export($patched, true),
var_export($other, true)
);

$this->fail($other, $description, $f);
}
}

/**
* Returns a string representation of the constraint.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*
* @return string
*/
public function toString(): string
{
return 'has the subset '.$this->exporter()->export($this->subset);
}

/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other
* @return string
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
protected function failureDescription($other): string
{
return 'an array '.$this->toString();
}

/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param iterable $other
* @return array
*/
private function toArray(iterable $other): array
{
if (is_array($other)) {
return $other;
}

if ($other instanceof ArrayObject) {
return $other->getArrayCopy();
}

if ($other instanceof Traversable) {
return iterator_to_array($other);
}

// Keep BC even if we know that array would not be the expected one
return (array) $other;
}
}
}

0 comments on commit e949315

Please sign in to comment.