$values */ private function makeGateway(array $values = []): SecurityReportSettingsGateway { $metadata = $this->createMock(SettingsMetadataGateway::class); $metadata->method('getValue')->willReturnCallback(static fn (string $key): ?string => $values[$key] ?? null); $metadata->method('set')->willReturn(true); return new SecurityReportSettingsGateway($metadata); } public function testTemplateDefaultsToEmpty(): void { $gateway = $this->makeGateway(); $this->assertSame('', $gateway->getTemplateHtml()); $this->assertFalse($gateway->hasCustomTemplate()); } public function testGetTemplateHtmlReturnsTrimmedStoredValue(): void { $gateway = $this->makeGateway([ SecurityReportSettingsGateway::KEY_TEMPLATE_HTML => "

{{title}}

", ]); $this->assertSame('

{{title}}

', $gateway->getTemplateHtml()); $this->assertTrue($gateway->hasCustomTemplate()); } public function testSetTemplateHtmlRejectsOversizedTemplate(): void { $gateway = $this->makeGateway(); $tooLong = str_repeat('a', SecurityReportSettingsGateway::MAX_TEMPLATE_LENGTH + 1); $this->assertFalse($gateway->setTemplateHtml($tooLong)); } public function testSetTemplateHtmlPersistsValueAndClearsOnEmpty(): void { $writes = []; $metadata = $this->createMock(SettingsMetadataGateway::class); $metadata->method('getValue')->willReturn(null); $metadata->method('set')->willReturnCallback(static function (string $key, ?string $value, ?string $description = null) use (&$writes): bool { $writes[$key] = $value; return true; }); $gateway = new SecurityReportSettingsGateway($metadata); $this->assertTrue($gateway->setTemplateHtml('

x

')); $this->assertSame('

x

', $writes[SecurityReportSettingsGateway::KEY_TEMPLATE_HTML]); // Blank input clears the setting (restores the built-in default). $this->assertTrue($gateway->setTemplateHtml(' ')); $this->assertNull($writes[SecurityReportSettingsGateway::KEY_TEMPLATE_HTML]); } }