Files
api/services/nginx/app/tests/Unit/Workfeed/DepartmentWeatherTimelineRangeTest.php
T

91 lines
3.7 KiB
PHP

<?php
app_require('routes/moduleWeatherAPIRoute.php');
use routes\moduleWeatherAPIRoute;
function weather_timeline_range_invoke_private(moduleWeatherAPIRoute $route, string $method, array $args = []): mixed
{
$reflection = new ReflectionClass($route);
$target = $reflection->getMethod($method);
$target->setAccessible(true);
return $target->invokeArgs($route, $args);
}
beforeEach(function (): void {
$_SERVER['REQUEST_URI'] = '/departments/weather';
});
it('builds a timeline range from start of yesterday to end of today', function (): void {
$route = new moduleWeatherAPIRoute();
$range = weather_timeline_range_invoke_private($route, 'getDepartmentWeatherTimelineRange');
$expectedStart = new DateTime(date('Y-m-d 00:00:00'));
$expectedStart->sub(new DateInterval('P1D'));
$expectedEndExclusive = new DateTime(date('Y-m-d 00:00:00'));
$expectedEndExclusive->add(new DateInterval('P1D'));
expect($range['start'] instanceof DateTime)->toBeTrue();
expect($range['endExclusive'] instanceof DateTime)->toBeTrue();
expect($range['start']->format('Y-m-d H:i:s'))->toBe($expectedStart->format('Y-m-d H:i:s'));
expect($range['endExclusive']->format('Y-m-d H:i:s'))->toBe($expectedEndExclusive->format('Y-m-d H:i:s'));
$hourCount = (int)(($range['endExclusive']->getTimestamp() - $range['start']->getTimestamp()) / 3600);
expect($hourCount)->toBe(48);
});
it('builds a timeline range relative to explicit date_from and date_to override', function (): void {
$route = new moduleWeatherAPIRoute();
$range = weather_timeline_range_invoke_private($route, 'getDepartmentWeatherTimelineRange', ['2026-03-08', '2026-03-10']);
expect($range['start']->format('Y-m-d H:i:s'))->toBe('2026-03-08 00:00:00');
expect($range['endExclusive']->format('Y-m-d H:i:s'))->toBe('2026-03-11 00:00:00');
$hourCount = (int)(($range['endExclusive']->getTimestamp() - $range['start']->getTimestamp()) / 3600);
expect($hourCount)->toBe(72);
});
it('resolves forecast day count for a given timeline range with sane limits', function (): void {
$route = new moduleWeatherAPIRoute();
$start = new DateTime(date('Y-m-d 00:00:00'));
$end = new DateTime(date('Y-m-d 00:00:00'));
$end->add(new DateInterval('P3D'));
$days = weather_timeline_range_invoke_private($route, 'resolveForecastDaysForTimelineRange', [$start, $end]);
expect($days)->toBe(3);
$farEnd = new DateTime(date('Y-m-d 00:00:00'));
$farEnd->add(new DateInterval('P40D'));
$clamped = weather_timeline_range_invoke_private($route, 'resolveForecastDaysForTimelineRange', [$start, $farEnd]);
expect($clamped)->toBe(14);
$pastStart = new DateTime(date('Y-m-d 00:00:00'));
$pastStart->sub(new DateInterval('P10D'));
$pastEnd = new DateTime(date('Y-m-d 00:00:00'));
$pastEnd->sub(new DateInterval('P5D'));
$pastDays = weather_timeline_range_invoke_private($route, 'resolveForecastDaysForTimelineRange', [$pastStart, $pastEnd]);
expect($pastDays)->toBe(1);
});
it('marks non-started slots as unknown regardless of wash-hour ratio', function (): void {
$route = new moduleWeatherAPIRoute();
$targets = [
'degraded_threshold' => 1.0,
'healthy_threshold' => 1.3,
];
$futureStatus = weather_timeline_range_invoke_private($route, 'calculateStatus', [10, 2.0, false, $targets]);
expect($futureStatus)->toBe('unknown');
$missingTargetStatus = weather_timeline_range_invoke_private($route, 'calculateStatus', [10, 2.0, true]);
expect($missingTargetStatus)->toBe('unknown');
$startedStatus = weather_timeline_range_invoke_private($route, 'calculateStatus', [10, 2.0, true, $targets]);
expect($startedStatus)->toBe('healthy');
});