JsonInvoiceStateAdapterTest.php
Pfad: tests/Rechnung/JsonInvoiceStateAdapterTest.php
Ext: php
Größe: 1700 Bytes
Geändert: 2026-07-16 16:54:17+02
<?php
declare(strict_types=1);
namespace Tests\Rechnung;
use Demo\Domain\Rechnung\InvoiceRecord;
use Demo\Domain\Rechnung\InvoiceState;
use Demo\Domain\Rechnung\InvoiceStatus;
use Demo\Infrastructure\Rechnung\JsonInvoiceStateAdapter;
use PHPUnit\Framework\TestCase;
use RuntimeException;
/**
* Prueft fail-closed und atomare JSON-Persistenz.
*/
final class JsonInvoiceStateAdapterTest extends TestCase
{
private string $path;
/** Erzeugt einen isolierten Testpfad. */
protected function setUp(): void
{
$this->path = sys_get_temp_dir() . '/invoice-state-' . bin2hex(random_bytes(8)) . '.json';
}
/** Entfernt lokale Testartefakte. */
protected function tearDown(): void
{
@unlink($this->path);
@unlink($this->path . '.lock');
}
/** Korrupter State darf niemals als leerer Erstlauf gelten. */
public function testKorruptesJsonBrichtAb(): void
{
file_put_contents($this->path, '{');
$this->expectException(RuntimeException::class);
(new JsonInvoiceStateAdapter($this->path))->load();
}
/** Save innerhalb des Prozesslocks bleibt atomar und reentrant. */
public function testExklusiverRoundtrip(): void
{
$adapter = new JsonInvoiceStateAdapter($this->path);
$record = new InvoiceRecord('source', 'key', InvoiceStatus::DISCOVERED);
$adapter->withExclusiveLock(function () use ($adapter, $record): void {
$adapter->save(InvoiceState::empty()->withRecord($record));
});
self::assertSame('source', $adapter->load()->all()[0]->quelleId);
self::assertSame(InvoiceState::SCHEMA_VERSION, $adapter->load()->schemaVersion);
}
}