Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TASK] Remove dependencies to Core testing classes #3378

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions Tests/Integration/Fixtures/Frontend/PhpError.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

declare(strict_types=1);

/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/

namespace ApacheSolrForTypo3\Solr\Tests\Integration;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Error\PageErrorHandler\PageErrorHandlerInterface;
use TYPO3\CMS\Core\Http\JsonResponse;

/**
* Copied from TYPO3 core as testing classes are excluded from Composer
* @see https://github.com/TYPO3-CMS/core/blob/v11.5.17/Tests/Functional/Fixtures/Frontend/PhpError.php
*/
class PhpError implements PageErrorHandlerInterface
{
/**
* @var int
*/
private $statusCode;

/**
* @var array
*/
private $configuration;

/**
* @param int $statusCode
* @param array $configuration
*/
public function __construct(int $statusCode, array $configuration)
{
$this->statusCode = $statusCode;
$this->configuration = $configuration;
}

/**
* @param ServerRequestInterface $request
* @param string $message
* @param array $reasons
* @return ResponseInterface
*/
public function handlePageError(
ServerRequestInterface $request,
string $message,
array $reasons = []
): ResponseInterface {
$data = [
'uri' => (string)$request->getUri(),
'message' => $message,
'reasons' => $reasons,
];
return new JsonResponse($data, $this->statusCode);
}
}
1 change: 0 additions & 1 deletion Tests/Integration/IntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
use TYPO3\CMS\Core\Http\ServerRequest;
use TYPO3\CMS\Core\Information\Typo3Version;
use TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait;
use TYPO3\CMS\Core\TimeTracker\TimeTracker;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
Expand Down
307 changes: 307 additions & 0 deletions Tests/Integration/SiteBasedTestTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,307 @@
<?php

declare(strict_types=1);

/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/

namespace ApacheSolrForTypo3\Solr\Tests\Integration;

use TYPO3\CMS\Core\Configuration\SiteConfiguration;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Internal\AbstractInstruction;
use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Internal\ArrayValueInstruction;
use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Internal\TypoScriptInstruction;
use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest;

