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 }