69 lines
2.5 KiB
PHP
69 lines
2.5 KiB
PHP
<?php
|
|||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
require_once __DIR__ . '/../app/Domain/Reporting/ReportDataMapper.php';
|
||
|
|
require_once __DIR__ . '/../app/Domain/Reporting/HoursPerClientReport.php';
|
||
|
|
require_once __DIR__ . '/../app/Domain/Reporting/SlaReport.php';
|
||
|
|
|
||
|
|
function reporting_assert_same(mixed $expected, mixed $actual, string $message): void
|
||
|
|
{
|
||
|
|
if ($expected !== $actual) {
|
||
|
|
throw new RuntimeException($message . "\nExpected: " . var_export($expected, true) . "\nActual: " . var_export($actual, true));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$record = [
|
||
|
|
'id' => 7,
|
||
|
|
'name' => 'Acme IT',
|
||
|
|
'status' => 'active',
|
||
|
|
'support_email' => 'support@example.test',
|
||
|
|
'internal_notes' => 'never disclose',
|
||
|
|
'password' => 'secret',
|
||
|
|
'credentials' => 'token',
|
||
|
|
'technical_ip' => '10.0.0.1',
|
||
|
|
'unknown_field' => 'not approved',
|
||
|
|
];
|
||
|
|
$mapper = new ReportDataMapper();
|
||
|
|
reporting_assert_same(
|
||
|
|
['id' => 7, 'name' => 'Acme IT', 'status' => 'active', 'support_email' => 'support@example.test'],
|
||
|
|
$mapper->clientFacing($record),
|
||
|
|
'Client-facing report data must be allow-listed.'
|
||
|
|
);
|
||
|
|
reporting_assert_same(
|
||
|
|
['internal_notes' => 'never disclose', 'password' => 'secret', 'credentials' => 'token', 'technical_ip' => '10.0.0.1', 'unknown_field' => 'not approved'],
|
||
|
|
$mapper->internal($record),
|
||
|
|
'Internal report data must remain separate from client-facing data.'
|
||
|
|
);
|
||
|
|
|
||
|
|
$hours = new HoursPerClientReport();
|
||
|
|
reporting_assert_same(
|
||
|
|
[
|
||
|
|
['client_id' => 7, 'client_name' => 'Acme IT', 'hours' => 3.0],
|
||
|
|
['client_id' => 2, 'client_name' => 'Beta', 'hours' => 3.5],
|
||
|
|
],
|
||
|
|
$hours->aggregate([
|
||
|
|
['client_id' => 7, 'client_name' => 'Acme IT', 'hours' => 1.25],
|
||
|
|
['client_id' => 2, 'client_name' => 'Beta', 'hours' => 3.5, 'internal_notes' => 'omit'],
|
||
|
|
['client_id' => 7, 'client_name' => 'Acme IT', 'hours' => 1.75, 'password' => 'omit'],
|
||
|
|
]),
|
||
|
|
'Hours must aggregate deterministically per client.'
|
||
|
|
);
|
||
|
|
|
||
|
|
$sla = new SlaReport();
|
||
|
|
reporting_assert_same(
|
||
|
|
[
|
||
|
|
['client_id' => 7, 'client_name' => 'Acme IT', 'allocated_hours' => 10.0, 'used_hours' => 9.0, 'remaining_hours' => 1.0, 'usage_percentage' => 90.0, 'status' => 'critical'],
|
||
|
|
],
|
||
|
|
$sla->rows([[
|
||
|
|
'client_id' => 7,
|
||
|
|
'client_name' => 'Acme IT',
|
||
|
|
'allocated_hours' => 10,
|
||
|
|
'hours' => [4, 5, -2],
|
||
|
|
'internal_notes' => 'omit',
|
||
|
|
'credentials' => 'omit',
|
||
|
|
]]),
|
||
|
|
'SLA rows must expose only safe, deterministic report fields.'
|
||
|
|
);
|
||
|
|
|
||
|
|
printf("Reporting contract tests: 3 passed\n");
|