chore: add unit test

This commit is contained in:
friedger
2024-03-20 15:42:36 +01:00
parent bbf4041ff5
commit 44fa4a2a5d
3 changed files with 98 additions and 87 deletions

View File

@@ -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 = '<!--errors-->';
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<Array<string>> = [];
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);

View File

@@ -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 = '<!--errors-->';
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<Array<string>> = [];
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}`);
}

9
tests/errors.test.ts Normal file
View File

@@ -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
});
});