Files
api/services/nginx/app/tests/Unit/XLVask/XLVaskUsageHallScopeTest.php
T

160 lines
4.6 KiB
PHP

<?php
require_once dirname(__DIR__, 3) . '/routes/xlvaskUsageLogsRoute.php';
class XLVaskUsageHallScopeRouteHarness extends \routes\xlvaskUsageLogsRoute
{
public bool $hasAllPermission = false;
public function __construct()
{
// Avoid request initialization in this focused unit test.
}
public function hasPermission(
string|\classes\permission_node $permission,
?int $customer_number = null
): bool {
$permissionKey = $permission instanceof \classes\permission_node
? (string)$permission->permission
: $permission;
return $this->hasAllPermission && $permissionKey === 'list_xlvask_usage_orders_all';
}
}
class XLVaskUsageHallScopeDbFake
{
public int $queryCount = 0;
private bool $softDeleteQueryAttempted = false;
/** @param array<int,array{HallId:mixed}> $rows */
public function __construct(
private readonly array $rows,
private readonly bool $deletedAtColumnMissing = false
)
{
}
public function query(string $sql): object
{
$this->queryCount++;
if ($this->deletedAtColumnMissing
&& !$this->softDeleteQueryAttempted
&& str_contains($sql, 'deleted_at IS NULL')) {
$this->softDeleteQueryAttempted = true;
throw new \Exception("Unknown column 'deleted_at' in 'WHERE'");
}
expect($sql)->toContain('SELECT DISTINCT HallId FROM plate_scanners');
return new stdClass();
}
/** @return array<int,array{HallId:mixed}> */
public function fetch_all(object $result): array
{
return $this->rows;
}
}
/**
* @param array<int,mixed> $groupHallIds
*/
function xlvask_usage_hall_scope_user(array $groupHallIds): object
{
return new class($groupHallIds) {
/** @param array<int,mixed> $groupHallIds */
public function __construct(private readonly array $groupHallIds)
{
}
public function getGroup(): object
{
return new class($this->groupHallIds) {
/** @param array<int,mixed> $groupHallIds */
public function __construct(private readonly array $groupHallIds)
{
}
/** @return array<int,mixed> */
public function getDepartmentsScannersHallIds(): array
{
return $this->groupHallIds;
}
};
}
};
}
/** @param array<int,mixed> $groupHallIds */
function resolve_xlvask_usage_hall_scope(
XLVaskUsageHallScopeRouteHarness $route,
XLVaskUsageHallScopeDbFake $dbFake,
array $groupHallIds
): array {
$hadDb = array_key_exists('db', $GLOBALS);
$originalDb = $GLOBALS['db'] ?? null;
$GLOBALS['db'] = $dbFake;
try {
$method = new ReflectionMethod(\routes\xlvaskUsageLogsRoute::class, 'allowedHallIdsForUser');
return $method->invoke($route, xlvask_usage_hall_scope_user($groupHallIds));
} finally {
if ($hadDb) {
$GLOBALS['db'] = $originalDb;
} else {
unset($GLOBALS['db']);
}
}
}
it('uses every normalized scanner hall for users with all-scope permission', function (): void {
$route = new XLVaskUsageHallScopeRouteHarness();
$route->hasAllPermission = true;
$dbFake = new XLVaskUsageHallScopeDbFake([
['HallId' => ' Hall-A '],
['HallId' => ''],
['HallId' => 'Hall-A'],
['HallId' => str_repeat('x', 192)],
['HallId' => 'Hall-B'],
]);
$hallIds = resolve_xlvask_usage_hall_scope($route, $dbFake, ['Own-Hall']);
expect($hallIds)->toBe(['Hall-A', 'Hall-B'])
->and($dbFake->queryCount)->toBe(1);
});
it('falls back when plate scanners table has no deleted_at column', function (): void {
$route = new XLVaskUsageHallScopeRouteHarness();
$route->hasAllPermission = true;
$dbFake = new XLVaskUsageHallScopeDbFake([
['HallId' => ' Hall-A '],
['HallId' => 'Hall-B'],
], true);
$hallIds = resolve_xlvask_usage_hall_scope($route, $dbFake, ['Own-Hall']);
expect($hallIds)->toBe(['Hall-A', 'Hall-B'])
->and($dbFake->queryCount)->toBe(2);
});
it('keeps own-scope users limited to normalized group halls', function (): void {
$route = new XLVaskUsageHallScopeRouteHarness();
$dbFake = new XLVaskUsageHallScopeDbFake([
['HallId' => 'Global-Hall'],
]);
$hallIds = resolve_xlvask_usage_hall_scope($route, $dbFake, [
' Own-Hall-A ',
'',
'Own-Hall-A',
'Own-Hall-B',
]);
expect($hallIds)->toBe(['Own-Hall-A', 'Own-Hall-B'])
->and($dbFake->queryCount)->toBe(0);
});