static-php-cli/tests/StaticPHP/Config/PackageConfigTest.php
2026-02-06 17:02:36 +08:00

436 lines
14 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\StaticPHP\Config;
use PHPUnit\Framework\TestCase;
use StaticPHP\Config\PackageConfig;
use StaticPHP\Exception\ValidationException;
use StaticPHP\Exception\WrongUsageException;
use StaticPHP\Runtime\SystemTarget;
/**
* @internal
*/
class PackageConfigTest extends TestCase
{
private string $tempDir;
protected function setUp(): void
{
parent::setUp();
$this->tempDir = sys_get_temp_dir() . '/package_config_test_' . uniqid();
mkdir($this->tempDir, 0755, true);
// Reset static state
$reflection = new \ReflectionClass(PackageConfig::class);
$property = $reflection->getProperty('package_configs');
$property->setAccessible(true);
$property->setValue([]);
}
protected function tearDown(): void
{
parent::tearDown();
// Clean up temp directory
if (is_dir($this->tempDir)) {
$this->removeDirectory($this->tempDir);
}
// Reset static state
$reflection = new \ReflectionClass(PackageConfig::class);
$property = $reflection->getProperty('package_configs');
$property->setAccessible(true);
$property->setValue([]);
}
public function testLoadFromDirThrowsExceptionWhenDirectoryDoesNotExist(): void
{
$this->expectException(WrongUsageException::class);
$this->expectExceptionMessage('Directory /nonexistent/path does not exist, cannot load pkg.json config.');
PackageConfig::loadFromDir('/nonexistent/path', 'test');
}
public function testLoadFromDirWithValidPkgJson(): void
{
$packageContent = json_encode([
'test-pkg' => [
'type' => 'library',
'artifact' => 'test-artifact',
],
]);
file_put_contents($this->tempDir . '/pkg.json', $packageContent);
PackageConfig::loadFromDir($this->tempDir, 'test');
$this->assertTrue(PackageConfig::isPackageExists('test-pkg'));
}
public function testLoadFromDirWithMultiplePackageFiles(): void
{
$pkg1Content = json_encode([
'pkg-1' => [
'type' => 'library',
'artifact' => 'artifact-1',
],
]);
$pkg2Content = json_encode([
'pkg-2' => [
'type' => 'php-extension',
],
]);
file_put_contents($this->tempDir . '/pkg.ext.json', $pkg1Content);
file_put_contents($this->tempDir . '/pkg.lib.json', $pkg2Content);
file_put_contents($this->tempDir . '/pkg.json', json_encode(['pkg-3' => ['type' => 'virtual-target']]));
PackageConfig::loadFromDir($this->tempDir, 'test');
$this->assertTrue(PackageConfig::isPackageExists('pkg-1'));
$this->assertTrue(PackageConfig::isPackageExists('pkg-2'));
$this->assertTrue(PackageConfig::isPackageExists('pkg-3'));
}
public function testLoadFromFileThrowsExceptionWhenFileCannotBeRead(): void
{
$this->expectException(WrongUsageException::class);
$this->expectExceptionMessage('Failed to read package config file:');
PackageConfig::loadFromFile('/nonexistent/file.json', 'test');
}
public function testLoadFromFileThrowsExceptionWhenJsonIsInvalid(): void
{
$file = $this->tempDir . '/invalid.json';
file_put_contents($file, 'not valid json{');
$this->expectException(ValidationException::class);
$this->expectExceptionMessage('invalid.json is broken');
PackageConfig::loadFromFile($file, 'test');
}
public function testLoadFromFileWithValidJson(): void
{
$file = $this->tempDir . '/valid.json';
$content = json_encode([
'my-pkg' => [
'type' => 'library',
'artifact' => 'my-artifact',
],
]);
file_put_contents($file, $content);
PackageConfig::loadFromFile($file, 'test');
$this->assertTrue(PackageConfig::isPackageExists('my-pkg'));
}
public function testIsPackageExistsReturnsFalseWhenPackageNotLoaded(): void
{
$this->assertFalse(PackageConfig::isPackageExists('non-existent'));
}
public function testIsPackageExistsReturnsTrueWhenPackageLoaded(): void
{
$file = $this->tempDir . '/pkg.json';
$content = json_encode([
'test-pkg' => [
'type' => 'library',
'artifact' => 'test',
],
]);
file_put_contents($file, $content);
PackageConfig::loadFromFile($file, 'test');
$this->assertTrue(PackageConfig::isPackageExists('test-pkg'));
}
public function testGetAllReturnsAllLoadedPackages(): void
{
$file = $this->tempDir . '/pkg.json';
$content = json_encode([
'pkg-a' => ['type' => 'virtual-target'],
'pkg-b' => ['type' => 'virtual-target'],
'pkg-c' => ['type' => 'virtual-target'],
]);
file_put_contents($file, $content);
PackageConfig::loadFromFile($file, 'test');
$all = PackageConfig::getAll();
$this->assertIsArray($all);
$this->assertCount(3, $all);
$this->assertArrayHasKey('pkg-a', $all);
$this->assertArrayHasKey('pkg-b', $all);
$this->assertArrayHasKey('pkg-c', $all);
}
public function testGetReturnsDefaultWhenPackageNotExists(): void
{
$result = PackageConfig::get('non-existent', 'field', 'default-value');
$this->assertEquals('default-value', $result);
}
public function testGetReturnsWholePackageWhenFieldNameIsNull(): void
{
$file = $this->tempDir . '/pkg.json';
$content = json_encode([
'test-pkg' => [
'type' => 'library',
'artifact' => 'test',
'depends' => ['dep1'],
],
]);
file_put_contents($file, $content);
PackageConfig::loadFromFile($file, 'test');
$result = PackageConfig::get('test-pkg');
$this->assertIsArray($result);
$this->assertEquals('library', $result['type']);
$this->assertEquals('test', $result['artifact']);
}
public function testGetReturnsFieldValueWhenFieldExists(): void
{
$file = $this->tempDir . '/pkg.json';
$content = json_encode([
'test-pkg' => [
'type' => 'library',
'artifact' => 'test-artifact',
],
]);
file_put_contents($file, $content);
PackageConfig::loadFromFile($file, 'test');
$result = PackageConfig::get('test-pkg', 'artifact');
$this->assertEquals('test-artifact', $result);
}
public function testGetReturnsDefaultWhenFieldNotExists(): void
{
$file = $this->tempDir . '/pkg.json';
$content = json_encode([
'test-pkg' => [
'type' => 'library',
'artifact' => 'test',
],
]);
file_put_contents($file, $content);
PackageConfig::loadFromFile($file, 'test');
$result = PackageConfig::get('test-pkg', 'non-existent-field', 'default');
$this->assertEquals('default', $result);
}
public function testGetWithSuffixFieldsOnLinux(): void
{
// Mock SystemTarget to return Linux
$mockTarget = $this->getMockBuilder(SystemTarget::class)
->disableOriginalConstructor()
->getMock();
$file = $this->tempDir . '/pkg.json';
$content = json_encode([
'test-pkg' => [
'type' => 'library',
'artifact' => 'test',
'depends' => ['base-dep'],
'depends@linux' => ['linux-dep'],
'depends@unix' => ['unix-dep'],
'depends@windows' => ['windows-dep'],
],
]);
file_put_contents($file, $content);
PackageConfig::loadFromFile($file, 'test');
// The get method will check SystemTarget::getTargetOS()
// On real Linux systems, it should return 'depends@linux' first
$result = PackageConfig::get('test-pkg', 'depends', []);
// Result should be one of the suffixed versions or base version
$this->assertIsArray($result);
}
public function testGetWithSuffixFieldsReturnsBasicFieldWhenNoSuffixMatch(): void
{
$file = $this->tempDir . '/pkg.json';
$content = json_encode([
'test-pkg' => [
'type' => 'library',
'artifact' => 'test',
'depends' => ['base-dep'],
],
]);
file_put_contents($file, $content);
PackageConfig::loadFromFile($file, 'test');
$result = PackageConfig::get('test-pkg', 'depends');
$this->assertEquals(['base-dep'], $result);
}
public function testGetWithNonSuffixedFieldIgnoresSuffixes(): void
{
$file = $this->tempDir . '/pkg.json';
$content = json_encode([
'test-pkg' => [
'type' => 'library',
'artifact' => 'test-artifact',
'artifact@linux' => 'linux-artifact', // This should be ignored
],
]);
file_put_contents($file, $content);
PackageConfig::loadFromFile($file, 'test');
// 'artifact' is not in SUFFIX_ALLOWED_FIELDS, so it won't check suffixes
$result = PackageConfig::get('test-pkg', 'artifact');
$this->assertEquals('test-artifact', $result);
}
public function testGetAllSuffixAllowedFields(): void
{
$file = $this->tempDir . '/pkg.json';
$content = json_encode([
'test-pkg' => [
'type' => 'library',
'artifact' => 'test',
'depends@linux' => ['dep1'],
'suggests@macos' => ['sug1'],
'headers@unix' => ['header.h'],
'static-libs@windows' => ['lib.a'],
'static-bins@linux' => ['bin'],
],
]);
file_put_contents($file, $content);
PackageConfig::loadFromFile($file, 'test');
// These are all suffix-allowed fields
$pkg = PackageConfig::get('test-pkg');
$this->assertArrayHasKey('depends@linux', $pkg);
$this->assertArrayHasKey('suggests@macos', $pkg);
$this->assertArrayHasKey('headers@unix', $pkg);
$this->assertArrayHasKey('static-libs@windows', $pkg);
$this->assertArrayHasKey('static-bins@linux', $pkg);
}
public function testLoadFromDirWithEmptyDirectory(): void
{
// Empty directory should not throw exception
PackageConfig::loadFromDir($this->tempDir, 'test');
$this->assertEquals([], PackageConfig::getAll());
}
public function testMultipleLoadsAppendConfigs(): void
{
$file1 = $this->tempDir . '/pkg1.json';
$file2 = $this->tempDir . '/pkg2.json';
file_put_contents($file1, json_encode(['pkg1' => ['type' => 'virtual-target']]));
file_put_contents($file2, json_encode(['pkg2' => ['type' => 'virtual-target']]));
PackageConfig::loadFromFile($file1, 'test');
PackageConfig::loadFromFile($file2, 'test');
$all = PackageConfig::getAll();
$this->assertCount(2, $all);
$this->assertArrayHasKey('pkg1', $all);
$this->assertArrayHasKey('pkg2', $all);
}
public function testGetWithComplexPhpExtensionPackage(): void
{
$file = $this->tempDir . '/pkg.json';
$content = json_encode([
'test-ext' => [
'type' => 'php-extension',
'depends' => ['dep1'],
'php-extension' => [
'zend-extension' => false,
'build-shared' => true,
'build-static' => false,
],
],
]);
file_put_contents($file, $content);
PackageConfig::loadFromFile($file, 'test');
$phpExt = PackageConfig::get('test-ext', 'php-extension');
$this->assertIsArray($phpExt);
$this->assertFalse($phpExt['zend-extension']);
$this->assertTrue($phpExt['build-shared']);
}
public function testGetReturnsNullAsDefaultWhenNotSpecified(): void
{
$file = $this->tempDir . '/pkg.json';
$content = json_encode([
'test-pkg' => [
'type' => 'virtual-target',
],
]);
file_put_contents($file, $content);
PackageConfig::loadFromFile($file, 'test');
$result = PackageConfig::get('test-pkg', 'non-existent');
$this->assertNull($result);
}
public function testLoadFromFileWithAllPackageTypes(): void
{
$file = $this->tempDir . '/pkg.json';
$content = json_encode([
'library-pkg' => [
'type' => 'library',
'artifact' => 'lib-artifact',
],
'extension-pkg' => [
'type' => 'php-extension',
],
'target-pkg' => [
'type' => 'target',
'artifact' => 'target-artifact',
],
'virtual-pkg' => [
'type' => 'virtual-target',
],
]);
file_put_contents($file, $content);
PackageConfig::loadFromFile($file, 'test');
$this->assertTrue(PackageConfig::isPackageExists('library-pkg'));
$this->assertTrue(PackageConfig::isPackageExists('extension-pkg'));
$this->assertTrue(PackageConfig::isPackageExists('target-pkg'));
$this->assertTrue(PackageConfig::isPackageExists('virtual-pkg'));
}
private function removeDirectory(string $dir): void
{
if (!is_dir($dir)) {
return;
}
$files = array_diff(scandir($dir), ['.', '..']);
foreach ($files as $file) {
$path = $dir . '/' . $file;
is_dir($path) ? $this->removeDirectory($path) : unlink($path);
}
rmdir($dir);
}
}