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 }
177
178 #[inline(always)]
179 fn expose_mut_value<O>(_test_vec_field: &TestValue<O>, _observed_mut_value: &mut O) {
180 }
182
183 #[inline(always)]
184 fn check_value<O>(_test_vec_field: &TestValue<O>, _observed_value: &O) {
185 }
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}