.State 0000666 00000000012 13371317322 0005624 0 ustar 00 finalized
.gitignore 0000666 00000000030 13371317322 0006533 0 ustar 00 /vendor/
/composer.lock
CHANGELOG.md 0000666 00000002727 13371317322 0006373 0 ustar 00 # 1.17.01.16
* Quality: Happy new year! (Ivan Enderlin, 2017-01-16T08:52:04+01:00)
# 1.16.11.08
* Documentation: New `README.md` file. (Ivan Enderlin, 2016-10-19T16:31:55+02:00)
* Documentation: Update `support` properties. (Ivan Enderlin, 2016-10-05T20:39:14+02:00)
# 1.16.01.11
* Quality: Drop PHP5.4. (Ivan Enderlin, 2016-01-11T09:15:26+01:00)
* Quality: Run devtools:cs. (Ivan Enderlin, 2016-01-09T09:01:35+01:00)
* Core: Remove `Hoa\Core`. (Ivan Enderlin, 2016-01-09T08:16:03+01:00)
* Consistency: Use `Hoa\Consistency`. (Ivan Enderlin, 2015-12-08T11:11:27+01:00)
# 0.15.11.23
* Fix phpDoc and a mistake on a static call. (Metalaka, 2015-11-21T17:44:35+01:00)
* Add a `.gitignore` file. (Metalaka, 2015-11-21T17:39:21+01:00)
* Test: Add test cases for the uncaught handler. (Ivan Enderlin, 2015-11-18T21:48:20+01:00)
* Idle: Add uncaught handler. (Ivan Enderlin, 2015-11-18T21:47:40+01:00)
* README: Add a better description and new usages. (Ivan Enderlin, 2015-11-18T21:36:03+01:00)
* Test: Write test suite of `Hoa\Exception\Group`. (Ivan Enderlin, 2015-11-18T08:28:04+01:00)
* Test: Write test suite of `Hoa\Exception\Error`. (Ivan Enderlin, 2015-11-17T22:30:14+01:00)
* Test: Write test suite of `…\Exception\Exception`. (Ivan Enderlin, 2015-11-17T22:03:31+01:00)
* Test: Write test suite of `Hoa\Exception\Idle`. (Ivan Enderlin, 2015-11-17T21:41:07+01:00)
* Split from `Hoa\Core`. (Ivan Enderlin, 2015-11-13T08:58:45+01:00)
(first snapshot)
Error.php 0000666 00000006215 13371317322 0006360 0 ustar 00 file = $file;
$this->line = $line;
$this->_trace = $trace;
parent::__construct($message, $code);
return;
}
/**
* Enable error handler: Transform PHP error into `\Hoa\Exception\Error`.
*
* @param bool $enable Enable.
* @return mixed
*/
public static function enableErrorHandler($enable = true)
{
if (false === $enable) {
return restore_error_handler();
}
return set_error_handler(
function ($no, $str, $file = null, $line = null, $ctx = null) {
if (0 === ($no & error_reporting())) {
return;
}
$trace = debug_backtrace();
array_shift($trace);
array_shift($trace);
throw new Error($str, $no, $file, $line, $trace);
}
);
}
}
Exception.php 0000666 00000006233 13371317322 0007225 0 ustar 00 send();
return;
}
/**
* Send the exception on hoa://Event/Exception.
*
* @return void
*/
public function send()
{
Event::notify(
'hoa://Event/Exception',
$this,
new Event\Bucket($this)
);
return;
}
}
/**
* Flex entity.
*/
Consistency::flexEntity('Hoa\Exception\Exception');
Group.php 0000666 00000015457 13371317322 0006373 0 ustar 00 _group = new \SplStack();
$this->beginTransaction();
return;
}
/**
* Raise an exception as a string.
*
* @param bool $previous Whether raise previous exception if exists.
* @return string
*/
public function raise($previous = false)
{
$out = parent::raise($previous);
if (0 >= count($this)) {
return $out;
}
$out .= "\n\n" . 'Contains the following exceptions:';
foreach ($this as $exception) {
$out .=
"\n\n" . ' • ' .
str_replace(
"\n",
"\n" . ' ',
$exception->raise($previous)
);
}
return $out;
}
/**
* Begin a transaction.
*
* @return \Hoa\Exception\Group
*/
public function beginTransaction()
{
$this->_group->push(new \ArrayObject());
return $this;
}
/**
* Rollback a transaction.
*
* @return \Hoa\Exception\Group
*/
public function rollbackTransaction()
{
if (1 >= count($this->_group)) {
return $this;
}
$this->_group->pop();
return $this;
}
/**
* Commit a transaction.
*
* @return \Hoa\Exception\Group
*/
public function commitTransaction()
{
if (false === $this->hasUncommittedExceptions()) {
$this->_group->pop();
return $this;
}
foreach ($this->_group->pop() as $index => $exception) {
$this[$index] = $exception;
}
return $this;
}
/**
* Check if there is uncommitted exceptions.
*
* @return bool
*/
public function hasUncommittedExceptions()
{
return
1 < count($this->_group) &&
0 < count($this->_group->top());
}
/**
* Check if an index in the group exists.
*
* @param mixed $index Index.
* @return bool
*/
public function offsetExists($index)
{
foreach ($this->_group as $group) {
if (isset($group[$index])) {
return true;
}
}
return false;
}
/**
* Get an exception from the group.
*
* @param mixed $index Index.
* @return Exception
*/
public function offsetGet($index)
{
foreach ($this->_group as $group) {
if (isset($group[$index])) {
return $group[$index];
}
}
return null;
}
/**
* Set an exception in the group.
*
* @param mixed $index Index.
* @param Exception $exception Exception.
* @return void
*/
public function offsetSet($index, $exception)
{
if (!($exception instanceof \Exception)) {
return null;
}
$group = $this->_group->top();
if (null === $index ||
true === is_int($index)) {
$group[] = $exception;
} else {
$group[$index] = $exception;
}
return;
}
/**
* Remove an exception in the group.
*
* @param mixed $index Index.
* @return void
*/
public function offsetUnset($index)
{
foreach ($this->_group as $group) {
if (isset($group[$index])) {
unset($group[$index]);
}
}
return;
}
/**
* Get committed exceptions in the group.
*
* @return \ArrayObject
*/
public function getExceptions()
{
return $this->_group->bottom();
}
/**
* Get an iterator over all exceptions (committed or not).
*
* @return \ArrayIterator
*/
public function getIterator()
{
return $this->getExceptions()->getIterator();
}
/**
* Count the number of committed exceptions.
*
* @return int
*/
public function count()
{
return count($this->getExceptions());
}
/**
* Count the stack size, i.e. the number of opened transactions.
*
* @return int
*/
public function getStackSize()
{
return count($this->_group);
}
}
Idle.php 0000666 00000020030 13371317322 0006133 0 ustar 00 _tmpArguments = $arguments;
parent::__construct($message, $code, $previous);
$this->_rawMessage = $message;
$this->message = @vsprintf($message, $this->getArguments());
return;
}
/**
* Get the backtrace.
* Do not use \Exception::getTrace() any more.
*
* @return array
*/
public function getBacktrace()
{
if (null === $this->_trace) {
$this->_trace = $this->getTrace();
}
return $this->_trace;
}
/**
* Get previous.
* Do not use \Exception::getPrevious() any more.
*
* @return \Exception
*/
public function getPreviousThrow()
{
if (null === $this->_previous) {
$this->_previous = $this->getPrevious();
}
return $this->_previous;
}
/**
* Get arguments for the message.
*
* @return array
*/
public function getArguments()
{
if (null === $this->_arguments) {
$arguments = $this->_tmpArguments;
if (!is_array($arguments)) {
$arguments = [$arguments];
}
foreach ($arguments as &$value) {
if (null === $value) {
$value = '(null)';
}
}
$this->_arguments = $arguments;
unset($this->_tmpArguments);
}
return $this->_arguments;
}
/**
* Get the raw message.
*
* @return string
*/
public function getRawMessage()
{
return $this->_rawMessage;
}
/**
* Get the message already formatted.
*
* @return string
*/
public function getFormattedMessage()
{
return $this->getMessage();
}
/**
* Get the source of the exception (class, method, function, main etc.).
*
* @return string
*/
public function getFrom()
{
$trace = $this->getBacktrace();
$from = '{main}';
if (!empty($trace)) {
$t = $trace[0];
$from = '';
if (isset($t['class'])) {
$from .= $t['class'] . '::';
}
if (isset($t['function'])) {
$from .= $t['function'] . '()';
}
}
return $from;
}
/**
* Raise an exception as a string.
*
* @param bool $previous Whether raise previous exception if exists.
* @return string
*/
public function raise($previous = false)
{
$message = $this->getFormattedMessage();
$trace = $this->getBacktrace();
$file = '/dev/null';
$line = -1;
$pre = $this->getFrom();
if (!empty($trace)) {
$file = isset($trace['file']) ? $trace['file'] : null;
$line = isset($trace['line']) ? $trace['line'] : null;
}
$pre .= ': ';
try {
$out =
$pre . '(' . $this->getCode() . ') ' . $message . "\n" .
'in ' . $this->getFile() . ' at line ' .
$this->getLine() . '.';
} catch (\Exception $e) {
$out =
$pre . '(' . $this->getCode() . ') ' . $message . "\n" .
'in ' . $file . ' around line ' . $line . '.';
}
if (true === $previous &&
null !== $previous = $this->getPreviousThrow()) {
$out .=
"\n\n" . ' ⬇' . "\n\n" .
'Nested exception (' . get_class($previous) . '):' . "\n" .
($previous instanceof self
? $previous->raise(true)
: $previous->getMessage());
}
return $out;
}
/**
* Catch uncaught exception (only \Hoa\Exception\Idle and children).
*
* @param \Throwable $exception The exception.
* @return void
* @throws \Throwable
*/
public static function uncaught($exception)
{
if (!($exception instanceof self)) {
throw $exception;
}
while (0 < ob_get_level()) {
ob_end_flush();
}
echo
'Uncaught exception (' . get_class($exception) . '):' . "\n" .
$exception->raise(true);
return;
}
/**
* String representation of object.
*
* @return string
*/
public function __toString()
{
return $this->raise();
}
/**
* Enable uncaught exception handler.
* This is restricted to Hoa's exceptions only.
*
* @param bool $enable Enable.
* @return mixed
*/
public static function enableUncaughtHandler($enable = true)
{
if (false === $enable) {
return restore_exception_handler();
}
return set_exception_handler(function ($exception) {
return self::uncaught($exception);
});
}
}
README.md 0000666 00000016501 13371317322 0006034 0 ustar 00
---
Hoa is a modular, extensible and
structured set of PHP libraries.
Moreover, Hoa aims at being a bridge between industrial and research worlds.
# Hoa\Exception
[![Help on IRC](https://img.shields.io/badge/help-%23hoaproject-ff0066.svg)](https://webchat.freenode.net/?channels=#hoaproject)
[![Help on Gitter](https://img.shields.io/badge/help-gitter-ff0066.svg)](https://gitter.im/hoaproject/central)
[![Documentation](https://img.shields.io/badge/documentation-hack_book-ff0066.svg)](https://central.hoa-project.net/Documentation/Library/Exception)
[![Board](https://img.shields.io/badge/organisation-board-ff0066.svg)](https://waffle.io/hoaproject/exception)
This library allows to use advanced exceptions. It provides generic exceptions
(that are sent over the `hoa://Event/Exception` event channel), idle exceptions
(that are not sent over an event channel), uncaught exception handlers, errors
to exceptions handler and group of exceptions (with transactions).
[Learn more](https://central.hoa-project.net/Documentation/Library/Exception).
## Installation
With [Composer](https://getcomposer.org/), to include this library into
your dependencies, you need to
require [`hoa/exception`](https://packagist.org/packages/hoa/exception):
```sh
$ composer require hoa/exception '~1.0'
```
For more installation procedures, please read [the Source
page](https://hoa-project.net/Source.html).
## Testing
Before running the test suites, the development dependencies must be installed:
```sh
$ composer install
```
Then, to run all the test suites:
```sh
$ vendor/bin/hoa test:run
```
For more information, please read the [contributor
guide](https://hoa-project.net/Literature/Contributor/Guide.html).
## Quick usage
We propose a quick overview of how to use generic exceptions, how to listen all
thrown exceptions through events and how to use group of exceptions.
### Generic exceptions
An exception is constitued of:
* A message,
* A code (optional),
* A list of arguments for the message (à la `printf`, optional),
* A previous exception (optional).
Thus, the following example builds an exception:
```php
$exception = new Hoa\Exception\Exception('Hello %s!', 0, 'world');
```
The exception message will be: `Hello world!`. The “raise” message (with all
information, not only the message) is:
```
{main}: (0) Hello world!
in … at line ….
```
Previous exceptions are shown too, for instance:
```php
$previous = new Hoa\Exception\Exception('Hello previous.');
$exception = new Hoa\Exception\Exception('Hello %s!', 0, 'world', $previous);
echo $exception->raise(true);
/**
* Will output:
* {main}: (0) Hello world!
* in … at line ….
*
* ⬇
*
* Nested exception (Hoa\Exception\Exception):
* {main}: (0) Hello previous.
* in … at line ….
*/
```
### Listen exceptions through events
Most exceptions in Hoa extend `Hoa\Exception\Exception`, which fire themselves
on the `hoa://Event/Exception` event channel (please, see [the `Hoa\Event`
library](http://central.hoa-project.net/Resource/Library/Event)). Consequently,
we can listen for all exceptions that are thrown in the application by writing:
```php
Hoa\Event\Event::getEvent('hoa://Event/Exception')->attach(
function (Hoa\Event\Bucket $bucket) {
$exception = $bucket->getData();
// …
}
);
```
Only the `Hoa\Exception\Idle` exceptions are not fired on the channel event.
### Group and transactions
Groups of exceptions are represented by the `Hoa\Exception\Group`. A group is an
exception that contains one or many exceptions. A transactional API is provided
to add more exceptions in the group with the following methods:
* `beginTransaction` to start a transaction,
* `rollbackTransaction` to remove all newly added exceptions since
`beginTransaction` call,
* `commitTransaction` to merge all newly added exceptions in the previous
transaction,
* `hasUncommittedExceptions` to check whether they are pending exceptions or
not.
For instance, if an exceptional behavior is due to several reasons, a group of
exceptions can be thrown instead of one exception. Group can be nested too,
which is useful to represent a tree of exceptions. Thus:
```php
// A group of exceptions.
$group = new Hoa\Exception\Group('Failed because of several reasons.');
$group['first'] = new Hoa\Exception\Exception('First reason');
$group['second'] = new Hoa\Exception\Exception('Second reason');
// Can nest another group.
$group['third'] = new Hoa\Exception\Group('Third reason');
$group['third']['fourth'] = new Hoa\Exception\Exception('Fourth reason');
echo $group->raise(true);
/**
* Will output:
* {main}: (0) Failed because of several reasons.
* in … at line ….
*
* Contains the following exceptions:
*
* • {main}: (0) First reason
* in … at line ….
*
* • {main}: (0) Second reason
* in … at line ….
*
* • {main}: (0) Third reason
* in … at line ….
*
* Contains the following exceptions:
*
* • {main}: (0) Fourth reason
* in … at line ….
*/
```
The following example uses a transaction to add new exceptions in the group:
```php
$group = new Hoa\Exception\Group('Failed because of several reasons.');
$group[] = new Hoa\Exception\Exception('Always present.');
$group->beginTransaction();
$group[] = new Hoa\Exception\Exception('Might be present.');
if (true === $condition) {
$group->commitTransaction();
} else {
$group->rollbackTransaction();
}
```
## Documentation
The
[hack book of `Hoa\Exception`](https://central.hoa-project.net/Documentation/Library/Exception)
contains detailed information about how to use this library and how it works.
To generate the documentation locally, execute the following commands:
```sh
$ composer require --dev hoa/devtools
$ vendor/bin/hoa devtools:documentation --open
```
More documentation can be found on the project's website:
[hoa-project.net](https://hoa-project.net/).
## Getting help
There are mainly two ways to get help:
* On the [`#hoaproject`](https://webchat.freenode.net/?channels=#hoaproject)
IRC channel,
* On the forum at [users.hoa-project.net](https://users.hoa-project.net).
## Contribution
Do you want to contribute? Thanks! A detailed [contributor
guide](https://hoa-project.net/Literature/Contributor/Guide.html) explains
everything you need to know.
## License
Hoa is under the New BSD License (BSD-3-Clause). Please, see
[`LICENSE`](https://hoa-project.net/LICENSE) for details.
Test/Unit/Error.php 0000666 00000012070 13371317322 0010212 0 ustar 00 when($result = new SUT('foo', 42, '/hoa/flatland', 153))
->then
->object($result)
->isInstanceOf('Hoa\Exception\Exception');
}
public function case_get_message()
{
$this
->given($exception = new SUT('foo', 42, '/hoa/flatland', 153))
->when($result = $exception->raise())
->then
->string($result)
->isEqualTo(
'{main}: (42) foo' . "\n" .
'in /hoa/flatland at line 153.'
);
}
public function case_disable_error_handler()
{
$this
->given(
$this->function->restore_error_handler = function () use (&$called) {
$called = true;
return null;
}
)
->when($result = SUT::enableErrorHandler(false))
->then
->variable($result)
->isNull()
->boolean($called)
->isTrue();
}
public function case_enable_error_handler()
{
$self = $this;
$this
->given(
$this->function->set_error_handler = function ($handler) use ($self, &$called) {
$called = true;
$self
->object($handler)
->isInstanceOf('Closure')
->let($reflection = new \ReflectionObject($handler))
->array($invokeParameters = $reflection->getMethod('__invoke')->getParameters())
->hasSize(5)
->string($invokeParameters[0]->getName())
->isEqualTo('no')
->string($invokeParameters[1]->getName())
->isEqualTo('str')
->string($invokeParameters[2]->getName())
->isEqualTo('file')
->boolean($invokeParameters[2]->isOptional())
->isTrue()
->string($invokeParameters[3]->getName())
->isEqualTo('line')
->boolean($invokeParameters[3]->isOptional())
->isTrue()
->string($invokeParameters[4]->getName())
->isEqualTo('ctx')
->boolean($invokeParameters[4]->isOptional())
->isTrue();
return null;
}
)
->when($result = SUT::enableErrorHandler())
->then
->variable($result)
->isNull()
->boolean($called)
->isTrue();
}
public function case_error_handler()
{
$this
->given(SUT::enableErrorHandler())
->exception(function () {
++$i;
})
->isInstanceOf('Hoa\Exception\Error')
->hasMessage('Undefined variable: i');
}
}
Test/Unit/Exception.php 0000666 00000006442 13371317322 0011065 0 ustar 00 when($result = new SUT('foo'))
->then
->object($result)
->isInstanceOf('Hoa\Exception\Idle');
}
public function case_event_is_registered()
{
$this
->given(new SUT('foo'))
->when($result = Event::eventExists('hoa://Event/Exception'))
->then
->boolean($result)
->isTrue();
}
public function case_event_is_sent()
{
$self = $this;
$this
->given(
Event::getEvent('hoa://Event/Exception')->attach(
function (Event\Bucket $bucket) use ($self, &$called) {
$called = true;
$self
->object($bucket->getSource())
->isInstanceOf('Hoa\Exception\Exception')
->string($bucket->getSource()->getMessage())
->isEqualTo('foo')
->object($bucket->getData())
->isIdenticalTo($bucket->getSource());
}
)
)
->when(new SUT('foo'))
->then
->boolean($called)
->isTrue();
}
}
Test/Unit/Group.php 0000666 00000046745 13371317322 0010235 0 ustar 00 when($result = new SUT('foo'))
->then
->object($result)
->isInstanceOf('Hoa\Exception\Exception')
->isInstanceOf('ArrayAccess')
->isInstanceOf('IteratorAggregate')
->isInstanceOf('Countable');
}
public function case_constructor()
{
$this
->given(
$message = 'foo %s %d %s',
$code = 7,
$arguments = ['arg', 42, null],
$previous = new SUT('previous')
)
->when($result = new SUT($message, $code, $arguments, $previous), $line = __LINE__)
->then
->string($result->getMessage())
->isEqualTo('foo arg 42 (null)')
->integer($result->getCode())
->isEqualTo(7)
->array($result->getArguments())
->isEqualTo(['arg', 42, '(null)'])
->object($result->getPreviousThrow())
->isIdenticalTo($previous)
->boolean($result->hasUncommittedExceptions())
->isFalse();
}
public function case_raise_zero_exception()
{
$this
->given($group = new SUT('foo'), $line = __LINE__)
->when($result = $group->raise())
->then
->string($result)
->isEqualTo(
__METHOD__ . '(): (0) foo' . "\n" .
'in ' . __FILE__ . ' at line ' . $line . '.'
);
}
public function case_raise_one_exception()
{
$this
->given(
$exception1 = new SUT('bar'), $barLine = __LINE__,
$group = new SUT('foo'), $fooLine = __LINE__,
$group[] = $exception1
)
->when($result = $group->raise())
->then
->string($result)
->isEqualTo(
__METHOD__ . '(): (0) foo' . "\n" .
'in ' . __FILE__ . ' at line ' . $fooLine . '.' . "\n\n" .
'Contains the following exceptions:' . "\n\n" .
' • ' . __METHOD__ . '(): (0) bar' . "\n" .
' in ' . __FILE__ . ' at line ' . $barLine . '.'
);
}
public function case_raise_more_exceptions()
{
$this
->given(
$exception1 = new SUT('bar'), $barLine = __LINE__,
$exception2 = new SUT('baz'), $bazLine = __LINE__,
$group = new SUT('foo'), $fooLine = __LINE__,
$group[] = $exception1,
$group[] = $exception2
)
->when($result = $group->raise())
->then
->string($result)
->isEqualTo(
__METHOD__ . '(): (0) foo' . "\n" .
'in ' . __FILE__ . ' at line ' . $fooLine . '.' . "\n\n" .
'Contains the following exceptions:' . "\n\n" .
' • ' . __METHOD__ . '(): (0) bar' . "\n" .
' in ' . __FILE__ . ' at line ' . $barLine . '.' . "\n\n" .
' • ' . __METHOD__ . '(): (0) baz' . "\n" .
' in ' . __FILE__ . ' at line ' . $bazLine . '.'
);
}
public function case_begin_transaction()
{
$this
->given(
$group = new SUT('foo'),
$oldStackSize = $group->getStackSize()
)
->when(
$result = $group->beginTransaction(),
$stackSize = $group->getStackSize()
)
->then
->integer($oldStackSize)
->isEqualTo(1)
->object($result)
->isIdenticalTo($group)
->integer($stackSize)
->isEqualTo($oldStackSize + 1);
}
public function case_rollback_transaction_with_an_empty_stack()
{
$this
->given(
$group = new SUT('foo'),
$oldStackSize = $group->getStackSize()
)
->when(
$result = $group->rollbackTransaction(),
$stackSize = $group->getStackSize()
)
->then
->integer($oldStackSize)
->isEqualTo(1)
->object($result)
->isIdenticalTo($group)
->integer($stackSize)
->isEqualTo($oldStackSize);
}
public function case_rollback_transaction()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction(),
$group->beginTransaction(),
$oldStackSize = $group->getStackSize(),
$group->rollbackTransaction()
)
->when(
$result = $group->rollbackTransaction(),
$stackSize = $group->getStackSize()
)
->then
->integer($oldStackSize)
->isEqualTo(3)
->object($result)
->isIdenticalTo($group)
->integer($stackSize)
->isEqualTo($oldStackSize - 2);
}
public function case_commit_transaction_with_an_empty_stack()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction(),
$oldCount = count($group),
$oldStackSize = $group->getStackSize()
)
->when(
$result = $group->commitTransaction(),
$count = count($group),
$stackSize = $group->getStackSize()
)
->then
->integer($oldCount)
->isEqualTo(0)
->integer($oldStackSize)
->isEqualTo(2)
->object($result)
->isIdenticalTo($group)
->integer($count)
->isEqualTo($oldCount)
->integer($stackSize)
->isEqualTo($oldStackSize - 1);
}
public function case_commit_transaction()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction(),
$exception1 = new SUT('bar'),
$exception2 = new SUT('baz'),
$group[] = $exception1,
$group[] = $exception2,
$oldCount = count($group),
$oldStackSize = $group->getStackSize()
)
->when(
$result = $group->commitTransaction(),
$count = count($group),
$stackSize = $group->getStackSize()
)
->then
->integer($oldCount)
->isEqualTo(0)
->integer($oldStackSize)
->isEqualTo(2)
->object($result)
->isIdenticalTo($group)
->integer($count)
->isEqualTo($oldCount + 2)
->integer($stackSize)
->isEqualTo($oldStackSize - 1)
->array(iterator_to_array($group->getIterator()))
->isEqualTo([
0 => $exception1,
1 => $exception2
]);
}
public function case_has_uncommitted_exceptions()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction(),
$group[] = new SUT('bar')
)
->when($result = $group->hasUncommittedExceptions())
->then
->boolean($result)
->isTrue();
}
public function case_has_no_uncommitted_exceptions()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction()
)
->when($result = $group->hasUncommittedExceptions())
->then
->boolean($result)
->isFalse();
}
public function case_has_no_uncommitted_exceptions_with_empty_stack()
{
$this
->given(
$group = new SUT('foo'),
$group[] = new SUT('bar')
)
->when($result = $group->hasUncommittedExceptions())
->then
->boolean($result)
->isFalse();
}
public function case_offset_exists_with_no_uncommited_exceptions()
{
$this
->given(
$group = new SUT('foo'),
$group['bar'] = new SUT('bar')
)
->when($result = $group->offsetExists('bar'))
->then
->boolean($result)
->isTrue();
}
public function case_offset_does_not_exist_with_no_uncommited_exceptions()
{
$this
->given(
$group = new SUT('foo'),
$group['bar'] = new SUT('bar')
)
->when($result = $group->offsetExists('baz'))
->then
->boolean($result)
->isFalse();
}
public function case_offset_exists()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction(),
$group->beginTransaction(),
$group['bar'] = new SUT('bar')
)
->when($result = $group->offsetExists('bar'))
->then
->boolean($result)
->isTrue();
}
public function case_offset_does_not_exist()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction(),
$group->beginTransaction(),
$group['bar'] = new SUT('bar')
)
->when($result = $group->offsetExists('baz'))
->then
->boolean($result)
->isFalse();
}
public function case_offset_get_with_no_uncommited_exceptions()
{
$this
->given(
$group = new SUT('foo'),
$exception1 = new SUT('bar'),
$group['bar'] = $exception1
)
->when($result = $group->offsetGet('bar'))
->then
->object($result)
->isIdenticalTo($exception1);
}
public function case_offset_get_does_not_exist_with_no_uncommited_exceptions()
{
$this
->given(
$group = new SUT('foo'),
$exception1 = new SUT('bar'),
$group['bar'] = $exception1
)
->when($result = $group->offsetGet('baz'))
->then
->variable($result)
->isNull();
}
public function case_offset_get()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction(),
$group->beginTransaction(),
$exception1 = new SUT('bar'),
$group['bar'] = $exception1
)
->when($result = $group->offsetGet('bar'))
->then
->object($result)
->isIdenticalTo($exception1);
}
public function case_offset_get_does_not_exist()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction(),
$group->beginTransaction(),
$exception1 = new SUT('bar'),
$group['bar'] = $exception1
)
->when($result = $group->offsetGet('baz'))
->then
->variable($result)
->isNull();
}
public function case_offset_set_not_an_exception()
{
$this
->given($group = new SUT('foo'))
->when($group->offsetSet('bar', new \StdClass()))
->then
->boolean($group->offsetExists('bar'))
->isFalse();
}
public function case_offset_set()
{
$this
->given(
$group = new SUT('foo'),
$exception1 = new SUT('bar')
)
->when($result = $group->offsetExists('bar'))
->then
->boolean($result)
->isFalse()
->when($group->offsetSet('bar', $exception1))
->then
->boolean($group->offsetExists('bar'))
->isTrue()
->object($group->offsetGet('bar'))
->isIdenticalTo($exception1);
}
public function case_offset_set_with_a_null_index()
{
$this
->given(
$group = new SUT('foo'),
$exception1 = new SUT('bar')
)
->when($group->offsetSet(null, $exception1))
->then
->boolean($group->offsetExists(0))
->isTrue()
->object($group->offsetGet(0))
->isIdenticalTo($exception1);
}
public function case_offset_set_with_an_integer_index()
{
$this
->given(
$group = new SUT('foo'),
$exception1 = new SUT('bar')
)
->when($group->offsetSet(42, $exception1))
->then
->boolean($group->offsetExists(42))
->isFalse()
->boolean($group->offsetExists(0))
->isTrue()
->object($group->offsetGet(0))
->isIdenticalTo($exception1);
}
public function case_offset_unset_with_no_uncommited_exceptions()
{
$this
->given(
$group = new SUT('foo'),
$group['bar'] = new SUT('bar')
)
->when($group->offsetUnset('bar'))
->then
->boolean($group->offsetExists('bar'))
->isFalse();
}
public function case_offset_unset_does_not_exist_with_no_uncommited_exceptions()
{
$this
->given($group = new SUT('foo'))
->when($group->offsetUnset('bar'))
->then
->boolean($group->offsetExists('bar'))
->isFalse();
}
public function case_offset_unset()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction(),
$group->beginTransaction(),
$group['bar'] = new SUT('bar')
)
->when($result = $group->offsetUnset('bar'))
->then
->boolean($group->offsetExists('bar'))
->isFalse();
}
public function case_offset_unset_does_not_exist()
{
$this
->given(
$group = new SUT('foo'),
$group->beginTransaction(),
$group->beginTransaction()
)
->when($result = $group->offsetUnset('bar'))
->then
->boolean($group->offsetExists('bar'))
->isFalse();
}
public function case_get_exceptions()
{
$this
->given(
$group = new SUT('foo'),
$exception1 = new SUT('bar'),
$exception2 = new SUT('baz'),
$group['bar'] = $exception1,
$group->beginTransaction(),
$group['baz'] = $exception2
)
->when($result = $group->getExceptions())
->then
->object($result)
->isInstanceOf('ArrayObject')
->object($result['bar'])
->isIdenticalTo($exception1);
}
public function case_get_iterator()
{
$this
->given(
$group = new SUT('foo'),
$exception1 = new SUT('bar'),
$group['bar'] = $exception1
)
->when($result = $group->getIterator())
->then
->object($result)
->isInstanceOf('ArrayIterator')
->array(iterator_to_array($result))
->isEqualTo([
'bar' => $exception1
]);
}
public function case_count()
{
$this
->given(
$group = new SUT('foo'),
$exception1 = new SUT('bar'),
$exception2 = new SUT('baz'),
$group['bar'] = $exception1,
$group->beginTransaction(),
$group['baz'] = $exception2
)
->when($result = count($group))
->then
->integer($result)
->isEqualTo(1);
}
public function get_get_stack_size()
{
$this
->given(
$group = new SUT('foo'),
$exception1 = new SUT('bar'),
$exception2 = new SUT('baz'),
$group['bar'] = $exception1,
$group->beginTransaction(),
$group['baz'] = $exception2
)
->when($result = $group->getStackSize())
->then
->integer($result)
->isEqualTo(2);
}
}
Test/Unit/Idle.php 0000666 00000020745 13371317322 0010006 0 ustar 00 when($result = new SUT('foo'))
->then
->object($result)
->isInstanceOf('Exception');
}
public function case_get_backtrace()
{
$this
->given($exception = new SUT('foo'))
->when($result = $exception->getBacktrace())
->then
->array($result)
->hasKey(0)
->array($result[0])
->hasKey('file')
->hasKey('line')
->hasKey('function')
->hasKey('class')
->hasKey('type')
->hasKey('args');
}
public function case_get_previous_throw()
{
$this
->given(
$previous = new SUT('previous'),
$exception = new SUT('foo', 0, [], $previous)
)
->when($result = $exception->getPreviousThrow())
->then
->object($result)
->isIdenticalTo($previous);
}
public function case_get_arguments()
{
$this
->given($exception = new SUT('foo', 0, ['arg', 42, null]))
->when($result = $exception->getArguments())
->then
->array($result)
->isEqualTo(['arg', 42, '(null)']);
}
public function case_get_arguments_from_a_string()
{
$this
->given($exception = new SUT('foo', 0, 'arg'))
->when($result = $exception->getArguments())
->then
->array($result)
->isEqualTo(['arg']);
}
public function case_get_raw_message()
{
$this
->given(
$message = 'foo %s',
$exception = new SUT($message)
)
->when($result = $exception->getRawMessage())
->then
->string($result)
->isEqualTo($message);
}
public function case_get_formatted_message()
{
$this
->given(
$message = 'foo %s',
$exception = new SUT($message, 0, 'bar')
)
->when($result = $exception->getFormattedMessage())
->then
->string($result)
->isEqualTo($exception->getMessage())
->isEqualTo('foo bar');
}
public function case_get_from_object()
{
$this
->given($exception = new SUT('foo'))
->when($result = $exception->getFrom())
->then
->string($result)
->isEqualTo(__METHOD__ . '()');
}
public function case_raise()
{
$this
->given($exception = new SUT('foo'), $line = __LINE__)
->when($result = $exception->raise())
->then
->string($result)
->isEqualTo(
__METHOD__ . '(): (0) foo' . "\n" .
'in ' . __FILE__ . ' at line ' . $line . '.'
);
}
public function case_raise_with_previous()
{
$this
->given(
$previous = new SUT('previous'), $previousLine = __LINE__,
$exception = new SUT('foo', 0, [], $previous), $line = __LINE__
)
->when($result = $exception->raise(true))
->then
->string($result)
->isEqualTo(
__METHOD__ . '(): (0) foo' . "\n" .
'in ' . __FILE__ . ' at line ' . $line . '.' . "\n\n" .
' ⬇' . "\n\n" .
'Nested exception (' . get_class($previous) . '):' . "\n" .
__METHOD__ . '(): (0) previous' . "\n" .
'in ' . __FILE__ . ' at line ' . $previousLine . '.'
);
}
public function case_uncaught()
{
$this
->given(
$this->function->ob_get_level = 0,
$exception = new SUT('foo'), $line = __LINE__
)
->when($result = SUT::uncaught($exception))
->then
->variable($result)
->isNull()
->output
->isEqualTo(
'Uncaught exception (' . get_class($exception) . '):' . "\n" .
__METHOD__ . '(): (0) foo' . "\n" .
'in ' . __FILE__ . ' at line ' . $line . '.'
);
}
public function case_uncaught_not_Hoa()
{
$this
->exception(function () {
SUT::uncaught(new \Exception('foo'));
})
->isInstanceOf('Exception')
->output
->isEmpty();
}
public function case_to_string()
{
$this
->given($exception = new SUT('foo'))
->when($result = $exception->__toString())
->then
->string($result)
->isEqualTo($exception->raise());
}
public function case_disable_uncaught_handler()
{
$this
->given(
$this->function->restore_exception_handler = function () use (&$called) {
$called = true;
return null;
}
)
->when($result = SUT::enableUncaughtHandler(false))
->then
->variable($result)
->isNull()
->boolean($called)
->isTrue();
}
public function case_enable_uncaught_handler()
{
$self = $this;
$this
->given(
$this->function->set_exception_handler = function ($handler) use ($self, &$called) {
$called = true;
$self
->object($handler)
->isInstanceOf('Closure')
->let($reflection = new \ReflectionObject($handler))
->array($invokeParameters = $reflection->getMethod('__invoke')->getParameters())
->hasSize(1)
->string($invokeParameters[0]->getName())
->isEqualTo('exception');
return null;
}
)
->when($result = SUT::enableUncaughtHandler())
->then
->variable($result)
->isNull()
->boolean($called)
->isTrue();
}
}
composer.json 0000666 00000002223 13371317322 0007273 0 ustar 00 {
"name" : "hoa/exception",
"description": "The Hoa\\Exception library.",
"type" : "library",
"keywords" : ["library", "exception"],
"homepage" : "https://hoa-project.net/",
"license" : "BSD-3-Clause",
"authors" : [
{
"name" : "Ivan Enderlin",
"email": "ivan.enderlin@hoa-project.net"
},
{
"name" : "Hoa community",
"homepage": "https://hoa-project.net/"
}
],
"support": {
"email" : "support@hoa-project.net",
"irc" : "irc://chat.freenode.net/hoaproject",
"forum" : "https://users.hoa-project.net/",
"docs" : "https://central.hoa-project.net/Documentation/Library/Exception",
"source": "https://central.hoa-project.net/Resource/Library/Exception"
},
"require": {
"hoa/consistency": "~1.0",
"hoa/event" : "~1.0"
},
"require-dev": {
"hoa/test": "~2.0"
},
"autoload": {
"psr-4": {
"Hoa\\Exception\\": "."
}
},
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
}
}