Files
superwork/vscode/src/codeReader/qa/pathAskPrompt.test.ts
T

100 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from 'vitest'
import { headLines } from './pathAskContext'
import { PATH_ASK_HEAD_LINES, pathAskFollowUp, pathAskPrompt } from './pathAskPrompt'
const FILE = 'app/[[...section]]/page.tsx'
const FOLDER = 'app/[[...section]]'
describe('问路径时发给模型的话', () => {
it('文件:写明是文件,带相对路径和开头', () => {
const prompt = pathAskPrompt({
kind: 'file',
path: FILE,
head: { lines: ['export default function Page() {', ' return null', '}'], truncated: false },
}, '这个名字是什么意思')
expect(prompt).toContain(`这是一个文件,相对路径:${FILE}`)
expect(prompt).toContain('1 | export default function Page() {')
expect(prompt).toContain('3 | }')
expect(prompt).toContain('问题:这个名字是什么意思')
expect(prompt).toContain('只读,不要改任何东西')
expect(prompt).not.toContain('剩下的需要时自己读')
})
it('文件开头超过上限时说明只贴了开头,相对路径仍在', () => {
const lines = Array.from({ length: PATH_ASK_HEAD_LINES }, (_, index) => `line ${index}`)
const prompt = pathAskPrompt({
kind: 'file',
path: FILE,
head: { lines, truncated: true },
}, '?')
expect(prompt).toContain(`这是一个文件,相对路径:${FILE}`)
expect(prompt).toContain(`上面只贴了开头 ${PATH_ASK_HEAD_LINES} 行`)
expect(prompt).toContain(`80 | line ${PATH_ASK_HEAD_LINES - 1}`)
expect(prompt).not.toContain('line 80')
})
it('工作区外的库文件:写明在项目外、给绝对路径(相对路径它读不到)', () => {
const library = '/Users/me/.local/share/uv/python/cpython-3.12/lib/python3.12/pathlib.py'
const prompt = pathAskPrompt({ kind: 'file', path: library, outside: true, head: { lines: ['"""Object-oriented filesystem paths."""'], truncated: true } }, 'rglob 怎么实现的')
expect(prompt).toContain(`这是项目外的一个文件(比如依赖库的源码),绝对路径:${library}`)
expect(prompt).not.toContain('相对路径:')
})
it('文件夹:写明是文件夹,带相对路径,只列这一层的名字', () => {
const prompt = pathAskPrompt({
kind: 'folder',
path: FOLDER,
children: [
{ name: 'components', kind: 'folder' },
{ name: 'page.tsx', kind: 'file' },
],
}, '[[...section]] 是啥意思')
expect(prompt).toContain(`这是一个文件夹,相对路径:${FOLDER}`)
expect(prompt).toContain('- 文件夹 components\n- 文件 page.tsx')
expect(prompt).toContain('只列了这一层的名字')
expect(prompt).toContain('问题:[[...section]] 是啥意思')
expect(prompt).not.toContain('export default')
})
})
describe('问路径时回答里的代码位置', () => {
it('在 git 仓库里:要求写成从仓库根算起的链接,带例子;接着问时再说一遍', () => {
const subject = { kind: 'folder' as const, path: FOLDER, repoRoot: '/work/shop', children: [] }
const prompt = pathAskPrompt(subject, '这里放什么')
expect(prompt).toContain('提到代码位置时写成 Markdown 链接,点了能跳过去。路径从仓库根 /work/shop 算起,开头不带 / 或 ./:')
expect(prompt).toContain('[文件名:起-止](路径#L起-L止)')
expect(prompt).toContain('例如:[OrderService.cancel](backend/app/orders/service.py#OrderService.cancel)')
expect(prompt).not.toContain('提到文件时写相对项目根目录的路径')
const followUp = pathAskFollowUp(subject, '再说说')
expect(followUp).toMatch(/^接着问(还是 app\/\[\[\.\.\.section\]\] 这个文件夹,需要时重新读):再说说\n\n提到代码位置时写成 Markdown 链接/)
})
it('不在 git 仓库里(库源码):写行内代码的绝对路径,不写链接', () => {
const library = '/Users/me/.local/share/uv/python/cpython-3.12/lib/python3.12/pathlib.py'
const prompt = pathAskPrompt({ kind: 'file', path: library, outside: true, head: { lines: [], truncated: false } }, '?')
expect(prompt).toContain('问的代码不在 git 仓库里,提到代码位置时写行内代码:绝对路径加行号')
expect(prompt).not.toContain('Markdown 链接')
})
})
describe('文件开头截取', () => {
it('超过行数上限时只留前 80 行,并标明没贴完', () => {
const text = Array.from({ length: 100 }, (_, index) => `L${index}`).join('\n')
expect(headLines(text, false, PATH_ASK_HEAD_LINES)).toEqual({
lines: Array.from({ length: PATH_ASK_HEAD_LINES }, (_, index) => `L${index}`),
truncated: true,
})
})
it('字节没读完时丢掉被截断的最后一行', () => {
expect(headLines('alpha\nbeta-cut', true, PATH_ASK_HEAD_LINES)).toEqual({
lines: ['alpha'],
truncated: true,
})
})
it('空文件没有行', () => {
expect(headLines('', false, PATH_ASK_HEAD_LINES)).toEqual({ lines: [], truncated: false })
})
})