• Stars
    star
    181
  • Rank 212,110 (Top 5 %)
  • Language
    Solidity
  • License
    MIT License
  • Created over 2 years ago
  • Updated 5 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Modern collection of testing assertions and logging utilities for Solidity

PRBTest Github Actions Coverage Foundry License: MIT

PRBTest is a modern collection of testing assertions and logging utilities for Solidity, and is meant to be a drop-in replacement for DSTest.

  • Feature-packed: assertions for equalities, inequalities, approximate equalities, numerical comparisons, and more
  • Type-rich: every assertion has overloads for address, bytes, bytes32, int256, string and uint256
  • Versioned releases so that you don't accidentally pull the latest version and break your test suites
  • Meant to be used with Foundry, but can also be used with Hardhat
  • Complementary to Forge Std
  • Designed for Solidity >=0.8.0
  • Thoroughly tested

Install

Foundry

First, run the install step:

forge install --no-commit PaulRBerg/prb-test@release-v0

Your .gitmodules file should now contain the following entry:

[submodule "lib/prb-test"]
  branch = "release-v0"
  path = "lib/prb-test"
  url = "https://github.com/PaulRBerg/prb-test"

Finally, add this to your remappings.txt file:

@prb/test/=lib/prb-test/src/

Node.js

pnpm add @prb/test
# or
npm install @prb/test

Template

If you're starting a project from scratch, the easiest way to install PRBTest is to use my Foundry template, since it comes pre-configured with PRBTest.

Usage

Once installed, all you need to do is import PRBTest and inherit from it in your test contract. PRBTest comes with a pre-instantiated cheatcodes environment accessible via the vm property. It also has support for logs.

// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0;

import { PRBTest } from "@prb/test/PRBTest.sol";

contract MyTest is PRBTest {
  function testExample() external {
    vm.warp(block.timestamp + 100);
    emit Log("Hello World");
    assertTrue(true);
  }
}

Assertions

All assertions have overloads with an additional err argument, so that you can pass custom error messages.

Name Argument Types
assertTrue bool
assertFalse bool
assertEq address, bytes, bytes32, int256, string, uint256 and their array equivalents
assertNotEq address, bytes, bytes32, int256, string, uint256 and their array equivalents
assertAlmostEq int256 and uint256
assertGt int256 and uint256
assertGte int256 and uint256
assertLt int256 and uint256
assertLte int256 and uint256
assertContains address[], bytes32[], int256[], string[], and uint256[]

Forge Std

PRBTest can be used alongside all testing utilities from forge-std, except for their Test contract.

Here's an example for how to use PRBTest with StdCheats and stdError:

// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0;

import { PRBTest } from "@prb/test/PRBTest.sol";
import { StdCheats } from "forge-std/StdCheats.sol";
import { stdError } from "forge-std/Test.sol";

contract MyTest is PRBTest, StdCheats {
  function testArithmeticOverflow() external {
    uint256 a = type(uint256).max;
    uint256 b = 1;
    vm.expectRevert(stdError.arithmeticError);
    a + b;
  }
}

Why Choose PRBTest Over DSTest?

DSTest is great. I have used it for a while, and I like it a lot. But, with time, I slowly came to realize that there's a lot of room for improvement.

1. Missing Features and Tests

DSTest is incomplete. Some commonly needed assertions, like equality assertions for arrays, assertEq(bool,bool) and assertNotEq, are missing from DSTest. PRBTest fills these gaps, and then some.

Also, the DSTest testing assertions are not themselves tested. Whereas the PRBTest testing assertions are tested, and in fact they are quite thoroughly tested. All other things being equal, this should give you more confidence that your tests do what you intend them to do.

2. No Release Versioning

DSTest doesn't version its releases, which makes it difficult to future-proof consumer repos. It's quite easy to accidentally update your git submodules and thus break your test suites. For some users, this is a real pain.

PRBTest is versioned via tags and branches and all changes are tracked in a CHANGELOG file. I maintain redundant branches for each release because git submodules don't support tags.

I will strive to follow the semver versioning scheme, though I won't do this before the v1.0 release, and it might not always be feasible.

3. Path Dependence

As one of the maintainers of DSTest said here, updating DSTest is painful to orchestrate. The reasons for this are twofold:

  1. Every DappTools project uses it as a git submodule.
  2. DSTest releases have not been versioned.

So any significant change in DSTest might wreak havoc downstream.

This issue has led to a "balkanization" of DSTest forks and extensions. See, for instance, Solmate's DSTestPlus and Forge Std's Test. Also see the discussions in this PR, in which the PR author ended up making the PR against forge-std rather than ds-test because he feared that his PR won't be merged.

4. Lack of Backward Compatibility with Node.js

It is my firm conviction that Foundry is the future of Ethereum smart contract development. Solidity code is best tested in Solidity itself.

But, due to various historical reasons, the Ethereum ecosystem has for a long time relied upon JavaScript for testing smart contracts. Refactoring a code base from Hardhat or Truffle to Foundry takes time, and it may not always be possible to do it in one fell swoop. Thus, to ensure backward compatibility, PRBTest is available as a Node.js package in the npm package registry.

For more details about this, see this discussion here.

Contributing

Feel free to dive in! Open an issue, start a discussion or submit a PR.

Pre Requisites

You will need the following software on your machine:

In addition, familiarity with Solidity is requisite.

Set Up

Clone this repository including submodules:

$ git clone --recurse-submodules -j8 [email protected]:PaulRBerg/prb-test.git

Then, inside the project's directory, run this to install the Node.js dependencies:

$ pnpm install

Now you can start making changes.

Syntax Highlighting

You will need the following VSCode extensions:

Acknowledgements

These contracts were inspired by or directly modified from the following sources:

License

This project is licensed under MIT.

