isFile() && $file->getExtension() === 'php') { $paths[] = $relativeDirectory . '/' . $iterator->getSubPathName(); } } } $paths = array_values(array_unique($paths)); sort($paths); return array_map(static fn (string $path): array => [$path], $paths); } public function testTickSchemaDoesNotUseDatabaseDefaultsForGameSchedules(): void { $schema = file_get_contents(__DIR__ . '/../hwe/sql/schema.sql'); self::assertIsString($schema); foreach ([ '`turntime` BIGINT', '`recent_war` BIGINT', '`last_refresh` BIGINT', '`time` BIGINT', '`valid_until` BIGINT', '`reserved_until` BIGINT', '`open_tick` BIGINT', '`close_tick` BIGINT', ] as $expected) { self::assertStringContainsString($expected, $schema); } self::assertDoesNotMatchRegularExpression('/\b(?:CURRENT_TIMESTAMP|NOW\s*\()/i', $schema); } public function testMonthlyTrafficTimestampUsesLogicalClock(): void { $source = file_get_contents(__DIR__ . '/../hwe/func.php'); self::assertIsString($source); self::assertMatchesRegularExpression( '/function updateTraffic\(\).*?GameClock::fromStorage\(\$gameStor\)->formatNow\(\).*?function CheckOverhead\(/s', $source, ); self::assertDoesNotMatchRegularExpression( '/function updateTraffic\(\).*?TimeUtil::now\(.*?function CheckOverhead\(/s', $source, ); } public function testGameLoginDeathCheckUsesTicksWhileSessionTtlRemainsOperational(): void { $source = file_get_contents(__DIR__ . '/../src/sammo/Session.php'); self::assertIsString($source); self::assertMatchesRegularExpression( '/function loginGame\(.*?GameClock::isInitialized\(\$gameStor\).*?GameClock::fromStorage\(\$gameStor\)->nowTick\(\).*?GameClock::TICKS_PER_TURN.*?function logoutGame\(/s', $source, ); self::assertMatchesRegularExpression( '/function loginGame\(.*?new \\\\DateTimeImmutable.*?getTimestamp\(\).*?function logoutGame\(/s', $source, ); self::assertDoesNotMatchRegularExpression( '/function loginGame\(.*?new\s+\\?DateTime(?:Immutable)?\([^)]*turntime.*?function logoutGame\(/s', $source, ); } public function testBrowserDoesNotCompareProjectedGameDatesToItsWallClock(): void { $expectations = [ 'hwe/ts/PageVote.vue' => ['currentVote.value.isOpen'], 'hwe/ts/components/MessagePlate.vue' => ['msg.clockMode === "manual"'], 'hwe/ts/gateway/entrance.ts' => ['resolveGatewayOpenState(game.isOpen, game.opentime, now)'], 'hwe/ts/select_npc.ts' => ['logicalClockRunning'], 'hwe/ts/select_general_from_pool.ts' => ['logicalClockRunning'], ]; foreach ($expectations as $path => $needles) { $source = file_get_contents(__DIR__ . '/../' . $path); self::assertIsString($source); foreach ($needles as $needle) { self::assertStringContainsString($needle, $source, $path); } } self::assertStringNotContainsString('formatTime(new Date())', file_get_contents(__DIR__ . '/../hwe/ts/PageVote.vue')); } public function testGatewayFormatsLogicalOpenTimeBeforeReturningIt(): void { $source = file_get_contents(__DIR__ . '/../hwe/j_server_basic_info.php'); self::assertIsString($source); self::assertStringContainsString( '$admin[\'opentime\'] = $clock->formatTick(Util::toInt($admin[\'opentime\']));', $source, ); } }