Files
2026-07-13 13:39:12 +08:00

94 lines
3.2 KiB
TypeScript

import assert from "node:assert/strict";
import { describe, test } from "node:test";
// We import the pure function directly from the source module.
// estimateTokens lives in src/lib/memory/retrieval.ts but the module
// has heavy DB dependencies at the top level. We replicate the pure
// function here to test the exact algorithm used by the route handler.
/**
* Exact replica of estimateTokens from src/lib/memory/retrieval.ts:34-37
* so the test does not pull in the full DB/SQLite dependency graph.
*/
function estimateTokens(text: string): number {
if (!text || typeof text !== "string") return 0;
return Math.ceil(text.length / 4);
}
describe("memory stats API — estimateTokens", () => {
test("returns 0 for empty string", () => {
assert.equal(estimateTokens(""), 0);
});
test("returns 0 for falsy/non-string input", () => {
assert.equal(estimateTokens(null as unknown as string), 0);
assert.equal(estimateTokens(undefined as unknown as string), 0);
assert.equal(estimateTokens(42 as unknown as string), 0);
});
test("returns 1 for a 1-char string", () => {
assert.equal(estimateTokens("a"), 1);
});
test("returns 1 for exactly 4 chars", () => {
assert.equal(estimateTokens("abcd"), 1);
});
test("returns 2 for 5 chars (ceiling division)", () => {
assert.equal(estimateTokens("abcde"), 2);
});
test("returns correct value for longer strings", () => {
// 100 chars -> ceil(100/4) = 25
assert.equal(estimateTokens("a".repeat(100)), 25);
});
});
describe("memory stats API — tokensUsed computation", () => {
test("sums estimateTokens across multiple content rows", () => {
const rows = [
{ content: "hello" }, // 5 chars -> ceil(5/4) = 2
{ content: "world!" }, // 6 chars -> ceil(6/4) = 2
{ content: "ab" }, // 2 chars -> ceil(2/4) = 1
];
const tokensUsed = rows.reduce((sum, r) => sum + estimateTokens(r.content), 0);
assert.equal(tokensUsed, 5);
});
test("returns 0 for empty rows array", () => {
const rows: { content: string }[] = [];
const tokensUsed = rows.reduce((sum, r) => sum + estimateTokens(r.content), 0);
assert.equal(tokensUsed, 0);
});
});
describe("memory stats API — hitRate computation", () => {
test("hitRate is 0 when no requests have been made", () => {
const cacheStats = { hits: 0, misses: 0 };
const total = cacheStats.hits + cacheStats.misses;
const hitRate = total > 0 ? cacheStats.hits / total : 0;
assert.equal(hitRate, 0);
});
test("hitRate is 1 when all requests are hits", () => {
const cacheStats = { hits: 10, misses: 0 };
const total = cacheStats.hits + cacheStats.misses;
const hitRate = total > 0 ? cacheStats.hits / total : 0;
assert.equal(hitRate, 1);
});
test("hitRate is 0.5 when hits equals misses", () => {
const cacheStats = { hits: 5, misses: 5 };
const total = cacheStats.hits + cacheStats.misses;
const hitRate = total > 0 ? cacheStats.hits / total : 0;
assert.equal(hitRate, 0.5);
});
test("hitRate computes correctly for arbitrary values", () => {
const cacheStats = { hits: 3, misses: 7 };
const total = cacheStats.hits + cacheStats.misses;
const hitRate = total > 0 ? cacheStats.hits / total : 0;
assert.equal(hitRate, 0.3);
});
});