Skip to content

Commit

Permalink
test: Allow to specify the running PHP version (#1039)
Browse files Browse the repository at this point in the history
This is not 100% correct as it won't change the actual runtime but it will adapt the PHP Parser version used.
  • Loading branch information
theofidry authored Jun 10, 2024
1 parent 49af316 commit f21ea1b
Show file tree
Hide file tree
Showing 12 changed files with 209 additions and 16 deletions.
2 changes: 2 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,5 @@ parameters:
path: 'src/Symbol/SymbolsRegistry.php'
- message: '#Stmt\:\:\$stmts#'
path: 'src/PhpParser/NodeVisitor/ClassAliasStmtAppender.php'
- message: '#PhpVersion::fromComponents#'
path: 'tests/SpecFramework/SpecScenario.php'
28 changes: 21 additions & 7 deletions src/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@
use PhpParser\PhpVersion;
use PhpParser\PrettyPrinter\Standard;
use Symfony\Component\Filesystem\Filesystem;
use Webmozart\Assert\Assert;

final class Container
{
private Filesystem $filesystem;
private ConfigurationFactory $configFactory;
private Parser $parser;
private ?PhpVersion $phpVersion = null;
private Reflector $reflector;
private ScoperFactory $scoperFactory;
private EnrichedReflectorFactory $enrichedReflectorFactory;
Expand Down Expand Up @@ -64,11 +66,11 @@ public function getConfigurationFactory(): ConfigurationFactory
return $this->configFactory;
}

public function getScoperFactory(): ScoperFactory
public function getScoperFactory(?PhpVersion $phpVersion = null): ScoperFactory
{
if (!isset($this->scoperFactory)) {
$this->scoperFactory = new ScoperFactory(
$this->getParser(),
$this->getParser($phpVersion),
$this->getEnrichedReflectorFactory(),
$this->getPrinter(),
);
Expand All @@ -77,21 +79,33 @@ public function getScoperFactory(): ScoperFactory
return $this->scoperFactory;
}

public function getParser(): Parser
public function getParser(?PhpVersion $phpVersion = null): Parser
{
if (!isset($this->parser)) {
$this->parser = $this->createParser();
$this->phpVersion = $phpVersion;
$this->parser = $this->createParser($phpVersion);
}

$parserVersion = $this->phpVersion;

$parserMessage = 'Cannot use the existing parser: its PHP version is different than the one requested.';

if (null === $parserVersion) {
Assert::null($phpVersion, $parserMessage);
} else {
Assert::notNull($phpVersion, $parserMessage);
Assert::true($parserVersion->equals($phpVersion), $parserMessage);
}

return $this->parser;
}

private function createParser(): Parser
private function createParser(?PhpVersion $phpVersion): Parser
{
$version = PhpVersion::getNewestSupported();
$version = $phpVersion ?? PhpVersion::getHostVersion();
$lexer = $version->isHostVersion() ? new Lexer() : new Emulative($version);

return $version->id >= 80000
return $version->id >= 80_000
? new Php8($lexer, $version)
: new Php7($lexer, $version);
}
Expand Down
70 changes: 70 additions & 0 deletions tests/ContainerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

namespace Humbug\PhpScoper;

use InvalidArgumentException;
use PhpParser\PhpVersion;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -58,4 +60,72 @@ public static function provideServiceGetter(): iterable
}
}
}

#[DataProvider('samePhpVersionProvider')]
public function test_it_can_get_the_parser_if_the_version_does_not_change(
?PhpVersion $version1,
?PhpVersion $version2,
): void {
$container = new Container();

$container->getParser($version1);
$container->getParser($version2);

$this->addToAssertionCount(1);
}

public static function samePhpVersionProvider(): iterable
{
yield 'no PHP version configured' => [
null,
null,
];

$phpVersion = PhpVersion::fromString('7.2');

yield 'same PHP version instance' => [
$phpVersion,
$phpVersion,
];

yield 'same PHP version, different instances' => [
PhpVersion::fromString('7.3'),
PhpVersion::fromString('7.3'),
];
}

#[DataProvider('differentPhpVersionProvider')]
public function test_it_cannot_create_two_different_versions_of_the_parser(
?PhpVersion $version1,
?PhpVersion $version2,
): void {
$container = new Container();

$container->getParser($version1);

$this->expectException(InvalidArgumentException::class);

$container->getParser($version2);
}

