import test from "node:test"; import assert from "node:assert/strict"; import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { pathToFileURL } from "node:url"; const serial = { concurrency: false }; function makeTempDir(prefix: string): string { return fs.mkdtempSync(path.join(os.tmpdir(), prefix)); } function removePath(targetPath: string) { fs.rmSync(targetPath, { recursive: true, force: true }); } const originalEnv = { DATA_DIR: process.env.DATA_DIR, NEXT_PHASE: process.env.NEXT_PHASE, }; function restoreEnv() { for (const [key, value] of Object.entries(originalEnv)) { if (value === undefined) { delete process.env[key]; } else { process.env[key] = value; } } } function cleanupGlobalDb() { try { if ((globalThis as any).__omnirouteDb?.open) { (globalThis as any).__omnirouteDb.close(); } } catch {} delete (globalThis as any).__omnirouteDb; } async function importFresh(modulePath: string) { const url = pathToFileURL(path.resolve(modulePath)).href; return import(`${url}?test=${Date.now()}-${Math.random().toString(16).slice(2)}`); } async function withEnv(overrides: Record, fn: () => Promise) { const snapshot: Record = {}; for (const key of Object.keys(overrides)) { snapshot[key] = process.env[key]; const value = overrides[key]; if (value === undefined) { delete process.env[key]; } else { process.env[key] = value; } } try { return await fn(); } finally { for (const [key, value] of Object.entries(snapshot)) { if (value === undefined) { delete process.env[key]; } else { process.env[key] = value; } } } } // ──────────────── Pure Utility Functions ──────────────── test("toSnakeCase converts camelCase to snake_case", () => { // Import once at module level for pure functions // We use a lazy import pattern }); // We'll use a single import for the module let core: any; test.before(async () => { const dataDir = makeTempDir("omniroute-db-core-utils-"); try { await withEnv({ DATA_DIR: dataDir }, async () => { core = await importFresh("src/lib/db/core.ts"); // Initialize DB so DB functions work too core.getDbInstance(); }); } catch { removePath(dataDir); } }); test.after(() => { try { core?.resetDbInstance(); } catch {} cleanupGlobalDb(); restoreEnv(); }); // ─── toSnakeCase ─────────────────────────────────────── test("toSnakeCase: basic camelCase conversion", () => { assert.equal(core.toSnakeCase("apiKey"), "api_key"); assert.equal(core.toSnakeCase("isActive"), "is_active"); assert.equal(core.toSnakeCase("providerName"), "provider_name"); }); test("toSnakeCase: empty string and single word", () => { assert.equal(core.toSnakeCase(""), ""); assert.equal(core.toSnakeCase("name"), "name"); assert.equal(core.toSnakeCase("id"), "id"); }); test("toSnakeCase: consecutive uppercase (acronyms)", () => { // The implementation inserts _ before each uppercase including the first // character, then lowercases. So "APIKey" → "_a_p_i_key". assert.equal(core.toSnakeCase("APIKey"), "_a_p_i_key"); assert.equal(core.toSnakeCase("DBConnection"), "_d_b_connection"); }); test("toSnakeCase: already snake_case stays same", () => { assert.equal(core.toSnakeCase("already_snake"), "already_snake"); assert.equal(core.toSnakeCase("already_snake_case"), "already_snake_case"); }); test("toSnakeCase: mixed snake and camel", () => { assert.equal(core.toSnakeCase("provider_name"), "provider_name"); assert.equal(core.toSnakeCase("provider_Name"), "provider__name"); }); // ─── toCamelCase ─────────────────────────────────────── test("toCamelCase: basic snake_case conversion", () => { assert.equal(core.toCamelCase("api_key"), "apiKey"); assert.equal(core.toCamelCase("is_active"), "isActive"); assert.equal(core.toCamelCase("provider_name"), "providerName"); }); test("toCamelCase: empty string and single word", () => { assert.equal(core.toCamelCase(""), ""); assert.equal(core.toCamelCase("name"), "name"); assert.equal(core.toCamelCase("id"), "id"); }); test("toCamelCase: multiple underscores", () => { assert.equal(core.toCamelCase("foo_bar_baz"), "fooBarBaz"); assert.equal(core.toCamelCase("a_b_c"), "aBC"); }); test("toCamelCase: leading underscore", () => { assert.equal(core.toCamelCase("_private"), "Private"); }); test("toCamelCase: trailing underscore is preserved", () => { // Regex _([a-z]) doesn't match trailing underscore (no char after it) assert.equal(core.toCamelCase("trailing_"), "trailing_"); }); // ─── objToSnake ──────────────────────────────────────── test("objToSnake: converts object keys to snake_case", () => { const input = { apiKey: "sk-test", isActive: true, providerName: "openai" }; const result = core.objToSnake(input); assert.deepEqual(result, { api_key: "sk-test", is_active: true, provider_name: "openai" }); }); test("objToSnake: null/undefined/non-object input", () => { assert.equal(core.objToSnake(null), null); assert.equal(core.objToSnake(undefined), undefined); assert.equal(core.objToSnake("string"), "string"); assert.equal(core.objToSnake(42), 42); }); test("objToSnake: empty object", () => { assert.deepEqual(core.objToSnake({}), {}); }); test("objToSnake: nested values preserved as-is (shallow)", () => { const input = { nestedObj: { innerKey: "val" }, items: [1, 2, 3] }; const result = core.objToSnake(input); assert.deepEqual(result, { nested_obj: { innerKey: "val" }, items: [1, 2, 3] }); }); // ─── rowToCamel ──────────────────────────────────────── test("rowToCamel: converts snake_case row to camelCase", () => { const row = { api_key: "sk-test", is_active: 1, provider_name: "openai" }; const result = core.rowToCamel(row); assert.deepEqual(result, { apiKey: "sk-test", isActive: true, providerName: "openai" }); }); test("rowToCamel: null/undefined row returns null", () => { assert.equal(core.rowToCamel(null), null); assert.equal(core.rowToCamel(undefined), null); }); test("rowToCamel: isActive boolean conversion (1/0)", () => { assert.deepEqual(core.rowToCamel({ is_active: 1 }), { isActive: true }); assert.deepEqual(core.rowToCamel({ is_active: 0 }), { isActive: false }); assert.deepEqual(core.rowToCamel({ is_active: true }), { isActive: true }); assert.deepEqual(core.rowToCamel({ is_active: false }), { isActive: false }); }); test("rowToCamel: rateLimitProtection boolean conversion", () => { assert.deepEqual(core.rowToCamel({ rate_limit_protection: 1 }), { rateLimitProtection: true }); assert.deepEqual(core.rowToCamel({ rate_limit_protection: 0 }), { rateLimitProtection: false }); }); test("rowToCamel: providerSpecificData JSON string parsing", () => { const data = JSON.stringify({ org: "my-org" }); const result = core.rowToCamel({ provider_specific_data: data }); assert.deepEqual(result, { providerSpecificData: { org: "my-org" } }); }); test("rowToCamel: providerSpecificData invalid JSON", () => { const result = core.rowToCamel({ provider_specific_data: "not-json" }); assert.equal(result?.providerSpecificData, "not-json"); }); test("rowToCamel: providerSpecificData non-string passes through", () => { const result = core.rowToCamel({ provider_specific_data: 42 }); assert.equal(result?.providerSpecificData, 42); }); test("rowToCamel: _json suffix columns parsed into base key", () => { const result = core.rowToCamel({ quota_window_thresholds_json: JSON.stringify([1, 2, 3]) }); assert.deepEqual(result, { quotaWindowThresholds: [1, 2, 3] }); }); test("rowToCamel: _json suffix with invalid JSON sets null", () => { const result = core.rowToCamel({ quota_window_thresholds_json: "broken" }); assert.deepEqual(result, { quotaWindowThresholds: null }); }); test("rowToCamel: ordinary fields pass through unchanged", () => { const result = core.rowToCamel({ name: "test", created_at: "2025-01-01" }); assert.deepEqual(result, { name: "test", createdAt: "2025-01-01" }); }); test("rowToCamel: empty row returns empty object", () => { assert.deepEqual(core.rowToCamel({}), {}); }); // ─── cleanNulls ──────────────────────────────────────── test("cleanNulls: removes null and undefined values", () => { const result = core.cleanNulls({ a: 1, b: null, c: "keep", d: undefined, e: 0, f: "" }); assert.deepEqual(result, { a: 1, c: "keep", e: 0, f: "" }); }); test("cleanNulls: all values kept", () => { const result = core.cleanNulls({ a: 1, b: "x", c: false }); assert.deepEqual(result, { a: 1, b: "x", c: false }); }); test("cleanNulls: empty object returns empty object", () => { assert.deepEqual(core.cleanNulls({}), {}); }); test("cleanNulls: all null/undefined returns empty object", () => { assert.deepEqual(core.cleanNulls({ a: null, b: undefined }), {}); }); // ─── getDriverInfo ───────────────────────────────────── test("getDriverInfo returns null (setDriverInfo never called)", () => { // setDriverInfo() exists but is never called in core.ts, so getDriverInfo // always returns null until/unless a caller invokes setDriverInfo(). assert.equal(core.getDriverInfo(), null); }); // ─── DB Functions (autoVacuum, pageSize, cacheSize) ─── test("setAutoVacuum and getAutoVacuumMode round-trip", serial, () => { // Get current const originalMode = core.getAutoVacuumMode(); // Set to NONE first core.setAutoVacuum("NONE"); assert.equal(core.getAutoVacuumMode(), "NONE"); // Set to FULL core.setAutoVacuum("FULL"); assert.equal(core.getAutoVacuumMode(), "FULL"); // Set to INCREMENTAL core.setAutoVacuum("INCREMENTAL"); assert.equal(core.getAutoVacuumMode(), "INCREMENTAL"); // Restore original core.setAutoVacuum(originalMode); assert.equal(core.getAutoVacuumMode(), originalMode); }); test("setAutoVacuum same mode is idempotent", serial, () => { const mode = core.getAutoVacuumMode(); // Calling again with same mode should not throw core.setAutoVacuum(mode); assert.equal(core.getAutoVacuumMode(), mode); }); test("runManualVacuum succeeds", serial, () => { const result = core.runManualVacuum(); assert.equal(result.success, true); assert.equal(typeof result.duration, "number"); assert.ok(result.duration >= 0); assert.equal(result.error, undefined); }); test("setPageSize round-trip", serial, () => { // Capture current page_size so we can restore it // We'll set to a known value, verify, then set back // Note: page_size can only be set if the DB is empty or after VACUUM // The implementation calls VACUUM after setting, which is safe const testPageSize = 4096; core.setPageSize(testPageSize); // We can't read it back directly via exported function, but it shouldn't throw // Verify by running it again (idempotent) core.setPageSize(testPageSize); }); test("setCacheSize round-trip", serial, () => { core.setCacheSize(16384); // Verify idempotent core.setCacheSize(16384); }); // ─── Edge Cases ──────────────────────────────────────── test("toSnakeCase and toCamelCase are inverses for simple cases", () => { const pairs = [ ["apiKey", "api_key"], ["isActive", "is_active"], ["providerName", "provider_name"], ["createdAt", "created_at"], ["updatedAt", "updated_at"], ]; for (const [camel, snake] of pairs) { assert.equal(core.toSnakeCase(camel), snake); assert.equal(core.toCamelCase(snake), camel); } }); test("cleanNulls with falsy values preserves 0, false, empty string", () => { const result = core.cleanNulls({ zero: 0, falseVal: false, emptyStr: "", nil: null }); assert.deepEqual(result, { zero: 0, falseVal: false, emptyStr: "" }); }); test("objToSnake returns same object reference for primitives", () => { const num = 42; assert.equal(core.objToSnake(num), 42); }); test("rowToCamel with isActive=1/non-1 edge cases", () => { assert.deepEqual(core.rowToCamel({ is_active: 1 }), { isActive: true }); assert.deepEqual(core.rowToCamel({ is_active: 0 }), { isActive: false }); assert.deepEqual(core.rowToCamel({ is_active: 2 }), { isActive: false }); assert.deepEqual(core.rowToCamel({ is_active: "yes" }), { isActive: false }); });