import { describe, expect, it } from 'vitest'; import { collectTablesFromSources, listReachableRustFiles, } from './check-spacetime-schema-guard.mjs'; const manifestPath = 'server-rs/crates/spacetime-module/Cargo.toml'; const sourceRoot = 'server-rs/crates/spacetime-module/src'; type SourceFiles = Record; function createSourceReader(files: SourceFiles) { const sources = new Map(Object.entries(files)); return (path: string) => sources.get(path) ?? null; } function collectReachableTables(files: SourceFiles) { const readSource = createSourceReader(files); const paths = listReachableRustFiles(readSource); return { paths, result: collectTablesFromSources( paths.map((path: string) => ({ path, text: readSource(path) ?? '' })), ), }; } function tableSource(structName: string, accessor: string) { return `#[spacetimedb::table(accessor = ${accessor})]\npub struct ${structName} {\n pub id: u64,\n}\n`; } describe('SpacetimeDB schema guard module reachability', () => { it('ignores duplicate accessors in retained but unreachable legacy sources', () => { const activePath = `${sourceRoot}/active.rs`; const shellPath = `${sourceRoot}/legacy_schema/example.rs`; const retiredPath = `${sourceRoot}/example.rs`; const { paths, result } = collectReachableTables({ [manifestPath]: '[lib]\npath = "src/active.rs"\n', [activePath]: '#[path = "legacy_schema/example.rs"]\nmod example;\n', [shellPath]: tableSource('ExampleSchemaShell', 'example'), [retiredPath]: tableSource('RetiredExample', 'example'), }); expect(paths).toEqual([activePath, shellPath]); expect(result.failures).toEqual([]); expect([...result.tables.keys()]).toEqual(['example']); }); it('still rejects duplicate accessors when both definitions are reachable', () => { const activePath = `${sourceRoot}/active.rs`; const firstPath = `${sourceRoot}/first.rs`; const secondPath = `${sourceRoot}/second.rs`; const { result } = collectReachableTables({ [manifestPath]: '[lib]\npath = "src/active.rs"\n', [activePath]: 'mod first;\nmod second;\n', [firstPath]: tableSource('FirstExample', 'example'), [secondPath]: tableSource('SecondExample', 'example'), }); expect(result.failures).toHaveLength(1); expect(result.failures[0]).toMatch(/table accessor example 重复定义/u); }); });