forge-test-names.ts 2.27 KB
Newer Older
1 2
import fs from 'fs'

3
import { glob } from 'glob'
4

5
/**
6
 * Series of function name checks.
7
 */
8 9 10 11 12 13 14 15 16
const checks: Array<{
  check: (parts: string[]) => boolean
  error: string
}> = [
  {
    error: 'test name parts should be in camelCase',
    check: (parts: string[]): boolean => {
      return parts.every((part) => {
        return part[0] === part[0].toLowerCase()
17 18 19
      })
    },
  },
20 21 22 23 24
  {
    error:
      'test names should have either 3 or 4 parts, each separated by underscores',
    check: (parts: string[]): boolean => {
      return parts.length === 3 || parts.length === 4
25 26
    },
  },
27 28 29 30
  {
    error: 'test names should begin with "test", "testFuzz", or "testDiff"',
    check: (parts: string[]): boolean => {
      return ['test', 'testFuzz', 'testDiff'].includes(parts[0])
31 32
    },
  },
33 34 35 36 37 38
  {
    error:
      'test names should end with either "succeeds", "reverts", "fails", "works" or "benchmark[_num]"',
    check: (parts: string[]): boolean => {
      return (
        ['succeeds', 'reverts', 'fails', 'benchmark', 'works'].includes(
39
          parts[parts.length - 1]
40 41 42 43
        ) ||
        (parts[parts.length - 2] === 'benchmark' &&
          !isNaN(parseInt(parts[parts.length - 1], 10)))
      )
44 45
    },
  },
46 47 48 49 50 51 52 53
  {
    error:
      'failure tests should have 4 parts, third part should indicate the reason for failure',
    check: (parts: string[]): boolean => {
      return (
        parts.length === 4 ||
        !['reverts', 'fails'].includes(parts[parts.length - 1])
      )
54
    },
55
  },
56
]
57

58 59 60
/**
 * Script for checking that all test functions are named correctly.
 */
61
const main = async () => {
62 63 64 65 66 67 68 69 70
  const errors: string[] = []
  const files = glob.sync('./forge-artifacts/**/*.t.sol/*Test*.json')
  for (const file of files) {
    const artifact = JSON.parse(fs.readFileSync(file, 'utf8'))
    for (const element of artifact.abi) {
      // Skip non-functions and functions that don't start with "test".
      if (element.type !== 'function' || !element.name.startsWith('test')) {
        continue
      }
71

72 73 74 75 76 77 78
      // Check the rest.
      for (const { check, error } of checks) {
        if (!check(element.name.split('_'))) {
          errors.push(`in ${file} function ${element.name}: ${error}`)
        }
      }
    }
79 80
  }

81 82
  if (errors.length > 0) {
    console.error(...errors)
83
    process.exit(1)
84 85
  }
}
86 87

main()