Vendored
+82
@@ -0,0 +1,82 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { Cache } from '../../src/cache/cache';
|
||||
|
||||
interface TestCacheValue {
|
||||
val: number;
|
||||
}
|
||||
|
||||
describe('Cache', () => {
|
||||
describe('has', () => {
|
||||
it('positive', () => {
|
||||
const cache = new Cache<string, TestCacheValue>();
|
||||
cache.set('test', { val: 2 });
|
||||
expect(cache.has('test')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('negative', () => {
|
||||
const cache = new Cache<string, TestCacheValue>();
|
||||
expect(cache.has('absent')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('get', () => {
|
||||
it('positive', () => {
|
||||
const cache = new Cache<string, TestCacheValue>();
|
||||
cache.set('test', { val: 2 });
|
||||
expect(cache.get('test')).toEqual({ val: 2 });
|
||||
});
|
||||
|
||||
it('negative', () => {
|
||||
const cache = new Cache<string, TestCacheValue>();
|
||||
expect(cache.get('absent')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
it('delete', () => {
|
||||
const cache = new Cache<string, TestCacheValue>();
|
||||
cache.set('test-1', { val: 1 });
|
||||
cache.set('test-2', { val: 2 });
|
||||
cache.set('test-3', { val: 3 });
|
||||
|
||||
cache.delete('test-2');
|
||||
|
||||
expect(cache.get('test-2')).toBeNull();
|
||||
expect(cache.get('test-1')).toEqual({ val: 1 });
|
||||
expect(cache.get('test-3')).toEqual({ val: 3 });
|
||||
});
|
||||
|
||||
it('clear', () => {
|
||||
const cache = new Cache<string, TestCacheValue>();
|
||||
cache.set('test-1', { val: 1 });
|
||||
cache.set('test-2', { val: 2 });
|
||||
cache.set('test-3', { val: 3 });
|
||||
|
||||
cache.clear();
|
||||
|
||||
expect(cache.get('test-1')).toBeNull();
|
||||
expect(cache.get('test-2')).toBeNull();
|
||||
expect(cache.get('test-3')).toBeNull();
|
||||
});
|
||||
|
||||
it('getMatches', () => {
|
||||
const cache = new Cache<string, TestCacheValue>();
|
||||
cache.set('test-1', { val: 1 });
|
||||
cache.set('test-2', { val: 2 });
|
||||
cache.set('test-3', { val: 3 });
|
||||
|
||||
expect(cache.getMatches((obj) => obj.val >= 2)).toEqual([{ val: 2 }, { val: 3 }]);
|
||||
});
|
||||
|
||||
it('entries', () => {
|
||||
const cache = new Cache<string, TestCacheValue>();
|
||||
cache.set('test-1', { val: 1 });
|
||||
cache.set('test-2', { val: 2 });
|
||||
cache.set('test-3', { val: 3 });
|
||||
|
||||
expect([...cache.entries()]).toEqual([
|
||||
['test-1', { val: 1 }],
|
||||
['test-2', { val: 2 }],
|
||||
['test-3', { val: 3 }],
|
||||
]);
|
||||
});
|
||||
});
|
||||
Vendored
+88
@@ -0,0 +1,88 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { EqualityCache } from '../../src/cache/equality-cache';
|
||||
|
||||
interface TestCacheValue {
|
||||
val: number;
|
||||
}
|
||||
|
||||
describe('EqualityCache', () => {
|
||||
describe('has', () => {
|
||||
it('positive', () => {
|
||||
const cache = new EqualityCache<string, TestCacheValue>();
|
||||
cache.set('test', { val: 2 });
|
||||
expect(cache.has('test')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('negative', () => {
|
||||
const cache = new EqualityCache<string, TestCacheValue>();
|
||||
expect(cache.has('absent')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('get', () => {
|
||||
it('positive', () => {
|
||||
const cache = new EqualityCache<string, TestCacheValue>();
|
||||
const original = { val: 2 };
|
||||
cache.set('test', original);
|
||||
|
||||
const replacement = { val: 2 };
|
||||
cache.set('test', replacement);
|
||||
|
||||
expect(cache.get('test')).not.toBe(original);
|
||||
expect(cache.get('test')).toBe(replacement);
|
||||
});
|
||||
|
||||
it('negative', () => {
|
||||
const cache = new EqualityCache<string, TestCacheValue>();
|
||||
expect(cache.get('absent')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
it('delete', () => {
|
||||
const cache = new EqualityCache<string, TestCacheValue>();
|
||||
cache.set('test-1', { val: 1 });
|
||||
cache.set('test-2', { val: 2 });
|
||||
cache.set('test-3', { val: 3 });
|
||||
|
||||
cache.delete('test-2');
|
||||
|
||||
expect(cache.get('test-2')).toBeNull();
|
||||
expect(cache.get('test-1')).toEqual({ val: 1 });
|
||||
expect(cache.get('test-3')).toEqual({ val: 3 });
|
||||
});
|
||||
|
||||
it('clear', () => {
|
||||
const cache = new EqualityCache<string, TestCacheValue>();
|
||||
cache.set('test-1', { val: 1 });
|
||||
cache.set('test-2', { val: 2 });
|
||||
cache.set('test-3', { val: 3 });
|
||||
|
||||
cache.clear();
|
||||
|
||||
expect(cache.get('test-1')).toBeNull();
|
||||
expect(cache.get('test-2')).toBeNull();
|
||||
expect(cache.get('test-3')).toBeNull();
|
||||
});
|
||||
|
||||
it('getMatches', () => {
|
||||
const cache = new EqualityCache<string, TestCacheValue>();
|
||||
cache.set('test-1', { val: 1 });
|
||||
cache.set('test-2', { val: 2 });
|
||||
cache.set('test-3', { val: 3 });
|
||||
|
||||
expect(cache.getMatches((obj) => obj.val >= 2)).toEqual([{ val: 2 }, { val: 3 }]);
|
||||
});
|
||||
|
||||
it('entries', () => {
|
||||
const cache = new EqualityCache<string, TestCacheValue>();
|
||||
cache.set('test-1', { val: 1 });
|
||||
cache.set('test-2', { val: 2 });
|
||||
cache.set('test-3', { val: 3 });
|
||||
|
||||
expect([...cache.entries()]).toEqual([
|
||||
['test-1', { val: 1 }],
|
||||
['test-2', { val: 2 }],
|
||||
['test-3', { val: 3 }],
|
||||
]);
|
||||
});
|
||||
});
|
||||
Vendored
+91
@@ -0,0 +1,91 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { EqualityMap } from '../../src/cache/equality-map';
|
||||
|
||||
describe('EqualityMap', () => {
|
||||
it('should set and get values with primitive keys', () => {
|
||||
const map = new EqualityMap<string, number>();
|
||||
map.set('a', 1);
|
||||
expect(map.get('a')).toBe(1);
|
||||
expect(map.has('a')).toBe(true);
|
||||
expect(map.get('b')).toBeUndefined();
|
||||
expect(map.has('b')).toBe(false);
|
||||
});
|
||||
|
||||
it('should set and get values with object keys using deep equality', () => {
|
||||
const map = new EqualityMap<{ x: number }, string>();
|
||||
map.set({ x: 1 }, 'foo');
|
||||
expect(map.get({ x: 1 })).toBe('foo');
|
||||
expect(map.has({ x: 1 })).toBe(true);
|
||||
expect(map.get({ x: 2 })).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should overwrite value if key is deeply equal', () => {
|
||||
const map = new EqualityMap<{ y: number }, string>();
|
||||
map.set({ y: 2 }, 'bar');
|
||||
map.set({ y: 2 }, 'baz');
|
||||
expect(map.get({ y: 2 })).toBe('baz');
|
||||
expect(map.size).toBe(1);
|
||||
});
|
||||
|
||||
it('should delete values by deep equality', () => {
|
||||
const map = new EqualityMap<{ z: number }, string>();
|
||||
map.set({ z: 3 }, 'val');
|
||||
expect(map.delete({ z: 3 })).toBe(true);
|
||||
expect(map.get({ z: 3 })).toBeUndefined();
|
||||
expect(map.size).toBe(0);
|
||||
});
|
||||
|
||||
it('should clear all values', () => {
|
||||
const map = new EqualityMap<number, string>();
|
||||
map.set(1, 'a');
|
||||
map.set(2, 'b');
|
||||
map.clear();
|
||||
expect(map.size).toBe(0);
|
||||
expect(map.get(1)).toBeUndefined();
|
||||
expect(map.get(2)).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should iterate entries', () => {
|
||||
const map = new EqualityMap<string, number>();
|
||||
map.set('a', 1);
|
||||
map.set('b', 2);
|
||||
const entries = Array.from(map);
|
||||
expect(entries).toContainEqual(['a', 1]);
|
||||
expect(entries).toContainEqual(['b', 2]);
|
||||
});
|
||||
|
||||
it('should iterate keys', () => {
|
||||
const map = new EqualityMap<string, number>();
|
||||
map.set('x', 10);
|
||||
map.set('y', 20);
|
||||
const keys = Array.from(map.keys());
|
||||
expect(keys).toContain('x');
|
||||
expect(keys).toContain('y');
|
||||
});
|
||||
|
||||
it('should iterate values', () => {
|
||||
const map = new EqualityMap<string, number>();
|
||||
map.set('foo', 100);
|
||||
map.set('bar', 200);
|
||||
const values = Array.from(map.values());
|
||||
expect(values).toContain(100);
|
||||
expect(values).toContain(200);
|
||||
});
|
||||
|
||||
it('should call forEach with correct arguments', () => {
|
||||
const map = new EqualityMap<string, number>();
|
||||
map.set('a', 1);
|
||||
map.set('b', 2);
|
||||
const calls: [number, string][] = [];
|
||||
map.forEach((value, key) => {
|
||||
calls.push([value, key]);
|
||||
});
|
||||
expect(calls).toContainEqual([1, 'a']);
|
||||
expect(calls).toContainEqual([2, 'b']);
|
||||
});
|
||||
|
||||
it('should have correct Symbol.toStringTag', () => {
|
||||
const map = new EqualityMap<number, number>();
|
||||
expect(Object.prototype.toString.call(map)).toBe('[object EqualityMap]');
|
||||
});
|
||||
});
|
||||
Vendored
+145
@@ -0,0 +1,145 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { ExpiringEqualityCache } from '../../src/cache/expiring-cache';
|
||||
|
||||
describe('ExpiringEqualityCache', () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
it('should set and get a value', () => {
|
||||
const cache = new ExpiringEqualityCache<string, number>();
|
||||
cache.set('foo', 123);
|
||||
expect(cache.get('foo')).toBe(123);
|
||||
});
|
||||
|
||||
it('should return null for a non-existent key', () => {
|
||||
const cache = new ExpiringEqualityCache<string, number>();
|
||||
expect(cache.get('foo')).toBeNull();
|
||||
});
|
||||
|
||||
it('should return null for an expired key', () => {
|
||||
const cache = new ExpiringEqualityCache<string, number>();
|
||||
const expiryDate = new Date(Date.now() + 1000);
|
||||
cache.set('foo', 123, expiryDate);
|
||||
vi.advanceTimersByTime(1001);
|
||||
expect(cache.get('foo')).toBeNull();
|
||||
});
|
||||
|
||||
it('should return the value if not expired', () => {
|
||||
const cache = new ExpiringEqualityCache<string, number>();
|
||||
const expiryDate = new Date(Date.now() + 1000);
|
||||
cache.set('foo', 123, expiryDate);
|
||||
vi.advanceTimersByTime(500);
|
||||
expect(cache.get('foo')).toBe(123);
|
||||
});
|
||||
|
||||
it('should correctly report has for existing non-expired key', () => {
|
||||
const cache = new ExpiringEqualityCache<string, number>();
|
||||
cache.set('foo', 123, new Date(Date.now() + 1000));
|
||||
expect(cache.has('foo')).toBe(true);
|
||||
});
|
||||
|
||||
it('should correctly report has for existing key with no expiry', () => {
|
||||
const cache = new ExpiringEqualityCache<string, number>();
|
||||
cache.set('foo', 123);
|
||||
expect(cache.has('foo')).toBe(true);
|
||||
});
|
||||
|
||||
it('should correctly report not for has for non-existent key', () => {
|
||||
const cache = new ExpiringEqualityCache<string, number>();
|
||||
expect(cache.has('foo')).toBe(false);
|
||||
});
|
||||
|
||||
it('should correctly report not for has for expired key', () => {
|
||||
const cache = new ExpiringEqualityCache<string, number>();
|
||||
cache.set('foo', 123, new Date(Date.now() + 1000));
|
||||
vi.advanceTimersByTime(1001);
|
||||
expect(cache.has('foo')).toBe(false);
|
||||
});
|
||||
|
||||
it('should delete a key', () => {
|
||||
const cache = new ExpiringEqualityCache<string, number>();
|
||||
cache.set('foo', 123);
|
||||
expect(cache.delete('foo')).toBe(true);
|
||||
expect(cache.get('foo')).toBeNull();
|
||||
expect(cache.has('foo')).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when deleting a non-existent key', () => {
|
||||
const cache = new ExpiringEqualityCache<string, number>();
|
||||
expect(cache.delete('foo')).toBe(false);
|
||||
});
|
||||
|
||||
it('should clear all keys', () => {
|
||||
const cache = new ExpiringEqualityCache<string, number>();
|
||||
cache.set('foo', 123);
|
||||
cache.set('bar', 456, new Date(Date.now() + 1000));
|
||||
cache.clear();
|
||||
expect(cache.get('foo')).toBeNull();
|
||||
expect(cache.get('bar')).toBeNull();
|
||||
expect(cache.has('foo')).toBe(false);
|
||||
expect(cache.has('bar')).toBe(false);
|
||||
});
|
||||
|
||||
it('should iterate over entries', () => {
|
||||
const cache = new ExpiringEqualityCache<string, number>();
|
||||
|
||||
cache.set('forever', 42);
|
||||
cache.set('bas', 43, new Date(Date.now()));
|
||||
cache.set('foo', 44, new Date(Date.now() + 1000));
|
||||
cache.set('bar', 45, new Date(Date.now() + 2000));
|
||||
|
||||
vi.advanceTimersByTime(1001);
|
||||
|
||||
expect([...cache.entries()]).toEqual([
|
||||
['forever', 42],
|
||||
['bar', 45],
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return empty iterator for an empty cache', () => {
|
||||
const cache = new ExpiringEqualityCache<string, number>();
|
||||
const entries = Array.from(cache.entries());
|
||||
expect(entries).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should return empty iterator if all entries are expired', () => {
|
||||
const cache = new ExpiringEqualityCache<string, number>();
|
||||
cache.set('foo', 123, new Date(Date.now() - 1000));
|
||||
cache.set('bar', 456, new Date(Date.now() - 500));
|
||||
vi.advanceTimersByTime(1); // Ensure current time is past expiry
|
||||
const entries = Array.from(cache.entries());
|
||||
expect(entries).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should get matches for non-expired values', () => {
|
||||
const cache = new ExpiringEqualityCache<string, { id: number; type: string }>();
|
||||
cache.set('a', { id: 1, type: 'A' });
|
||||
cache.set('b', { id: 2, type: 'B' }, new Date(Date.now() + 1000));
|
||||
cache.set('c', { id: 3, type: 'A' }, new Date(Date.now() - 1000)); // expired
|
||||
cache.set('d', { id: 4, type: 'A' }, new Date(Date.now() + 500));
|
||||
|
||||
const matches = cache.getMatches((value) => value.type === 'A');
|
||||
expect(matches).toHaveLength(2);
|
||||
expect(matches).toContainEqual({ id: 1, type: 'A' });
|
||||
expect(matches).toContainEqual({ id: 4, type: 'A' });
|
||||
});
|
||||
|
||||
it('should return empty array for getMatches on an empty cache', () => {
|
||||
const cache = new ExpiringEqualityCache<string, { id: number }>();
|
||||
const matches = cache.getMatches((value) => value.id > 0);
|
||||
expect(matches).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should return empty array for getMatches if no values match predicate', () => {
|
||||
const cache = new ExpiringEqualityCache<string, { id: number }>();
|
||||
cache.set('a', { id: 1 });
|
||||
cache.set('b', { id: 2 });
|
||||
const matches = cache.getMatches((value) => value.id > 5);
|
||||
expect(matches).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
Vendored
+70
@@ -0,0 +1,70 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { LRUCache } from '../../src/cache/lru';
|
||||
|
||||
interface TestCacheValue {
|
||||
val: number;
|
||||
}
|
||||
|
||||
describe('LRUCache', () => {
|
||||
describe('has', () => {
|
||||
it('positive', () => {
|
||||
const cache = new LRUCache<string, TestCacheValue>(1);
|
||||
cache.set('test', { val: 2 });
|
||||
expect(cache.has('test')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('negative', () => {
|
||||
const cache = new LRUCache<string, TestCacheValue>(1);
|
||||
expect(cache.has('absent')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('get', () => {
|
||||
it('positive', () => {
|
||||
const cache = new LRUCache<string, TestCacheValue>(1);
|
||||
cache.set('test', { val: 2 });
|
||||
expect(cache.get('test')).toEqual({ val: 2 });
|
||||
});
|
||||
|
||||
it('negative', () => {
|
||||
const cache = new LRUCache<string, TestCacheValue>(1);
|
||||
expect(cache.get('absent')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
it('delete', () => {
|
||||
const cache = new LRUCache<string, TestCacheValue>(1);
|
||||
cache.set('test-1', { val: 1 });
|
||||
|
||||
cache.delete('test-1');
|
||||
|
||||
expect(cache.get('test-1')).toBeNull();
|
||||
});
|
||||
|
||||
it('clear', () => {
|
||||
const cache = new LRUCache<string, TestCacheValue>(1);
|
||||
cache.set('test-1', { val: 1 });
|
||||
|
||||
cache.clear();
|
||||
|
||||
expect(cache.get('test-1')).toBeNull();
|
||||
});
|
||||
|
||||
it('getMatches', () => {
|
||||
const cache = new LRUCache<string, TestCacheValue>(1);
|
||||
cache.set('test-1', { val: 1 });
|
||||
cache.set('test-2', { val: 2 });
|
||||
cache.set('test-3', { val: 3 });
|
||||
|
||||
expect(cache.getMatches((obj) => obj.val >= 0)).toEqual([{ val: 3 }]);
|
||||
});
|
||||
|
||||
it('entries', () => {
|
||||
const cache = new LRUCache<string, TestCacheValue>(1);
|
||||
cache.set('test-1', { val: 1 });
|
||||
cache.set('test-2', { val: 2 });
|
||||
cache.set('test-3', { val: 3 });
|
||||
|
||||
expect([...cache.entries()]).toEqual([['test-3', { val: 3 }]]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user