mirror of
https://github.com/linshenkx/prompt-optimizer.git
synced 2026-06-05 05:59:40 +08:00
213 lines
7.4 KiB
TypeScript
213 lines
7.4 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
import { PreferenceService } from '../../../src/services/preference/service';
|
|
import { MemoryStorageProvider } from '../../../src/services/storage/memoryStorageProvider';
|
|
|
|
describe('PreferenceService', () => {
|
|
let preferenceService: PreferenceService;
|
|
let mockStorage: MemoryStorageProvider;
|
|
|
|
beforeEach(() => {
|
|
mockStorage = new MemoryStorageProvider();
|
|
preferenceService = new PreferenceService(mockStorage);
|
|
});
|
|
|
|
describe('基本功能', () => {
|
|
it('should set and get preference', async () => {
|
|
await preferenceService.set('test-key', 'test-value');
|
|
const value = await preferenceService.get('test-key', null);
|
|
|
|
expect(value).toBe('test-value');
|
|
});
|
|
|
|
it('should return default value when key does not exist', async () => {
|
|
const value = await preferenceService.get('non-existent-key', 'default');
|
|
|
|
expect(value).toBe('default');
|
|
});
|
|
|
|
it('should delete preference', async () => {
|
|
await preferenceService.set('test-key', 'test-value');
|
|
await preferenceService.delete('test-key');
|
|
const value = await preferenceService.get('test-key', 'default');
|
|
|
|
expect(value).toBe('default');
|
|
});
|
|
|
|
it('should clear all preferences', async () => {
|
|
await preferenceService.set('key1', 'value1');
|
|
await preferenceService.set('key2', 'value2');
|
|
|
|
await preferenceService.clear();
|
|
|
|
const value1 = await preferenceService.get('key1', 'default');
|
|
const value2 = await preferenceService.get('key2', 'default');
|
|
|
|
expect(value1).toBe('default');
|
|
expect(value2).toBe('default');
|
|
});
|
|
});
|
|
|
|
describe('批量操作', () => {
|
|
it('should get all preferences', async () => {
|
|
await preferenceService.set('app:settings:ui:theme-id', 'dark');
|
|
await preferenceService.set('app:settings:ui:preferred-language', 'zh-CN');
|
|
await preferenceService.set('app:selected-optimize-model', 'gemini');
|
|
|
|
const allPreferences = await preferenceService.getAll();
|
|
|
|
expect(allPreferences).toEqual({
|
|
'app:settings:ui:theme-id': 'dark',
|
|
'app:settings:ui:preferred-language': 'zh-CN',
|
|
'app:selected-optimize-model': 'gemini'
|
|
});
|
|
});
|
|
|
|
it('should return empty object when no preferences exist', async () => {
|
|
const allPreferences = await preferenceService.getAll();
|
|
|
|
expect(allPreferences).toEqual({});
|
|
});
|
|
|
|
it('should handle errors gracefully in getAll', async () => {
|
|
// 设置一些正常的偏好
|
|
await preferenceService.set('valid-key', 'valid-value');
|
|
|
|
// 模拟存储中有损坏的数据
|
|
await mockStorage.setItem('pref:invalid-key', 'invalid-json{');
|
|
|
|
const allPreferences = await preferenceService.getAll();
|
|
|
|
// 应该返回有效的偏好,跳过无效的
|
|
expect(allPreferences).toEqual({
|
|
'valid-key': 'valid-value'
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('键名管理', () => {
|
|
it('should list all preference keys', async () => {
|
|
await preferenceService.set('key1', 'value1');
|
|
await preferenceService.set('key2', 'value2');
|
|
|
|
const keys = await preferenceService.keys();
|
|
|
|
expect(keys).toContain('key1');
|
|
expect(keys).toContain('key2');
|
|
expect(keys).toHaveLength(2);
|
|
});
|
|
|
|
it('should handle prefix correctly in storage', async () => {
|
|
await preferenceService.set('test-key', 'test-value');
|
|
|
|
// 直接检查存储中的键名应该带有前缀
|
|
const storageValue = await mockStorage.getItem('pref:test-key');
|
|
expect(storageValue).toBe('"test-value"');
|
|
|
|
// 但是keys()方法应该返回不带前缀的键名
|
|
const keys = await preferenceService.keys();
|
|
expect(keys).toContain('test-key');
|
|
expect(keys).not.toContain('pref:test-key');
|
|
});
|
|
});
|
|
|
|
describe('数据类型处理', () => {
|
|
it('should handle different data types', async () => {
|
|
await preferenceService.set('string-key', 'string-value');
|
|
await preferenceService.set('number-key', 42);
|
|
await preferenceService.set('boolean-key', true);
|
|
await preferenceService.set('object-key', { nested: 'value' });
|
|
|
|
expect(await preferenceService.get('string-key', null)).toBe('string-value');
|
|
expect(await preferenceService.get('number-key', null)).toBe(42);
|
|
expect(await preferenceService.get('boolean-key', null)).toBe(true);
|
|
expect(await preferenceService.get('object-key', null)).toEqual({ nested: 'value' });
|
|
});
|
|
|
|
it('should convert all values to strings in getAll', async () => {
|
|
await preferenceService.set('string-key', 'string-value');
|
|
await preferenceService.set('number-key', 42);
|
|
await preferenceService.set('boolean-key', true);
|
|
|
|
const allPreferences = await preferenceService.getAll();
|
|
|
|
expect(allPreferences).toEqual({
|
|
'string-key': 'string-value',
|
|
'number-key': '42',
|
|
'boolean-key': 'true'
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('错误处理', () => {
|
|
it('should reject undefined preference keys with a clear error', async () => {
|
|
await mockStorage.setItem('pref:undefined', 'true')
|
|
|
|
await expect(
|
|
preferenceService.get(undefined as unknown as string, false)
|
|
).rejects.toThrow('Invalid preference key')
|
|
})
|
|
|
|
it('should reject oversized session snapshots on write', async () => {
|
|
const oversizedValue = {
|
|
payload: 'x'.repeat(1024 * 1024 + 128),
|
|
}
|
|
|
|
await expect(
|
|
preferenceService.set('session/v1/image-multiimage', oversizedValue)
|
|
).rejects.toMatchObject({
|
|
code: 'error.storage.write',
|
|
params: expect.objectContaining({
|
|
reason: 'session_snapshot_too_large',
|
|
key: 'session/v1/image-multiimage',
|
|
}),
|
|
})
|
|
});
|
|
|
|
it('should reject oversized session snapshots on read before parsing', async () => {
|
|
const oversizedRaw = JSON.stringify({
|
|
payload: 'x'.repeat(1024 * 1024 + 128),
|
|
})
|
|
|
|
await mockStorage.setItem('pref:session/v1/image-multiimage', oversizedRaw)
|
|
|
|
await expect(
|
|
preferenceService.get('session/v1/image-multiimage', null)
|
|
).rejects.toMatchObject({
|
|
code: 'error.storage.read',
|
|
params: expect.objectContaining({
|
|
reason: 'session_snapshot_too_large',
|
|
key: 'session/v1/image-multiimage',
|
|
}),
|
|
})
|
|
});
|
|
|
|
it('should handle storage errors in get', async () => {
|
|
const mockStorageWithError = {
|
|
getItem: vi.fn().mockRejectedValue(new Error('Storage error')),
|
|
setItem: vi.fn(),
|
|
removeItem: vi.fn(),
|
|
keys: vi.fn().mockResolvedValue([]),
|
|
clear: vi.fn()
|
|
};
|
|
|
|
const serviceWithError = new PreferenceService(mockStorageWithError as any);
|
|
|
|
await expect(serviceWithError.get('test-key', 'default')).rejects.toThrow('Failed to get preference');
|
|
});
|
|
|
|
it('should handle storage errors in set', async () => {
|
|
const mockStorageWithError = {
|
|
getItem: vi.fn(),
|
|
setItem: vi.fn().mockRejectedValue(new Error('Storage error')),
|
|
removeItem: vi.fn(),
|
|
keys: vi.fn().mockResolvedValue([]),
|
|
clear: vi.fn()
|
|
};
|
|
|
|
const serviceWithError = new PreferenceService(mockStorageWithError as any);
|
|
|
|
await expect(serviceWithError.set('test-key', 'test-value')).rejects.toThrow('Failed to set preference');
|
|
});
|
|
});
|
|
});
|