From 44fa4a2a5daa383822062c6991ebd5c0c77f287c Mon Sep 17 00:00:00 2001 From: friedger Date: Wed, 20 Mar 2024 15:42:36 +0100 Subject: [PATCH] chore: add unit test --- scripts/error-codes.ts | 89 +------------------------------------- scripts/lib/error-codes.ts | 87 +++++++++++++++++++++++++++++++++++++ tests/errors.test.ts | 9 ++++ 3 files changed, 98 insertions(+), 87 deletions(-) create mode 100644 scripts/lib/error-codes.ts create mode 100644 tests/errors.test.ts diff --git a/scripts/error-codes.ts b/scripts/error-codes.ts index 9a9d041..1dfdc55 100644 --- a/scripts/error-codes.ts +++ b/scripts/error-codes.ts @@ -1,92 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 import { initSimnet } from '@hirosystems/clarinet-sdk'; -import { readFileSync, writeFileSync } from 'fs'; -const readmeFile = './README.md'; +import { createErrorsTable } from './lib/error-codes.ts'; const manifestFile = './Clarinet.toml'; - -const constantErrRegex = /^\s*\(define-constant\s+(err-.+?)\s+(\(.+?\))\s*\)(.*?)$/gm; -const errorCodeRegex = /u([0-9]+)/; -const commentRegex = /;;\s*(.+)/; -const readmeErrorsDelineator = ''; - -const tableHeader = ['Contract', 'Constant', 'Value', 'Description']; - const simnet = await initSimnet(manifestFile); -export function isTestContract(contractName: string) { - return contractName.indexOf('mock') >= 0; -} - -function padTableCell(content: string, length: number) { - const repeat = length - content.length + 1; - return repeat > 0 ? ' ' + content + ' '.repeat(repeat) : ' '; -} - -function createErrorsTable() { - const errorsSeenCount: { [key: string]: { lastConstantName: string; count: number } } = {}; - let readme = readFileSync(readmeFile).toString(); - const errorTable: Array> = []; - const longestColumnCells = tableHeader.map(v => v.length); - - const compareReadme = process.env.EXTRACT_CHECK && readme; - - for (const [contractId, abi] of simnet.getContractsInterfaces()) { - if (isTestContract(contractId)) continue; - console.log(abi); - const source = simnet.getContractSource(contractId); - if (!source) continue; - const errorConstants = source.matchAll(constantErrRegex); - for (const [, errorConstant, errorValue, errorComment] of errorConstants) { - const errorDescription = errorComment?.match(commentRegex)?.[1] || ''; // || '_None_'; - if (!errorValue.match(errorCodeRegex)) - console.error(`Constant '${errorConstant}' error value is not in form of (err uint)`); - if (!errorsSeenCount[errorValue]) - errorsSeenCount[errorValue] = { lastConstantName: errorConstant, count: 1 }; - else if (errorsSeenCount[errorValue].lastConstantName !== errorConstant) { - errorsSeenCount[errorValue].lastConstantName = errorConstant; - ++errorsSeenCount[errorValue].count; - } - const row = [contractId.split('.')[1], errorConstant, errorValue, errorDescription]; - row.map((content, index) => { - if (content.length > longestColumnCells[index]) longestColumnCells[index] = content.length; - }); - errorTable.push(row); - } - } - - const nonUniqueErrors = Object.entries(errorsSeenCount).filter(([, value]) => value.count > 1); - if (nonUniqueErrors.length > 0) console.log(nonUniqueErrors); - - errorTable.sort((a, b) => (a[2] === b[2] ? (a[0] > b[0] ? 1 : -1) : a[2] > b[2] ? 1 : -1)); // string sort - - let errors = - '|' + - tableHeader - .map((content, index) => padTableCell(content, longestColumnCells[index])) - .join('|') + - '|\n'; - errors += '|' + longestColumnCells.map(length => '-'.repeat(length + 2)).join('|') + '|\n'; - errors += errorTable.reduce( - (accumulator, row) => - accumulator + - '|' + - row.map((content, index) => padTableCell(content, longestColumnCells[index])).join('|') + - '|\n', - '' - ); - - const split = readme.split(readmeErrorsDelineator); - readme = `${split[0]}${readmeErrorsDelineator}\n${errors}${readmeErrorsDelineator}${split[2]}`; - - if (compareReadme && compareReadme !== readme) { - throw new Error( - 'Generated readme is not equal to readme in current commit (error table mismatch)' - ); - } - - writeFileSync(readmeFile, readme); - console.log(`Error table written to ${readmeFile}`); -} - -console.log('start'); -createErrorsTable(); +createErrorsTable(simnet, false); diff --git a/scripts/lib/error-codes.ts b/scripts/lib/error-codes.ts new file mode 100644 index 0000000..04e9adf --- /dev/null +++ b/scripts/lib/error-codes.ts @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: BUSL-1.1 + +import { Simnet } from '@hirosystems/clarinet-sdk'; +import { readFileSync, writeFileSync } from 'fs'; +const readmeFile = './README.md'; + +const constantErrRegex = /^\s*\(define-constant\s+(err-.+?)\s+(\(.+?\))\s*\)(.*?)$/gm; +const errorCodeRegex = /u([0-9]+)/; +const commentRegex = /;;\s*(.+)/; +const readmeErrorsDelineator = ''; + +const tableHeader = ['Contract', 'Constant', 'Value', 'Description']; + +export function isTestContract(contractName: string) { + return contractName.indexOf('mock') >= 0; +} + +function padTableCell(content: string, length: number) { + const repeat = length - content.length + 1; + return repeat > 0 ? ' ' + content + ' '.repeat(repeat) : ' '; +} + +export function createErrorsTable(simnet: Simnet, extractCheck: boolean) { + const errorsSeenCount: { [key: string]: { lastConstantName: string; count: number } } = {}; + let readme = readFileSync(readmeFile).toString(); + const errorTable: Array> = []; + const longestColumnCells = tableHeader.map(v => v.length); + + const compareReadme = extractCheck && readme; + + for (const [contractId, abi] of simnet.getContractsInterfaces()) { + if (isTestContract(contractId)) continue; + console.log(abi); + const source = simnet.getContractSource(contractId); + if (!source) continue; + const errorConstants = source.matchAll(constantErrRegex); + for (const [, errorConstant, errorValue, errorComment] of errorConstants) { + const errorDescription = errorComment?.match(commentRegex)?.[1] || ''; // || '_None_'; + if (!errorValue.match(errorCodeRegex)) + console.error(`Constant '${errorConstant}' error value is not in form of (err uint)`); + if (!errorsSeenCount[errorValue]) + errorsSeenCount[errorValue] = { lastConstantName: errorConstant, count: 1 }; + else if (errorsSeenCount[errorValue].lastConstantName !== errorConstant) { + errorsSeenCount[errorValue].lastConstantName = errorConstant; + ++errorsSeenCount[errorValue].count; + } + const row = [contractId.split('.')[1], errorConstant, errorValue, errorDescription]; + row.map((content, index) => { + if (content.length > longestColumnCells[index]) longestColumnCells[index] = content.length; + }); + errorTable.push(row); + } + } + + const nonUniqueErrors = Object.entries(errorsSeenCount).filter(([, value]) => value.count > 1); + if (nonUniqueErrors.length > 0) console.log(nonUniqueErrors); + + errorTable.sort((a, b) => (a[2] === b[2] ? (a[0] > b[0] ? 1 : -1) : a[2] > b[2] ? 1 : -1)); // string sort + + let errors = + '|' + + tableHeader + .map((content, index) => padTableCell(content, longestColumnCells[index])) + .join('|') + + '|\n'; + errors += '|' + longestColumnCells.map(length => '-'.repeat(length + 2)).join('|') + '|\n'; + errors += errorTable.reduce( + (accumulator, row) => + accumulator + + '|' + + row.map((content, index) => padTableCell(content, longestColumnCells[index])).join('|') + + '|\n', + '' + ); + + const split = readme.split(readmeErrorsDelineator); + readme = `${split[0]}${readmeErrorsDelineator}\n${errors}${readmeErrorsDelineator}${split[2]}`; + + if (compareReadme && compareReadme !== readme) { + throw new Error( + 'Generated readme is not equal to readme in current commit (error table mismatch)' + ); + } + + writeFileSync(readmeFile, readme); + console.log(`Error table written to ${readmeFile}`); +} diff --git a/tests/errors.test.ts b/tests/errors.test.ts new file mode 100644 index 0000000..3bdbac2 --- /dev/null +++ b/tests/errors.test.ts @@ -0,0 +1,9 @@ +import { describe, it } from 'vitest'; +import { createErrorsTable } from '../scripts/lib/error-codes.ts'; + +describe('readme', () => { + it('should have the correct error code table', () => { + createErrorsTable(simnet, true); + // should not throw an error + }); +});