mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-21 15:55:50 +00:00
style: 完成所有文件的lint
This commit is contained in:
@@ -1,226 +1,226 @@
|
||||
import { mock, describe, expect, test, beforeEach } from "bun:test";
|
||||
import { logMock } from "../../../tests/mocks/log";
|
||||
import { mock, describe, expect, test, beforeEach } from 'bun:test'
|
||||
import { logMock } from '../../../tests/mocks/log'
|
||||
|
||||
// Mock log.ts to cut the bootstrap/state dependency chain
|
||||
mock.module("src/utils/log.ts", logMock);
|
||||
mock.module('src/utils/log.ts', logMock)
|
||||
|
||||
const { memoizeWithTTL, memoizeWithTTLAsync, memoizeWithLRU } = await import(
|
||||
"../memoize"
|
||||
);
|
||||
'../memoize'
|
||||
)
|
||||
|
||||
// ─── memoizeWithTTL ────────────────────────────────────────────────────
|
||||
|
||||
describe("memoizeWithTTL", () => {
|
||||
test("returns cached value on second call", () => {
|
||||
let calls = 0;
|
||||
describe('memoizeWithTTL', () => {
|
||||
test('returns cached value on second call', () => {
|
||||
let calls = 0
|
||||
const fn = memoizeWithTTL((x: number) => {
|
||||
calls++;
|
||||
return x * 2;
|
||||
}, 60_000);
|
||||
calls++
|
||||
return x * 2
|
||||
}, 60_000)
|
||||
|
||||
expect(fn(5)).toBe(10);
|
||||
expect(fn(5)).toBe(10);
|
||||
expect(calls).toBe(1);
|
||||
});
|
||||
expect(fn(5)).toBe(10)
|
||||
expect(fn(5)).toBe(10)
|
||||
expect(calls).toBe(1)
|
||||
})
|
||||
|
||||
test("different args get separate cache entries", () => {
|
||||
let calls = 0;
|
||||
test('different args get separate cache entries', () => {
|
||||
let calls = 0
|
||||
const fn = memoizeWithTTL((x: number) => {
|
||||
calls++;
|
||||
return x + 1;
|
||||
}, 60_000);
|
||||
calls++
|
||||
return x + 1
|
||||
}, 60_000)
|
||||
|
||||
expect(fn(1)).toBe(2);
|
||||
expect(fn(2)).toBe(3);
|
||||
expect(calls).toBe(2);
|
||||
});
|
||||
expect(fn(1)).toBe(2)
|
||||
expect(fn(2)).toBe(3)
|
||||
expect(calls).toBe(2)
|
||||
})
|
||||
|
||||
test("cache.clear empties the cache", () => {
|
||||
let calls = 0;
|
||||
test('cache.clear empties the cache', () => {
|
||||
let calls = 0
|
||||
const fn = memoizeWithTTL(() => {
|
||||
calls++;
|
||||
return "val";
|
||||
}, 60_000);
|
||||
calls++
|
||||
return 'val'
|
||||
}, 60_000)
|
||||
|
||||
fn();
|
||||
fn.cache.clear();
|
||||
fn();
|
||||
expect(calls).toBe(2);
|
||||
});
|
||||
fn()
|
||||
fn.cache.clear()
|
||||
fn()
|
||||
expect(calls).toBe(2)
|
||||
})
|
||||
|
||||
test("returns stale value and triggers background refresh after TTL", async () => {
|
||||
let calls = 0;
|
||||
test('returns stale value and triggers background refresh after TTL', async () => {
|
||||
let calls = 0
|
||||
const fn = memoizeWithTTL((x: number) => {
|
||||
calls++;
|
||||
return x * calls;
|
||||
}, 1); // 1ms TTL
|
||||
calls++
|
||||
return x * calls
|
||||
}, 1) // 1ms TTL
|
||||
|
||||
const first = fn(10);
|
||||
expect(first).toBe(10); // calls=1, 10*1
|
||||
const first = fn(10)
|
||||
expect(first).toBe(10) // calls=1, 10*1
|
||||
|
||||
// Wait for TTL to expire
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
await new Promise(r => setTimeout(r, 10))
|
||||
|
||||
// Should return stale value (10) and trigger background refresh
|
||||
const second = fn(10);
|
||||
expect(second).toBe(10); // stale value returned immediately
|
||||
const second = fn(10)
|
||||
expect(second).toBe(10) // stale value returned immediately
|
||||
|
||||
// Wait for background refresh microtask
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
await new Promise(r => setTimeout(r, 10))
|
||||
|
||||
// Now cache should have refreshed value (calls=2 during refresh, 10*2=20)
|
||||
const third = fn(10);
|
||||
expect(third).toBe(20);
|
||||
});
|
||||
});
|
||||
const third = fn(10)
|
||||
expect(third).toBe(20)
|
||||
})
|
||||
})
|
||||
|
||||
// ─── memoizeWithTTLAsync ───────────────────────────────────────────────
|
||||
|
||||
describe("memoizeWithTTLAsync", () => {
|
||||
test("caches async result", async () => {
|
||||
let calls = 0;
|
||||
describe('memoizeWithTTLAsync', () => {
|
||||
test('caches async result', async () => {
|
||||
let calls = 0
|
||||
const fn = memoizeWithTTLAsync(async (x: number) => {
|
||||
calls++;
|
||||
return x * 2;
|
||||
}, 60_000);
|
||||
calls++
|
||||
return x * 2
|
||||
}, 60_000)
|
||||
|
||||
expect(await fn(5)).toBe(10);
|
||||
expect(await fn(5)).toBe(10);
|
||||
expect(calls).toBe(1);
|
||||
});
|
||||
expect(await fn(5)).toBe(10)
|
||||
expect(await fn(5)).toBe(10)
|
||||
expect(calls).toBe(1)
|
||||
})
|
||||
|
||||
test("deduplicates concurrent cold-miss calls", async () => {
|
||||
let calls = 0;
|
||||
test('deduplicates concurrent cold-miss calls', async () => {
|
||||
let calls = 0
|
||||
const fn = memoizeWithTTLAsync(async (x: number) => {
|
||||
calls++;
|
||||
await new Promise((r) => setTimeout(r, 20));
|
||||
return x;
|
||||
}, 60_000);
|
||||
calls++
|
||||
await new Promise(r => setTimeout(r, 20))
|
||||
return x
|
||||
}, 60_000)
|
||||
|
||||
const [a, b, c] = await Promise.all([fn(1), fn(1), fn(1)]);
|
||||
expect(a).toBe(1);
|
||||
expect(b).toBe(1);
|
||||
expect(c).toBe(1);
|
||||
expect(calls).toBe(1);
|
||||
});
|
||||
const [a, b, c] = await Promise.all([fn(1), fn(1), fn(1)])
|
||||
expect(a).toBe(1)
|
||||
expect(b).toBe(1)
|
||||
expect(c).toBe(1)
|
||||
expect(calls).toBe(1)
|
||||
})
|
||||
|
||||
test("cache.clear forces re-computation", async () => {
|
||||
let calls = 0;
|
||||
test('cache.clear forces re-computation', async () => {
|
||||
let calls = 0
|
||||
const fn = memoizeWithTTLAsync(async () => {
|
||||
calls++;
|
||||
return "v";
|
||||
}, 60_000);
|
||||
calls++
|
||||
return 'v'
|
||||
}, 60_000)
|
||||
|
||||
await fn();
|
||||
fn.cache.clear();
|
||||
await fn();
|
||||
expect(calls).toBe(2);
|
||||
});
|
||||
await fn()
|
||||
fn.cache.clear()
|
||||
await fn()
|
||||
expect(calls).toBe(2)
|
||||
})
|
||||
|
||||
test("returns stale value on TTL expiry", async () => {
|
||||
let calls = 0;
|
||||
test('returns stale value on TTL expiry', async () => {
|
||||
let calls = 0
|
||||
const fn = memoizeWithTTLAsync(async () => {
|
||||
calls++;
|
||||
return calls;
|
||||
}, 1); // 1ms TTL
|
||||
calls++
|
||||
return calls
|
||||
}, 1) // 1ms TTL
|
||||
|
||||
const first = await fn();
|
||||
expect(first).toBe(1);
|
||||
const first = await fn()
|
||||
expect(first).toBe(1)
|
||||
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
await new Promise(r => setTimeout(r, 10))
|
||||
|
||||
// Should return stale value (1) immediately
|
||||
const second = await fn();
|
||||
expect(second).toBe(1);
|
||||
});
|
||||
});
|
||||
const second = await fn()
|
||||
expect(second).toBe(1)
|
||||
})
|
||||
})
|
||||
|
||||
// ─── memoizeWithLRU ────────────────────────────────────────────────────
|
||||
|
||||
describe("memoizeWithLRU", () => {
|
||||
test("caches results by key", () => {
|
||||
let calls = 0;
|
||||
describe('memoizeWithLRU', () => {
|
||||
test('caches results by key', () => {
|
||||
let calls = 0
|
||||
const fn = memoizeWithLRU(
|
||||
(x: number) => {
|
||||
calls++;
|
||||
return x * 2;
|
||||
calls++
|
||||
return x * 2
|
||||
},
|
||||
(x) => String(x),
|
||||
10
|
||||
);
|
||||
x => String(x),
|
||||
10,
|
||||
)
|
||||
|
||||
expect(fn(5)).toBe(10);
|
||||
expect(fn(5)).toBe(10);
|
||||
expect(calls).toBe(1);
|
||||
});
|
||||
expect(fn(5)).toBe(10)
|
||||
expect(fn(5)).toBe(10)
|
||||
expect(calls).toBe(1)
|
||||
})
|
||||
|
||||
test("evicts least recently used when max reached", () => {
|
||||
let calls = 0;
|
||||
test('evicts least recently used when max reached', () => {
|
||||
let calls = 0
|
||||
const fn = memoizeWithLRU(
|
||||
(x: number) => {
|
||||
calls++;
|
||||
return x;
|
||||
calls++
|
||||
return x
|
||||
},
|
||||
(x) => String(x),
|
||||
3
|
||||
);
|
||||
x => String(x),
|
||||
3,
|
||||
)
|
||||
|
||||
fn(1);
|
||||
fn(2);
|
||||
fn(3);
|
||||
expect(calls).toBe(3);
|
||||
fn(1)
|
||||
fn(2)
|
||||
fn(3)
|
||||
expect(calls).toBe(3)
|
||||
|
||||
fn(4); // evicts key "1"
|
||||
expect(fn.cache.has("1")).toBe(false);
|
||||
expect(fn.cache.has("4")).toBe(true);
|
||||
});
|
||||
fn(4) // evicts key "1"
|
||||
expect(fn.cache.has('1')).toBe(false)
|
||||
expect(fn.cache.has('4')).toBe(true)
|
||||
})
|
||||
|
||||
test("cache.size returns current size", () => {
|
||||
test('cache.size returns current size', () => {
|
||||
const fn = memoizeWithLRU(
|
||||
(x: number) => x,
|
||||
(x) => String(x),
|
||||
10
|
||||
);
|
||||
x => String(x),
|
||||
10,
|
||||
)
|
||||
|
||||
fn(1);
|
||||
fn(2);
|
||||
expect(fn.cache.size()).toBe(2);
|
||||
});
|
||||
fn(1)
|
||||
fn(2)
|
||||
expect(fn.cache.size()).toBe(2)
|
||||
})
|
||||
|
||||
test("cache.delete removes entry", () => {
|
||||
test('cache.delete removes entry', () => {
|
||||
const fn = memoizeWithLRU(
|
||||
(x: number) => x,
|
||||
(x) => String(x),
|
||||
10
|
||||
);
|
||||
x => String(x),
|
||||
10,
|
||||
)
|
||||
|
||||
fn(1);
|
||||
expect(fn.cache.has("1")).toBe(true);
|
||||
fn.cache.delete("1");
|
||||
expect(fn.cache.has("1")).toBe(false);
|
||||
});
|
||||
fn(1)
|
||||
expect(fn.cache.has('1')).toBe(true)
|
||||
fn.cache.delete('1')
|
||||
expect(fn.cache.has('1')).toBe(false)
|
||||
})
|
||||
|
||||
test("cache.get returns value without updating recency", () => {
|
||||
test('cache.get returns value without updating recency', () => {
|
||||
const fn = memoizeWithLRU(
|
||||
(x: number) => x * 10,
|
||||
(x) => String(x),
|
||||
10
|
||||
);
|
||||
x => String(x),
|
||||
10,
|
||||
)
|
||||
|
||||
fn(5);
|
||||
expect(fn.cache.get("5")).toBe(50);
|
||||
});
|
||||
fn(5)
|
||||
expect(fn.cache.get('5')).toBe(50)
|
||||
})
|
||||
|
||||
test("cache.clear empties everything", () => {
|
||||
test('cache.clear empties everything', () => {
|
||||
const fn = memoizeWithLRU(
|
||||
(x: number) => x,
|
||||
(x) => String(x),
|
||||
10
|
||||
);
|
||||
x => String(x),
|
||||
10,
|
||||
)
|
||||
|
||||
fn(1);
|
||||
fn(2);
|
||||
fn.cache.clear();
|
||||
expect(fn.cache.size()).toBe(0);
|
||||
});
|
||||
});
|
||||
fn(1)
|
||||
fn(2)
|
||||
fn.cache.clear()
|
||||
expect(fn.cache.size()).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user