/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { describe, it, expect, vi, afterEach, beforeEach, } from 'vitest';
import { getIdeProcessInfo } from './process-utils.js';
import os from 'node:os';
const mockedExec = vi.hoisted(() => vi.fn());
vi.mock('node:util', () => ({
    promisify: vi.fn().mockReturnValue(mockedExec),
}));
vi.mock('node:os', () => ({
    default: {
        platform: vi.fn(),
    },
}));
describe('getIdeProcessInfo', () => {
    beforeEach(() => {
        Object.defineProperty(process, 'pid', { value: 1000, configurable: true });
        mockedExec.mockReset();
    });
    afterEach(() => {
        vi.restoreAllMocks();
    });
    describe('on Unix', () => {
        it('should traverse up to find the shell and return grandparent process info', async () => {
            os.platform.mockReturnValue('linux');
            // process (1000) -> shell (800) -> IDE (700)
            mockedExec
                .mockResolvedValueOnce({ stdout: '800 /bin/bash' }) // pid 1000 -> ppid 800 (shell)
                .mockResolvedValueOnce({ stdout: '700 /usr/lib/vscode/code' }) // pid 800 -> ppid 700 (IDE)
                .mockResolvedValueOnce({ stdout: '700 /usr/lib/vscode/code' }); // get command for pid 700
            const result = await getIdeProcessInfo();
            expect(result).toEqual({ pid: 700, command: '/usr/lib/vscode/code' });
        });
        it('should return parent process info if grandparent lookup fails', async () => {
            os.platform.mockReturnValue('linux');
            mockedExec
                .mockResolvedValueOnce({ stdout: '800 /bin/bash' }) // pid 1000 -> ppid 800 (shell)
                .mockRejectedValueOnce(new Error('ps failed')) // lookup for ppid of 800 fails
                .mockResolvedValueOnce({ stdout: '800 /bin/bash' }); // get command for pid 800
            const result = await getIdeProcessInfo();
            expect(result).toEqual({ pid: 800, command: '/bin/bash' });
        });
    });
    describe('on Windows', () => {
        it('should traverse up and find the great-grandchild of the root process', async () => {
            os.platform.mockReturnValue('win32');
            // process (1000) -> powershell (900) -> code (800) -> wininit (700) -> root (0)
            // Ancestors: [1000, 900, 800, 700]
            // Target (great-grandchild of root): 900
            const processes = [
                {
                    ProcessId: 1000,
                    ParentProcessId: 900,
                    Name: 'node.exe',
                    CommandLine: 'node.exe',
                },
                {
                    ProcessId: 900,
                    ParentProcessId: 800,
                    Name: 'powershell.exe',
                    CommandLine: 'powershell.exe',
                },
                {
                    ProcessId: 800,
                    ParentProcessId: 700,
                    Name: 'code.exe',
                    CommandLine: 'code.exe',
                },
                {
                    ProcessId: 700,
                    ParentProcessId: 0,
                    Name: 'wininit.exe',
                    CommandLine: 'wininit.exe',
                },
            ];
            mockedExec.mockResolvedValueOnce({ stdout: JSON.stringify(processes) });
            const result = await getIdeProcessInfo();
            expect(result).toEqual({ pid: 900, command: 'powershell.exe' });
            expect(mockedExec).toHaveBeenCalledWith(expect.stringContaining('Get-CimInstance Win32_Process'), expect.anything());
        });
        it('should handle short process chains', async () => {
            os.platform.mockReturnValue('win32');
            // process (1000) -> root (0)
            const processes = [
                {
                    ProcessId: 1000,
                    ParentProcessId: 0,
                    Name: 'node.exe',
                    CommandLine: 'node.exe',
                },
            ];
            mockedExec.mockResolvedValueOnce({ stdout: JSON.stringify(processes) });
            const result = await getIdeProcessInfo();
            expect(result).toEqual({ pid: 1000, command: 'node.exe' });
        });
        it('should handle PowerShell failure gracefully', async () => {
            os.platform.mockReturnValue('win32');
            mockedExec.mockRejectedValueOnce(new Error('PowerShell failed'));
            // Fallback to getProcessInfo for current PID
            mockedExec.mockResolvedValueOnce({ stdout: '' }); // ps command fails on windows
            const result = await getIdeProcessInfo();
            expect(result).toEqual({ pid: 1000, command: '' });
        });
        it('should handle malformed JSON output gracefully', async () => {
            os.platform.mockReturnValue('win32');
            mockedExec.mockResolvedValueOnce({ stdout: '{"invalid":json}' });
            // Fallback to getProcessInfo for current PID
            mockedExec.mockResolvedValueOnce({ stdout: '' });
            const result = await getIdeProcessInfo();
            expect(result).toEqual({ pid: 1000, command: '' });
        });
        it('should handle single process output from ConvertTo-Json', async () => {
            os.platform.mockReturnValue('win32');
            const process = {
                ProcessId: 1000,
                ParentProcessId: 0,
                Name: 'node.exe',
                CommandLine: 'node.exe',
            };
            mockedExec.mockResolvedValueOnce({ stdout: JSON.stringify(process) });
            const result = await getIdeProcessInfo();
            expect(result).toEqual({ pid: 1000, command: 'node.exe' });
        });
        it('should handle missing process in map during traversal', async () => {
            os.platform.mockReturnValue('win32');
            // process (1000) -> parent (900) -> missing (800)
            const processes = [
                {
                    ProcessId: 1000,
                    ParentProcessId: 900,
                    Name: 'node.exe',
                    CommandLine: 'node.exe',
                },
                {
                    ProcessId: 900,
                    ParentProcessId: 800,
                    Name: 'parent.exe',
                    CommandLine: 'parent.exe',
                },
            ];
            mockedExec.mockResolvedValueOnce({ stdout: JSON.stringify(processes) });
            const result = await getIdeProcessInfo();
            // Ancestors: [1000, 900]. Length < 3, returns last (900)
            expect(result).toEqual({ pid: 900, command: 'parent.exe' });
        });
    });
});
//# sourceMappingURL=process-utils.test.js.map