assert_tv/
set.rs

1use crate::TlsEnvGuard;
2use crate::{
3    initialize_tv_case_from_file, DynDeserializer, DynSerializer, TestMode, TestVectorFileFormat,
4};
5use std::fmt::{Debug, Formatter};
6use std::marker::PhantomData;
7use std::panic::Location;
8use std::path::PathBuf;
9
10pub trait TestVectorSet {
11    fn start<TV: TestVector>() -> Self;
12}
13
14pub struct TestValue<O> {
15    pub name: Option<String>,
16    pub description: Option<String>,
17    pub test_value_field_code_location: String,
18    pub serializer: Option<DynSerializer<O>>,
19    pub deserializer: Option<DynDeserializer<O>>,
20    pub compress: bool,
21    pub offload: bool,
22    pub _data_marker: PhantomData<O>,
23}
24
25impl<O> Debug for TestValue<O> {
26    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
27        f.debug_struct("TestValue")
28            .field("name", &self.name)
29            .field("description", &self.description)
30            .field(
31                "test_value_field_code_location",
32                &self.test_value_field_code_location,
33            )
34            .finish()
35    }
36}
37
38impl<O> TestValue<O> {
39    pub fn new(
40        name: Option<String>,
41        description: Option<String>,
42        code_location: String,
43        serializer: Option<DynSerializer<O>>,
44        deserializer: Option<DynDeserializer<O>>,
45        compress: bool,
46        offload: bool,
47    ) -> Self {
48        Self {
49            name,
50            description,
51            test_value_field_code_location: code_location,
52            serializer,
53            deserializer,
54            compress,
55            offload,
56            _data_marker: PhantomData,
57        }
58    }
59}
60
61pub trait TestVector {
62    fn initialize_test_vector<T: Into<PathBuf>>(
63        tv_file_path: T,
64        file_format: TestVectorFileFormat,
65        test_mode: TestMode,
66    ) -> TlsEnvGuard {
67        initialize_tv_case_from_file(tv_file_path, file_format, test_mode)
68            .expect("Failed to initialize test vector")
69    }
70
71    #[inline(always)]
72    fn initialize_values<T: TestVectorSet>() -> T
73    where
74        Self: Sized,
75    {
76        T::start::<Self>()
77    }
78
79    #[inline(always)]
80    #[track_caller]
81    fn expose_value<O>(test_vec_field: &TestValue<O>, mut observed_value: O) -> O {
82        let caller_location = Location::caller();
83        let caller_location = Some(format!("{}:{}", caller_location.file(), caller_location.line()));
84        let value = crate::process_next_entry(
85            crate::TestVectorEntryType::Const,
86            test_vec_field.description.clone(),
87            test_vec_field.name.clone(),
88            &observed_value,
89            caller_location,
90            Some(test_vec_field.test_value_field_code_location.clone()),
91            test_vec_field.serializer.as_ref().unwrap_or_else(|| panic!("Serializer was not provided for test field: {test_vec_field:?}")),
92            Some(
93                test_vec_field.deserializer.as_ref().unwrap_or_else(|| panic!("Deserializer was not provided for test field: {test_vec_field:?}")),
94            ),
95            test_vec_field.offload,
96        )
97            .expect("Error processing observed test vector value")
98            .expect("Unexpected error processing observed test vector const: no value was loaded");
99        value
100    }
101
102    #[inline(always)]
103    #[track_caller]
104    fn expose_mut_value<O>(test_vec_field: &TestValue<O>, observed_mut_value: &mut O) {
105        let caller_location = Location::caller();
106        let caller_location = Some(format!("{}:{}", caller_location.file(), caller_location.line()));
107        *observed_mut_value = crate::process_next_entry(
108            crate::TestVectorEntryType::Const,
109            test_vec_field.description.clone(),
110            test_vec_field.name.clone(),
111            observed_mut_value,
112            caller_location,
113            Some(test_vec_field.test_value_field_code_location.clone()),
114            test_vec_field.serializer.as_ref().unwrap_or_else(|| panic!("Serializer was not provided for test field: {test_vec_field:?}")),
115            Some(
116                test_vec_field.deserializer.as_ref().unwrap_or_else(|| panic!("Deserializer was not provided for test field: {test_vec_field:?}")),
117            ),
118            test_vec_field.offload,
119        )
120        .expect("Error processing observed test vector value")
121        .expect("Unexpected error processing observed test vector const: no value was loaded");
122    }
123
124    #[inline(always)]
125    #[track_caller]
126    fn check_value<O>(test_vec_field: &TestValue<O>, observed_value: &O) {
127        let caller_location = Location::caller();
128        let caller_location = Some(format!("{}:{}", caller_location.file(), caller_location.line()));
129        crate::process_next_entry(
130            crate::TestVectorEntryType::Output,
131            test_vec_field.description.clone(),
132            test_vec_field.name.clone(),
133            observed_value,
134            caller_location,
135            Some(test_vec_field.test_value_field_code_location.clone()),
136            test_vec_field.serializer.as_ref().unwrap_or_else(|| {
137                panic!(
138                    "Serializer was not provided for test field: {test_vec_field:?}"
139                )
140            }),
141            None,
142            test_vec_field.offload,
143        )
144        .expect("Error checking observed test vector value");
145    }
146
147    fn is_test_vector_enabled() -> bool {
148        true
149    }
150}
151
152#[derive(Clone, Debug)]
153pub struct TestVectorActive;
154
155impl TestVector for TestVectorActive {}
156
157#[derive(Clone, Debug)]
158pub struct TestVectorNOP;
159
160impl TestVector for TestVectorNOP {
161    #[inline(always)]
162    fn initialize_test_vector<T: Into<PathBuf>>(
163        _tv_file_path: T,
164        _file_format: TestVectorFileFormat,
165        _test_mode: TestMode,
166    ) -> TlsEnvGuard {
167        panic!(
168            "TestVectorNOP is used (by default) for when the code runs in production.\
169             No test vector was explicitly defined."
170        )
171    }
172
173    #[inline(always)]
174    fn expose_value<O>(_test_vec_field: &TestValue<O>, observed_value: O) -> O {
175        observed_value // return the value given
176    }
177
178    #[inline(always)]
179    fn expose_mut_value<O>(_test_vec_field: &TestValue<O>, _observed_mut_value: &mut O) {
180        // no impl does nothing
181    }
182
183    #[inline(always)]
184    fn check_value<O>(_test_vec_field: &TestValue<O>, _observed_value: &O) {
185        // no impl does nothing
186    }
187
188    #[inline(always)]
189    fn is_test_vector_enabled() -> bool {
190        false
191    }
192}
193
194#[cfg(test)]
195mod tests {
196    use crate::{initialize_tv_case_from_file, TestMode, TestVectorFileFormat};
197
198    #[test]
199    fn it_works() {
200        let _guard: crate::TlsEnvGuard =
201            initialize_tv_case_from_file("a", TestVectorFileFormat::Json, TestMode::Init).unwrap();
202    }
203}