Files
static-php-cli/tests/StaticPHP/Artifact/ArtifactDownloaderTest.php
2026-04-12 13:29:06 +08:00

352 lines
11 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\StaticPHP\Artifact;
use PHPUnit\Framework\TestCase;
use StaticPHP\Artifact\Artifact;
use StaticPHP\Artifact\ArtifactDownloader;
use StaticPHP\Config\ArtifactConfig;
use StaticPHP\Exception\WrongUsageException;
use StaticPHP\Registry\ArtifactLoader;
/**
* @internal
*/
class ArtifactDownloaderTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();
// Reset ArtifactConfig and ArtifactLoader static state
$reflection = new \ReflectionClass(ArtifactConfig::class);
$property = $reflection->getProperty('artifact_configs');
$property->setAccessible(true);
$property->setValue(null, []);
$loaderReflection = new \ReflectionClass(ArtifactLoader::class);
$loaderProperty = $loaderReflection->getProperty('artifacts');
$loaderProperty->setAccessible(true);
$loaderProperty->setValue(null, null);
}
protected function tearDown(): void
{
parent::tearDown();
$reflection = new \ReflectionClass(ArtifactConfig::class);
$property = $reflection->getProperty('artifact_configs');
$property->setAccessible(true);
$property->setValue(null, []);
$loaderReflection = new \ReflectionClass(ArtifactLoader::class);
$loaderProperty = $loaderReflection->getProperty('artifacts');
$loaderProperty->setAccessible(true);
$loaderProperty->setValue(null, null);
}
// ==================== DOWNLOADERS constant ====================
public function testDownloadersConstantHasExpectedKeys(): void
{
$expectedKeys = ['bitbuckettag', 'filelist', 'git', 'ghrel', 'ghtar', 'ghtagtar', 'local', 'pie', 'pecl', 'url', 'php-release', 'hosted'];
foreach ($expectedKeys as $key) {
$this->assertArrayHasKey($key, ArtifactDownloader::DOWNLOADERS, "Missing downloader key: {$key}");
}
}
// ==================== Constructor options ====================
public function testConstructWithDefaultOptions(): void
{
$downloader = new ArtifactDownloader([], false);
$this->assertSame(0, $downloader->getRetry());
$this->assertFalse($downloader->interactive);
$this->assertEmpty($downloader->getArtifacts());
}
public function testConstructWithParallelOption(): void
{
$downloader = new ArtifactDownloader(['parallel' => 4], false);
// parallel is internal but setParallel/getArtifacts reveals behavior; check via setParallel chainability
// Indirect verification: setParallel with same value returns $this
$this->assertSame($downloader, $downloader->setParallel(4));
}
public function testConstructWithRetryOption(): void
{
$downloader = new ArtifactDownloader(['retry' => 3], false);
$this->assertSame(3, $downloader->getRetry());
}
public function testConstructWithNegativeRetryClampedToZero(): void
{
$downloader = new ArtifactDownloader(['retry' => -5], false);
$this->assertSame(0, $downloader->getRetry());
}
public function testConstructWithPreferSourceBoolOption(): void
{
// prefer-source=true sets default to FETCH_PREFER_SOURCE (0)
$downloader = new ArtifactDownloader(['prefer-source' => true], false);
$this->assertSame(0, $downloader->getRetry()); // sanity check, object created fine
}
public function testConstructWithPreferBinaryBoolOption(): void
{
$downloader = new ArtifactDownloader(['prefer-binary' => true], false);
$this->assertNotNull($downloader);
}
public function testConstructWithPreferPreBuiltBoolOption(): void
{
$downloader = new ArtifactDownloader(['prefer-pre-built' => true], false);
$this->assertNotNull($downloader);
}
public function testConstructWithSourceOnlyBoolOption(): void
{
$downloader = new ArtifactDownloader(['source-only' => true], false);
$this->assertNotNull($downloader);
}
public function testConstructWithBinaryOnlyBoolOption(): void
{
$downloader = new ArtifactDownloader(['binary-only' => true], false);
$this->assertNotNull($downloader);
}
public function testConstructWithIgnoreCacheBoolOption(): void
{
$downloader = new ArtifactDownloader(['ignore-cache' => true], false);
$this->assertNotNull($downloader);
}
public function testConstructWithIgnoreCacheStringOptionParsesNames(): void
{
$downloader = new ArtifactDownloader(['ignore-cache' => 'openssl,zlib'], false);
$this->assertNotNull($downloader);
}
public function testConstructWithIgnoreCacheSourcesBackwardCompat(): void
{
$downloader = new ArtifactDownloader(['ignore-cache-sources' => true], false);
$this->assertNotNull($downloader);
}
public function testConstructWithCustomUrlOptionAddsToIgnoreCache(): void
{
$downloader = new ArtifactDownloader(
['custom-url' => ['openssl:https://custom.example.com/openssl.tar.gz']],
false
);
$this->assertNotNull($downloader);
}
public function testConstructWithCustomGitOption(): void
{
$downloader = new ArtifactDownloader(
['custom-git' => ['php-src:master:https://github.com/php/php-src.git']],
false
);
$this->assertNotNull($downloader);
}
public function testConstructWithCustomLocalOption(): void
{
$downloader = new ArtifactDownloader(
['custom-local' => ['my-lib:/tmp/my-lib-source']],
false
);
$this->assertNotNull($downloader);
}
public function testConstructWithNoAltOption(): void
{
$downloader = new ArtifactDownloader(['no-alt' => true], false);
$this->assertNotNull($downloader);
}
// ==================== getRetry ====================
public function testGetRetryDefaultsToZero(): void
{
$downloader = new ArtifactDownloader([], false);
$this->assertSame(0, $downloader->getRetry());
}
public function testGetRetryReturnsConfiguredValue(): void
{
$downloader = new ArtifactDownloader(['retry' => 5], false);
$this->assertSame(5, $downloader->getRetry());
}
// ==================== getOption ====================
public function testGetOptionReturnsConfiguredValue(): void
{
$downloader = new ArtifactDownloader(['retry' => 2, 'parallel' => 3], false);
$this->assertSame(2, $downloader->getOption('retry'));
$this->assertSame(3, $downloader->getOption('parallel'));
}
public function testGetOptionReturnsDefaultWhenNotSet(): void
{
$downloader = new ArtifactDownloader([], false);
$this->assertNull($downloader->getOption('non-existent'));
$this->assertSame('default-val', $downloader->getOption('non-existent', 'default-val'));
}
// ==================== getArtifacts ====================
public function testGetArtifactsReturnsEmptyInitially(): void
{
$downloader = new ArtifactDownloader([], false);
$this->assertSame([], $downloader->getArtifacts());
}
// ==================== add ====================
public function testAddWithArtifactObjectAddsToList(): void
{
$downloader = new ArtifactDownloader([], false);
$artifact = new Artifact('my-pkg', ['source' => ['type' => 'url', 'url' => 'https://example.com/file.tar.gz']]);
$downloader->add($artifact);
$artifacts = $downloader->getArtifacts();
$this->assertArrayHasKey('my-pkg', $artifacts);
$this->assertSame($artifact, $artifacts['my-pkg']);
}
public function testAddReturnsSelf(): void
{
$downloader = new ArtifactDownloader([], false);
$artifact = new Artifact('my-pkg', ['source' => ['type' => 'url', 'url' => 'https://example.com/file.tar.gz']]);
$result = $downloader->add($artifact);
$this->assertSame($downloader, $result);
}
public function testAddDoesNotAddDuplicateArtifact(): void
{
$downloader = new ArtifactDownloader([], false);
$artifact = new Artifact('my-pkg', ['source' => ['type' => 'url', 'url' => 'https://example.com/file.tar.gz']]);
$downloader->add($artifact);
$downloader->add($artifact);
$this->assertCount(1, $downloader->getArtifacts());
}
public function testAddWithStringNameLooksUpFromArtifactLoader(): void
{
$this->injectArtifactConfig('my-lib', ['source' => ['type' => 'url', 'url' => 'https://example.com/file.tar.gz']]);
$downloader = new ArtifactDownloader([], false);
$downloader->add('my-lib');
$artifacts = $downloader->getArtifacts();
$this->assertArrayHasKey('my-lib', $artifacts);
}
public function testAddWithStringNameThrowsForNonExistentArtifact(): void
{
$downloader = new ArtifactDownloader([], false);
$this->expectException(WrongUsageException::class);
$this->expectExceptionMessage("Artifact 'non-existent' not found");
$downloader->add('non-existent');
}
// ==================== addArtifacts ====================
public function testAddArtifactsAddsMultipleAtOnce(): void
{
$downloader = new ArtifactDownloader([], false);
$a1 = new Artifact('pkg-a', ['source' => ['type' => 'url', 'url' => 'https://example.com/a.tar.gz']]);
$a2 = new Artifact('pkg-b', ['source' => ['type' => 'url', 'url' => 'https://example.com/b.tar.gz']]);
$downloader->addArtifacts([$a1, $a2]);
$this->assertCount(2, $downloader->getArtifacts());
$this->assertArrayHasKey('pkg-a', $downloader->getArtifacts());
$this->assertArrayHasKey('pkg-b', $downloader->getArtifacts());
}
public function testAddArtifactsReturnsSelf(): void
{
$downloader = new ArtifactDownloader([], false);
$result = $downloader->addArtifacts([]);
$this->assertSame($downloader, $result);
}
// ==================== setParallel ====================
public function testSetParallelReturnsSelf(): void
{
$downloader = new ArtifactDownloader([], false);
$result = $downloader->setParallel(3);
$this->assertSame($downloader, $result);
}
public function testSetParallelEnforcesMinimumOfOne(): void
{
$downloader = new ArtifactDownloader([], false);
$downloader->setParallel(0);
// No direct getter for parallel, but verifying it doesn't throw
$this->assertSame($downloader, $downloader->setParallel(0));
}
public function testSetParallelAcceptsNormalValue(): void
{
$downloader = new ArtifactDownloader([], false);
$result = $downloader->setParallel(5);
$this->assertSame($downloader, $result);
}
// ==================== Helpers ====================
private function injectArtifactConfig(string $name, array $config): void
{
$reflection = new \ReflectionClass(ArtifactConfig::class);
$property = $reflection->getProperty('artifact_configs');
$property->setAccessible(true);
$configs = $property->getValue(null) ?? [];
$configs[$name] = $config;
$property->setValue(null, $configs);
}
}