GitNexus/gitnexus/test/unit/schema.test.ts
zwxxb 282d82f1e0 refactor(move): simplify & harden the Move integration architecture (reduced scope)
Trimmed rebuild of 6ea5aa44 (fork PR #4): Move core (gitnexus/src/core/move/)
and Move tests, plus the functional minimum elsewhere.

Dropped from the original commit:
- .gitignore .codex/ entry (unrelated)
- cli/analyze.ts env-constant swap (cosmetic; same string literal)
- core/logger.ts warnRespectingProgressBar extraction and the
  filesystem-walker.ts reuse of it (Move code never imports the helper)
- scope-resolution callable-value-flow warning aggregation and pipeline/run.ts
  progress-warning formatting, with their two tests (warning-UX hardening,
  not Move-functional)
- process-detection interface doc-comment retuning (DEFAULT_CONFIG runtime
  values already match upstream; region left byte-identical to upstream)

Kept outside src/core/move/ and Move tests (one line each):
- gitnexus-shared/src/graph/types.ts: 'external' locationFidelity for
  dependency symbols
- gitnexus-shared/src/lbug/schema-constants.ts: 'Type' node table registration
- core/lbug/schema.ts: Type table schema + Move rel-table endpoint pairs
- core/lbug/node-table-layout.ts: TYPE_LAYOUT CSV layout
- core/lbug/csv-generator.ts: 'Type' in MULTI_LANG_TYPES routing
- core/lbug/lbug-adapter.ts: deleteAllExternalNodes + shared delete-by-label
  mechanics; Type backtick entry
- core/incremental/subgraph-extract.ts: external nodes get the
  delete-all-then-rebuild treatment
- core/run-analyze.ts: Move consistency digest to meta.json;
  deleteAllExternalNodes call; grouped Move meta; finally-based shutdown
- storage/repo-manager.ts: moveConsistency in RepoMeta;
  INCREMENTAL_SCHEMA_VERSION 13 (Type/EnumVariant persistence)
- core/ingestion/pipeline.ts: generic TStandaloneIngest output threading
- types/pipeline.ts: PipelineResult.standaloneIngest replaces ingestWarnings
- core/ingestion/process-processor.ts: ENTRY_POINT_OF explicit graph roots
- tests: schema, node-table-layout, process-processor,
  repo-manager-reconcile, call-summary-schema-version,
  incremental-subgraph-extract, run-analyze-fts-repair (unit);
  lbug-core-adapter (integration)

Gates: tsc clean; Move unit 185/185; full unit suite green except three
pre-existing Darwin-environment failures reproduced on the pristine base;
integration (move + lbug-core-adapter) 29/29.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 18:58:03 +02:00

296 lines
9.8 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import {
NODE_TABLES,
REL_TABLE_NAME,
REL_TYPES,
EMBEDDING_TABLE_NAME,
NODE_SCHEMA_QUERIES,
REL_SCHEMA_QUERIES,
SCHEMA_QUERIES,
FILE_SCHEMA,
FOLDER_SCHEMA,
FUNCTION_SCHEMA,
CLASS_SCHEMA,
INTERFACE_SCHEMA,
METHOD_SCHEMA,
PROPERTY_SCHEMA,
TYPE_SCHEMA,
CODE_ELEMENT_SCHEMA,
COMMUNITY_SCHEMA,
PROCESS_SCHEMA,
BASICBLOCK_SCHEMA,
RELATION_SCHEMA,
EMBEDDING_SCHEMA,
CREATE_VECTOR_INDEX_QUERY,
} from '../../src/core/lbug/schema.js';
describe('LadybugDB Schema', () => {
describe('NODE_TABLES', () => {
it('includes all core node types', () => {
const core = [
'File',
'Folder',
'Function',
'Class',
'Interface',
'Method',
'CodeElement',
'Community',
'Process',
];
for (const t of core) {
expect(NODE_TABLES).toContain(t);
}
});
it('includes multi-language node types', () => {
const multiLang = [
'Struct',
'Enum',
'EnumVariant',
'Macro',
'Typedef',
'Union',
'Namespace',
'Trait',
'Impl',
'TypeAlias',
'Type',
'Const',
'Static',
'Variable',
'Property',
'Record',
'Delegate',
'Annotation',
'Constructor',
'Template',
'Module',
];
for (const t of multiLang) {
expect(NODE_TABLES).toContain(t);
}
});
it('includes the BasicBlock taint/PDG substrate node (issue #2080)', () => {
expect(NODE_TABLES).toContain('BasicBlock');
});
it('has expected total count', () => {
// 10 core (including Section) + 21 multi-language/Move + Route + Tool + BasicBlock = 34
expect(NODE_TABLES).toHaveLength(34);
});
});
describe('REL_TYPES', () => {
it('includes all expected relationship types', () => {
const expected = [
'CONTAINS',
'DEFINES',
'IMPORTS',
'CALLS',
'EXTENDS',
'IMPLEMENTS',
'MEMBER_OF',
'STEP_IN_PROCESS',
'FRIEND_OF',
'READS_RESOURCE',
'WRITES_RESOURCE',
'ACQUIRES',
'USES_TYPE',
'EMITS',
];
for (const t of expected) {
expect(REL_TYPES).toContain(t);
}
});
it('includes the taint/PDG substrate edge types (issue #2080)', () => {
for (const t of ['CFG', 'REACHING_DEF', 'TAINTED', 'SANITIZES', 'TAINT_PATH']) {
expect(REL_TYPES).toContain(t);
}
});
it('includes the control-dependence edge types (issue #2085 M5)', () => {
for (const t of ['CDG', 'POST_DOMINATE']) {
expect(REL_TYPES).toContain(t);
}
});
it('includes the DI collection-injection edge type (#2200)', () => {
expect(REL_TYPES).toContain('INJECTS');
});
});
describe('node schema DDL', () => {
it.each([
['FILE_SCHEMA', FILE_SCHEMA, 'File'],
['FOLDER_SCHEMA', FOLDER_SCHEMA, 'Folder'],
['FUNCTION_SCHEMA', FUNCTION_SCHEMA, 'Function'],
['CLASS_SCHEMA', CLASS_SCHEMA, 'Class'],
['INTERFACE_SCHEMA', INTERFACE_SCHEMA, 'Interface'],
['METHOD_SCHEMA', METHOD_SCHEMA, 'Method'],
['CODE_ELEMENT_SCHEMA', CODE_ELEMENT_SCHEMA, 'CodeElement'],
['COMMUNITY_SCHEMA', COMMUNITY_SCHEMA, 'Community'],
['PROCESS_SCHEMA', PROCESS_SCHEMA, 'Process'],
])('%s contains CREATE NODE TABLE for %s', (_, schema, tableName) => {
expect(schema).toContain('CREATE NODE TABLE');
expect(schema).toContain(tableName);
expect(schema).toContain('PRIMARY KEY');
});
it('Function schema has startLine and endLine', () => {
expect(FUNCTION_SCHEMA).toContain('startLine INT64');
expect(FUNCTION_SCHEMA).toContain('endLine INT64');
});
it('Function schema has isExported', () => {
expect(FUNCTION_SCHEMA).toContain('isExported BOOLEAN');
});
it('Property schema preserves declaredType', () => {
expect(SCHEMA_QUERIES).toContain(PROPERTY_SCHEMA);
expect(PROPERTY_SCHEMA).toContain('declaredType STRING');
});
it('Type schema preserves Move dependency identity and location fidelity', () => {
expect(SCHEMA_QUERIES).toContain(TYPE_SCHEMA);
expect(TYPE_SCHEMA).toContain('qualifiedName STRING');
expect(TYPE_SCHEMA).toContain('moduleQualifiedName STRING');
expect(TYPE_SCHEMA).toContain('locationFidelity STRING');
});
it('BasicBlock schema is wired into SCHEMA_QUERIES (issue #2080, F1 guard)', () => {
// Defining BASICBLOCK_SCHEMA is not enough — it must be appended to
// NODE_SCHEMA_QUERIES (→ SCHEMA_QUERIES) or initLbug never creates the
// table and the bulk-COPY round-trip fails with "table does not exist".
expect(SCHEMA_QUERIES).toContain(BASICBLOCK_SCHEMA);
expect(BASICBLOCK_SCHEMA).toContain('CREATE NODE TABLE BasicBlock');
expect(BASICBLOCK_SCHEMA).toContain('filePath STRING');
expect(BASICBLOCK_SCHEMA).toContain('startLine INT64');
expect(BASICBLOCK_SCHEMA).toContain('endLine INT64');
expect(BASICBLOCK_SCHEMA).toContain('text STRING');
expect(BASICBLOCK_SCHEMA).toContain('PRIMARY KEY (id)');
});
it('Community schema has heuristicLabel and cohesion', () => {
expect(COMMUNITY_SCHEMA).toContain('heuristicLabel STRING');
expect(COMMUNITY_SCHEMA).toContain('cohesion DOUBLE');
});
it('Process schema has processType and stepCount', () => {
expect(PROCESS_SCHEMA).toContain('processType STRING');
expect(PROCESS_SCHEMA).toContain('stepCount INT32');
});
});
describe('relation schema', () => {
it('creates a single REL TABLE named CodeRelation', () => {
expect(RELATION_SCHEMA).toContain(`CREATE REL TABLE ${REL_TABLE_NAME}`);
});
it('has type, confidence, reason, step properties', () => {
expect(RELATION_SCHEMA).toContain('type STRING');
expect(RELATION_SCHEMA).toContain('confidence DOUBLE');
expect(RELATION_SCHEMA).toContain('reason STRING');
expect(RELATION_SCHEMA).toContain('step INT32');
});
it('connects Function to Function (CALLS)', () => {
expect(RELATION_SCHEMA).toContain('FROM Function TO Function');
});
it('connects File to Function (CONTAINS/DEFINES)', () => {
expect(RELATION_SCHEMA).toContain('FROM File TO Function');
});
it('connects symbols to Community (MEMBER_OF)', () => {
expect(RELATION_SCHEMA).toContain('FROM Function TO Community');
expect(RELATION_SCHEMA).toContain('FROM Class TO Community');
});
it('connects symbols to Process (STEP_IN_PROCESS)', () => {
expect(RELATION_SCHEMA).toContain('FROM Function TO Process');
expect(RELATION_SCHEMA).toContain('FROM Method TO Process');
});
it('persists Move enum fields and signature/field type targets', () => {
expect(RELATION_SCHEMA).toContain('FROM `EnumVariant` TO `Property`');
expect(RELATION_SCHEMA).toContain('FROM Function TO `Type`');
expect(RELATION_SCHEMA).toContain('FROM `Module` TO `Type`');
expect(RELATION_SCHEMA).toContain('FROM `Struct` TO `Type`');
expect(RELATION_SCHEMA).toContain('FROM `Property` TO `Struct`');
expect(RELATION_SCHEMA).toContain('FROM `Property` TO `Enum`');
expect(RELATION_SCHEMA).toContain('FROM `Property` TO `Type`');
});
it('connects BasicBlock to BasicBlock (taint/PDG substrate edges, #2080)', () => {
expect(RELATION_SCHEMA).toContain('FROM BasicBlock TO BasicBlock');
});
it('has all FROM/TO pairs needed for HAS_METHOD edges', () => {
// HAS_METHOD sources: Class, Interface, Struct, Trait, Impl, Record
// HAS_METHOD targets: Method, Constructor (Property is now HAS_PROPERTY)
const sources = ['Class', 'Interface'];
const backtickSources = ['Struct', 'Trait', 'Impl', 'Record'];
const targets = ['Method'];
const backtickTargets = ['Constructor'];
// Non-backtick source → non-backtick target
for (const src of sources) {
for (const tgt of targets) {
expect(RELATION_SCHEMA).toContain(`FROM ${src} TO ${tgt}`);
}
for (const tgt of backtickTargets) {
expect(RELATION_SCHEMA).toContain(`FROM ${src} TO \`${tgt}\``);
}
}
// Backtick source → all targets
for (const src of backtickSources) {
for (const tgt of targets) {
expect(RELATION_SCHEMA).toContain(`FROM \`${src}\` TO ${tgt}`);
}
for (const tgt of backtickTargets) {
expect(RELATION_SCHEMA).toContain(`FROM \`${src}\` TO \`${tgt}\``);
}
}
});
});
describe('embedding schema', () => {
it('creates CodeEmbedding table', () => {
expect(EMBEDDING_SCHEMA).toContain(`CREATE NODE TABLE ${EMBEDDING_TABLE_NAME}`);
expect(EMBEDDING_SCHEMA).toContain('embedding FLOAT[384]');
});
it('has vector index query', () => {
expect(CREATE_VECTOR_INDEX_QUERY).toContain('CREATE_VECTOR_INDEX');
expect(CREATE_VECTOR_INDEX_QUERY).toContain('cosine');
});
});
describe('schema query ordering', () => {
it('NODE_SCHEMA_QUERIES has correct count', () => {
// 31 + EnumVariant + BasicBlock + Type = 34
expect(NODE_SCHEMA_QUERIES).toHaveLength(34);
});
it('REL_SCHEMA_QUERIES has one relation table', () => {
expect(REL_SCHEMA_QUERIES).toHaveLength(1);
});
it('SCHEMA_QUERIES includes all node + rel + embedding schemas', () => {
// 34 node + 1 rel + 1 embedding = 36
expect(SCHEMA_QUERIES).toHaveLength(36);
});
it('node schemas come before relation schemas in SCHEMA_QUERIES', () => {
const relIndex = SCHEMA_QUERIES.indexOf(RELATION_SCHEMA);
const lastNodeIndex = SCHEMA_QUERIES.indexOf(
NODE_SCHEMA_QUERIES[NODE_SCHEMA_QUERIES.length - 1],
);
expect(relIndex).toBeGreaterThan(lastNodeIndex);
});
});
});