mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-18 06:15:37 +08:00
Add getResolvedPackageClosure method to DependencyResolver for improved package resolution
This commit is contained in:
@@ -412,6 +412,39 @@ class DependencyResolverTest extends TestCase
|
||||
$this->assertNotContains('c', $subDeps, 'c is not in the resolved set, should be excluded');
|
||||
}
|
||||
|
||||
public function testGetResolvedPackageClosureFiltersSuggestsThroughResolvedSet(): void
|
||||
{
|
||||
$this->loadConfig([
|
||||
'a' => ['type' => 'target', 'depends' => ['b'], 'suggests' => ['c']],
|
||||
'b' => ['type' => 'library'],
|
||||
'c' => ['type' => 'library'],
|
||||
]);
|
||||
|
||||
$withoutSuggested = DependencyResolver::getResolvedPackageClosure(['a'], ['b', 'a']);
|
||||
$withSuggested = DependencyResolver::getResolvedPackageClosure(['a'], ['b', 'c', 'a']);
|
||||
|
||||
$this->assertSame(['b', 'a'], $withoutSuggested);
|
||||
$this->assertSame(['b', 'c', 'a'], $withSuggested);
|
||||
}
|
||||
|
||||
public function testGetResolvedPackageClosureAppliesDependencyOverrides(): void
|
||||
{
|
||||
$this->loadConfig([
|
||||
'php' => ['type' => 'target', 'depends' => ['libxml2']],
|
||||
'libxml2' => ['type' => 'library'],
|
||||
'ext-demo' => ['type' => 'php-extension', 'depends' => ['demo-lib']],
|
||||
'demo-lib' => ['type' => 'library'],
|
||||
]);
|
||||
|
||||
$closure = DependencyResolver::getResolvedPackageClosure(
|
||||
['php'],
|
||||
['libxml2', 'demo-lib', 'ext-demo', 'php'],
|
||||
['php' => ['ext-demo']],
|
||||
);
|
||||
|
||||
$this->assertSame(['libxml2', 'demo-lib', 'ext-demo', 'php'], $closure);
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────
|
||||
// Edge cases & defensive
|
||||
// ──────────────────────────────────────────────
|
||||
|
||||
207
tests/StaticPHP/Util/SPCConfigUtilTest.php
Normal file
207
tests/StaticPHP/Util/SPCConfigUtilTest.php
Normal file
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\StaticPHP\Util;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use StaticPHP\Config\PackageConfig;
|
||||
use StaticPHP\DI\ApplicationContext;
|
||||
use StaticPHP\Exception\WrongUsageException;
|
||||
use StaticPHP\Package\LibraryPackage;
|
||||
use StaticPHP\Package\Package;
|
||||
use StaticPHP\Package\PackageInstaller;
|
||||
use StaticPHP\Package\PhpExtensionPackage;
|
||||
use StaticPHP\Package\TargetPackage;
|
||||
use StaticPHP\Util\SPCConfigUtil;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class SPCConfigUtilTest extends TestCase
|
||||
{
|
||||
/** @var array<string, false|string> */
|
||||
private array $savedEnv = [];
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
ApplicationContext::reset();
|
||||
$this->resetPackageConfig();
|
||||
foreach (['CFLAGS', 'CXXFLAGS', 'LDFLAGS', 'LIBS', 'SPC_DEFAULT_CFLAGS', 'SPC_DEFAULT_CXXFLAGS', 'SPC_DEFAULT_LDFLAGS', 'SPC_EXTRA_LIBS'] as $name) {
|
||||
$this->savedEnv[$name] = getenv($name);
|
||||
}
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
foreach ($this->savedEnv as $name => $value) {
|
||||
$value === false ? putenv($name) : putenv("{$name}={$value}");
|
||||
}
|
||||
$this->resetPackageConfig();
|
||||
ApplicationContext::reset();
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function testStandaloneConfigStillControlsSuggestsDuringResolution(): void
|
||||
{
|
||||
$this->loadLinkFixture();
|
||||
$util = new SPCConfigUtil(['no_php' => true, 'libs_only_deps' => true]);
|
||||
|
||||
$withoutSuggests = $util->config(['root']);
|
||||
$withSuggests = $util->config(['root'], include_suggests: true);
|
||||
|
||||
$this->assertStringContainsString('/fixtures/librequired.a', $withoutSuggests['libs']);
|
||||
$this->assertStringNotContainsString('/fixtures/liboptional.a', $withoutSuggests['libs']);
|
||||
$this->assertStringContainsString('/fixtures/liboptional.a', $withSuggests['libs']);
|
||||
}
|
||||
|
||||
public function testResolvedConfigIncludesOnlySuggestedPackagesThatWereResolved(): void
|
||||
{
|
||||
$this->loadLinkFixture();
|
||||
$util = new SPCConfigUtil(['no_php' => true, 'libs_only_deps' => true]);
|
||||
|
||||
$withoutOptional = $util->configForResolvedBuild(['root'], $this->createInstaller([
|
||||
'required' => 'library',
|
||||
'root' => 'library',
|
||||
]));
|
||||
$withOptional = $util->configForResolvedBuild(['root'], $this->createInstaller([
|
||||
'required' => 'library',
|
||||
'optional' => 'library',
|
||||
'root' => 'library',
|
||||
]));
|
||||
|
||||
$this->assertStringNotContainsString('/fixtures/liboptional.a', $withoutOptional['libs']);
|
||||
$this->assertStringContainsString('/fixtures/liboptional.a', $withOptional['libs']);
|
||||
}
|
||||
|
||||
public function testResolvedConfigSupportsExplicitPhpLinkClosureOverrides(): void
|
||||
{
|
||||
$this->loadConfig([
|
||||
'php' => ['type' => 'target', 'depends' => ['core']],
|
||||
'core' => ['type' => 'library', 'static-libs' => ['/fixtures/libcore.a']],
|
||||
'ext-demo' => ['type' => 'php-extension', 'depends' => ['ext-lib']],
|
||||
'ext-lib' => ['type' => 'library', 'static-libs' => ['/fixtures/libext.a']],
|
||||
'php-fpm' => ['type' => 'virtual-target', 'depends' => ['php'], 'suggests' => ['fpm-lib']],
|
||||
'fpm-lib' => ['type' => 'library', 'static-libs' => ['/fixtures/libfpm.a']],
|
||||
]);
|
||||
$util = new SPCConfigUtil(['libs_only_deps' => true]);
|
||||
|
||||
$config = $util->configForResolvedBuild(['php'], $this->createInstaller([
|
||||
'core' => 'library',
|
||||
'ext-lib' => 'library',
|
||||
'ext-demo' => 'static-extension',
|
||||
'fpm-lib' => 'library',
|
||||
'php-fpm' => 'virtual-target',
|
||||
'php' => 'target',
|
||||
]));
|
||||
|
||||
$this->assertStringContainsString('/fixtures/libcore.a', $config['libs']);
|
||||
$this->assertStringContainsString('/fixtures/libext.a', $config['libs']);
|
||||
$this->assertStringContainsString('/fixtures/libfpm.a', $config['libs']);
|
||||
}
|
||||
|
||||
public function testResolvedConfigRejectsRootOutsideResolvedSet(): void
|
||||
{
|
||||
$this->loadLinkFixture();
|
||||
|
||||
$this->expectException(WrongUsageException::class);
|
||||
$this->expectExceptionMessage("Package 'root' is not part of the resolved package set");
|
||||
|
||||
new SPCConfigUtil(['no_php' => true])->configForResolvedBuild(['root'], $this->createInstaller([
|
||||
'required' => 'library',
|
||||
]));
|
||||
}
|
||||
|
||||
public function testCAndCxxFlagsRemainIndependent(): void
|
||||
{
|
||||
putenv('SPC_DEFAULT_CFLAGS=-DDEFAULT_C');
|
||||
putenv('SPC_DEFAULT_CXXFLAGS=-DDEFAULT_CXX');
|
||||
putenv('SPC_DEFAULT_LDFLAGS=-Wl,default');
|
||||
putenv('CFLAGS=-DUSER_C');
|
||||
putenv('CXXFLAGS=-DUSER_CXX');
|
||||
putenv('LDFLAGS=-Wl,user');
|
||||
|
||||
$config = new SPCConfigUtil(['no_php' => true, 'libs_only_deps' => true])->configWithResolvedPackages([]);
|
||||
|
||||
$this->assertStringContainsString('-DDEFAULT_C', $config['cflags']);
|
||||
$this->assertStringContainsString('-DUSER_C', $config['cflags']);
|
||||
$this->assertStringNotContainsString('-DDEFAULT_CXX', $config['cflags']);
|
||||
$this->assertStringContainsString('-DDEFAULT_CXX', $config['cxxflags']);
|
||||
$this->assertStringContainsString('-DUSER_CXX', $config['cxxflags']);
|
||||
$this->assertStringContainsString('-Wl,default', $config['ldflags']);
|
||||
$this->assertStringContainsString('-Wl,user', $config['ldflags']);
|
||||
}
|
||||
|
||||
private function loadLinkFixture(): void
|
||||
{
|
||||
$this->loadConfig([
|
||||
'root' => [
|
||||
'type' => 'library',
|
||||
'depends' => ['required'],
|
||||
'suggests' => ['optional'],
|
||||
'static-libs' => ['/fixtures/libroot.a'],
|
||||
],
|
||||
'required' => ['type' => 'library', 'static-libs' => ['/fixtures/librequired.a']],
|
||||
'optional' => ['type' => 'library', 'static-libs' => ['/fixtures/liboptional.a']],
|
||||
]);
|
||||
}
|
||||
|
||||
private function loadConfig(array $configs): void
|
||||
{
|
||||
$reflection = new \ReflectionClass(PackageConfig::class);
|
||||
$property = $reflection->getProperty('package_configs');
|
||||
$property->setValue(null, $configs);
|
||||
}
|
||||
|
||||
private function resetPackageConfig(): void
|
||||
{
|
||||
$this->loadConfig([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, 'library'|'static-extension'|'target'|'virtual-target'> $packages
|
||||
*/
|
||||
private function createInstaller(array $packages): PackageInstaller
|
||||
{
|
||||
$installer = new PackageInstaller(['no-tracker' => true], false);
|
||||
$resolved = [];
|
||||
foreach ($packages as $name => $type) {
|
||||
$package = match ($type) {
|
||||
'static-extension' => $this->createStaticExtension($name),
|
||||
'target' => $this->createTarget($name, false),
|
||||
'virtual-target' => $this->createTarget($name, true),
|
||||
default => $this->createNamedPackage(LibraryPackage::class, $name),
|
||||
};
|
||||
$resolved[$name] = $package;
|
||||
}
|
||||
|
||||
$reflection = new \ReflectionClass(PackageInstaller::class);
|
||||
$reflection->getProperty('packages')->setValue($installer, $resolved);
|
||||
return $installer;
|
||||
}
|
||||
|
||||
private function createStaticExtension(string $name): PhpExtensionPackage
|
||||
{
|
||||
$extension = $this->createMock(PhpExtensionPackage::class);
|
||||
$extension->method('getName')->willReturn($name);
|
||||
$extension->method('isBuildStatic')->willReturn(true);
|
||||
return $extension;
|
||||
}
|
||||
|
||||
private function createTarget(string $name, bool $virtual): TargetPackage
|
||||
{
|
||||
$target = $this->createMock(TargetPackage::class);
|
||||
$target->method('getName')->willReturn($name);
|
||||
$target->method('isVirtualTarget')->willReturn($virtual);
|
||||
return $target;
|
||||
}
|
||||
|
||||
/** @param class-string<Package> $class */
|
||||
private function createNamedPackage(string $class, string $name): Package
|
||||
{
|
||||
$package = $this->createMock($class);
|
||||
$package->method('getName')->willReturn($name);
|
||||
return $package;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user