Skip to content

Commit a1e416a

Browse files
Add comprehensive tests for git context feature
- Unit tests for GitCliAdapter (getCurrentBranch, getRecentCommits, getBranches) - Integration tests for WorkspaceGitService::getGitInfo - Application tests for WorkspaceMgmtFacade::getGitInfo - Tests cover commit bodies, multiline messages, branch switching, and limits Co-authored-by: Manuel Kießling <manuel@kiessling.net>
1 parent 41801d2 commit a1e416a

File tree

3 files changed

+671
-0
lines changed

3 files changed

+671
-0
lines changed
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Tests\Integration\WorkspaceMgmt;
6+
7+
use App\WorkspaceMgmt\Domain\Entity\Workspace;
8+
use App\WorkspaceMgmt\Domain\Service\WorkspaceGitService;
9+
use App\WorkspaceMgmt\Facade\Enum\WorkspaceStatus;
10+
use Doctrine\ORM\EntityManagerInterface;
11+
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
12+
use Symfony\Component\Process\Process;
13+
14+
use function is_dir;
15+
use function sys_get_temp_dir;
16+
use function uniqid;
17+
18+
/**
19+
* Integration test for WorkspaceGitService::getGitInfo.
20+
* Tests the full integration with GitCliAdapter using a real git repository.
21+
*/
22+
final class WorkspaceGitServiceTest extends KernelTestCase
23+
{
24+
private string $testRepoPath;
25+
private WorkspaceGitService $gitService;
26+
private EntityManagerInterface $entityManager;
27+
private string $workspaceRoot;
28+
29+
protected function setUp(): void
30+
{
31+
self::bootKernel();
32+
$container = self::getContainer();
33+
34+
/** @var WorkspaceGitService $gitService */
35+
$gitService = $container->get(WorkspaceGitService::class);
36+
$this->gitService = $gitService;
37+
38+
/** @var EntityManagerInterface $entityManager */
39+
$entityManager = $container->get(EntityManagerInterface::class);
40+
$this->entityManager = $entityManager;
41+
42+
$this->workspaceRoot = $container->getParameter('workspace_mgmt.workspace_root');
43+
44+
// Create a test git repository
45+
$this->testRepoPath = sys_get_temp_dir() . '/workspace-git-test-' . uniqid();
46+
mkdir($this->testRepoPath, 0777, true);
47+
48+
$this->runGitCommand('init');
49+
$this->runGitCommand('config user.name "Test User"');
50+
$this->runGitCommand('config user.email "test@example.com"');
51+
52+
// Create some commits with bodies
53+
file_put_contents($this->testRepoPath . '/file1.txt', 'Content 1');
54+
$this->runGitCommand('add .');
55+
$this->runGitCommand('commit -m "Initial commit" -m "Set up the project structure"');
56+
57+
file_put_contents($this->testRepoPath . '/file2.txt', 'Content 2');
58+
$this->runGitCommand('add .');
59+
$this->runGitCommand('commit -m "Add feature" -m "Implemented the main feature" -m "" -m "Related to issue #123"');
60+
61+
// Create a feature branch
62+
$this->runGitCommand('checkout -b feature/new-feature');
63+
file_put_contents($this->testRepoPath . '/file3.txt', 'Content 3');
64+
$this->runGitCommand('add .');
65+
$this->runGitCommand('commit -m "Feature work"');
66+
67+
// Go back to main
68+
$this->runGitCommand('checkout main');
69+
}
70+
71+
protected function tearDown(): void
72+
{
73+
parent::tearDown();
74+
75+
if (is_dir($this->testRepoPath)) {
76+
$this->removeDirectory($this->testRepoPath);
77+
}
78+
}
79+
80+
public function testGetGitInfoReturnsCompleteInformation(): void
81+
{
82+
// Arrange: Create a workspace pointing to our test repo
83+
$workspace = $this->createTestWorkspace();
84+
85+
// Act: Get git info
86+
$gitInfo = $this->gitService->getGitInfo($workspace, 5);
87+
88+
// Assert: Current branch
89+
self::assertSame('main', $gitInfo->currentBranch);
90+
91+
// Assert: Commits
92+
self::assertCount(2, $gitInfo->recentCommits);
93+
94+
$firstCommit = $gitInfo->recentCommits[0];
95+
self::assertSame('Add feature', $firstCommit->message);
96+
self::assertStringContainsString('Implemented the main feature', $firstCommit->body);
97+
self::assertStringContainsString('Related to issue #123', $firstCommit->body);
98+
self::assertNotEmpty($firstCommit->hash);
99+
self::assertInstanceOf(\DateTimeImmutable::class, $firstCommit->committedAt);
100+
101+
$secondCommit = $gitInfo->recentCommits[1];
102+
self::assertSame('Initial commit', $secondCommit->message);
103+
self::assertStringContainsString('Set up the project structure', $secondCommit->body);
104+
105+
// Assert: Branches
106+
self::assertCount(2, $gitInfo->localBranches);
107+
self::assertContains('main', $gitInfo->localBranches);
108+
self::assertContains('feature/new-feature', $gitInfo->localBranches);
109+
}
110+
111+
public function testGetGitInfoOnFeatureBranch(): void
112+
{
113+
// Arrange: Switch to feature branch
114+
$this->runGitCommand('checkout feature/new-feature');
115+
$workspace = $this->createTestWorkspace();
116+
117+
// Act
118+
$gitInfo = $this->gitService->getGitInfo($workspace, 10);
119+
120+
// Assert
121+
self::assertSame('feature/new-feature', $gitInfo->currentBranch);
122+
self::assertCount(3, $gitInfo->recentCommits);
123+
self::assertSame('Feature work', $gitInfo->recentCommits[0]->message);
124+
}
125+
126+
public function testGetGitInfoWithLimitedCommits(): void
127+
{
128+
// Arrange
129+
$workspace = $this->createTestWorkspace();
130+
131+
// Act: Request only 1 commit
132+
$gitInfo = $this->gitService->getGitInfo($workspace, 1);
133+
134+
// Assert
135+
self::assertCount(1, $gitInfo->recentCommits);
136+
self::assertSame('Add feature', $gitInfo->recentCommits[0]->message);
137+
}
138+
139+
private function createTestWorkspace(): Workspace
140+
{
141+
$workspace = new Workspace('test-project-' . uniqid());
142+
$workspace->setStatus(WorkspaceStatus::AVAILABLE_FOR_CONVERSATION);
143+
$workspace->setBranchName('main');
144+
145+
$this->entityManager->persist($workspace);
146+
$this->entityManager->flush();
147+
148+
$workspaceId = $workspace->getId();
149+
self::assertNotNull($workspaceId);
150+
151+
// Move test repo to the workspace root location
152+
$targetPath = $this->workspaceRoot . '/' . $workspaceId;
153+
if (is_dir($targetPath)) {
154+
$this->removeDirectory($targetPath);
155+
}
156+
rename($this->testRepoPath, $targetPath);
157+
$this->testRepoPath = $targetPath;
158+
159+
return $workspace;
160+
}
161+
162+
private function runGitCommand(string $command): void
163+
{
164+
$process = Process::fromShellCommandline('git ' . $command);
165+
$process->setWorkingDirectory($this->testRepoPath);
166+
$process->setTimeout(10);
167+
$process->mustRun();
168+
}
169+
170+
private function removeDirectory(string $path): void
171+
{
172+
if (!is_dir($path)) {
173+
return;
174+
}
175+
176+
$items = scandir($path);
177+
if ($items === false) {
178+
return;
179+
}
180+
181+
foreach ($items as $item) {
182+
if ($item === '.' || $item === '..') {
183+
continue;
184+
}
185+
186+
$itemPath = $path . '/' . $item;
187+
if (is_dir($itemPath)) {
188+
$this->removeDirectory($itemPath);
189+
} else {
190+
unlink($itemPath);
191+
}
192+
}
193+
194+
rmdir($path);
195+
}
196+
}

0 commit comments

Comments
 (0)