expectException(ValidationException::class); $this->expectExceptionMessage('test.json is broken'); $data = 'not an array'; ConfigValidator::validateAndLintArtifacts('test.json', $data); } public function testValidateAndLintArtifactsWithCustomSource(): void { $data = [ 'test-artifact' => [ 'source' => 'custom', ], ]; ConfigValidator::validateAndLintArtifacts('test.json', $data); $this->assertEquals('custom', $data['test-artifact']['source']); } public function testValidateAndLintArtifactsExpandsUrlString(): void { $data = [ 'test-artifact' => [ 'source' => 'https://example.com/file.tar.gz', ], ]; ConfigValidator::validateAndLintArtifacts('test.json', $data); $this->assertIsArray($data['test-artifact']['source']); $this->assertEquals('url', $data['test-artifact']['source']['type']); $this->assertEquals('https://example.com/file.tar.gz', $data['test-artifact']['source']['url']); } public function testValidateAndLintArtifactsExpandsHttpUrlString(): void { $data = [ 'test-artifact' => [ 'source' => 'http://example.com/file.tar.gz', ], ]; ConfigValidator::validateAndLintArtifacts('test.json', $data); $this->assertIsArray($data['test-artifact']['source']); $this->assertEquals('url', $data['test-artifact']['source']['type']); $this->assertEquals('http://example.com/file.tar.gz', $data['test-artifact']['source']['url']); } public function testValidateAndLintArtifactsWithSourceObject(): void { $data = [ 'test-artifact' => [ 'source' => [ 'type' => 'git', 'url' => 'https://github.com/example/repo.git', 'rev' => 'main', ], ], ]; ConfigValidator::validateAndLintArtifacts('test.json', $data); $this->assertIsArray($data['test-artifact']['source']); $this->assertEquals('git', $data['test-artifact']['source']['type']); } public function testValidateAndLintArtifactsWithBinaryCustom(): void { $data = [ 'test-artifact' => [ 'binary' => 'custom', ], ]; ConfigValidator::validateAndLintArtifacts('test.json', $data); $this->assertIsArray($data['test-artifact']['binary']); $this->assertArrayHasKey('linux-x86_64', $data['test-artifact']['binary']); $this->assertEquals('custom', $data['test-artifact']['binary']['linux-x86_64']['type']); } public function testValidateAndLintArtifactsWithBinaryHosted(): void { $data = [ 'test-artifact' => [ 'binary' => 'hosted', ], ]; ConfigValidator::validateAndLintArtifacts('test.json', $data); $this->assertIsArray($data['test-artifact']['binary']); $this->assertArrayHasKey('macos-aarch64', $data['test-artifact']['binary']); $this->assertEquals('hosted', $data['test-artifact']['binary']['macos-aarch64']['type']); } public function testValidateAndLintArtifactsWithBinaryPlatformObject(): void { $data = [ 'test-artifact' => [ 'binary' => [ 'linux-x86_64' => [ 'type' => 'url', 'url' => 'https://example.com/binary.tar.gz', ], ], ], ]; ConfigValidator::validateAndLintArtifacts('test.json', $data); $this->assertEquals('url', $data['test-artifact']['binary']['linux-x86_64']['type']); } public function testValidateAndLintArtifactsExpandsBinaryPlatformUrlString(): void { $data = [ 'test-artifact' => [ 'binary' => [ 'linux-x86_64' => 'https://example.com/binary.tar.gz', ], ], ]; ConfigValidator::validateAndLintArtifacts('test.json', $data); $this->assertIsArray($data['test-artifact']['binary']['linux-x86_64']); $this->assertEquals('url', $data['test-artifact']['binary']['linux-x86_64']['type']); $this->assertEquals('https://example.com/binary.tar.gz', $data['test-artifact']['binary']['linux-x86_64']['url']); } public function testValidateAndLintArtifactsWithSourceMirror(): void { $data = [ 'test-artifact' => [ 'source-mirror' => 'https://mirror.example.com/file.tar.gz', ], ]; ConfigValidator::validateAndLintArtifacts('test.json', $data); $this->assertIsArray($data['test-artifact']['source-mirror']); $this->assertEquals('url', $data['test-artifact']['source-mirror']['type']); } public function testValidateAndLintPackagesThrowsExceptionWhenDataIsNotArray(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage('pkg.json is broken'); $data = 'not an array'; ConfigValidator::validateAndLintPackages('pkg.json', $data); } public function testValidateAndLintPackagesThrowsExceptionWhenPackageIsNotAssocArray(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage('Package [test-pkg] in pkg.json is not a valid associative array'); $data = [ 'test-pkg' => ['list', 'array'], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); } public function testValidateAndLintPackagesThrowsExceptionWhenTypeMissing(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage("Package [test-pkg] in pkg.json has invalid or missing 'type' field"); $data = [ 'test-pkg' => [ 'depends' => [], ], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); } public function testValidateAndLintPackagesThrowsExceptionWhenTypeInvalid(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage("Package [test-pkg] in pkg.json has invalid or missing 'type' field"); $data = [ 'test-pkg' => [ 'type' => 'invalid-type', ], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); } public function testValidateAndLintPackagesWithValidLibraryType(): void { $data = [ 'test-lib' => [ 'type' => 'library', 'artifact' => 'test-artifact', ], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); $this->assertEquals('library', $data['test-lib']['type']); } public function testValidateAndLintPackagesWithValidPhpExtensionType(): void { $data = [ 'test-ext' => [ 'type' => 'php-extension', ], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); $this->assertEquals('php-extension', $data['test-ext']['type']); } public function testValidateAndLintPackagesWithValidTargetType(): void { $data = [ 'test-target' => [ 'type' => 'target', 'artifact' => 'test-artifact', ], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); $this->assertEquals('target', $data['test-target']['type']); } public function testValidateAndLintPackagesWithValidVirtualTargetType(): void { $data = [ 'test-virtual' => [ 'type' => 'virtual-target', ], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); $this->assertEquals('virtual-target', $data['test-virtual']['type']); } public function testValidateAndLintPackagesThrowsExceptionWhenLibraryMissingArtifact(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage("Package [test-lib] in pkg.json of type 'library' must have an 'artifact' field"); $data = [ 'test-lib' => [ 'type' => 'library', ], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); } public function testValidateAndLintPackagesThrowsExceptionWhenTargetMissingArtifact(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage("Package [test-target] in pkg.json of type 'target' must have an 'artifact' field"); $data = [ 'test-target' => [ 'type' => 'target', ], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); } public function testValidateAndLintPackagesWithPhpExtensionFields(): void { $data = [ 'test-ext' => [ 'type' => 'php-extension', 'php-extension' => [ 'zend-extension' => false, 'build-shared' => true, ], ], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); $this->assertIsArray($data['test-ext']['php-extension']); } public function testValidateAndLintPackagesThrowsExceptionWhenPhpExtensionIsNotObject(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage('Package test-ext [php-extension] must be an object'); $data = [ 'test-ext' => [ 'type' => 'php-extension', 'php-extension' => 'string', ], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); } public function testValidateAndLintPackagesWithDependsField(): void { $data = [ 'test-pkg' => [ 'type' => 'library', 'artifact' => 'test', 'depends' => ['dep1', 'dep2'], ], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); $this->assertIsArray($data['test-pkg']['depends']); } public function testValidateAndLintPackagesThrowsExceptionWhenDependsIsNotList(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage('Package test-pkg [depends] must be a list'); $data = [ 'test-pkg' => [ 'type' => 'library', 'artifact' => 'test', 'depends' => 'not-a-list', ], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); } public function testValidateAndLintPackagesWithSuffixFields(): void { $data = [ 'test-pkg' => [ 'type' => 'library', 'artifact' => 'test', 'depends@linux' => ['linux-dep'], 'depends@windows' => ['windows-dep'], 'headers@unix' => ['header.h'], ], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); $this->assertIsArray($data['test-pkg']['depends@linux']); } public function testValidateAndLintPackagesThrowsExceptionForInvalidSuffixFieldType(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage('Package test-pkg [headers@linux] must be a list'); $data = [ 'test-pkg' => [ 'type' => 'library', 'artifact' => 'test', 'headers@linux' => 'not-a-list', ], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); } public function testValidateAndLintPackagesThrowsExceptionForUnknownField(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage('package [test-pkg] has invalid field [unknown-field]'); $data = [ 'test-pkg' => [ 'type' => 'library', 'artifact' => 'test', 'unknown-field' => 'value', ], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); } public function testValidateAndLintPackagesThrowsExceptionForUnknownPhpExtensionField(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage('php-extension [test-ext] has invalid field [unknown]'); $data = [ 'test-ext' => [ 'type' => 'php-extension', 'php-extension' => [ 'unknown' => 'value', ], ], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); } public function testValidatePlatformStringWithValidPlatforms(): void { ConfigValidator::validatePlatformString('linux-x86_64'); ConfigValidator::validatePlatformString('linux-aarch64'); ConfigValidator::validatePlatformString('windows-x86_64'); ConfigValidator::validatePlatformString('windows-aarch64'); ConfigValidator::validatePlatformString('macos-x86_64'); ConfigValidator::validatePlatformString('macos-aarch64'); $this->assertTrue(true); // If no exception thrown, test passes } public function testValidatePlatformStringThrowsExceptionForInvalidFormat(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage("Invalid platform format 'invalid', expected format 'os-arch'"); ConfigValidator::validatePlatformString('invalid'); } public function testValidatePlatformStringThrowsExceptionForTooManyParts(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage("Invalid platform format 'linux-x86_64-extra', expected format 'os-arch'"); ConfigValidator::validatePlatformString('linux-x86_64-extra'); } public function testValidatePlatformStringThrowsExceptionForInvalidOS(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage("Invalid platform OS 'bsd' in platform 'bsd-x86_64'"); ConfigValidator::validatePlatformString('bsd-x86_64'); } public function testValidatePlatformStringThrowsExceptionForInvalidArch(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage("Invalid platform architecture 'arm' in platform 'linux-arm'"); ConfigValidator::validatePlatformString('linux-arm'); } public function testArtifactTypeFieldsConstant(): void { $this->assertArrayHasKey('filelist', ConfigValidator::ARTIFACT_TYPE_FIELDS); $this->assertArrayHasKey('git', ConfigValidator::ARTIFACT_TYPE_FIELDS); $this->assertArrayHasKey('ghtagtar', ConfigValidator::ARTIFACT_TYPE_FIELDS); $this->assertArrayHasKey('url', ConfigValidator::ARTIFACT_TYPE_FIELDS); $this->assertArrayHasKey('custom', ConfigValidator::ARTIFACT_TYPE_FIELDS); } public function testValidateAndLintArtifactsThrowsExceptionForInvalidArtifactType(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage("Artifact source object has unknown type 'invalid-type'"); $data = [ 'test-artifact' => [ 'source' => [ 'type' => 'invalid-type', ], ], ]; ConfigValidator::validateAndLintArtifacts('test.json', $data); } public function testValidateAndLintArtifactsThrowsExceptionForMissingRequiredField(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage("Artifact source object of type 'git' must have required field 'url'"); $data = [ 'test-artifact' => [ 'source' => [ 'type' => 'git', 'rev' => 'main', // missing 'url' ], ], ]; ConfigValidator::validateAndLintArtifacts('test.json', $data); } public function testValidateAndLintArtifactsThrowsExceptionForMissingTypeInSource(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage("Artifact source object must have a valid 'type' field"); $data = [ 'test-artifact' => [ 'source' => [ 'url' => 'https://example.com', ], ], ]; ConfigValidator::validateAndLintArtifacts('test.json', $data); } public function testValidateAndLintArtifactsWithAllArtifactTypes(): void { $data = [ 'filelist-artifact' => [ 'source' => [ 'type' => 'filelist', 'url' => 'https://example.com/list', 'regex' => '/pattern/', ], ], 'git-artifact' => [ 'source' => [ 'type' => 'git', 'url' => 'https://github.com/example/repo.git', 'rev' => 'main', ], ], 'ghtagtar-artifact' => [ 'source' => [ 'type' => 'ghtagtar', 'repo' => 'example/repo', ], ], 'url-artifact' => [ 'source' => [ 'type' => 'url', 'url' => 'https://example.com/file.tar.gz', ], ], 'custom-artifact' => [ 'source' => [ 'type' => 'custom', ], ], ]; ConfigValidator::validateAndLintArtifacts('test.json', $data); $this->assertIsArray($data); } public function testValidateAndLintPackagesWithAllFieldTypes(): void { $data = [ 'test-pkg' => [ 'type' => 'library', 'artifact' => 'test-artifact', 'depends' => ['dep1'], 'suggests' => ['sug1'], 'license' => [ 'type' => 'file', 'path' => 'LICENSE', ], 'lang' => 'c', 'frameworks' => ['framework1'], 'headers' => ['header.h'], 'static-libs' => ['lib.a'], 'pkg-configs' => ['pkg.pc'], 'static-bins' => ['bin'], ], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); $this->assertEquals('library', $data['test-pkg']['type']); } public function testValidateAndLintPackagesThrowsExceptionForWrongTypeString(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage('Package test-pkg [artifact] must be string'); $data = [ 'test-pkg' => [ 'type' => 'library', 'artifact' => ['not', 'a', 'string'], ], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); } public function testValidateAndLintPackagesThrowsExceptionForWrongTypeBool(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage('Package test-ext [zend-extension] must be boolean'); $data = [ 'test-ext' => [ 'type' => 'php-extension', 'php-extension' => [ 'zend-extension' => 'not-a-bool', ], ], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); } public function testValidateAndLintPackagesThrowsExceptionForWrongTypeAssocArray(): void { $this->expectException(ValidationException::class); $this->expectExceptionMessage('Package test-pkg [support] must be an object'); $data = [ 'test-pkg' => [ 'type' => 'php-extension', 'php-extension' => [ 'support' => 'not-an-object', ], ], ]; ConfigValidator::validateAndLintPackages('pkg.json', $data); } }