Back to home page

EIC code displayed by LXR

 
 

    


Warning, /firebird/firebird-ng/src/app/utils/config-property.spec.ts is written in an unsupported language. File is not indexed.

0001 import { ConfigProperty } from './config-property';
0002 
0003 // Mock storage for testing
0004 class MockStorage {
0005     private storage: Map<string, string> = new Map();
0006 
0007     getItem(key: string): string | null {
0008         return this.storage.get(key) || null;
0009     }
0010 
0011     setItem(key: string, value: string): void {
0012         this.storage.set(key, value);
0013     }
0014 
0015     clear(): void {
0016         this.storage.clear();
0017     }
0018 
0019     // Helper to inspect storage contents for testing
0020     getAll(): Map<string, string> {
0021         return new Map(this.storage);
0022     }
0023 }
0024 
0025 describe('ConfigProperty', () => {
0026     let mockStorage: MockStorage;
0027 
0028     beforeEach(() => {
0029         mockStorage = new MockStorage();
0030     });
0031 
0032     describe('constructor', () => {
0033         it('should initialize with default value when storage is empty', () => {
0034             const prop = new ConfigProperty('testKey', 'defaultValue', undefined, undefined, mockStorage);
0035             expect(prop.value).toBe('defaultValue');
0036         });
0037 
0038         it('should load value from storage if present', () => {
0039             // For string values, storage holds the raw string (not JSON-encoded)
0040             mockStorage.setItem('testKey', 'storedValue');
0041             const prop = new ConfigProperty('testKey', 'defaultValue', undefined, undefined, mockStorage);
0042             expect(prop.value).toBe('storedValue');
0043         });
0044 
0045         it('should use default if stored value fails validation', () => {
0046             // For string values, storage holds the raw string (not JSON-encoded)
0047             mockStorage.setItem('testKey', 'invalid');
0048             const validator = (v: string) => v.startsWith('valid');
0049             const prop = new ConfigProperty('testKey', 'validDefault', undefined, validator, mockStorage);
0050             expect(prop.value).toBe('validDefault');
0051         });
0052     });
0053 
0054     describe('setValue', () => {
0055         it('should update value and storage', () => {
0056             const prop = new ConfigProperty('testKey', 'default', undefined, undefined, mockStorage);
0057             prop.setValue('newValue');
0058             expect(prop.value).toBe('newValue');
0059             expect(mockStorage.getItem('testKey')).toBe('newValue');
0060         });
0061 
0062         it('should update timestamp when setting value', () => {
0063             const prop = new ConfigProperty('testKey', 'default', undefined, undefined, mockStorage);
0064             const beforeTime = Date.now();
0065             prop.setValue('newValue');
0066             const afterTime = Date.now();
0067 
0068             const timestamp = prop.getTimestamp();
0069             expect(timestamp).not.toBeNull();
0070             expect(timestamp!).toBeGreaterThanOrEqual(beforeTime);
0071             expect(timestamp!).toBeLessThanOrEqual(afterTime);
0072         });
0073 
0074         it('should use explicit timestamp when provided', () => {
0075             const prop = new ConfigProperty('testKey', 'default', undefined, undefined, mockStorage);
0076             const explicitTime = 1000000;
0077             prop.setValue('newValue', explicitTime);
0078             expect(prop.getTimestamp()).toBe(explicitTime);
0079         });
0080 
0081         it('should not update if explicit timestamp is older than stored', () => {
0082             const prop = new ConfigProperty('testKey', 'default', undefined, undefined, mockStorage);
0083             prop.setValue('first', 2000);
0084             prop.setValue('second', 1000); // older timestamp
0085             expect(prop.value).toBe('first');
0086         });
0087 
0088         it('should reject invalid values', () => {
0089             const validator = (v: number) => v > 0;
0090             const prop = new ConfigProperty<number>('testKey', 10, undefined, validator, mockStorage);
0091             prop.setValue(-5 as number);
0092             expect(prop.value).toBe(10); // unchanged
0093         });
0094 
0095         it('should call saveCallback after setting value', () => {
0096             const callback = vi.fn();
0097             const prop = new ConfigProperty('testKey', 'default', callback, undefined, mockStorage);
0098             prop.setValue('newValue');
0099             expect(callback).toHaveBeenCalled();
0100         });
0101     });
0102 
0103     describe('setDefault', () => {
0104         it('should reset value to default', () => {
0105             const prop = new ConfigProperty('testKey', 'default', undefined, undefined, mockStorage);
0106             prop.setValue('changed');
0107             expect(prop.value).toBe('changed');
0108 
0109             prop.setDefault();
0110             expect(prop.value).toBe('default');
0111         });
0112 
0113         it('should persist default value to storage', () => {
0114             const prop = new ConfigProperty('testKey', 'default', undefined, undefined, mockStorage);
0115             prop.setValue('changed');
0116             expect(mockStorage.getItem('testKey')).toBe('changed');
0117 
0118             prop.setDefault();
0119             expect(mockStorage.getItem('testKey')).toBe('default');
0120         });
0121 
0122         it('should update timestamp when setting default', () => {
0123             const prop = new ConfigProperty('testKey', 'default', undefined, undefined, mockStorage);
0124 
0125             // Set a value with an old timestamp
0126             const oldTime = 1000;
0127             prop.setValue('changed', oldTime);
0128             expect(prop.getTimestamp()).toBe(oldTime);
0129 
0130             // setDefault should update the timestamp to current time
0131             const beforeReset = Date.now();
0132             prop.setDefault();
0133             const afterReset = Date.now();
0134 
0135             const newTimestamp = prop.getTimestamp();
0136             expect(newTimestamp).not.toBeNull();
0137             expect(newTimestamp!).toBeGreaterThanOrEqual(beforeReset);
0138             expect(newTimestamp!).toBeLessThanOrEqual(afterReset);
0139         });
0140 
0141         it('should allow subsequent setValue after setDefault respects timestamp logic', () => {
0142             const prop = new ConfigProperty('testKey', 'default', undefined, undefined, mockStorage);
0143 
0144             // Set value with old timestamp
0145             prop.setValue('old', 1000);
0146 
0147             // Reset to default (gets current timestamp)
0148             prop.setDefault();
0149             const resetTimestamp = prop.getTimestamp();
0150 
0151             // Try to set with older timestamp - should be rejected
0152             prop.setValue('older', 500);
0153             expect(prop.value).toBe('default');
0154 
0155             // Set with newer timestamp - should succeed
0156             prop.setValue('newer', resetTimestamp! + 1000);
0157             expect(prop.value).toBe('newer');
0158         });
0159 
0160         it('should call saveCallback when setting default', () => {
0161             const callback = vi.fn();
0162             const prop = new ConfigProperty('testKey', 'default', callback, undefined, mockStorage);
0163 
0164             callback.mockClear();
0165             prop.setDefault();
0166             expect(callback).toHaveBeenCalled();
0167         });
0168 
0169         it('should notify subscribers when setting default', () => {
0170             const prop = new ConfigProperty('testKey', 'default', undefined, undefined, mockStorage);
0171             prop.setValue('changed');
0172 
0173             const values: string[] = [];
0174             prop.changes$.subscribe(v => values.push(v));
0175 
0176             prop.setDefault();
0177 
0178             expect(values).toContain('default');
0179         });
0180     });
0181 
0182     describe('value getter/setter', () => {
0183         it('should get current value', () => {
0184             const prop = new ConfigProperty('testKey', 'default', undefined, undefined, mockStorage);
0185             expect(prop.value).toBe('default');
0186         });
0187 
0188         it('should set value using property setter', () => {
0189             const prop = new ConfigProperty('testKey', 'default', undefined, undefined, mockStorage);
0190             prop.value = 'newValue';
0191             expect(prop.value).toBe('newValue');
0192         });
0193     });
0194 
0195     describe('key getter', () => {
0196         it('should return the key', () => {
0197             const prop = new ConfigProperty('myKey', 'default', undefined, undefined, mockStorage);
0198             expect(prop.key).toBe('myKey');
0199         });
0200     });
0201 
0202     describe('getTimestamp', () => {
0203         it('should return null when no timestamp is stored', () => {
0204             const prop = new ConfigProperty('testKey', 'default', undefined, undefined, mockStorage);
0205             // Before any setValue, there's no timestamp
0206             expect(prop.getTimestamp()).toBeNull();
0207         });
0208 
0209         it('should return timestamp after setValue', () => {
0210             const prop = new ConfigProperty('testKey', 'default', undefined, undefined, mockStorage);
0211             prop.setValue('value');
0212             expect(prop.getTimestamp()).not.toBeNull();
0213         });
0214     });
0215 
0216     describe('changes$ observable', () => {
0217         it('should emit initial value', () => {
0218             const prop = new ConfigProperty('testKey', 'default', undefined, undefined, mockStorage);
0219             let emittedValue: string | undefined;
0220             prop.changes$.subscribe(v => emittedValue = v);
0221             expect(emittedValue).toBe('default');
0222         });
0223 
0224         it('should emit on value changes', () => {
0225             const prop = new ConfigProperty('testKey', 'default', undefined, undefined, mockStorage);
0226             const values: string[] = [];
0227             prop.changes$.subscribe(v => values.push(v));
0228 
0229             prop.setValue('first');
0230             prop.setValue('second');
0231 
0232             expect(values).toEqual(['default', 'first', 'second']);
0233         });
0234     });
0235 
0236     describe('type handling', () => {
0237         it('should handle string values', () => {
0238             const prop = new ConfigProperty('testKey', 'default', undefined, undefined, mockStorage);
0239             prop.setValue('hello');
0240             expect(mockStorage.getItem('testKey')).toBe('hello');
0241         });
0242 
0243         it('should handle number values', () => {
0244             const prop = new ConfigProperty('testKey', 42, undefined, undefined, mockStorage);
0245             prop.setValue(100);
0246             expect(mockStorage.getItem('testKey')).toBe('100');
0247             expect(prop.value).toBe(100);
0248         });
0249 
0250         it('should handle boolean values', () => {
0251             const prop = new ConfigProperty('testKey', true, undefined, undefined, mockStorage);
0252             prop.setValue(false);
0253             expect(mockStorage.getItem('testKey')).toBe('false');
0254             expect(prop.value).toBe(false);
0255         });
0256 
0257         it('should handle object values', () => {
0258             const prop = new ConfigProperty<Record<string, number>>('testKey', { a: 1 }, undefined, undefined, mockStorage);
0259             prop.setValue({ b: 2 });
0260             expect(mockStorage.getItem('testKey')).toBe('{"b":2}');
0261             expect(prop.value).toEqual({ b: 2 });
0262         });
0263 
0264         it('should handle array values', () => {
0265             const prop = new ConfigProperty('testKey', [1, 2], undefined, undefined, mockStorage);
0266             prop.setValue([3, 4, 5]);
0267             expect(mockStorage.getItem('testKey')).toBe('[3,4,5]');
0268             expect(prop.value).toEqual([3, 4, 5]);
0269         });
0270     });
0271 });