@zhanghongping/json-sage-workflow-cli
Version:
An intelligent JSON processing workflow system with improved error handling and configuration
152 lines (124 loc) • 5.22 kB
text/typescript
import { SmartCache } from '../core/cache';
describe('SmartCache', () => {
let cache: SmartCache<any>;
beforeEach(() => {
cache = new SmartCache({
maxSize: 1000,
ttl: 1000, // 1 second for testing
smartPruning: true
});
});
describe('Basic Operations', () => {
it('should store and retrieve values', () => {
const testData = { test: 'value' };
cache.set('key1', testData);
expect(cache.get('key1')).toEqual(testData);
});
it('should handle non-existent keys', () => {
expect(cache.get('nonexistent')).toBeUndefined();
});
it('should handle undefined and null values', () => {
cache.set('undefined', undefined);
cache.set('null', null);
expect(cache.get('undefined')).toBeUndefined();
expect(cache.get('null')).toBeNull();
});
});
describe('TTL Functionality', () => {
it('should expire items after TTL', async () => {
const testData = { test: 'value' };
cache.set('expiring', testData);
// Wait for TTL to expire
await new Promise(resolve => setTimeout(resolve, 1100));
expect(cache.get('expiring')).toBeUndefined();
});
it('should reset TTL on access', async () => {
const testData = { test: 'value' };
cache.set('accessed', testData);
// Access the item just before expiration
await new Promise(resolve => setTimeout(resolve, 900));
expect(cache.get('accessed')).toEqual(testData);
// Wait another 900ms (total 1800ms, more than original TTL)
await new Promise(resolve => setTimeout(resolve, 900));
expect(cache.get('accessed')).toEqual(testData);
});
});
describe('Size Management', () => {
it('should handle large items', () => {
const largeData = { data: 'x'.repeat(2000) }; // Exceeds maxSize
cache.set('large', largeData);
expect(cache.get('large')).toBeUndefined();
});
it('should evict items when full', () => {
// Fill cache to capacity
for (let i = 0; i < 10; i++) {
cache.set(`key${i}`, { data: 'x'.repeat(90) });
}
// Add one more item
cache.set('newKey', { data: 'test' });
// Some old items should be evicted
let existingItems = 0;
for (let i = 0; i < 10; i++) {
if (cache.get(`key${i}`)) existingItems++;
}
expect(existingItems).toBeLessThan(10);
expect(cache.get('newKey')).toBeDefined();
});
});
describe('Smart Pruning', () => {
it('should prefer keeping frequently accessed items', () => {
// Add items
for (let i = 0; i < 5; i++) {
cache.set(`key${i}`, { data: 'x'.repeat(100) });
}
// Access some items frequently
for (let i = 0; i < 10; i++) {
cache.get('key0');
cache.get('key1');
}
// Fill cache to force eviction
for (let i = 5; i < 10; i++) {
cache.set(`key${i}`, { data: 'x'.repeat(100) });
}
// Frequently accessed items should still be there
expect(cache.get('key0')).toBeDefined();
expect(cache.get('key1')).toBeDefined();
});
});
describe('Statistics', () => {
it('should track cache statistics', () => {
cache.set('key1', 'value1');
cache.get('key1');
cache.get('key1');
const stats = cache.getStats();
expect(stats).toHaveProperty('totalSize');
expect(stats).toHaveProperty('itemCount');
expect(stats).toHaveProperty('utilization');
expect(stats).toHaveProperty('averageAccessCount');
expect(stats.itemCount).toBe(1);
expect(stats.averageAccessCount).toBe(2);
});
});
describe('Edge Cases', () => {
it('should handle circular references', () => {
const circular: any = { name: 'test' };
circular.self = circular;
expect(() => cache.set('circular', circular)).not.toThrow();
});
it('should handle various data types', () => {
const testCases = [
['string', 'test string'],
['number', 123],
['boolean', true],
['array', [1, 2, 3]],
['date', new Date()],
['regexp', /test/],
['function', function() { return 'test'; }]
];
testCases.forEach(([key, value]) => {
cache.set(key as string, value);
expect(cache.get(key as string)).toEqual(value);
});
});
});
});