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_DomQuery37 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      */
0225     public function fail($other, $description, PHPUnit_Framework_ComparisonFailure $cannot_be_used = NULL)
0226     {
0227         // require_once 'Zend/Test/PHPUnit/Constraint/Exception.php';
0228         switch ($this->_assertType) {
0229             case self::ASSERT_CONTENT_CONTAINS:
0230                 $failure = 'Failed asserting node denoted by %s CONTAINS content "%s"';
0231                 if ($this->_negate) {
0232                     $failure = 'Failed asserting node DENOTED BY %s DOES NOT CONTAIN content "%s"';
0233                 }
0234                 $failure = sprintf($failure, $other, $this->_content);
0235                 break;
0236             case self::ASSERT_CONTENT_REGEX:
0237                 $failure = 'Failed asserting node denoted by %s CONTAINS content MATCHING "%s"';
0238                 if ($this->_negate) {
0239                     $failure = 'Failed asserting node DENOTED BY %s DOES NOT CONTAIN content MATCHING "%s"';
0240                 }
0241                 $failure = sprintf($failure, $other, $this->_content);
0242                 break;
0243             case self::ASSERT_CONTENT_COUNT:
0244                 $failure = 'Failed asserting node DENOTED BY %s OCCURS EXACTLY %d times';
0245                 if ($this->_negate) {
0246                     $failure = 'Failed asserting node DENOTED BY %s DOES NOT OCCUR EXACTLY %d times';
0247                 }
0248                 $failure = sprintf($failure, $other, $this->_content);
0249                 break;
0250             case self::ASSERT_CONTENT_COUNT_MIN:
0251                 $failure = 'Failed asserting node DENOTED BY %s OCCURS AT LEAST %d times';
0252                 $failure = sprintf($failure, $other, $this->_content);
0253                 break;
0254             case self::ASSERT_CONTENT_COUNT_MAX:
0255                 $failure = 'Failed asserting node DENOTED BY %s OCCURS AT MOST %d times';
0256                 $failure = sprintf($failure, $other, $this->_content);
0257                 break;
0258             case self::ASSERT_QUERY:
0259             default:
0260                 $failure = 'Failed asserting node DENOTED BY %s EXISTS';
0261                 if ($this->_negate) {
0262                     $failure = 'Failed asserting node DENOTED BY %s DOES NOT EXIST';
0263                 }
0264                 $failure = sprintf($failure, $other);
0265                 break;
0266         }
0267 
0268         if (!empty($description)) {
0269             $failure = $description . "\n" . $failure;
0270         }
0271 
0272         throw new Zend_Test_PHPUnit_Constraint_Exception($failure);
0273     }
0274 
0275     /**
0276      * Complete implementation
0277      *
0278      * @return string
0279      */
0280     public function toString()
0281     {
0282         return '';
0283     }
0284 
0285     /**
0286      * Register XPath namespaces
0287      *
0288      * @param   array $xpathNamespaces
0289      * @return  void
0290      */
0291     public function registerXpathNamespaces($xpathNamespaces)
0292     {
0293         $this->_xpathNamespaces = $xpathNamespaces;
0294     }
0295 
0296     /**
0297      * Check to see if content is matched in selected nodes
0298      *
0299      * @param  Zend_Dom_Query_Result $result
0300      * @param  string $match Content to match
0301      * @return bool
0302      */
0303     protected function _matchContent($result, $match)
0304     {
0305         $match = (string) $match;
0306 
0307         if (0 == count($result)) {
0308             return false;
0309         }
0310 
0311         foreach ($result as $node) {
0312             $content = $this->_getNodeContent($node);
0313             if (strstr($content, $match)) {
0314                 return true;
0315             }
0316         }
0317 
0318         return false;
0319     }
0320 
0321     /**
0322      * Check to see if content is NOT matched in selected nodes
0323      *
0324      * @param  Zend_Dom_Query_Result $result
0325      * @param  string $match
0326      * @return bool
0327      */
0328     protected function _notMatchContent($result, $match)
0329     {
0330         if (0 == count($result)) {
0331             return true;
0332         }
0333 
0334         foreach ($result as $node) {
0335             $content = $this->_getNodeContent($node);
0336             if (strstr($content, $match)) {
0337                 return false;
0338             }
0339         }
0340 
0341         return true;
0342     }
0343 
0344     /**
0345      * Check to see if content is matched by regex in selected nodes
0346      *
0347      * @param  Zend_Dom_Query_Result $result
0348      * @param  string $pattern
0349      * @return bool
0350      */
0351     protected function _regexContent($result, $pattern)
0352     {
0353         if (0 == count($result)) {
0354             return false;
0355         }
0356 
0357         foreach ($result as $node) {
0358             $content = $this->_getNodeContent($node);
0359             if (preg_match($pattern, $content)) {
0360                 return true;
0361             }
0362         }
0363 
0364         return false;
0365     }
0366 
0367     /**
0368      * Check to see if content is NOT matched by regex in selected nodes
0369      *
0370      * @param  Zend_Dom_Query_Result $result
0371      * @param  string $pattern
0372      * @return bool
0373      */
0374     protected function _notRegexContent($result, $pattern)
0375     {
0376         if (0 == count($result)) {
0377             return true;
0378         }
0379 
0380         foreach ($result as $node) {
0381             $content = $this->_getNodeContent($node);
0382             if (preg_match($pattern, $content)) {
0383                 return false;
0384             }
0385         }
0386 
0387         return true;
0388     }
0389 
0390     /**
0391      * Determine if content count matches criteria
0392      *
0393      * @param  Zend_Dom_Query_Result $result
0394      * @param  int $test Value against which to test
0395      * @param  string $type assertion type
0396      * @return boolean
0397      */
0398     protected function _countContent($result, $test, $type)
0399     {
0400         $count = count($result);
0401 
0402         switch ($type) {
0403             case self::ASSERT_CONTENT_COUNT:
0404                 return ($this->_negate)
0405                     ? ($test != $count)
0406                     : ($test == $count);
0407             case self::ASSERT_CONTENT_COUNT_MIN:
0408                 return ($count >= $test);
0409             case self::ASSERT_CONTENT_COUNT_MAX:
0410                 return ($count <= $test);
0411             default:
0412                 return false;
0413         }
0414     }
0415 
0416     /**
0417      * Get node content, minus node markup tags
0418      *
0419      * @param  DOMNode $node
0420      * @return string
0421      */
0422     protected function _getNodeContent(DOMNode $node)
0423     {
0424         if ($node instanceof DOMAttr) {
0425             return $node->value;
0426         } else {
0427             $doc     = $node->ownerDocument;
0428             $content = $doc->saveXML($node);
0429             $tag     = $node->nodeName;
0430             $regex   = '|</?' . $tag . '[^>]*>|';
0431             return preg_replace($regex, '', $content);
0432         }
0433     }
0434 }