8000 GitHub - denysin08/smock: Mock contract functionality for buidler.
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
forked from jacobmort/smock

Mock contract functionality for buidler.

Notifications You must be signed in to change notification settings

denysin08/smock

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@eth-optimisim/smock

smock is a utility package that can generate mock Solidity contracts (for testing). smock hooks into a ethereumjs-vm instance so that mock contract functions can be written entirely in JavaScript. smock currently only supports buidler, but will be extended to support other testing frameworks.

Some nice benefits of hooking in at the VM level:

  • Don't need to deploy any special contracts just for mocking!
  • All of the calls are synchronous.
  • Perform arbitrary javascript logic within your return value (return a function).
  • It sounds cool.

smock also contains smoddit, another utility that allows you to modify the internal storage of contracts. We've found this to be quite useful in cases where many interactions occur within a single contract (typically to save gas).

Installation

You can easily install smock via npm:

npm install @eth-optimism/smock

Or via yarn:

yarn add @eth-optimism/smock

Note on Using smoddit

smoddit requires access to the internal storage layout of your smart contracts. The Solidity compiler exposes this via the storageLayout flag, but buidler does not enable this flag by default (and doesn't provide an easy way to do so). When using smoddit with buidler, you must therefore (for now) also import our compiler-storage-layout plugin within your buidler.config.ts. smoddit will not work without this plugin until support for custom compiler flags is added to buidler.

Here's an example buidler.config.ts that shows how to import the plugin:

// buidler.config.ts
import { usePlugin, BuidlerConfig } from 'hardhat/config'

usePlugin(...)
usePlugin(...)

import '@eth-optimism/smock/buidler-plugins/compiler-storage-layout'

const config: BuidlerConfig = {
  ...
}

export default config

Table of Contents

API

Functions

smockit

Import
import { smockit } from '@eth-optimism/smock'
Signature
const smockit = async (
  spec: ContractInterface | Contract | ContractFactory,
  opts: {
    provider?: any,
    address?: string,
  },
): Promise<MockContract>

smoddit

Import
import { smoddit } from '@eth-optimism/smock'
Signature
const smoddit = async (
  name: string,
  signer?: any
): Promise<ModifiableContractFactory>

Types

smockit

MockContract
interface MockContract extends Contract {
  smocked: {
    [functionName: string]: MockContractFunction
  }
}
MockContractFunction
interface MockContractFunction {
  calls: string[]
  will: {
    return: {
      (): void
      with: (returnValue?: MockReturnValue) => void
    }
    revert: {
      (): void
      with: (revertValue?: string) => void
    }
    resolve: 'return' | 'revert'
  }
}
MockReturnValue
export type MockReturnValue =
  | string
  | Object
  | any[]
  | ((...params: any[]) => MockReturnValue)

smoddit

ModifiableContractFactory
interface ModifiableContractFactory extends ContractFactory {
  deploy: (...args: any[]) => Promise<ModifiableContract>
}
ModifiableContract
interface ModifiableContract extends Contract {
  smodify: {
    put: (storage: any) => void
    set: (storage: any) => void
    reset: () => void
  }
}

Examples (smockit)

Via ethers.Contract

import { ethers } from 'hardhat'
import { smockit } from '@eth-optimism/smock'

const MyContractFactory = await ethers.getContractFactory('MyContract')
const MyContract = await MyContractFactory.deploy(...)

// Smockit!
const MyMockContract = await smockit(MyContract)

MyMockContract.myFunction.will.return.with('Some return value!')

console.log(await MyMockContract.myFunction()) // 'Some return value!'

Asserting Call Count

import { ethers } from 'hardhat'
import { smockit } from '@eth-optimism/smock'

const MyContractFactory = await ethers.getContractFactory('MyContract')
const MyContract = await MyContractFactory.deploy(...)

const MyOtherContractFactory = await ethers.getContractFactory('MyOtherContract')
const MyOtherContract = await MyOtherContract.deploy(...)

// Smockit!
const MyMockContract = await smockit(MyContract)

MyMockContract.smocked.myFunction.will.return.with('Some return value!')

// Assuming that MyOtherContract.myOtherFunction calls MyContract.myFunction.
await MyOtherContract.myOtherFunction()

console.log(MyMockContract.smocked.myFunction.calls.length) // 1

Asserting Call Data

import { ethers } from 'hardhat'
import { smockit } from '@eth-optimism/smock'

const MyContractFactory = await ethers.getContractFactory('MyContract')
const MyContract = await MyContractFactory.deploy(...)

const MyOtherContractFactory = await ethers.getContractFactory('MyOtherContract')
const MyOtherContract = await MyOtherContract.deploy(...)

// Smockit!
const MyMockContract = await smockit(MyContract)

MyMockContract.smocked.myFunction.will.return.with('Some return value!')

// Assuming that MyOtherContract.myOtherFunction calls MyContract.myFunction with 'Hello World!'.
await MyOtherContract.myOtherFunction()

console.log(MyMockContract.smocked.myFunction.calls[0]) // 'Hello World!'

Returning (w/o Data)

import { ethers } from 'hardhat'
import { smockit } from '@eth-optimism/smock'

const MyContractFactory = await ethers.getContractFactory('MyContract')
const MyContract = await MyContractFactory.deploy(...)

// Smockit!
const MyMockContract = await smockit(MyContract)

MyMockContract.smocked.myFunction.will.return()

console.log(await MyMockContract.myFunction()) // []

Returning a Struct

import { ethers } from 'hardhat'
import { smockit } from '@eth-optimism/smock'

const MyContractFactory = await ethers.getContractFactory('MyContract')
const MyContract = await MyContractFactory.deploy(...)

// Smockit!
const MyMockContract = await smockit(MyContract)

MyMockContract.smocked.myFunction.will.return.with({
    valueA: 'Some value',
    valueB: 1234,
    valueC: true
})

console.log(await MyMockContract.myFunction()) // ['Some value', 1234, true]

Returning a Function

import { ethers } from 'hardhat'
import { smockit } from '@eth-optimism/smock'

const MyContractFactory = await ethers.getContractFactory('MyContract')
const MyContract = await MyContractFactory.deploy(...)

// Smockit!
const MyMockContract = await smockit(MyContract)

MyMockContract.smocked.myFunction.will.return.with(() => {
  return 'Some return value!'
})

console.log(await MyMockContract.myFunction()) // ['Some return value!']

Returning a Function (w/ Arguments)

import { ethers } from 'hardhat'
import { smockit } from '@eth-optimism/smock'

const MyContractFactory = await ethers.getContractFactory('MyContract')
const MyContract = await MyContractFactory.deploy(...)

// Smockit!
const MyMockContract = await smockit(MyContract)

MyMockContract.smocked.myFunction.will.return.with((myFunctionArgument: string) => {
  return myFunctionArgument
})

console.log(await MyMockContract.myFunction('Some return value!')) // ['Some return value!']

Reverting (w/o Data)

import { ethers } from 'hardhat'
import { smockit } from '@eth-optimism/smock'

const MyContractFactory = await ethers.getContractFactory('MyContract')
const MyContract = await MyContractFactory.deploy(...)

// Smockit!
const MyMockContract = await smockit(MyContract)

MyMockContract.smocked.myFunction.will.revert()

console.log(await MyMockContract.myFunction()) // Revert!

Reverting (w/ Data)

import { ethers } from 'hardhat'
import { smockit } from '@eth-optimism/smock'

const MyContractFactory = await ethers.getContractFactory('MyContract')
const MyContract = await MyContractFactory.deploy(...)

// Smockit!
const MyMockContract = await smockit(MyContract)

MyMockContract.smocked.myFunction.will.revert.with('0x1234')

console.log(await MyMockContract.myFunction('Some return value!')) // Revert!

Examples (smoddit)

Creating a Modifiable Contract

import { ethers } from 'hardhat'
import { smoddit } from '@eth-optimism/smock'

// Smoddit!
const MyModifiableContractFactory = await smoddit('MyContract')
const MyModifiableContract = await MyModifiableContractFactory.deploy(...)

Modifying a uint256

import { ethers } from 'hardhat'
import { smoddit } from '@eth-optimism/smock'

// Smoddit!
const MyModifiableContractFactory = await smoddit('MyContract')
const MyModifiableContract = await MyModifiableContractFactory.deploy(...)

MyModifiableContract.smodify.put({
  myInternalUint256: 1234
})

console.log(await MyMockContract.getMyInternalUint256()) // 1234

Modifying a Struct

import { ethers } from 'hardhat'
import { smoddit } from '@eth-optimism/smock'

// Smoddit!
const MyModifiableContractFactory = await smoddit('MyContract')
const MyModifiableContract = await MyModifiableContractFactory.deploy(...)

MyModifiableContract.smodify.put({
  myInternalStruct: {
    valueA: 1234,
    valueB: true
  }
})

console.log(await MyMockContract.getMyInternalStruct()) // { valueA: 1234, valueB: true }

Modifying a Mapping

import { ethers } from 'hardhat'
import { smoddit } from '@eth-optimism/smock'

// Smoddit!
const MyModifiableContractFactory = await smoddit('MyContract')
const MyModifiableContract = await MyModifiableContractFactory.deploy(...)

MyModifiableContract.smodify.put({
  myInternalMapping: {
    1234: 5678
  }
})

console.log(await MyMockContract.getMyInternalMappingValue(1234)) // 5678

Modifying a Nested Mapping

import { ethers } from 'hardhat'
import { smoddit } from '@eth-optimism/smock'

// Smoddit!
const MyModifiableContractFactory = await smoddit('MyContract')
const MyModifiableContract = await MyModifiableContractFactory.deploy(...)

MyModifiableContract.smodify.put({
  myInternalNestedMapping: {
    1234: {
      4321: 5678
    }
  }
})

console.log(await MyMockContract.getMyInternalNestedMappingValue(1234, 4321)) // 5678

About

Mock contract functionality for buidler.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 89.5%
  • Solidity 10.5%
0