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

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_DomQuery34 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 $other String to examine
0136      * @param  null|string Assertion type
0137      * @return bool
0138      */
0139     public function evaluate($other, $assertType = null)
0140     {
0141         if (strstr($assertType, 'Not')) {
0142             $this->setNegate(true);
0143             $assertType = str_replace('Not', '', $assertType);
0144         }
0145 
0146         if (strstr($assertType, 'Xpath')) {
0147             $this->setUseXpath(true);
0148             $assertType = str_replace('Xpath', 'Query', $assertType);
0149         }
0150 
0151         if (!in_array($assertType, $this->_assertTypes)) {
0152             // require_once 'Zend/Test/PHPUnit/Constraint/Exception.php';
0153             throw new Zend_Test_PHPUnit_Constraint_Exception(sprintf('Invalid assertion type "%s" provided to %s constraint', $assertType, __CLASS__));
0154         }
0155 
0156         $this->_assertType = $assertType;
0157 
0158         $method   = $this->_useXpath ? 'queryXpath' : 'query';
0159         $domQuery = new Zend_Dom_Query($other);
0160         $domQuery->registerXpathNamespaces($this->_xpathNamespaces);
0161         $result   = $domQuery->$method($this->_path);
0162         $argv     = func_get_args();
0163         $argc     = func_num_args();
0164 
0165         switch ($assertType) {
0166             case self::ASSERT_CONTENT_CONTAINS:
0167                 if (3 > $argc) {
0168                     // require_once 'Zend/Test/PHPUnit/Constraint/Exception.php';
0169                     throw new Zend_Test_PHPUnit_Constraint_Exception('No content provided against which to match');
0170                 }
0171                 $this->_content = $content = $argv[2];
0172                 return ($this->_negate)
0173                     ? $this->_notMatchContent($result, $content)
0174                     : $this->_matchContent($result, $content);
0175             case self::ASSERT_CONTENT_REGEX:
0176                 if (3 > $argc) {
0177                     // require_once 'Zend/Test/PHPUnit/Constraint/Exception.php';
0178                     throw new Zend_Test_PHPUnit_Constraint_Exception('No pattern provided against which to match');
0179                 }
0180                 $this->_content = $content = $argv[2];
0181                 return ($this->_negate)
0182                     ? $this->_notRegexContent($result, $content)
0183                     : $this->_regexContent($result, $content);
0184             case self::ASSERT_CONTENT_COUNT:
0185             case self::ASSERT_CONTENT_COUNT_MIN:
0186             case self::ASSERT_CONTENT_COUNT_MAX:
0187                 if (3 > $argc) {
0188                     // require_once 'Zend/Test/PHPUnit/Constraint/Exception.php';
0189                     throw new Zend_Test_PHPUnit_Constraint_Exception('No count provided against which to compare');
0190                 }
0191                 $this->_content = $content = $argv[2];
0192                 return $this->_countContent($result, $content, $assertType);
0193             case self::ASSERT_QUERY:
0194             default:
0195                 if ($this->_negate) {
0196                     return (0 == count($result));
0197                 } else {
0198                     return (0 != count($result));
0199                 }
0200         }
0201     }
0202 
0203     /**
0204      * Report Failure
0205      *
0206      * @see    PHPUnit_Framework_Constraint for implementation details
0207      * @param  mixed $other CSS selector path
0208      * @param  string $description
0209      * @param  bool $not
0210      * @return void
0211      * @throws PHPUnit_Framework_ExpectationFailedException
0212      */
0213     public function fail($other, $description, $not = false)
0214     {
0215         // require_once 'Zend/Test/PHPUnit/Constraint/Exception.php';
0216         switch ($this->_assertType) {
0217             case self::ASSERT_CONTENT_CONTAINS:
0218                 $failure = 'Failed asserting node denoted by %s CONTAINS content "%s"';
0219                 if ($this->_negate) {
0220                     $failure = 'Failed asserting node DENOTED BY %s DOES NOT CONTAIN content "%s"';
0221                 }
0222                 $failure = sprintf($failure, $other, $this->_content);
0223                 break;
0224             case self::ASSERT_CONTENT_REGEX:
0225                 $failure = 'Failed asserting node denoted by %s CONTAINS content MATCHING "%s"';
0226                 if ($this->_negate) {
0227                     $failure = 'Failed asserting node DENOTED BY %s DOES NOT CONTAIN content MATCHING "%s"';
0228                 }
0229                 $failure = sprintf($failure, $other, $this->_content);
0230                 break;
0231             case self::ASSERT_CONTENT_COUNT:
0232                 $failure = 'Failed asserting node DENOTED BY %s OCCURS EXACTLY %d times';
0233                 if ($this->_negate) {
0234                     $failure = 'Failed asserting node DENOTED BY %s DOES NOT OCCUR EXACTLY %d times';
0235                 }
0236                 $failure = sprintf($failure, $other, $this->_content);
0237                 break;
0238             case self::ASSERT_CONTENT_COUNT_MIN:
0239                 $failure = 'Failed asserting node DENOTED BY %s OCCURS AT LEAST %d times';
0240                 $failure = sprintf($failure, $other, $this->_content);
0241                 break;
0242             case self::ASSERT_CONTENT_COUNT_MAX:
0243                 $failure = 'Failed asserting node DENOTED BY %s OCCURS AT MOST %d times';
0244                 $failure = sprintf($failure, $other, $this->_content);
0245                 break;
0246             case self::ASSERT_QUERY:
0247             default:
0248                 $failure = 'Failed asserting node DENOTED BY %s EXISTS';
0249                 if ($this->_negate) {
0250                     $failure = 'Failed asserting node DENOTED BY %s DOES NOT EXIST';
0251                 }
0252                 $failure = sprintf($failure, $other);
0253                 break;
0254         }
0255 
0256         if (!empty($description)) {
0257             $failure = $description . "\n" . $failure;
0258         }
0259 
0260         throw new Zend_Test_PHPUnit_Constraint_Exception($failure);
0261     }
0262 
0263     /**
0264      * Complete implementation
0265      *
0266      * @return string
0267      */
0268     public function toString()
0269     {
0270         return '';
0271     }
0272 
0273     /**
0274      * Register XPath namespaces
0275      *
0276      * @param   array $xpathNamespaces
0277      * @return  void
0278      */
0279     public function registerXpathNamespaces($xpathNamespaces)
0280     {
0281         $this->_xpathNamespaces = $xpathNamespaces;
0282     }
0283 
0284     /**
0285      * Check to see if content is matched in selected nodes
0286      *
0287      * @param  Zend_Dom_Query_Result $result
0288      * @param  string $match Content to match
0289      * @return bool
0290      */
0291     protected function _matchContent($result, $match)
0292     {
0293         $match = (string) $match;
0294 
0295         if (0 == count($result)) {
0296             return false;
0297         }
0298 
0299         foreach ($result as $node) {
0300             $content = $this->_getNodeContent($node);
0301             if (strstr($content, $match)) {
0302                 return true;
0303             }
0304         }
0305 
0306         return false;
0307     }
0308 
0309     /**
0310      * Check to see if content is NOT matched in selected nodes
0311      *
0312      * @param  Zend_Dom_Query_Result $result
0313      * @param  string $match
0314      * @return bool
0315      */
0316     protected function _notMatchContent($result, $match)
0317     {
0318         if (0 == count($result)) {
0319             return true;
0320         }
0321 
0322         foreach ($result as $node) {
0323             $content = $this->_getNodeContent($node);
0324             if (strstr($content, $match)) {
0325                 return false;
0326             }
0327         }
0328 
0329         return true;
0330     }
0331 
0332     /**
0333      * Check to see if content is matched by regex in selected nodes
0334      *
0335      * @param  Zend_Dom_Query_Result $result
0336      * @param  string $pattern
0337      * @return bool
0338      */
0339     protected function _regexContent($result, $pattern)
0340     {
0341         if (0 == count($result)) {
0342             return false;
0343         }
0344 
0345         foreach ($result as $node) {
0346             $content = $this->_getNodeContent($node);
0347             if (preg_match($pattern, $content)) {
0348                 return true;
0349             }
0350         }
0351 
0352         return false;
0353     }
0354 
0355     /**
0356      * Check to see if content is NOT matched by regex in selected nodes
0357      *
0358      * @param  Zend_Dom_Query_Result $result
0359      * @param  string $pattern
0360      * @return bool
0361      */
0362     protected function _notRegexContent($result, $pattern)
0363     {
0364         if (0 == count($result)) {
0365             return true;
0366         }
0367 
0368         foreach ($result as $node) {
0369             $content = $this->_getNodeContent($node);
0370             if (preg_match($pattern, $content)) {
0371                 return false;
0372             }
0373         }
0374 
0375         return true;
0376     }
0377 
0378     /**
0379      * Determine if content count matches criteria
0380      *
0381      * @param  Zend_Dom_Query_Result $result
0382      * @param  int $test Value against which to test
0383      * @param  string $type assertion type
0384      * @return boolean
0385      */
0386     protected function _countContent($result, $test, $type)
0387     {
0388         $count = count($result);
0389 
0390         switch ($type) {
0391             case self::ASSERT_CONTENT_COUNT:
0392                 return ($this->_negate)
0393                     ? ($test != $count)
0394                     : ($test == $count);
0395             case self::ASSERT_CONTENT_COUNT_MIN:
0396                 return ($count >= $test);
0397             case self::ASSERT_CONTENT_COUNT_MAX:
0398                 return ($count <= $test);
0399             default:
0400                 return false;
0401         }
0402     }
0403 
0404     /**
0405      * Get node content, minus node markup tags
0406      *
0407      * @param  DOMNode $node
0408      * @return string
0409      */
0410     protected function _getNodeContent(DOMNode $node)
0411     {
0412         if ($node instanceof DOMAttr) {
0413             return $node->value;
0414         } else {
0415             $doc     = $node->ownerDocument;
0416             $content = $doc->saveXML($node);
0417             $tag     = $node->nodeName;
0418             $regex   = '|</?' . $tag . '[^>]*>|';
0419             return preg_replace($regex, '', $content);
0420         }
0421     }
0422 }