Skip to content

Instantly share code, notes, and snippets.

@gbirke
Created March 8, 2013 08:50
Show Gist options
  • Save gbirke/5115086 to your computer and use it in GitHub Desktop.
Save gbirke/5115086 to your computer and use it in GitHub Desktop.
This PHPUnit constraint class is for applying another constraint to a value inside a nested array structure.
<?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 <[email protected]>
*/
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;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment