<h1 align="center">p2panda-rs test_utils</h1>
<div align="center">
<strong>All the things a panda needs (for testing)</strong>
</div>
<br />
`test_utils` provides tools for [p2panda](https://github.com/p2panda/p2panda) which can be used for testing in Rust.
## Parameter Fixtures
These fixtures can be injected into tests via there parameters. They can be customised using the `#[case]` marco otherwise default values will be used.
A simple example is shown below, see module level [docs](https://github.com/p2panda/p2panda/blob/main/p2panda-rs/src/test_utils/fixtures/mod.rs) for more examples.
```rust
use rstest::rstest;
use crate::entry::Entry;
use crate::identity::KeyPair;
use crate::test_utils::fixtures::{entry, key_pair};
// In this test `entry` and `key_pair` are injected directly into the test,
// they were imported from the fixtures module above and their default values
// will be used.
#[cfg(test)]
fn encode_entry(entry: Entry, key_pair: KeyPair) {
assert!(sign_and_encode(&entry, &key_pair).is_ok());
}
```
## Fixture templates
These can be used to apply a collection of different parameter fixtures to a single test.
```rust
use rstest::rstest;
use crate::entry::Entry;
use crate::identity::KeyPair;
use crate::test_utils::fixtures::{entry, key_pair};
use crate::test_utils::fixtures::templates::many_valid_entries;
// This test is similar to the first, but now using a template we can test
// against many different valid entries.
#[apply(many_valid_entries)]
fn encode_multiple_entries(#[case] entry: Entry, key_pair: KeyPair) {
assert!(sign_and_encode(&entry, &key_pair).is_ok());
}
```
## Mock Node & Client
The two structs `Node` and `Client` can be used to simulate networking traffic with multiple authors that would exist in a live p2panda network. These are to be used in testing when needing to generate common p2panda data which relies on communication between these different parts.
```rust
// IMPORTS MISSING FOR BREVITY //
//
// We are using many tools from the `test_utils` in this example, please see
// module level docs for more thorough examples.
let panda = Client::new("panda".to_string(), keypair_from_private(private_key));
let penguin = Client::new("penguin".to_string(), KeyPair::new());
let mut node = Node::new();
// Panda publishes a create operation. In doing so they create a document log
// which contains one entry.
//
// PANDA : [1]
// PENGUIN:
let (panda_entry_1_hash, next_entry_args) = send_to_node(
&mut node,
&panda,
&operation(
Some(operation_fields(vec![(
"cafe_name",
OperationValue::Text("Panda Cafe".to_string()),
)])),
None,
None
)
).unwrap();
// Panda publishes an update operation. This appends a new entry to the
// document log, the operation also refers to the previous tip of the graph by
// it's operation id.
//
// PANDA : [1] <--[2]
// PENGUIN:
let (panda_entry_2_hash, next_entry_args) = send_to_node(
&mut node,
&panda,
&operation(
Some(operation_fields(vec![(
"cafe_name",
OperationValue::Text("Panda Cafe!!".to_string()),
)])),
Some(panda_entry_1_hash.clone().into()),
None
)
).unwrap();
// Now Penguin publishes an update operation which refers to Panda's document
// (via it's tip operation). In doing this Penguin creates their own document log
// which now contains one entry, the operation on this entry refers to Panda's
// document log tip.
//
// PANDA : [1] <--[2]
// PENGUIN: \--[1]
let (penguin_entry_1_hash, next_entry_args) = send_to_node(
&mut node,
&penguin,
&operation(
Some(operation_fields(vec![(
"cafe_name",
OperationValue::Text("Panda Cafe!!".to_string()),
)])),
Some(panda_entry_2_hash.clone().into()),
None
)
)
.unwrap();
```
## Logging
To enable logging in the mock node run the test suite with the following env vars set:
```bash
# Run tests with info logging
RUST_LOG=p2panda_rs=info cargo test
# Run tests with info and debug logging
RUST_LOG=p2panda_rs=debug cargo test
```