From b041124a4cb3ecffc91364715b199eb3130000c7 Mon Sep 17 00:00:00 2001 From: Rudolph Gottesheim Date: Wed, 11 Mar 2026 09:20:03 +0100 Subject: [PATCH] Add contextValueEquals() matcher to TestLogger Provides a concise way to assert that a log context key holds a specific value using strict equality, without writing a custom value-matcher callable. Co-Authored-By: Claude Sonnet 4.6 --- doc/TestLogger.md | 27 +++++++++++++++++++++++++++ src/TestLogger.php | 13 +++++++++++++ tests/unit/TestLoggerTest.php | 29 +++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/doc/TestLogger.md b/doc/TestLogger.md index 666b25a..c5c84e3 100644 --- a/doc/TestLogger.md +++ b/doc/TestLogger.md @@ -192,6 +192,33 @@ Context value "response_time" does not match: Response too fast: 500 ms ``` +### `contextValueEquals(string $key, mixed $expected): callable` + +Matches log records where a specific context key exists and its value is strictly equal (`===`) to `$expected`. + +This is a convenience shorthand for `contextValueMatches($key, Val::eq($expected))`. + +```php +// Check if status_code equals 200 +TestLogger::contextValueEquals('status_code', 200) + +// Check if environment equals "production" +TestLogger::contextValueEquals('environment', 'production') +``` + +**Example failure messages:** + +When key doesn't exist: +``` +Context has no key "status_code". +``` + +When value doesn't match: +``` +Context value "status_code" does not match: + Expected value 200, but got 500. +``` + ### `exceptionMatches(callable $exceptionMatcher): callable` Matches log records where the context contains an `exception` key with a `Throwable` value that satisfies the provided matcher. diff --git a/src/TestLogger.php b/src/TestLogger.php index dc4894f..a903964 100644 --- a/src/TestLogger.php +++ b/src/TestLogger.php @@ -4,6 +4,7 @@ namespace Eventjet\TestDouble; +use Eventjet\TestDouble\Matcher\Val; use Override; use Psr\Log\AbstractLogger; use Stringable; @@ -111,6 +112,18 @@ public static function contextValueMatches(string $key, callable $valueMatcher): }; } + /** + * Matches log records where a specific context key exists and its value is strictly equal to $expected. + * + * This is a convenience wrapper around {@see contextValueMatches()} and {@see Val::eq()}. + * + * @return Matcher + */ + public static function contextValueEquals(string $key, mixed $expected): callable + { + return self::contextValueMatches($key, Val::eq($expected)); + } + /** * @param ExceptionMatcher $exceptionMatcher * @return Matcher diff --git a/tests/unit/TestLoggerTest.php b/tests/unit/TestLoggerTest.php index 241ce7f..9686e2e 100644 --- a/tests/unit/TestLoggerTest.php +++ b/tests/unit/TestLoggerTest.php @@ -144,6 +144,27 @@ public static function onceIssueCases(): iterable Expected an instance of Throwable, got DateTime. EOF, ]; + yield 'contextValueEquals: key does not exist' => [ + [new LogRecord(LogLevel::INFO, 'Foo', ['bar' => 'baz'])], + TestLogger::contextValueEquals('foo', 'baz'), + <<<'EOF' + None of the records matched: + + Record 0: + Context has no key "foo". + EOF, + ]; + yield 'contextValueEquals: value does not match' => [ + [new LogRecord(LogLevel::INFO, 'Foo', ['foo' => 'actual'])], + TestLogger::contextValueEquals('foo', 'expected'), + <<<'EOF' + None of the records matched: + + Record 0: + Context value "foo" does not match: + Expected value "expected", but got "actual". + EOF, + ]; } /** @@ -199,6 +220,14 @@ public function __toString(): string static fn(Throwable $error) => $error instanceof CustomError ? true : 'Wrong', ), ]; + yield 'contextValueEquals: value matches' => [ + [new LogRecord(LogLevel::INFO, 'Foo', ['foo' => 'bar'])], + TestLogger::contextValueEquals('foo', 'bar'), + ]; + yield 'contextValueEquals: integer value matches' => [ + [new LogRecord(LogLevel::INFO, 'Foo', ['count' => 42])], + TestLogger::contextValueEquals('count', 42), + ]; } /**