Skip to content

Commit

Permalink
support input types more flexibly and test
Browse files Browse the repository at this point in the history
  • Loading branch information
0age committed Dec 8, 2024
1 parent 1eedba6 commit 56c9245
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 47 deletions.
4 changes: 2 additions & 2 deletions src/__tests__/utils/test-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { setupRoutes } from '../../routes';
import { dbManager } from '../setup';
import { signMessage } from 'viem/accounts';
import { getAddress } from 'viem/utils';
import { CompactMessage } from '../../validation/types';

// Helper to generate test data
const defaultBaseUrl = 'https://smallocator.example';
Expand Down Expand Up @@ -237,7 +238,7 @@ export function getFreshCompact(): typeof validCompact {
export function compactToAPI(
compact: typeof validCompact,
options: { nullNonce?: boolean } = {}
): Record<string, string | number | null> {
): CompactMessage {
const nonce = options.nullNonce ? null : compact.nonce;

// Convert ID to hex preserving all bits
Expand All @@ -257,7 +258,6 @@ export function compactToAPI(
witnessHash: compact.witnessHash
? ensure0x(padToBytes(compact.witnessHash, 32))
: null,
chainId: compact.chainId.toString(),
};
}

Expand Down
38 changes: 31 additions & 7 deletions src/__tests__/validation/compact-graphql.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { validateCompact } from '../../validation/compact';
import { getFreshCompact } from '../utils/test-server';
import { getFreshCompact, compactToAPI } from '../utils/test-server';
import { PGlite } from '@electric-sql/pglite';
import {
graphqlClient,
Expand Down Expand Up @@ -59,7 +59,11 @@ describe('Compact GraphQL Validation', () => {
},
});

const result = await validateCompact(getFreshCompact(), '1', db);
const result = await validateCompact(
compactToAPI(getFreshCompact()),
'1',
db
);
expect(result.isValid).toBe(true);
});

Expand Down Expand Up @@ -90,7 +94,11 @@ describe('Compact GraphQL Validation', () => {
},
});

const result = await validateCompact(getFreshCompact(), '1', db);
const result = await validateCompact(
compactToAPI(getFreshCompact()),
'1',
db
);
expect(result.isValid).toBe(false);
expect(result.error).toContain('Insufficient');
});
Expand Down Expand Up @@ -122,7 +130,11 @@ describe('Compact GraphQL Validation', () => {
},
});

const result = await validateCompact(getFreshCompact(), '1', db);
const result = await validateCompact(
compactToAPI(getFreshCompact()),
'1',
db
);
expect(result.isValid).toBe(false);
expect(result.error).toContain('withdrawals enabled');
});
Expand Down Expand Up @@ -154,7 +166,11 @@ describe('Compact GraphQL Validation', () => {
},
});

const result = await validateCompact(getFreshCompact(), '1', db);
const result = await validateCompact(
compactToAPI(getFreshCompact()),
'1',
db
);
expect(result.isValid).toBe(false);
expect(result.error).toContain('Invalid allocator ID');
});
Expand Down Expand Up @@ -186,7 +202,11 @@ describe('Compact GraphQL Validation', () => {
},
});

