Files
michaelschiemer/tests/Unit/Framework/Mcp/Tools/GitToolsTest.php
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
2025-10-25 19:18:37 +02:00

239 lines
9.4 KiB
PHP

<?php
declare(strict_types=1);
use App\Framework\Mcp\Tools\GitTools;
describe('GitTools', function () {
beforeEach(function () {
$this->projectRoot = '/home/michael/dev/michaelschiemer';
$this->gitTools = new GitTools($this->projectRoot);
});
describe('git_status', function () {
it('returns git status with staged, unstaged, and untracked files', function () {
$result = $this->gitTools->gitStatus();
expect($result)->toHaveKeys(['staged', 'unstaged', 'untracked', 'clean', 'summary']);
expect($result['staged'])->toBeArray();
expect($result['unstaged'])->toBeArray();
expect($result['untracked'])->toBeArray();
expect($result['summary'])->toHaveKeys(['staged_count', 'unstaged_count', 'untracked_count']);
expect($result['clean'])->toBeIn([true, false]);
});
it('marks repository as clean when no changes exist', function () {
// This test assumes a clean repository state
// In real scenarios, you might need to setup a clean git state first
$result = $this->gitTools->gitStatus();
if ($result['clean']) {
expect($result['staged'])->toBeEmpty();
expect($result['unstaged'])->toBeEmpty();
expect($result['untracked'])->toBeEmpty();
}
});
});
describe('git_diff', function () {
it('returns diff for unstaged changes by default', function () {
$result = $this->gitTools->gitDiff(staged: false);
expect($result)->toHaveKeys(['diff', 'staged', 'file', 'has_changes']);
expect($result['staged'])->toBeFalse();
});
it('returns diff for staged changes when staged flag is true', function () {
$result = $this->gitTools->gitDiff(staged: true);
expect($result)->toHaveKeys(['diff', 'staged', 'file', 'has_changes']);
expect($result['staged'])->toBeTrue();
});
it('can get diff for specific file', function () {
$result = $this->gitTools->gitDiff(staged: false, file: 'README.md');
expect($result)->toHaveKey('file');
expect($result['file'])->toBe('README.md');
});
});
describe('git_log', function () {
it('returns recent commit history', function () {
$result = $this->gitTools->gitLog(limit: 5);
expect($result)->toHaveKeys(['commits', 'count', 'limit']);
expect($result['commits'])->toBeArray();
expect($result['limit'])->toBe(5);
if (! empty($result['commits'])) {
$commit = $result['commits'][0];
expect($commit)->toHaveKeys(['hash', 'short_hash', 'author', 'email', 'date', 'message']);
expect(strlen($commit['hash']))->toBe(40); // Full SHA-1 hash
expect(strlen($commit['short_hash']))->toBe(7);
}
});
it('respects the limit parameter', function () {
$result = $this->gitTools->gitLog(limit: 3);
expect($result['count'])->toBeLessThanOrEqual(3);
expect($result['limit'])->toBe(3);
});
});
describe('git_branch_info', function () {
it('returns current branch information', function () {
$result = $this->gitTools->gitBranchInfo();
expect($result)->toHaveKeys(['current_branch', 'local_branches', 'remote_branches', 'total_local', 'total_remote']);
expect($result['current_branch'])->toBeString();
expect($result['local_branches'])->toBeArray();
expect($result['remote_branches'])->toBeArray();
});
it('includes branch counts', function () {
$result = $this->gitTools->gitBranchInfo();
expect($result['total_local'])->toBeInt();
expect($result['total_remote'])->toBeInt();
expect($result['total_local'])->toBe(count($result['local_branches']));
expect($result['total_remote'])->toBe(count($result['remote_branches']));
});
});
describe('git_changed_files', function () {
it('returns all changed files with their status', function () {
$result = $this->gitTools->gitChangedFiles();
expect($result)->toHaveKeys(['changes', 'total', 'by_status']);
expect($result['changes'])->toBeArray();
expect($result['total'])->toBeInt();
expect($result['by_status'])->toBeArray();
});
it('includes staged flag for each change', function () {
$result = $this->gitTools->gitChangedFiles();
foreach ($result['changes'] as $change) {
expect($change)->toHaveKeys(['file', 'status', 'staged']);
expect($change['staged'])->toBeIn([true, false]);
}
});
});
describe('git_stash_list', function () {
it('returns list of stashed changes', function () {
$result = $this->gitTools->gitStashList();
expect($result)->toHaveKeys(['stashes', 'count']);
expect($result['stashes'])->toBeArray();
expect($result['count'])->toBe(count($result['stashes']));
});
it('parses stash entries correctly', function () {
$result = $this->gitTools->gitStashList();
foreach ($result['stashes'] as $stash) {
expect($stash)->toHaveKeys(['ref', 'index', 'message']);
expect($stash['ref'])->toContain('stash@{');
expect($stash['index'])->toBeInt();
expect($stash['message'])->toBeString();
}
});
});
describe('git_remote_info', function () {
it('returns configured remotes', function () {
$result = $this->gitTools->gitRemoteInfo();
expect($result)->toHaveKeys(['remotes', 'count']);
expect($result['remotes'])->toBeArray();
expect($result['count'])->toBe(count($result['remotes']));
});
it('includes fetch and push URLs for each remote', function () {
$result = $this->gitTools->gitRemoteInfo();
foreach ($result['remotes'] as $remote) {
expect($remote)->toHaveKey('name');
expect($remote['name'])->toBeString();
}
});
});
describe('git_conflict_status', function () {
it('checks for merge/rebase conflicts', function () {
$result = $this->gitTools->gitConflictStatus();
expect($result)->toHaveKeys(['has_conflicts', 'state', 'conflicted_files', 'count']);
expect($result['has_conflicts'])->toBeIn([true, false]);
expect($result['state'])->toBeIn(['normal', 'merging', 'rebasing', 'cherry-picking']);
expect($result['conflicted_files'])->toBeArray();
expect($result['count'])->toBe(count($result['conflicted_files']));
});
it('returns normal state when no conflicts exist', function () {
$result = $this->gitTools->gitConflictStatus();
// Assuming clean repository state
if (! $result['has_conflicts']) {
expect($result['state'])->toBe('normal');
expect($result['conflicted_files'])->toBeEmpty();
expect($result['count'])->toBe(0);
}
});
});
describe('git_generate_commit_message', function () {
it('generates conventional commit message from staged changes', function () {
// This test requires staged changes
$result = $this->gitTools->generateCommitMessage();
// If no staged changes, should return error
if (isset($result['error'])) {
expect($result['error'])->toContain('No staged changes');
expect($result)->toHaveKey('suggestion');
} else {
// If staged changes exist
expect($result)->toHaveKeys([
'suggested_message',
'type',
'scope',
'description',
'changes_summary',
'conventional_commit',
]);
expect($result['conventional_commit'])->toBeTrue();
expect($result['type'])->toBeIn(['feat', 'fix', 'docs', 'test', 'chore', 'refactor']);
}
});
});
describe('error handling', function () {
it('handles git command failures gracefully', function () {
// Create GitTools with invalid project root
$invalidGitTools = new GitTools('/invalid/path/that/does/not/exist');
$result = $invalidGitTools->gitStatus();
// Should either work (if git falls back to current dir) or return error
expect($result)->toBeArray();
});
});
describe('private helper methods', function () {
it('correctly analyzes diff output', function () {
// Test through generateCommitMessage which uses analyzeDiff
$result = $this->gitTools->generateCommitMessage();
if (isset($result['changes_summary'])) {
$summary = $result['changes_summary'];
expect($summary)->toHaveKeys(['files', 'file_count', 'additions', 'deletions', 'net_change']);
expect($summary['file_count'])->toBe(count($summary['files']));
expect($summary['net_change'])->toBe($summary['additions'] - $summary['deletions']);
}
});
});
});