Lines 0.00% 0 / 11
Methods 0.00% 0 / 4
Classes 0.00% 0 / 1
Name Lines Methods CRAP
 __construct 0.00% 0 / 1 0.00% 0 / 1 2
 log 0.00% 0 / 4 0.00% 0 / 1 6
 waitForMessage 0.00% 0 / 3 0.00% 0 / 1 6
 listMessagesAt 0.00% 0 / 3 0.00% 0 / 1 2
13final class RecordingLogger extends AbstractLogger
14{
15    public private(set) RecordedLogCollection $records;
16
17    /** @var array<string, DeferredFuture<null>> */
18    private array $awaited = [];
19
20    public function __construct()
21    {
22        $this->records = RecordedLogCollection::empty();
23    }
24
25    /**
26     * @param mixed $level
27     * @param array<mixed> $context
28     */
29    public function log($level, string|Stringable $message, array $context = []): void
30    {
31        $this->records = $this->records->withRecordedLog(new RecordedLog(\is_string($level) ? $level : 'unknown', (string) $message, $context));
32
33        $awaited = $this->awaited[(string) $message] ?? null;
34        unset($this->awaited[(string) $message]);
35        $awaited?->complete();
36    }
37
38    /** @return Future<null> */
39    public function waitForMessage(string $message): Future
40    {
41        if ($this->records->containsWhere(static fn(RecordedLog $record): bool => $record->message === $message)) {
42            return Future::complete();
43        }
44
45        return ($this->awaited[$message] ??= new DeferredFuture())->getFuture();
46    }
47
48    /** @return list<string> */
49    public function listMessagesAt(string $level): array
50    {
51        return $this->records
52            ->filter(static fn(RecordedLog $record): bool => $record->level === $level)
53            ->mapToList(static fn(RecordedLog $record): string => $record->message);
54    }
55}