import { afterEach, describe, expect, it, vi } from 'vitest' afterEach(() => { vi.doUnmock('koffi') vi.resetModules() }) describe.skipIf(process.platform !== 'linux')('Linux libc execve binding', () => { it('preserves inherited stdio, null-terminates argv and envp, and reports execve errno', async () => { const nativeExecve = vi.fn(() => -1) const nativeFcntl = vi.fn((fd: number, command: number) => { if (command === 2) return 0 return [1, 0, 5][fd] }) const func = vi.fn((declaration: string) => declaration.includes('execve') ? nativeExecve : nativeFcntl) const load = vi.fn(() => ({ func })) const errno = vi.fn(() => 2) vi.doMock('koffi', () => ({ default: { errno, load } })) const { loadLinuxExecve } = await import('../src/linux-execve.ts') const execve = loadLinuxExecve() expect(loadLinuxExecve()).toBe(execve) expect(load).toHaveBeenCalledExactlyOnceWith(null) expect(func.mock.calls).toEqual([ ['int execve(const char *pathname, const char **argv, const char **envp)'], ['int fcntl(int fd, int cmd, int arg)'], ]) let failure: unknown try { execve('/missing/tool', ['tool', 'literal arg'], { A: '1', EMPTY: '' }) } catch (error) { failure = error } expect(nativeFcntl.mock.calls).toEqual([ [0, 1, 0], [0, 2, 0], [1, 1, 0], [2, 1, 0], [2, 2, 4], ]) expect(nativeExecve).toHaveBeenCalledExactlyOnceWith( '/missing/tool', ['tool', 'literal arg', null], ['A=1', 'EMPTY=', null], ) expect(errno).toHaveBeenCalledOnce() expect(failure).toMatchObject({ code: 'ENOENT', errno: -2, syscall: 'execve', path: '/missing/tool', }) expect(failure).toBeInstanceOf(Error) expect((failure as Error).message).toContain("ENOENT: no such file or directory, execve '/missing/tool'") }) it('reports failure to read descriptor flags before replacing the process', async () => { const nativeExecve = vi.fn() const nativeFcntl = vi.fn(() => -1) const func = vi.fn((declaration: string) => declaration.includes('execve') ? nativeExecve : nativeFcntl) const errno = vi.fn(() => 9) vi.doMock('koffi', () => ({ default: { errno, load: () => ({ func }) } })) const { loadLinuxExecve } = await import('../src/linux-execve.ts') expect(() => loadLinuxExecve()('/bin/tool', ['tool'], {})).toThrow(expect.objectContaining({ code: 'EBADF', errno: -9, syscall: 'fcntl', })) expect(nativeFcntl).toHaveBeenCalledExactlyOnceWith(0, 1, 0) expect(nativeExecve).not.toHaveBeenCalled() expect(errno).toHaveBeenCalledOnce() }) it('reports failure to clear close-on-exec before replacing the process', async () => { const nativeExecve = vi.fn() const nativeFcntl = vi.fn() .mockReturnValueOnce(1) .mockReturnValueOnce(-1) const func = vi.fn((declaration: string) => declaration.includes('execve') ? nativeExecve : nativeFcntl) const errno = vi.fn(() => 5) vi.doMock('koffi', () => ({ default: { errno, load: () => ({ func }) } })) const { loadLinuxExecve } = await import('../src/linux-execve.ts') expect(() => loadLinuxExecve()('/bin/tool', ['tool'], {})).toThrow(expect.objectContaining({ code: 'EIO', errno: -5, syscall: 'fcntl', })) expect(nativeFcntl.mock.calls).toEqual([ [0, 1, 0], [0, 2, 0], ]) expect(nativeExecve).not.toHaveBeenCalled() expect(errno).toHaveBeenCalledOnce() }) })