/**
 * Git 路由单元测试
 */
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import path from 'node:path';
import { describe, expect, it } from 'vitest';
import { assertGitWorkspacePathAccessible, shouldIncludeGitDiffSummaryFile } from './git.js';
describe('git stash operations', () => {
    function parseStashList(output) {
        const stashes = [];
        const lines = output.split('\n').filter(line => line.trim());
        for (const line of lines) {
            const refMatch = line.match(/^(stash@\{\d+\})/);
            if (!refMatch)
                continue;
            const ref = refMatch[1];
            const restOfLine = line.slice(ref.length + 2);
            let branch = '';
            let message = restOfLine;
            const branchMatch = restOfLine.match(/^(?:On|WIP on)\s+([^:]+):\s*(.*)$/);
            if (branchMatch) {
                branch = branchMatch[1].trim();
                message = branchMatch[2].trim();
            }
            stashes.push({ ref, branch, message });
        }
        return stashes;
    }
    it('parses simple stash list output', () => {
        const output = 'stash@{0}: On main: 快照: 添加新功能';
        const result = parseStashList(output);
        expect(result.length).toBe(1);
        expect(result[0].ref).toBe('stash@{0}');
        expect(result[0].branch).toBe('main');
        expect(result[0].message).toBe('快照: 添加新功能');
    });
    it('parses WIP stash format', () => {
        const output = 'stash@{0}: WIP on feature: test changes';
        const result = parseStashList(output);
        expect(result.length).toBe(1);
        expect(result[0].branch).toBe('feature');
        expect(result[0].message).toBe('test changes');
    });
    it('handles multiple stash entries', () => {
        const output = [
            'stash@{0}: On main: 最新快照',
            'stash@{1}: On main: 旧快照',
        ].join('\n');
        const result = parseStashList(output);
        expect(result.length).toBe(2);
    });
    it('returns empty array for empty output', () => {
        expect(parseStashList('')).toEqual([]);
    });
});
describe('git command validation', () => {
    it('validates workspacePath requirement', () => {
        const validateInput = (body) => {
            if (!body.workspacePath || !String(body.workspacePath).trim()) {
                return { valid: false, error: 'workspacePath is required' };
            }
            return { valid: true };
        };
        expect(validateInput({}).valid).toBe(false);
        expect(validateInput({ workspacePath: '/valid/path' }).valid).toBe(true);
    });
    it('validates stashRef format', () => {
        const isValidStashRef = (ref) => /^stash@\{\d+\}$/.test(ref);
        expect(isValidStashRef('stash@{0}')).toBe(true);
        expect(isValidStashRef('stash@{99}')).toBe(true);
        expect(isValidStashRef('invalid')).toBe(false);
    });
});
describe('git workspace path validation', () => {
    it('accepts existing workspace directories', async () => {
        const workspaceDir = await mkdtemp(path.join(tmpdir(), 'aws-git-workspace-'));
        try {
            await expect(assertGitWorkspacePathAccessible(workspaceDir)).resolves.toBeUndefined();
        }
        finally {
            await rm(workspaceDir, { recursive: true, force: true });
        }
    });
    it('rejects missing workspace paths with a diagnostic error', async () => {
        const missingPath = path.join(tmpdir(), `aws-missing-workspace-${Date.now()}`);
        await expect(assertGitWorkspacePathAccessible(missingPath)).rejects.toThrow('workspace path does not exist');
    });
    it('rejects file paths because git cwd must be a directory', async () => {
        const workspaceDir = await mkdtemp(path.join(tmpdir(), 'aws-git-workspace-file-'));
        const filePath = path.join(workspaceDir, 'workspace.txt');
        try {
            await writeFile(filePath, 'not a directory');
            await expect(assertGitWorkspacePathAccessible(filePath)).rejects.toThrow('workspace path is not a directory');
        }
        finally {
            await rm(workspaceDir, { recursive: true, force: true });
        }
    });
});
describe('git diff summary visibility', () => {
    it('filters ordinary modified files without textual changes', () => {
        expect(shouldIncludeGitDiffSummaryFile('modified', 0, 0, false)).toBe(false);
    });
    it('keeps modified files with text or binary changes', () => {
        expect(shouldIncludeGitDiffSummaryFile('modified', 1, 0, false)).toBe(true);
        expect(shouldIncludeGitDiffSummaryFile('modified', 0, 1, false)).toBe(true);
        expect(shouldIncludeGitDiffSummaryFile('modified', 0, 0, true)).toBe(true);
    });
    it('keeps structural status changes even when line counts are zero', () => {
        expect(shouldIncludeGitDiffSummaryFile('added', 0, 0, false)).toBe(true);
        expect(shouldIncludeGitDiffSummaryFile('deleted', 0, 0, false)).toBe(true);
        expect(shouldIncludeGitDiffSummaryFile('renamed', 0, 0, false)).toBe(true);
    });
});
describe('error handling', () => {
    it('detects "no local changes" error', () => {
        const isNoChangesError = (stderr) => stderr.includes('No local changes to save');
        expect(isNoChangesError('error: No local changes to save')).toBe(true);
        expect(isNoChangesError('other error')).toBe(false);
    });
    it('detects conflict during pop', () => {
        const hasConflict = (stdout, stderr) => stdout.includes('CONFLICT') || stderr.includes('CONFLICT');
        expect(hasConflict('CONFLICT (content): Merge conflict', '')).toBe(true);
        expect(hasConflict('clean merge', '')).toBe(false);
    });
    it('detects invalid stash reference', () => {
        const isInvalidRef = (stderr) => stderr.includes('is not a valid reference');
        expect(isInvalidRef('stash@{99} is not a valid reference')).toBe(true);
        expect(isInvalidRef('other error')).toBe(false);
    });
});
