UNPKG

@bowtieddevops/bowtieddevops-test-package-3

Version:
164 lines (149 loc) 5.37 kB
import { Simnet, tx } from "@hirosystems/clarinet-sdk"; import { describe, it } from "vitest"; import { extractTestAnnotations, } from "./parser/clarity-parser"; import { expectOkTrue, isValidTestFunction } from "./parser/test-helpers"; import { FunctionAnnotations } from "./parser/clarity-parser-flow-tests"; /** * Returns true if the contract is a test contract * @param contractName name of the contract * @returns */ function isTestContract(contractName: string) { return ( contractName.substring(contractName.length - 5) === "_test" && contractName.substring(contractName.length - 10) !== "_flow_test" ); } export function generateUnitTests(simnet: Simnet) { const accounts = simnet.getAccounts(); // for each test contract create a test suite simnet.getContractsInterfaces().forEach((contract, contractFQN) => { if (!isTestContract(contractFQN)) { return; } describe(contractFQN, () => { // determine whether the contract has a prepare function const hasDefaultPrepareFunction = contract.functions.findIndex((f) => f.name === "prepare") >= 0; contract.functions.forEach((functionCall) => { if (!isValidTestFunction(functionCall)) { return; } const functionName = functionCall.name; const source = simnet.getContractSource(contractFQN)!; const annotations: any = extractTestAnnotations(source); const functionAnnotations: FunctionAnnotations = annotations[functionName] || {}; const mineBlocksBefore = parseInt(annotations["mine-blocks-before"] as string) || 0; const testDescription = `${functionCall.name}${functionAnnotations.name ? `: ${functionAnnotations.name}` : "" }`; it(testDescription, () => { // handle prepare function for this test if (hasDefaultPrepareFunction && !functionAnnotations.prepare) functionAnnotations.prepare = "prepare"; if (functionAnnotations["no-prepare"]) delete functionAnnotations.prepare; // handle caller address for this test const callerAddress = functionAnnotations.caller ? annotations.caller[0] === "'" ? `${(annotations.caller as string).substring(1)}` : accounts.get(annotations.caller)! : accounts.get("deployer")!; if (functionAnnotations.prepare) { // mine block with prepare function call mineBlockWithPrepareAndTestFunctionCall( contractFQN, functionAnnotations.prepare as string, mineBlocksBefore, functionName, callerAddress, simnet, accounts ); } else { // mine block without prepare function call mineBlockWithTestFunctionCall( contractFQN, mineBlocksBefore, functionName, callerAddress, simnet ); } }); }); }); }); } /** * Mine a block with a prepare function call and a test function call * If requested, mine the specified number of blocks beforehand. * @param contractFQN the contract id of the test * @param prepareFunctionName the function name of the prepare function * @param mineBlocksBefore the number of blocks to mine before the prepare function call, can be 0 * @param functionName the test function name * @param callerAddress the caller of the test function */ function mineBlockWithPrepareAndTestFunctionCall( contractFQN: string, prepareFunctionName: string, mineBlocksBefore: number, functionName: string, callerAddress: string, simnet: Simnet, accounts: any ) { if (mineBlocksBefore > 0) { let block = simnet.mineBlock([ tx.callPublicFn( contractFQN, prepareFunctionName, [], accounts.get("deployer")! ), ]); expectOkTrue(block, contractFQN, prepareFunctionName, 0); simnet.mineEmptyBlocks(mineBlocksBefore - 1); block = simnet.mineBlock([ tx.callPublicFn(contractFQN, functionName, [], callerAddress), ]); expectOkTrue(block, contractFQN, functionName, 0); } else { let block = simnet.mineBlock([ tx.callPublicFn( contractFQN, prepareFunctionName, [], accounts.get("deployer")! ), tx.callPublicFn(contractFQN, functionName, [], callerAddress), ]); expectOkTrue(block, contractFQN, prepareFunctionName, 0); expectOkTrue(block, contractFQN, functionName, 1); } } /** * Mines a block with a single test function call * If requested, mine the specified number of blocks beforehand. * * @param contractFQN the contract id of the test * @param mineBlocksBefore the number of blocks to mine before the test function call, can be 0 * @param functionName the test function name * @param callerAddress the caller of the test function */ function mineBlockWithTestFunctionCall( contractFQN: string, mineBlocksBefore: number, functionName: string, callerAddress: string, simnet: Simnet ) { simnet.mineEmptyBlocks(mineBlocksBefore); const block = simnet.mineBlock([ tx.callPublicFn(contractFQN, functionName, [], callerAddress), ]); expectOkTrue(block, contractFQN, functionName, 0); }