public static function differentPhpVersionProvider(): iterable
{
$phpVersion = PhpVersion::fromString('7.2');
$anotherPhpVersion = PhpVersion::fromString('7.3');

yield 'no PHP version configured' => [
null,
$phpVersion,
];

yield 'no PHP version requested' => [
$phpVersion,
null,
];

yield 'different PHP versions' => [
$phpVersion,
$anotherPhpVersion,
];
}
}
9 changes: 6 additions & 3 deletions tests/Scoper/PhpScoperSpecTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use Humbug\PhpScoper\Symbol\Reflector;
use Humbug\PhpScoper\Symbol\SymbolsRegistry;
use PhpParser\Error as PhpParserError;
use PhpParser\PhpVersion;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -59,7 +60,7 @@ public function test_it_uses_the_right_specs_directory(): void
#[DataProvider('provideValidFiles')]
public function test_can_scope_valid_files(SpecScenario $scenario): void
{
$scenario->checkPHPVersionRequirements();
$scenario->checkPHPVersionRequirements($scenario->phpVersionUsed);

$filePath = 'file.php';
$symbolsRegistry = new SymbolsRegistry();
Expand All @@ -68,6 +69,7 @@ public function test_can_scope_valid_files(SpecScenario $scenario): void
$scenario->prefix,
$scenario->symbolsConfiguration,
$symbolsRegistry,
$scenario->getPhpParserVersion(),
);

