mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-25 07:53:32 +00:00
201 lines
5.9 KiB
TypeScript
201 lines
5.9 KiB
TypeScript
/**
|
|
* Tests for schema.ts — Schema Validation & Helpers.
|
|
*
|
|
* Tests the exported pure functions: escapeLucene(), validateRelationshipType(),
|
|
* and the exported constants and types.
|
|
*/
|
|
|
|
import { describe, it, expect } from "vitest";
|
|
import {
|
|
escapeLucene,
|
|
validateRelationshipType,
|
|
ALLOWED_RELATIONSHIP_TYPES,
|
|
MEMORY_CATEGORIES,
|
|
ENTITY_TYPES,
|
|
} from "./schema.js";
|
|
|
|
// ============================================================================
|
|
// escapeLucene()
|
|
// ============================================================================
|
|
|
|
describe("escapeLucene", () => {
|
|
it("should return normal text unchanged", () => {
|
|
expect(escapeLucene("hello world")).toBe("hello world");
|
|
});
|
|
|
|
it("should return empty string unchanged", () => {
|
|
expect(escapeLucene("")).toBe("");
|
|
});
|
|
|
|
it("should escape plus sign", () => {
|
|
expect(escapeLucene("a+b")).toBe("a\\+b");
|
|
});
|
|
|
|
it("should escape minus sign", () => {
|
|
expect(escapeLucene("a-b")).toBe("a\\-b");
|
|
});
|
|
|
|
it("should escape ampersand", () => {
|
|
expect(escapeLucene("a&b")).toBe("a\\&b");
|
|
});
|
|
|
|
it("should escape pipe", () => {
|
|
expect(escapeLucene("a|b")).toBe("a\\|b");
|
|
});
|
|
|
|
it("should escape exclamation mark", () => {
|
|
expect(escapeLucene("hello!")).toBe("hello\\!");
|
|
});
|
|
|
|
it("should escape parentheses", () => {
|
|
expect(escapeLucene("(group)")).toBe("\\(group\\)");
|
|
});
|
|
|
|
it("should escape curly braces", () => {
|
|
expect(escapeLucene("{range}")).toBe("\\{range\\}");
|
|
});
|
|
|
|
it("should escape square brackets", () => {
|
|
expect(escapeLucene("[range]")).toBe("\\[range\\]");
|
|
});
|
|
|
|
it("should escape caret", () => {
|
|
expect(escapeLucene("boost^2")).toBe("boost\\^2");
|
|
});
|
|
|
|
it("should escape double quotes", () => {
|
|
expect(escapeLucene('"exact"')).toBe('\\"exact\\"');
|
|
});
|
|
|
|
it("should escape tilde", () => {
|
|
expect(escapeLucene("fuzzy~")).toBe("fuzzy\\~");
|
|
});
|
|
|
|
it("should escape asterisk", () => {
|
|
expect(escapeLucene("wild*")).toBe("wild\\*");
|
|
});
|
|
|
|
it("should escape question mark", () => {
|
|
expect(escapeLucene("single?")).toBe("single\\?");
|
|
});
|
|
|
|
it("should escape colon", () => {
|
|
expect(escapeLucene("field:value")).toBe("field\\:value");
|
|
});
|
|
|
|
it("should escape backslash", () => {
|
|
expect(escapeLucene("path\\file")).toBe("path\\\\file");
|
|
});
|
|
|
|
it("should escape forward slash", () => {
|
|
expect(escapeLucene("a/b")).toBe("a\\/b");
|
|
});
|
|
|
|
it("should escape multiple special characters in one string", () => {
|
|
expect(escapeLucene("(a+b) && c*")).toBe("\\(a\\+b\\) \\&\\& c\\*");
|
|
});
|
|
|
|
it("should handle mixed normal and special characters", () => {
|
|
expect(escapeLucene("hello world! [test]")).toBe("hello world\\! \\[test\\]");
|
|
});
|
|
|
|
it("should handle strings with only special characters", () => {
|
|
expect(escapeLucene("+-")).toBe("\\+\\-");
|
|
});
|
|
});
|
|
|
|
// ============================================================================
|
|
// validateRelationshipType()
|
|
// ============================================================================
|
|
|
|
describe("validateRelationshipType", () => {
|
|
describe("valid relationship types", () => {
|
|
it("should accept WORKS_AT", () => {
|
|
expect(validateRelationshipType("WORKS_AT")).toBe(true);
|
|
});
|
|
|
|
it("should accept LIVES_AT", () => {
|
|
expect(validateRelationshipType("LIVES_AT")).toBe(true);
|
|
});
|
|
|
|
it("should accept KNOWS", () => {
|
|
expect(validateRelationshipType("KNOWS")).toBe(true);
|
|
});
|
|
|
|
it("should accept MARRIED_TO", () => {
|
|
expect(validateRelationshipType("MARRIED_TO")).toBe(true);
|
|
});
|
|
|
|
it("should accept PREFERS", () => {
|
|
expect(validateRelationshipType("PREFERS")).toBe(true);
|
|
});
|
|
|
|
it("should accept DECIDED", () => {
|
|
expect(validateRelationshipType("DECIDED")).toBe(true);
|
|
});
|
|
|
|
it("should accept RELATED_TO", () => {
|
|
expect(validateRelationshipType("RELATED_TO")).toBe(true);
|
|
});
|
|
|
|
it("should accept all ALLOWED_RELATIONSHIP_TYPES", () => {
|
|
for (const type of ALLOWED_RELATIONSHIP_TYPES) {
|
|
expect(validateRelationshipType(type)).toBe(true);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("invalid relationship types", () => {
|
|
it("should reject unknown relationship type", () => {
|
|
expect(validateRelationshipType("HATES")).toBe(false);
|
|
});
|
|
|
|
it("should reject empty string", () => {
|
|
expect(validateRelationshipType("")).toBe(false);
|
|
});
|
|
|
|
it("should be case sensitive — lowercase is rejected", () => {
|
|
expect(validateRelationshipType("works_at")).toBe(false);
|
|
});
|
|
|
|
it("should be case sensitive — mixed case is rejected", () => {
|
|
expect(validateRelationshipType("Works_At")).toBe(false);
|
|
});
|
|
|
|
it("should reject types with extra whitespace", () => {
|
|
expect(validateRelationshipType(" WORKS_AT ")).toBe(false);
|
|
});
|
|
|
|
it("should reject potential Cypher injection", () => {
|
|
expect(validateRelationshipType("WORKS_AT]->(n) DELETE n//")).toBe(false);
|
|
});
|
|
});
|
|
});
|
|
|
|
// ============================================================================
|
|
// Exported Constants
|
|
// ============================================================================
|
|
|
|
describe("exported constants", () => {
|
|
it("MEMORY_CATEGORIES should contain expected categories", () => {
|
|
expect(MEMORY_CATEGORIES).toContain("preference");
|
|
expect(MEMORY_CATEGORIES).toContain("fact");
|
|
expect(MEMORY_CATEGORIES).toContain("decision");
|
|
expect(MEMORY_CATEGORIES).toContain("entity");
|
|
expect(MEMORY_CATEGORIES).toContain("other");
|
|
});
|
|
|
|
it("ENTITY_TYPES should contain expected types", () => {
|
|
expect(ENTITY_TYPES).toContain("person");
|
|
expect(ENTITY_TYPES).toContain("organization");
|
|
expect(ENTITY_TYPES).toContain("location");
|
|
expect(ENTITY_TYPES).toContain("event");
|
|
expect(ENTITY_TYPES).toContain("concept");
|
|
});
|
|
|
|
it("ALLOWED_RELATIONSHIP_TYPES should be a Set", () => {
|
|
expect(ALLOWED_RELATIONSHIP_TYPES).toBeInstanceOf(Set);
|
|
expect(ALLOWED_RELATIONSHIP_TYPES.size).toBe(7);
|
|
});
|
|
});
|