File indexing completed on 2024-12-29 05:28:07

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Test
0017  * @subpackage PHPUnit
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  * @version    $Id$
0021  */
0022 
0023 /** @see Zend_Dom_Query */
0024 // require_once 'Zend/Dom/Query.php';
0025 
0026 /**
0027  * Zend_Dom_Query-based PHPUnit Constraint
0028  *
0029  * @uses       PHPUnit_Framework_Constraint
0030  * @category   Zend
0031  * @package    Zend_Test
0032  * @subpackage PHPUnit
0033  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0034  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0035  */
0036 class Zend_Test_PHPUnit_Constraint_DomQuery41 extends PHPUnit_Framework_Constraint
0037 {
0038     /**#@+
0039      * Assertion type constants
0040      */
0041     const ASSERT_QUERY            = 'assertQuery';
0042     const ASSERT_CONTENT_CONTAINS = 'assertQueryContentContains';
0043     const ASSERT_CONTENT_REGEX    = 'assertQueryContentRegex';
0044     const ASSERT_CONTENT_COUNT    = 'assertQueryCount';
0045     const ASSERT_CONTENT_COUNT_MIN= 'assertQueryCountMin';
0046     const ASSERT_CONTENT_COUNT_MAX= 'assertQueryCountMax';
0047     /**#@-*/
0048 
0049     /**
0050      * Current assertion type
0051      * @var string
0052      */
0053     protected $_assertType        = null;
0054 
0055     /**
0056      * Available assertion types
0057      * @var array
0058      */
0059     protected $_assertTypes       = array(
0060         self::ASSERT_QUERY,
0061         self::ASSERT_CONTENT_CONTAINS,
0062         self::ASSERT_CONTENT_REGEX,
0063         self::ASSERT_CONTENT_COUNT,
0064         self::ASSERT_CONTENT_COUNT_MIN,
0065         self::ASSERT_CONTENT_COUNT_MAX,
0066     );
0067 
0068     /**
0069      * Content being matched
0070      * @var string
0071      */
0072     protected $_content           = null;
0073 
0074     /**
0075      * Whether or not assertion is negated
0076      * @var bool
0077      */
0078     protected $_negate            = false;
0079 
0080     /**
0081      * CSS selector or XPath path to select against
0082      * @var string
0083      */
0084     protected $_path              = null;
0085 
0086     /**
0087      * Whether or not to use XPath when querying
0088      * @var bool
0089      */
0090     protected $_useXpath          = false;
0091 
0092     /**
0093      * XPath namespaces
0094      * @var array
0095      */
0096     protected $_xpathNamespaces = array();
0097 
0098     /**
0099      * Constructor; setup constraint state
0100      *
0101      * @param  string $path CSS selector path
0102      * @return void
0103      */
0104     public function __construct($path)
0105     {
0106         $this->_path = $path;
0107     }
0108 
0109     /**
0110      * Indicate negative match
0111      *
0112      * @param  bool $flag
0113      * @return void
0114      */
0115     public function setNegate($flag = true)
0116     {
0117         $this->_negate = $flag;
0118     }
0119 
0120     /**
0121      * Whether or not path is a straight XPath expression
0122      *
0123      * @param  bool $flag
0124      * @return Zend_Test_PHPUnit_Constraint_DomQuery
0125      */
0126     public function setUseXpath($flag = true)
0127     {
0128         $this->_useXpath = (bool) $flag;
0129         return $this;
0130     }
0131 
0132     /**
0133      * Evaluate an object to see if it fits the constraints
0134      *
0135      * @param  string       Response content to be matched against (haystack)
0136      * @param  null|string  Assertion type
0137      * @param  string       (optional) String to match (needle), may be required depending on assertion type
0138      * @return bool
0139      * 
0140      * NOTE:
0141      * Drastic changes up to PHPUnit 3.5.15 this was:
0142      *     public function evaluate($other, $assertType = null)
0143      * In PHPUnit 3.6.0 they changed the interface into this:
0144      *     public function evaluate($other, $description = '', $returnResult = FALSE)
0145      * We use the new interface for PHP-strict checking, but emulate the old one
0146      */
0147     public function evaluate($content, $assertType = '', $match = FALSE)
0148     {
0149         if (strstr($assertType, 'Not')) {
0150             $this->setNegate(true);
0151             $assertType = str_replace('Not', '', $assertType);
0152         }
0153 
0154         if (strstr($assertType, 'Xpath')) {
0155             $this->setUseXpath(true);
0156             $assertType = str_replace('Xpath', 'Query', $assertType);
0157         }
0158 
0159         if (!in_array($assertType, $this->_assertTypes)) {
0160             // require_once 'Zend/Test/PHPUnit/Constraint/Exception.php';
0161             throw new Zend_Test_PHPUnit_Constraint_Exception(sprintf('Invalid assertion type "%s" provided to %s constraint', $assertType, __CLASS__));
0162         }
0163 
0164         $this->_assertType = $assertType;
0165 
0166         $method   = $this->_useXpath ? 'queryXpath' : 'query';
0167         $domQuery = new Zend_Dom_Query($content);
0168         $domQuery->registerXpathNamespaces($this->_xpathNamespaces);
0169         $result   = $domQuery->$method($this->_path);
0170 
0171         switch ($assertType) {
0172             case self::ASSERT_CONTENT_CONTAINS:
0173                 if (!$match) {
0174                     // require_once 'Zend/Test/PHPUnit/Constraint/Exception.php';
0175                     throw new Zend_Test_PHPUnit_Constraint_Exception('No content provided against which to match');
0176                 }
0177                 $this->_content = $match;
0178                 return ($this->_negate)
0179                     ? $this->_notMatchContent($result, $match)
0180                     : $this->_matchContent($result, $match);
0181             case self::ASSERT_CONTENT_REGEX:
0182                 if (!$match) {
0183                     // require_once 'Zend/Test/PHPUnit/Constraint/Exception.php';
0184                     throw new Zend_Test_PHPUnit_Constraint_Exception('No pattern provided against which to match');
0185                 }
0186                 $this->_content = $match;
0187                 return ($this->_negate)
0188                     ? $this->_notRegexContent($result, $match)
0189                     : $this->_regexContent($result, $match);
0190             case self::ASSERT_CONTENT_COUNT:
0191             case self::ASSERT_CONTENT_COUNT_MIN:
0192             case self::ASSERT_CONTENT_COUNT_MAX:
0193                 if ($match === false) {
0194                     // require_once 'Zend/Test/PHPUnit/Constraint/Exception.php';
0195                     throw new Zend_Test_PHPUnit_Constraint_Exception('No count provided against which to compare');
0196                 }
0197                 $this->_content = $match;
0198                 return $this->_countContent($result, $match, $assertType);
0199             case self::ASSERT_QUERY:
0200             default:
0201                 if ($this->_negate) {
0202                     return (0 == count($result));
0203                 } else {
0204                     return (0 != count($result));
0205                 }
0206         }
0207     }
0208 
0209     /**
0210      * Report Failure
0211      *
0212      * @see    PHPUnit_Framework_Constraint for implementation details
0213      * @param  mixed    CSS selector path
0214      * @param  string   Failure description
0215      * @param  object   Cannot be used, null
0216      * @return void
0217      * @throws PHPUnit_Framework_ExpectationFailedException
0218      * NOTE:
0219      * Drastic changes up to PHPUnit 3.5.15 this was:
0220      *     public function fail($other, $description, $not = false)
0221      * In PHPUnit 3.6.0 they changed the interface into this:
0222      *     protected function fail($other, $description, PHPUnit_Framework_ComparisonFailure $comparisonFailure = NULL)
0223      * We use the new interface for PHP-strict checking
0224      * NOTE 2:
0225      * Interface changed again in PHPUnit 4.1.0 because of refactoring to SebastianBergmann\Comparator
0226      */
0227     public function fail($other, $description, \SebastianBergmann\Comparator\ComparisonFailure $cannot_be_used = NULL)
0228     {
0229         // require_once 'Zend/Test/PHPUnit/Constraint/Exception.php';
0230         switch ($this->_assertType) {
0231             case self::ASSERT_CONTENT_CONTAINS:
0232                 $failure = 'Failed asserting node denoted by %s CONTAINS content "%s"';
0233                 if ($this->_negate) {
0234                     $failure = 'Failed asserting node DENOTED BY %s DOES NOT CONTAIN content "%s"';
0235                 }
0236                 $failure = sprintf($failure, $other, $this->_content);
0237                 break;
0238             case self::ASSERT_CONTENT_REGEX:
0239                 $failure = 'Failed asserting node denoted by %s CONTAINS content MATCHING "%s"';
0240                 if ($this->_negate) {
0241                     $failure = 'Failed asserting node DENOTED BY %s DOES NOT CONTAIN content MATCHING "%s"';
0242                 }
0243                 $failure = sprintf($failure, $other, $this->_content);
0244                 break;
0245             case self::ASSERT_CONTENT_COUNT:
0246                 $failure = 'Failed asserting node DENOTED BY %s OCCURS EXACTLY %d times';
0247                 if ($this->_negate) {
0248                     $failure = 'Failed asserting node DENOTED BY %s DOES NOT OCCUR EXACTLY %d times';
0249                 }
0250                 $failure = sprintf($failure, $other, $this->_content);
0251                 break;
0252             case self::ASSERT_CONTENT_COUNT_MIN:
0253                 $failure = 'Failed asserting node DENOTED BY %s OCCURS AT LEAST %d times';
0254                 $failure = sprintf($failure, $other, $this->_content);
0255                 break;
0256             case self::ASSERT_CONTENT_COUNT_MAX:
0257                 $failure = 'Failed asserting node DENOTED BY %s OCCURS AT MOST %d times';
0258                 $failure = sprintf($failure, $other, $this->_content);
0259                 break;
0260             case self::ASSERT_QUERY:
0261             default:
0262                 $failure = 'Failed asserting node DENOTED BY %s EXISTS';
0263                 if ($this->_negate) {
0264                     $failure = 'Failed asserting node DENOTED BY %s DOES NOT EXIST';
0265                 }
0266                 $failure = sprintf($failure, $other);
0267                 break;
0268         }
0269 
0270         if (!empty($description)) {
0271             $failure = $description . "\n" . $failure;
0272         }
0273 
0274         throw new Zend_Test_PHPUnit_Constraint_Exception($failure);
0275     }
0276 
0277     /**
0278      * Complete implementation
0279      *
0280      * @return string
0281      */
0282     public function toString()
0283     {
0284         return '';
0285     }
0286 
0287     /**
0288      * Register XPath namespaces
0289      *
0290      * @param   array $xpathNamespaces
0291      * @return  void
0292      */
0293     public function registerXpathNamespaces($xpathNamespaces)
0294     {
0295         $this->_xpathNamespaces = $xpathNamespaces;
0296     }
0297 
0298     /**
0299      * Check to see if content is matched in selected nodes
0300      *
0301      * @param  Zend_Dom_Query_Result $result
0302      * @param  string $match Content to match
0303      * @return bool
0304      */
0305     protected function _matchContent($result, $match)
0306     {
0307         $match = (string) $match;
0308 
0309         if (0 == count($result)) {
0310             return false;
0311         }
0312 
0313         foreach ($result as $node) {
0314             $content = $this->_getNodeContent($node);
0315             if (strstr($content, $match)) {
0316                 return true;
0317             }
0318         }
0319 
0320         return false;
0321     }
0322 
0323     /**
0324      * Check to see if content is NOT matched in selected nodes
0325      *
0326      * @param  Zend_Dom_Query_Result $result
0327      * @param  string $match
0328      * @return bool
0329      */
0330     protected function _notMatchContent($result, $match)
0331     {
0332         if (0 == count($result)) {
0333             return true;
0334         }
0335 
0336         foreach ($result as $node) {
0337             $content = $this->_getNodeContent($node);
0338             if (strstr($content, $match)) {
0339                 return false;
0340             }
0341         }
0342 
0343         return true;
0344     }
0345 
0346     /**
0347      * Check to see if content is matched by regex in selected nodes
0348      *
0349      * @param  Zend_Dom_Query_Result $result
0350      * @param  string $pattern
0351      * @return bool
0352      */
0353     protected function _regexContent($result, $pattern)
0354     {
0355         if (0 == count($result)) {
0356             return false;
0357         }
0358 
0359         foreach ($result as $node) {
0360             $content = $this->_getNodeContent($node);
0361             if (preg_match($pattern, $content)) {
0362                 return true;
0363             }
0364         }
0365 
0366         return false;
0367     }
0368 
0369     /**
0370      * Check to see if content is NOT matched by regex in selected nodes
0371      *
0372      * @param  Zend_Dom_Query_Result $result
0373      * @param  string $pattern
0374      * @return bool
0375      */
0376     protected function _notRegexContent($result, $pattern)
0377     {
0378         if (0 == count($result)) {
0379             return true;
0380         }
0381 
0382         foreach ($result as $node) {
0383             $content = $this->_getNodeContent($node);
0384             if (preg_match($pattern, $content)) {
0385                 return false;
0386             }
0387         }
0388 
0389         return true;
0390     }
0391 
0392     /**
0393      * Determine if content count matches criteria
0394      *
0395      * @param  Zend_Dom_Query_Result $result
0396      * @param  int $test Value against which to test
0397      * @param  string $type assertion type
0398      * @return boolean
0399      */
0400     protected function _countContent($result, $test, $type)
0401     {
0402         $count = count($result);
0403 
0404         switch ($type) {
0405             case self::ASSERT_CONTENT_COUNT:
0406                 return ($this->_negate)
0407                     ? ($test != $count)
0408                     : ($test == $count);
0409             case self::ASSERT_CONTENT_COUNT_MIN:
0410                 return ($count >= $test);
0411             case self::ASSERT_CONTENT_COUNT_MAX:
0412                 return ($count <= $test);
0413             default:
0414                 return false;
0415         }
0416     }
0417 
0418     /**
0419      * Get node content, minus node markup tags
0420      *
0421      * @param  DOMNode $node
0422      * @return string
0423      */
0424     protected function _getNodeContent(DOMNode $node)
0425     {
0426         if ($node instanceof DOMAttr) {
0427             return $node->value;
0428         } else {
0429             $doc     = $node->ownerDocument;
0430             $content = $doc->saveXML($node);
0431             $tag     = $node->nodeName;
0432             $regex   = '|</?' . $tag . '[^>]*>|';
0433             return preg_replace($regex, '', $content);
0434         }
0435     }
0436 }