// SPDX-License-Identifier: AGPL-3.0-only // Copyright (C) 2026 Giancarlo Erra - Altaire Limited import { describe, expect, it } from "vitest"; import { CHUNK_OVERLAP, CHUNK_SIZE, getLanguageFromExtension, INDEX_BATCH_SIZE, MAX_AVG_LINE_LENGTH, MAX_CHUNK_CHARS, MAX_FILE_BYTES, mergeExtraExtensions, OLLAMA_CONTAINER_NAME, OLLAMA_HOST, OLLAMA_IMAGE, OLLAMA_PORT, parseExtraExtensions, QDRANT_CONTAINER_NAME, QDRANT_GRPC_PORT, QDRANT_HOST, QDRANT_IMAGE, QDRANT_MODE, QDRANT_PORT, QDRANT_URL, resolveQdrantPort, SEARCH_DEFAULT_LIMIT, SEARCH_MIN_SCORE, SPECIAL_FILES, SUPPORTED_EXTENSIONS, } from "../../src/constants.js"; describe("constants", () => { describe("Qdrant configuration", () => { it("has default port 16333", () => { expect(QDRANT_PORT).toBe(16333); }); it("has default gRPC port 16334", () => { expect(QDRANT_GRPC_PORT).toBe(16334); }); it("defaults host to localhost", () => { expect(QDRANT_HOST).toBe("localhost"); }); it("has correct container name", () => { expect(QDRANT_CONTAINER_NAME).toBe("socraticode-qdrant"); }); it("uses pinned Qdrant image version", () => { expect(QDRANT_IMAGE).toMatch(/^qdrant\/qdrant:v\d+\.\d+\.\d+$/); }); it("defaults mode to managed", () => { expect(QDRANT_MODE).toBe("managed"); }); it("defaults URL to undefined", () => { expect(QDRANT_URL).toBeUndefined(); }); }); describe("Ollama configuration", () => { it("has default port 11435", () => { expect(OLLAMA_PORT).toBe(11435); }); it("defaults host to localhost with configured port", () => { expect(OLLAMA_HOST).toBe(`http://localhost:${OLLAMA_PORT}`); }); it("has correct container name", () => { expect(OLLAMA_CONTAINER_NAME).toBe("socraticode-ollama"); }); it("uses latest Ollama image", () => { expect(OLLAMA_IMAGE).toBe("ollama/ollama:latest"); }); }); describe("chunking configuration", () => { it("has reasonable chunk size", () => { expect(CHUNK_SIZE).toBeGreaterThan(0); expect(CHUNK_SIZE).toBeLessThanOrEqual(500); }); it("has overlap smaller than chunk size", () => { expect(CHUNK_OVERLAP).toBeGreaterThan(0); expect(CHUNK_OVERLAP).toBeLessThan(CHUNK_SIZE); }); it("defaults to 100 lines per chunk", () => { expect(CHUNK_SIZE).toBe(100); }); it("defaults to 10 lines overlap", () => { expect(CHUNK_OVERLAP).toBe(10); }); }); describe("search configuration", () => { it("defaults SEARCH_DEFAULT_LIMIT to 10", () => { expect(SEARCH_DEFAULT_LIMIT).toBe(10); }); it("clamps SEARCH_DEFAULT_LIMIT between 1 and 50", () => { // Can't easily test env override in-process, but verify the default is within bounds expect(SEARCH_DEFAULT_LIMIT).toBeGreaterThanOrEqual(1); expect(SEARCH_DEFAULT_LIMIT).toBeLessThanOrEqual(50); }); it("defaults SEARCH_MIN_SCORE to 0.10", () => { expect(SEARCH_MIN_SCORE).toBeCloseTo(0.10); }); it("clamps SEARCH_MIN_SCORE between 0 and 1", () => { expect(SEARCH_MIN_SCORE).toBeGreaterThanOrEqual(0); expect(SEARCH_MIN_SCORE).toBeLessThanOrEqual(1); }); }); describe("indexing configuration", () => { it("defaults INDEX_BATCH_SIZE to 50", () => { expect(INDEX_BATCH_SIZE).toBe(50); }); it("defaults MAX_FILE_BYTES to 5MB", () => { expect(MAX_FILE_BYTES).toBe(5_000_000); }); it("MAX_AVG_LINE_LENGTH is a positive number", () => { expect(MAX_AVG_LINE_LENGTH).toBeGreaterThan(0); }); it("defaults MAX_AVG_LINE_LENGTH to 500", () => { expect(MAX_AVG_LINE_LENGTH).toBe(500); }); it("MAX_CHUNK_CHARS is a positive number", () => { expect(MAX_CHUNK_CHARS).toBeGreaterThan(0); }); it("defaults MAX_CHUNK_CHARS to 2000", () => { expect(MAX_CHUNK_CHARS).toBe(2000); }); it("MAX_CHUNK_CHARS is less than MAX_AVG_LINE_LENGTH * CHUNK_SIZE (sanity check)", () => { // Ensures MAX_CHUNK_CHARS is a tighter limit than unconstrained line-based chunks expect(MAX_CHUNK_CHARS).toBeLessThan(MAX_AVG_LINE_LENGTH * CHUNK_SIZE); }); }); describe("SUPPORTED_EXTENSIONS", () => { it("is a Set", () => { expect(SUPPORTED_EXTENSIONS).toBeInstanceOf(Set); }); it("contains common programming language extensions", () => { const expected = [".js", ".ts", ".py", ".java", ".go", ".rs", ".rb", ".php", ".swift", ".c", ".cpp"]; for (const ext of expected) { expect(SUPPORTED_EXTENSIONS.has(ext), `missing: ${ext}`).toBe(true); } }); it("contains TypeScript variants", () => { expect(SUPPORTED_EXTENSIONS.has(".ts")).toBe(true); expect(SUPPORTED_EXTENSIONS.has(".tsx")).toBe(true); expect(SUPPORTED_EXTENSIONS.has(".mjs")).toBe(true); expect(SUPPORTED_EXTENSIONS.has(".cjs")).toBe(true); }); it("contains web extensions", () => { expect(SUPPORTED_EXTENSIONS.has(".html")).toBe(true); expect(SUPPORTED_EXTENSIONS.has(".css")).toBe(true); expect(SUPPORTED_EXTENSIONS.has(".scss")).toBe(true); expect(SUPPORTED_EXTENSIONS.has(".vue")).toBe(true); expect(SUPPORTED_EXTENSIONS.has(".svelte")).toBe(true); }); it("contains config/data extensions", () => { expect(SUPPORTED_EXTENSIONS.has(".json")).toBe(true); expect(SUPPORTED_EXTENSIONS.has(".yaml")).toBe(true); expect(SUPPORTED_EXTENSIONS.has(".yml")).toBe(true); expect(SUPPORTED_EXTENSIONS.has(".toml")).toBe(true); expect(SUPPORTED_EXTENSIONS.has(".xml")).toBe(true); }); it("contains documentation extensions", () => { expect(SUPPORTED_EXTENSIONS.has(".md")).toBe(true); expect(SUPPORTED_EXTENSIONS.has(".mdx")).toBe(true); expect(SUPPORTED_EXTENSIONS.has(".rst")).toBe(true); expect(SUPPORTED_EXTENSIONS.has(".txt")).toBe(true); }); it("does not contain binary or image extensions", () => { expect(SUPPORTED_EXTENSIONS.has(".png")).toBe(false); expect(SUPPORTED_EXTENSIONS.has(".jpg")).toBe(false); expect(SUPPORTED_EXTENSIONS.has(".exe")).toBe(false); expect(SUPPORTED_EXTENSIONS.has(".pdf")).toBe(false); }); it("has at least 50 extensions", () => { expect(SUPPORTED_EXTENSIONS.size).toBeGreaterThanOrEqual(50); }); }); describe("SPECIAL_FILES", () => { it("is a Set", () => { expect(SPECIAL_FILES).toBeInstanceOf(Set); }); it("includes Dockerfile", () => { expect(SPECIAL_FILES.has("Dockerfile")).toBe(true); }); it("includes Makefile", () => { expect(SPECIAL_FILES.has("Makefile")).toBe(true); }); it("includes Gemfile", () => { expect(SPECIAL_FILES.has("Gemfile")).toBe(true); }); it("includes .gitignore", () => { expect(SPECIAL_FILES.has(".gitignore")).toBe(true); }); it("includes .env.example", () => { expect(SPECIAL_FILES.has(".env.example")).toBe(true); }); }); describe("getLanguageFromExtension", () => { it("maps .ts to typescript", () => { expect(getLanguageFromExtension(".ts")).toBe("typescript"); }); it("maps .tsx to typescript", () => { expect(getLanguageFromExtension(".tsx")).toBe("typescript"); }); it("maps .js to javascript", () => { expect(getLanguageFromExtension(".js")).toBe("javascript"); }); it("maps .py to python", () => { expect(getLanguageFromExtension(".py")).toBe("python"); }); it("maps .java to java", () => { expect(getLanguageFromExtension(".java")).toBe("java"); }); it("maps .go to go", () => { expect(getLanguageFromExtension(".go")).toBe("go"); }); it("maps .rs to rust", () => { expect(getLanguageFromExtension(".rs")).toBe("rust"); }); it("maps .rb to ruby", () => { expect(getLanguageFromExtension(".rb")).toBe("ruby"); }); it("maps .cpp to cpp", () => { expect(getLanguageFromExtension(".cpp")).toBe("cpp"); }); it("maps .cs to csharp", () => { expect(getLanguageFromExtension(".cs")).toBe("csharp"); }); it("maps .swift to swift", () => { expect(getLanguageFromExtension(".swift")).toBe("swift"); }); it("maps .sh to shell", () => { expect(getLanguageFromExtension(".sh")).toBe("shell"); }); it("maps .md to markdown", () => { expect(getLanguageFromExtension(".md")).toBe("markdown"); }); it("maps .dart to dart", () => { expect(getLanguageFromExtension(".dart")).toBe("dart"); }); it("maps .lua to lua", () => { expect(getLanguageFromExtension(".lua")).toBe("lua"); }); it("maps .sql to sql", () => { expect(getLanguageFromExtension(".sql")).toBe("sql"); }); it("returns plaintext for unknown extensions", () => { expect(getLanguageFromExtension(".xyz")).toBe("plaintext"); expect(getLanguageFromExtension(".abc")).toBe("plaintext"); expect(getLanguageFromExtension("")).toBe("plaintext"); }); it("maps .r and .R to r", () => { expect(getLanguageFromExtension(".r")).toBe("r"); expect(getLanguageFromExtension(".R")).toBe("r"); }); it("maps .kt to kotlin", () => { expect(getLanguageFromExtension(".kt")).toBe("kotlin"); }); it("maps .scala to scala", () => { expect(getLanguageFromExtension(".scala")).toBe("scala"); }); it("maps .php to php", () => { expect(getLanguageFromExtension(".php")).toBe("php"); }); }); describe("parseExtraExtensions", () => { it("returns empty set for undefined", () => { expect(parseExtraExtensions(undefined).size).toBe(0); }); it("returns empty set for empty string", () => { expect(parseExtraExtensions("").size).toBe(0); }); it("returns empty set for whitespace-only", () => { expect(parseExtraExtensions(" ").size).toBe(0); }); it("parses comma-separated extensions with dots", () => { const result = parseExtraExtensions(".tpl,.blade,.hbs"); expect(result).toEqual(new Set([".tpl", ".blade", ".hbs"])); }); it("adds leading dots when missing", () => { const result = parseExtraExtensions("tpl,blade"); expect(result).toEqual(new Set([".tpl", ".blade"])); }); it("trims whitespace and lowercases", () => { const result = parseExtraExtensions(" .TPL , .Blade "); expect(result).toEqual(new Set([".tpl", ".blade"])); }); it("deduplicates entries", () => { const result = parseExtraExtensions(".tpl,.tpl,tpl"); expect(result.size).toBe(1); expect(result.has(".tpl")).toBe(true); }); }); describe("mergeExtraExtensions", () => { it("returns env var default when no tool param", () => { // EXTRA_EXTENSIONS env var is not set in test environment, so should be empty const result = mergeExtraExtensions(); expect(result.size).toBe(0); }); it("returns tool param extensions when provided", () => { const result = mergeExtraExtensions(".tpl,.blade"); expect(result).toEqual(new Set([".tpl", ".blade"])); }); it("returns empty for undefined tool param", () => { const result = mergeExtraExtensions(undefined); expect(result.size).toBe(0); }); }); }); describe("resolveQdrantPort", () => { it("returns explicit port from URL", () => { expect(resolveQdrantPort("https://qdrant.example.com:6333")).toBe(6333); expect(resolveQdrantPort("http://localhost:8080")).toBe(8080); expect(resolveQdrantPort("https://my-qdrant.com:8443")).toBe(8443); }); it("defaults to 443 for HTTPS URLs without explicit port", () => { expect(resolveQdrantPort("https://qdrant.example.com")).toBe(443); expect(resolveQdrantPort("https://my-tunnel.trycloudflare.com")).toBe(443); }); it("defaults to 6333 for HTTP URLs without explicit port", () => { expect(resolveQdrantPort("http://localhost")).toBe(6333); expect(resolveQdrantPort("http://192.168.1.100")).toBe(6333); }); it("handles URLs with paths and query strings", () => { expect(resolveQdrantPort("https://qdrant.example.com:9999/some/path")).toBe(9999); expect(resolveQdrantPort("https://qdrant.example.com/some/path")).toBe(443); }); });