94 lines
4.8 KiB
TypeScript
94 lines
4.8 KiB
TypeScript
import type { BlockView } from '../blockView'
|
|
import { describe, expect, it } from 'vitest'
|
|
import { toBlockViews } from '../blockView'
|
|
import { createPythonAdapter } from '../languages/python'
|
|
import { WASM_DIR, withBlocks } from '../testSupport'
|
|
import { BlockAnchors } from './anchor'
|
|
|
|
const py = createPythonAdapter(WASM_DIR)
|
|
|
|
function views(source: string): Promise<BlockView[]> {
|
|
return withBlocks(py, 'python', source, blocks => toBlockViews(blocks, { source, language: py, markers: [] }, undefined))
|
|
}
|
|
|
|
function flatten(list: BlockView[]): BlockView[] {
|
|
return list.flatMap(view => [view, ...flatten(view.children)])
|
|
}
|
|
|
|
/** 各块的记号,按源码先后,连同它这块的第一行源码 */
|
|
async function anchors(source: string): Promise<[string, string][]> {
|
|
return flatten(await views(source)).map(view => [view.anchor, view.code.split('\n')[0]])
|
|
}
|
|
|
|
const SOURCE = `class ReferralRelation(Base):
|
|
def display(self):
|
|
if self.active:
|
|
return self.name
|
|
return "none"
|
|
|
|
def other(self):
|
|
if self.active:
|
|
return 1
|
|
|
|
|
|
def helper(x):
|
|
print(x)
|
|
print(x)
|
|
`
|
|
|
|
describe('块的位置记号', () => {
|
|
it('有名字的块是外层各个有名字的块加自己的种类和名字;没名字的块是外层最近的有名字的块加种类和源码哈希;同一层重复的依次编号', async () => {
|
|
const list = await anchors(SOURCE)
|
|
const hashed = (anchor: string): string => anchor.replace(/@[0-9a-f]{8}/g, '@#')
|
|
expect(list.map(([anchor, code]) => [hashed(anchor), code])).toEqual([
|
|
['class ReferralRelation', 'class ReferralRelation(Base):'],
|
|
['class ReferralRelation > function display', 'def display(self):'],
|
|
['class ReferralRelation > function display > if @#', 'if self.active:'],
|
|
['class ReferralRelation > function display > return @#', 'return self.name'],
|
|
['class ReferralRelation > function display > return @#', 'return "none"'],
|
|
['class ReferralRelation > function other', 'def other(self):'],
|
|
['class ReferralRelation > function other > if @#', 'if self.active:'],
|
|
['class ReferralRelation > function other > return @#', 'return 1'],
|
|
['function helper', 'def helper(x):'],
|
|
['function helper > statement @#', 'print(x)'],
|
|
['function helper > statement @#[1]', 'print(x)'],
|
|
])
|
|
// 两个函数里一模一样的条件各在各的函数下面,互不影响;源码不同的两个返回哈希不同
|
|
expect(list[2][0].split(' > ').at(-1)).toBe(list[6][0].split(' > ').at(-1))
|
|
expect(list[3][0]).not.toBe(list[4][0])
|
|
expect(new Set(list.map(([anchor]) => anchor)).size).toBe(list.length)
|
|
})
|
|
|
|
it('上面插几行、改缩进和空白:记号都不变', async () => {
|
|
const before = await anchors(SOURCE)
|
|
const after = await anchors(`import os\n\n# 新加的注释\n${SOURCE.replace('print(x)\n print(x)', 'print( x )\n print(x)')}`)
|
|
const shifted = after.filter(([anchor]) => before.some(([old]) => old === anchor))
|
|
expect(shifted.map(([anchor]) => anchor)).toEqual(before.map(([anchor]) => anchor))
|
|
})
|
|
|
|
it('改别的函数的名字:别处的记号不变,改名的函数和它里面的块换了记号', async () => {
|
|
const before = new Set((await anchors(SOURCE)).map(([anchor]) => anchor))
|
|
const after = (await anchors(SOURCE.replace('def other(self)', 'def renamed(self)'))).map(([anchor]) => anchor)
|
|
const kept = after.filter(anchor => before.has(anchor))
|
|
expect(kept).toEqual([...before].filter(anchor => !anchor.includes('function other')))
|
|
expect(after.filter(anchor => !before.has(anchor)).every(anchor => anchor.includes('function renamed'))).toBe(true)
|
|
})
|
|
|
|
it('没名字的块自己的源码改了:记号变了,旧问答认不回来;有名字的块改了主体、签名照样认得', async () => {
|
|
const before = await anchors(SOURCE)
|
|
const after = await anchors(SOURCE.replace('if self.active:\n return self.name', 'if self.visible:\n return self.name').replace('def helper(x):', 'def helper(x, y=1):'))
|
|
const anchorOf = (list: [string, string][], code: string): string | undefined => list.find(([, line]) => line === code)?.[0]
|
|
expect(after.map(([anchor]) => anchor)).not.toContain(anchorOf(before, 'if self.active:'))
|
|
expect(anchorOf(after, 'return self.name')).toBe(anchorOf(before, 'return self.name'))
|
|
expect(anchorOf(after, 'def helper(x, y=1):')).toBe(anchorOf(before, 'def helper(x):'))
|
|
})
|
|
|
|
it('名字里的空白压成一个空格,空名字按没名字算', () => {
|
|
const anchors = new BlockAnchors()
|
|
expect(anchors.place('', 'variable', '{\n a,\n b\n}', '').anchor).toBe('variable { a, b }')
|
|
const unnamed = anchors.place('scope', 'statement', ' ', 'x = 1')
|
|
expect(unnamed.anchor).toMatch(/^scope > statement @[0-9a-f]{8}$/)
|
|
expect(unnamed.inner).toBe('scope')
|
|
})
|
|
})
|