/** * Value Objects Unit Tests */ import { SessionId, PartyId, ShareId, Threshold, ShareData, PublicKey, Signature, MessageHash, } from '../../../src/domain/value-objects'; describe('Value Objects', () => { describe('SessionId', () => { it('should create valid SessionId', () => { const sessionId = SessionId.create('550e8400-e29b-41d4-a716-446655440000'); expect(sessionId.value).toBe('550e8400-e29b-41d4-a716-446655440000'); }); it('should generate unique SessionId', () => { const sessionId1 = SessionId.generate(); const sessionId2 = SessionId.generate(); expect(sessionId1.value).not.toBe(sessionId2.value); }); it('should throw error for invalid format', () => { expect(() => SessionId.create('invalid')).toThrow(); expect(() => SessionId.create('')).toThrow(); }); it('should compare equality correctly', () => { const sessionId1 = SessionId.create('550e8400-e29b-41d4-a716-446655440000'); const sessionId2 = SessionId.create('550e8400-e29b-41d4-a716-446655440000'); const sessionId3 = SessionId.create('660e8400-e29b-41d4-a716-446655440001'); expect(sessionId1.equals(sessionId2)).toBe(true); expect(sessionId1.equals(sessionId3)).toBe(false); }); }); describe('PartyId', () => { it('should create valid PartyId', () => { const partyId = PartyId.create('user123-server'); expect(partyId.value).toBe('user123-server'); }); it('should create from components', () => { const partyId = PartyId.fromComponents('user123', 'server'); expect(partyId.value).toBe('user123-server'); }); it('should extract identifier and type', () => { const partyId = PartyId.create('user123-server'); expect(partyId.getIdentifier()).toBe('user123'); expect(partyId.getType()).toBe('server'); }); it('should throw error for invalid format', () => { expect(() => PartyId.create('')).toThrow(); expect(() => PartyId.create('nohyphen')).toThrow(); }); }); describe('ShareId', () => { it('should create valid ShareId', () => { const shareId = ShareId.create('share_1699887766123_abc123xyz'); expect(shareId.value).toBe('share_1699887766123_abc123xyz'); }); it('should generate unique ShareId', () => { const shareId1 = ShareId.generate(); const shareId2 = ShareId.generate(); expect(shareId1.value).not.toBe(shareId2.value); expect(shareId1.value).toMatch(/^share_\d+_[a-z0-9]+$/); }); it('should throw error for invalid format', () => { expect(() => ShareId.create('invalid')).toThrow(); }); }); describe('Threshold', () => { it('should create valid threshold', () => { const threshold = Threshold.create(3, 2); expect(threshold.n).toBe(3); expect(threshold.t).toBe(2); expect(threshold.toString()).toBe('2-of-3'); }); it('should provide common configurations', () => { const twoOfThree = Threshold.twoOfThree(); expect(twoOfThree.toString()).toBe('2-of-3'); const threeOfFive = Threshold.threeOfFive(); expect(threeOfFive.toString()).toBe('3-of-5'); }); it('should validate participants', () => { const threshold = Threshold.create(3, 2); expect(threshold.validateParticipants(2)).toBe(true); expect(threshold.validateParticipants(3)).toBe(true); expect(threshold.validateParticipants(1)).toBe(false); expect(threshold.validateParticipants(4)).toBe(false); }); it('should throw error for invalid values', () => { expect(() => Threshold.create(0, 0)).toThrow(); expect(() => Threshold.create(2, 3)).toThrow(); // t > n expect(() => Threshold.create(3, 1)).toThrow(); // t < 2 }); }); describe('ShareData', () => { it('should create valid ShareData', () => { const shareData = ShareData.create( Buffer.from('encrypted-data'), Buffer.from('123456789012'), // 12 bytes Buffer.from('1234567890123456'), // 16 bytes ); expect(shareData.encryptedData).toEqual(Buffer.from('encrypted-data')); }); it('should serialize to JSON and back', () => { const original = ShareData.create( Buffer.from('encrypted-data'), Buffer.from('123456789012'), Buffer.from('1234567890123456'), ); const json = original.toJSON(); const restored = ShareData.fromJSON(json); expect(restored.encryptedData).toEqual(original.encryptedData); expect(restored.iv).toEqual(original.iv); expect(restored.authTag).toEqual(original.authTag); }); it('should throw error for invalid IV length', () => { expect(() => ShareData.create( Buffer.from('data'), Buffer.from('short'), // Less than 12 bytes Buffer.from('1234567890123456'), )).toThrow(); }); it('should throw error for invalid authTag length', () => { expect(() => ShareData.create( Buffer.from('data'), Buffer.from('123456789012'), Buffer.from('short'), // Less than 16 bytes )).toThrow(); }); }); describe('PublicKey', () => { it('should create from hex', () => { const hex = '03' + '0'.repeat(64); const publicKey = PublicKey.fromHex(hex); expect(publicKey.toHex()).toBe(hex); expect(publicKey.isCompressed()).toBe(true); }); it('should create from base64', () => { const buffer = Buffer.alloc(33); buffer[0] = 0x03; const publicKey = PublicKey.fromBase64(buffer.toString('base64')); expect(publicKey.bytes).toHaveLength(33); }); it('should detect compressed vs uncompressed', () => { const compressed = PublicKey.create(Buffer.alloc(33, 0x03)); const uncompressed = PublicKey.create(Buffer.alloc(65, 0x04)); expect(compressed.isCompressed()).toBe(true); expect(uncompressed.isCompressed()).toBe(false); }); it('should throw error for invalid length', () => { expect(() => PublicKey.create(Buffer.alloc(32))).toThrow(); expect(() => PublicKey.create(Buffer.alloc(64))).toThrow(); }); }); describe('Signature', () => { it('should create from components', () => { const r = Buffer.alloc(32, 0x01); const s = Buffer.alloc(32, 0x02); const signature = Signature.create(r, s, 0); expect(signature.r).toEqual(r); expect(signature.s).toEqual(s); expect(signature.v).toBe(0); }); it('should parse from hex', () => { const hex = '0'.repeat(128); // 64 bytes = r + s const signature = Signature.fromHex(hex); expect(signature.r).toHaveLength(32); expect(signature.s).toHaveLength(32); }); it('should convert to hex', () => { const r = Buffer.alloc(32, 0x01); const s = Buffer.alloc(32, 0x02); const signature = Signature.create(r, s); const hex = signature.toHex(); expect(hex).toHaveLength(128); }); it('should throw error for invalid component length', () => { expect(() => Signature.create(Buffer.alloc(31), Buffer.alloc(32))).toThrow(); expect(() => Signature.create(Buffer.alloc(32), Buffer.alloc(31))).toThrow(); }); }); describe('MessageHash', () => { it('should create from hex', () => { const hex = '0x' + '0'.repeat(64); const hash = MessageHash.fromHex(hex); expect(hash.bytes).toHaveLength(32); }); it('should create from hex without prefix', () => { const hex = '0'.repeat(64); const hash = MessageHash.fromHex(hex); expect(hash.bytes).toHaveLength(32); }); it('should convert to hex with prefix', () => { const hex = '0'.repeat(64); const hash = MessageHash.fromHex(hex); expect(hash.toHex()).toBe('0x' + hex); }); it('should throw error for invalid length', () => { expect(() => MessageHash.fromHex('0x1234')).toThrow(); }); }); });