From 4b52bb8baf9c3b0c99320f93b7e0b54fe05e6a85 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Sun, 8 May 2022 16:22:19 +1000 Subject: [PATCH] wip --- changelog.md | 203 --------------------------------------- readme.md | 79 ++++++++++----- src/ChannelFake.php | 5 +- src/LogFake.php | 2 +- tests/LogFakeApiTest.php | 80 +++++---------- 5 files changed, 83 insertions(+), 286 deletions(-) delete mode 100644 changelog.md diff --git a/changelog.md b/changelog.md deleted file mode 100644 index b64cc60..0000000 --- a/changelog.md +++ /dev/null @@ -1,203 +0,0 @@ -# Changelog - -## v2.0.0 - -## Version support - -- Drop PHP `^7.1` support. -- Drop `illuminate/config` version `~5.6.0 || ~5.7.0 || ~5.8.0 || ^6.0 || ^7.0 || ^8.0` support. -- Add `illuminate/config` version `^9.0` support. -- Drop `illuminate/container` version `~5.6.0 || ~5.7.0 || ~5.8.0 || ^6.0 || ^7.0 || ^8.0` support. -- Add `illuminate/container` version `^9.0` support. -- Drop `illuminate/support` version `~5.6.0 || ~5.7.0 || ~5.8.0 || ^6.0 || ^7.0 || ^8.0` support. -- Add `illuminate/support` version `^9.0` support. -- Drop `phpunit/phpunit` version `^7.0 || ^8.0` support. -- Add `psr/log` version `^3.0` support. - -## Feature - -- Added a changelog -- Drop support for named arguments. -- Return `$this` from assertion functions to allow for assertion chaining. -- Add `LogFake::bind()` helper to bind the fake to the container. -- When no channel name is specified and no configuration default is found, the channel name now defaults to `"null"` to match the framework. - -```diff -- Log::swap(new LogFake()); -+ LogFake::bind(); -``` - -- Add `LogFake::dumpAll()` to dump all logs from every channel and stack to help with debugging (thanks @brentkelly). - -```php -Log::dumpAll(); - -// dumps all channel / stack logs to console... -``` -- Add `LogFake::ddAll()` to dump all logs from every channel and stack and then die to help with debugging (thanks @brentkelly). - -```php -Log::ddAll(); - -// dumps all channel / stack logs to console and stops execution... -``` - -- Add `LogFake::assertChannelIsCurrentlyForgotten($channel)` to assert against the _current_ forgotten state of a channel. - -```php -Log::channel('slack')->info('xxxx'); - -Log::forgetChannel('slack'); - -Log::assertChannelIsCurrentlyForgotten('slack'); // ✅ -``` - -- Add `LogFake::build()` to support to "ondemand" feature of the Log Manager. This channel will always be named `"ondemand"`. - -```php -Log::build($config)->info('xxxx'); - -Log::channel('ondemand')->assertLogged('xxxx'); // ✅ - -``` - -- Add `ChannelFake::assertWasForgotten()` to assert that a channel was forgotten at least once. - -```php -Log::channel('slack')->info('xxxx'); -Log::forgetChannel('slack'); - -Log::channel('slack')->info('xxxx'); - -Log::channel('slack')->assertWasForgotten(); // ✅ -``` - -- Add `ChannelFake::assertWasForgottenTimes($times)` to assert that a channel was forgotten the specified number of times. - -```php -Log::channel('slack')->info('xxxx'); -Log::forgetChannel('slack'); - -Log::channel('slack')->info('xxxx'); -Log::forgetChannel('slack'); - -Log::channel('slack')->assertWasForgottenTimes(2); // ✅ -``` - -- Add `ChannelFake::assertWasNotForgotten()` to assert that a channel was never forgotten. - -```php -Log::channel('slack')->info('xxxx'); - -Log::channel('slack')->assertWasNotForgotten(); // ✅ -``` - -- Add `ChannelFake::assertCurrentContext($context)` to assert that the context is currently present in the channel. A Stack cannot utilise this function as a stack's context is reset each time it is resolved from the LogManager. - -```php -Log::channel('slack')->withContext(['foo' => 'bar']); - -Log::channel('slack')->assertCurrentContext(['foo' => 'bar']); -``` - -- Add `ChannelFake::assertHadContext($context)` to assert that the context was as some point present in the channel. - -```php -Log::channel('slack')->withContext(['foo' => 'bar']); -Log::channel('slack')->withoutContext(); - -Log::channel('slack')->assertHadContext(['foo' => 'bar']); // ✅ -``` - -- Add `ChannelFake::assertHadContextAtSetCall($context, $call)` to assert that the specified context was set at the call to `with{out}Context()` count. - -```php -Log::channel('slack')->withContext(['foo' => 'bar']); -Log::channel('slack')->withoutContext([]); -Log::channel('slack')->withContext(['bar' => 'baz']); - -Log::channel('slack')->assertHadContextAtSetCall(['foo' => 'bar'], 1); // ✅ -Log::channel('slack')->assertHadContextAtSetCall([], 2); // ✅ -Log::channel('slack')->assertHadContextAtSetCall(['bar' => 'baz'], 3); // ✅ -``` - -- Add `ChannelFake::assertContextSetTimes($times)` to assert that context has been set the specified number of times. - -```php -Log::channel('slack')->withContext(['foo' => 'bar']); -Log::channel('slack')->withoutContext([]); - -Log::assertContextSetTimes(2); // ✅ -``` - -- Add `ChannelFake::dump(?$level)` to dump the logs from the channel to help with debugging (thanks @brentkelly). - -```php -Log::channel('slack')->dump(); - -// dumps logs to console... -``` - -- Add `ChannelFake::dd(?$level)` to dump all logs from the channel and then die to help with debugging (thanks @brentkelly). - -```php -Log::channel('slack')->dump(); - -// dumps logs to console and stops execution... -``` - -- Document that failing expectation exception messages are no longer considered breaking changes. -- **BREAKING**: Update failing expectation exception messages. -- **BREAKING**: The logger is no longer responsible for housing everything. i.e. the channels no longer proxy things back to the logger and instead they now house their own logs. _This should only be breaking if you are extending any of the classes provided by this package._ -- **BREAKING**: Make protected methods / properties private. _This should only be breaking if you are extending any of the classes provided by this package._ -- **BREAKING**: Add type declarations where possible. _This should only be breaking if you are extending any of the classes provided by this package or if you are passing in wrong value types_. -- **BREAKING**: Callable parameters have been replaced by Closure based parameters. - -```diff -- Log::assertLogged('info', [$this, 'someCallableMethod']); -+ Log::assertLogged('info', fn ($message, $context) => $this->someCallableMethod($message, $context)); -``` - -- **BREAKING**: `LogFake::assertLogged()` no longer accepts an integer as the second parameter. Utilise the `LogFake::assertLoggedTimes()` function instead. - -```diff -- Log::assertLogged('info', 5); -+ Log::assertLoggedTimes('info', 5); -``` - -- **BREAKING**: `LogFake::assertLoggedTimes()` no longer has a default value of `1` for the `$times` parameter. - -```diff -- LogFake::assertLoggedTimes('info'); -+ LogFake::assertLoggedTimes('info', 1); -``` - -- **BREAKING**: The `ChannelFake::logged()` is now `@internal` and is not meant for public consumption. -- **BREAKING**: The `ChannelFake::hasLogged()` function has been removed. -- **BREAKING**: The `ChannelFake::hasNotLogged()` function has been removed. -- **BREAKING**: Several helper functions have been made private, `@internal`, or removed completely. _This should only be breaking if you are extending any of the classes provided by this package._ -- **BREAKING**: Stacks can no longer be resolved via the `LogFake::channel($name)` function and should be resolved via the `LogFake::stack($channels, $channel)` function instead. _This should only be a breaking change if you are referencing a stack name directly._ -- Removed assertLoggedMessage. Utilise assertLogged with a closure instead - -```diff -Log::stack(['slack', 'stderr'], 'my-stack')->info('xxxx'); - - -g Log::channel('Stack:my-stack,slack,stderr')->assert(/* ... */); -+ Log::stack(['slack', 'stderr'], 'my-stack')->assert(/* ... */); -``` - -## Chore - -- Run CI linting against PHP `8.1`. -- Drop CI testing against PHP `^7.0`. -- Drop CI testing against Laravel `~5.*`, `^6.0`, `^7.0`, and `^8.0`. -- Drop CI testing against PHPUnit `^7.0` and `^8.0`. -- Drop Psalm type checking CI step in favour of PHPStan. -- Drop composer normalize CI step. -- Add CI testing against Laravel `^9.0`. -- Add CI testing against PHP `8.1`. -- Migrate PHP-CS-Fixer config.. -- Add PHP-CS-Fixer rules. -- Move dev dependencies to a dedicated `composer.json` via `bamarni/composer-bin-plugin`. - diff --git a/readme.md b/readme.md index d27e9e4..3a1f7ea 100644 --- a/readme.md +++ b/readme.md @@ -513,12 +513,65 @@ The same as [`dumpAll()`](https://github.com/timacdonald/log-fake#dumpall), but ## Other APIs -### Log::allLogs() +### logs() +Get a collection of all log entries from a channel or stack. -### Log::allChannelsAndStacks() -### Log::logged() -### Log::logs() +#### Can be called on... + +- [x] Facade base (default channel) +- [x] Channels +- [x] Stacks + +#### Example usage... + +```php +/* + * implementation... + */ + +Log::channel('slack')->info('User logged in.'); + +Log::channel('slack')->alert('Stripe request initiated.'); + +/* + * example usage... + */ + +$logs = Log::channel('slack')->logs(); + +assert($logs->count() === 2); ✅ +``` + +### allLogs() + +Similar to [`logs()`](https://github.com/timacdonald/log-fake#logs), except that it is called on the Facade base and returns a collection of logs from all the channels and stacks. + +#### Can be called on... + +- [x] Facade base ~(default channel)~ +- [ ] Channels +- [ ] Stacks + +#### Example usage... + +```php +/* + * implementation... + */ + +Log::info('User logged in.'); + +Log::channel('slack')->alert('Stripe request initiated.'); + +/* + * example usage... + */ + +$logs = Log::allLogs(); + +assert($logs->count() === 2); ✅ +``` ## Credits @@ -530,21 +583,3 @@ And a special (vegi) thanks to [Caneco](https://twitter.com/caneco) for the logo ## Thanksware You are free to use this package, but I ask that you reach out to someone (not me) who has previously, or is currently, maintaining or contributing to an open source library you are using in your project and thank them for their work. Consider your entire tech stack: packages, frameworks, languages, databases, operating systems, frontend, backend, etc. - -## Upgrading - -- Failure messages have been updated. -- assertLoggedTimes no longer has a default $times value. -- assertLogged no longer accepts an integer as the second parameter. Use `assertLoggedTimes` directly instead -- the `hasLogged` function has been removed. use assertions or the Log::logged(...)->isEmpty()" instead -- the `hasNotLogged` function has been removed. use assertions or the Log::logged(...)->isNotEmpty()" instead -- the `getLogger` method now returns a `ChannelFake` -- raw log arrays now contain the 'times_channel_has_been_forgotten_at_time_of_writing_log' key, indicating how many times the channel has been forgotten at the time of creation -` -- assertion closures now recieve an addition 3rd parameter int: times_forgotten -- Don't support named parameters -- The "stack:" prefix has been removed and now uses the channel name or the default value. channels are now comma seperated - -- a stack never has "currentContext" as it is reset each time it is resolved from the manager. -- `getChannels` returns all channels - forgotten or not -- Note that exception messages could change at any time and are not protected and are not considered breaking changes. diff --git a/src/ChannelFake.php b/src/ChannelFake.php index 3c45784..b238377 100644 --- a/src/ChannelFake.php +++ b/src/ChannelFake.php @@ -35,9 +35,6 @@ class ChannelFake implements LoggerInterface private bool $isCurrentlyForgotten = false; - /** - * @internal - */ public function __construct(private string $name) { // @@ -259,7 +256,7 @@ public function setEventDispatcher(Dispatcher $dispatcher): void * @param (Closure(LogEntry): bool) $callback * @return Collection */ - public function logged(Closure $callback): Collection + private function logged(Closure $callback): Collection { return $this->logs() ->filter(fn (LogEntry $log): bool => (bool) $callback($log)) /** @phpstan-ignore-line */ diff --git a/src/LogFake.php b/src/LogFake.php index 34beea7..1d6a552 100644 --- a/src/LogFake.php +++ b/src/LogFake.php @@ -201,7 +201,7 @@ public function allLogs(): Collection /** * @return Collection */ - public function allChannelsAndStacks(): Collection + private function allChannelsAndStacks(): Collection { return Collection::make($this->channels)->merge($this->stacks); } diff --git a/tests/LogFakeApiTest.php b/tests/LogFakeApiTest.php index ac44521..282940d 100644 --- a/tests/LogFakeApiTest.php +++ b/tests/LogFakeApiTest.php @@ -9,6 +9,7 @@ use Stringable; use Symfony\Component\VarDumper\VarDumper; use Throwable; +use TiMacDonald\CallableFake\CallableFake; use TiMacDonald\Log\ChannelFake; use TiMacDonald\Log\LogEntry; use TiMacDonald\Log\LogFake; @@ -20,35 +21,6 @@ */ class LogFakeApiTest extends TestCase { - public function testLogged(): void - { - $log = new LogFake(); - - // default channel... - self::assertTrue($log->logged(fn () => true)->isEmpty()); - self::assertTrue($log->logged(fn () => false)->isEmpty()); - $log->info('xxxx'); - self::assertCount(1, $log->logged(fn () => true)); - self::assertSame('xxxx', $log->logged(fn () => true)[0]->message); - self::assertTrue($log->logged(fn () => false)->isEmpty()); - - // channel... - self::assertTrue($log->channel('channel')->logged(fn () => true)->isEmpty()); - self::assertTrue($log->channel('channel')->logged(fn () => false)->isEmpty()); - $log->channel('channel')->info('xxxx'); - self::assertCount(1, $log->channel('channel')->logged(fn () => true)); - self::assertSame('xxxx', $log->channel('channel')->logged(fn () => true)[0]->message); - self::assertTrue($log->channel('channel')->logged(fn () => false)->isEmpty()); - - // stack... - self::assertTrue($log->stack(['c1', 'c2'], 'name')->logged(fn () => true)->isEmpty()); - self::assertTrue($log->stack(['c1', 'c2'], 'name')->logged(fn () => false)->isEmpty()); - $log->stack(['c1', 'c2'], 'name')->info('xxxx'); - self::assertCount(1, $log->stack(['c1', 'c2'], 'name')->logged(fn () => true)); - self::assertSame('xxxx', $log->stack(['c1', 'c2'], 'name')->logged(fn () => true)[0]->message); - self::assertTrue($log->stack(['c1', 'c2'], 'name')->logged(fn () => false)->isEmpty()); - } - public function testLoggingLevelMethods(): void { $log = new LogFake(); @@ -201,18 +173,6 @@ public function testSetDefaultDriver(): void self::assertSame('expected-driver', config()->get('logging.default')); } - public function testLoggedClosureWithNonBooleanReturn(): void - { - $log = new LogFake(); - $log->info('xxxx'); - - $logs = $log->logged(fn () => 0); /** @phpstan-ignore-line */ - self::assertCount(0, $logs); - - $logs = $log->logged(fn () => 1); /** @phpstan-ignore-line */ - self::assertCount(1, $logs); - } - public function testDummyMethods(): void { $log = new LogFake(); @@ -516,50 +476,58 @@ public function testItHandlesNullDriverConfig(): void public function testItCanLogStringableObjects(): void { $log = new LogFake(); - $stringable = new class () implements Stringable { + $callable = new CallableFake(fn () => true); + $log->info(new class () implements Stringable { public function __toString(): string { return 'expected message'; } - }; - - $log->info($stringable); + }); + $log->assertLogged($callable->asClosure()); - $message = $log->logged(fn () => true)[0]->message; - assert($message instanceof Stringable); - self::assertSame($message->__toString(), 'expected message'); + $callable->assertCalledTimes(function (LogEntry $log) { + return $log->message instanceof Stringable && $log->message->__toString() === 'expected message'; + }, 1); } public function testItAddsContextToLogs(): void { $log = new LogFake(); + $callable = new CallableFake(fn () => true); $log->withContext(['foo' => 'xxxx']) ->withContext(['bar' => 'xxxx']) ->info('expected message', [ 'baz' => 'xxxx', ]); + $log->assertLogged($callable->asClosure()); - self::assertSame($log->logged(fn () => true)[0]->context, [ - 'foo' => 'xxxx', - 'bar' => 'xxxx', - 'baz' => 'xxxx', - ]); + $callable->assertCalledTimes(function (LogEntry $log) { + return $log->context === [ + 'foo' => 'xxxx', + 'bar' => 'xxxx', + 'baz' => 'xxxx', + ]; + }, 1); } public function testItCanClearContext(): void { $log = new LogFake(); + $callable = new CallableFake(fn () => true); $log->withContext(['foo' => 'xxxx']) ->withoutContext() ->info('expected message', [ 'baz' => 'xxxx', ]); + $log->assertLogged($callable->asClosure()); - self::assertSame($log->logged(fn () => true)[0]->context, [ - 'baz' => 'xxxx', - ]); + $callable->assertCalledTimes(function (LogEntry $log) { + return $log->context === [ + 'baz' => 'xxxx', + ]; + }, 1); }