/** * Constructor * * @param string|object $actual A fully-namespaced class name or an object instance. * @param string $expected The expected method method name to be called. */ public function __construct($actual, $expected) { $this->_backtrace = Debugger::backtrace(); if (is_string($actual)) { $actual = ltrim($actual, '\\'); } $this->_check($actual); if (!$expected) { throw new InvalidArgumentException("Method name can't be empty."); } $names = is_array($expected) ? $expected : [$expected]; $reference = $actual; if (count($names) > 1) { if (!Stub::registered(Suite::hash($reference))) { throw new InvalidArgumentException("Kahlan can't Spy chained methods on real PHP code, you need to Stub the chain first."); } } $reference = $this->_reference($reference); foreach ($names as $index => $name) { if (preg_match('/^::.*/', $name)) { $reference = is_object($reference) ? get_class($reference) : $reference; } $this->_expected[] = $name; $this->_messages[$name] = $this->_watch(new Message(['parent' => $this, 'reference' => $reference, 'name' => $name])); $reference = null; } }
/** * Constructor * * @param string|object $actual A fully-namespaced class name or an object instance. * @param string $expected The expected method method name to be called. */ public function __construct($actual) { $actual = ltrim($actual, '\\'); $this->_actual = $actual; Suite::register(Suite::hash($actual)); $this->_message = new Message(['name' => $actual]); $this->_backtrace = Debugger::backtrace(); }
/** * Constructor * * @param string|object $actual A fully-namespaced class name or an object instance. * @param string $expected The expected method method name to be called. */ public function __construct($actual, $expected) { if (preg_match('/^::.*/', $expected)) { $actual = is_object($actual) ? get_class($actual) : $actual; } $call = $this->_classes['call']; $this->_actual = $actual; $this->_expected = $expected; $this->_call = new $call($actual); $this->_message = $this->_call->method($expected); $this->_backtrace = Debugger::backtrace(); }
/** * Overrides the default error handler * * @param boolean $enable If `true` override the default error handler, * if `false` restore the default handler. * @param array $options An options array. Available options are: * - 'handler': An error handler closure. * */ protected function _errorHandler($enable, $options = []) { $defaults = ['handler' => null]; $options += $defaults; if (!$enable) { return restore_error_handler(); } $handler = function ($code, $message, $file, $line = 0, $args = []) { $trace = debug_backtrace(); $trace = array_slice($trace, 1, count($trace)); $message = "`" . Debugger::errorType($code) . "` {$message}"; $code = 0; $exception = compact('code', 'message', 'file', 'line', 'trace'); throw new PhpErrorException($exception); }; $options['handler'] = $options['handler'] ?: $handler; set_error_handler($options['handler'], error_reporting()); }
describe("::loader()", function () { it("gets/sets a loader", function () { $loader = Stub::create(); expect(Debugger::loader($loader))->toBe($loader); }); }); describe("::errorType()", function () { it("returns some reader-friendly error type string", function () { expect(Debugger::errorType(E_ERROR))->toBe('E_ERROR'); expect(Debugger::errorType(E_WARNING))->toBe('E_WARNING'); expect(Debugger::errorType(E_PARSE))->toBe('E_PARSE'); expect(Debugger::errorType(E_NOTICE))->toBe('E_NOTICE'); expect(Debugger::errorType(E_CORE_ERROR))->toBe('E_CORE_ERROR'); expect(Debugger::errorType(E_CORE_WARNING))->toBe('E_CORE_WARNING'); expect(Debugger::errorType(E_CORE_ERROR))->toBe('E_CORE_ERROR'); expect(Debugger::errorType(E_COMPILE_ERROR))->toBe('E_COMPILE_ERROR'); expect(Debugger::errorType(E_CORE_WARNING))->toBe('E_CORE_WARNING'); expect(Debugger::errorType(E_COMPILE_WARNING))->toBe('E_COMPILE_WARNING'); expect(Debugger::errorType(E_USER_ERROR))->toBe('E_USER_ERROR'); expect(Debugger::errorType(E_USER_WARNING))->toBe('E_USER_WARNING'); expect(Debugger::errorType(E_USER_NOTICE))->toBe('E_USER_NOTICE'); expect(Debugger::errorType(E_STRICT))->toBe('E_STRICT'); expect(Debugger::errorType(E_RECOVERABLE_ERROR))->toBe('E_RECOVERABLE_ERROR'); expect(Debugger::errorType(E_DEPRECATED))->toBe('E_DEPRECATED'); expect(Debugger::errorType(E_USER_DEPRECATED))->toBe('E_USER_DEPRECATED'); }); it("returns <INVALID> for undefined error type", function () { expect(Debugger::errorType(123456))->toBe('<INVALID>'); }); }); });
/** * Applies focus up to the root. */ protected function _emitFocus() { $this->_root->_focuses[] = Debugger::focus($this->backtraceFocus(), Debugger::backtrace()); $instances = $this->_parents(true); foreach ($instances as $instance) { $instance->focus(); } }
/** * Adds an expectation report and emits a report event. * * @param array $data The report data. */ public function add($type, $data = []) { if ($this->type() === 'passed' && $type === 'failed') { $this->type('failed'); } $data['type'] = $type; if (!isset($data['backtrace'])) { $data['backtrace'] = []; } else { $data['backtrace'] = Debugger::focus($this->scope()->backtraceFocus(), $data['backtrace'], 1); } $child = new static($data + ['scope' => $this->_scope]); $this->_children[] = $child; return $child; }
/** * Logs a result. * * @param boolean $boolean Set `true` for success and `false` for failure. * @param array $data Test details array. * @return boolean */ protected function _log($boolean, $data = []) { $not = $this->_not; $pass = $not ? !$boolean : $boolean; if ($pass) { $data['type'] = 'pass'; } else { $data['type'] = 'fail'; $this->_passed = false; } $description = $data['description']; if (is_array($description)) { $data['params'] = $description['params']; $data['description'] = $description['description']; } $data['backtrace'] = Debugger::backtrace(); $data['not'] = $not; $this->_logs[] = $data; $this->_not = false; return $boolean; }
/** * Helper which extracts the backtrace of a report. * * @param array $data The report data. */ public function _backtrace($data) { if (isset($data['exception'])) { return Debugger::backtrace(['trace' => $data['exception']]); } $type = $data['type']; $depth = $type === 'pass' || $type === 'fail' | $type === 'skip' ? 1 : null; if (!isset($data['backtrace'])) { $data['backtrace'] = []; } return Debugger::focus($this->scope()->backtraceFocus(), $data['backtrace'], $depth); }
/** * Prints focused report to STDOUT * * @param array $report A report array. */ protected function _reportFocused($report) { if (!($backtraces = $report['focuses'])) { return; } $this->write("Focus Mode Detected in the following files:\n", 'b;yellow;'); foreach ($backtraces as $backtrace) { $this->write(Debugger::trace(['trace' => $backtrace, 'depth' => 1]), 'n;yellow'); $this->write("\n"); } $this->write("exit(-1)\n\n", 'red'); }
/** * The Constructor. * * @param array $config The Suite config array. Options are: * -`'type'` _string_ : supported type are `'normal'` & `'focus'`. * -`'message'` _string_ : the description message. * -`'parent'` _object_ : the parent scope. * -`'root'` _object_ : the root scope. * -`'log'` _object_ : the log instance. * -`'timeout'` _integer_: the timeout. */ public function __construct($config = []) { $defaults = ['type' => 'normal', 'message' => '', 'parent' => null, 'root' => null, 'log' => null, 'timeout' => 0, 'summary' => null]; $config += $defaults; $this->_type = $config['type']; $this->_message = $config['message']; $this->_parent = $config['parent']; $this->_root = $this->_parent ? $this->_parent->_root : $this; $this->_timeout = $config['timeout']; $this->_backtrace = Debugger::focus($this->backtraceFocus(), Debugger::backtrace(), 1); $this->_log = $config['log'] ?: new Log(['scope' => $this, 'backtrace' => $this->_backtrace]); $this->_summary = $config['summary']; if ($this->_summary) { return; } if ($this->_root->summary()) { $this->_summary = $this->_root->summary(); } else { $this->_summary = new Summary(); } }