import { describe, it, expect } from '@jest/globals'; // Mock crypto.getRandomValues for testing Object.defineProperty(global, 'crypto', { value: { getRandomValues: (arr: Uint8Array) => { for (let i = 0; i < arr.length; i++) { arr[i] = Math.floor(Math.random() * 256); } return arr; } } }); // Mock window for testing if (typeof window === 'undefined') { Object.defineProperty(global, 'window', { value: { location: { origin: 'http://localhost:3000' }, sessionStorage: { getItem: () => null, setItem: () => {}, removeItem: () => {} } } }); } describe('DeepLinkManager Scopes Validation', () => { // Test scope validation logic directly without importing the full DeepLinkManager function validateScopeFormat(scope: string): boolean { if (!scope || typeof scope !== 'string') { return false; } const parts = scope.split('::'); if (parts.length !== 3) { return false; } const [address, module, func] = parts; // Each part must be non-empty if (!address || !module || !func) { return false; } // Basic address format validation (hex or wildcard) if (address !== '*' && !isValidAddressFormat(address)) { return false; } return true; } function isValidAddressFormat(address: string): boolean { // Accept hex addresses (0x...) and bech32 addresses (rooch1...) if (address.startsWith('0x')) { return /^0x[a-fA-F0-9]+$/.test(address); } if (address.startsWith('rooch1')) { return /^rooch1[a-z0-9]+$/.test(address); } return false; } describe('scope format validation', () => { it('should accept valid scope formats', () => { const validScopes = [ '0x123::defi::swap', '*::nft::mint', '0xabc::gamefi::*', 'rooch1abc123::module::function' ]; validScopes.forEach(scope => { expect(validateScopeFormat(scope)).toBe(true); }); }); it('should reject invalid scope formats', () => { const invalidScopes = [ 'invalid', // Missing :: separators '0x123::defi', // Only two parts '::defi::swap', // Empty address '0x123::', // Empty module and function '0x123::::swap', // Extra separators '' // Empty string ]; invalidScopes.forEach(scope => { expect(validateScopeFormat(scope)).toBe(false); }); }); it('should accept wildcard patterns', () => { const wildcardScopes = [ '*::*::*', '0x123::*::*', '*::defi::*', '*::*::mint' ]; wildcardScopes.forEach(scope => { expect(validateScopeFormat(scope)).toBe(true); }); }); it('should validate address formats correctly', () => { expect(isValidAddressFormat('0x123abc')).toBe(true); expect(isValidAddressFormat('0xABCDEF1234567890')).toBe(true); expect(isValidAddressFormat('rooch1abc123')).toBe(true); expect(isValidAddressFormat('*')).toBe(false); // * is handled separately expect(isValidAddressFormat('invalid-address')).toBe(false); expect(isValidAddressFormat('0xGGG')).toBe(false); // Invalid hex expect(isValidAddressFormat('rooch2invalid')).toBe(false); // Invalid bech32 }); }); describe('validateScopes function', () => { function validateScopes(scopes: string[]): { valid: boolean; invalidScopes: string[] } { const invalidScopes = scopes.filter(scope => !validateScopeFormat(scope)); return { valid: invalidScopes.length === 0, invalidScopes, }; } it('should return valid for all valid scopes', () => { const scopes = ['0x123::defi::swap', '*::nft::mint']; const result = validateScopes(scopes); expect(result.valid).toBe(true); expect(result.invalidScopes).toEqual([]); }); it('should return invalid scopes', () => { const scopes = ['0x123::defi::swap', 'invalid-scope', '*::nft::mint']; const result = validateScopes(scopes); expect(result.valid).toBe(false); expect(result.invalidScopes).toContain('invalid-scope'); }); it('should handle empty array', () => { const result = validateScopes([]); expect(result.valid).toBe(true); expect(result.invalidScopes).toEqual([]); }); }); });