Back to home page

EIC code displayed by LXR

 
 

    


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

0001 import { PersistentProperty } from './persistent-property';
0002 
0003 describe('ConfigProperty', () => {
0004   let mockStorage: { [key: string]: string };
0005   let mockStorageInterface: any;
0006 
0007   beforeEach(() => {
0008     // Create a mock storage that simulates localStorage
0009     mockStorage = {};
0010     mockStorageInterface = {
0011       getItem: (key: string) => mockStorage[key] || null,
0012       setItem: (key: string, value: string) => { mockStorage[key] = value; }
0013     };
0014   });
0015 
0016   afterEach(() => {
0017     mockStorage = {};
0018   });
0019 
0020   describe('Basic functionality', () => {
0021     it('should create with default value', () => {
0022       const config = new PersistentProperty('test', 'defaultValue', undefined, undefined, mockStorageInterface);
0023       expect(config.value).toBe('defaultValue');
0024     });
0025 
0026     it('should save and load string values', () => {
0027       const config = new PersistentProperty('test', 'default', undefined, undefined, mockStorageInterface);
0028       config.value = 'newValue';
0029 
0030       // Create a new instance to verify persistence
0031       const config2 = new PersistentProperty('test', 'default', undefined, undefined, mockStorageInterface);
0032       expect(config2.value).toBe('newValue');
0033     });
0034 
0035     it('should save and load object values', () => {
0036       const defaultObj = { name: 'default', count: 0 };
0037       const config = new PersistentProperty('test', defaultObj, undefined, undefined, mockStorageInterface);
0038 
0039       const newObj = { name: 'updated', count: 42 };
0040       config.value = newObj;
0041 
0042       // Create a new instance to verify persistence
0043       const config2 = new PersistentProperty('test', defaultObj, undefined, undefined, mockStorageInterface);
0044       expect(config2.value).toEqual(newObj);
0045     });
0046 
0047     it('should validate values when validator is provided', () => {
0048       const validator = (value: number) => value > 0 && value < 100;
0049       const config = new PersistentProperty<number>('test', 50, undefined, validator, mockStorageInterface);
0050 
0051       // Valid value should be accepted
0052       config.value = 75;
0053       expect(config.value).toBe(75);
0054 
0055       // Invalid value should be rejected
0056       const consoleSpy = spyOn(console, 'error');
0057       config.value = 150;
0058       expect(config.value).toBe(75); // Should still be the previous valid value
0059       expect(consoleSpy).toHaveBeenCalledWith('Validation failed for:', 150);
0060     });
0061 
0062     it('should call saveCallback when value is set', () => {
0063       const saveCallback = jasmine.createSpy('saveCallback');
0064       const config = new PersistentProperty('test', 'default', saveCallback, undefined, mockStorageInterface);
0065 
0066       config.value = 'newValue';
0067       expect(saveCallback).toHaveBeenCalled();
0068     });
0069 
0070     it('should emit changes through Observable', (done) => {
0071       const config = new PersistentProperty('test', 'initial', undefined, undefined, mockStorageInterface);
0072 
0073       let emissionCount = 0;
0074       const expectedValues = ['initial', 'second', 'third'];
0075 
0076       config.changes$.subscribe(value => {
0077         expect(value).toBe(expectedValues[emissionCount]);
0078         emissionCount++;
0079 
0080         if (emissionCount === 3) {
0081           done();
0082         }
0083       });
0084 
0085       config.value = 'second';
0086       config.value = 'third';
0087     });
0088   });
0089 
0090   describe('Time-based configuration', () => {
0091     it('should store timestamp when saving value without explicit time', () => {
0092       const config = new PersistentProperty('test', 'default', undefined, undefined, mockStorageInterface);
0093       const beforeTime = Date.now();
0094 
0095       config.value = 'newValue';
0096 
0097       const afterTime = Date.now();
0098       const storedTime = parseInt(mockStorage['test.time'], 10);
0099 
0100       expect(storedTime).toBeGreaterThanOrEqual(beforeTime);
0101       expect(storedTime).toBeLessThanOrEqual(afterTime);
0102     });
0103 
0104     it('should store timestamp with setValue when time is provided', () => {
0105       const config = new PersistentProperty('test', 'default', undefined, undefined, mockStorageInterface);
0106       const specificTime = 1234567890;
0107 
0108       config.setValue('newValue', specificTime);
0109 
0110       expect(mockStorage['test.time']).toBe('1234567890');
0111       expect(config.value).toBe('newValue');
0112     });
0113 
0114     it('should only update if provided timestamp is newer than stored', () => {
0115       const config = new PersistentProperty('test', 'default', undefined, undefined, mockStorageInterface);
0116 
0117       // Set initial value with timestamp
0118       config.setValue('value1', 1000);
0119       expect(config.value).toBe('value1');
0120 
0121       // Try to set with older timestamp - should be rejected
0122       const consoleSpy = spyOn(console, 'log');
0123       config.setValue('value2', 500);
0124       expect(config.value).toBe('value1'); // Should remain unchanged
0125       expect(consoleSpy).toHaveBeenCalled();
0126 
0127       // Set with newer timestamp - should be accepted
0128       config.setValue('value3', 1500);
0129       expect(config.value).toBe('value3');
0130     });
0131 
0132     it('should accept update when no timestamp exists in storage', () => {
0133       const config = new PersistentProperty('test', 'default', undefined, undefined, mockStorageInterface);
0134 
0135       // Manually set a value without timestamp (simulating old data)
0136       mockStorage['test'] = '"oldValue"';
0137 
0138       // Create new instance and update with timestamp
0139       const config2 = new PersistentProperty('test', 'default', undefined, undefined, mockStorageInterface);
0140       config2.setValue('newValue', 1000);
0141 
0142       expect(config2.value).toBe('newValue');
0143       expect(mockStorage['test.time']).toBe('1000');
0144     });
0145 
0146     it('should handle concurrent updates correctly', () => {
0147       // Simulate two different sources trying to update the same config
0148       const config1 = new PersistentProperty('shared', 'initial', undefined, undefined, mockStorageInterface);
0149       const config2 = new PersistentProperty('shared', 'initial', undefined, undefined, mockStorageInterface);
0150 
0151       // Source 1 updates at time 1000
0152       config1.setValue('update1', 1000);
0153       expect(config1.value).toBe('update1');
0154 
0155       // Source 2 tries to update with older timestamp - should fail
0156       const consoleSpy = spyOn(console, 'log');
0157       config2.setValue('update2', 900);
0158 
0159       // Reload config2 to get the latest value
0160       const config2Reloaded = new PersistentProperty('shared', 'initial', undefined, undefined, mockStorageInterface);
0161       expect(config2Reloaded.value).toBe('update1'); // Should still be update1
0162 
0163       // Source 2 updates with newer timestamp - should succeed
0164       config2.setValue('update3', 1100);
0165       const config1Reloaded = new PersistentProperty('shared', 'initial', undefined, undefined, mockStorageInterface);
0166       expect(config1Reloaded.value).toBe('update3');
0167     });
0168 
0169     it('should use current time when no timestamp is provided to setValue', () => {
0170       const config = new PersistentProperty('test', 'default', undefined, undefined, mockStorageInterface);
0171       const beforeTime = Date.now();
0172 
0173       config.setValue('newValue'); // No timestamp provided
0174 
0175       const afterTime = Date.now();
0176       const storedTime = parseInt(mockStorage['test.time'], 10);
0177 
0178       expect(storedTime).toBeGreaterThanOrEqual(beforeTime);
0179       expect(storedTime).toBeLessThanOrEqual(afterTime);
0180     });
0181 
0182     it('should not call saveCallback when update is rejected due to older timestamp', () => {
0183       const saveCallback = jasmine.createSpy('saveCallback');
0184       const config = new PersistentProperty('test', 'default', saveCallback, undefined, mockStorageInterface);
0185 
0186       // Set initial value with timestamp
0187       config.setValue('value1', 1000);
0188       expect(saveCallback).toHaveBeenCalledTimes(1);
0189 
0190       // Try to set with older timestamp
0191       saveCallback.calls.reset();
0192       config.setValue('value2', 500);
0193       expect(saveCallback).not.toHaveBeenCalled();
0194     });
0195 
0196     it('should not emit changes when update is rejected due to older timestamp', (done) => {
0197       const config = new PersistentProperty('test', 'initial', undefined, undefined, mockStorageInterface);
0198 
0199       // Set initial value with timestamp
0200       config.setValue('value1', 1000);
0201 
0202       let emissionCount = 0;
0203       config.changes$.subscribe(value => {
0204         emissionCount++;
0205         if (emissionCount === 1) {
0206           expect(value).toBe('value1'); // First emission from subscription
0207         } else if (emissionCount === 2) {
0208           expect(value).toBe('value3'); // Should skip value2
0209           done();
0210         } else {
0211           fail('Unexpected emission');
0212         }
0213       });
0214 
0215       // This should be rejected
0216       setTimeout(() => {
0217         config.setValue('value2', 500);
0218 
0219         // This should be accepted
0220         setTimeout(() => {
0221           config.setValue('value3', 1500);
0222         }, 10);
0223       }, 10);
0224     });
0225 
0226     it('should handle array values with timestamps correctly', () => {
0227       const config = new PersistentProperty<number[]>('test', [], undefined, undefined, mockStorageInterface);
0228 
0229       config.setValue([1, 2, 3], 1000);
0230       expect(config.value).toEqual([1, 2, 3]);
0231       expect(mockStorage['test.time']).toBe('1000');
0232 
0233       // Try to update with older timestamp
0234       config.setValue([4, 5, 6], 900);
0235       expect(config.value).toEqual([1, 2, 3]); // Should remain unchanged
0236 
0237       // Update with newer timestamp
0238       config.setValue([7, 8, 9], 1100);
0239       expect(config.value).toEqual([7, 8, 9]);
0240       expect(mockStorage['test.time']).toBe('1100');
0241     });
0242   });
0243 
0244   describe('Error handling', () => {
0245     it('should handle corrupted stored values gracefully', () => {
0246       // Store invalid JSON
0247       mockStorage['test'] = 'invalid json {]';
0248 
0249       const consoleSpy = spyOn(console, 'error');
0250       const config = new PersistentProperty('test', { default: true }, undefined, undefined, mockStorageInterface);
0251 
0252       expect(config.value).toEqual({ default: true }); // Should fall back to default
0253       expect(consoleSpy).toHaveBeenCalled();
0254     });
0255 
0256     it('should handle corrupted timestamp gracefully', () => {
0257       mockStorage['test'] = '"validValue"';
0258       mockStorage['test.time'] = 'not a number';
0259 
0260       const consoleSpy = spyOn(console, 'error');
0261       const config = new PersistentProperty('test', 'default', undefined, undefined, mockStorageInterface);
0262 
0263       // Should still allow updates when timestamp is corrupted
0264       config.setValue('newValue', 1000);
0265       expect(config.value).toBe('newValue');
0266     });
0267 
0268     it('should handle missing storage gracefully', () => {
0269       const brokenStorage = {
0270         getItem: () => { throw new Error('Storage error'); },
0271         setItem: () => { throw new Error('Storage error'); }
0272       };
0273 
0274       const consoleSpy = spyOn(console, 'error');
0275       const config = new PersistentProperty('test', 'default', undefined, undefined, brokenStorage);
0276 
0277       expect(config.value).toBe('default'); // Should use default value
0278       expect(consoleSpy).toHaveBeenCalled();
0279     });
0280   });
0281 
0282   describe('setDefault method', () => {
0283     it('should reset value to default', () => {
0284       const config = new PersistentProperty('test', 'defaultValue', undefined, undefined, mockStorageInterface);
0285 
0286       config.value = 'newValue';
0287       expect(config.value).toBe('newValue');
0288 
0289       config.setDefault();
0290       expect(config.value).toBe('defaultValue');
0291     });
0292   });
0293 });