Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Behat\Mink\Exception; Chris@0: Chris@0: use Behat\Mink\Driver\DriverInterface; Chris@0: use Behat\Mink\Session; Chris@0: Chris@0: /** Chris@0: * Exception thrown for failed expectations. Chris@0: * Chris@0: * Some specialized child classes are available to customize the error rendering. Chris@0: * Chris@0: * @author Konstantin Kudryashov Chris@0: */ Chris@0: class ExpectationException extends Exception Chris@0: { Chris@0: private $session; Chris@0: private $driver; Chris@0: Chris@0: /** Chris@0: * Initializes exception. Chris@0: * Chris@0: * @param string $message optional message Chris@0: * @param DriverInterface|Session $driver driver instance (or session for BC) Chris@0: * @param \Exception|null $exception expectation exception Chris@0: */ Chris@0: public function __construct($message, $driver, \Exception $exception = null) Chris@0: { Chris@0: if ($driver instanceof Session) { Chris@0: @trigger_error('Passing a Session object to the ExpectationException constructor is deprecated as of Mink 1.7. Pass the driver instead.', E_USER_DEPRECATED); Chris@0: Chris@0: $this->session = $driver; Chris@0: $this->driver = $driver->getDriver(); Chris@0: } elseif (!$driver instanceof DriverInterface) { Chris@0: // Trigger an exception as we cannot typehint a disjunction Chris@0: throw new \InvalidArgumentException('The ExpectationException constructor expects a DriverInterface or a Session.'); Chris@0: } else { Chris@0: $this->driver = $driver; Chris@0: } Chris@0: Chris@0: if (!$message && null !== $exception) { Chris@0: $message = $exception->getMessage(); Chris@0: } Chris@0: Chris@0: parent::__construct($message, 0, $exception); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns exception message with additional context info. Chris@0: * Chris@0: * @return string Chris@0: */ Chris@0: public function __toString() Chris@0: { Chris@0: try { Chris@0: $pageText = $this->pipeString($this->trimString($this->getContext())."\n"); Chris@0: $string = sprintf("%s\n\n%s%s", $this->getMessage(), $this->getResponseInfo(), $pageText); Chris@0: } catch (\Exception $e) { Chris@0: return $this->getMessage(); Chris@0: } Chris@0: Chris@0: return $string; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets the context rendered for this exception. Chris@0: * Chris@0: * @return string Chris@0: */ Chris@0: protected function getContext() Chris@0: { Chris@0: return $this->trimBody($this->driver->getContent()); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns driver. Chris@0: * Chris@0: * @return DriverInterface Chris@0: */ Chris@0: protected function getDriver() Chris@0: { Chris@0: return $this->driver; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns exception session. Chris@0: * Chris@0: * @return Session Chris@0: * Chris@0: * @deprecated since 1.7, to be removed in 2.0. Use getDriver and the driver API instead. Chris@0: */ Chris@0: protected function getSession() Chris@0: { Chris@0: if (null === $this->session) { Chris@0: throw new \LogicException(sprintf('The deprecated method %s cannot be used when passing a driver in the constructor', __METHOD__)); Chris@0: } Chris@0: Chris@0: @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.', __METHOD__), E_USER_DEPRECATED); Chris@0: Chris@0: return $this->session; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Prepends every line in a string with pipe (|). Chris@0: * Chris@0: * @param string $string Chris@0: * Chris@0: * @return string Chris@0: */ Chris@0: protected function pipeString($string) Chris@0: { Chris@0: return '| '.strtr($string, array("\n" => "\n| ")); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Removes response header/footer, letting only content. Chris@0: * Chris@0: * @param string $string response content Chris@0: * Chris@0: * @return string Chris@0: */ Chris@0: protected function trimBody($string) Chris@0: { Chris@0: $string = preg_replace(array('/^.*/s', '/<\/body>.*$/s'), array('', ''), $string); Chris@0: Chris@0: return $string; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Trims string to specified number of chars. Chris@0: * Chris@0: * @param string $string response content Chris@0: * @param int $count trim count Chris@0: * Chris@0: * @return string Chris@0: */ Chris@0: protected function trimString($string, $count = 1000) Chris@0: { Chris@0: $string = trim($string); Chris@0: Chris@0: if ($count < mb_strlen($string)) { Chris@0: return mb_substr($string, 0, $count - 3).'...'; Chris@0: } Chris@0: Chris@0: return $string; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns response information string. Chris@0: * Chris@0: * @return string Chris@0: */ Chris@0: protected function getResponseInfo() Chris@0: { Chris@0: $driver = basename(str_replace('\\', '/', get_class($this->driver))); Chris@0: Chris@0: $info = '+--[ '; Chris@0: try { Chris@0: $info .= 'HTTP/1.1 '.$this->driver->getStatusCode().' | '; Chris@0: } catch (UnsupportedDriverActionException $e) { Chris@0: // Ignore the status code when not supported Chris@0: } Chris@0: $info .= $this->driver->getCurrentUrl().' | '.$driver." ]\n|\n"; Chris@0: Chris@0: return $info; Chris@0: } Chris@0: }