test-utils.ts 2.81 KB
Newer Older
1 2
import { expect } from 'chai'
import { BigNumber } from 'ethers'
3

4
import { sleep } from './misc'
5

6 7 8 9 10
interface deviationRanges {
  percentUpperDeviation?: number
  percentLowerDeviation?: number
  absoluteUpperDeviation?: number
  absoluteLowerDeviation?: number
11 12
}

13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
export const awaitCondition = async (
  cond: () => Promise<boolean>,
  rate = 1000,
  attempts = 10
) => {
  for (let i = 0; i < attempts; i++) {
    const ok = await cond()
    if (ok) {
      return
    }

    await sleep(rate)
  }

  throw new Error('Timed out.')
}

30 31 32 33 34 35
/**
 * Assert that a number lies within a custom defined range of the target.
 */
export const expectApprox = (
  actual: BigNumber | number,
  target: BigNumber | number,
36 37 38 39 40 41
  {
    percentUpperDeviation,
    percentLowerDeviation,
    absoluteUpperDeviation,
    absoluteLowerDeviation,
  }: deviationRanges
42 43 44 45
): void => {
  actual = BigNumber.from(actual)
  target = BigNumber.from(target)

46 47 48 49 50 51 52
  // Ensure at least one deviation parameter is defined
  const nonNullDeviations =
    percentUpperDeviation ||
    percentLowerDeviation ||
    absoluteUpperDeviation ||
    absoluteLowerDeviation
  if (!nonNullDeviations) {
53
    throw new Error(
54
      'Must define at least one parameter to limit the deviation of the actual value.'
55 56 57
    )
  }

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
  // Upper bound calculation.
  let upper: BigNumber
  // Set the two possible upper bounds if and only if they are defined.
  const upperPcnt: BigNumber = !percentUpperDeviation
    ? null
    : target.mul(100 + percentUpperDeviation).div(100)
  const upperAbs: BigNumber = !absoluteUpperDeviation
    ? null
    : target.add(absoluteUpperDeviation)

  if (upperPcnt && upperAbs) {
    // If both are set, take the lesser of the two upper bounds.
    upper = upperPcnt.lte(upperAbs) ? upperPcnt : upperAbs
  } else {
    // Else take whichever is not undefined or set to null.
    upper = upperPcnt || upperAbs
  }

  // Lower bound calculation.
  let lower: BigNumber
  // Set the two possible lower bounds if and only if they are defined.
  const lowerPcnt: BigNumber = !percentLowerDeviation
    ? null
    : target.mul(100 - percentLowerDeviation).div(100)
  const lowerAbs: BigNumber = !absoluteLowerDeviation
    ? null
    : target.sub(absoluteLowerDeviation)
  if (lowerPcnt && lowerAbs) {
    // If both are set, take the greater of the two lower bounds.
    lower = lowerPcnt.gte(lowerAbs) ? lowerPcnt : lowerAbs
  } else {
    // Else take whichever is not undefined or set to null.
    lower = lowerPcnt || lowerAbs
  }

  // Apply the assertions if they are non-null.
  if (upper) {
    expect(
      actual.lte(upper),
      `Actual value (${actual}) is greater than the calculated upper bound of (${upper})`
    ).to.be.true
  }
  if (lower) {
    expect(
      actual.gte(lower),
      `Actual value (${actual}) is less than the calculated lower bound of (${lower})`
    ).to.be.true
  }
106
}