import test from "node:test"; import assert from "node:assert/strict"; import { parseLabelsFromSchemaCypher, levenshtein, nearestLabel, } from "../schema-cypher-parser.js"; test("parseLabelsFromSchemaCypher: extracts labels from constraint and index forms", () => { const text = ` CREATE CONSTRAINT person_email IF NOT EXISTS FOR (p:Person) REQUIRE p.email IS UNIQUE; CREATE CONSTRAINT business_account IF NOT EXISTS FOR (b:LocalBusiness) REQUIRE b.accountId IS UNIQUE; CREATE INDEX admin_user_account IF NOT EXISTS FOR (au:AdminUser) ON (au.accountId); CREATE INDEX knowledge_doc IF NOT EXISTS FOR (k:KnowledgeDocument) ON (k.embedding) OPTIONS { ... }; `; const labels = parseLabelsFromSchemaCypher(text); assert.deepEqual(labels, [ "AdminUser", "KnowledgeDocument", "LocalBusiness", "Person", ]); }); test("parseLabelsFromSchemaCypher: deduplicates labels declared multiple times", () => { const text = ` FOR (p:Person) REQUIRE p.email IS UNIQUE; FOR (p:Person) REQUIRE p.telephone IS UNIQUE; FOR (p:Person) ON (p.status); `; assert.deepEqual(parseLabelsFromSchemaCypher(text), ["Person"]); }); test("parseLabelsFromSchemaCypher: returns sorted output", () => { const text = `FOR (z:Zebra) ON (z.x); FOR (a:Aardvark) ON (a.x); FOR (m:Mongoose) ON (m.x);`; assert.deepEqual(parseLabelsFromSchemaCypher(text), [ "Aardvark", "Mongoose", "Zebra", ]); }); test("parseLabelsFromSchemaCypher: ignores non-constraint cypher", () => { const text = ` MATCH (n:Person) RETURN n; CREATE (b:Business { name: 'X' }); FOR (p:Person) REQUIRE p.email IS UNIQUE; `; // MATCH/CREATE patterns don't include FOR, so they're ignored. assert.deepEqual(parseLabelsFromSchemaCypher(text), ["Person"]); }); test("parseLabelsFromSchemaCypher: empty input returns empty array", () => { assert.deepEqual(parseLabelsFromSchemaCypher(""), []); }); test("levenshtein: identical strings", () => { assert.equal(levenshtein("Person", "Person"), 0); }); test("levenshtein: substitution distance", () => { // LocaIBusiness vs LocalBusiness — capital-I-as-l typo from the incident. assert.equal(levenshtein("LocaIBusiness", "LocalBusiness"), 1); }); test("levenshtein: insertion + deletion", () => { assert.equal(levenshtein("Person", "Persons"), 1); assert.equal(levenshtein("Persons", "Person"), 1); }); test("levenshtein: handles empty strings", () => { assert.equal(levenshtein("", "abc"), 3); assert.equal(levenshtein("abc", ""), 3); assert.equal(levenshtein("", ""), 0); }); test("nearestLabel: finds the closest match", () => { const candidates = ["Person", "LocalBusiness", "AdminUser"]; assert.equal(nearestLabel("LocaIBusiness", candidates), "LocalBusiness"); assert.equal(nearestLabel("AdminUsr", candidates), "AdminUser"); }); test("nearestLabel: returns null when no match within maxDistance", () => { const candidates = ["Person", "LocalBusiness"]; assert.equal(nearestLabel("Quokka", candidates), null); // Default maxDistance is 3; "abcde" is too far from any candidate. assert.equal(nearestLabel("abcde", candidates, 1), null); }); test("nearestLabel: empty candidates returns null", () => { assert.equal(nearestLabel("Person", []), null); }); test("parseLabelsFromSchemaCypher: extracts labels from a multi-label union", () => { const text = ` CREATE FULLTEXT INDEX entity_search_admin IF NOT EXISTS FOR (n:Person|Organization|KnowledgeDocument) ON EACH [n.name, n.body]; `; const labels = parseLabelsFromSchemaCypher(text); assert.deepEqual(labels, ["KnowledgeDocument", "Organization", "Person"]); }); test("parseLabelsFromSchemaCypher: extracts a union spanning several lines", () => { const text = ` CREATE FULLTEXT INDEX entity_search_admin IF NOT EXISTS FOR (n:Person|UserProfile |FAQPage|EmailAccount |AssistantMessage) ON EACH [n.name]; `; const labels = parseLabelsFromSchemaCypher(text); assert.deepEqual(labels, [ "AssistantMessage", "EmailAccount", "FAQPage", "Person", "UserProfile", ]); }); test("parseLabelsFromSchemaCypher: single and union forms coexist", () => { const text = ` CREATE CONSTRAINT person_email_unique IF NOT EXISTS FOR (p:Person) REQUIRE p.email IS UNIQUE; CREATE FULLTEXT INDEX entity_search_admin IF NOT EXISTS FOR (n:Task|Project) ON EACH [n.name]; `; const labels = parseLabelsFromSchemaCypher(text); assert.deepEqual(labels, ["Person", "Project", "Task"]); }); test("parseLabelsFromSchemaCypher: strips backticks from a reserved-word label", () => { // Cypher escapes a label colliding with a reserved word in backticks. The // backticks are quoting, not part of the label name. const text = ` CREATE INDEX order_account IF NOT EXISTS FOR (n:\`Order\`) ON (n.accountId); CREATE INDEX case_account IF NOT EXISTS FOR (n:\`Case\`) ON (n.accountId); `; const labels = parseLabelsFromSchemaCypher(text); assert.deepEqual(labels, ["Case", "Order"]); });