public
Created

This PHPUnit constraint class is for applying another constraint to a value inside a nested array structure.

  • Download Gist
NestedArrayConstraint.php
PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
<?php
/**
* This constraint class is for applying another constraint to a value inside a nested array structure.
*
* When initializing this constraint you specify a "key path" - an array of keys, each accessing the next level of the
* array to check.
*
* @author Gabriel Birke <gb@birke-software.de>
*/
class NestedArrayConstraint extends PHPUnit_Framework_Constraint
{
 
private $path;
private $constraint;
private $pathMatches = false;
private $pathValue;
 
/**
* @param array $path Key path to the desired value
* @param PHPUnit_Framework_Constraint $constraint Constraint that will be evaluated with the value at the end of the key path
*/
public function __construct($path, PHPUnit_Framework_Constraint $constraint){
$this->path = $path;
$this->constraint = $constraint;
}
 
/**
* Check if the array contains the keys in $this->path and if it does, delegate evaluation to internal constraint
*
* @param mixed $other
* @param string $description
* @param bool $returnResult
* @return bool|mixed
*/
public function evaluate($other, $description = '', $returnResult = FALSE)
{
$success = false;
 
if($this->matches($other) && $this->constraint->evaluate($this->pathValue, $description, TRUE)) {
$success = true;
}
 
if ($returnResult) {
return $success;
}
 
if (!$success) {
$this->fail($other, $description);
}
}
 
/**
* Check if $other is an array and contains all the keys specified in $this->path
*
* @param mixed $other
* @return bool
*/
protected function matches($other)
{
if(!is_array($other)) {
return false;
}
$pointer = $other;
foreach($this->path as $p) {
if(!isset($pointer[$p])) {
return false;
}
$pointer = $pointer[$p];
}
$this->pathMatches = true;
$this->pathValue = $pointer;
return true;
}
 
/**
* Depending on the type of failure, choose different values for $other
*
* @param mixed $other
* @param string $description
* @param PHPUnit_Framework_ComparisonFailure $comparisonFailure
*/
protected function fail($other, $description, PHPUnit_Framework_ComparisonFailure $comparisonFailure = NULL)
{
if($this->pathMatches) {
parent::fail($this->pathValue, $description, $comparisonFailure);
}
else {
parent::fail($other, $description, $comparisonFailure);
}
 
}
 
/**
* Returns a string representation of the object.
*
* @return string
*/
public function toString()
{
if($this->pathMatches) {
return $this->constraint->toString();
}
else {
$keys = implode('', array_map(function($v){ return "[$v]"; }, $this->path));
return "has nested key path ". $keys;
}
}
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.