test(windows): close final native coverage gaps

This commit is contained in:
Tianyi Cui
2026-08-09 00:48:46 +08:00
parent d2928584e7
commit 9e724dcad7
11 changed files with 88 additions and 30 deletions

View File

@@ -314,9 +314,10 @@ describe.skipIf(!hasPwsh)('PwshLocalExecutor.start (background process handles)'
env: { BG_VAR: 'bg-env' },
dshEnv: { DSH_BG_VAR: 'bg-dsh-env' },
}))
const output = await readUntil(proc, '[bg-env][bg-dsh-env]')
expect(output).toBe('bg-stdin\n[bg-env][bg-dsh-env]\n')
const partialOutput = await readUntil(proc, '[bg-env][bg-dsh-env]')
await proc.done
const output = partialOutput + lf(proc.readOutput().delta)
expect(output).toBe('bg-stdin\n[bg-env][bg-dsh-env]\n')
expect(proc.exitCode).toBe(0)
})

View File

@@ -4113,11 +4113,12 @@ describe('dynamic nested workspace context injection', () => {
await ctx.plugin(RecordingFileSystem)
await ctx.plugin(workspaceContext, { maxBytes: 65536 })
const fs = ctx.fs as RecordingFileSystem
const agent = stubAgent('/')
const root = resolve('/')
const agent = stubAgent(root)
const failure = new Error('projection failed')
const warn = vi.spyOn(ctx.logger, 'warn').mockImplementation(() => undefined)
fs.entries.set('/.git', { type: 'directory' })
fs.entries.set('/AGENTS.md', { type: 'file', content: 'workspace rule' })
fs.entries.set(join(root, '.git'), { type: 'directory' })
fs.entries.set(join(root, 'AGENTS.md'), { type: 'file', content: 'workspace rule' })
vi.spyOn(agent.inbox, 'prepend').mockImplementationOnce(() => { throw failure })
ctx.emit('tools/result', stubToolExecution({

View File

@@ -22,7 +22,7 @@ import BrowseDirectoryPicker from '@deepseek-ai/dsh-host-directory-picker-browse
import NativeDirectoryPicker from '@deepseek-ai/dsh-host-directory-picker-native'
import * as DirectoryPickerAuto from '../src/index.ts'
const renameControl = vi.hoisted(() => ({ attempts: 0, remainingFailures: 0 }))
const renameControl = vi.hoisted(() => ({ attempts: 0, injectedFailures: 0, remainingFailures: 0 }))
vi.mock('node:fs/promises', async (importOriginal) => {
const actual = await importOriginal<typeof import('node:fs/promises')>()
@@ -32,6 +32,7 @@ vi.mock('node:fs/promises', async (importOriginal) => {
renameControl.attempts++
if (renameControl.remainingFailures > 0) {
renameControl.remainingFailures--
renameControl.injectedFailures++
throw Object.assign(new Error(`transient rename failure for ${newPath}`), { code: 'EPERM' })
}
await actual.rename(oldPath, newPath)
@@ -59,6 +60,7 @@ afterEach(async () => {
root = undefined
fakeBin = undefined
renameControl.attempts = 0
renameControl.injectedFailures = 0
renameControl.remainingFailures = 0
})
@@ -187,6 +189,8 @@ describe('real Loader composition', () => {
expect(entryNames(ctx)).not.toContain(NATIVE)
// Same self-dispose persistence as above: let the write land before teardown.
await expect.poll(async () => await readFile(configPath, 'utf8')).toContain('disabled: true')
expect(renameControl.attempts).toBe(2)
expect(renameControl.injectedFailures).toBe(1)
expect(renameControl.remainingFailures).toBe(0)
expect(renameControl.attempts).toBeGreaterThanOrEqual(2)
})
})

View File

@@ -272,7 +272,7 @@ describe('PiAiAdapter provider routing', () => {
await Promise.race([
server.responseClosed,
new Promise<never>((_resolve, reject) => {
setTimeout(() => { reject(new Error('SDK request did not close after idle timeout')) }, 100)
setTimeout(() => { reject(new Error('SDK request did not close after idle timeout')) }, 1_000)
}),
])

View File

@@ -38,9 +38,9 @@ describe('lsp-local provider resolution', () => {
// A tiny executable script placed on a custom PATH dir: the load-time resolver must find it.
const bin = join(root, 'bin')
await mkdir(bin)
const exe = join(bin, 'fake-lsp')
await writeFile(exe, '#!/bin/sh\nexit 0\n')
await chmod(exe, 0o755)
const exe = join(bin, process.platform === 'win32' ? 'fake-lsp.cmd' : 'fake-lsp')
await writeFile(exe, process.platform === 'win32' ? '@exit /b 0\r\n' : '#!/bin/sh\nexit 0\n')
if (process.platform !== 'win32') await chmod(exe, 0o755)
const ctx = new Context()
await ctx.plugin(Lsp)
@@ -49,7 +49,7 @@ describe('lsp-local provider resolution', () => {
await expect(ctx.plugin(LspLocal, config('onpath', {
command: 'fake-lsp',
args: [],
env: { PATH: bin },
env: { PATH: bin, ...process.platform === 'win32' ? { PATHEXT: '.CMD' } : {} },
extensionToLanguage: { '.ts': 'typescript' },
}))).resolves.toBeDefined()
await ctx.fiber.dispose()

View File

@@ -55,7 +55,7 @@ describe('renderUri', () => {
it('returns an absolute path for a file: URI outside the workspace', () => {
const outside = resolve(WS, '..', 'other', 'lib', 'b.ts')
const uri = pathToFileURL(outside).href
expect(renderUri(uri, WS_URI)).toBe(outside)
expect(renderUri(uri, WS_URI)).toBe(outside.replaceAll('\\', '/'))
})
it('renders the workspace root itself as "."', () => {
@@ -83,7 +83,7 @@ describe('renderUri', () => {
})
it('preserves backslashes as ordinary POSIX filename characters', () => {
expect(renderUri('file:///home/u/proj/dir%5Cname/a.ts', WS_URI)).toBe('dir\\name/a.ts')
expect(renderUri('file:///home/u/proj/dir%5Cname/a.ts', 'file:///home/u/proj')).toBe('dir\\name/a.ts')
})
it('keeps malformed or mismatched URI coordinates verbatim', () => {

View File

@@ -174,18 +174,32 @@ describe('real @openai/codex 0.147.0 product', () => {
}, 60_000)
it('cancels a real app-server command approval without executing the command', async () => {
const { harness, fixture } = await realHarness([
const command = process.platform === 'win32'
? 'cmd /c type nul > approval-side-effect'
: 'touch approval-side-effect'
const commandCalls = [
{
kind: 'functionCall',
name: 'exec_command',
arguments: {
cmd: process.platform === 'win32'
? 'cmd /c type nul > approval-side-effect'
: 'touch approval-side-effect',
cmd: command,
sandbox_permissions: 'require_escalated',
justification: 'exercise the unattended approval boundary',
},
},
{
name: 'shell_command',
arguments: {
command,
sandbox_permissions: 'require_escalated',
justification: 'exercise the unattended approval boundary',
},
},
] as const
const { harness, fixture } = await realHarness([
{
kind: 'advertisedFunctionCall',
choices: commandCalls,
},
])
const sideEffect = join(harness.workspace, 'approval-side-effect')
const run = await harness.ctx.subagents.start('codex', {
@@ -202,9 +216,9 @@ describe('real @openai/codex 0.147.0 product', () => {
expect(existsSync(sideEffect)).toBe(false)
expect(fixture.requests).toHaveLength(1)
const tools = fixture.requests[0]!.body.tools as Array<Record<string, unknown>>
expect(tools).toEqual(expect.arrayContaining([
expect.objectContaining({ type: 'function', name: 'exec_command' }),
]))
expect(commandCalls.some(call => tools.some(tool => (
tool.type === 'function' && tool.name === call.name
)))).toBe(true)
expect(fixture.requests.every(requestEntry =>
requestEntry.headers.authorization === 'Bearer dsh-fake-openai-key',
)).toBe(true)

View File

@@ -22,6 +22,13 @@ export type ResponsesBehavior =
readonly name: string
readonly arguments: Record<string, unknown>
}
| {
readonly kind: 'advertisedFunctionCall'
readonly choices: readonly {
readonly name: string
readonly arguments: Record<string, unknown>
}[]
}
| { readonly kind: 'hold' }
/** Running package-private Responses fixture. */
@@ -218,6 +225,18 @@ function closeServer(server: Server): Promise<void> {
})
}
function advertisedFunctionNames(body: Record<string, unknown>): Set<string> {
if (!Array.isArray(body.tools)) return new Set()
return new Set(body.tools.flatMap((tool): string[] => (
tool !== null
&& typeof tool === 'object'
&& (tool as Record<string, unknown>).type === 'function'
&& typeof (tool as Record<string, unknown>).name === 'string'
? [(tool as Record<string, unknown>).name as string]
: []
)))
}
/**
* Start a loopback-only Responses SSE fixture.
* @param script - one behavior per expected Responses request.
@@ -234,11 +253,12 @@ export async function startResponsesFixture(
openResponses.add(response)
response.on('close', () => { openResponses.delete(response) })
void readRequest(request).then((body) => {
const parsedBody = JSON.parse(body) as Record<string, unknown>
requests.push({
method: request.method,
path: request.url,
headers: request.headers,
body: JSON.parse(body) as Record<string, unknown>,
body: parsedBody,
})
started.resolve(undefined)
const behavior = behaviors.shift()
@@ -247,6 +267,14 @@ export async function startResponsesFixture(
response.end(JSON.stringify({ error: { message: 'fixture script exhausted' } }))
return
}
const advertisedCall = behavior.kind === 'advertisedFunctionCall'
? behavior.choices.find(choice => advertisedFunctionNames(parsedBody).has(choice.name))
: undefined
if (behavior.kind === 'advertisedFunctionCall' && advertisedCall === undefined) {
response.writeHead(500, { 'content-type': 'application/json' })
response.end(JSON.stringify({ error: { message: 'none of the fixture function calls was advertised' } }))
return
}
response.writeHead(200, {
'content-type': 'text/event-stream',
'cache-control': 'no-cache',
@@ -254,9 +282,15 @@ export async function startResponsesFixture(
'x-request-id': 'req_fixture',
})
if (behavior.kind === 'hold') return
const events = behavior.kind === 'complete'
? completeResponsesEvents(behavior.text)
: functionCallEvents(behavior.name, behavior.arguments)
let events: Record<string, unknown>[]
if (behavior.kind === 'complete') {
events = completeResponsesEvents(behavior.text)
} else {
const call = behavior.kind === 'functionCall'
? behavior
: advertisedCall!
events = functionCallEvents(call.name, call.arguments)
}
for (const event of events) {
response.write(`data: ${JSON.stringify(event)}\n\n`)
}