Trdelnik Logo # Trdelník Ackee Blockchain Discord invitation developed by [Ackee Blockchain](https://ackeeblockchain.com) [![Crates.io](https://img.shields.io/crates/v/trdelnik-cli?label=CLI)](https://crates.io/crates/trdelnik-cli) [![Crates.io](https://img.shields.io/crates/v/trdelnik-test?label=Test)](https://crates.io/crates/trdelnik-test) [![Crates.io](https://img.shields.io/crates/v/trdelnik-client?label=Client)](https://crates.io/crates/trdelnik-client) [![Crates.io](https://img.shields.io/crates/v/trdelnik-explorer?label=Explorer)](https://crates.io/crates/trdelnik-explorer)
[![lint](https://github.com/Ackee-Blockchain/trdelnik/actions/workflows/lint.yml/badge.svg)](https://github.com/Ackee-Blockchain/trdelnik/actions/workflows/lint.yml) [![Test Escrow and Turnstile](https://github.com/Ackee-Blockchain/trdelnik/actions/workflows/run_examples.yml/badge.svg)](https://github.com/Ackee-Blockchain/trdelnik/actions/workflows/run_examples.yml)

Trdelník is Rust based testing framework providing several convenient developer tools for testing Solana programs written in Anchor.

Trdelnik Demo

Dependencies

Installation

```shell cargo install trdelnik-cli

or the specific version

cargo install --version trdelnik-cli ```

Usage

```shell

navigate to your project root directory

trdelnik init

it will generate .program_client and trdelnik-tests directories with all the necessary files

trdelnik test

want more?

trdelnik --help ```

How to write tests?

``rust // <my_project>/trdelnik-tests/tests/test.rs // TODO: do not forget to add all necessary dependencies to the generatedtrdelnik-tests/Cargo.toml` use programclient::myinstruction; use trdelnikclient::*; use myprogram;

[throws]

[fixture]

async fn initfixture() -> Fixture { // create a test fixture let mut fixture = Fixture { client: Client::new(systemkeypair(0)), // make sure your program is using a correct program ID program: programkeypair(1), state: keypair(42), }; // deploy a tested program fixture.deploy().await?; // call instruction init myinstruction::initialize( &fixture.client, fixture.state.pubkey(), fixture.client.payer().pubkey(), System::id(), Some(fixture.state.clone()), ).await?; fixture }

[trdelnik_test]

async fn testhappypath(#[future] initfixture: Result) { let fixture = initfixture.await?; // call the instruction myinstruction::dosomething( &fixture.client, "dummystring".toowned(), fixture.state.pubkey(), None, ).await?; // check the test result let state = fixture.getstate().await?; asserteq!(state.something_changed, "yes"); } ```

Make sure your program is using a correct program ID in the derive_id!(...) macro and inside Anchor.toml. If not, obtain the public key of a key pair you're using and replace it in these two places. To get the program ID of a key pair (key pair's public key) the trdelnik key-pair command can be used. For example $ trdelnik key-pair program 7 will print information about the key pair received from program_keypair(7).

Instructions with custom structures

```rust pub struct MyStruct { amount: u64, }

// ...

pub fn my_instruction(ctx: Context, data: MyStruct) { /* ... */ } ```

```rust // .program_client/src/lib.rs

// DO NOT EDIT - automatically generated file pub mod myprograminstruction { use trdelnikclient::*; use myprogram::MyStruct; // add this import

// ... } ```

Skipping tests

```rust

[trdelnik_test]

[ignore]

async fn test() {} ```

Testing programs with associated token accounts

```toml

/trdelnik-tests/Cargo.toml

import the correct versions manually

anchor-spl = "0.28.0" spl-associated-token-account = "2.0.0" ```

```rust // /trdelnik-tests/tests/test.rs use anchorspl::token::Token; use splassociatedtokenaccount;

async fn initfixture() -> Fixture { // ... let account = keypair(1); let mint = keypair(2); // constructs a token mint client .createtokenmint(&mint, mint.pubkey(), None, 0) .await?; // constructs associated token account let tokenaccount = client .createassociatedtokenaccount(&account, mint.pubkey()) .await?; let associatedtokenprogram = splassociatedtokenaccount::id(); // derives the associated token account address for the given wallet and mint let associatedtokenaddress = splassociatedtokenaccount::getassociatedtokenaddress(&account.pubkey(), mint); Fixture { // ... token_program: Token::id(), } } ```

How to use the fuzzer?

Once you initialize Trdelnik in your Anchor project, you will find a fuzz test template in the trdelnik-tests/src/bin folder that you can modify according to your needs or create new targets. Do not forget to install honggfuzz-rs using cargo install honggfuzz.

```shell

To run the fuzz test, execute this command from your terminal and replace with the name of your fuzz target (by default "fuzz_target")

trdelnik fuzz run

To debug your fuzz target crash with parameters from a crash file

trdelnik fuzz run-debug ```

Under the hood Trdelnik uses honggfuzz-rs. You can pass parameters via environment variables. List of hongfuzz parameters can be found in honggfuzz usage documentation. For example: ```shell

Time-out: 10 secs

Number of concurrent fuzzing threads: 1

Number of fuzzing iterations: 10000

Display Solana logs in the terminal

HFUZZRUNARGS="-t 10 -n 1 -N 10000 -Q" trdelnik fuzz run ```

NOTE: If you will use the solana-program-test crate for fuzzing, creating a new test program using ProgramTest::new() will create temporary folders in your /tmp directory that will not be cleared in case your program panics. You might want to clear these folders manually.

Supported versions

| Trdelnik CLI | Anchor | Solana | |--------------|:---------:|---------:| | latest | ~0.28.* | =1.16.6 | | v0.4.0 | ~0.27.* | >=1.15 | | v0.3.0 | ~0.25.* | >=1.10 | | v0.2.0 | ~0.24.* | >=1.9 |

Configuration

The configuration variables can be edited in the Trdelnik.toml file that'll be generated in the root of the project.

| Name | Default value | Description | |----------------------------------|---------------|-----------------------------------------------------------------------------| | test.validator_startup_timeout | 10 000 | Time to wait for the solana-test-validator in milliseconds before failure |

Roadmap

Awards

Marinade Community Prize - winner of the Marinade grant for the 2022 Solana Riptide Hackathon.

Contribution

Thank you for your interest in contributing to Trdelník! Please see the CONTRIBUTING.md to learn how.

License

This project is licensed under the MIT license.

University and investment partners