UNPKG

@speckle/objectloader2

Version:

This is an updated objectloader for the Speckle viewer written in typescript

151 lines 6.28 kB
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest'; import { MemoryCache, MemoryCacheItem } from './MemoryCache.js'; const logger = () => { // console.log(message, ...optionalParams) }; const defaultOptions = { maxSizeInMb: 10, ttlms: 1000 }; const createItem = (id, size, referencedIds = []) => { const base = { id, // eslint-disable-next-line camelcase speckle_type: 'Base' }; if (referencedIds.length > 0) { base.data = referencedIds.map((referencedId) => ({ // eslint-disable-next-line camelcase speckle_type: 'reference', referencedId })); } return { baseId: id, base, size }; }; describe('MemoryCacheItem', () => { it('should correctly determine if it is expired', () => { const item = createItem('1', 100); const now = Date.now(); const cacheItem = new MemoryCacheItem(item, now + 1000); expect(cacheItem.isExpired(now + 500)).toBe(false); expect(cacheItem.isExpired(now + 1500)).toBe(true); }); it('should update its access time', () => { const item = createItem('1', 100); const now = Date.now(); const cacheItem = new MemoryCacheItem(item, now + 1000); cacheItem.setAccess(now + 500, 1000); expect(cacheItem.isExpired(now + 1000)).toBe(false); expect(cacheItem.isExpired(now + 1600)).toBe(true); }); it('should return the correct item', () => { const item = createItem('1', 100); const cacheItem = new MemoryCacheItem(item, Date.now() + 1000); expect(cacheItem.getItem()).toEqual(item); }); it('should be done if expired', () => { const item = createItem('1', 100); const now = Date.now(); const cacheItem = new MemoryCacheItem(item, now + 1000); expect(cacheItem.done(now + 1500)).toBe(true); expect(cacheItem.done(now + 500)).toBe(false); }); }); describe('MemoryCache', () => { beforeEach(() => { vi.useFakeTimers(); }); afterEach(() => { vi.useRealTimers(); }); it('should add and get an item', () => { const cache = new MemoryCache(defaultOptions, logger); const item = createItem('1', 100); const requestItem = vi.fn(); cache.add(item, requestItem); const retrieved = cache.get('1'); expect(retrieved).toEqual(item); expect(requestItem).not.toHaveBeenCalled(); }); it('should update expiry on get', () => { const cache = new MemoryCache({ ...defaultOptions, ttlms: 100 }, logger); const item = createItem('1', 100); cache.add(item, vi.fn()); vi.advanceTimersByTime(50); const retrieved = cache.get('1'); expect(retrieved).toBeDefined(); vi.advanceTimersByTime(80); const retrievedAgain = cache.get('1'); expect(retrievedAgain).toBeDefined(); }); it('should return undefined for non-existent item', () => { const cache = new MemoryCache(defaultOptions, logger); expect(cache.get('non-existent')).toBeUndefined(); }); it('should scan for references and request missing ones', () => { const cache = new MemoryCache(defaultOptions, logger); const requestItem = vi.fn(); const item = createItem('1', 100, ['2', '3']); cache.add(createItem('3', 50), vi.fn()); // pre-cache one of the references cache.scanForReferences(item.base, requestItem); expect(requestItem).toHaveBeenCalledTimes(1); expect(requestItem).toHaveBeenCalledWith('2'); expect(requestItem).not.toHaveBeenCalledWith('3'); }); it('should clean up expired items when size exceeds max', () => { const options = { maxSizeInMb: 0, ttlms: 100 }; // 100 bytes const cache = new MemoryCache(options, logger); const requestItem = vi.fn(); const item1 = createItem('1', 60); const item2 = createItem('2', 60); const now = 1; cache.add(item1, requestItem, now - 200); cache.cleanCache(now); cache.add(item2, requestItem, now + 100); expect(cache.get('1')).toBeUndefined(); expect(cache.get('2')).toBeDefined(); }); it('should not clean up expired items if they have references', () => { const options = { maxSizeInMb: 0.0001, ttlms: 100 }; // 100 bytes const cache = new MemoryCache(options, logger); const requestItem = vi.fn(); const item1 = createItem('1', 60); const item2 = createItem('2', 60, ['1']); cache.add(item1, requestItem); vi.advanceTimersByTime(110); // item1 expires cache.add(item2, requestItem); // item2 adds a reference to item1 vi.advanceTimersByTime(100); expect(cache.get('1')).toBeDefined(); expect(cache.get('2')).toBeDefined(); }); it('compareMaybeBasesByReferences should sort correctly', () => { const cache = new MemoryCache(defaultOptions, logger); const requestItem = vi.fn(); const item1 = createItem('1', 10); const item2 = createItem('2', 10); const item3 = createItem('3', 10, ['1', '2']); const item4 = createItem('4', 10, ['2']); cache.add(item1, requestItem); cache.add(item2, requestItem); cache.add(item3, requestItem); cache.add(item4, requestItem); expect(cache.compareMaybeBasesByReferences('1', '2')).toBe(-1); expect(cache.compareMaybeBasesByReferences('2', '1')).toBe(1); expect(cache.compareMaybeBasesByReferences('1', '1')).toBe(0); expect(cache.compareMaybeBasesByReferences('1', '5')).toBe(1); expect(cache.compareMaybeBasesByReferences('5', '1')).toBe(-1); expect(cache.compareMaybeBasesByReferences('5', '6')).toBe(0); }); it('should throw when used after dispose', () => { const cache = new MemoryCache(defaultOptions, logger); cache.dispose(); const item = createItem('1', 100); expect(() => cache.add(item, vi.fn())).toThrow('MemoryCache is disposed'); expect(() => cache.get('1')).toThrow('MemoryCache is disposed'); }); }); //# sourceMappingURL=MemoryCache.test.js.map