url_cleaner_engine/
testing.rs

1//! A basic and not very good testing framework.
2
3use std::borrow::Cow;
4
5use serde::{Serialize, Deserialize};
6
7use crate::types::*;
8use crate::util::*;
9
10/// Tests.
11#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
12pub struct Tests {
13    /// The individual [`TestSet`]s.
14    pub sets: Vec<TestSet>
15}
16
17impl Tests {
18    /// Do the tests. Panicking if any fail.
19    /// # Panics
20    /// If any call to [`TestSet::do`] panics, "returns" that panic.
21    pub fn r#do(self, cleaner: &Cleaner) {
22        for set in self.sets {
23            set.r#do(cleaner)
24        }
25    }
26}
27
28/// Rules for how to construct a [`Job`] from a [`Cleaner`] and the [`Test`]s to run on it.
29#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
30pub struct TestSet {
31    /// The [`ParamsDiff`] to apply to the [`Cleaner`].
32    #[serde(default, skip_serializing_if = "is_default")]
33    pub params_diff: Option<ParamsDiff>,
34    /// The [`JobContext`] to give to the [`Job`].
35    #[serde(default, skip_serializing_if = "is_default")]
36    pub job_context: JobContext,
37    /// The [`Test`]s to run.
38    pub tests: Vec<Test>
39}
40
41impl TestSet {
42    /// Do the tests, panicking if any fail.
43    /// # Panics
44    /// If a value from [`JobIter`] is an error, panics.
45    ///
46    /// If a call to [`Task::do`] returns an error, panics.
47    ///
48    /// If any test fails, panics.
49    pub fn r#do(self, cleaner: &Cleaner) {
50        let mut cleaner = Cow::Borrowed(cleaner);
51
52        println!(
53            "Running test set:\nparams_diff: {}\njob_context: {}",
54            serde_json::to_string(&self.params_diff).expect("Serialization to never fail"),
55            serde_json::to_string(&self.job_context).expect("Serialization to never fail")
56        );
57
58        if let Some(params_diff) = self.params_diff {
59            params_diff.apply(&mut cleaner.to_mut().params);
60        }
61
62        let (task_configs, expectations) = self.tests.clone().into_iter().map(|Test {task_config, expectation}| (task_config, expectation)).collect::<(Vec<_>, Vec<_>)>();
63
64        let job = Job {
65            context: &self.job_context,
66            cleaner: &cleaner,
67            #[cfg(feature = "cache")]
68            cache: &Default::default(),
69            lazy_task_configs: Box::new(task_configs.into_iter().map(|task_config| Ok(task_config.into())))
70        };
71
72        for (test, task_source, expectation) in self.tests.into_iter().zip(job).zip(expectations).map(|((x, y), z)| (x, y, z)) {
73            println!("Running test: {}", serde_json::to_string(&test).expect("Serialization to never fail"));
74            crate::task_state_view!(task_state, url = task_source.expect("Making TaskSource failed.").make().expect("Making Task failed.").r#do().expect("Task failed."));
75            assert!(expectation.satisfied_by(&task_state).is_ok_and(|x| x), "The expectation failed.\nExpectation: {expectation:?}\ntask_state: {task_state:?}");
76        }
77
78        println!();
79    }
80}
81
82/// An individual test.
83#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
84pub struct Test {
85    /// The [`TaskConfig`].
86    pub task_config: TaskConfig,
87    /// The expected result.
88    pub expectation: Condition
89}