Commit fa6bfbbe authored by Maurelian's avatar Maurelian Committed by Matthew Slipper

ctb: Read abi rather than operating on text

parent cdb67852
...@@ -2,8 +2,8 @@ import fs from 'fs' ...@@ -2,8 +2,8 @@ import fs from 'fs'
import path from 'path' import path from 'path'
type Check = { type Check = {
check: (name: string, parts: string[]) => void, check: (name: string, parts: string[]) => void
makeError: (name: string) => Error, makeError: (name: string) => Error
} }
/** /**
...@@ -13,31 +13,37 @@ const FunctionNameChecks: { [name: string]: Check } = { ...@@ -13,31 +13,37 @@ const FunctionNameChecks: { [name: string]: Check } = {
invalidCase: { invalidCase: {
check: (name: string, parts: string[]): void => { check: (name: string, parts: string[]): void => {
parts.forEach((part) => { parts.forEach((part) => {
if (part[0] !== part[0].toLowerCase()) if (part[0] !== part[0].toLowerCase()) {
throw FunctionNameChecks.invalidCase.makeError(name) throw FunctionNameChecks.invalidCase.makeError(name)
}
}) })
}, },
makeError: (name: string): Error => new Error( makeError: (name: string): Error =>
`Invalid test name: ${name}.\n Test name parts should be in camelCase.` new Error(
) `Invalid test name "${name}".\n Test name parts should be in camelCase.`
),
}, },
invalidNumParts: { invalidNumParts: {
check: (name: string, parts: string[]): void => { check: (name: string, parts: string[]): void => {
if (parts.length < 3 || parts.length > 4) if (parts.length < 3 || parts.length > 4) {
throw FunctionNameChecks.invalidNumParts.makeError(name) throw FunctionNameChecks.invalidNumParts.makeError(name)
}
}, },
makeError: (name: string): Error => new Error( makeError: (name: string): Error =>
`Invalid test name: ${name}.\n Test names should have either 3 or 4 parts, each separated by underscores.` new Error(
) `Invalid test name "${name}".\n Test names should have either 3 or 4 parts, each separated by underscores.`
),
}, },
invalidPrefix: { invalidPrefix: {
check: (name: string, parts: string[]): void => { check: (name: string, parts: string[]): void => {
if (!['test', 'testFuzz', 'testDiff'].includes(parts[0])) if (!['test', 'testFuzz', 'testDiff'].includes(parts[0])) {
throw FunctionNameChecks.invalidPrefix.makeError(name) throw FunctionNameChecks.invalidPrefix.makeError(name)
}
}, },
makeError: (name: string): Error => new Error( makeError: (name: string): Error =>
`Invalid test name: ${name}.\n Names should begin with "test", "testFuzz", or "testDiff".` new Error(
) `Invalid test name "${name}".\n Names should begin with "test", "testFuzz", or "testDiff".`
),
}, },
invalidTestResult: { invalidTestResult: {
check: (name: string, parts: string[]): void => { check: (name: string, parts: string[]): void => {
...@@ -46,69 +52,69 @@ const FunctionNameChecks: { [name: string]: Check } = { ...@@ -46,69 +52,69 @@ const FunctionNameChecks: { [name: string]: Check } = {
parts[parts.length - 1] parts[parts.length - 1]
) && ) &&
parts[parts.length - 2] !== 'benchmark' parts[parts.length - 2] !== 'benchmark'
) ) {
throw FunctionNameChecks.invalidTestResult.makeError(name) throw FunctionNameChecks.invalidTestResult.makeError(name)
}
}, },
makeError: (name: string): Error => new Error( makeError: (name: string): Error =>
`Invalid test name: ${name}.\n Test names should end with either "succeeds", "reverts", "fails", "works" or "benchmark[_num]".` new Error(
) `Invalid test name "${name}".\n Test names should end with either "succeeds", "reverts", "fails", "works" or "benchmark[_num]".`
),
}, },
noFailureReason: { noFailureReason: {
check: (name: string, parts: string[]): void => { check: (name: string, parts: string[]): void => {
if ( if (
['reverts', 'fails'].includes(parts[parts.length - 1]) && ['reverts', 'fails'].includes(parts[parts.length - 1]) &&
parts.length < 4 parts.length < 4
) ) {
throw FunctionNameChecks.noFailureReason.makeError(name) throw FunctionNameChecks.noFailureReason.makeError(name)
},
makeError: (name: string): Error => new Error(
`Invalid test name: ${name}.\n Failure tests should have 4 parts. The third part should indicate the reason for failure.`
)
} }
},
makeError: (name: string): Error =>
new Error(
`Invalid test name "${name}".\n Failure tests should have 4 parts. The third part should indicate the reason for failure.`
),
},
} }
// Given a test function name, ensures it matches the expected format // Given a test function name, ensures it matches the expected format
const handleFunctionName = (name: string) => { const handleFunctionName = (name: string) => {
if (!name.startsWith('test')) if (!name.startsWith('test')) {
return return
}
const parts = name.split('_') const parts = name.split('_')
Object.values(FunctionNameChecks).forEach(({ check }) => check(name, parts)) Object.values(FunctionNameChecks).forEach(({ check }) => check(name, parts))
} }
// Todo: define this function for validating contract names
// Given a test contract name, ensures it matches the expected format
const handleContractName = (name: string) => {
name
}
const main = async () => { const main = async () => {
const testPath = './contracts/test' const artifactsPath = './forge-artifacts'
const testFiles = fs.readdirSync(testPath)
for (const testFile of testFiles) { // Get a list of all solidity files with the extension t.sol
const filePath = path.join(testPath, testFile) const solTestFiles = fs
const lines = fs .readdirSync(artifactsPath)
.readFileSync(filePath, 'utf-8') .filter((solFile) => solFile.includes('.t.sol'))
.split('\n')
.map((l) => l.trim()) // Build a list of artifacts for contracts which include the string Test in them
let currentContract: string let testArtifacts: string[] = []
for (const line of lines) { for (const file of solTestFiles) {
if (line.startsWith('contract')) { testArtifacts = testArtifacts.concat(
currentContract = line.split(' ')[1] fs
handleContractName(line) .readdirSync(path.join(artifactsPath, file))
continue .filter((x) => x.includes('Test'))
} else if (line.startsWith('function')) { .map((x) => path.join(artifactsPath, stf, x))
const funcName = line.split(' ')[1].split('(')[0]
try {
handleFunctionName(funcName)
} catch (error) {
throw new Error(
`In ${filePath}::${currentContract}:\n ${error.message}`
) )
} }
continue
} for (const artifact of testArtifacts) {
JSON.parse(fs.readFileSync(artifact, 'utf8'))
.abi.filter((el) => el.type === 'function')
.forEach((el) => {
try {
handleFunctionName(el.name)
} catch (error) {
throw new Error(`In ${path.parse(artifact).name}: ${error.message}`)
} }
})
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment