From 8b9dbda0126d49828fedf650601a8f69cc6f6f2d Mon Sep 17 00:00:00 2001 From: Jayesh Somani Date: Fri, 22 May 2026 17:59:51 +0530 Subject: [PATCH] inital testing --- docker-compose.yml | 6 +- tests/VCS/Adapter/ForgejoTest.php | 2 +- tests/VCS/Adapter/GitHubTest.php | 2 +- tests/VCS/Adapter/GitLabTest.php | 816 +-------------------------- tests/VCS/Adapter/GiteaTest.php | 862 +--------------------------- tests/VCS/Adapter/GogsTest.php | 2 +- tests/VCS/Base.php | 900 ++++++++++++++++++++++++++---- 7 files changed, 810 insertions(+), 1780 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 3c0afa8f..f579d26b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -82,7 +82,7 @@ services: required: false entrypoint: /bin/sh environment: - - GITEA_ADMIN_USERNAME=${GITEA_ADMIN_USERNAME:-utopia} + - GITEA_ADMIN_USERNAME=${GITEA_ADMIN_USERNAME:-root} - GITEA_ADMIN_PASSWORD=${GITEA_ADMIN_PASSWORD:-password} - GITEA_ADMIN_EMAIL=${GITEA_ADMIN_EMAIL:-utopia@example.com} command: > @@ -137,7 +137,7 @@ services: required: false entrypoint: /bin/sh environment: - - FORGEJO_ADMIN_USERNAME=${FORGEJO_ADMIN_USERNAME:-utopia} + - FORGEJO_ADMIN_USERNAME=${FORGEJO_ADMIN_USERNAME:-root} - FORGEJO_ADMIN_PASSWORD=${FORGEJO_ADMIN_PASSWORD:-password} - FORGEJO_ADMIN_EMAIL=${FORGEJO_ADMIN_EMAIL:-utopia@example.com} command: > @@ -178,7 +178,7 @@ services: required: false entrypoint: /bin/sh environment: - - GOGS_ADMIN_USERNAME=${GOGS_ADMIN_USERNAME:-utopia} + - GOGS_ADMIN_USERNAME=${GOGS_ADMIN_USERNAME:-root} - GOGS_ADMIN_PASSWORD=${GOGS_ADMIN_PASSWORD:-password} - GOGS_ADMIN_EMAIL=${GOGS_ADMIN_EMAIL:-utopia@example.com} command: diff --git a/tests/VCS/Adapter/ForgejoTest.php b/tests/VCS/Adapter/ForgejoTest.php index ad1ec502..8615d985 100644 --- a/tests/VCS/Adapter/ForgejoTest.php +++ b/tests/VCS/Adapter/ForgejoTest.php @@ -23,7 +23,7 @@ protected function createVCSAdapter(): Git return new Forgejo(new Cache(new None())); } - public function setUp(): void + public function setupAdapter(): void { if (empty(static::$accessToken)) { $this->setupForgejo(); diff --git a/tests/VCS/Adapter/GitHubTest.php b/tests/VCS/Adapter/GitHubTest.php index f929b3a5..14f39080 100644 --- a/tests/VCS/Adapter/GitHubTest.php +++ b/tests/VCS/Adapter/GitHubTest.php @@ -22,7 +22,7 @@ protected function createVCSAdapter(): Git return new GitHub(new Cache(new None())); } - public function setUp(): void + public function setupAdapter(): void { $privateKey = str_replace('\\n', "\n", System::getEnv('TESTS_GITHUB_PRIVATE_KEY') ?? ''); $appId = System::getEnv('TESTS_GITHUB_APP_IDENTIFIER') ?? ''; diff --git a/tests/VCS/Adapter/GitLabTest.php b/tests/VCS/Adapter/GitLabTest.php index 84e5918f..1ab02e5a 100644 --- a/tests/VCS/Adapter/GitLabTest.php +++ b/tests/VCS/Adapter/GitLabTest.php @@ -20,7 +20,7 @@ protected function createVCSAdapter(): Git return new GitLab(new Cache(new None())); } - public function setUp(): void + public function setupAdapter(): void { if (empty(static::$accessToken)) { $this->setupGitLab(); @@ -63,112 +63,6 @@ protected function setupGitLab(): void } - public function testCreateRepository(): void - { - $repositoryName = 'test-create-repository-' . \uniqid(); - - $result = $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->assertIsArray($result); - $this->assertArrayHasKey('name', $result); - $this->assertSame($repositoryName, $result['name']); - $this->assertFalse($result['visibility'] === 'private'); - $this->assertArrayHasKey('pushed_at', $result); - $this->assertNotFalse(\strtotime($result['pushed_at'])); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testGetRepository(): void - { - $repositoryName = 'test-get-repository-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $result = $this->vcsAdapter->getRepository(static::$owner, $repositoryName); - - $this->assertIsArray($result); - $this->assertSame($repositoryName, $result['name']); - $this->assertArrayHasKey('pushed_at', $result); - $this->assertNotFalse(\strtotime($result['pushed_at'])); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testListRepositoryContentsNonExistingPath(): void - { - $repositoryName = 'test-list-repository-contents-invalid-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - - try { - $contents = $this->vcsAdapter->listRepositoryContents(static::$owner, $repositoryName, 'non-existing-path'); - - $this->assertIsArray($contents); - $this->assertEmpty($contents); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testDeleteRepository(): void - { - $repositoryName = 'test-delete-repository-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - $result = $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - - $this->assertTrue($result); - } - - public function testGetDeletedRepositoryFails(): void - { - $repositoryName = 'non-existing-repository-' . \uniqid(); - - $this->expectException(\Exception::class); - $this->vcsAdapter->getRepository(static::$owner, $repositoryName); - } - - public function testGetPullRequestFromBranch(): void - { - $repositoryName = 'test-get-pr-from-branch-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'my-feature', static::$defaultBranch); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'feature.txt', 'content', 'Add feature', 'my-feature'); - - $this->vcsAdapter->createPullRequest( - static::$owner, - $repositoryName, - 'Feature MR', - 'my-feature', - static::$defaultBranch - ); - - $result = $this->vcsAdapter->getPullRequestFromBranch(static::$owner, $repositoryName, 'my-feature'); - - $this->assertIsArray($result); - $this->assertNotEmpty($result); - $this->assertArrayHasKey('head', $result); - $this->assertSame('my-feature', $result['head']['ref'] ?? ''); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testGetOwnerName(): void - { - $result = $this->vcsAdapter->getOwnerName('', null); - - $this->assertIsString($result); - $this->assertNotEmpty($result); - } - public function testGetOwnerNameWithRepositoryId(): void { $repositoryName = 'test-get-owner-name-' . \uniqid(); @@ -230,138 +124,6 @@ public function testSearchRepositoriesWithSearch(): void } } - public function testCreateComment(): void - { - $repositoryName = 'test-create-comment-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'test-branch', static::$defaultBranch); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'test', 'Add test', 'test-branch'); - - $pr = $this->vcsAdapter->createPullRequest( - static::$owner, - $repositoryName, - 'Test PR', - 'test-branch', - static::$defaultBranch - ); - - $prNumber = $pr['iid'] ?? 0; - $this->assertGreaterThan(0, $prNumber); - - $commentId = $this->vcsAdapter->createComment(static::$owner, $repositoryName, $prNumber, 'Test comment'); - - $this->assertNotEmpty($commentId); - $this->assertIsString($commentId); - - $retrieved = $this->vcsAdapter->getComment(static::$owner, $repositoryName, $commentId); - $this->assertSame('Test comment', $retrieved); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testUpdateComment(): void - { - $repositoryName = 'test-update-comment-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'test-branch', static::$defaultBranch); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'test', 'Add test', 'test-branch'); - - $pr = $this->vcsAdapter->createPullRequest( - static::$owner, - $repositoryName, - 'Test PR', - 'test-branch', - static::$defaultBranch - ); - - $prNumber = $pr['iid'] ?? 0; - $this->assertGreaterThan(0, $prNumber); - - $commentId = $this->vcsAdapter->createComment(static::$owner, $repositoryName, $prNumber, 'Original comment'); - - $updatedCommentId = $this->vcsAdapter->updateComment(static::$owner, $repositoryName, $commentId, 'Updated comment'); - - $this->assertSame($commentId, $updatedCommentId); - - $finalComment = $this->vcsAdapter->getComment(static::$owner, $repositoryName, $commentId); - $this->assertSame('Updated comment', $finalComment); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testGenerateCloneCommand(): void - { - $repositoryName = 'test-clone-command-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $directory = '/tmp/test-clone-' . \uniqid(); - - try { - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - - $command = $this->vcsAdapter->generateCloneCommand( - static::$owner, - $repositoryName, - static::$defaultBranch, - \Utopia\VCS\Adapter\Git::CLONE_TYPE_BRANCH, - $directory, - '/' - ); - - $this->assertIsString($command); - $this->assertStringContainsString('git init', $command); - $this->assertStringContainsString('git remote add origin', $command); - $this->assertStringContainsString('git config core.sparseCheckout true', $command); - $this->assertStringContainsString($repositoryName, $command); - - $output = []; - \exec($command . ' 2>&1', $output, $exitCode); - $this->assertSame(0, $exitCode, implode("\n", $output)); - $this->assertFileExists($directory . '/README.md'); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - if (\is_dir($directory)) { - \exec('rm -rf ' . escapeshellarg($directory)); - } - } - } - - public function testGenerateCloneCommandWithCommitHash(): void - { - $repositoryName = 'test-clone-commit-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - - $commit = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, static::$defaultBranch); - $commitHash = $commit['commitHash']; - - $directory = '/tmp/test-clone-commit-' . \uniqid(); - $command = $this->vcsAdapter->generateCloneCommand( - static::$owner, - $repositoryName, - $commitHash, - \Utopia\VCS\Adapter\Git::CLONE_TYPE_COMMIT, - $directory, - '/' - ); - - $this->assertIsString($command); - $this->assertStringContainsString('git fetch --depth=1', $command); - $this->assertStringContainsString($commitHash, $command); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - public function testGetCommitStatuses(): void { $repositoryName = 'test-get-commit-statuses-' . \uniqid(); @@ -398,39 +160,6 @@ public function testGetCommitStatuses(): void } } - - public function testUpdateCommitStatus(): void - { - $repositoryName = 'test-update-commit-status-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $commit = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, static::$defaultBranch); - $commitHash = $commit['commitHash']; - - $this->vcsAdapter->updateCommitStatus( - $repositoryName, - $commitHash, - static::$owner, - 'success', - 'Build passed', - 'https://example.com', - 'ci/build' - ); - - $statuses = $this->vcsAdapter->getCommitStatuses(static::$owner, $repositoryName, $commitHash); - - $this->assertIsArray($statuses); - $this->assertNotEmpty($statuses); - - $states = array_column($statuses, 'state'); - $this->assertContains('success', $states); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - public function testGetCommitStatusesEmptyForNewCommit(): void { $repositoryName = 'test-get-commit-statuses-empty-' . \uniqid(); @@ -481,90 +210,6 @@ public function testGenerateCloneCommandWithTag(): void } } - public function testGenerateCloneCommandWithInvalidRepository(): void - { - $directory = '/tmp/test-clone-invalid-' . \uniqid(); - - try { - $command = $this->vcsAdapter->generateCloneCommand( - static::$owner, - 'nonexistent-repo-' . \uniqid(), - static::$defaultBranch, - \Utopia\VCS\Adapter\Git::CLONE_TYPE_BRANCH, - $directory, - '/' - ); - - $output = []; - \exec($command . ' 2>&1', $output, $exitCode); - - $cloneFailed = ($exitCode !== 0) || !file_exists($directory . '/README.md'); - $this->assertTrue($cloneFailed, 'Clone should have failed for nonexistent repository'); - } finally { - if (\is_dir($directory)) { - \exec('rm -rf ' . escapeshellarg($directory)); - } - } - } - - public function testGetCommit(): void - { - $repositoryName = 'test-get-commit-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $customMessage = 'Test commit message'; - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test', $customMessage); - - $latestCommit = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, static::$defaultBranch); - $commitHash = $latestCommit['commitHash']; - - $result = $this->vcsAdapter->getCommit(static::$owner, $repositoryName, $commitHash); - - $this->assertIsArray($result); - $this->assertArrayHasKey('commitHash', $result); - $this->assertArrayHasKey('commitMessage', $result); - $this->assertArrayHasKey('commitAuthor', $result); - $this->assertArrayHasKey('commitUrl', $result); - $this->assertArrayHasKey('commitAuthorAvatar', $result); - $this->assertArrayHasKey('commitAuthorUrl', $result); - $this->assertSame($commitHash, $result['commitHash']); - $this->assertStringStartsWith($customMessage, $result['commitMessage']); - $this->assertNotEmpty($result['commitUrl']); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testGetLatestCommit(): void - { - $repositoryName = 'test-get-latest-commit-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $firstMessage = 'First commit'; - $secondMessage = 'Second commit'; - - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test', $firstMessage); - $commit1 = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, static::$defaultBranch); - - $this->assertIsArray($commit1); - $this->assertNotEmpty($commit1['commitHash']); - $this->assertStringStartsWith($firstMessage, $commit1['commitMessage']); - $this->assertNotEmpty($commit1['commitUrl']); - - $commit1Hash = $commit1['commitHash']; - - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'test', $secondMessage); - $commit2 = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, static::$defaultBranch); - - $this->assertStringStartsWith($secondMessage, $commit2['commitMessage']); - $this->assertNotSame($commit1Hash, $commit2['commitHash']); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - public function testGetCommitWithInvalidHash(): void { $repositoryName = 'test-get-commit-invalid-' . \uniqid(); @@ -578,20 +223,6 @@ public function testGetCommitWithInvalidHash(): void } } - public function testGetLatestCommitWithInvalidBranch(): void - { - $repositoryName = 'test-get-latest-commit-invalid-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - - try { - $this->expectException(\Exception::class); - $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, 'non-existing-branch'); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - public function testValidateWebhookEvent(): void { $secret = 'my-secret-token'; @@ -794,268 +425,6 @@ public function testCreateWebhook(): void } } - public function testGetRepositoryName(): void - { - $repositoryName = 'test-get-repository-name-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $repo = $this->vcsAdapter->getRepository(static::$owner, $repositoryName); - $repositoryId = (string) ($repo['id'] ?? ''); - - $result = $this->vcsAdapter->getRepositoryName($repositoryId); - - $this->assertIsString($result); - $this->assertSame($repositoryName, $result); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testGetRepositoryNameWithInvalidId(): void - { - $this->expectException(\Exception::class); - $this->vcsAdapter->getRepositoryName('99999999'); - } - - public function testGetComment(): void - { - $repositoryName = 'test-get-comment-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'test-branch', static::$defaultBranch); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'test', 'Add test', 'test-branch'); - - $pr = $this->vcsAdapter->createPullRequest( - static::$owner, - $repositoryName, - 'Test PR', - 'test-branch', - static::$defaultBranch - ); - - $prNumber = $pr['iid'] ?? 0; - $commentId = $this->vcsAdapter->createComment(static::$owner, $repositoryName, $prNumber, 'Test comment'); - - $result = $this->vcsAdapter->getComment(static::$owner, $repositoryName, $commentId); - - $this->assertIsString($result); - $this->assertSame('Test comment', $result); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testGetPullRequest(): void - { - $repositoryName = 'test-get-pull-request-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'feature-branch', static::$defaultBranch); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'feature.txt', 'feature content', 'Add feature', 'feature-branch'); - - $pr = $this->vcsAdapter->createPullRequest( - static::$owner, - $repositoryName, - 'Test MR', - 'feature-branch', - static::$defaultBranch, - 'Test MR description' - ); - - $prNumber = $pr['iid'] ?? 0; - $this->assertGreaterThan(0, $prNumber); - - $result = $this->vcsAdapter->getPullRequest(static::$owner, $repositoryName, $prNumber); - - $this->assertIsArray($result); - $this->assertArrayHasKey('number', $result); - $this->assertArrayHasKey('title', $result); - $this->assertArrayHasKey('state', $result); - $this->assertArrayHasKey('head', $result); - $this->assertArrayHasKey('base', $result); - $this->assertSame($prNumber, $result['number']); - $this->assertSame('Test MR', $result['title']); - $this->assertSame('opened', $result['state']); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testGetPullRequestFiles(): void - { - $repositoryName = 'test-get-pull-request-files-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'feature-branch', static::$defaultBranch); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'feature.txt', 'feature content', 'Add feature', 'feature-branch'); - - $pr = $this->vcsAdapter->createPullRequest( - static::$owner, - $repositoryName, - 'Test MR Files', - 'feature-branch', - static::$defaultBranch - ); - - $prNumber = $pr['iid'] ?? 0; - $this->assertGreaterThan(0, $prNumber); - - $result = []; - $this->assertEventually(function () use (&$result, $repositoryName, $prNumber) { - $result = $this->vcsAdapter->getPullRequestFiles(static::$owner, $repositoryName, $prNumber); - $this->assertNotEmpty($result); - }, 15000, 1000); - - $this->assertIsArray($result); - $filenames = array_column($result, 'filename'); - $this->assertContains('feature.txt', $filenames); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testGetPullRequestWithInvalidNumber(): void - { - $repositoryName = 'test-get-pull-request-invalid-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->expectException(\Exception::class); - $this->vcsAdapter->getPullRequest(static::$owner, $repositoryName, 99999); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testGetRepositoryTree(): void - { - $repositoryName = 'test-get-repository-tree-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'src/main.php', 'vcsAdapter->createFile(static::$owner, $repositoryName, 'src/lib.php', 'vcsAdapter->getRepositoryTree(static::$owner, $repositoryName, static::$defaultBranch, false); - - $this->assertIsArray($tree); - $this->assertContains('README.md', $tree); - $this->assertContains('src', $tree); - $this->assertCount(2, $tree); - - // Recursive — all files - $treeRecursive = $this->vcsAdapter->getRepositoryTree(static::$owner, $repositoryName, static::$defaultBranch, true); - - $this->assertIsArray($treeRecursive); - $this->assertContains('README.md', $treeRecursive); - $this->assertContains('src/main.php', $treeRecursive); - $this->assertContains('src/lib.php', $treeRecursive); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testGetRepositoryTreeWithInvalidBranch(): void - { - $repositoryName = 'test-get-repository-tree-invalid-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - - try { - $tree = $this->vcsAdapter->getRepositoryTree(static::$owner, $repositoryName, 'non-existing-branch', false); - - $this->assertIsArray($tree); - $this->assertEmpty($tree); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testGetRepositoryContent(): void - { - $repositoryName = 'test-get-repository-content-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $fileContent = '# Hello World'; - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', $fileContent); - - $result = $this->vcsAdapter->getRepositoryContent(static::$owner, $repositoryName, 'README.md'); - - $this->assertIsArray($result); - $this->assertArrayHasKey('content', $result); - $this->assertArrayHasKey('sha', $result); - $this->assertArrayHasKey('size', $result); - $this->assertSame($fileContent, $result['content']); - $this->assertGreaterThan(0, $result['size']); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testGetRepositoryContentWithRef(): void - { - $repositoryName = 'test-get-repository-content-ref-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'main branch content'); - - $result = $this->vcsAdapter->getRepositoryContent(static::$owner, $repositoryName, 'test.txt', static::$defaultBranch); - - $this->assertIsArray($result); - $this->assertSame('main branch content', $result['content']); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testGetRepositoryContentFileNotFound(): void - { - $repositoryName = 'test-get-repository-content-not-found-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - - try { - $this->expectException(\Utopia\VCS\Exception\FileNotFound::class); - $this->vcsAdapter->getRepositoryContent(static::$owner, $repositoryName, 'non-existing.txt'); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testListBranches(): void - { - $repositoryName = 'test-list-branches-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'feature-branch', static::$defaultBranch); - $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'another-branch', static::$defaultBranch); - - $result = $this->vcsAdapter->listBranches(static::$owner, $repositoryName); - - $this->assertIsArray($result); - $this->assertNotEmpty($result); - - $this->assertContains(static::$defaultBranch, $result); - $this->assertContains('feature-branch', $result); - $this->assertContains('another-branch', $result); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - public function testListBranchesEmptyRepo(): void { $repositoryName = 'test-list-branches-empty-' . \uniqid(); @@ -1072,189 +441,6 @@ public function testListBranchesEmptyRepo(): void } } - public function testListRepositoryLanguages(): void - { - $repositoryName = 'test-list-repository-languages-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'main.php', 'vcsAdapter->createFile(static::$owner, $repositoryName, 'script.js', 'console.log("test");'); - - $languages = []; - $this->assertEventually(function () use (&$languages, $repositoryName) { - $languages = $this->vcsAdapter->listRepositoryLanguages(static::$owner, $repositoryName); - $this->assertNotEmpty($languages); - }, 30000, 2000); - - $this->assertIsArray($languages); - $this->assertNotEmpty($languages); - $this->assertContains('PHP', $languages); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testListRepositoryLanguagesEmptyRepo(): void - { - $repositoryName = 'test-list-repository-languages-empty-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $languages = $this->vcsAdapter->listRepositoryLanguages(static::$owner, $repositoryName); - - $this->assertIsArray($languages); - $this->assertEmpty($languages); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testListRepositoryContents(): void - { - $repositoryName = 'test-list-repository-contents-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'file1.txt', 'content1'); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'src/main.php', 'vcsAdapter->listRepositoryContents(static::$owner, $repositoryName); - - $this->assertIsArray($contents); - $this->assertCount(3, $contents); - - $names = array_column($contents, 'name'); - $this->assertContains('README.md', $names); - $this->assertContains('file1.txt', $names); - $this->assertContains('src', $names); - - foreach ($contents as $item) { - $this->assertArrayHasKey('name', $item); - $this->assertArrayHasKey('type', $item); - $this->assertArrayHasKey('size', $item); - } - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testGetUser(): void - { - $result = $this->vcsAdapter->getUser('root'); - - $this->assertIsArray($result); - $this->assertArrayHasKey('id', $result); - $this->assertArrayHasKey('username', $result); - } - - public function testGetUserWithInvalidUsername(): void - { - $this->expectException(\Exception::class); - $this->vcsAdapter->getUser('non-existent-user-' . \uniqid()); - } - - public function testCreatePrivateRepository(): void - { - $repositoryName = 'test-create-private-repository-' . \uniqid(); - - $result = $this->vcsAdapter->createRepository(static::$owner, $repositoryName, true); - - try { - $this->assertIsArray($result); - $this->assertSame('private', $result['visibility']); - - $fetched = $this->vcsAdapter->getRepository(static::$owner, $repositoryName); - $this->assertSame('private', $fetched['visibility']); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testGetRepositoryWithNonExistingOwner(): void - { - $repositoryName = 'test-non-existing-owner-' . \uniqid(); - - $this->expectException(\Exception::class); - $this->vcsAdapter->getRepository('non-existing-owner-' . \uniqid(), $repositoryName); - } - - public function testCreateRepositoryWithInvalidName(): void - { - $repositoryName = 'invalid name with spaces'; - - try { - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->fail('Expected exception for invalid repository name'); - } catch (\Exception $e) { - $this->assertTrue(true); - } - } - - public function testDeleteRepositoryTwiceFails(): void - { - $repositoryName = 'test-delete-repository-twice-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - - $this->expectException(\Exception::class); - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - - public function testDeleteNonExistingRepositoryFails(): void - { - $this->expectException(\Exception::class); - $this->vcsAdapter->deleteRepository(static::$owner, 'non-existing-repo-' . \uniqid()); - } - - public function testGetPullRequestFromBranchNoPR(): void - { - $repositoryName = 'test-get-pr-no-pr-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'lonely-branch', static::$defaultBranch); - - $result = $this->vcsAdapter->getPullRequestFromBranch(static::$owner, $repositoryName, 'lonely-branch'); - - $this->assertIsArray($result); - $this->assertEmpty($result); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testCreateCommentInvalidPR(): void - { - $repositoryName = 'test-comment-invalid-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - - try { - $this->expectException(\Exception::class); - $this->vcsAdapter->createComment(static::$owner, $repositoryName, 99999, 'Test comment'); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testGetCommentInvalidId(): void - { - $repositoryName = 'test-get-comment-invalid-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - - try { - $result = $this->vcsAdapter->getComment(static::$owner, $repositoryName, '99999999'); - $this->assertIsString($result); - $this->assertSame('', $result); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - public function testGetEventPushMatchesCheckoutSha(): void { $payload = json_encode([ diff --git a/tests/VCS/Adapter/GiteaTest.php b/tests/VCS/Adapter/GiteaTest.php index 507b0c51..2b6c55f2 100644 --- a/tests/VCS/Adapter/GiteaTest.php +++ b/tests/VCS/Adapter/GiteaTest.php @@ -24,7 +24,7 @@ protected function createVCSAdapter(): Git return new Gitea(new Cache(new None())); } - public function setUp(): void + public function setupAdapter(): void { if (empty(static::$accessToken)) { $this->setupGitea(); @@ -79,51 +79,6 @@ public function testListBranchesEmptyRepo(): void } } - public function testCreateRepository(): void - { - $owner = static::$owner; - $repositoryName = 'test-create-repository-' . \uniqid(); - - $result = $this->vcsAdapter->createRepository($owner, $repositoryName, false); - - $this->assertIsArray($result); - $this->assertArrayHasKey('name', $result); - $this->assertSame($repositoryName, $result['name']); - $this->assertArrayHasKey('owner', $result); - $this->assertSame($owner, $result['owner']['login']); - $this->assertFalse($result['private']); - $this->assertArrayHasKey('pushed_at', $result); - $this->assertNotFalse(\strtotime($result['pushed_at'])); - - $this->assertTrue($this->vcsAdapter->deleteRepository(static::$owner, $repositoryName)); - } - - public function testGetDeletedRepositoryFails(): void - { - $repositoryName = 'test-get-deleted-repository-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - - $this->expectException(\Exception::class); - $this->vcsAdapter->getRepository(static::$owner, $repositoryName); - } - - public function testCreatePrivateRepository(): void - { - $repositoryName = 'test-create-private-repository-' . \uniqid(); - - $result = $this->vcsAdapter->createRepository(static::$owner, $repositoryName, true); - - $this->assertIsArray($result); - $this->assertTrue($result['private']); - - // Verify with getRepository - $fetched = $this->vcsAdapter->getRepository(static::$owner, $repositoryName); - $this->assertTrue($fetched['private']); - - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - public function testCommentWorkflow(): void { $repositoryName = 'test-comment-workflow-' . \uniqid(); @@ -166,66 +121,6 @@ public function testCommentWorkflow(): void } } - public function testGetComment(): void - { - $repositoryName = 'test-get-comment-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'test-branch', static::$defaultBranch); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'test', 'Add test', 'test-branch'); - - // Create PR - $pr = $this->vcsAdapter->createPullRequest( - static::$owner, - $repositoryName, - 'Test PR', - 'test-branch', - static::$defaultBranch - ); - - $prNumber = $pr['number'] ?? 0; - - // Create a comment - $commentId = $this->vcsAdapter->createComment(static::$owner, $repositoryName, $prNumber, 'Test comment'); - - // Test getComment - $result = $this->vcsAdapter->getComment(static::$owner, $repositoryName, $commentId); - - $this->assertIsString($result); - $this->assertSame('Test comment', $result); - - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - - public function testCreateCommentInvalidPR(): void - { - $repositoryName = 'test-comment-invalid-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - - try { - $this->expectException(\Exception::class); - $this->vcsAdapter->createComment(static::$owner, $repositoryName, 99999, 'Test comment'); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testGetCommentInvalidId(): void - { - $repositoryName = 'test-get-comment-invalid-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - - $result = $this->vcsAdapter->getComment(static::$owner, $repositoryName, '99999999'); - - $this->assertIsString($result); - $this->assertSame('', $result); - - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - public function testHasAccessToAllRepositories(): void { $this->assertTrue($this->vcsAdapter->hasAccessToAllRepositories()); @@ -248,21 +143,6 @@ public function testGetRepositoryTreeWithSlashInBranchName(): void $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } - public function testGetRepository(): void - { - $repositoryName = 'test-get-repository-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - $result = $this->vcsAdapter->getRepository(static::$owner, $repositoryName); - - $this->assertIsArray($result); - $this->assertSame($repositoryName, $result['name']); - $this->assertSame(static::$owner, $result['owner']['login']); - $this->assertArrayHasKey('pushed_at', $result); - $this->assertNotFalse(\strtotime($result['pushed_at'])); - $this->assertTrue($this->vcsAdapter->deleteRepository(static::$owner, $repositoryName)); - } - public function testGetRepositoryName(): void { $repositoryName = 'test-get-repository-name-' . \uniqid(); @@ -278,162 +158,6 @@ public function testGetRepositoryName(): void $this->assertTrue($this->vcsAdapter->deleteRepository(static::$owner, $repositoryName)); } - public function testGetRepositoryNameWithInvalidId(): void - { - try { - $this->vcsAdapter->getRepositoryName('999999999'); - $this->fail('Expected exception for non-existing repository ID'); - } catch (\Exception $e) { - $this->assertTrue(true); - } - } - - public function testCreateRepositoryWithInvalidName(): void - { - $repositoryName = 'invalid name with spaces'; - - try { - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->fail('Expected exception for invalid repository name'); - } catch (\Exception $e) { - $this->assertTrue(true); - } - } - - public function testGetRepositoryWithNonExistingOwner(): void - { - $repositoryName = 'test-non-existing-owner-' . \uniqid(); - - try { - $this->vcsAdapter->getRepository('non-existing-owner-' . \uniqid(), $repositoryName); - $this->fail('Expected exception for non-existing owner'); - } catch (\Exception $e) { - $this->assertTrue(true); - } - } - - public function testGetRepositoryTree(): void - { - $repositoryName = 'test-get-repository-tree-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - // Create files in repo - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test Repo'); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'src/main.php', 'vcsAdapter->createFile(static::$owner, $repositoryName, 'src/lib.php', 'vcsAdapter->getRepositoryTree(static::$owner, $repositoryName, static::$defaultBranch, false); - - $this->assertIsArray($tree); - $this->assertContains('README.md', $tree); - $this->assertContains('src', $tree); - $this->assertCount(2, $tree); // Only README.md and src folder at root - - // Test recursive (should show all files including nested) - $treeRecursive = $this->vcsAdapter->getRepositoryTree(static::$owner, $repositoryName, static::$defaultBranch, true); - - $this->assertIsArray($treeRecursive); - $this->assertContains('README.md', $treeRecursive); - $this->assertContains('src', $treeRecursive); - $this->assertContains('src/main.php', $treeRecursive); - $this->assertContains('src/lib.php', $treeRecursive); - $this->assertGreaterThanOrEqual(4, count($treeRecursive)); - - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - - public function testGetRepositoryTreeWithInvalidBranch(): void - { - $repositoryName = 'test-get-repository-tree-invalid-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - - $tree = $this->vcsAdapter->getRepositoryTree(static::$owner, $repositoryName, 'non-existing-branch', false); - - $this->assertIsArray($tree); - $this->assertEmpty($tree); - - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - - public function testGetRepositoryContent(): void - { - $repositoryName = 'test-get-repository-content-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - $fileContent = '# Hello World'; - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', $fileContent); - - $result = $this->vcsAdapter->getRepositoryContent(static::$owner, $repositoryName, 'README.md'); - - $this->assertIsArray($result); - $this->assertArrayHasKey('content', $result); - $this->assertArrayHasKey('sha', $result); - $this->assertArrayHasKey('size', $result); - $this->assertSame($fileContent, $result['content']); - $this->assertIsString($result['sha']); - $this->assertGreaterThan(0, $result['size']); - - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - - public function testGetRepositoryContentWithRef(): void - { - $repositoryName = 'test-get-repository-content-ref-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'main branch content'); - - $result = $this->vcsAdapter->getRepositoryContent(static::$owner, $repositoryName, 'test.txt', static::$defaultBranch); - - $this->assertIsArray($result); - $this->assertSame('main branch content', $result['content']); - - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - - public function testGetRepositoryContentFileNotFound(): void - { - $repositoryName = 'test-get-repository-content-not-found-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - - $this->expectException(\Utopia\VCS\Exception\FileNotFound::class); - $this->vcsAdapter->getRepositoryContent(static::$owner, $repositoryName, 'non-existing.txt'); - - } - - public function testListRepositoryContents(): void - { - $repositoryName = 'test-list-repository-contents-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'file1.txt', 'content1'); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'src/main.php', 'vcsAdapter->listRepositoryContents(static::$owner, $repositoryName); - - $this->assertIsArray($contents); - $this->assertCount(3, $contents); // README.md, file1.txt, src folder - - $names = array_column($contents, 'name'); - $this->assertContains('README.md', $names); - $this->assertContains('file1.txt', $names); - $this->assertContains('src', $names); - - // Verify types - foreach ($contents as $item) { - $this->assertArrayHasKey('name', $item); - $this->assertArrayHasKey('type', $item); - $this->assertArrayHasKey('size', $item); - } - - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - public function testListRepositoryContentsInSubdirectory(): void { $repositoryName = 'test-list-repository-contents-subdir-' . \uniqid(); @@ -454,158 +178,6 @@ public function testListRepositoryContentsInSubdirectory(): void $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } - public function testListRepositoryContentsNonExistingPath(): void - { - $repositoryName = 'test-list-repository-contents-invalid-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - - $contents = $this->vcsAdapter->listRepositoryContents(static::$owner, $repositoryName, 'non-existing-path'); - - $this->assertIsArray($contents); - $this->assertEmpty($contents); - - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - - public function testGetPullRequest(): void - { - $repositoryName = 'test-get-pull-request-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'feature-branch', static::$defaultBranch); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'feature.txt', 'feature content', 'Add feature', 'feature-branch'); - - $pr = $this->vcsAdapter->createPullRequest( - static::$owner, - $repositoryName, - 'Test PR', - 'feature-branch', - static::$defaultBranch, - 'Test PR description' - ); - - $prNumber = $pr['number'] ?? 0; - $this->assertGreaterThan(0, $prNumber); - - // Now test getPullRequest - $result = $this->vcsAdapter->getPullRequest(static::$owner, $repositoryName, $prNumber); - - $this->assertIsArray($result); - $this->assertArrayHasKey('number', $result); - $this->assertArrayHasKey('title', $result); - $this->assertArrayHasKey('state', $result); - $this->assertArrayHasKey('head', $result); - $this->assertArrayHasKey('base', $result); - - $this->assertSame($prNumber, $result['number']); - $this->assertSame('Test PR', $result['title']); - $this->assertSame('open', $result['state']); - - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - - public function testGetPullRequestFiles(): void - { - $repositoryName = 'test-get-pull-request-files-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'feature-branch', static::$defaultBranch); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'feature.txt', 'feature content', 'Add feature', 'feature-branch'); - - $pr = $this->vcsAdapter->createPullRequest( - static::$owner, - $repositoryName, - 'Test PR Files', - 'feature-branch', - static::$defaultBranch - ); - - $prNumber = $pr['number'] ?? 0; - $this->assertGreaterThan(0, $prNumber); - - $result = $this->vcsAdapter->getPullRequestFiles(static::$owner, $repositoryName, $prNumber); - - $this->assertIsArray($result); - $this->assertNotEmpty($result); - - $filenames = array_column($result, 'filename'); - $this->assertContains('feature.txt', $filenames); - - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - - public function testGetPullRequestWithInvalidNumber(): void - { - $repositoryName = 'test-get-pull-request-invalid-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - - try { - $this->expectException(\Exception::class); - $this->vcsAdapter->getPullRequest(static::$owner, $repositoryName, 99999); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - - } - - public function testGenerateCloneCommand(): void - { - $repositoryName = 'test-clone-command-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - - $command = $this->vcsAdapter->generateCloneCommand( - static::$owner, - $repositoryName, - static::$defaultBranch, - \Utopia\VCS\Adapter\Git::CLONE_TYPE_BRANCH, - '/tmp/test-clone-' . \uniqid(), - '/' - ); - - $this->assertIsString($command); - $this->assertStringContainsString('git init', $command); - $this->assertStringContainsString('git remote add origin', $command); - $this->assertStringContainsString('git config core.sparseCheckout true', $command); - $this->assertStringContainsString($repositoryName, $command); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testGenerateCloneCommandWithCommitHash(): void - { - $repositoryName = 'test-clone-commit-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - - $commit = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, static::$defaultBranch); - $commitHash = $commit['commitHash']; - - $command = $this->vcsAdapter->generateCloneCommand( - static::$owner, - $repositoryName, - $commitHash, - \Utopia\VCS\Adapter\Git::CLONE_TYPE_COMMIT, - '/tmp/test-clone-commit-' . \uniqid(), - '/' - ); - $this->assertIsString($command); - $this->assertStringContainsString('git fetch --depth=1', $command); - $this->assertStringContainsString($commitHash, $command); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - public function testGenerateCloneCommandWithTag(): void { $repositoryName = 'test-clone-tag-' . \uniqid(); @@ -643,114 +215,6 @@ public function testGenerateCloneCommandWithTag(): void } } - public function testGenerateCloneCommandWithInvalidRepository(): void - { - $directory = '/tmp/test-clone-invalid-' . \uniqid(); - - try { - $command = $this->vcsAdapter->generateCloneCommand( - 'nonexistent-owner-' . \uniqid(), - 'nonexistent-repo-' . \uniqid(), - static::$defaultBranch, - \Utopia\VCS\Adapter\Git::CLONE_TYPE_BRANCH, - $directory, - '/' - ); - - $output = []; - exec($command . ' 2>&1', $output, $exitCode); - - $cloneFailed = ($exitCode !== 0) || !file_exists($directory . '/README.md'); - - $this->assertTrue( - $cloneFailed, - 'Clone should have failed for nonexistent repository. Exit code: ' . $exitCode - ); - } finally { - if (\is_dir($directory)) { - exec('rm -rf ' . escapeshellarg($directory)); - } - } - } - - public function testUpdateComment(): void - { - $repositoryName = 'test-update-comment-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'test-branch', static::$defaultBranch); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'test', 'Add test', 'test-branch'); - - // Create PR - $pr = $this->vcsAdapter->createPullRequest( - static::$owner, - $repositoryName, - 'Test PR', - 'test-branch', - static::$defaultBranch - ); - - $prNumber = $pr['number'] ?? 0; - $this->assertGreaterThan(0, $prNumber); - - // Create comment - $commentId = $this->vcsAdapter->createComment(static::$owner, $repositoryName, $prNumber, 'Original comment'); - - // Test updateComment - $updatedCommentId = $this->vcsAdapter->updateComment(static::$owner, $repositoryName, (string)$commentId, 'Updated comment'); - - $this->assertSame($commentId, $updatedCommentId); - - // Verify comment was updated - $finalComment = $this->vcsAdapter->getComment(static::$owner, $repositoryName, $commentId); - $this->assertSame('Updated comment', $finalComment); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testUpdateCommitStatus(): void - { - $repositoryName = 'test-update-commit-status-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - - $commit = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, static::$defaultBranch); - $commitHash = $commit['commitHash']; - - $this->vcsAdapter->updateCommitStatus( - $repositoryName, - $commitHash, - static::$owner, - 'success', - 'Tests passed', - 'https://example.com/build/123', - 'ci/tests' - ); - - $statuses = $this->vcsAdapter->getCommitStatuses(static::$owner, $repositoryName, $commitHash); - $this->assertIsArray($statuses); - $this->assertNotEmpty($statuses); - - $found = false; - foreach ($statuses as $status) { - if (($status['context'] ?? '') === 'ci/tests') { - $this->assertSame('success', $status['status'] ?? ''); - $this->assertSame('Tests passed', $status['description'] ?? ''); - $found = true; - break; - } - } - $this->assertTrue($found, 'Expected status with context ci/tests was not found'); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - public function testUpdateCommitStatusWithInvalidCommit(): void { $repositoryName = 'test-update-status-invalid-' . \uniqid(); @@ -780,78 +244,6 @@ public function testUpdateCommitStatusWithNonExistingRepository(): void ); } - public function testGetCommit(): void - { - $repositoryName = 'test-get-commit-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - $customMessage = 'Test commit message'; - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test Commit', $customMessage); - - $latestCommit = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, static::$defaultBranch); - $commitHash = $latestCommit['commitHash']; - - $result = $this->vcsAdapter->getCommit(static::$owner, $repositoryName, $commitHash); - - $this->assertIsArray($result); - $this->assertArrayHasKey('commitHash', $result); - $this->assertArrayHasKey('commitMessage', $result); - $this->assertArrayHasKey('commitAuthor', $result); - $this->assertArrayHasKey('commitUrl', $result); - $this->assertArrayHasKey('commitAuthorAvatar', $result); - $this->assertArrayHasKey('commitAuthorUrl', $result); - - $this->assertSame($commitHash, $result['commitHash']); - $this->assertSame('utopia', $result['commitAuthor']); - $this->assertStringStartsWith($customMessage, $result['commitMessage']); - $this->assertStringContainsString($this->avatarDomain, $result['commitAuthorAvatar']); - $this->assertNotEmpty($result['commitUrl']); - - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - - public function testGetLatestCommit(): void - { - $repositoryName = 'test-get-latest-commit-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - $firstMessage = 'First commit'; - $secondMessage = 'Second commit'; - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test', $firstMessage); - - $commit1 = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, static::$defaultBranch); - - $this->assertIsArray($commit1); - $this->assertArrayHasKey('commitHash', $commit1); - $this->assertArrayHasKey('commitMessage', $commit1); - $this->assertArrayHasKey('commitAuthor', $commit1); - $this->assertArrayHasKey('commitUrl', $commit1); - $this->assertArrayHasKey('commitAuthorAvatar', $commit1); - $this->assertArrayHasKey('commitAuthorUrl', $commit1); - - $this->assertNotEmpty($commit1['commitHash']); - $this->assertSame('utopia', $commit1['commitAuthor']); - $this->assertStringStartsWith($firstMessage, $commit1['commitMessage']); - $this->assertStringContainsString($this->avatarDomain, $commit1['commitAuthorAvatar']); - $this->assertNotEmpty($commit1['commitUrl']); - - $commit1Hash = $commit1['commitHash']; - - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'test content', $secondMessage); - - $commit2 = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, static::$defaultBranch); - - $this->assertIsArray($commit2); - $this->assertNotEmpty($commit2['commitHash']); - $this->assertStringStartsWith($secondMessage, $commit2['commitMessage']); - - $commit2Hash = $commit2['commitHash']; - - $this->assertNotSame($commit1Hash, $commit2Hash); - - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - public function testGetCommitWithInvalidSha(): void { $repositoryName = 'test-get-commit-invalid-' . \uniqid(); @@ -866,20 +258,6 @@ public function testGetCommitWithInvalidSha(): void } } - public function testGetLatestCommitWithInvalidBranch(): void - { - $repositoryName = 'test-get-latest-commit-invalid-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - - try { - $this->expectException(\Exception::class); - $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, 'non-existing-branch'); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - public function testGetEventPush(): void { $payload = json_encode([ @@ -1103,45 +481,6 @@ public function testGetEventUnsupportedEvent(): void $this->assertEmpty($result); } - public function testSearchRepositories(): void - { - // Create multiple repositories - $repo1Name = 'test-search-repo1-' . \uniqid(); - $repo2Name = 'test-search-repo2-' . \uniqid(); - $repo3Name = 'other-repo-' . \uniqid(); - - $this->vcsAdapter->createRepository(static::$owner, $repo1Name, false); - $this->vcsAdapter->createRepository(static::$owner, $repo2Name, false); - $this->vcsAdapter->createRepository(static::$owner, $repo3Name, false); - - try { - // Search without filter - should return all - $result = $this->vcsAdapter->searchRepositories(static::$owner, 1, 10); - - $this->assertIsArray($result); - $this->assertArrayHasKey('items', $result); - $this->assertArrayHasKey('total', $result); - $this->assertGreaterThanOrEqual(3, $result['total']); - - // Search with filter - $result = $this->vcsAdapter->searchRepositories(static::$owner, 1, 10, 'test-search'); - - $this->assertIsArray($result); - $this->assertGreaterThanOrEqual(2, $result['total']); - - // Verify the filtered repos are in results - $repoNames = array_column($result['items'], 'name'); - $this->assertContains($repo1Name, $repoNames); - $this->assertContains($repo2Name, $repoNames); - $this->assertArrayHasKey('pushed_at', $result['items'][0]); - $this->assertNotFalse(\strtotime($result['items'][0]['pushed_at'])); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repo1Name); - $this->vcsAdapter->deleteRepository(static::$owner, $repo2Name); - $this->vcsAdapter->deleteRepository(static::$owner, $repo3Name); - } - } - public function testSearchRepositoriesPagination(): void { $repo1 = 'test-pagination-1-' . \uniqid(); @@ -1187,32 +526,6 @@ public function testSearchRepositoriesInvalidOwner(): void $this->assertSame(0, $result['total']); } - public function testDeleteRepository(): void - { - $repositoryName = 'test-delete-repository-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - $result = $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - - $this->assertTrue($result); - } - - public function testDeleteRepositoryTwiceFails(): void - { - $repositoryName = 'test-delete-repository-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - - $this->expectException(\Exception::class); - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - - public function testDeleteNonExistingRepositoryFails(): void - { - $this->expectException(\Exception::class); - $this->vcsAdapter->deleteRepository(static::$owner, 'non-existing-repo-' . \uniqid()); - } - public function testGetOwnerName(): void { $repositoryName = 'test-get-owner-name-' . \uniqid(); @@ -1263,23 +576,6 @@ public function testGetOwnerNameWithNullRepositoryId(): void $this->vcsAdapter->getOwnerName('', null); } - public function testGetUser(): void - { - // Get current authenticated user's info - $ownerInfo = $this->vcsAdapter->getUser(static::$owner); - - $this->assertIsArray($ownerInfo); - $this->assertArrayHasKey('login', $ownerInfo); - $this->assertArrayHasKey('id', $ownerInfo); - $this->assertSame(static::$owner, $ownerInfo['login']); - } - - public function testGetUserWithInvalidUsername(): void - { - $this->expectException(\Exception::class); - $this->vcsAdapter->getUser('non-existent-user-' . \uniqid()); - } - public function testGetInstallationRepository(): void { // This method is not applicable for this adapter @@ -1289,93 +585,6 @@ public function testGetInstallationRepository(): void $this->vcsAdapter->getInstallationRepository('any-repo-name'); } - public function testGetPullRequestFromBranch(): void - { - $repositoryName = 'test-get-pr-from-branch-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'my-feature', static::$defaultBranch); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'feature.txt', 'content', 'Add feature', 'my-feature'); - - // Create PR - $pr = $this->vcsAdapter->createPullRequest( - static::$owner, - $repositoryName, - 'Feature PR', - 'my-feature', - static::$defaultBranch - ); - - $this->assertArrayHasKey('number', $pr); - - // Test getPullRequestFromBranch - $result = $this->vcsAdapter->getPullRequestFromBranch(static::$owner, $repositoryName, 'my-feature'); - - $this->assertIsArray($result); - $this->assertNotEmpty($result); - $this->assertArrayHasKey('head', $result); - - $resultHead = $result['head'] ?? []; - $this->assertSame('my-feature', $resultHead['ref'] ?? ''); - - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - - public function testGetPullRequestFromBranchNoPR(): void - { - $repositoryName = 'test-get-pr-no-pr-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'lonely-branch', static::$defaultBranch); - - // Don't create a PR - just test the method - $result = $this->vcsAdapter->getPullRequestFromBranch(static::$owner, $repositoryName, 'lonely-branch'); - - $this->assertIsArray($result); - $this->assertEmpty($result); - - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - - public function testCreateComment(): void - { - $repositoryName = 'test-create-comment-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'test-branch', static::$defaultBranch); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'test', 'Add test', 'test-branch'); - - // Create PR - $pr = $this->vcsAdapter->createPullRequest( - static::$owner, - $repositoryName, - 'Test PR', - 'test-branch', - static::$defaultBranch - ); - - $prNumber = $pr['number'] ?? 0; - $this->assertGreaterThan(0, $prNumber); - - // Test createComment - $commentId = $this->vcsAdapter->createComment(static::$owner, $repositoryName, $prNumber, 'Test comment'); - - $this->assertNotEquals('', $commentId); - $this->assertIsString($commentId); - $this->assertIsNumeric($commentId); - - // Verify comment was created - $retrievedComment = $this->vcsAdapter->getComment(static::$owner, $repositoryName, $commentId); - $this->assertSame('Test comment', $retrievedComment); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - public function testCreateFile(): void { $repositoryName = 'test-create-file-'.\uniqid(); @@ -1431,42 +640,6 @@ public function testCreateFileOnBranch(): void } } - public function testListBranches(): void - { - $repositoryName = 'test-list-branches-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - // Create initial file on main branch - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - - // Create additional branches - $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'feature-1', static::$defaultBranch); - $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'feature-2', static::$defaultBranch); - - $branches = []; - $maxAttempts = 10; - for ($attempt = 0; $attempt < $maxAttempts; $attempt++) { - $branches = $this->vcsAdapter->listBranches(static::$owner, $repositoryName); - - if (in_array('feature-1', $branches, true) && in_array('feature-2', $branches, true)) { - break; - } - - usleep(500000); - } - - $this->assertIsArray($branches); - $this->assertNotEmpty($branches); - $this->assertContains(static::$defaultBranch, $branches); - $this->assertContains('feature-1', $branches); - $this->assertContains('feature-2', $branches); - $this->assertGreaterThanOrEqual(3, count($branches)); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - public function testCreateTag(): void { $repositoryName = 'test-create-tag-' . \uniqid(); @@ -1498,39 +671,6 @@ public function testCreateTag(): void } } - public function testListRepositoryLanguages(): void - { - $repositoryName = 'test-list-repository-languages-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'main.php', 'vcsAdapter->createFile(static::$owner, $repositoryName, 'script.js', 'console.log("test");'); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'style.css', 'body { margin: 0; }'); - - sleep(2); - - $languages = $this->vcsAdapter->listRepositoryLanguages(static::$owner, $repositoryName); - - $this->assertIsArray($languages); - $this->assertNotEmpty($languages); - $this->assertContains('PHP', $languages); - - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - - public function testListRepositoryLanguagesEmptyRepo(): void - { - $repositoryName = 'test-list-repository-languages-empty-' . \uniqid(); - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - $languages = $this->vcsAdapter->listRepositoryLanguages(static::$owner, $repositoryName); - - $this->assertIsArray($languages); - $this->assertEmpty($languages); - - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - public function testWebhookPushEvent(): void { $repositoryName = 'test-webhook-push-' . \uniqid(); diff --git a/tests/VCS/Adapter/GogsTest.php b/tests/VCS/Adapter/GogsTest.php index dd551b6f..bfeb6194 100644 --- a/tests/VCS/Adapter/GogsTest.php +++ b/tests/VCS/Adapter/GogsTest.php @@ -23,7 +23,7 @@ protected function createVCSAdapter(): Git return new Gogs(new Cache(new None())); } - public function setUp(): void + public function setupAdapter(): void { if (empty(static::$accessToken)) { $this->setupGogs(); diff --git a/tests/VCS/Base.php b/tests/VCS/Base.php index 5aadff0b..357bcf39 100644 --- a/tests/VCS/Base.php +++ b/tests/VCS/Base.php @@ -2,39 +2,26 @@ namespace Utopia\Tests; -use Exception; use PHPUnit\Framework\TestCase; use Utopia\Fetch\Client; use Utopia\System\System; use Utopia\VCS\Adapter\Git; -use Utopia\VCS\Adapter\Git\GitHub; +use Utopia\VCS\Exception\FileNotFound; abstract class Base extends TestCase { protected Git $vcsAdapter; - - protected function setUp(): void - { - $this->vcsAdapter = $this->createVCSAdapter(); - } + protected static string $owner = ''; + protected static string $defaultBranch = 'main'; abstract protected function createVCSAdapter(): Git; - abstract public function testUpdateComment(): void; - - abstract public function testGenerateCloneCommand(): void; - - abstract public function testGenerateCloneCommandWithCommitHash(): void; - - abstract public function testGetRepositoryName(): void; - - abstract public function testGetComment(): void; + abstract protected function setupAdapter(): void; - abstract public function testGetPullRequest(): void; - - abstract public function testGetPullRequestFiles(): void; - - abstract public function testGetRepositoryTree(): void; + public function setUp(): void + { + $this->setupAdapter(); + } /** @return array */ protected function getLastWebhookRequest(): array @@ -89,33 +76,324 @@ protected function deleteLastWebhookRequest(): void ); } - public function testGetPullRequestFromBranch(): void + public function testCreateRepository(): void { - $result = $this->vcsAdapter->getPullRequestFromBranch('vermakhushboo', 'basic-js-crud', 'test'); - $this->assertIsArray($result); - $this->assertNotEmpty($result); + $repositoryName = 'test-create-repository-' . \uniqid(); + + $result = $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $this->assertIsArray($result); + $this->assertArrayHasKey('name', $result); + $this->assertSame($repositoryName, $result['name']); + $this->assertArrayHasKey('pushed_at', $result); + $this->assertTrue( + $result['pushed_at'] === null || \strtotime($result['pushed_at']) !== false + ); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } } - public function testGetOwnerName(): void + public function testCreatePrivateRepository(): void { - $installationId = System::getEnv('TESTS_GITHUB_INSTALLATION_ID') ?? ''; - $owner = $this->vcsAdapter->getOwnerName($installationId); - $this->assertSame('test-kh', $owner); + $repositoryName = 'test-create-private-' . \uniqid(); + + $result = $this->vcsAdapter->createRepository(static::$owner, $repositoryName, true); + + try { + $this->assertIsArray($result); + $this->assertArrayHasKey('name', $result); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } } - public function testSearchRepositories(): void + public function testGetRepository(): void { - ['items' => $repos, 'total' => $total] = $this->vcsAdapter->searchRepositories('test-kh', 1, 2); - $this->assertCount(2, $repos); - $this->assertSame(6, $total); - $this->assertArrayHasKey('pushed_at', $repos[0]); - $this->assertNotFalse(\strtotime($repos[0]['pushed_at'])); + $repositoryName = 'test-get-repository-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $result = $this->vcsAdapter->getRepository(static::$owner, $repositoryName); + + $this->assertIsArray($result); + $this->assertSame($repositoryName, $result['name']); + $this->assertArrayHasKey('pushed_at', $result); + $this->assertTrue( + $result['pushed_at'] === null || \strtotime($result['pushed_at']) !== false + ); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } } - public function testCreateComment(): void + public function testGetDeletedRepositoryFails(): void + { + $this->expectException(\Exception::class); + $this->vcsAdapter->getRepository(static::$owner, 'non-existing-repository-' . \uniqid()); + } + + public function testGetRepositoryWithNonExistingOwner(): void + { + $this->expectException(\Exception::class); + $this->vcsAdapter->getRepository('non-existing-owner-' . \uniqid(), 'non-existing-repo'); + } + + public function testDeleteRepository(): void + { + $repositoryName = 'test-delete-repository-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + $result = $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + $this->assertTrue($result); + } + + public function testDeleteRepositoryTwiceFails(): void + { + $repositoryName = 'test-delete-repository-twice-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + + $this->expectException(\Exception::class); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + + public function testDeleteNonExistingRepositoryFails(): void + { + $this->expectException(\Exception::class); + $this->vcsAdapter->deleteRepository(static::$owner, 'non-existing-repo-' . \uniqid()); + } + + public function testCreateRepositoryWithInvalidName(): void + { + try { + $this->vcsAdapter->createRepository(static::$owner, 'invalid name with spaces', false); + $this->fail('Expected exception for invalid repository name'); + } catch (\Exception $e) { + $this->assertTrue(true); + } + } + + public function testGetRepositoryName(): void + { + $repositoryName = 'test-get-repository-name-' . \uniqid(); + $created = $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $this->assertIsArray($created); + $this->assertArrayHasKey('id', $created); + $repositoryId = (string) ($created['id'] ?? ''); + + $result = $this->vcsAdapter->getRepositoryName($repositoryId); + + $this->assertIsString($result); + $this->assertSame($repositoryName, $result); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testGetRepositoryNameWithInvalidId(): void + { + $this->expectException(\Exception::class); + $this->vcsAdapter->getRepositoryName('99999999'); + } + + public function testGetRepositoryTree(): void + { + $repositoryName = 'test-get-repository-tree-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'src/main.php', 'vcsAdapter->createFile(static::$owner, $repositoryName, 'src/lib.php', 'vcsAdapter->getRepositoryTree(static::$owner, $repositoryName, static::$defaultBranch, false); + $this->assertIsArray($tree); + $this->assertContains('README.md', $tree); + $this->assertContains('src', $tree); + $this->assertCount(2, $tree); + + $treeRecursive = $this->vcsAdapter->getRepositoryTree(static::$owner, $repositoryName, static::$defaultBranch, true); + $this->assertIsArray($treeRecursive); + $this->assertContains('README.md', $treeRecursive); + $this->assertContains('src/main.php', $treeRecursive); + $this->assertContains('src/lib.php', $treeRecursive); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testGetRepositoryTreeWithInvalidBranch(): void + { + $repositoryName = 'test-get-repository-tree-invalid-' . \uniqid(); + + try { + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + + $tree = $this->vcsAdapter->getRepositoryTree(static::$owner, $repositoryName, 'non-existing-branch', false); + $this->assertIsArray($tree); + $this->assertEmpty($tree); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testGetRepositoryContent(): void + { + $repositoryName = 'test-get-repository-content-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $fileContent = '# Hello World'; + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', $fileContent); + + $result = $this->vcsAdapter->getRepositoryContent(static::$owner, $repositoryName, 'README.md'); + + $this->assertIsArray($result); + $this->assertArrayHasKey('content', $result); + $this->assertArrayHasKey('sha', $result); + $this->assertArrayHasKey('size', $result); + $this->assertSame($fileContent, $result['content']); + $this->assertGreaterThan(0, $result['size']); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testGetRepositoryContentWithRef(): void + { + $repositoryName = 'test-get-repository-content-ref-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'main branch content'); + + $result = $this->vcsAdapter->getRepositoryContent(static::$owner, $repositoryName, 'test.txt', static::$defaultBranch); + + $this->assertIsArray($result); + $this->assertSame('main branch content', $result['content']); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testGetRepositoryContentFileNotFound(): void + { + $repositoryName = 'test-get-repository-content-not-found-' . \uniqid(); + + try { + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + + $this->expectException(FileNotFound::class); + $this->vcsAdapter->getRepositoryContent(static::$owner, $repositoryName, 'non-existing.txt'); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testListRepositoryContents(): void + { + $repositoryName = 'test-list-repository-contents-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'file1.txt', 'content1'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'src/main.php', 'vcsAdapter->listRepositoryContents(static::$owner, $repositoryName); + + $this->assertIsArray($contents); + $this->assertCount(3, $contents); + + $names = array_column($contents, 'name'); + $this->assertContains('README.md', $names); + $this->assertContains('file1.txt', $names); + $this->assertContains('src', $names); + + foreach ($contents as $item) { + $this->assertArrayHasKey('name', $item); + $this->assertArrayHasKey('type', $item); + $this->assertArrayHasKey('size', $item); + } + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testListRepositoryContentsNonExistingPath(): void + { + $repositoryName = 'test-list-repository-contents-invalid-' . \uniqid(); + + try { + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + + $contents = $this->vcsAdapter->listRepositoryContents(static::$owner, $repositoryName, 'non-existing-path'); + $this->assertIsArray($contents); + $this->assertEmpty($contents); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testListRepositoryLanguages(): void + { + $repositoryName = 'test-list-repository-languages-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'main.php', 'vcsAdapter->createFile(static::$owner, $repositoryName, 'script.js', 'console.log("test");'); + + $languages = []; + $this->assertEventually(function () use (&$languages, $repositoryName) { + $languages = $this->vcsAdapter->listRepositoryLanguages(static::$owner, $repositoryName); + $this->assertNotEmpty($languages); + }, 30000, 2000); + + $this->assertIsArray($languages); + $this->assertContains('PHP', $languages); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testListRepositoryLanguagesEmptyRepo(): void + { + $repositoryName = 'test-list-repository-languages-empty-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $languages = $this->vcsAdapter->listRepositoryLanguages(static::$owner, $repositoryName); + $this->assertIsArray($languages); + $this->assertEmpty($languages); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testListBranches(): void { - $commentId = $this->vcsAdapter->createComment('test-kh', 'test2', 1, 'hello'); - $this->assertNotEmpty($commentId); + $repositoryName = 'test-list-branches-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + + $branches = $this->vcsAdapter->listBranches(static::$owner, $repositoryName); + + $this->assertIsArray($branches); + $this->assertNotEmpty($branches); + $this->assertContains(static::$defaultBranch, $branches); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } } public function testListBranchesEmptyRepo(): void @@ -123,84 +401,510 @@ public function testListBranchesEmptyRepo(): void $this->markTestSkipped('Each adapter handles empty repos differently - override in adapter-specific test'); } - public function testListBranches(): void + public function testGetCommit(): void { - $branches = $this->vcsAdapter->listBranches('vermakhushboo', 'basic-js-crud'); - $this->assertIsArray($branches); - $this->assertNotEmpty($branches); + $repositoryName = 'test-get-commit-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $customMessage = 'Test commit message'; + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test', $customMessage); + + $latestCommit = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, static::$defaultBranch); + $commitHash = $latestCommit['commitHash']; + + $result = $this->vcsAdapter->getCommit(static::$owner, $repositoryName, $commitHash); + + $this->assertIsArray($result); + $this->assertArrayHasKey('commitHash', $result); + $this->assertArrayHasKey('commitMessage', $result); + $this->assertArrayHasKey('commitAuthor', $result); + $this->assertArrayHasKey('commitUrl', $result); + $this->assertArrayHasKey('commitAuthorAvatar', $result); + $this->assertArrayHasKey('commitAuthorUrl', $result); + $this->assertSame($commitHash, $result['commitHash']); + $this->assertStringStartsWith($customMessage, $result['commitMessage']); + $this->assertNotEmpty($result['commitUrl']); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } } - public function testListRepositoryLanguages(): void + public function testGetLatestCommit(): void { - $languages = $this->vcsAdapter->listRepositoryLanguages('vermakhushboo', 'basic-js-crud'); + $repositoryName = 'test-get-latest-commit-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $firstMessage = 'First commit'; + $secondMessage = 'Second commit'; + + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test', $firstMessage); + $commit1 = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, static::$defaultBranch); + + $this->assertIsArray($commit1); + $this->assertNotEmpty($commit1['commitHash']); + $this->assertStringStartsWith($firstMessage, $commit1['commitMessage']); + $this->assertNotEmpty($commit1['commitUrl']); + + $commit1Hash = $commit1['commitHash']; - $this->assertIsArray($languages); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'test', $secondMessage); + $commit2 = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, static::$defaultBranch); - $this->assertContains('JavaScript', $languages); - $this->assertContains('HTML', $languages); - $this->assertContains('CSS', $languages); + $this->assertStringStartsWith($secondMessage, $commit2['commitMessage']); + $this->assertNotSame($commit1Hash, $commit2['commitHash']); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } } - public function testListRepositoryContents(): void + public function testGetLatestCommitWithInvalidBranch(): void { - $contents = $this->vcsAdapter->listRepositoryContents('appwrite', 'appwrite', 'src/Appwrite'); - $this->assertIsArray($contents); - $this->assertNotEmpty($contents); - - $contents = $this->vcsAdapter->listRepositoryContents('appwrite', 'appwrite', ''); - $this->assertIsArray($contents); - $this->assertNotEmpty($contents); - $this->assertGreaterThan(0, \count($contents)); - - // Test with ref parameter - $contents = $this->vcsAdapter->listRepositoryContents('appwrite', 'appwrite', '', 'main'); - $this->assertIsArray($contents); - $this->assertNotEmpty($contents); - $this->assertGreaterThan(0, \count($contents)); - - $fileContent = null; - foreach ($contents as $content) { - if ($content['type'] === GitHub::CONTENTS_FILE) { - $fileContent = $content; - break; + $repositoryName = 'test-get-latest-commit-invalid-' . \uniqid(); + + try { + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + + $this->expectException(\Exception::class); + $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, 'non-existing-branch'); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testUpdateCommitStatus(): void + { + $repositoryName = 'test-update-commit-status-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $commit = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, static::$defaultBranch); + $commitHash = $commit['commitHash']; + + $this->vcsAdapter->updateCommitStatus( + $repositoryName, + $commitHash, + static::$owner, + 'success', + 'Build passed', + 'https://example.com', + 'ci/build' + ); + + $this->assertTrue(true); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testGenerateCloneCommand(): void + { + $repositoryName = 'test-clone-command-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + $directory = '/tmp/test-clone-' . \uniqid(); + + try { + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + + $command = $this->vcsAdapter->generateCloneCommand( + static::$owner, + $repositoryName, + static::$defaultBranch, + Git::CLONE_TYPE_BRANCH, + $directory, + '*' + ); + + $this->assertIsString($command); + $this->assertStringContainsString('sparse-checkout', $command); + $this->assertStringContainsString($repositoryName, $command); + + $output = []; + \exec($command . ' 2>&1', $output, $exitCode); + $this->assertSame(0, $exitCode, implode("\n", $output)); + $this->assertFileExists($directory . '/README.md'); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + if (\is_dir($directory)) { + \exec('rm -rf ' . escapeshellarg($directory)); } } - $this->assertNotNull($fileContent); - $this->assertNotEmpty($fileContent['name']); - $this->assertStringContainsString('.', $fileContent['name']); - $this->assertIsNumeric($fileContent['size']); - $this->assertGreaterThan(0, $fileContent['size']); - - $directoryContent = null; - foreach ($contents as $content) { - if ($content['type'] === GitHub::CONTENTS_DIRECTORY) { - $directoryContent = $content; - break; + } + + public function testGenerateCloneCommandWithCommitHash(): void + { + $repositoryName = 'test-clone-commit-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + + $commit = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, static::$defaultBranch); + $commitHash = $commit['commitHash']; + + $directory = '/tmp/test-clone-commit-' . \uniqid(); + $command = $this->vcsAdapter->generateCloneCommand( + static::$owner, + $repositoryName, + $commitHash, + Git::CLONE_TYPE_COMMIT, + $directory, + '*' + ); + + $this->assertIsString($command); + $this->assertStringContainsString('sparse-checkout', $command); + + $output = []; + \exec($command . ' 2>&1', $output, $exitCode); + $this->assertSame(0, $exitCode, implode("\n", $output)); + $this->assertFileExists($directory . '/README.md'); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testGenerateCloneCommandWithInvalidRepository(): void + { + $directory = '/tmp/test-clone-invalid-' . \uniqid(); + + try { + $command = $this->vcsAdapter->generateCloneCommand( + static::$owner, + 'nonexistent-repo-' . \uniqid(), + static::$defaultBranch, + Git::CLONE_TYPE_BRANCH, + $directory, + '*' + ); + + $output = []; + \exec($command . ' 2>&1', $output, $exitCode); + + $cloneFailed = ($exitCode !== 0) || !file_exists($directory . '/README.md'); + $this->assertTrue($cloneFailed, 'Clone should have failed for nonexistent repository'); + } finally { + if (\is_dir($directory)) { + \exec('rm -rf ' . escapeshellarg($directory)); } } - $this->assertNotNull($directoryContent); - $this->assertNotEmpty($directoryContent['name']); - $this->assertIsNumeric($directoryContent['size']); - $this->assertSame(0, $directoryContent['size']); } - public function testCreateRepository(): void + public function testGetOwnerName(): void { - $repository = $this->vcsAdapter->createRepository('test-kh', 'new-repo', true); - $this->assertIsArray($repository); - $this->assertSame('test-kh/new-repo', $repository['full_name']); - $this->assertArrayHasKey('pushed_at', $repository); - $this->assertNotFalse(\strtotime($repository['pushed_at'])); + $result = $this->vcsAdapter->getOwnerName(''); + $this->assertIsString($result); + $this->assertNotEmpty($result); + $this->assertSame(static::$owner, $result); } - /** - * @depends testCreateRepository - */ - public function testDeleteRepository(): void + public function testSearchRepositories(): void + { + $repo1Name = 'test-search-repo1-' . \uniqid(); + $repo2Name = 'test-search-repo2-' . \uniqid(); + + $this->vcsAdapter->createRepository(static::$owner, $repo1Name, false); + $this->vcsAdapter->createRepository(static::$owner, $repo2Name, false); + + try { + $result = $this->vcsAdapter->searchRepositories(static::$owner, 1, 10); + + $this->assertIsArray($result); + $this->assertArrayHasKey('items', $result); + $this->assertArrayHasKey('total', $result); + $this->assertGreaterThanOrEqual(2, $result['total']); + + $this->assertArrayHasKey('pushed_at', $result['items'][0]); + $this->assertTrue( + $result['items'][0]['pushed_at'] === null || \strtotime($result['items'][0]['pushed_at']) !== false + ); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repo1Name); + $this->vcsAdapter->deleteRepository(static::$owner, $repo2Name); + } + } + + public function testGetPullRequest(): void + { + $repositoryName = 'test-get-pull-request-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'feature-branch', static::$defaultBranch); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'feature.txt', 'feature content', 'Add feature', 'feature-branch'); + + $pr = $this->vcsAdapter->createPullRequest( + static::$owner, + $repositoryName, + 'Test PR', + 'feature-branch', + static::$defaultBranch, + 'Test PR description' + ); + + $prNumber = $pr['iid'] ?? $pr['number'] ?? 0; + $this->assertGreaterThan(0, $prNumber); + + $result = $this->vcsAdapter->getPullRequest(static::$owner, $repositoryName, $prNumber); + + $this->assertIsArray($result); + $this->assertArrayHasKey('number', $result); + $this->assertArrayHasKey('title', $result); + $this->assertArrayHasKey('state', $result); + $this->assertArrayHasKey('head', $result); + $this->assertArrayHasKey('base', $result); + $this->assertSame($prNumber, $result['number']); + $this->assertSame('Test PR', $result['title']); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testGetPullRequestFiles(): void + { + $repositoryName = 'test-get-pull-request-files-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'feature-branch', static::$defaultBranch); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'feature.txt', 'feature content', 'Add feature', 'feature-branch'); + + $pr = $this->vcsAdapter->createPullRequest( + static::$owner, + $repositoryName, + 'Test PR Files', + 'feature-branch', + static::$defaultBranch + ); + + $prNumber = $pr['iid'] ?? $pr['number'] ?? 0; + + $result = []; + $this->assertEventually(function () use (&$result, $repositoryName, $prNumber) { + $result = $this->vcsAdapter->getPullRequestFiles(static::$owner, $repositoryName, $prNumber); + $this->assertNotEmpty($result); + }, 15000, 1000); + + $this->assertIsArray($result); + $filenames = array_column($result, 'filename'); + $this->assertContains('feature.txt', $filenames); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testGetPullRequestWithInvalidNumber(): void + { + $repositoryName = 'test-get-pull-request-invalid-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $this->expectException(\Exception::class); + $this->vcsAdapter->getPullRequest(static::$owner, $repositoryName, 99999); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testGetPullRequestFromBranch(): void + { + $repositoryName = 'test-get-pr-from-branch-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'my-feature', static::$defaultBranch); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'feature.txt', 'content', 'Add feature', 'my-feature'); + + $this->vcsAdapter->createPullRequest( + static::$owner, + $repositoryName, + 'Feature PR', + 'my-feature', + static::$defaultBranch + ); + + $result = $this->vcsAdapter->getPullRequestFromBranch(static::$owner, $repositoryName, 'my-feature'); + + $this->assertIsArray($result); + $this->assertNotEmpty($result); + $this->assertArrayHasKey('head', $result); + $this->assertSame('my-feature', $result['head']['ref'] ?? ''); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testGetPullRequestFromBranchNoPR(): void + { + $repositoryName = 'test-get-pr-no-pr-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'lonely-branch', static::$defaultBranch); + + $result = $this->vcsAdapter->getPullRequestFromBranch(static::$owner, $repositoryName, 'lonely-branch'); + + $this->assertIsArray($result); + $this->assertEmpty($result); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testCreateComment(): void + { + $repositoryName = 'test-create-comment-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'test-branch', static::$defaultBranch); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'test', 'Add test', 'test-branch'); + + $pr = $this->vcsAdapter->createPullRequest( + static::$owner, + $repositoryName, + 'Test PR', + 'test-branch', + static::$defaultBranch + ); + + $prNumber = $pr['iid'] ?? $pr['number'] ?? 0; + $this->assertGreaterThan(0, $prNumber); + + $commentId = $this->vcsAdapter->createComment(static::$owner, $repositoryName, $prNumber, 'Test comment'); + + $this->assertNotEmpty($commentId); + $this->assertIsString($commentId); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testGetComment(): void + { + $repositoryName = 'test-get-comment-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'test-branch', static::$defaultBranch); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'test', 'Add test', 'test-branch'); + + $pr = $this->vcsAdapter->createPullRequest( + static::$owner, + $repositoryName, + 'Test PR', + 'test-branch', + static::$defaultBranch + ); + + $prNumber = $pr['iid'] ?? $pr['number'] ?? 0; + $commentId = $this->vcsAdapter->createComment(static::$owner, $repositoryName, $prNumber, 'Test comment'); + + $result = $this->vcsAdapter->getComment(static::$owner, $repositoryName, $commentId); + + $this->assertIsString($result); + $this->assertSame('Test comment', $result); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testUpdateComment(): void + { + $repositoryName = 'test-update-comment-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'test-branch', static::$defaultBranch); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'test', 'Add test', 'test-branch'); + + $pr = $this->vcsAdapter->createPullRequest( + static::$owner, + $repositoryName, + 'Test PR', + 'test-branch', + static::$defaultBranch + ); + + $prNumber = $pr['iid'] ?? $pr['number'] ?? 0; + $commentId = $this->vcsAdapter->createComment(static::$owner, $repositoryName, $prNumber, 'Original comment'); + + $updatedCommentId = $this->vcsAdapter->updateComment(static::$owner, $repositoryName, $commentId, 'Updated comment'); + + $this->assertSame($commentId, $updatedCommentId); + + $finalComment = $this->vcsAdapter->getComment(static::$owner, $repositoryName, $commentId); + $this->assertSame('Updated comment', $finalComment); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testCreateCommentInvalidPR(): void + { + $repositoryName = 'test-comment-invalid-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + + try { + $this->expectException(\Exception::class); + $this->vcsAdapter->createComment(static::$owner, $repositoryName, 99999, 'Test comment'); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testGetCommentInvalidId(): void + { + $repositoryName = 'test-get-comment-invalid-' . \uniqid(); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + + try { + $result = $this->vcsAdapter->getComment(static::$owner, $repositoryName, '99999999'); + $this->assertIsString($result); + $this->assertSame('', $result); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testGetUser(): void + { + $result = $this->vcsAdapter->getUser('root'); + $this->assertIsArray($result); + $this->assertArrayHasKey('id', $result); + $this->assertArrayHasKey('username', $result); + } + + public function testGetUserWithInvalidUsername(): void + { + $this->expectException(\Exception::class); + $this->vcsAdapter->getUser('non-existent-user-' . \uniqid()); + } + + public function testGetEventPush(): void + { + $this->markTestSkipped('Override in adapter-specific test'); + } + + public function testGetEventPullRequest(): void + { + $this->markTestSkipped('Override in adapter-specific test'); + } + + public function testValidateWebhookEvent(): void { - $result = $this->vcsAdapter->deleteRepository('test-kh', 'new-repo'); - $this->assertSame(true, $result); - $this->expectException(Exception::class); - $result = $this->vcsAdapter->deleteRepository('test-kh', 'new-repo-2'); + $this->markTestSkipped('Override in adapter-specific test'); } }