diff --git a/judge/judgedaemon.main.php b/judge/judgedaemon.main.php index 3fca91e93f..aa7065c71a 100644 --- a/judge/judgedaemon.main.php +++ b/judge/judgedaemon.main.php @@ -758,14 +758,14 @@ private function request(string $url, string $verb = 'GET', $data = '', bool $fa } } if ($trial == BACKOFF_STEPS) { - $errstr = $errstr . " Retry limit reached."; + $errstr .= " Retry limit reached."; } else { $retry_in_sec = $delay_in_sec + BACKOFF_JITTER_SEC * random_int(0, mt_getrandmax()) / mt_getrandmax(); $warnstr = $errstr . " This request will be retried after about " . round($retry_in_sec, 2) . "sec... (" . $trial . "/" . BACKOFF_STEPS . ")"; warning($warnstr); dj_sleep($retry_in_sec); - $delay_in_sec = $delay_in_sec * BACKOFF_FACTOR; + $delay_in_sec *= BACKOFF_FACTOR; } } if (!$succeeded) { @@ -860,7 +860,7 @@ private function runCommandSafe(array $command_parts, &$retval = DONT_CARE, $log return false; } - $command = implode(' ', array_map('dj_escapeshellarg', $command_parts)); + $command = implode(' ', array_map(dj_escapeshellarg(...), $command_parts)); logmsg(LOG_DEBUG, "Executing command: $command"); system($command, $retval_local); @@ -1771,10 +1771,10 @@ private function fetchTestcase(string $workdirpath, string $testcase_id, int $ju private function initsignals(): void { - pcntl_signal(SIGTERM, [self::class, 'signalHandler']); - pcntl_signal(SIGINT, [self::class, 'signalHandler']); - pcntl_signal(SIGHUP, [self::class, 'signalHandler']); - pcntl_signal(SIGUSR1, [self::class, 'signalHandler']); + pcntl_signal(SIGTERM, self::signalHandler(...)); + pcntl_signal(SIGINT, self::signalHandler(...)); + pcntl_signal(SIGHUP, self::signalHandler(...)); + pcntl_signal(SIGUSR1, self::signalHandler(...)); } } diff --git a/webapp/composer.json b/webapp/composer.json index 4defb3181d..18f1eb1b0d 100644 --- a/webapp/composer.json +++ b/webapp/composer.json @@ -110,6 +110,7 @@ "phpstan/phpstan": "^2.0", "phpstan/phpstan-doctrine": "^2.0", "phpunit/phpunit": "^9.6", + "rector/rector": "^2.2", "sebastian/diff": "*", "squizlabs/php_codesniffer": "*", "symfony/debug-bundle": "7.4.*", diff --git a/webapp/composer.lock b/webapp/composer.lock index 488dec6342..0c5b8113b9 100644 --- a/webapp/composer.lock +++ b/webapp/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "003ba90bd309e5dfb8183c828c6da8c2", + "content-hash": "994f1c88ded5fa9863d0857e43e37fa3", "packages": [ { "name": "brick/math", @@ -11243,6 +11243,66 @@ ], "time": "2025-09-24T06:29:11+00:00" }, + { + "name": "rector/rector", + "version": "2.2.11", + "source": { + "type": "git", + "url": "https://github.com/rectorphp/rector.git", + "reference": "7bd21a40b0332b93d4bfee284093d7400696902d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/7bd21a40b0332b93d4bfee284093d7400696902d", + "reference": "7bd21a40b0332b93d4bfee284093d7400696902d", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0", + "phpstan/phpstan": "^2.1.32" + }, + "conflict": { + "rector/rector-doctrine": "*", + "rector/rector-downgrade-php": "*", + "rector/rector-phpunit": "*", + "rector/rector-symfony": "*" + }, + "suggest": { + "ext-dom": "To manipulate phpunit.xml via the custom-rule command" + }, + "bin": [ + "bin/rector" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Instant Upgrade and Automated Refactoring of any PHP code", + "homepage": "https://getrector.com/", + "keywords": [ + "automation", + "dev", + "migration", + "refactoring" + ], + "support": { + "issues": "https://github.com/rectorphp/rector/issues", + "source": "https://github.com/rectorphp/rector/tree/2.2.11" + }, + "funding": [ + { + "url": "https://github.com/tomasvotruba", + "type": "github" + } + ], + "time": "2025-12-02T11:23:46+00:00" + }, { "name": "sebastian/cli-parser", "version": "1.0.2", diff --git a/webapp/phpstan.dist.neon b/webapp/phpstan.dist.neon index d90a891c61..da58f7322c 100644 --- a/webapp/phpstan.dist.neon +++ b/webapp/phpstan.dist.neon @@ -4,6 +4,7 @@ parameters: - src - migrations - resources/functions.php + - rector.php - tests scanFiles: - vendor/vrana/adminer/adminer/include/functions.inc.php diff --git a/webapp/rector.php b/webapp/rector.php new file mode 100644 index 0000000000..caefd1f671 --- /dev/null +++ b/webapp/rector.php @@ -0,0 +1,27 @@ +withPaths([ + __DIR__ . '/config', + __DIR__ . '/public', + __DIR__ . '/resources', + __DIR__ . '/src', + __DIR__ . '/tests', + ]) + ->withPhpSets(php82: true) + ->withComposerBased(twig: true, doctrine: true, phpunit: true, symfony: true) + ->withSkip([ + NullToStrictStringFuncCallArgRector::class, + RenameFunctionRector::class, + ConsistentImplodeRector::class, + ClosureToArrowFunctionRector::class, + ]) + ->withTypeCoverageLevel(0) + ->withDeadCodeLevel(0) + ->withCodeQualityLevel(0); diff --git a/webapp/src/Command/AdminerCompileCommand.php b/webapp/src/Command/AdminerCompileCommand.php index 41600da220..c3c57c47e2 100644 --- a/webapp/src/Command/AdminerCompileCommand.php +++ b/webapp/src/Command/AdminerCompileCommand.php @@ -13,16 +13,15 @@ name: 'adminer:compile', description: 'Compile adminer in vendor', )] -class AdminerCompileCommand extends Command +class AdminerCompileCommand { public function __construct( #[Autowire('%domjudge.vendordir%')] - private readonly string $vendorDir, + private readonly string $vendorDir ) { - parent::__construct(); } - protected function execute(InputInterface $input, OutputInterface $output): int + public function __invoke(OutputInterface $output): int { $process = new Process( ['php', 'compile.php', 'mysql'], diff --git a/webapp/src/Command/ResetUserPasswordCommand.php b/webapp/src/Command/ResetUserPasswordCommand.php index 1d7e942aea..123d79803b 100644 --- a/webapp/src/Command/ResetUserPasswordCommand.php +++ b/webapp/src/Command/ResetUserPasswordCommand.php @@ -37,7 +37,7 @@ public function __invoke( $style->error('Can not find user with username ' . $username); return Command::FAILURE; } - $password = $password ?? Utils::generatePassword(); + $password ??= Utils::generatePassword(); $user->setPassword( $this->passwordHasher->hashPassword($user, $password) ); diff --git a/webapp/src/Controller/Jury/ContestController.php b/webapp/src/Controller/Jury/ContestController.php index e4fd8b251e..5518d2666c 100644 --- a/webapp/src/Controller/Jury/ContestController.php +++ b/webapp/src/Controller/Jury/ContestController.php @@ -967,7 +967,7 @@ private function checkTimezones(FormInterface $form): ?Response $fields = explode('+', $tmpValue); } elseif (str_contains($tmpValue, '-')) { $fields = explode('-', $tmpValue); - } elseif (substr($tmpValue, -1) === 'Z') { + } elseif (str_ends_with($tmpValue, 'Z')) { $timeZones[] = 'UTC'; continue; } diff --git a/webapp/src/Controller/Jury/ExecutableController.php b/webapp/src/Controller/Jury/ExecutableController.php index 8e1722c8e7..4b6c769e4a 100644 --- a/webapp/src/Controller/Jury/ExecutableController.php +++ b/webapp/src/Controller/Jury/ExecutableController.php @@ -74,7 +74,7 @@ public function indexAction(Request $request): Response foreach (['compare', 'run', 'full_debug'] as $config_script) { try { $configScripts[] = (string)$this->config->get('default_' . $config_script); - } catch (PHPInvalidArgumentException $e) { + } catch (PHPInvalidArgumentException) { // If not found this is an older database, as we only use this for visual changes ignore this error; } } @@ -129,22 +129,13 @@ public function indexAction(Request $request): Response } $execdata['execid']['cssclass'] = 'execid'; $type = $execdata['type']['value']; - switch ($type) { - case 'compare': - $execdata['icon']['icon'] = 'code-compare'; - break; - case 'compile': - $execdata['icon']['icon'] = 'language'; - break; - case 'debug': - $execdata['icon']['icon'] = 'bug'; - break; - case 'run': - $execdata['icon']['icon'] = 'person-running'; - break; - default: - $execdata['icon']['icon'] = 'question'; - } + $execdata['icon']['icon'] = match ($type) { + 'compare' => 'code-compare', + 'compile' => 'language', + 'debug' => 'bug', + 'run' => 'person-running', + default => 'question', + }; $execdata['badges']['value'] = $badges; if ($this->isGranted('ROLE_ADMIN')) { diff --git a/webapp/src/Controller/Jury/RejudgingController.php b/webapp/src/Controller/Jury/RejudgingController.php index 655495651a..11ac65083c 100644 --- a/webapp/src/Controller/Jury/RejudgingController.php +++ b/webapp/src/Controller/Jury/RejudgingController.php @@ -383,7 +383,7 @@ public function viewAction( // Only load the statistics if desired. The query is quite long and can result in much data, so only have it run // when needed or when we don't have a lot of data to load. - $showStatistics = $showStatistics ?? $onlyAHandfulOfSubmissions; + $showStatistics ??= $onlyAHandfulOfSubmissions; if ($showStatistics && count($repetitions) > 0) { $stats = $this->getStats($rejudging); } else { diff --git a/webapp/src/DataTransferObject/Shadowing/EventType.php b/webapp/src/DataTransferObject/Shadowing/EventType.php index f486f054b5..ea5ed08a02 100644 --- a/webapp/src/DataTransferObject/Shadowing/EventType.php +++ b/webapp/src/DataTransferObject/Shadowing/EventType.php @@ -42,32 +42,20 @@ public static function fromString(string $value): EventType */ public function getEventClass(): ?string { - switch ($this) { - case self::CLARIFICATIONS: - return ClarificationEvent::class; - case self::CONTESTS: - return ContestEvent::class; - case self::GROUPS: - return GroupEvent::class; - case self::JUDGEMENTS: - return JudgementEvent::class; - case self::JUDGEMENT_TYPES: - return JudgementTypeEvent::class; - case self::LANGUAGES: - return LanguageEvent::class; - case self::ORGANIZATIONS: - return OrganizationEvent::class; - case self::PROBLEMS: - return ProblemEvent::class; - case self::RUNS: - return RunEvent::class; - case self::STATE: - return StateEvent::class; - case self::SUBMISSIONS: - return SubmissionEvent::class; - case self::TEAMS: - return TeamEvent::class; - } - return null; + return match ($this) { + self::CLARIFICATIONS => ClarificationEvent::class, + self::CONTESTS => ContestEvent::class, + self::GROUPS => GroupEvent::class, + self::JUDGEMENTS => JudgementEvent::class, + self::JUDGEMENT_TYPES => JudgementTypeEvent::class, + self::LANGUAGES => LanguageEvent::class, + self::ORGANIZATIONS => OrganizationEvent::class, + self::PROBLEMS => ProblemEvent::class, + self::RUNS => RunEvent::class, + self::STATE => StateEvent::class, + self::SUBMISSIONS => SubmissionEvent::class, + self::TEAMS => TeamEvent::class, + default => null, + }; } } diff --git a/webapp/src/Doctrine/ExternalIdAssigner.php b/webapp/src/Doctrine/ExternalIdAssigner.php index c7e7ac3b6e..098fa252eb 100644 --- a/webapp/src/Doctrine/ExternalIdAssigner.php +++ b/webapp/src/Doctrine/ExternalIdAssigner.php @@ -31,7 +31,7 @@ public function __invoke(PostPersistEventArgs $args): void return; } - $entityClass = get_class($entity); + $entityClass = $entity::class; if ($entity instanceof CalculatedExternalIdBasedOnRelatedFieldInterface) { $externalid = $entity->getCalculatedExternalId(); } else { diff --git a/webapp/src/Entity/Contest.php b/webapp/src/Entity/Contest.php index 75dd6c7b25..cad2c18a6b 100644 --- a/webapp/src/Entity/Contest.php +++ b/webapp/src/Entity/Contest.php @@ -83,7 +83,7 @@ class Contest extends BaseApiEntity implements options: ['comment' => 'Time contest becomes visible in team/public views', 'unsigned' => true] )] #[Serializer\Exclude] - private string|float|null $activatetime; + private string|float|null $activatetime = null; #[ORM\Column( type: 'decimal', @@ -118,7 +118,7 @@ class Contest extends BaseApiEntity implements options: ['comment' => 'Time after which no more submissions are accepted', 'unsigned' => true] )] #[Serializer\Exclude] - private string|float|null $endtime; + private string|float|null $endtime = null; #[ORM\Column( type: 'decimal', diff --git a/webapp/src/Entity/Submission.php b/webapp/src/Entity/Submission.php index 0932fff1bd..12ae6873d2 100644 --- a/webapp/src/Entity/Submission.php +++ b/webapp/src/Entity/Submission.php @@ -83,7 +83,7 @@ class Submission extends BaseApiEntity implements options: ['comment' => 'JSON encoded list of expected results - used to validate jury submissions'] )] #[Serializer\Exclude] - private ?array $expected_results; + private ?array $expected_results = null; #[ORM\Column( nullable: true, diff --git a/webapp/src/Form/Type/JuryClarificationType.php b/webapp/src/Form/Type/JuryClarificationType.php index 70b8a69689..9843e63240 100644 --- a/webapp/src/Form/Type/JuryClarificationType.php +++ b/webapp/src/Form/Type/JuryClarificationType.php @@ -115,7 +115,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $builder->add('jurymember', HiddenType::class, [ 'constraints' => [ - new Callback([$this, 'checkJuryMember']) + new Callback($this->checkJuryMember(...)) ] ]); } diff --git a/webapp/src/Service/BalloonService.php b/webapp/src/Service/BalloonService.php index 2b3dad6d13..ae03e83c32 100644 --- a/webapp/src/Service/BalloonService.php +++ b/webapp/src/Service/BalloonService.php @@ -78,7 +78,7 @@ public function updateBalloons( $this->em->persist($balloon); try { $this->em->flush(); - } catch (UniqueConstraintViolationException $e) { + } catch (UniqueConstraintViolationException) { } } } diff --git a/webapp/src/Service/ConfigurationService.php b/webapp/src/Service/ConfigurationService.php index 6499ee29bd..5727019a01 100644 --- a/webapp/src/Service/ConfigurationService.php +++ b/webapp/src/Service/ConfigurationService.php @@ -150,7 +150,7 @@ function (ConfigCacheInterface $cache): void { }); return array_map( - fn(array $item) => ConfigurationSpecification::fromArray($item), + ConfigurationSpecification::fromArray(...), require $cacheFile ); } @@ -177,8 +177,7 @@ public function saveChanges( } unset($spec); - /** @var array $options */ - $options = $options ?? $this->em->createQueryBuilder() + $options ??= $this->em->createQueryBuilder() ->from(Configuration::class, 'c', 'c.name') ->select('c') ->getQuery() diff --git a/webapp/src/Service/DOMJudgeService.php b/webapp/src/Service/DOMJudgeService.php index ea507abfc7..e75f31dbab 100644 --- a/webapp/src/Service/DOMJudgeService.php +++ b/webapp/src/Service/DOMJudgeService.php @@ -1781,8 +1781,8 @@ public function checkNewVersion(): string|false { $cache = new FilesystemAdapter(); try { - $versions = $cache->get('domjudge_versions', [$this, 'cacherCheckNewVersion']); - } catch (InvalidArgumentException $e) { + $versions = $cache->get('domjudge_versions', $this->cacherCheckNewVersion(...)); + } catch (InvalidArgumentException) { return false; } diff --git a/webapp/src/Service/EventLogService.php b/webapp/src/Service/EventLogService.php index 935ef5ade7..31d76b984c 100644 --- a/webapp/src/Service/EventLogService.php +++ b/webapp/src/Service/EventLogService.php @@ -849,10 +849,6 @@ public function endpointForEntity($entity): ?string $entity = substr($entity, strlen('Proxies\\__CG__\\')); } - if (isset($this->entityToEndpoint[$entity])) { - return $this->entityToEndpoint[$entity]; - } - - return null; + return $this->entityToEndpoint[$entity] ?? null; } } diff --git a/webapp/src/Service/ImportExportService.php b/webapp/src/Service/ImportExportService.php index cd4d725f81..0aee63a310 100644 --- a/webapp/src/Service/ImportExportService.php +++ b/webapp/src/Service/ImportExportService.php @@ -741,7 +741,7 @@ public function importJson(string $type, UploadedFile $file, ?string &$message = $content = file_get_contents($file->getRealPath()); try { $data = Utils::jsonDecode($content); - } catch (JsonException $e) { + } catch (JsonException) { // Check if we can parse it as YAML try { $data = Yaml::parse($content, Yaml::PARSE_DATETIME); diff --git a/webapp/src/Service/ImportProblemService.php b/webapp/src/Service/ImportProblemService.php index 2f91d270b8..b778fdabc1 100644 --- a/webapp/src/Service/ImportProblemService.php +++ b/webapp/src/Service/ImportProblemService.php @@ -269,7 +269,7 @@ public function importZippedProblem( } $validationMode = 'default'; - if (!$this->parseYaml($problemYaml, $messages, $validationMode, $propertyAccessor, $problem)) { + if (!static::parseYaml($problemYaml, $messages, $validationMode, $propertyAccessor, $problem)) { return null; } if (!$this->searchAndAddValidator($zip, $zipEntries, $messages, $externalId, $validationMode, $problem)) { diff --git a/webapp/src/Twig/TwigExtension.php b/webapp/src/Twig/TwigExtension.php index 90f3da039b..23a33bc800 100644 --- a/webapp/src/Twig/TwigExtension.php +++ b/webapp/src/Twig/TwigExtension.php @@ -640,7 +640,7 @@ public function printHosts(array $hostnames): string $prefix_len = strlen($common_prefix); // Extract the longest common suffix. - $reversed = array_map('strrev', $local_parts); + $reversed = array_map(strrev(...), $local_parts); $common_suffix = strrev($this->getCommonPrefix($reversed)); $suffix_len = strlen($common_suffix); @@ -648,7 +648,7 @@ public function printHosts(array $hostnames): string // $common_suffix, then $common_prefix = $common_suffix = the entire string. $middle_parts = array_map(fn($host) => substr($host, $prefix_len, strlen($host) - $prefix_len - $suffix_len), $local_parts); // Usually the middle parts contain numbers, so use natural sort for them. - usort($middle_parts, 'strnatcmp'); + usort($middle_parts, strnatcmp(...)); if (empty($common_prefix) && empty($common_suffix)) { // No common prefix nor suffix: list all the names without "{}". @@ -1020,7 +1020,7 @@ public function hexColorToRGBA(string $text, float $opacity = 1): string $opacity = hexdec(array_pop($m)); // no-break case 3: - $vals = array_map("hexdec", $m); + $vals = array_map(hexdec(...), $m); $vals[] = $opacity; return "rgba(" . implode(",", $vals) . ")"; diff --git a/webapp/src/Twig/TwigGlobalsExtension.php b/webapp/src/Twig/TwigGlobalsExtension.php index 5b7bac54c7..e0599a20be 100644 --- a/webapp/src/Twig/TwigGlobalsExtension.php +++ b/webapp/src/Twig/TwigGlobalsExtension.php @@ -69,7 +69,7 @@ public function getGlobals(): array 'alpha3_countries' => Countries::getAlpha3Names(), 'alpha3_alpha2_country_mapping' => array_combine( Countries::getAlpha3Codes(), - array_map(fn($alpha3) => Countries::getAlpha2Code($alpha3), Countries::getAlpha3Codes()) + array_map(Countries::getAlpha2Code(...), Countries::getAlpha3Codes()) ), 'show_shadow_differences' => $this->tokenStorage->getToken() && $this->authorizationChecker->isGranted('ROLE_ADMIN') && diff --git a/webapp/src/Utils/Utils.php b/webapp/src/Utils/Utils.php index 6a184de7b8..7b30f0f445 100644 --- a/webapp/src/Utils/Utils.php +++ b/webapp/src/Utils/Utils.php @@ -389,9 +389,9 @@ public static function relativeLuminance(string $rgb): float [$r, $g, $b] = static::parseHexColor($rgb); [$lr, $lg, $lb] = [ - pow($r / 255, 2.4), - pow($g / 255, 2.4), - pow($b / 255, 2.4), + ($r / 255) ** 2.4, + ($g / 255) ** 2.4, + ($b / 255) ** 2.4, ]; return 0.2126 * $lr + 0.7152 * $lg + 0.0722 * $lb; @@ -404,8 +404,8 @@ public static function apcaContrast(string $fgColor, string $bgColor): float $luminanceBackground = static::relativeLuminance($bgColor); $contrast = ($luminanceBackground > $luminanceForeground) - ? (pow($luminanceBackground, 0.56) - pow($luminanceForeground, 0.57)) * 1.14 - : (pow($luminanceBackground, 0.65) - pow($luminanceForeground, 0.62)) * 1.14; + ? ($luminanceBackground ** 0.56 - $luminanceForeground ** 0.57) * 1.14 + : ($luminanceBackground ** 0.65 - $luminanceForeground ** 0.62) * 1.14; return round($contrast * 100, 2); } @@ -959,7 +959,7 @@ public static function toTsvField(string $field) : string */ public static function parseTsvLine(string $line): array { - return array_map('stripcslashes', explode("\t", rtrim($line, "\r\n"))); + return array_map(stripcslashes(...), explode("\t", rtrim($line, "\r\n"))); } /** diff --git a/webapp/tests/Unit/Controller/API/AccountBaseTestCase.php b/webapp/tests/Unit/Controller/API/AccountBaseTestCase.php index 3070077e15..647fbcd957 100644 --- a/webapp/tests/Unit/Controller/API/AccountBaseTestCase.php +++ b/webapp/tests/Unit/Controller/API/AccountBaseTestCase.php @@ -259,7 +259,7 @@ public function testCreateUserFileImportMissingField(string $newUsersFile, strin public function provideNewAccountFileMissingField(): Generator { - foreach ($this->provideNewAccount() as $index => $testUser) { + foreach ($this->provideNewAccount() as $testUser) { if (isset($testUser[0]['skipImportFile'])) { // Not all properties which we can set via the API account endpoint can also // be imported via the API file import. diff --git a/webapp/tests/Unit/Controller/API/ConfigControllerTest.php b/webapp/tests/Unit/Controller/API/ConfigControllerTest.php index d596ab58e2..9b910172a9 100644 --- a/webapp/tests/Unit/Controller/API/ConfigControllerTest.php +++ b/webapp/tests/Unit/Controller/API/ConfigControllerTest.php @@ -71,7 +71,7 @@ public function testConfigChangeVisible(): void static::assertEquals(false, $response['compile_penalty']); static::assertEquals(20, $response['penalty_time']); - $this->withChangedConfiguration('penalty_time', 100, function () { + $this->withChangedConfiguration('penalty_time', 100, function (): void { $response = $this->verifyApiJsonResponse('GET', $this->endpoint, 200); static::assertIsArray($response); diff --git a/webapp/tests/Unit/Controller/API/GeneralInfoControllerTest.php b/webapp/tests/Unit/Controller/API/GeneralInfoControllerTest.php index 42a64aead5..084a7c9842 100644 --- a/webapp/tests/Unit/Controller/API/GeneralInfoControllerTest.php +++ b/webapp/tests/Unit/Controller/API/GeneralInfoControllerTest.php @@ -129,7 +129,7 @@ public function provideUsers(): Generator */ public function testCountryFlagExists(string $countryCode, string $size): void { - $this->withChangedConfiguration('show_flags', true, function () use ($countryCode, $size) { + $this->withChangedConfiguration('show_flags', true, function () use ($countryCode, $size): void { $this->client->request('GET', "/api/country-flags/$countryCode/$size"); /** @var BinaryFileResponse $response */ $response = $this->client->getResponse(); @@ -161,7 +161,7 @@ public function provideCountryFlagExists(): Generator */ public function testCountryFlagNotFound(string $countryCode, string $size): void { - $this->withChangedConfiguration('show_flags', true, function () use ($countryCode, $size) { + $this->withChangedConfiguration('show_flags', true, function () use ($countryCode, $size): void { $this->client->request('GET', "/api/country-flags/$countryCode/$size"); /** @var BinaryFileResponse $response */ $response = $this->client->getResponse(); @@ -183,7 +183,7 @@ public function provideCountryFlagSizeNotFound(): Generator */ public function testCountryNotFound(string $countryCode, string $size): void { - $this->withChangedConfiguration('show_flags', true, function () use ($countryCode, $size) { + $this->withChangedConfiguration('show_flags', true, function () use ($countryCode, $size): void { $this->client->request('GET', "/api/country-flags/$countryCode/$size"); /** @var BinaryFileResponse $response */ $response = $this->client->getResponse(); @@ -207,7 +207,7 @@ public function provideCountryFlagNotFound(): Generator */ public function testCountryFlagDisabled(string $countryCode, string $size): void { - $this->withChangedConfiguration('show_flags', false, function () use ($countryCode, $size) { + $this->withChangedConfiguration('show_flags', false, function () use ($countryCode, $size): void { $this->client->request('GET', "/api/country-flags/$countryCode/$size"); /** @var BinaryFileResponse $response */ $response = $this->client->getResponse(); diff --git a/webapp/tests/Unit/Controller/API/GroupControllerTest.php b/webapp/tests/Unit/Controller/API/GroupControllerTest.php index 63f75d6274..ddd357cc4b 100644 --- a/webapp/tests/Unit/Controller/API/GroupControllerTest.php +++ b/webapp/tests/Unit/Controller/API/GroupControllerTest.php @@ -68,7 +68,7 @@ public function testNewAddedGroup(array $newGroupPostData): void } $objectsAfterTest = $this->verifyApiJsonResponse('GET', $url, 200, $this->apiUser); - $newItems = array_map('unserialize', array_diff(array_map('serialize', $objectsAfterTest), array_map('serialize', $objectsBeforeTest))); + $newItems = array_map(unserialize(...), array_diff(array_map(serialize(...), $objectsAfterTest), array_map(serialize(...), $objectsBeforeTest))); self::assertEquals(1, count($newItems)); $listKey = array_keys($newItems)[0]; foreach ($newGroupPostData as $key => $value) { @@ -102,7 +102,7 @@ public function testNewAddedGroupPut(array $newGroupPostData): void } $objectsAfterTest = $this->verifyApiJsonResponse('GET', $url, 200, $this->apiUser); - $newItems = array_map('unserialize', array_diff(array_map('serialize', $objectsAfterTest), array_map('serialize', $objectsBeforeTest))); + $newItems = array_map(unserialize(...), array_diff(array_map(serialize(...), $objectsAfterTest), array_map(serialize(...), $objectsBeforeTest))); self::assertEquals(1, count($newItems)); $listKey = array_keys($newItems)[0]; foreach ($newGroupPostData as $key => $value) { diff --git a/webapp/tests/Unit/Controller/API/JudgementTypesControllerTest.php b/webapp/tests/Unit/Controller/API/JudgementTypesControllerTest.php index 2313560f36..8842044af1 100644 --- a/webapp/tests/Unit/Controller/API/JudgementTypesControllerTest.php +++ b/webapp/tests/Unit/Controller/API/JudgementTypesControllerTest.php @@ -31,7 +31,7 @@ class JudgementTypesControllerTest extends BaseTestCase public function testJudgementTypeChangedPenalty(): void { - $this->withChangedConfiguration('compile_penalty', true, function () { + $this->withChangedConfiguration('compile_penalty', true, function (): void { $contestId = $this->getDemoContestId(); $endpointId = $this->apiEndpoint; diff --git a/webapp/tests/Unit/Controller/API/OrganizationControllerTest.php b/webapp/tests/Unit/Controller/API/OrganizationControllerTest.php index fda292a563..ca41933578 100644 --- a/webapp/tests/Unit/Controller/API/OrganizationControllerTest.php +++ b/webapp/tests/Unit/Controller/API/OrganizationControllerTest.php @@ -109,7 +109,7 @@ public function testSingle(int|string $id, array $expectedProperties): void */ public function testCountryAbsentWhenDisabled(): void { - $this->withChangedConfiguration('show_flags', false, function () { + $this->withChangedConfiguration('show_flags', false, function (): void { $apiEndpoint = $this->apiEndpoint; $contestId = $this->getDemoContestId(); // The hardcoded 1 here is the team affiliation from the TeamAffiliationFixture example data fixture. @@ -233,7 +233,7 @@ public function testNewAddedOrganization(): void $this->verifyApiJsonResponse('POST', $url, 201, 'admin', $newOrganizationPostData); $objectsAfterTest = $this->verifyApiJsonResponse('GET', $myURL, 200, $this->apiUser); - $newItems = array_map('unserialize', array_diff(array_map('serialize', $objectsAfterTest), array_map('serialize', $objectsBeforeTest))); + $newItems = array_map(unserialize(...), array_diff(array_map(serialize(...), $objectsAfterTest), array_map(serialize(...), $objectsBeforeTest))); self::assertEquals(1, count($newItems)); $listKey = array_keys($newItems)[0]; foreach ($newOrganizationPostData as $key => $value) { diff --git a/webapp/tests/Unit/Controller/Jury/ConfigControllerTest.php b/webapp/tests/Unit/Controller/Jury/ConfigControllerTest.php index 77475b802a..02d32fac78 100644 --- a/webapp/tests/Unit/Controller/Jury/ConfigControllerTest.php +++ b/webapp/tests/Unit/Controller/Jury/ConfigControllerTest.php @@ -45,7 +45,7 @@ public function testConfigSettingsPresent(): void public function testChangedPenaltyTime(): void { $this->withChangedConfiguration('penalty_time', "30", - function ($errors) { + function ($errors): void { static::assertEmpty($errors); $this->verifyPageResponse('GET', '/jury/config', 200); $crawler = $this->getCurrentCrawler(); @@ -60,7 +60,7 @@ function ($errors) { public function testChangedLongConfigName(): void { $this->withChangedConfiguration('config_external_contest_sources_allow_untrusted_certificates', 'on', - function ($errors) { + function ($errors): void { static::assertEmpty($errors); $this->verifyPageResponse('GET', '/jury/config', 200); }); @@ -72,7 +72,7 @@ function ($errors) { public function testChangedPenaltyTimeInvalid(): void { $this->withChangedConfiguration('penalty_time', "-1", - function ($errors) { + function ($errors): void { static::assertEquals(['penalty_time' => 'A non-negative number is required.'], $errors); $this->verifyPageResponse('GET', '/jury/config', 200); $crawler = $this->getCurrentCrawler(); diff --git a/webapp/tests/Unit/Controller/Jury/PrintControllerTest.php b/webapp/tests/Unit/Controller/Jury/PrintControllerTest.php index 18778aa90c..6a80482c47 100644 --- a/webapp/tests/Unit/Controller/Jury/PrintControllerTest.php +++ b/webapp/tests/Unit/Controller/Jury/PrintControllerTest.php @@ -35,7 +35,7 @@ public function testPrintingDisabledAccessDenied(): void public function testPrintingEnabledJuryIndexPage(): void { $this->withChangedConfiguration('print_command', static::PRINT_COMMAND, - function () { + function (): void { $this->verifyPageResponse('GET', '/jury', 200); static::assertSelectorExists('a:contains("Print")'); }); @@ -47,7 +47,7 @@ function () { public function testPrintingEnabledSubmitForm(): void { $this->withChangedConfiguration('print_command', static::PRINT_COMMAND, - function () { + function (): void { $this->verifyPageResponse('GET', '/jury/print', 200); $testFile = __DIR__ . '/PrintControllerTest.php'; diff --git a/webapp/tests/Unit/Controller/Jury/ProblemControllerTest.php b/webapp/tests/Unit/Controller/Jury/ProblemControllerTest.php index 410dc4f859..f737c7ee49 100644 --- a/webapp/tests/Unit/Controller/Jury/ProblemControllerTest.php +++ b/webapp/tests/Unit/Controller/Jury/ProblemControllerTest.php @@ -139,7 +139,7 @@ public function testMultiDeleteProblems(): void $problemIds = []; $createdProblems = []; - foreach ($problemsData as $index => $data) { + foreach ($problemsData as $data) { $problem = new Problem(); $problem->setName($data['name']); $problem->setExternalid($data['externalid']); diff --git a/webapp/tests/Unit/Controller/Team/MiscControllerTest.php b/webapp/tests/Unit/Controller/Team/MiscControllerTest.php index e76b3c6204..b5e074e7c1 100644 --- a/webapp/tests/Unit/Controller/Team/MiscControllerTest.php +++ b/webapp/tests/Unit/Controller/Team/MiscControllerTest.php @@ -83,7 +83,7 @@ public function testPrintingDisabledAccessDenied(): void public function testPrintingEnabledTeamMenu(): void { $this->withChangedConfiguration('print_command', self::PRINT_COMMAND, - function () { + function (): void { $this->verifyPageResponse('GET', '/team', 200); static::assertSelectorExists('a:contains("Print")'); }); @@ -95,7 +95,7 @@ function () { public function testPrintingEnabledSubmitForm(): void { $this->withChangedConfiguration('print_command', self::PRINT_COMMAND, - function () { + function (): void { $this->client->request('GET', '/team/print'); $testFile = __DIR__ . '/MiscControllerTest.php'; diff --git a/webapp/tests/Unit/Controller/Team/ProblemControllerTest.php b/webapp/tests/Unit/Controller/Team/ProblemControllerTest.php index 941169fdbe..5f59196598 100644 --- a/webapp/tests/Unit/Controller/Team/ProblemControllerTest.php +++ b/webapp/tests/Unit/Controller/Team/ProblemControllerTest.php @@ -56,7 +56,7 @@ function () use ( $descriptions, $withLimits, $letters - ) { + ): void { $crawler = $this->client->request('GET', '/team/problems'); // Check that the correct menu item is selected. diff --git a/webapp/tests/Unit/Service/ConfigurationServiceTest.php b/webapp/tests/Unit/Service/ConfigurationServiceTest.php index 7b82e6d220..c24239ebca 100644 --- a/webapp/tests/Unit/Service/ConfigurationServiceTest.php +++ b/webapp/tests/Unit/Service/ConfigurationServiceTest.php @@ -232,12 +232,18 @@ public function testUnknownConfigsNonPublic(): void $this->configRepository->expects(self::once()) ->method('findAll') ->willReturn($unknownItems); - $this->logger->expects(self::exactly(2)) - ->method('warning') - ->withConsecutive( - ['Configuration value %s not defined', ['unknown1']], - ['Configuration value %s not defined', ['unknown2']] - ); + $matcher = self::exactly(2); + $this->logger->expects($matcher) + ->method('warning')->willReturnCallback(function (...$parameters) use ($matcher): void { + if ($matcher->getInvocationCount() === 1) { + $this->assertSame('Configuration value %s not defined', $parameters[0]); + $this->assertSame(['unknown1'], $parameters[1]); + } + if ($matcher->getInvocationCount() === 2) { + $this->assertSame('Configuration value %s not defined', $parameters[0]); + $this->assertSame(['unknown2'], $parameters[1]); + } + }); $all = $this->config->all(); self::assertArrayNotHasKey('unknown1', $all); diff --git a/webapp/tests/Unit/Utils/UtilsTest.php b/webapp/tests/Unit/Utils/UtilsTest.php index 09bea4acd0..33d5bc411f 100644 --- a/webapp/tests/Unit/Utils/UtilsTest.php +++ b/webapp/tests/Unit/Utils/UtilsTest.php @@ -949,8 +949,8 @@ public function testGeneratePasswordMoreEntropy(): void } self::assertEquals(1, max(array_count_values($passes))); - self::assertEquals(32, min(array_map('strlen', $passes))); - self::assertEquals(32, max(array_map('strlen', $passes))); + self::assertEquals(32, min(array_map(strlen(...), $passes))); + self::assertEquals(32, max(array_map(strlen(...), $passes))); self::assertTrue($onlyCorrectChars); } @@ -971,8 +971,8 @@ public function testGeneratePasswordWithLessEntropy(): void } self::assertEquals(1, max(array_count_values($passes))); - self::assertEquals(12, min(array_map('strlen', $passes))); - self::assertEquals(12, max(array_map('strlen', $passes))); + self::assertEquals(12, min(array_map(strlen(...), $passes))); + self::assertEquals(12, max(array_map(strlen(...), $passes))); self::assertTrue($onlyalnum); self::assertFalse($containsforbidden); }