Skip to content

Commit c5f2099

Browse files
committed
Satisfy PHPMD and cover Safe logger edge paths
CI surfaced two checks the unpushed branch had never run locally: - sa/PHPMD flagged UnusedFormalParameter on no-op / contract-driven signatures. Add @SuppressWarnings("PHPMD.UnusedFormalParameter") (quoted so PHPStan's phpDoc parser accepts the dotted rule name) on NullSemanticLogger and on SafeSemanticLogger::__unserialize, whose parameters are required by the interface / magic-method contract but intentionally unused. - codecov (100% target) flagged the no-op NullSemanticLogger methods and the best-effort catch blocks in SafeSemanticLogger::event()/close() as uncovered. NullSemanticLogger is a pure no-op null object, so its methods are marked @codeCoverageIgnore; the SafeSemanticLogger catch blocks are the resilience guarantee, so they get real failure tests instead. Also address review nitpicks: merge the two stacked docblocks on StructuredRepositoryLoggerInterface, and unlink the temp file in SemanticLogTreeTrait.
1 parent c8744bf commit c5f2099

5 files changed

Lines changed: 87 additions & 4 deletions

File tree

src/Log/NullSemanticLogger.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,28 +15,42 @@
1515
* Zero-cost default when cache logging is turned off. open() returns an empty
1616
* id (which SafeSemanticLogger and disciplined call sites treat as "no close
1717
* needed"), and flush() returns an empty log session.
18+
*
19+
* Every parameter is dictated by SemanticLoggerInterface and intentionally
20+
* unused in this no-op implementation. The methods are trivial no-ops with no
21+
* behavior to assert, so each is excluded from coverage rather than carrying
22+
* tests that prove nothing.
23+
*
24+
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
1825
*/
1926
final class NullSemanticLogger implements SemanticLoggerInterface
2027
{
2128
private const EMPTY_SCHEMA_URL = 'https://koriym.github.io/Koriym.SemanticLogger/schemas/semantic-log.json';
2229

30+
/** @codeCoverageIgnore */
2331
#[Override]
2432
public function open(AbstractContext $context): string
2533
{
2634
return '';
2735
}
2836

37+
/** @codeCoverageIgnore */
2938
#[Override]
3039
public function event(AbstractContext $context): void
3140
{
3241
}
3342

43+
/** @codeCoverageIgnore */
3444
#[Override]
3545
public function close(AbstractContext $context, string $openId): void
3646
{
3747
}
3848

39-
/** {@inheritDoc} */
49+
/**
50+
* {@inheritDoc}
51+
*
52+
* @codeCoverageIgnore
53+
*/
4054
#[Override]
4155
public function flush(array $links = []): LogJson
4256
{

src/Log/SafeSemanticLogger.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,13 @@ public function __serialize(): array
130130
return [];
131131
}
132132

133-
/** @param array<string, mixed> $data */
133+
/**
134+
* Session state is never carried across serialization, so the payload is ignored.
135+
*
136+
* @param array<string, mixed> $data
137+
*
138+
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
139+
*/
134140
public function __unserialize(array $data): void
135141
{
136142
$this->logger = new SemanticLogger();

src/StructuredRepositoryLoggerInterface.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010
* Separated from RepositoryLoggerInterface so that adding structured accessors
1111
* does not break third-party RepositoryLoggerInterface implementations (BC).
1212
* Use this for structural assertions instead of substring-matching __toString().
13-
*/
14-
/**
13+
*
1514
* @deprecated Since the SemanticLogger migration; structured logs are now the
1615
* {@see \Koriym\SemanticLogger\LogJson} tree returned by SemanticLogger::flush().
1716
*/

tests/SafeSemanticLoggerTest.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,66 @@ public function testSerializesWithoutCarryingSessionState(): void
6868
$restored->close(new CacheMissContext('resource'), $id);
6969
$this->assertCount(1, $restored->flush()->toArray()['open']);
7070
}
71+
72+
public function testEventFailureIsSwallowed(): void
73+
{
74+
// Delegate succeeds on open() (so SafeSemanticLogger stays unbroken and enters
75+
// event()'s try) but throws on event(): the failure must be swallowed.
76+
$flaky = new class implements SemanticLoggerInterface {
77+
public function open(AbstractContext $context): string
78+
{
79+
return 'x';
80+
}
81+
82+
public function event(AbstractContext $context): void
83+
{
84+
throw new RuntimeException('event failed');
85+
}
86+
87+
public function close(AbstractContext $context, string $openId): void
88+
{
89+
}
90+
91+
public function flush(array $links = []): LogJson
92+
{
93+
return new LogJson('https://koriym.github.io/Koriym.SemanticLogger/schemas/semantic-log.json', [], [], [], $links);
94+
}
95+
};
96+
$safe = new SafeSemanticLogger($flaky);
97+
98+
$safe->open(new GetContext('page://self/x'));
99+
$safe->event(new CacheMissContext('resource')); // throws inside; must not escape
100+
// The session is marked broken and flush() returns an empty log without throwing.
101+
$this->assertSame([], $safe->flush()->toArray()['open']);
102+
}
103+
104+
public function testCloseFailureIsSwallowed(): void
105+
{
106+
// Delegate succeeds on open() but throws on close(): the failure must be swallowed.
107+
$flaky = new class implements SemanticLoggerInterface {
108+
public function open(AbstractContext $context): string
109+
{
110+
return 'x';
111+
}
112+
113+
public function event(AbstractContext $context): void
114+
{
115+
}
116+
117+
public function close(AbstractContext $context, string $openId): void
118+
{
119+
throw new RuntimeException('close failed');
120+
}
121+
122+
public function flush(array $links = []): LogJson
123+
{
124+
return new LogJson('https://koriym.github.io/Koriym.SemanticLogger/schemas/semantic-log.json', [], [], [], $links);
125+
}
126+
};
127+
$safe = new SafeSemanticLogger($flaky);
128+
129+
$id = $safe->open(new GetContext('page://self/x'));
130+
$safe->close(new CacheMissContext('resource'), $id); // throws inside; must not escape
131+
$this->assertSame([], $safe->flush()->toArray()['open']);
132+
}
71133
}

tests/SemanticLogTreeTrait.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use function ob_start;
1818
use function sys_get_temp_dir;
1919
use function tempnam;
20+
use function unlink;
2021

2122
use const JSON_UNESCAPED_SLASHES;
2223

@@ -52,6 +53,7 @@ private function flushAndValidate(SemanticLoggerInterface $logger): array
5253
(new SemanticLogValidator())->validate($file, $schemaDir);
5354
} finally {
5455
ob_get_clean();
56+
unlink($file);
5557
}
5658

5759
return $tree;

0 commit comments

Comments
 (0)