testDir = sys_get_temp_dir() . '/composer_test_' . uniqid(); mkdir($this->testDir, 0777, true); // Create mock SymfonyStyle $this->io = $this->createMock(SymfonyStyle::class); $this->composerGenerator = new ComposerGenerator(); } protected function tearDown(): void { if (is_dir($this->testDir)) { $this->removeDirectory($this->testDir); } } private function removeDirectory($dir) { if (!is_dir($dir)) { return; } $items = scandir($dir); foreach ($items as $item) { if ($item != '.' && $item != '..') { $path = $dir . DIRECTORY_SEPARATOR . $item; if (is_dir($path)) { $this->removeDirectory($path); } else { unlink($path); } } } rmdir($dir); } public function testGenerateContent() { $packageName = 'six-shop/test-extension'; $namespace = 'SixShop\\TestExtension\\'; $id = 'six-shop-test-extension'; $description = 'A test extension package'; $content = $this->composerGenerator->generateContent($packageName, $namespace, $id, $description); $this->assertIsString($content); $this->assertNotEmpty($content); // Test JSON structure $jsonData = json_decode($content, true); $this->assertIsArray($jsonData); $this->assertEquals(JSON_ERROR_NONE, json_last_error()); // Test package information $this->assertEquals($packageName, $jsonData['name']); $this->assertEquals($description, $jsonData['description']); // Test PSR-4 autoloading $this->assertArrayHasKey('autoload', $jsonData); $this->assertArrayHasKey('psr-4', $jsonData['autoload']); $this->assertArrayHasKey($namespace, $jsonData['autoload']['psr-4']); $this->assertEquals('src', $jsonData['autoload']['psr-4'][$namespace]); // Test SixShop extension configuration $this->assertArrayHasKey('extra', $jsonData); $this->assertArrayHasKey('sixshop', $jsonData['extra']); $this->assertEquals($id, $jsonData['extra']['sixshop']['id']); } public function testSaveComposerFile() { $packageName = 'six-shop/test-extension'; $content = '{"name": "six-shop/test-extension", "description": "Test"}'; $this->io->expects($this->once()) ->method('success') ->with($this->stringContains('composer.json 文件已成功生成')); $result = $this->composerGenerator->saveComposerFile($packageName, $content, $this->testDir, $this->io); $this->assertTrue($result); $this->assertFileExists($this->testDir . '/composer.json'); $this->assertEquals($content, file_get_contents($this->testDir . '/composer.json')); } public function testSaveComposerFileFailure() { $packageName = 'six-shop/test-extension'; $content = '{"name": "six-shop/test-extension"}'; $invalidDir = '/invalid/directory/path'; $this->io->expects($this->once()) ->method('error') ->with($this->stringContains('无法创建目录')); $result = $this->composerGenerator->saveComposerFile($packageName, $content, $invalidDir, $this->io); $this->assertFalse($result); } public function testCreateComposerJson() { $packageName = 'six-shop/test-extension'; $namespace = 'SixShop\\TestExtension\\'; $id = 'six-shop-test-extension'; $description = 'A test extension package'; $this->io->expects($this->once()) ->method('section') ->with('生成的 composer.json 内容:'); $this->io->expects($this->once()) ->method('text') ->with($this->isType('string')); $this->io->expects($this->once()) ->method('confirm') ->with('是否将内容保存到 composer.json 文件?', true) ->willReturn(true); $this->io->expects($this->once()) ->method('success') ->with($this->stringContains('composer.json 文件已成功生成')); $result = $this->composerGenerator->createComposerJson( $packageName, $namespace, $id, $description, $this->testDir, $this->io ); $this->assertTrue($result); $this->assertFileExists($this->testDir . '/composer.json'); } public function testCreateComposerJsonWithUserDecline() { $packageName = 'six-shop/test-extension'; $namespace = 'SixShop\\TestExtension\\'; $id = 'six-shop-test-extension'; $description = 'A test extension package'; $this->io->expects($this->once()) ->method('confirm') ->with('是否将内容保存到 composer.json 文件?', true) ->willReturn(false); $result = $this->composerGenerator->createComposerJson( $packageName, $namespace, $id, $description, $this->testDir, $this->io ); $this->assertTrue($result); $this->assertFileDoesNotExist($this->testDir . '/composer.json'); } public function testGenerateContentWithDifferentNamespaces() { $testCases = [ ['SixShop\\Hello\\', 'six-shop/hello'], ['MyCompany\\Extensions\\TestExt\\', 'mycompany/test-extension'], ['SingleNamespace\\', 'vendor/package'] ]; foreach ($testCases as [$namespace, $packageName]) { $content = $this->composerGenerator->generateContent($packageName, $namespace, 'test-id', 'Test description'); $jsonData = json_decode($content, true); $this->assertArrayHasKey($namespace, $jsonData['autoload']['psr-4']); $this->assertEquals('src', $jsonData['autoload']['psr-4'][$namespace]); } } public function testJsonStructureCompliance() { $content = $this->composerGenerator->generateContent( 'six-shop/test-extension', 'SixShop\\TestExtension\\', 'test-extension-id', 'Test description' ); $jsonData = json_decode($content, true); // Test required composer.json fields $this->assertArrayHasKey('name', $jsonData); $this->assertArrayHasKey('description', $jsonData); $this->assertArrayHasKey('type', $jsonData); $this->assertArrayHasKey('require', $jsonData); $this->assertArrayHasKey('autoload', $jsonData); $this->assertArrayHasKey('extra', $jsonData); // Test type field $this->assertEquals('sixshop-extension', $jsonData['type']); // Test minimum requirements $this->assertArrayHasKey('php', $jsonData['require']); $this->assertEquals('>=8.3', $jsonData['require']['php']); } public function testExtensionIdFormat() { $testCases = [ 'six-shop/hello' => 'six-shop-hello', 'vendor/my-extension' => 'vendor-my-extension', 'company/test_pkg' => 'company-test_pkg' ]; foreach ($testCases as $packageName => $expectedId) { $content = $this->composerGenerator->generateContent( $packageName, 'Test\\Namespace\\', $expectedId, 'Test description' ); $jsonData = json_decode($content, true); $this->assertEquals($expectedId, $jsonData['extra']['sixshop']['id']); } } public function testGenerateContentErrorHandling() { // Test that the method works with valid parameters // Since the template exists, this should not throw an exception $content = $this->composerGenerator->generateContent( 'test/package', 'Test\\Namespace\\', 'test-id', 'Test description' ); $this->assertIsString($content); $this->assertNotEmpty($content); } public function testSaveComposerFileDirectoryCreation() { $nestedDir = $this->testDir . '/nested/deep/directory'; $packageName = 'six-shop/test-extension'; $content = '{"name": "six-shop/test-extension"}'; $this->io->expects($this->once()) ->method('success'); $result = $this->composerGenerator->saveComposerFile($packageName, $content, $nestedDir, $this->io); $this->assertTrue($result); $this->assertDirectoryExists($nestedDir); $this->assertFileExists($nestedDir . '/composer.json'); } public function testCompletePackageJsonStructure() { $content = $this->composerGenerator->generateContent( 'six-shop/advanced-extension', 'SixShop\\AdvancedExtension\\', 'six-shop-advanced-extension', 'An advanced SixShop extension with comprehensive features' ); $jsonData = json_decode($content, true); // Verify complete structure $expectedStructure = [ 'name' => 'six-shop/advanced-extension', 'description' => 'An advanced SixShop extension with comprehensive features', 'type' => 'sixshop-extension', 'require' => [ 'php' => '>=8.3', 'six-shop/core' => '>=0.6 <1.0' ], 'autoload' => [ 'psr-4' => [ 'SixShop\\AdvancedExtension\\' => 'src' ] ], 'extra' => [ 'sixshop' => [ 'id' => 'six-shop-advanced-extension', 'class' => 'SixShop\\AdvancedExtension\\Extension' ] ] ]; $this->assertEquals($expectedStructure['name'], $jsonData['name']); $this->assertEquals($expectedStructure['description'], $jsonData['description']); $this->assertEquals($expectedStructure['type'], $jsonData['type']); $this->assertEquals($expectedStructure['require'], $jsonData['require']); $this->assertEquals($expectedStructure['autoload'], $jsonData['autoload']); $this->assertEquals($expectedStructure['extra'], $jsonData['extra']); } }