More Repositories

1

hardhat-template

Hardhat-based template for developing Solidity smart contracts
TypeScript
1,958
star
2

prb-math

Solidity library for advanced fixed-point math
Solidity
876
star
3

foundry-template

Foundry-based template for developing Solidity smart contracts
Solidity
560
star
4

prb-proxy

Proxy contract to compose Ethereum transactions
Solidity
271
star
5

prb-contracts

Off-the-shelf Solidity smart contracts
Solidity
132
star
6

multisol

CLI application for verifying Solidity contracts on Etherscan
Rust
113
star
7

rust-template

A template for developing Rust projects, with sensible defaults
Rust
84
star
8

awesome-zkp-starter-pack

A curated collection of links for zero-knowledge proof cryptography used in blockchains
70
star
9

btt-examples

Examples for Branching Tree Technique, a simple specification framework for writing structured Solidity tests
Solidity
58
star
10

evm-bn

Convert fixed-point numbers to ethers big numbers and vice-versa.
TypeScript
49
star
11

check-same-sign

Gas golfing the most gas efficient way to check if two integers have the same sign in Solidity
Solidity
46
star
12

foundry-multibuild

GitHub Action for building a Foundry project with a range of Solidity versions
Shell
39
star
13

hardhat-packager

Hardhat plugin for preparing the contract artifacts and the TypeChain bindings for registry deployment
TypeScript
35
star
14

ethsum

Simple Ethereum address checksum tool
JavaScript
33
star
15

solplate

Simple utility for generating boilerplate Solidity contracts
Rust
32
star
16

typescript-template

A template for developing TypeScript project, with sensible defaults
TypeScript
32
star
17

awesome-many-worlds

Curated collection of educational materials on the many-worlds interpretation of quantum mechanics
25
star
18

github-labels

GitHub labels to use across repositories
Shell
21
star
19

CoinMarketCap-Desktop

A simple desktop wrapper for CoinMarketCap
JavaScript
21
star
20

cryptfolio-scripts

A collection of Google Apps Script custom functions for tracking crypto portfolios in Google Sheets
JavaScript
20
star
21

erc2212

Reference implementation for ERC-2212
JavaScript
12
star
22

unchecked-counter

Solidity counter type that bypasses checked arithmetic
Solidity
12
star
23

create2-repro

Repo to reproduce the inconsistent CREATE2 behavior in Foundry
Solidity
11
star
24

contractz

Sketchbook for my Ethereum contracts
Solidity
11
star
25

modlizer

Struggling with iOS design patterns? Embrace Modlizer
Swift
11
star
26

defi-types

TypeChain bindings for DeFi protocols
Solidity
10
star
27

dyi-crypto-taxes

Spreadsheet templates and practical tips and tricks for doing your taxes alone
10
star
28

abdk-gas-estimations

Gas estimations for ADBKMath64x64
Solidity
9
star
29

rust-book-annotations

My absorption of the Rust Book
Rust
8
star
30

javascript-template

A template for developing JavaScript projects, with sensible defaults
JavaScript
7
star
31

typescript-monorepo-template

Dummy monorepo set up with Typescript and Yarn Workspaces
TypeScript
4
star
32

tft

Browser extension that prevents typos by asking you to double-check the content before posting a long tweet
JavaScript
3
star
33

foundry-expect-emit-bug

Repo to reproduce the bug I ran into while writing tests with Foundry
Solidity
3
star
34

cea-contracts

Base smart contracts used in the default template of Create Eth App
JavaScript
3
star
35

my-eth-app

Default boilerplate code generated by create-eth-app
HTML
3
star
36

hardhat-prb

Hardhat plugins to complement the PRB smart contract libraries
TypeScript
3
star
37

react-hooks

React Hooks to be shared across my personal projects and packages
JavaScript
2
star
38

flipper-ui

The frontend app for the users of Flipper.
JavaScript
2
star
39

web3-react-blobs

Blobs of web3-react code used in the Sablier Interface
JavaScript
2
star
40

forge-coverage-bug

Repo to reproduce the bug in the forge coverage command
Solidity
2
star
41

PaulRBerg.github.io

My personal website
HTML
2
star
42

xstate-useActor-bug

xstate useActor bug
TypeScript
2
star
43

vscode-dictionary

Personal dictionary for vscode-spell-checker
2
star
44

prb-proxy-frontend

Landing page for PRBProxy
TypeScript
2
star
45

eslint-config

Eslint config to be shared across my personal projects and packages
JavaScript
2
star
46

test-foundry-template

Solidity
2
star
47

rage-stream

Rage stream functionality added to Sablier
TypeScript
1
star
48

airdropx

Firebase backend for the AirdropX Telegram bot
JavaScript
1
star
49

learn-plasma-rss

RSS feed for Plasma resources
JavaScript
1
star
50

paulrberg-labelsync

Dummy repo for label-sync.com
1
star
51

sketchpad

Personal repo for learning, logs and constants
JavaScript
1
star
52

cea-template

The official base template for Create Eth App.
HTML
1
star
53

hardhat-ignition-basic

Dummy project for going through the [email protected] basic tutorial
TypeScript
1
star
54

buidler-invalid-opcode

Reproduces the ganache-cli invalid opcode bug
TypeScript
1
star
55

yarn-rc34-error

Dummy project to reproduce the errors I encountered with [email protected]
JavaScript
1
star
56

ethiasi

Landing page for the first Ethereum event in Iasi, Romania
CSS
1
star
57

ethereum-signatures-progress

A collection of links and resources I collected in order to implement EIP-191 and EIP-712 into geth.
1
star
58

codebase-go

Personal repo for learning, logs and constants related to golang.
Go
1
star
59

dfe

Browser extension that hides the price of Ether
JavaScript
1
star