import type { BlockView } from '../blockView' import { describe, expect, it } from 'vitest' import { toBlockViews } from '../blockView' import { blockMarks } from '../diff/viewDiff' import { rustImplRule } from '../rules/rustImpl' import { readFixture, viewLines, WASM_DIR, withBlocks } from '../testSupport' import { rustZhTranslator } from '../translators/rustZh' import { createRustAdapter } from './rust' const adapter = createRustAdapter(WASM_DIR) const sample = readFixture('rustLang.rs') function views(source: string): Promise { return withBlocks(adapter, 'rust', source, blocks => toBlockViews(blocks, { source, language: adapter, markers: [] }, rustZhTranslator, { rules: [rustImplRule], report: () => {}, })) } function card(list: BlockView[], kind: string): BlockView { const found = list.find(block => block.kind === kind) if (!found) throw new Error(`没有 ${kind}`) return found } describe('rust 语言卡片', () => { it('use、结构体、枚举、实现、函数、特质', async () => { expect(viewLines(await views(sample))).toEqual([ 'import 1', ' 来源: serde', ' 导入项: 1 个', ' Serialize | —', 'import 2', ' 来源: std::sync', ' 导入项: 1 个', ' Arc | —', 'import 3', ' 来源: foo', ' 导入项: 2 个', ' Bar | Baz', ' Qux | —', 'class 5', ' 名称: AgentRow', ' 说明: 桌面端列表里的一行代理。', ' 可见性: 公开', ' 字段: 2 个', ' id | Uuid | 公开', ' name | String | 本模块', 'class 12', ' 名称: CrateOnly', ' 可见性: 本 crate', ' 字段: 1 个', ' up | u8 | 父模块', 'enum 16', ' 名称: AgentState', ' 说明: 这个代理现在处在哪一步。', ' 变体: 3 个', ' Idle | —', ' Running | { pid: u32 }', ' Failed | String', 'rust.impl 23', ' 名称: AgentRow 的方法', ' 方法: 1 个', ' rename | &mut self, name: String | ()', ' function 24', ' 名称: rename', ' 可见性: 本模块', ' 参数: 2 个', ' self | &mut self', ' name | String', ' 返回: ()', 'function 27', ' 名称: start_server', ' 说明: 在本机拉起接口服务。', ' 异步: 是', ' 可见性: 公开', ' 输入参数: 1 个', ' addr | SocketAddr', ' 返回: Result<(), StartError>', ' 分情况: 2 支', ' Ok(listener) | 记下监听地址', ' Err(err) | 返回 StartError', 'trait 41', ' 名称: Store', ' 说明: 按 id 读写代理。', ' 方法: 2 个', ' get | &self, id: Uuid | Result', ' save | &mut self, row: AgentRow | Result<(), StoreError>', ]) }) it('实现的方法放进方法表那一行', async () => { const impl = card(await views(sample), 'rust.impl') const [method] = impl.children expect(method?.slot).toEqual({ row: 1, item: 0 }) }) it('给结构体加一个字段,多出来的那一行标成新增', async () => { const before = 'pub struct AgentRow {\n name: String,\n}\n' const after = 'pub struct AgentRow {\n name: String,\n id: Uuid,\n}\n' const [oldCard] = await views(before) const [newCard] = await views(after) const marks = oldCard && newCard ? blockMarks(oldCard, newCard) : undefined const field = newCard && 'properties' in newCard ? newCard.properties.findIndex(row => row.label === '字段') : -1 expect(field).toBeGreaterThanOrEqual(0) expect(marks?.rows?.changed[field]).toEqual({ items: { changed: { 1: { added: true } }, removed: [] }, }) }) it('带身体的模块拆成子块,常量和外部函数是卡片', async () => { const source = [ '/// 平台相关。', 'pub mod platform {', ' /// 读入。', ' use std::io::Read;', ' /// 上限。', ' pub const LIMIT: u32 = 8;', ' static NAME: &str = "a";', ' pub fn open() -> u32 { LIMIT }', ' extern "C" {', ' /// 外部。', ' pub fn bar(x: i32) -> i32;', ' }', ' let local = 1;', ' println!("hi");', '}', 'mod other;', '', 'impl Agent {', ' pub const N: u8 = 2;', '}', '', ].join('\n') const list = await views(source) const mod = list.find(block => block.kind === 'module') expect(mod?.kind).toBe('module') expect(list.some(block => block.kind === 'statement' && block.code.includes('const LIMIT'))).toBe(false) expect(list.filter(block => block.kind === 'statement').map(block => block.code)).toEqual(['mod other;']) expect(mod?.children.map(block => block.kind)).toEqual(['import', 'const', 'variable', 'function', 'function', 'statement', 'statement']) expect(viewLines(mod ? [mod] : [])).toEqual([ 'module 1', ' 名称: platform', ' 说明: 平台相关。', ' 可见性: 公开', ' import 3', ' 来源: std::io', ' 导入项: 1 个', ' Read | —', ' const 5', ' 名称: LIMIT', ' 说明: 上限。', ' 访问级别: 公共', ' 类型: u32', ' 值: 8', ' variable 7', ' 名称: NAME', ' 类型: &str', ' 初始值: "a"', ' function 8', ' 名称: open', ' 可见性: 公开', ' 返回: u32', ' function 10', ' 名称: bar', ' 说明: 外部。', ' 可见性: 公开', ' 输入参数: 1 个', ' x | i32', ' 返回: i32', ' statement 13: 令 local = 1;', ' statement 14: println!("hi")', ]) const impl = list.find(block => block.kind === 'rust.impl') const inner = impl?.children.find(block => block.kind === 'const') expect(inner?.kind).toBe('const') expect(viewLines(inner ? [inner] : []).join('\n')).toContain('名称: N') expect(viewLines(inner ? [inner] : []).join('\n')).toMatch(/类型: u8|值: 2/) }) })