76 lines
3.6 KiB
PHP
76 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit;
|
|
|
|
use App\Services\CartographyWorkbookAudit;
|
|
use PHPUnit\Framework\TestCase;
|
|
use RuntimeException;
|
|
use ZipArchive;
|
|
|
|
class CartographyWorkbookAuditTest extends TestCase
|
|
{
|
|
private string $path;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->path = tempnam(sys_get_temp_dir(), 'gis-test-');
|
|
$zip = new ZipArchive;
|
|
$zip->open($this->path, ZipArchive::OVERWRITE);
|
|
$zip->addFromString('xl/workbook.xml', '<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><sheets><sheet name="Synthetic" sheetId="1" r:id="rId1"/></sheets></workbook>');
|
|
$zip->addFromString('xl/_rels/workbook.xml.rels', '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Target="worksheets/sheet1.xml"/></Relationships>');
|
|
$zip->addFromString('xl/worksheets/sheet1.xml', '<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData><row r="1"><c r="A1" t="inlineStr"><is><t>Private synthetic label</t></is></c></row><row r="2"><c r="A2" t="inlineStr"><is><t>Private synthetic label</t></is></c></row><row r="3"><c r="B3"><f>1+1</f><v>2</v></c><c r="C3"/></row></sheetData></worksheet>');
|
|
$zip->close();
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
unlink($this->path);
|
|
parent::tearDown();
|
|
}
|
|
|
|
/** @return array<string, string> */
|
|
private function manifest(): array
|
|
{
|
|
return ['sha256' => hash_file('sha256', $this->path), 'owner' => 'Synthetic owner', 'version' => 'test-1',
|
|
'received_at' => '2026-09-28', 'classification' => 'internal', 'inspection_authorization' => 'Synthetic test only'];
|
|
}
|
|
|
|
public function test_audit_quarantines_unknown_crs_and_reports_duplicates_without_copying_source_values(): void
|
|
{
|
|
$report = (new CartographyWorkbookAudit)->inspect($this->path, $this->manifest());
|
|
$this->assertSame(3, $report['rows_inspected']);
|
|
$this->assertSame('quarantined', $report['status']);
|
|
$this->assertFalse($report['publication_allowed']);
|
|
$this->assertSame([], $report['transformations']);
|
|
$this->assertSame('duplicate', $report['sheets'][0]['rows'][1]['status']);
|
|
$this->assertStringNotContainsString('Private synthetic label', json_encode($report));
|
|
$this->assertStringContainsString('formula_not_evaluated', json_encode($report));
|
|
$this->assertStringContainsString('original_crs_unknown', json_encode($report));
|
|
}
|
|
|
|
public function test_checksum_mismatch_is_rejected(): void
|
|
{
|
|
$this->expectException(RuntimeException::class);
|
|
$this->expectExceptionMessage('checksum');
|
|
(new CartographyWorkbookAudit)->inspect($this->path, [...$this->manifest(), 'sha256' => str_repeat('0', 64)]);
|
|
}
|
|
|
|
public function test_inspection_requires_authorization_evidence(): void
|
|
{
|
|
$this->expectException(RuntimeException::class);
|
|
(new CartographyWorkbookAudit)->inspect($this->path, [...$this->manifest(), 'inspection_authorization' => '']);
|
|
}
|
|
|
|
public function test_xml_entities_are_rejected(): void
|
|
{
|
|
$zip = new ZipArchive;
|
|
$zip->open($this->path);
|
|
$zip->addFromString('xl/workbook.xml', '<!DOCTYPE workbook [<!ENTITY x SYSTEM "file:///secret">]><workbook>&x;</workbook>');
|
|
$zip->close();
|
|
$this->expectException(RuntimeException::class);
|
|
$this->expectExceptionMessage('unsafe');
|
|
(new CartographyWorkbookAudit)->inspect($this->path, $this->manifest());
|
|
}
|
|
}
|