try {
Expand Down Expand Up @@ -109,7 +111,8 @@ public static function provideValidFiles(): iterable
private static function createScoper(
string $prefix,
SymbolsConfiguration $symbolsConfiguration,
SymbolsRegistry $symbolsRegistry
SymbolsRegistry $symbolsRegistry,
?PhpVersion $phpVersionUsed,
): Scoper {
$container = new Container();

Expand All @@ -126,7 +129,7 @@ private static function createScoper(
);

return new PhpScoper(
$container->getParser(),
$container->getParser($phpVersionUsed),
new FakeScoper(),
new TraverserFactory(
$enrichedReflector,
Expand Down
1 change: 1 addition & 0 deletions tests/SpecFramework/Config/Meta.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public function __construct(
public string $prefix = 'Humbug',
public ?int $minPhpVersion = null,
public ?int $maxPhpVersion = null,
public ?int $phpVersionUsed = null,
public bool $exposeGlobalConstants = false,
public bool $exposeGlobalClasses = false,
public bool $exposeGlobalFunctions = false,
Expand Down
3 changes: 3 additions & 0 deletions tests/SpecFramework/Config/SpecWithConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public static function create(
?string $prefix = null,
?int $minPhpVersion = null,
?int $maxPhpVersion = null,
?int $phpVersionUsed = null,
?bool $exposeGlobalConstants = null,
?bool $exposeGlobalClasses = null,
?bool $exposeGlobalFunctions = null,
Expand All @@ -55,6 +56,7 @@ public static function create(
$prefix,
$minPhpVersion,
$maxPhpVersion,
$phpVersionUsed,
$exposeGlobalConstants,
$exposeGlobalClasses,
$exposeGlobalFunctions,
Expand All @@ -77,6 +79,7 @@ private function __construct(
public ?string $prefix,
public ?int $minPhpVersion,
public ?int $maxPhpVersion,
public ?int $phpVersionUsed,
public ?bool $exposeGlobalConstants,
public ?bool $exposeGlobalClasses,
public ?bool $exposeGlobalFunctions,
Expand Down
1 change: 1 addition & 0 deletions tests/SpecFramework/SpecParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ private static function parseSpec(
return new SpecScenario(
$specWithConfig->minPhpVersion ?? $meta->minPhpVersion ?? null,
$specWithConfig->maxPhpVersion ?? $meta->maxPhpVersion ?? null,
$specWithConfig->phpVersionUsed ?? $meta->phpVersionUsed ?? null,
$file,
$completeTitle,
$specWithConfig->inputCode,
Expand Down
25 changes: 22 additions & 3 deletions tests/SpecFramework/SpecScenario.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,20 @@

use Humbug\PhpScoper\Configuration\SymbolsConfiguration;
use Humbug\PhpScoper\Symbol\SymbolsRegistry;
use PhpParser\PhpVersion;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\SkippedWithMessageException;
use PHPUnit\Framework\TestCase;
use Throwable;
use function usort;
use const PHP_VERSION_ID;

final readonly class SpecScenario
{
public function __construct(
public ?int $minPhpVersion,
public ?int $maxPhpVersion,
public ?int $phpVersionUsed,
public string $file,
public string $title,
public string $inputCode,
Expand All @@ -38,12 +41,28 @@ public function __construct(
) {
}

public function checkPHPVersionRequirements(): void
public function getPhpParserVersion(): ?PhpVersion
{
$phpVersionId = $this->phpVersionUsed;

if (null === $phpVersionId) {
return null;
}

$minorRemainder = $phpVersionId % 1000;
$minor = $minorRemainder / 100;
$major = ($phpVersionId - $minorRemainder) / 10_000;

return PhpVersion::fromComponents($major, $minor);
}

public function checkPHPVersionRequirements(?int $phpVersionIdUsed): void
{
$phpVersionIdUsed ??= PHP_VERSION_ID;
$minPhpVersion = $this->minPhpVersion;
$maxPhpVersion = $this->maxPhpVersion;

if (null !== $minPhpVersion && $minPhpVersion > PHP_VERSION_ID) {
if (null !== $minPhpVersion && $minPhpVersion > $phpVersionIdUsed) {
throw new SkippedWithMessageException(
sprintf(
'Min PHP version not matched for spec "%s".',
Expand All @@ -52,7 +71,7 @@ public function checkPHPVersionRequirements(): void
);
}

if (null !== $maxPhpVersion && $maxPhpVersion <= PHP_VERSION_ID) {
if (null !== $maxPhpVersion && $maxPhpVersion <= $phpVersionIdUsed) {
throw new SkippedWithMessageException(
sprintf(
'Max PHP version not matched for spec "%s".',
Expand Down
2 changes: 2 additions & 0 deletions tests/SpecFrameworkTest/Fixtures/complete-spec-file.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
prefix: 'Humbug',
minPhpVersion: 70_200,
maxPhpVersion: 80_300,
phpVersionUsed: 70_400,
exposeGlobalConstants: true,
exposeGlobalClasses: true,
exposeGlobalFunctions: true,
Expand Down Expand Up @@ -62,6 +63,7 @@
prefix: 'AnotherPrefix',
minPhpVersion: 70_300,
maxPhpVersion: 80_200,
phpVersionUsed: 80_300,
exposeGlobalConstants: false,
exposeGlobalClasses: false,
exposeGlobalFunctions: false,
Expand Down
11 changes: 8 additions & 3 deletions tests/SpecFrameworkTest/SpecParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public static function specProvider(): iterable
self::FIXTURE_DIR.'/simple-spec-file.php',
[
'Fixtures/simple-spec-file.php: 0' => new SpecScenario(
null,
null,
null,
'Fixtures/simple-spec-file.php',
Expand All @@ -84,6 +85,7 @@ public static function specProvider(): iterable
[],
),
'Fixtures/simple-spec-file.php: A spec with a title' => new SpecScenario(
null,
null,
null,
'Fixtures/simple-spec-file.php:33',
Expand All @@ -108,7 +110,8 @@ public static function specProvider(): iterable
'Fixtures/complete-spec-file.php: Spec with default meta values' => new SpecScenario(
70_200,
80_300,
'Fixtures/complete-spec-file.php:39',
70_400,
'Fixtures/complete-spec-file.php:40',
'[Example of simple spec file] Spec with default meta values',
$specCode,
'Humbug',
Expand All @@ -132,7 +135,8 @@ public static function specProvider(): iterable
'Fixtures/complete-spec-file.php: Spec with the more verbose form' => new SpecScenario(
70_200,
80_300,
'Fixtures/complete-spec-file.php:49',
70_400,
'Fixtures/complete-spec-file.php:50',
'[Example of simple spec file] Spec with the more verbose form',
$specCode,
'Humbug',
Expand All @@ -156,7 +160,8 @@ public static function specProvider(): iterable
'Fixtures/complete-spec-file.php: Spec with overridden meta values' => new SpecScenario(
70_300,
80_200,
'Fixtures/complete-spec-file.php:61',
80_300,
'Fixtures/complete-spec-file.php:62',
'[Example of simple spec file] Spec with overridden meta values',
$specCode,
'AnotherPrefix',
Expand Down
4 changes: 4 additions & 0 deletions tests/SpecFrameworkTest/SpecPrinterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public static function scenarioProvider(): iterable

yield 'simple scenario' => [
new SpecScenario(
null,
null,
null,
'Fixtures/complete-spec-file.php',
Expand Down Expand Up @@ -139,6 +140,7 @@ public static function scenarioProvider(): iterable
new SpecScenario(
70_200,
80_300,
70_400,
'Fixtures/complete-spec-file.php',
'[Example of simple spec file] Spec with the more verbose form',
$specCode,
Expand Down Expand Up @@ -219,6 +221,7 @@ public static function scenarioProvider(): iterable
new SpecScenario(
70_200,
80_300,
70_400,
'Fixtures/complete-spec-file.php',
'[Example of simple spec file] Spec with the more verbose form',
$specCode,
Expand Down Expand Up @@ -333,6 +336,7 @@ public static function scenarioProvider(): iterable

yield 'simple scenario with recorded symbols' => [
new SpecScenario(
null,
null,
null,
'Fixtures/complete-spec-file.php',
Expand Down
Loading

0 comments on commit f21ea1b

Please sign in to comment.