Files
archived-ai-mate/tests/Command/InitCommandTest.php

199 lines
7.2 KiB
PHP

<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\AI\Mate\Tests\Command;
use PHPUnit\Framework\TestCase;
use Psr\Log\NullLogger;
use Symfony\AI\Mate\Agent\AgentInstructionsAggregator;
use Symfony\AI\Mate\Agent\AgentInstructionsMaterializer;
use Symfony\AI\Mate\Command\InitCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Tester\CommandTester;
/**
* @author Johannes Wachter <johannes@sulu.io>
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
*/
final class InitCommandTest extends TestCase
{
private string $tempDir;
protected function setUp(): void
{
$this->tempDir = sys_get_temp_dir().'/mate-test-'.uniqid();
mkdir($this->tempDir, 0755, true);
}
protected function tearDown(): void
{
$this->removeDirectory($this->tempDir);
}
public function testCreatesDirectoryAndConfigFile()
{
$command = $this->createCommand();
$tester = new CommandTester($command);
$tester->execute([]);
$this->assertSame(Command::SUCCESS, $tester->getStatusCode());
$this->assertDirectoryExists($this->tempDir.'/mate');
$this->assertFileExists($this->tempDir.'/mate/extensions.php');
$this->assertFileExists($this->tempDir.'/mate/config.php');
$this->assertFileExists($this->tempDir.'/mate/.env');
$this->assertFileExists($this->tempDir.'/mate/AGENT_INSTRUCTIONS.md');
$this->assertFileExists($this->tempDir.'/mcp.json');
$this->assertFileExists($this->tempDir.'/bin/codex');
$this->assertFileExists($this->tempDir.'/bin/codex.bat');
$this->assertTrue(is_executable($this->tempDir.'/bin/codex'));
$this->assertTrue(is_link($this->tempDir.'/.mcp.json'));
$this->assertSame('mcp.json', readlink($this->tempDir.'/.mcp.json'));
$this->assertFileExists($this->tempDir.'/AGENTS.md');
$content = file_get_contents($this->tempDir.'/mate/extensions.php');
$this->assertIsString($content);
$this->assertStringContainsString('mate discover', $content);
$this->assertStringContainsString('enabled', $content);
}
public function testDisplaysSuccessMessage()
{
$command = $this->createCommand();
$tester = new CommandTester($command);
$tester->execute([]);
$output = $tester->getDisplay();
$this->assertStringContainsString('AI Mate Initialization', $output);
$this->assertStringContainsString('extensions.php', $output);
$this->assertStringContainsString('config.php', $output);
$this->assertStringContainsString('vendor/bin/mate discover', $output);
$this->assertStringContainsString('./bin/codex', $output);
$this->assertStringContainsString('Summary', $output);
$this->assertStringContainsString('Created', $output);
}
public function testDoesNotOverwriteExistingFileWithoutConfirmation()
{
$command = $this->createCommand();
$tester = new CommandTester($command);
// Create existing file
mkdir($this->tempDir.'/mate', 0755, true);
file_put_contents($this->tempDir.'/mate/extensions.php', '<?php return ["test" => "value"];');
// Execute with 'no' response (twice for both files)
$tester->setInputs(['no', 'no']);
$tester->execute([]);
// File should still contain original content
$content = file_get_contents($this->tempDir.'/mate/extensions.php');
$this->assertIsString($content);
$this->assertStringContainsString('test', $content);
$this->assertStringContainsString('value', $content);
}
public function testOverwritesExistingFileWithConfirmation()
{
$command = $this->createCommand();
$tester = new CommandTester($command);
// Create existing file
mkdir($this->tempDir.'/mate', 0755, true);
file_put_contents($this->tempDir.'/mate/extensions.php', '<?php return ["test" => "value"];');
// Execute with 'yes' response (twice for both files)
$tester->setInputs(['yes', 'yes']);
$tester->execute([]);
// File should be overwritten with template content
$content = file_get_contents($this->tempDir.'/mate/extensions.php');
$this->assertIsString($content);
$this->assertStringNotContainsString('test', $content);
$this->assertStringContainsString('mate discover', $content);
$this->assertStringContainsString('enabled', $content);
}
public function testCreatesDirectoryIfNotExists()
{
$command = $this->createCommand();
$tester = new CommandTester($command);
// Ensure mate directory doesn't exist
$this->assertDirectoryDoesNotExist($this->tempDir.'/mate');
$tester->execute([]);
// Directory should be created
$this->assertDirectoryExists($this->tempDir.'/mate');
$this->assertFileExists($this->tempDir.'/mate/extensions.php');
$this->assertFileExists($this->tempDir.'/mate/config.php');
}
public function testSetsExtensionFalseByDefault()
{
// Create composer.json without ai-mate config
file_put_contents($this->tempDir.'/composer.json', json_encode(['name' => 'test/package']));
$command = $this->createCommand();
$tester = new CommandTester($command);
$tester->execute([]);
$this->assertSame(Command::SUCCESS, $tester->getStatusCode());
// Verify composer.json has extension: false by default
$composerContent = file_get_contents($this->tempDir.'/composer.json');
$this->assertIsString($composerContent);
$composerJson = json_decode($composerContent, true);
$this->assertIsArray($composerJson);
$this->assertArrayHasKey('extra', $composerJson);
$this->assertArrayHasKey('ai-mate', $composerJson['extra']);
$this->assertArrayHasKey('extension', $composerJson['extra']['ai-mate']);
$this->assertFalse($composerJson['extra']['ai-mate']['extension']);
// Verify note is displayed
$output = $tester->getDisplay();
$this->assertStringContainsString('extension: false', $output);
$this->assertStringContainsString('By default', $output);
}
private function createCommand(): InitCommand
{
$logger = new NullLogger();
$aggregator = new AgentInstructionsAggregator($this->tempDir, [], $logger);
$materializer = new AgentInstructionsMaterializer($this->tempDir, $aggregator, $logger);
return new InitCommand($this->tempDir, $materializer);
}
private function removeDirectory(string $dir): void
{
if (!is_dir($dir)) {
return;
}
$files = array_diff(scandir($dir), ['.', '..']);
foreach ($files as $file) {
$path = $dir.'/'.$file;
if (is_link($path)) {
unlink($path);
} elseif (is_dir($path)) {
$this->removeDirectory($path);
} else {
unlink($path);
}
}
rmdir($dir);
}
}