Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions modules/express/test/unit/typedRoutes/acceptShare.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,23 @@ export function assertDecode<T>(codec: t.Type<T, unknown>, input: unknown): T {
return result.right;
}

/**
* Helper function to extract path parameter names from a route path
* Supports both Express-style (:param) and OpenAPI-style ({param}) notation
*/
function extractPathParams(path: string): string[] {
const colonParams = path.match(/:(\w+)/g)?.map((p) => p.slice(1)) || [];
const braceParams = path.match(/\{(\w+)\}/g)?.map((p) => p.slice(1, -1)) || [];
return [...colonParams, ...braceParams];
}

/**
* Helper function to get codec parameter names from a params object
*/
function getCodecParamNames(paramsCodec: Record<string, any>): string[] {
return Object.keys(paramsCodec);
}

describe('AcceptShare codec tests', function () {
describe('AcceptShareRequestParams', function () {
it('should validate valid params', function () {
Expand Down Expand Up @@ -102,6 +119,26 @@ describe('AcceptShare codec tests', function () {
assert.ok(PostAcceptShare.response[200]);
assert.ok(PostAcceptShare.response[400]);
});

/**
* CRITICAL TEST: Validates that path parameter names match codec parameter names
* to prevent runtime validation errors.
*/
it('should have path parameter names matching codec parameter names', function () {
const pathParams = extractPathParams(PostAcceptShare.path);
const codecParams = getCodecParamNames(AcceptShareRequestParams);

pathParams.sort();
codecParams.sort();

assert.deepStrictEqual(
pathParams,
codecParams,
`Path parameters ${JSON.stringify(pathParams)} do not match codec parameters ${JSON.stringify(
codecParams
)}. ` + `This will cause runtime validation errors! Path: ${PostAcceptShare.path}`
);
});
});

it('should handle empty strings for optional fields', function () {
Expand Down
36 changes: 36 additions & 0 deletions modules/express/test/unit/typedRoutes/coinSignTx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,23 @@ import {
} from '../../../src/typedRoutes/api/v2/coinSignTx';
import { assertDecode } from './common';

/**
* Helper function to extract path parameter names from a route path
* Supports both Express-style (:param) and OpenAPI-style ({param}) notation
*/
function extractPathParams(path: string): string[] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move this to a util?

const colonParams = path.match(/:(\w+)/g)?.map((p) => p.slice(1)) || [];
const braceParams = path.match(/\{(\w+)\}/g)?.map((p) => p.slice(1, -1)) || [];
return [...colonParams, ...braceParams];
}

/**
* Helper function to get codec parameter names from a params object
*/
function getCodecParamNames(paramsCodec: Record<string, any>): string[] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

return Object.keys(paramsCodec);
}

describe('CoinSignTx codec tests', function () {
describe('CoinSignTxParams', function () {
it('should validate params with required coin', function () {
Expand Down Expand Up @@ -370,5 +387,24 @@ describe('CoinSignTx codec tests', function () {
assert.ok(PostCoinSignTx.response[200]);
assert.ok(PostCoinSignTx.response[400]);
});

/**
* CRITICAL TEST: Validates that path parameter names match codec parameter names
* to prevent runtime validation errors.
*/
it('should have path parameter names matching codec parameter names', function () {
const pathParams = extractPathParams(PostCoinSignTx.path);
const codecParams = getCodecParamNames(CoinSignTxParams);

pathParams.sort();
codecParams.sort();

assert.deepStrictEqual(
pathParams,
codecParams,
`Path parameters ${JSON.stringify(pathParams)} do not match codec parameters ${JSON.stringify(codecParams)}. ` +
`This will cause runtime validation errors! Path: ${PostCoinSignTx.path}`
);
});
});
});
36 changes: 36 additions & 0 deletions modules/express/test/unit/typedRoutes/consolidateUnspents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,23 @@ import {
} from '../../../src/typedRoutes/api/v1/consolidateUnspents';
import { assertDecode } from './common';

/**
* Helper function to extract path parameter names from a route path
* Supports both Express-style (:param) and OpenAPI-style ({param}) notation
*/
function extractPathParams(path: string): string[] {
const colonParams = path.match(/:(\w+)/g)?.map((p) => p.slice(1)) || [];
const braceParams = path.match(/\{(\w+)\}/g)?.map((p) => p.slice(1, -1)) || [];
return [...colonParams, ...braceParams];
}

/**
* Helper function to get codec parameter names from a params object
*/
function getCodecParamNames(paramsCodec: Record<string, any>): string[] {
return Object.keys(paramsCodec);
}

describe('ConsolidateUnspents codec tests', function () {
describe('ConsolidateUnspentsRequestParams', function () {
it('should validate params with required id', function () {
Expand Down Expand Up @@ -657,5 +674,24 @@ describe('ConsolidateUnspents codec tests', function () {
assert.ok(PutConsolidateUnspents.response[200]);
assert.ok(PutConsolidateUnspents.response[400]);
});

/**
* CRITICAL TEST: Validates that path parameter names match codec parameter names
* to prevent runtime validation errors.
*/
it('should have path parameter names matching codec parameter names', function () {
const pathParams = extractPathParams(PutConsolidateUnspents.path);
const codecParams = getCodecParamNames(ConsolidateUnspentsRequestParams);

pathParams.sort();
codecParams.sort();

assert.deepStrictEqual(
pathParams,
codecParams,
`Path parameters ${JSON.stringify(pathParams)} do not match codec parameters ${JSON.stringify(codecParams)}. ` +
`This will cause runtime validation errors! Path: ${PutConsolidateUnspents.path}`
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,23 @@ import {
} from '../../../src/typedRoutes/api/v1/constructPendingApprovalTx';
import { assertDecode } from './common';

/**
* Helper function to extract path parameter names from a route path
* Supports both Express-style (:param) and OpenAPI-style ({param}) notation
*/
function extractPathParams(path: string): string[] {
const colonParams = path.match(/:(\w+)/g)?.map((p) => p.slice(1)) || [];
const braceParams = path.match(/\{(\w+)\}/g)?.map((p) => p.slice(1, -1)) || [];
return [...colonParams, ...braceParams];
}

/**
* Helper function to get codec parameter names from a params object
*/
function getCodecParamNames(paramsCodec: Record<string, any>): string[] {
return Object.keys(paramsCodec);
}

describe('ConstructPendingApprovalTx codec tests', function () {
describe('ConstructPendingApprovalTxRequestParams', function () {
it('should validate params with required id', function () {
Expand Down Expand Up @@ -301,5 +318,24 @@ describe('ConstructPendingApprovalTx codec tests', function () {
assert.ok(PutConstructPendingApprovalTx.response[200]);
assert.ok(PutConstructPendingApprovalTx.response[400]);
});

/**
* CRITICAL TEST: Validates that path parameter names match codec parameter names
* to prevent runtime validation errors.
*/
it('should have path parameter names matching codec parameter names', function () {
const pathParams = extractPathParams(PutConstructPendingApprovalTx.path);
const codecParams = getCodecParamNames(ConstructPendingApprovalTxRequestParams);

pathParams.sort();
codecParams.sort();

assert.deepStrictEqual(
pathParams,
codecParams,
`Path parameters ${JSON.stringify(pathParams)} do not match codec parameters ${JSON.stringify(codecParams)}. ` +
`This will cause runtime validation errors! Path: ${PutConstructPendingApprovalTx.path}`
);
});
});
});
36 changes: 36 additions & 0 deletions modules/express/test/unit/typedRoutes/fanoutUnspents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,23 @@ import {
} from '../../../src/typedRoutes/api/v1/fanoutUnspents';
import { assertDecode } from './common';

/**
* Helper function to extract path parameter names from a route path
* Supports both Express-style (:param) and OpenAPI-style ({param}) notation
*/
function extractPathParams(path: string): string[] {
const colonParams = path.match(/:(\w+)/g)?.map((p) => p.slice(1)) || [];
const braceParams = path.match(/\{(\w+)\}/g)?.map((p) => p.slice(1, -1)) || [];
return [...colonParams, ...braceParams];
}

/**
* Helper function to get codec parameter names from a params object
*/
function getCodecParamNames(paramsCodec: Record<string, any>): string[] {
return Object.keys(paramsCodec);
}

describe('FanoutUnspents codec tests', function () {
describe('FanoutUnspentsRequestParams', function () {
it('should validate params with required id', function () {
Expand Down Expand Up @@ -390,5 +407,24 @@ describe('FanoutUnspents codec tests', function () {
assert.ok(PutFanoutUnspents.response[200]);
assert.ok(PutFanoutUnspents.response[400]);
});

/**
* CRITICAL TEST: Validates that path parameter names match codec parameter names
* to prevent runtime validation errors.
*/
it('should have path parameter names matching codec parameter names', function () {
const pathParams = extractPathParams(PutFanoutUnspents.path);
const codecParams = getCodecParamNames(FanoutUnspentsRequestParams);

pathParams.sort();
codecParams.sort();

assert.deepStrictEqual(
pathParams,
codecParams,
`Path parameters ${JSON.stringify(pathParams)} do not match codec parameters ${JSON.stringify(codecParams)}. ` +
`This will cause runtime validation errors! Path: ${PutFanoutUnspents.path}`
);
});
});
});
35 changes: 34 additions & 1 deletion modules/express/test/unit/typedRoutes/pendingApproval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,23 @@ import {
PutPendingApproval,
} from '../../../src/typedRoutes/api/v1/pendingApproval';
import { assertDecode } from './common';

/**
* Helper function to extract path parameter names from a route path
* Supports both Express-style (:param) and OpenAPI-style ({param}) notation
*/
function extractPathParams(path: string): string[] {
const colonParams = path.match(/:(\w+)/g)?.map((p) => p.slice(1)) || [];
const braceParams = path.match(/\{(\w+)\}/g)?.map((p) => p.slice(1, -1)) || [];
return [...colonParams, ...braceParams];
}

/**
* Helper function to test io-ts codec decoding
* Helper function to get codec parameter names from a params object
*/
function getCodecParamNames(paramsCodec: Record<string, any>): string[] {
return Object.keys(paramsCodec);
}

describe('PendingApproval codec tests', function () {
describe('pendingApprovalRequestParams', function () {
Expand Down Expand Up @@ -203,5 +217,24 @@ describe('PendingApproval codec tests', function () {
assert.ok(PutPendingApproval.response[200]);
assert.ok(PutPendingApproval.response[400]);
});

/**
* CRITICAL TEST: Validates that path parameter names match codec parameter names
* to prevent runtime validation errors.
*/
it('should have path parameter names matching codec parameter names', function () {
const pathParams = extractPathParams(PutPendingApproval.path);
const codecParams = getCodecParamNames(pendingApprovalRequestParams);

pathParams.sort();
codecParams.sort();

assert.deepStrictEqual(
pathParams,
codecParams,
`Path parameters ${JSON.stringify(pathParams)} do not match codec parameters ${JSON.stringify(codecParams)}. ` +
`This will cause runtime validation errors! Path: ${PutPendingApproval.path}`
);
});
});
});
36 changes: 36 additions & 0 deletions modules/express/test/unit/typedRoutes/signTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,23 @@ import {
} from '../../../src/typedRoutes/api/v1/signTransaction';
import { assertDecode } from './common';

/**
* Helper function to extract path parameter names from a route path
* Supports both Express-style (:param) and OpenAPI-style ({param}) notation
*/
function extractPathParams(path: string): string[] {
const colonParams = path.match(/:(\w+)/g)?.map((p) => p.slice(1)) || [];
const braceParams = path.match(/\{(\w+)\}/g)?.map((p) => p.slice(1, -1)) || [];
return [...colonParams, ...braceParams];
}

/**
* Helper function to get codec parameter names from a params object
*/
function getCodecParamNames(paramsCodec: Record<string, any>): string[] {
return Object.keys(paramsCodec);
}

describe('SignTransaction codec tests', function () {
describe('signTransactionRequestParams', function () {
it('should validate valid params', function () {
Expand Down Expand Up @@ -334,5 +351,24 @@ describe('SignTransaction codec tests', function () {
assert.ok(PostSignTransaction.response[200]);
assert.ok(PostSignTransaction.response[400]);
});

/**
* CRITICAL TEST: Validates that path parameter names match codec parameter names
* to prevent runtime validation errors.
*/
it('should have path parameter names matching codec parameter names', function () {
const pathParams = extractPathParams(PostSignTransaction.path);
const codecParams = getCodecParamNames(signTransactionRequestParams);

pathParams.sort();
codecParams.sort();

assert.deepStrictEqual(
pathParams,
codecParams,
`Path parameters ${JSON.stringify(pathParams)} do not match codec parameters ${JSON.stringify(codecParams)}. ` +
`This will cause runtime validation errors! Path: ${PostSignTransaction.path}`
);
});
});
});
36 changes: 36 additions & 0 deletions modules/express/test/unit/typedRoutes/walletRecoverToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,23 @@ import {
} from '../../../src/typedRoutes/api/v2/walletRecoverToken';
import { assertDecode } from './common';

/**
* Helper function to extract path parameter names from a route path
* Supports both Express-style (:param) and OpenAPI-style ({param}) notation
*/
function extractPathParams(path: string): string[] {
const colonParams = path.match(/:(\w+)/g)?.map((p) => p.slice(1)) || [];
const braceParams = path.match(/\{(\w+)\}/g)?.map((p) => p.slice(1, -1)) || [];
return [...colonParams, ...braceParams];
}

/**
* Helper function to get codec parameter names from a params object
*/
function getCodecParamNames(paramsCodec: Record<string, any>): string[] {
return Object.keys(paramsCodec);
}

describe('WalletRecoverToken codec tests', function () {
describe('RecoverTokenParams', function () {
it('should validate params with required coin and id', function () {
Expand Down Expand Up @@ -580,5 +597,24 @@ describe('WalletRecoverToken codec tests', function () {
assert.ok(PostWalletRecoverToken.response[200]);
assert.ok(PostWalletRecoverToken.response[400]);
});

/**
* CRITICAL TEST: Validates that path parameter names match codec parameter names
* to prevent runtime validation errors.
*/
it('should have path parameter names matching codec parameter names', function () {
const pathParams = extractPathParams(PostWalletRecoverToken.path);
const codecParams = getCodecParamNames(RecoverTokenParams);

pathParams.sort();
codecParams.sort();

assert.deepStrictEqual(
pathParams,
codecParams,
`Path parameters ${JSON.stringify(pathParams)} do not match codec parameters ${JSON.stringify(codecParams)}. ` +
`This will cause runtime validation errors! Path: ${PostWalletRecoverToken.path}`
);
});
});
});
Loading