Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow integer log levels #3

Merged
merged 18 commits into from
Mar 14, 2023
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 34 additions & 12 deletions src/TestLogger.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,27 @@ final class TestLogger extends AbstractLogger
/** @var array<int|string, array<int, array<string, mixed>>> */
public array $recordsByLevel = [];

/** @var array<string, string|int> */
public array $levelMap = [
jonathanjfshaw marked this conversation as resolved.
Show resolved Hide resolved
LogLevel::EMERGENCY => LogLevel::EMERGENCY,
LogLevel::ALERT => LogLevel::ALERT,
LogLevel::CRITICAL => LogLevel::CRITICAL,
LogLevel::ERROR => LogLevel::ERROR,
LogLevel::WARNING => LogLevel::WARNING,
LogLevel::NOTICE => LogLevel::NOTICE,
LogLevel::INFO => LogLevel::INFO,
LogLevel::DEBUG => LogLevel::DEBUG,
];

/**
* @param array<string, string|int>|null $levelMap
* Keys are LogLevel::*, values are alternative strings or integers used as log levels in the SUT.
jonathanjfshaw marked this conversation as resolved.
Show resolved Hide resolved
*/
public function __construct(?array $levelMap = null)
{
$this->levelMap = $levelMap ?? $this->levelMap;
}

/**
* {@inheritDoc}
*
Expand All @@ -83,18 +104,18 @@ public function log($level, $message, array $context = []): void
}

/**
* @param LogLevel::* $level
* @param string|int $level
*/
public function hasRecords(string $level): bool
public function hasRecords(string|int $level): bool
{
return isset($this->recordsByLevel[$level]);
}

/**
* @param string|array<string, mixed> $record
* @param LogLevel::* $level
* @param string|int $level
*/
public function hasRecord($record, string $level): bool
public function hasRecord($record, string|int $level): bool
{
if (\is_string($record)) {
$record = ['message' => $record];
Expand All @@ -110,19 +131,19 @@ public function hasRecord($record, string $level): bool
}

/**
* @param LogLevel::* $level
* @param string|int $level
*/
public function hasRecordThatContains(string $message, string $level): bool
public function hasRecordThatContains(string $message, string|int $level): bool
{
return $this->hasRecordThatPasses(static function (array $rec) use ($message) {
return \strpos($rec['message'], $message) !== false;
}, $level);
}

/**
* @param LogLevel::* $level
* @param string|int $level
*/
public function hasRecordThatMatches(string $regex, string $level): bool
public function hasRecordThatMatches(string $regex, string|int $level): bool
{
return $this->hasRecordThatPasses(static function ($rec) use ($regex) {
return \preg_match($regex, $rec['message']) > 0;
Expand All @@ -131,9 +152,9 @@ public function hasRecordThatMatches(string $regex, string $level): bool

/**
* @param callable(array<string, mixed>, int): bool $predicate
* @param LogLevel::* $level
* @param string|int $level
*/
public function hasRecordThatPasses(callable $predicate, string $level): bool
public function hasRecordThatPasses(callable $predicate, string|int $level): bool
{
if (! isset($this->recordsByLevel[$level])) {
return false;
Expand All @@ -153,10 +174,11 @@ public function hasRecordThatPasses(callable $predicate, string $level): bool
*/
public function __call(string $method, array $args): bool
{
if (\preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) {
$levelNames = \implode('|', \array_map('ucfirst', \array_keys($this->levelMap)));
if (\preg_match('/(.*)(' . $levelNames . ')(.*)/', $method, $matches) > 0) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing the idea behind this change is that a user may have instantiated the TestLogger without defining all of those levels in their map? If so, I think my preference would be to revert this change and add some validation to the constructor to ensure that the map contains all log levels. That would ensure that all of the magic methods defined on lines 15-54 are always available and guaranteed to never throw a BadMethodCallException.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this was motivated by DRY. It smelled to me to repeat the name information twice in the class. I have kept this code, but added the requested validation to the __construct() method. Happy to remove this code if you prefer the simplicity of explicit repetition instead of DRY.

$genericMethod = $matches[1] . ($matches[3] !== 'Records' ? 'Record' : '') . $matches[3];
$callable = [$this, $genericMethod];
$level = \strtolower($matches[2]);
$level = $this->levelMap[\strtolower($matches[2])];
if (\is_callable($callable)) {
$args[] = $level;

Expand Down