sfTesterResponse.class.php 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. <?php
  2. /*
  3. * This file is part of the symfony package.
  4. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  5. *
  6. * For the full copyright and license information, please view the LICENSE
  7. * file that was distributed with this source code.
  8. */
  9. /**
  10. * sfTesterResponse implements tests for the symfony response object.
  11. *
  12. * @package symfony
  13. * @subpackage test
  14. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  15. * @version SVN: $Id: sfTesterResponse.class.php 12517 2008-11-01 07:10:55Z fabien $
  16. */
  17. class sfTesterResponse extends sfTester
  18. {
  19. protected
  20. $response = null,
  21. $dom = null,
  22. $domCssSelector = null;
  23. /**
  24. * Prepares the tester.
  25. */
  26. public function prepare()
  27. {
  28. }
  29. /**
  30. * Initializes the tester.
  31. */
  32. public function initialize()
  33. {
  34. $this->response = $this->browser->getResponse();
  35. $this->dom = null;
  36. $this->domCssSelector = null;
  37. if (preg_match('/(x|ht)ml/i', $this->response->getContentType(), $matches))
  38. {
  39. $this->dom = new DomDocument('1.0', $this->response->getCharset());
  40. $this->dom->validateOnParse = true;
  41. if ('x' == $matches[1])
  42. {
  43. @$this->dom->loadXML($this->response->getContent());
  44. }
  45. else
  46. {
  47. @$this->dom->loadHTML($this->response->getContent());
  48. }
  49. $this->domCssSelector = new sfDomCssSelector($this->dom);
  50. }
  51. }
  52. /**
  53. * Tests that the response matches a given CSS selector.
  54. *
  55. * @param string $selector The response selector or a sfDomCssSelector object
  56. * @param mixed $value Flag for the selector
  57. * @param array $options Options for the current test
  58. *
  59. * @return sfTestFunctionalBase|sfTester
  60. */
  61. public function checkElement($selector, $value = true, $options = array())
  62. {
  63. if (is_null($this->dom))
  64. {
  65. throw new LogicException('The DOM is not accessible because the browser response content type is not HTML.');
  66. }
  67. if (is_object($selector))
  68. {
  69. $values = $selector->getValues();
  70. }
  71. else
  72. {
  73. $values = $this->domCssSelector->matchAll($selector)->getValues();
  74. }
  75. if (false === $value)
  76. {
  77. $this->tester->is(count($values), 0, sprintf('response selector "%s" does not exist', $selector));
  78. }
  79. else if (true === $value)
  80. {
  81. $this->tester->cmp_ok(count($values), '>', 0, sprintf('response selector "%s" exists', $selector));
  82. }
  83. else if (is_int($value))
  84. {
  85. $this->tester->is(count($values), $value, sprintf('response selector "%s" matches "%s" times', $selector, $value));
  86. }
  87. else if (preg_match('/^(!)?([^a-zA-Z0-9\\\\]).+?\\2[ims]?$/', $value, $match))
  88. {
  89. $position = isset($options['position']) ? $options['position'] : 0;
  90. if ($match[1] == '!')
  91. {
  92. $this->tester->unlike(@$values[$position], substr($value, 1), sprintf('response selector "%s" does not match regex "%s"', $selector, substr($value, 1)));
  93. }
  94. else
  95. {
  96. $this->tester->like(@$values[$position], $value, sprintf('response selector "%s" matches regex "%s"', $selector, $value));
  97. }
  98. }
  99. else
  100. {
  101. $position = isset($options['position']) ? $options['position'] : 0;
  102. $this->tester->is(@$values[$position], $value, sprintf('response selector "%s" matches "%s"', $selector, $value));
  103. }
  104. if (isset($options['count']))
  105. {
  106. $this->tester->is(count($values), $options['count'], sprintf('response selector "%s" matches "%s" times', $selector, $options['count']));
  107. }
  108. return $this->getObjectToReturn();
  109. }
  110. /**
  111. * Tests for a response header.
  112. *
  113. * @param string $key
  114. * @param string $value
  115. *
  116. * @return sfTestFunctionalBase|sfTester
  117. */
  118. public function isHeader($key, $value)
  119. {
  120. $headers = explode(', ', $this->response->getHttpHeader($key));
  121. $ok = false;
  122. $regex = false;
  123. $mustMatch = true;
  124. if (preg_match('/^(!)?([^a-zA-Z0-9\\\\]).+?\\2[ims]?$/', $value, $match))
  125. {
  126. $regex = $value;
  127. if ($match[1] == '!')
  128. {
  129. $mustMatch = false;
  130. $regex = substr($value, 1);
  131. }
  132. }
  133. foreach ($headers as $header)
  134. {
  135. if (false !== $regex)
  136. {
  137. if ($mustMatch)
  138. {
  139. if (preg_match($regex, $header))
  140. {
  141. $ok = true;
  142. $this->tester->pass(sprintf('response header "%s" matches "%s" (%s)', $key, $value, $this->response->getHttpHeader($key)));
  143. break;
  144. }
  145. }
  146. else
  147. {
  148. if (preg_match($regex, $header))
  149. {
  150. $ok = true;
  151. $this->tester->fail(sprintf('response header "%s" does not match "%s" (%s)', $key, $value, $this->response->getHttpHeader($key)));
  152. break;
  153. }
  154. }
  155. }
  156. else if ($header == $value)
  157. {
  158. $ok = true;
  159. $this->tester->pass(sprintf('response header "%s" is "%s" (%s)', $key, $value, $this->response->getHttpHeader($key)));
  160. break;
  161. }
  162. }
  163. if (!$ok)
  164. {
  165. if (!$mustMatch)
  166. {
  167. $this->tester->pass(sprintf('response header "%s" matches "%s" (%s)', $key, $value, $this->response->getHttpHeader($key)));
  168. }
  169. else
  170. {
  171. $this->tester->fail(sprintf('response header "%s" matches "%s" (%s)', $key, $value, $this->response->getHttpHeader($key)));
  172. }
  173. }
  174. return $this->getObjectToReturn();
  175. }
  176. /**
  177. * Tests if a cookie was set.
  178. *
  179. * @param string $name
  180. * @param string $value
  181. * @param array $attributes Other cookie attributes to check (expires, path, domain, etc)
  182. *
  183. * @return sfTestFunctionalBase|sfTester
  184. */
  185. public function setsCookie($name, $value = null, $attributes = array())
  186. {
  187. foreach ($this->response->getCookies() as $cookie)
  188. {
  189. if ($name == $cookie['name'])
  190. {
  191. if (is_null($value))
  192. {
  193. $this->tester->pass(sprintf('response sets cookie "%s"', $name));
  194. }
  195. else
  196. {
  197. $this->tester->ok($value == $cookie['value'], sprintf('response sets cookie "%s" to "%s"', $name, $value));
  198. }
  199. foreach ($attributes as $attributeName => $attributeValue)
  200. {
  201. if (!array_key_exists($attributeName, $cookie))
  202. {
  203. throw new LogicException(sprintf('The cookie attribute "%s" is not valid.', $attributeName));
  204. }
  205. $this->tester->is($cookie[$attributeName], $attributeValue, sprintf('"%s" cookie "%s" attribute is "%s"', $name, $attributeName, $attributeValue));
  206. }
  207. return $this->getObjectToReturn();
  208. }
  209. }
  210. $this->tester->fail(sprintf('response sets cookie "%s"', $name));
  211. return $this->getObjectToReturn();
  212. }
  213. /**
  214. * Tests whether or not a given string is in the response.
  215. *
  216. * @param string Text to check
  217. *
  218. * @return sfTestFunctionalBase|sfTester
  219. */
  220. public function contains($text)
  221. {
  222. $this->tester->like($this->response->getContent(), '/'.preg_quote($text, '/').'/', sprintf('response contains "%s"', substr($text, 0, 40)));
  223. return $this->getObjectToReturn();
  224. }
  225. /**
  226. * Tests the status code.
  227. *
  228. * @param string $statusCode Status code to check, default 200
  229. *
  230. * @return sfTestFunctionalBase|sfTester
  231. */
  232. public function isStatusCode($statusCode = 200)
  233. {
  234. $this->tester->is($this->response->getStatusCode(), $statusCode, sprintf('status code is "%s"', $statusCode));
  235. return $this->getObjectToReturn();
  236. }
  237. /**
  238. * Tests if the current request has been redirected.
  239. *
  240. * @param bool $boolean Flag for redirection mode
  241. *
  242. * @return sfTestFunctionalBase|sfTester
  243. */
  244. public function isRedirected($boolean = true)
  245. {
  246. if ($location = $this->response->getHttpHeader('location'))
  247. {
  248. $boolean ? $this->tester->pass(sprintf('page redirected to "%s"', $location)) : $this->tester->fail(sprintf('page redirected to "%s"', $location));
  249. }
  250. else
  251. {
  252. $boolean ? $this->tester->fail('page redirected') : $this->tester->pass('page not redirected');
  253. }
  254. return $this->getObjectToReturn();
  255. }
  256. /**
  257. * Outputs some debug information about the current response.
  258. */
  259. public function debug()
  260. {
  261. print $this->tester->error('Response debug');
  262. printf("HTTP/1.X %s\n", $this->response->getStatusCode());
  263. foreach ($this->response->getHttpHeaders() as $name => $value)
  264. {
  265. printf("%s: %s\n", $name, $value);
  266. }
  267. foreach ($this->response->getCookies() as $cookie)
  268. {
  269. vprintf("Set-Cookie: %s=%s; %spath=%s%s%s%s\n", array(
  270. $cookie['name'],
  271. $cookie['value'],
  272. is_null($cookie['expire']) ? '' : sprintf('expires=%s; ', date('D d-M-Y H:i:s T', $cookie['expire'])),
  273. $cookie['path'],
  274. $cookie['domain'] ? sprintf('; domain=%s', $cookie['domain']) : '',
  275. $cookie['secure'] ? '; secure' : '',
  276. $cookie['httpOnly'] ? '; HttpOnly' : '',
  277. ));
  278. }
  279. echo "\n";
  280. echo $this->response->getContent();
  281. exit(1);
  282. }
  283. }