hotshot_testing/
script.rs

1// Copyright (c) 2021-2024 Espresso Systems (espressosys.com)
2// This file is part of the HotShot repository.
3
4// You should have received a copy of the MIT License
5// along with the HotShot repository. If not, see <https://mit-license.org/>.
6
7use std::{sync::Arc, time::Duration};
8
9use hotshot_task_impls::events::HotShotEvent;
10use hotshot_types::traits::node_implementation::NodeType;
11
12use crate::predicates::{Predicate, PredicateResult};
13
14pub enum InputOrder<TYPES: NodeType> {
15    Random(Vec<HotShotEvent<TYPES>>),
16    Serial(Vec<HotShotEvent<TYPES>>),
17}
18
19#[macro_export]
20macro_rules! random {
21    ($($x:expr),* $(,)?) => {
22        {
23            let inputs = vec![$($x),*];
24            InputOrder::Random(inputs)
25        }
26    };
27}
28
29#[macro_export]
30macro_rules! serial {
31    ($($x:expr),* $(,)?) => {
32        {
33            let inputs = vec![$($x),*];
34            InputOrder::Serial(inputs)
35        }
36    };
37}
38
39pub struct TaskScript<TYPES: NodeType, S> {
40    /// The time to wait on the receiver for this script.
41    pub timeout: Duration,
42    pub state: S,
43    pub expectations: Vec<Expectations<TYPES, S>>,
44}
45
46pub struct Expectations<TYPES: NodeType, S> {
47    pub output_asserts: Vec<Box<dyn Predicate<Arc<HotShotEvent<TYPES>>>>>,
48    pub task_state_asserts: Vec<Box<dyn Predicate<S>>>,
49}
50
51impl<TYPES: NodeType, S> Expectations<TYPES, S> {
52    pub fn from_outputs(output_asserts: Vec<Box<dyn Predicate<Arc<HotShotEvent<TYPES>>>>>) -> Self {
53        Self {
54            output_asserts,
55            task_state_asserts: vec![],
56        }
57    }
58    pub fn from_outputs_and_task_states(
59        output_asserts: Vec<Box<dyn Predicate<Arc<HotShotEvent<TYPES>>>>>,
60        task_state_asserts: Vec<Box<dyn Predicate<S>>>,
61    ) -> Self {
62        Self {
63            output_asserts,
64            task_state_asserts,
65        }
66    }
67}
68
69pub fn panic_extra_output_in_script<S>(stage_number: usize, script_name: String, output: &S)
70where
71    S: std::fmt::Debug,
72{
73    let extra_output_error = format!(
74        "Stage {stage_number} | Received unexpected additional output in \
75         {script_name}:\n\n{output:?}"
76    );
77
78    panic!("{}", extra_output_error);
79}
80
81pub fn panic_missing_output_in_script<S>(stage_number: usize, script_name: String, predicate: &S)
82where
83    S: std::fmt::Debug,
84{
85    let output_missing_error = format!(
86        "Stage {stage_number} | Failed to receive output for predicate in {script_name}: \
87         {predicate:?}"
88    );
89
90    panic!("{}", output_missing_error);
91}
92
93pub async fn validate_task_state_or_panic_in_script<S>(
94    stage_number: usize,
95    script_name: String,
96    state: &S,
97    assert: &dyn Predicate<S>,
98) {
99    assert!(
100        assert.evaluate(state).await == PredicateResult::Pass,
101        "Stage {stage_number} | Task state in {script_name} failed to satisfy: {assert:?}"
102    );
103}
104
105pub async fn validate_output_or_panic_in_script<S: std::fmt::Debug>(
106    stage_number: usize,
107    script_name: String,
108    output: &S,
109    assert: &dyn Predicate<S>,
110) -> PredicateResult {
111    let result = assert.evaluate(output).await;
112
113    match result {
114        PredicateResult::Pass => result,
115        PredicateResult::Incomplete => result,
116        PredicateResult::Fail => {
117            panic!(
118                "Stage {stage_number} | Output in {script_name} failed to satisfy: \
119                 {assert:?}.\n\nReceived:\n\n{output:?}"
120            )
121        },
122    }
123}