const result = await validateCompact(getFreshCompact(), '1', db);
const result = await validateCompact(
compactToAPI(getFreshCompact()),
'1',
db
);
expect(result.isValid).toBe(false);
expect(result.error).toContain('Invalid allocator ID');
});
Expand All @@ -196,7 +216,11 @@ describe('Compact GraphQL Validation', () => {
throw new Error('GraphQL request failed');
};

const result = await validateCompact(getFreshCompact(), '1', db);
const result = await validateCompact(
compactToAPI(getFreshCompact()),
'1',
db
);
expect(result.isValid).toBe(false);
expect(result.error).toContain('GraphQL request failed');
});
Expand Down
62 changes: 53 additions & 9 deletions src/__tests__/validation/compact-validation.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { validateCompact } from '../../validation/compact';
import { getFreshCompact } from '../utils/test-server';
import { getFreshCompact, compactToAPI } from '../utils/test-server';
import { PGlite } from '@electric-sql/pglite';
import { graphqlClient } from '../../graphql';
import {
Expand Down Expand Up @@ -29,14 +29,54 @@ describe('Compact Basic Validation', () => {
graphqlClient.request = originalRequest;
});

it('should validate correct compact', async (): Promise<void> => {
const result = await validateCompact(getFreshCompact(), '1', db);
it('should validate correct compact with decimal inputs', async (): Promise<void> => {
const result = await validateCompact(
compactToAPI(getFreshCompact()),
'1',
db
);
expect(result.isValid).toBe(true);
});

it('should validate correct compact with hex inputs', async (): Promise<void> => {
const freshCompact = getFreshCompact();
const hexCompact = {
...compactToAPI(freshCompact),
id: '0x' + freshCompact.id.toString(16),
expires: '0x' + freshCompact.expires.toString(16),
amount: '0x' + BigInt(freshCompact.amount).toString(16),
nonce: freshCompact.nonce ? '0x' + freshCompact.nonce.toString(16) : null,
};
const result = await validateCompact(hexCompact, '1', db);
expect(result.isValid).toBe(true);
});

it('should validate correct compact with mixed decimal and hex inputs', async (): Promise<void> => {
const freshCompact = getFreshCompact();
const mixedCompact = {
...compactToAPI(freshCompact),
id: '0x' + freshCompact.id.toString(16),
expires: freshCompact.expires.toString(),
amount: '0x' + BigInt(freshCompact.amount).toString(16),
nonce: freshCompact.nonce ? freshCompact.nonce.toString() : null,
};
const result = await validateCompact(mixedCompact, '1', db);
expect(result.isValid).toBe(true);
});

it('should reject invalid hex format', async (): Promise<void> => {
const invalidCompact = {
...compactToAPI(getFreshCompact()),
id: '0xInvalidHex',
};
const result = await validateCompact(invalidCompact, '1', db);
expect(result.isValid).toBe(false);
expect(result.error).toContain('Failed to convert id');
});

it('should reject invalid arbiter address', async (): Promise<void> => {
const invalidCompact = {
...getFreshCompact(),
...compactToAPI(getFreshCompact()),
arbiter: 'invalid-address',
};
const result = await validateCompact(invalidCompact, '1', db);
Expand All @@ -46,7 +86,7 @@ describe('Compact Basic Validation', () => {

it('should reject invalid sponsor address', async (): Promise<void> => {
const invalidCompact = {
...getFreshCompact(),
...compactToAPI(getFreshCompact()),
sponsor: 'invalid-address',
};
const result = await validateCompact(invalidCompact, '1', db);
Expand All @@ -56,8 +96,8 @@ describe('Compact Basic Validation', () => {

it('should reject invalid expires timestamp', async (): Promise<void> => {
const invalidCompact = {
...getFreshCompact(),
expires: BigInt(-1),
...compactToAPI(getFreshCompact()),
expires: '-1',
};
const result = await validateCompact(invalidCompact, '1', db);
expect(result.isValid).toBe(false);
Expand All @@ -66,7 +106,7 @@ describe('Compact Basic Validation', () => {

it('should reject invalid amount', async (): Promise<void> => {
const invalidCompact = {
...getFreshCompact(),
...compactToAPI(getFreshCompact()),
amount: '-1',
};
const result = await validateCompact(invalidCompact, '1', db);
Expand All @@ -75,7 +115,11 @@ describe('Compact Basic Validation', () => {
});

it('should reject invalid chain id', async (): Promise<void> => {
const result = await validateCompact(getFreshCompact(), 'invalid', db);
const result = await validateCompact(
compactToAPI(getFreshCompact()),
'invalid',
db
);
expect(result.isValid).toBe(false);
expect(result.error).toContain('Invalid chain ID');
});
Expand Down
85 changes: 61 additions & 24 deletions src/__tests__/validation/structure-validation.test.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { validateStructure } from '../../validation/structure';
import { getFreshCompact } from '../utils/test-server';
import { getFreshCompact, compactToAPI } from '../utils/test-server';

describe('Structure Validation', () => {
it('should validate correct compact structure', async (): Promise<void> => {
const compact = getFreshCompact();
const compact = compactToAPI(getFreshCompact());
const result = await validateStructure(compact);
expect(result.isValid).toBe(true);
});

it('should reject invalid arbiter address', async (): Promise<void> => {
const invalidCompact = {
...getFreshCompact(),
...compactToAPI(getFreshCompact()),
arbiter: 'invalid-address',
};
const result = await validateStructure(invalidCompact);
Expand All @@ -20,7 +20,7 @@ describe('Structure Validation', () => {

it('should reject invalid sponsor address', async (): Promise<void> => {
const invalidCompact = {
...getFreshCompact(),
...compactToAPI(getFreshCompact()),
sponsor: 'invalid-address',
};
const result = await validateStructure(invalidCompact);
Expand All @@ -30,67 +30,67 @@ describe('Structure Validation', () => {

it('should reject negative expires timestamp', async (): Promise<void> => {
const invalidCompact = {
...getFreshCompact(),
expires: BigInt(-1),
...compactToAPI(getFreshCompact()),
expires: '-1',
};
const result = await validateStructure(invalidCompact);
expect(result.isValid).toBe(false);
expect(result.error).toBe('Invalid expires timestamp');
expect(result.error).toContain('must be a positive number');
});

it('should reject zero expires timestamp', async (): Promise<void> => {
const invalidCompact = {
...getFreshCompact(),
expires: BigInt(0),
...compactToAPI(getFreshCompact()),
expires: '0',
};
const result = await validateStructure(invalidCompact);
expect(result.isValid).toBe(false);
expect(result.error).toBe('Invalid expires timestamp');
expect(result.error).toContain('must be a positive number');
});

it('should reject negative id', async (): Promise<void> => {
const invalidCompact = {
...getFreshCompact(),
id: BigInt(-1),
...compactToAPI(getFreshCompact()),
id: '-1',
};
const result = await validateStructure(invalidCompact);
expect(result.isValid).toBe(false);
expect(result.error).toBe('Invalid id');
expect(result.error).toContain('must be a positive number');
});

it('should reject zero id', async (): Promise<void> => {
const invalidCompact = {
...getFreshCompact(),
id: BigInt(0),
...compactToAPI(getFreshCompact()),
id: '0',
};
const result = await validateStructure(invalidCompact);
expect(result.isValid).toBe(false);
expect(result.error).toBe('Invalid id');
expect(result.error).toContain('must be a positive number');
});

it('should reject invalid amount format', async (): Promise<void> => {
const invalidCompact = {
...getFreshCompact(),
...compactToAPI(getFreshCompact()),
amount: '-1',
};
const result = await validateStructure(invalidCompact);
expect(result.isValid).toBe(false);
expect(result.error).toBe('Invalid amount format');
expect(result.error).toContain('must be a positive number');
});

it('should reject non-numeric amount', async (): Promise<void> => {
const invalidCompact = {
...getFreshCompact(),
...compactToAPI(getFreshCompact()),
amount: 'abc',
};
const result = await validateStructure(invalidCompact);
expect(result.isValid).toBe(false);
expect(result.error).toBe('Invalid amount format');
expect(result.error).toContain('Failed to convert amount');
});

it('should reject witness type without hash', async (): Promise<void> => {
const invalidCompact = {
...getFreshCompact(),
...compactToAPI(getFreshCompact()),
witnessTypeString: 'type',
witnessHash: null,
};
Expand All @@ -103,7 +103,7 @@ describe('Structure Validation', () => {

it('should reject witness hash without type', async (): Promise<void> => {
const invalidCompact = {
...getFreshCompact(),
...compactToAPI(getFreshCompact()),
witnessTypeString: null,
witnessHash: '0x1234',
};
Expand All @@ -116,7 +116,7 @@ describe('Structure Validation', () => {

it('should accept both witness fields as null', async (): Promise<void> => {
const validCompact = {
...getFreshCompact(),
...compactToAPI(getFreshCompact()),
witnessTypeString: null,
witnessHash: null,
};
Expand All @@ -126,11 +126,48 @@ describe('Structure Validation', () => {

it('should accept both witness fields as present', async (): Promise<void> => {
const validCompact = {
...getFreshCompact(),
...compactToAPI(getFreshCompact()),
witnessTypeString: 'type',
witnessHash: '0x1234',
};
const result = await validateStructure(validCompact);
expect(result.isValid).toBe(true);
});

// New tests for hex input support
it('should accept hex format id', async (): Promise<void> => {
const validCompact = {
...compactToAPI(getFreshCompact()),
id: '0x123',
};
const result = await validateStructure(validCompact);
expect(result.isValid).toBe(true);
});

it('should accept hex format amount', async (): Promise<void> => {
const validCompact = {
...compactToAPI(getFreshCompact()),
amount: '0x123',
};
const result = await validateStructure(validCompact);
expect(result.isValid).toBe(true);
});

it('should accept hex format expires', async (): Promise<void> => {
const validCompact = {
...compactToAPI(getFreshCompact()),
expires: '0x123',
};
const result = await validateStructure(validCompact);
expect(result.isValid).toBe(true);
});

it('should accept hex format nonce', async (): Promise<void> => {
const validCompact = {
...compactToAPI(getFreshCompact()),
nonce: '0x123',
};
const result = await validateStructure(validCompact);
expect(result.isValid).toBe(true);
});
});
Loading

0 comments on commit 56c9245

Please sign in to comment.