ExpectationException.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. <?php
  2. /*
  3. * This file is part of the Mink package.
  4. * (c) Konstantin Kudryashov <ever.zet@gmail.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. namespace Behat\Mink\Exception;
  10. use Behat\Mink\Driver\DriverInterface;
  11. use Behat\Mink\Session;
  12. /**
  13. * Exception thrown for failed expectations.
  14. *
  15. * Some specialized child classes are available to customize the error rendering.
  16. *
  17. * @author Konstantin Kudryashov <ever.zet@gmail.com>
  18. */
  19. class ExpectationException extends Exception
  20. {
  21. private $session;
  22. private $driver;
  23. /**
  24. * Initializes exception.
  25. *
  26. * @param string $message optional message
  27. * @param DriverInterface|Session $driver driver instance (or session for BC)
  28. * @param \Exception|null $exception expectation exception
  29. */
  30. public function __construct($message, $driver, \Exception $exception = null)
  31. {
  32. if ($driver instanceof Session) {
  33. @trigger_error('Passing a Session object to the ExpectationException constructor is deprecated as of Mink 1.7. Pass the driver instead.', E_USER_DEPRECATED);
  34. $this->session = $driver;
  35. $this->driver = $driver->getDriver();
  36. } elseif (!$driver instanceof DriverInterface) {
  37. // Trigger an exception as we cannot typehint a disjunction
  38. throw new \InvalidArgumentException('The ExpectationException constructor expects a DriverInterface or a Session.');
  39. } else {
  40. $this->driver = $driver;
  41. }
  42. if (!$message && null !== $exception) {
  43. $message = $exception->getMessage();
  44. }
  45. parent::__construct($message, 0, $exception);
  46. }
  47. /**
  48. * Returns exception message with additional context info.
  49. *
  50. * @return string
  51. */
  52. public function __toString()
  53. {
  54. try {
  55. $pageText = $this->pipeString($this->trimString($this->getContext())."\n");
  56. $string = sprintf("%s\n\n%s%s", $this->getMessage(), $this->getResponseInfo(), $pageText);
  57. } catch (\Exception $e) {
  58. return $this->getMessage();
  59. }
  60. return $string;
  61. }
  62. /**
  63. * Gets the context rendered for this exception.
  64. *
  65. * @return string
  66. */
  67. protected function getContext()
  68. {
  69. return $this->trimBody($this->driver->getContent());
  70. }
  71. /**
  72. * Returns driver.
  73. *
  74. * @return DriverInterface
  75. */
  76. protected function getDriver()
  77. {
  78. return $this->driver;
  79. }
  80. /**
  81. * Returns exception session.
  82. *
  83. * @return Session
  84. *
  85. * @deprecated since 1.7, to be removed in 2.0. Use getDriver and the driver API instead.
  86. */
  87. protected function getSession()
  88. {
  89. if (null === $this->session) {
  90. throw new \LogicException(sprintf('The deprecated method %s cannot be used when passing a driver in the constructor', __METHOD__));
  91. }
  92. @trigger_error(sprintf('The method %s is deprecated as of Mink 1.7 and will be removed in 2.0. Use getDriver and the driver API instead.'));
  93. return $this->session;
  94. }
  95. /**
  96. * Prepends every line in a string with pipe (|).
  97. *
  98. * @param string $string
  99. *
  100. * @return string
  101. */
  102. protected function pipeString($string)
  103. {
  104. return '| '.strtr($string, array("\n" => "\n| "));
  105. }
  106. /**
  107. * Removes response header/footer, letting only <body /> content.
  108. *
  109. * @param string $string response content
  110. *
  111. * @return string
  112. */
  113. protected function trimBody($string)
  114. {
  115. $string = preg_replace(array('/^.*<body>/s', '/<\/body>.*$/s'), array('<body>', '</body>'), $string);
  116. return $string;
  117. }
  118. /**
  119. * Trims string to specified number of chars.
  120. *
  121. * @param string $string response content
  122. * @param int $count trim count
  123. *
  124. * @return string
  125. */
  126. protected function trimString($string, $count = 1000)
  127. {
  128. $string = trim($string);
  129. if ($count < mb_strlen($string)) {
  130. return mb_substr($string, 0, $count - 3).'...';
  131. }
  132. return $string;
  133. }
  134. /**
  135. * Returns response information string.
  136. *
  137. * @return string
  138. */
  139. protected function getResponseInfo()
  140. {
  141. $driver = basename(str_replace('\\', '/', get_class($this->driver)));
  142. $info = '+--[ ';
  143. try {
  144. $info .= 'HTTP/1.1 '.$this->driver->getStatusCode().' | ';
  145. } catch (UnsupportedDriverActionException $e) {
  146. // Ignore the status code when not supported
  147. }
  148. $info .= $this->driver->getCurrentUrl().' | '.$driver." ]\n|\n";
  149. return $info;
  150. }
  151. }