config = $this->createMock(IConfig::class); $this->appConfig = $this->createMock(IAppConfig::class); $this->appManager = $this->createMock(IAppManager::class); $this->initialState = $this->createMock(InitialStateService::class); $this->navigationManager = $this->createMock(INavigationManager::class); $this->templateManager = $this->createMock(ITemplateManager::class); $this->serverVersion = $this->createMock(ServerVersion::class); $this->request = $this->createMock(IRequest::class); } #[\PHPUnit\Framework\Attributes\DataProvider('dataVersionHash')] public function testVersionHash( string $path, string $file, bool $installed, bool $debug, string $expected, ): void { $this->appManager->expects(self::any()) ->method('getAppVersion') ->willReturnCallback(fn ($appId) => match ($appId) { 'shipped' => 'shipped_1', 'other' => 'other_2', default => "$appId", }); $this->appManager->expects(self::any()) ->method('isShipped') ->willReturnCallback(fn (string $app) => $app === 'shipped'); $this->config->expects(self::atLeastOnce()) ->method('getSystemValueBool') ->willReturnMap([ ['installed', $installed], ['debug', $debug], ]); $this->config->expects(self::any()) ->method('getAppValue') ->with('theming', 'cachebuster', '0') ->willReturn('42'); $this->request->method('getPathInfo') ->willReturn('/' . $path); $this->templateLayout = new TemplateLayout( $this->config, $this->appConfig, $this->appManager, $this->initialState, $this->navigationManager, $this->templateManager, $this->serverVersion, $this->request, ); $layout = $this->templateLayout->getPageTemplate(TemplateResponse::RENDER_AS_ERROR, ''); self::invokePrivate($this->templateLayout, 'versionHash', ['version_hash']); $hash = self::invokePrivate($this->templateLayout, 'getVersionHashSuffix', [$path, $file]); self::assertEquals($expected, $hash); } public static function dataVersionHash() { return [ 'no hash if in debug mode' => ['apps/shipped', 'style.css', true, true, ''], 'only version hash if not installed' => ['apps/shipped', 'style.css', false, false, '?v=version_hash'], 'version hash with cache buster if neither path nor file provided' => ['', '', true, false, '?v=version_hash-42'], 'app version hash if external app' => ['apps/other', 'app.css', true, false, '?v=' . substr(md5('other_2'), 0, 8) . '-42'], 'app version and version hash if shipped app' => ['apps/shipped', 'style.css', true, false, '?v=' . substr(md5('shipped_1-version_hash'), 0, 8) . '-42'], 'prefer path over file' => ['apps/shipped', 'other/app.css', true, false, '?v=' . substr(md5('shipped_1-version_hash'), 0, 8) . '-42'], ]; } }