From 3f3a7f7b3debd7dea107f1648155f9451a105a5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Thu, 6 Jan 2022 23:07:04 +0100 Subject: [PATCH 1/4] Import test classes from psr/log 1.1.4 --- .github/workflows/continuous-integration.yml | 6 +- CHANGELOG.md | 4 + composer.json | 9 +- src/Test/DummyTest.php | 18 +++ src/Test/LoggerInterfaceTest.php | 138 +++++++++++++++++ src/Test/TestLogger.php | 147 +++++++++++++++++++ tests/Test/TestLoggerTest.php | 1 - 7 files changed, 316 insertions(+), 7 deletions(-) create mode 100644 src/Test/DummyTest.php create mode 100644 src/Test/LoggerInterfaceTest.php create mode 100644 src/Test/TestLogger.php diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index a1fa841..4375411 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -5,9 +5,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - # There is no code, we don't have to test old PHP versions php-versions: - - 7.4 - 8.0 - 8.1 dependency-levels: @@ -15,7 +13,7 @@ jobs: experimental: - false include: - - php-versions: 7.4 + - php-versions: 8.0 dependency-levels: 'lowest' experimental: false fail-fast: false @@ -30,7 +28,7 @@ jobs: php-version: ${{ matrix.php-versions }} - name: Validating PHP syntax - run: find ./tests/ -type f -name '*.php' -print0 | xargs -0 -L 1 -P 4 -- php -l + run: find ./{src,tests}/ -type f -name '*.php' -print0 | xargs -0 -L 1 -P 4 -- php -l - name: Validate composer.json and composer.lock run: composer validate diff --git a/CHANGELOG.md b/CHANGELOG.md index f22ac53..03c12e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [1.1.0] - YYYY-MM-DD + +- Import classes from [`psr/log`][] `v1.1.4`, for compatibility with `v2.0.0` and `v3.0.0`. + ## [1.0.0] - YYYY-MM-DD - Initial release. This ports the test for and from [`psr/log` v1.1][], according to diff --git a/composer.json b/composer.json index b0db5c7..fdfc7b4 100644 --- a/composer.json +++ b/composer.json @@ -10,13 +10,18 @@ } ], "require": { - "php": "^5.3 | ^7.0 | ^8.0", - "psr/log": "^1.1.1" + "php": "^8.0", + "psr/log": "^2.0 | ^3.0" }, "require-dev": { "phpunit/phpunit": "^8.0 | ^9.0", "squizlabs/php_codesniffer": "^3.6" }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, "autoload-dev": { "psr-4": { "Psr\\Log\\Tests\\": "tests" diff --git a/src/Test/DummyTest.php b/src/Test/DummyTest.php new file mode 100644 index 0000000..9638c11 --- /dev/null +++ b/src/Test/DummyTest.php @@ -0,0 +1,18 @@ + ". + * + * Example ->error('Foo') would yield "error Foo". + * + * @return string[] + */ + abstract public function getLogs(); + + public function testImplements() + { + $this->assertInstanceOf('Psr\Log\LoggerInterface', $this->getLogger()); + } + + /** + * @dataProvider provideLevelsAndMessages + */ + public function testLogsAtAllLevels($level, $message) + { + $logger = $this->getLogger(); + $logger->{$level}($message, array('user' => 'Bob')); + $logger->log($level, $message, array('user' => 'Bob')); + + $expected = array( + $level.' message of level '.$level.' with context: Bob', + $level.' message of level '.$level.' with context: Bob', + ); + $this->assertEquals($expected, $this->getLogs()); + } + + public function provideLevelsAndMessages() + { + return array( + LogLevel::EMERGENCY => array(LogLevel::EMERGENCY, 'message of level emergency with context: {user}'), + LogLevel::ALERT => array(LogLevel::ALERT, 'message of level alert with context: {user}'), + LogLevel::CRITICAL => array(LogLevel::CRITICAL, 'message of level critical with context: {user}'), + LogLevel::ERROR => array(LogLevel::ERROR, 'message of level error with context: {user}'), + LogLevel::WARNING => array(LogLevel::WARNING, 'message of level warning with context: {user}'), + LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of level notice with context: {user}'), + LogLevel::INFO => array(LogLevel::INFO, 'message of level info with context: {user}'), + LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of level debug with context: {user}'), + ); + } + + /** + * @expectedException \Psr\Log\InvalidArgumentException + */ + public function testThrowsOnInvalidLevel() + { + $logger = $this->getLogger(); + $logger->log('invalid level', 'Foo'); + } + + public function testContextReplacement() + { + $logger = $this->getLogger(); + $logger->info('{Message {nothing} {user} {foo.bar} a}', array('user' => 'Bob', 'foo.bar' => 'Bar')); + + $expected = array('info {Message {nothing} Bob Bar a}'); + $this->assertEquals($expected, $this->getLogs()); + } + + public function testObjectCastToString() + { + if (method_exists($this, 'createPartialMock')) { + $dummy = $this->createPartialMock('Psr\Log\Test\DummyTest', array('__toString')); + } else { + $dummy = $this->getMock('Psr\Log\Test\DummyTest', array('__toString')); + } + $dummy->expects($this->once()) + ->method('__toString') + ->will($this->returnValue('DUMMY')); + + $this->getLogger()->warning($dummy); + + $expected = array('warning DUMMY'); + $this->assertEquals($expected, $this->getLogs()); + } + + public function testContextCanContainAnything() + { + $closed = fopen('php://memory', 'r'); + fclose($closed); + + $context = array( + 'bool' => true, + 'null' => null, + 'string' => 'Foo', + 'int' => 0, + 'float' => 0.5, + 'nested' => array('with object' => new DummyTest), + 'object' => new \DateTime, + 'resource' => fopen('php://memory', 'r'), + 'closed' => $closed, + ); + + $this->getLogger()->warning('Crazy context data', $context); + + $expected = array('warning Crazy context data'); + $this->assertEquals($expected, $this->getLogs()); + } + + public function testContextExceptionKeyCanBeExceptionOrOtherValues() + { + $logger = $this->getLogger(); + $logger->warning('Random message', array('exception' => 'oops')); + $logger->critical('Uncaught Exception!', array('exception' => new \LogicException('Fail'))); + + $expected = array( + 'warning Random message', + 'critical Uncaught Exception!' + ); + $this->assertEquals($expected, $this->getLogs()); + } +} diff --git a/src/Test/TestLogger.php b/src/Test/TestLogger.php new file mode 100644 index 0000000..1be3230 --- /dev/null +++ b/src/Test/TestLogger.php @@ -0,0 +1,147 @@ + $level, + 'message' => $message, + 'context' => $context, + ]; + + $this->recordsByLevel[$record['level']][] = $record; + $this->records[] = $record; + } + + public function hasRecords($level) + { + return isset($this->recordsByLevel[$level]); + } + + public function hasRecord($record, $level) + { + if (is_string($record)) { + $record = ['message' => $record]; + } + return $this->hasRecordThatPasses(function ($rec) use ($record) { + if ($rec['message'] !== $record['message']) { + return false; + } + if (isset($record['context']) && $rec['context'] !== $record['context']) { + return false; + } + return true; + }, $level); + } + + public function hasRecordThatContains($message, $level) + { + return $this->hasRecordThatPasses(function ($rec) use ($message) { + return strpos($rec['message'], $message) !== false; + }, $level); + } + + public function hasRecordThatMatches($regex, $level) + { + return $this->hasRecordThatPasses(function ($rec) use ($regex) { + return preg_match($regex, $rec['message']) > 0; + }, $level); + } + + public function hasRecordThatPasses(callable $predicate, $level) + { + if (!isset($this->recordsByLevel[$level])) { + return false; + } + foreach ($this->recordsByLevel[$level] as $i => $rec) { + if (call_user_func($predicate, $rec, $i)) { + return true; + } + } + return false; + } + + public function __call($method, $args) + { + if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) { + $genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3]; + $level = strtolower($matches[2]); + if (method_exists($this, $genericMethod)) { + $args[] = $level; + return call_user_func_array([$this, $genericMethod], $args); + } + } + throw new \BadMethodCallException('Call to undefined method ' . get_class($this) . '::' . $method . '()'); + } + + public function reset() + { + $this->records = []; + $this->recordsByLevel = []; + } +} diff --git a/tests/Test/TestLoggerTest.php b/tests/Test/TestLoggerTest.php index b7cd975..98d6041 100644 --- a/tests/Test/TestLoggerTest.php +++ b/tests/Test/TestLoggerTest.php @@ -8,7 +8,6 @@ /** * Test classes from psr/log 1.1.x * - * @requires PHP 7.4 * @covers \Psr\Log\Test\TestLogger * @covers \Psr\Log\Test\LoggerInterfaceTest * From ac98e5edfeb424476cbd467c45c2144574b7f5fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Thu, 6 Jan 2022 23:16:20 +0100 Subject: [PATCH 2/4] Fix compatibility with PHPUnit and psr/log 3.0 --- src/Test/LoggerInterfaceTest.php | 11 +++++------ src/Test/TestLogger.php | 9 +++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/Test/LoggerInterfaceTest.php b/src/Test/LoggerInterfaceTest.php index e1e5354..8e143a8 100644 --- a/src/Test/LoggerInterfaceTest.php +++ b/src/Test/LoggerInterfaceTest.php @@ -2,6 +2,7 @@ namespace Psr\Log\Test; +use Psr\Log\InvalidArgumentException; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; use PHPUnit\Framework\TestCase; @@ -32,7 +33,7 @@ abstract public function getLogs(); public function testImplements() { - $this->assertInstanceOf('Psr\Log\LoggerInterface', $this->getLogger()); + $this->assertInstanceOf(LoggerInterface::class, $this->getLogger()); } /** @@ -65,11 +66,9 @@ public function provideLevelsAndMessages() ); } - /** - * @expectedException \Psr\Log\InvalidArgumentException - */ public function testThrowsOnInvalidLevel() { + $this->expectException(InvalidArgumentException::class); $logger = $this->getLogger(); $logger->log('invalid level', 'Foo'); } @@ -86,9 +85,9 @@ public function testContextReplacement() public function testObjectCastToString() { if (method_exists($this, 'createPartialMock')) { - $dummy = $this->createPartialMock('Psr\Log\Test\DummyTest', array('__toString')); + $dummy = $this->createPartialMock(DummyTest::class, array('__toString')); } else { - $dummy = $this->getMock('Psr\Log\Test\DummyTest', array('__toString')); + $dummy = $this->getMock(DummyTest::class, array('__toString')); } $dummy->expects($this->once()) ->method('__toString') diff --git a/src/Test/TestLogger.php b/src/Test/TestLogger.php index 1be3230..8e4d53b 100644 --- a/src/Test/TestLogger.php +++ b/src/Test/TestLogger.php @@ -56,17 +56,14 @@ */ class TestLogger extends AbstractLogger { - /** - * @var array - */ - public $records = []; + public array $records = []; - public $recordsByLevel = []; + public array $recordsByLevel = []; /** * @inheritdoc */ - public function log($level, $message, array $context = []) + public function log($level, string|\Stringable $message, array $context = []): void { $record = [ 'level' => $level, From 3dd1c6dacd6af347eae9756b4df68ae2e726cad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Fri, 14 Jan 2022 23:06:30 +0100 Subject: [PATCH 3/4] Modernize code for PHP 8.0 --- src/Test/LoggerInterfaceTest.php | 64 ++++++++++++++++---------------- src/Test/TestLogger.php | 18 ++++----- tests/Test/TestLoggerTest.php | 2 +- 3 files changed, 41 insertions(+), 43 deletions(-) diff --git a/src/Test/LoggerInterfaceTest.php b/src/Test/LoggerInterfaceTest.php index 8e143a8..dcb975a 100644 --- a/src/Test/LoggerInterfaceTest.php +++ b/src/Test/LoggerInterfaceTest.php @@ -16,6 +16,8 @@ abstract class LoggerInterfaceTest extends TestCase { /** + * Return an instance of the logger to be tested. + * * @return LoggerInterface */ abstract public function getLogger(); @@ -42,28 +44,28 @@ public function testImplements() public function testLogsAtAllLevels($level, $message) { $logger = $this->getLogger(); - $logger->{$level}($message, array('user' => 'Bob')); - $logger->log($level, $message, array('user' => 'Bob')); + $logger->{$level}($message, ['user' => 'Bob']); + $logger->log($level, $message, ['user' => 'Bob']); - $expected = array( - $level.' message of level '.$level.' with context: Bob', - $level.' message of level '.$level.' with context: Bob', - ); + $expected = [ + $level . ' message of level ' . $level . ' with context: Bob', + $level . ' message of level ' . $level . ' with context: Bob', + ]; $this->assertEquals($expected, $this->getLogs()); } public function provideLevelsAndMessages() { - return array( - LogLevel::EMERGENCY => array(LogLevel::EMERGENCY, 'message of level emergency with context: {user}'), - LogLevel::ALERT => array(LogLevel::ALERT, 'message of level alert with context: {user}'), - LogLevel::CRITICAL => array(LogLevel::CRITICAL, 'message of level critical with context: {user}'), - LogLevel::ERROR => array(LogLevel::ERROR, 'message of level error with context: {user}'), - LogLevel::WARNING => array(LogLevel::WARNING, 'message of level warning with context: {user}'), - LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of level notice with context: {user}'), - LogLevel::INFO => array(LogLevel::INFO, 'message of level info with context: {user}'), - LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of level debug with context: {user}'), - ); + return [ + LogLevel::EMERGENCY => [LogLevel::EMERGENCY, 'message of level emergency with context: {user}'], + LogLevel::ALERT => [LogLevel::ALERT, 'message of level alert with context: {user}'], + LogLevel::CRITICAL => [LogLevel::CRITICAL, 'message of level critical with context: {user}'], + LogLevel::ERROR => [LogLevel::ERROR, 'message of level error with context: {user}'], + LogLevel::WARNING => [LogLevel::WARNING, 'message of level warning with context: {user}'], + LogLevel::NOTICE => [LogLevel::NOTICE, 'message of level notice with context: {user}'], + LogLevel::INFO => [LogLevel::INFO, 'message of level info with context: {user}'], + LogLevel::DEBUG => [LogLevel::DEBUG, 'message of level debug with context: {user}'], + ]; } public function testThrowsOnInvalidLevel() @@ -76,26 +78,22 @@ public function testThrowsOnInvalidLevel() public function testContextReplacement() { $logger = $this->getLogger(); - $logger->info('{Message {nothing} {user} {foo.bar} a}', array('user' => 'Bob', 'foo.bar' => 'Bar')); + $logger->info('{Message {nothing} {user} {foo.bar} a}', ['user' => 'Bob', 'foo.bar' => 'Bar']); - $expected = array('info {Message {nothing} Bob Bar a}'); + $expected = ['info {Message {nothing} Bob Bar a}']; $this->assertEquals($expected, $this->getLogs()); } public function testObjectCastToString() { - if (method_exists($this, 'createPartialMock')) { - $dummy = $this->createPartialMock(DummyTest::class, array('__toString')); - } else { - $dummy = $this->getMock(DummyTest::class, array('__toString')); - } + $dummy = $this->createPartialMock(DummyTest::class, ['__toString']); $dummy->expects($this->once()) ->method('__toString') ->will($this->returnValue('DUMMY')); $this->getLogger()->warning($dummy); - $expected = array('warning DUMMY'); + $expected = ['warning DUMMY']; $this->assertEquals($expected, $this->getLogs()); } @@ -104,34 +102,34 @@ public function testContextCanContainAnything() $closed = fopen('php://memory', 'r'); fclose($closed); - $context = array( + $context = [ 'bool' => true, 'null' => null, 'string' => 'Foo', 'int' => 0, 'float' => 0.5, - 'nested' => array('with object' => new DummyTest), - 'object' => new \DateTime, + 'nested' => ['with object' => new DummyTest()], + 'object' => new \DateTime(), 'resource' => fopen('php://memory', 'r'), 'closed' => $closed, - ); + ]; $this->getLogger()->warning('Crazy context data', $context); - $expected = array('warning Crazy context data'); + $expected = ['warning Crazy context data']; $this->assertEquals($expected, $this->getLogs()); } public function testContextExceptionKeyCanBeExceptionOrOtherValues() { $logger = $this->getLogger(); - $logger->warning('Random message', array('exception' => 'oops')); - $logger->critical('Uncaught Exception!', array('exception' => new \LogicException('Fail'))); + $logger->warning('Random message', ['exception' => 'oops']); + $logger->critical('Uncaught Exception!', ['exception' => new \LogicException('Fail')]); - $expected = array( + $expected = [ 'warning Random message', 'critical Uncaught Exception!' - ); + ]; $this->assertEquals($expected, $this->getLogs()); } } diff --git a/src/Test/TestLogger.php b/src/Test/TestLogger.php index 8e4d53b..31aaf38 100644 --- a/src/Test/TestLogger.php +++ b/src/Test/TestLogger.php @@ -2,7 +2,8 @@ namespace Psr\Log\Test; -use Psr\Log\AbstractLogger; +use Psr\Log\LoggerInterface; +use Psr\Log\LoggerTrait; /** * Used for testing purposes. @@ -54,8 +55,10 @@ * @method bool hasInfoThatPasses($message) * @method bool hasDebugThatPasses($message) */ -class TestLogger extends AbstractLogger +class TestLogger implements LoggerInterface { + use LoggerTrait; + public array $records = []; public array $recordsByLevel = []; @@ -98,16 +101,12 @@ public function hasRecord($record, $level) public function hasRecordThatContains($message, $level) { - return $this->hasRecordThatPasses(function ($rec) use ($message) { - return strpos($rec['message'], $message) !== false; - }, $level); + return $this->hasRecordThatPasses(fn ($rec) => str_contains($rec['message'], $message), $level); } public function hasRecordThatMatches($regex, $level) { - return $this->hasRecordThatPasses(function ($rec) use ($regex) { - return preg_match($regex, $rec['message']) > 0; - }, $level); + return $this->hasRecordThatPasses(fn ($rec) => preg_match($regex, $rec['message']) > 0, $level); } public function hasRecordThatPasses(callable $predicate, $level) @@ -116,10 +115,11 @@ public function hasRecordThatPasses(callable $predicate, $level) return false; } foreach ($this->recordsByLevel[$level] as $i => $rec) { - if (call_user_func($predicate, $rec, $i)) { + if ($predicate($rec, $i)) { return true; } } + return false; } diff --git a/tests/Test/TestLoggerTest.php b/tests/Test/TestLoggerTest.php index 98d6041..236a04b 100644 --- a/tests/Test/TestLoggerTest.php +++ b/tests/Test/TestLoggerTest.php @@ -71,7 +71,7 @@ public function testHasRecord(string $level): void $this->assertTrue(call_user_func([$logger, $levelMethod], $record), $levelMethod.' without context'); $record = ['message' => $level.' Message', ['foo' => 'bar']]; - $this->assertTrue($logger->hasRecord($record, $level),'hasRecord with context'); + $this->assertTrue($logger->hasRecord($record, $level), 'hasRecord with context'); $this->assertTrue(call_user_func([$logger, $levelMethod], $record), $levelMethod.' with context'); $this->assertTrue(call_user_func([$logger, $levelMethod.'ThatContains'], 'Message'), $levelMethod.'ThatContains'); From 2c9fe51d0b6133421a0ab05fbb770e7f99bf86bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Sat, 22 Jan 2022 21:35:21 +0100 Subject: [PATCH 4/4] Materialize magical methods from TestLogger::__call --- src/Test/TestLogger.php | 276 +++++++++++++++++++++++++++++++++------- 1 file changed, 230 insertions(+), 46 deletions(-) diff --git a/src/Test/TestLogger.php b/src/Test/TestLogger.php index 31aaf38..e3af87f 100644 --- a/src/Test/TestLogger.php +++ b/src/Test/TestLogger.php @@ -9,58 +9,12 @@ * Used for testing purposes. * * It records all records and gives you access to them for verification. - * - * @method bool hasEmergency($record) - * @method bool hasAlert($record) - * @method bool hasCritical($record) - * @method bool hasError($record) - * @method bool hasWarning($record) - * @method bool hasNotice($record) - * @method bool hasInfo($record) - * @method bool hasDebug($record) - * - * @method bool hasEmergencyRecords() - * @method bool hasAlertRecords() - * @method bool hasCriticalRecords() - * @method bool hasErrorRecords() - * @method bool hasWarningRecords() - * @method bool hasNoticeRecords() - * @method bool hasInfoRecords() - * @method bool hasDebugRecords() - * - * @method bool hasEmergencyThatContains($message) - * @method bool hasAlertThatContains($message) - * @method bool hasCriticalThatContains($message) - * @method bool hasErrorThatContains($message) - * @method bool hasWarningThatContains($message) - * @method bool hasNoticeThatContains($message) - * @method bool hasInfoThatContains($message) - * @method bool hasDebugThatContains($message) - * - * @method bool hasEmergencyThatMatches($message) - * @method bool hasAlertThatMatches($message) - * @method bool hasCriticalThatMatches($message) - * @method bool hasErrorThatMatches($message) - * @method bool hasWarningThatMatches($message) - * @method bool hasNoticeThatMatches($message) - * @method bool hasInfoThatMatches($message) - * @method bool hasDebugThatMatches($message) - * - * @method bool hasEmergencyThatPasses($message) - * @method bool hasAlertThatPasses($message) - * @method bool hasCriticalThatPasses($message) - * @method bool hasErrorThatPasses($message) - * @method bool hasWarningThatPasses($message) - * @method bool hasNoticeThatPasses($message) - * @method bool hasInfoThatPasses($message) - * @method bool hasDebugThatPasses($message) */ class TestLogger implements LoggerInterface { use LoggerTrait; public array $records = []; - public array $recordsByLevel = []; /** @@ -78,16 +32,26 @@ public function log($level, string|\Stringable $message, array $context = []): v $this->records[] = $record; } + /** + * @param string $level + * @return bool + */ public function hasRecords($level) { return isset($this->recordsByLevel[$level]); } + /** + * @param array $record + * @param string $level + * @return bool + */ public function hasRecord($record, $level) { if (is_string($record)) { $record = ['message' => $record]; } + return $this->hasRecordThatPasses(function ($rec) use ($record) { if ($rec['message'] !== $record['message']) { return false; @@ -99,16 +63,31 @@ public function hasRecord($record, $level) }, $level); } + /** + * @param string $message + * @param string $level + * @return bool + */ public function hasRecordThatContains($message, $level) { return $this->hasRecordThatPasses(fn ($rec) => str_contains($rec['message'], $message), $level); } + /** + * @param string $regex + * @param string $level + * @return bool + */ public function hasRecordThatMatches($regex, $level) { return $this->hasRecordThatPasses(fn ($rec) => preg_match($regex, $rec['message']) > 0, $level); } + /** + * @param callable $predicate + * @param string $level + * @return bool + */ public function hasRecordThatPasses(callable $predicate, $level) { if (!isset($this->recordsByLevel[$level])) { @@ -123,8 +102,13 @@ public function hasRecordThatPasses(callable $predicate, $level) return false; } + /** + * @deprecated Since psr/log-util 1.1 + */ public function __call($method, $args) { + @trigger_error(sprintf('Since psr/log-util 1.1: Method "%s" is deprecated and should not be called. Use method "%s" instead.', __FUNCTION__, $method), \E_USER_DEPRECATED); + if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) { $genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3]; $level = strtolower($matches[2]); @@ -136,6 +120,206 @@ public function __call($method, $args) throw new \BadMethodCallException('Call to undefined method ' . get_class($this) . '::' . $method . '()'); } + public function hasEmergency($record): bool + { + return $this->hasRecord($record, 'emergency'); + } + + public function hasAlert($record): bool + { + return $this->hasRecord($record, 'alert'); + } + + public function hasCritical($record): bool + { + return $this->hasRecord($record, 'critical'); + } + + public function hasError($record): bool + { + return $this->hasRecord($record, 'error'); + } + + public function hasWarning($record): bool + { + return $this->hasRecord($record, 'warning'); + } + + public function hasNotice($record): bool + { + return $this->hasRecord($record, 'notice'); + } + + public function hasInfo($record): bool + { + return $this->hasRecord($record, 'info'); + } + + public function hasDebug($record): bool + { + return $this->hasRecord($record, 'debug'); + } + + public function hasEmergencyRecords(): bool + { + return $this->hasRecords('emergency'); + } + + public function hasAlertRecords(): bool + { + return $this->hasRecords('alert'); + } + + public function hasCriticalRecords(): bool + { + return $this->hasRecords('critical'); + } + + public function hasErrorRecords(): bool + { + return $this->hasRecords('error'); + } + + public function hasWarningRecords(): bool + { + return $this->hasRecords('warning'); + } + + public function hasNoticeRecords(): bool + { + return $this->hasRecords('notice'); + } + + public function hasInfoRecords(): bool + { + return $this->hasRecords('info'); + } + + public function hasDebugRecords(): bool + { + return $this->hasRecords('debug'); + } + + public function hasEmergencyThatContains($message): bool + { + return $this->hasRecordThatContains($message, 'emergency'); + } + + public function hasAlertThatContains($message): bool + { + return $this->hasRecordThatContains($message, 'alert'); + } + + public function hasCriticalThatContains($message): bool + { + return $this->hasRecordThatContains($message, 'critical'); + } + + public function hasErrorThatContains($message): bool + { + return $this->hasRecordThatContains($message, 'error'); + } + + public function hasWarningThatContains($message): bool + { + return $this->hasRecordThatContains($message, 'warning'); + } + + public function hasNoticeThatContains($message): bool + { + return $this->hasRecordThatContains($message, 'notice'); + } + + public function hasInfoThatContains($message): bool + { + return $this->hasRecordThatContains($message, 'info'); + } + + public function hasDebugThatContains($message): bool + { + return $this->hasRecordThatContains($message, 'debug'); + } + + public function hasEmergencyThatMatches(string $regex): bool + { + return $this->hasRecordThatMatches($regex, 'emergency'); + } + + public function hasAlertThatMatches(string $regex): bool + { + return $this->hasRecordThatMatches($regex, 'alert'); + } + + public function hasCriticalThatMatches(string $regex): bool + { + return $this->hasRecordThatMatches($regex, 'critical'); + } + + public function hasErrorThatMatches(string $regex): bool + { + return $this->hasRecordThatMatches($regex, 'error'); + } + + public function hasWarningThatMatches(string $regex): bool + { + return $this->hasRecordThatMatches($regex, 'warning'); + } + + public function hasNoticeThatMatches(string $regex): bool + { + return $this->hasRecordThatMatches($regex, 'notice'); + } + + public function hasInfoThatMatches(string $regex): bool + { + return $this->hasRecordThatMatches($regex, 'info'); + } + + public function hasDebugThatMatches(string $regex): bool + { + return $this->hasRecordThatMatches($regex, 'debug'); + } + + public function hasEmergencyThatPasses(callable $predicate): bool + { + return $this->hasRecordThatPasses($predicate, 'emergency'); + } + + public function hasAlertThatPasses(callable $predicate): bool + { + return $this->hasRecordThatPasses($predicate, 'alert'); + } + + public function hasCriticalThatPasses(callable $predicate): bool + { + return $this->hasRecordThatPasses($predicate, 'critical'); + } + + public function hasErrorThatPasses(callable $predicate): bool + { + return $this->hasRecordThatPasses($predicate, 'error'); + } + + public function hasWarningThatPasses(callable $predicate): bool + { + return $this->hasRecordThatPasses($predicate, 'warning'); + } + + public function hasNoticeThatPasses(callable $predicate): bool + { + return $this->hasRecordThatPasses($predicate, 'notice'); + } + + public function hasInfoThatPasses(callable $predicate): bool + { + return $this->hasRecordThatPasses($predicate, 'info'); + } + + public function hasDebugThatPasses(callable $predicate): bool + { + return $this->hasRecordThatPasses($predicate, 'debug'); + } + public function reset() { $this->records = [];