import { BackupShare, BackupShareStatus, } from '../../../src/domain/entities/backup-share.entity'; import { DomainError } from '../../../src/domain/errors/domain.error'; describe('BackupShare Entity', () => { const validParams = { userId: BigInt(12345), accountSequence: BigInt(1001), publicKey: '02' + 'a'.repeat(64), encryptedShareData: 'encrypted-data-base64', encryptionKeyId: 'key-v1', }; describe('create', () => { it('should create a backup share with valid parameters', () => { const share = BackupShare.create(validParams); expect(share.userId).toBe(validParams.userId); expect(share.accountSequence).toBe(validParams.accountSequence); expect(share.publicKey).toBe(validParams.publicKey); expect(share.encryptedShareData).toBe(validParams.encryptedShareData); expect(share.encryptionKeyId).toBe(validParams.encryptionKeyId); expect(share.partyIndex).toBe(2); expect(share.threshold).toBe(2); expect(share.totalParties).toBe(3); expect(share.status).toBe(BackupShareStatus.ACTIVE); expect(share.accessCount).toBe(0); expect(share.shareId).toBeNull(); }); it('should allow custom threshold and totalParties', () => { const share = BackupShare.create({ ...validParams, threshold: 3, totalParties: 5, }); expect(share.threshold).toBe(3); expect(share.totalParties).toBe(5); }); }); describe('recordAccess', () => { it('should increment access count for active share', () => { const share = BackupShare.create(validParams); share.recordAccess(); expect(share.accessCount).toBe(1); expect(share.lastAccessedAt).not.toBeNull(); }); it('should throw error when accessing revoked share', () => { const share = BackupShare.create(validParams); share.revoke('TEST_REASON'); expect(() => share.recordAccess()).toThrow(DomainError); expect(() => share.recordAccess()).toThrow( 'Cannot access revoked or rotated share', ); }); }); describe('revoke', () => { it('should revoke an active share', () => { const share = BackupShare.create(validParams); share.revoke('SECURITY_BREACH'); expect(share.status).toBe(BackupShareStatus.REVOKED); expect(share.revokedAt).not.toBeNull(); }); it('should throw error when revoking already revoked share', () => { const share = BackupShare.create(validParams); share.revoke('FIRST_REVOKE'); expect(() => share.revoke('SECOND_REVOKE')).toThrow(DomainError); expect(() => share.revoke('SECOND_REVOKE')).toThrow( 'Share already revoked', ); }); }); describe('rotate', () => { it('should rotate encryption for active share', () => { const share = BackupShare.create(validParams); const newEncryptedData = 'new-encrypted-data'; const newKeyId = 'key-v2'; share.rotate(newEncryptedData, newKeyId); expect(share.encryptedShareData).toBe(newEncryptedData); expect(share.encryptionKeyId).toBe(newKeyId); expect(share.status).toBe(BackupShareStatus.ACTIVE); }); it('should throw error when rotating revoked share', () => { const share = BackupShare.create(validParams); share.revoke('TEST'); expect(() => share.rotate('new-data', 'key-v2')).toThrow(DomainError); expect(() => share.rotate('new-data', 'key-v2')).toThrow( 'Cannot rotate revoked share', ); }); }); describe('isActive', () => { it('should return true for active share', () => { const share = BackupShare.create(validParams); expect(share.isActive()).toBe(true); }); it('should return false for revoked share', () => { const share = BackupShare.create(validParams); share.revoke('TEST'); expect(share.isActive()).toBe(false); }); }); describe('setShareId', () => { it('should set share ID when not already set', () => { const share = BackupShare.create(validParams); share.setShareId(BigInt(1)); expect(share.shareId).toBe(BigInt(1)); }); it('should throw error when share ID already set', () => { const share = BackupShare.create(validParams); share.setShareId(BigInt(1)); expect(() => share.setShareId(BigInt(2))).toThrow(DomainError); expect(() => share.setShareId(BigInt(2))).toThrow('Share ID already set'); }); }); describe('toProps', () => { it('should return all properties', () => { const share = BackupShare.create(validParams); const props = share.toProps(); expect(props.userId).toBe(validParams.userId); expect(props.accountSequence).toBe(validParams.accountSequence); expect(props.publicKey).toBe(validParams.publicKey); expect(props.status).toBe(BackupShareStatus.ACTIVE); expect(props.partyIndex).toBe(2); }); }); describe('reconstitute', () => { it('should reconstitute from props', () => { const original = BackupShare.create(validParams); original.setShareId(BigInt(123)); const props = original.toProps(); const reconstituted = BackupShare.reconstitute(props); expect(reconstituted.shareId).toBe(props.shareId); expect(reconstituted.userId).toBe(props.userId); expect(reconstituted.status).toBe(props.status); }); }); });