# Introduction

{% embed url="<https://youtu.be/tgs5q-GJmg4>" %}
Introduction | Testing with Foundry
{% endembed %}

## Setup

Install foundry toolchain:

```bash
curl -L https://foundry.paradigm.xyz | bash
foundryup
```

If everything goes well, you will now have four binaries at your disposal: `forge`, `cast`, `anvil`, and `chisel`.

{% hint style="info" %}
To update `foundryup` after installation, simply run `foundryup` again, and it will update to the latest Foundry release. You can also revert to a specific version of Foundry with `foundryup -v $VERSION`.
{% endhint %}

## First Steps with Foundry

Start a new project:

```
forge init <project_name>
```

Suppose we named the project "hello\_foundry", then the project layout is:

```
$ cd hello_foundry
$ tree . -d -L 1
.
├── lib
├── script
├── src
└── test

4 directories
```

Build the prject:

```
forge build
```

Test the project:

```
forge test
```

## Forge Cheatsheet

### Dependency

<mark style="color:red;">**Install dependency**</mark>, such as solmate:

```
forge install transmissions11/solmate
```

The dependency is going to be installed in the `/lib` directory.

Forge can <mark style="color:red;">**remap**</mark> dependencies to make them easier to import. Forge will automatically try to deduce some remappings for you:

```sh
$ forge remappings
ds-test/=lib/forge-std/lib/ds-test/src/
forge-std/=lib/forge-std/src/
solmate/=lib/solmate/src/
weird-erc20/=lib/weird-erc20/src/
```

These remappings mean:

* To import from `forge-std` we would write: `import "forge-std/Contract.sol";`
* To import from `ds-test` we would write: `import "ds-test/Contract.sol";`
* To import from `solmate` we would write: `import "solmate/Contract.sol";`
* To import from `weird-erc20` we would write: `import "weird-erc20/Contract.sol";`

You can customize these remappings by creating a `remappings.txt` file in the root of your project.

<mark style="color:red;">**Update dependency**</mark>:

```
forge update lib/solmate
```

<mark style="color:red;">**Remove dependency**</mark>:

```
forge remove solmate
```

### Tests

Forge will look for the tests anywhere in your source directory. Any contract with a function that starts with `test` is considered to be a test. Usually, tests will be placed in `test/` by convention and end with `.t.sol`.

<mark style="color:red;">**Run all tests:**</mark>

```
forge test
```

<mark style="color:red;">**Run a specific test:**</mark>

```
forge test --match-contract ComplicatedContractTest --match-test testDeposit
```

Inverse versions of these flags also exist (`--no-match-contract` and `--no-match-test`).

Match a <mark style="color:red;">**glob pattern**</mark>:

```
forge test --match-path test/ContractB.t.sol
```

The inverse of the `--match-path` flag is `--no-match-path`.

<mark style="color:red;">**Verbosity:**</mark>

* **Level 2 (`-vv`)**: Logs emitted during tests are also displayed. That includes assertion errors from tests, showing information such as expected vs actual.
* **Level 3 (`-vvv`)**: Stack traces for failing tests are also displayed.
* **Level 4 (`-vvvv`)**: Stack traces for all tests are displayed, and setup traces for failing tests are displayed.
* **Level 5 (`-vvvvv`)**: Stack traces and setup traces are always displayed.

## Hello World

Copy the contract from solidity-by-example.org:

{% embed url="<https://solidity-by-example.org/hello-world/>" %}
Hello World
{% endembed %}

```solidity
// SPDX-License-Identifier: MIT
// compiler version must be greater than or equal to 0.8.17 and less than 0.9.0
pragma solidity ^0.8.17;

contract HelloWorld {
    string public greet = "Hello World!";
}

```

Compile it:

```bash
forge build
```

Create a test file `HelloWorld.t.sol`. Copy and paste the content of `Counter.t.sol` into this new test file and write our own test cases:

```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Test.sol";
import "../src/HelloWorld.sol";

contract HelloWorldTest is Test {
    HelloWorld public helloWorld;

    function setUp() public {
        helloWolrd = new HelloWorld();
    }

    function testGreet() public {
        assertEq(helloWorld.greet(), "Hello World!");
    }

}

```

Note that `setup()` will be executed before executing each test case, and test case function name must start with the `test` prefix.

Run test:

```bash
forge test
```

<figure><img src="https://3988450783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWVjG_njKgBtvmnKaJh%2Fuploads%2Fc3Iez1OQGhdFqFuW4Xvw%2Fimage.png?alt=media&#x26;token=0d544b96-9057-456d-9caa-1f411370fbba" alt=""><figcaption><p>forge test</p></figcaption></figure>

Note that `forge test` would run all test files in the `test/` directory. If you only want to run a single test file:

```bash
forge test --match-path test/HelloWorld.t.sol
```

<figure><img src="https://3988450783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWVjG_njKgBtvmnKaJh%2Fuploads%2FBicaD4tDtT9iZiF6VCjX%2Fimage.png?alt=media&#x26;token=9d5f1a0d-8816-4a7e-ac6c-40aadb54e960" alt=""><figcaption><p>forge test --match-path</p></figcaption></figure>

Let's make the test fail:

```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Test.sol";
import "../src/HelloWorld.sol";

contract HelloWorldTest is Test {
    HelloWorld public helloWorld;

    function setUp() public {
        helloWorld = new HelloWorld();
    }

    function testGreet() public {
        assertEq(helloWorld.greet(), "Hello World?");
    }

}

```

Run test with verbosity marks:

```bash
forge test --match-path test/HelloWorld.t.sol -vvv
```

<figure><img src="https://3988450783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWVjG_njKgBtvmnKaJh%2Fuploads%2FzjeeTZZUK8C1CByxGaad%2Fimage.png?alt=media&#x26;token=fc30b368-217f-461c-9a74-d12363f0e12a" alt=""><figcaption><p>Failed test</p></figcaption></figure>

You can see why the test case failed in the `Traces` output.