/**
* Copied from TYPO3 core as testing classes are excluded from Composer
* @see https://github.com/TYPO3-CMS/core/blob/main/Tests/Functional/SiteHandling/SiteBasedTestTrait.php
*/
trait SiteBasedTestTrait
{
/**
* @param array $items
*/
protected static function failIfArrayIsNotEmpty(array $items): void
{
if (empty($items)) {
return;
}

static::fail(
'Array was not empty as expected, but contained these items:' . LF
. '* ' . implode(LF . '* ', $items)
);
}

/**
* @param string $identifier
* @param array $site
* @param array $languages
* @param array $errorHandling
*/
protected function writeSiteConfiguration(
string $identifier,
array $site = [],
array $languages = [],
array $errorHandling = []
): void {
$configuration = $site;
if (!empty($languages)) {
$configuration['languages'] = $languages;
}
if (!empty($errorHandling)) {
$configuration['errorHandling'] = $errorHandling;
}
$siteConfiguration = new SiteConfiguration(
$this->instancePath . '/typo3conf/sites/',
$this->get('cache.core')
);

try {
// ensure no previous site configuration influences the test
GeneralUtility::rmdir($this->instancePath . '/typo3conf/sites/' . $identifier, true);
$siteConfiguration->write($identifier, $configuration);
} catch (\Exception $exception) {
$this->markTestSkipped($exception->getMessage());
}
}

/**
* @param string $identifier
* @param array $overrides
*/
protected function mergeSiteConfiguration(
string $identifier,
array $overrides
): void {
$siteConfiguration = new SiteConfiguration(
$this->instancePath . '/typo3conf/sites/',
$this->get('cache.core')
);
$configuration = $siteConfiguration->load($identifier);
$configuration = array_merge($configuration, $overrides);
try {
$siteConfiguration->write($identifier, $configuration);
} catch (\Exception $exception) {
$this->markTestSkipped($exception->getMessage());
}
}

/**
* @param int $rootPageId
* @param string $base
* @return array
*/
protected function buildSiteConfiguration(
int $rootPageId,
string $base = ''
): array {
return [
'rootPageId' => $rootPageId,
'base' => $base,
];
}

/**
* @param string $identifier
* @param string $base
* @return array
*/
protected function buildDefaultLanguageConfiguration(
string $identifier,
string $base
): array {
$configuration = $this->buildLanguageConfiguration($identifier, $base);
$configuration['typo3Language'] = 'default';
$configuration['flag'] = 'global';
unset($configuration['fallbackType'], $configuration['fallbacks']);
return $configuration;
}

/**
* @param string $identifier
* @param string $base
* @param array $fallbackIdentifiers
* @param string $fallbackType
* @return array
*/
protected function buildLanguageConfiguration(
string $identifier,
string $base,
array $fallbackIdentifiers = [],
string $fallbackType = null
): array {
$preset = $this->resolveLanguagePreset($identifier);

$configuration = [
'languageId' => $preset['id'],
'title' => $preset['title'],
'navigationTitle' => $preset['title'],
'base' => $base,
'locale' => $preset['locale'],
'iso-639-1' => $preset['iso'] ?? '',
'hreflang' => $preset['hrefLang'] ?? '',
'direction' => $preset['direction'] ?? '',
'typo3Language' => $preset['iso'] ?? '',
'flag' => $preset['iso'] ?? '',
'fallbackType' => $fallbackType ?? (empty($fallbackIdentifiers) ? 'strict' : 'fallback'),
];

if (!empty($fallbackIdentifiers)) {
$fallbackIds = array_map(
function (string $fallbackIdentifier) {
$preset = $this->resolveLanguagePreset($fallbackIdentifier);
return $preset['id'];
},
$fallbackIdentifiers
);
$configuration['fallbackType'] = $fallbackType ?? 'fallback';
$configuration['fallbacks'] = implode(',', $fallbackIds);
}

return $configuration;
}

/**
* @param string $handler
* @param array $codes
* @return array
*/
protected function buildErrorHandlingConfiguration(
string $handler,
array $codes
): array {
if ($handler === 'Page') {
// This implies you cannot test both 404 and 403 in the same test.
// Fixing that requires much deeper changes to the testing harness,
// as the structure here is only a portion of the config array structure.
if (in_array(404, $codes, true)) {
$baseConfiguration = [
'errorContentSource' => 't3://page?uid=404',
];
} elseif (in_array(403, $codes, true)) {
$baseConfiguration = [
'errorContentSource' => 't3://page?uid=403',
];
}
} elseif ($handler === 'Fluid') {
$baseConfiguration = [
'errorFluidTemplate' => 'typo3/sysext/core/Tests/Functional/Fixtures/Frontend/FluidError.html',
'errorFluidTemplatesRootPath' => '',
'errorFluidLayoutsRootPath' => '',
'errorFluidPartialsRootPath' => '',
];
} elseif ($handler === 'PHP') {
$baseConfiguration = [
'errorPhpClassFQCN' => PhpError::class,
];
} else {
throw new \LogicException(
sprintf('Invalid handler "%s"', $handler),
1533894782
);
}

$baseConfiguration['errorHandler'] = $handler;

return array_map(
static function (int $code) use ($baseConfiguration) {
$baseConfiguration['errorCode'] = $code;
return $baseConfiguration;
},
$codes
);
}

/**
* @param string $identifier
* @return mixed
*/
protected function resolveLanguagePreset(string $identifier)
{
if (!isset(static::LANGUAGE_PRESETS[$identifier])) {
throw new \LogicException(
sprintf('Undefined preset identifier "%s"', $identifier),
1533893665
);
}
return static::LANGUAGE_PRESETS[$identifier];
}

/**
* @param InternalRequest $request
* @param AbstractInstruction ...$instructions
* @return InternalRequest
*
* @todo Instruction handling should be part of Testing Framework (multiple instructions per identifier, merge in interface)
*/
protected function applyInstructions(InternalRequest $request, AbstractInstruction ...$instructions): InternalRequest
{
$modifiedInstructions = [];

foreach ($instructions as $instruction) {
$identifier = $instruction->getIdentifier();
if (isset($modifiedInstructions[$identifier]) || $request->getInstruction($identifier) !== null) {
$modifiedInstructions[$identifier] = $this->mergeInstruction(
$modifiedInstructions[$identifier] ?? $request->getInstruction($identifier),
$instruction
);
} else {
$modifiedInstructions[$identifier] = $instruction;
}
}

return $request->withInstructions($modifiedInstructions);
}

/**
* @param AbstractInstruction $current
* @param AbstractInstruction $other
* @return AbstractInstruction
*/
protected function mergeInstruction(AbstractInstruction $current, AbstractInstruction $other): AbstractInstruction
{
if (get_class($current) !== get_class($other)) {
throw new \LogicException('Cannot merge different instruction types', 1565863174);
}

if ($current instanceof TypoScriptInstruction) {
/** @var TypoScriptInstruction $other */
$typoScript = array_replace_recursive(
$current->getTypoScript() ?? [],
$other->getTypoScript() ?? []
);
$constants = array_replace_recursive(
$current->getConstants() ?? [],
$other->getConstants() ?? []
);
if ($typoScript !== []) {
$current = $current->withTypoScript($typoScript);
}
if ($constants !== []) {
$current = $current->withConstants($constants);
}
return $current;
}

if ($current instanceof ArrayValueInstruction) {
/** @var ArrayValueInstruction $other */
$array = array_merge_recursive($current->getArray(), $other->getArray());
return $current->withArray($array);
}

return $current;
}
}