1
2use std::collections::HashMap;
3
4use serde_json::Value;
5use tracing::debug;
6use anyhow::{anyhow, Result};
7
8use crate::generators::{ContentTypeHandler, Generator, GeneratorTestMode, VariantMatcher, GenerateValue};
9use crate::path_exp::DocPath;
10use crate::bodies::OptionalBody;
11
12pub type QueryParams = Vec<(String, String)>;
13
14pub struct FormUrlEncodedHandler {
16 pub params: QueryParams
18}
19
20impl ContentTypeHandler<String> for FormUrlEncodedHandler {
21 fn process_body(
22 &mut self,
23 generators: &HashMap<DocPath, Generator>,
24 mode: &GeneratorTestMode,
25 context: &HashMap<&str, Value>,
26 matcher: &Box<dyn VariantMatcher + Send + Sync>
27 ) -> Result<OptionalBody, String> {
28 for (key, generator) in generators {
29 if generator.corresponds_to_mode(mode) {
30 debug!("Applying generator {:?} to key {}", generator, key);
31 self.apply_key(key, generator, context, matcher);
32 }
33 };
34 debug!("Query Params {:?}", self.params);
35 match serde_urlencoded::to_string(self.params.clone()) {
36 Ok(query_string) => Ok(OptionalBody::Present(query_string.into(), Some("application/x-www-form-urlencoded".into()), None)),
37 Err(err) => Err(anyhow!("Failed to convert query params to query string: {}", err).to_string())
38 }
39 }
40
41 fn apply_key(
42 &mut self,
43 key: &DocPath,
44 generator: &dyn GenerateValue<String>,
45 context: &HashMap<&str, Value>,
46 matcher: &Box<dyn VariantMatcher + Send + Sync>,
47 ) {
48 let mut map: HashMap<String, usize> = HashMap::new();
49 for (param_key, param_value) in self.params.iter_mut() {
50 let index = map.entry(param_key.clone()).or_insert(0);
51 if key.eq(&DocPath::root().join(param_key.clone())) || key.eq(&DocPath::root().join(param_key.clone()).join_index(*index)) {
52 return match generator.generate_value(¶m_value, context, matcher) {
53 Ok(new_value) => *param_value = new_value,
54 Err(_) => ()
55 }
56 }
57 *index += 1;
58 }
59 }
60}
61
62
63#[cfg(test)]
64mod tests {
65 use expectest::expect;
66 use expectest::prelude::*;
67 use test_log::test;
68 use maplit::hashmap;
69
70 use crate::generators::NoopVariantMatcher;
71
72 use super::*;
73 use super::Generator;
74
75 #[test]
76 fn applies_the_generator_to_a_valid_param() {
77 let params = vec!(("a".to_string(), "100".to_string()), ("b".to_string(), "B".to_string()), ("c".to_string(), "C".to_string()));
78 let mut form_urlencoded_handler = FormUrlEncodedHandler { params };
79
80 form_urlencoded_handler.apply_key(&DocPath::new_unwrap("$.b"), &Generator::RandomInt(0, 10), &hashmap!{}, &NoopVariantMatcher.boxed());
81
82 expect!(&form_urlencoded_handler.params[1].1).to_not(be_equal_to("B"));
83 }
84
85 #[test]
86 fn does_not_apply_the_generator_to_invalid_param() {
87 let params = vec!(("a".to_string(), "100".to_string()), ("b".to_string(), "B".to_string()), ("c".to_string(), "C".to_string()));
88 let mut form_urlencoded_handler = FormUrlEncodedHandler { params };
89
90 form_urlencoded_handler.apply_key(&DocPath::new_unwrap("$.d"), &Generator::RandomInt(0, 10), &hashmap!{}, &NoopVariantMatcher.boxed());
91
92 expect!(form_urlencoded_handler.params).to(be_equal_to(vec!(("a".to_string(), "100".to_string()), ("b".to_string(), "B".to_string()), ("c".to_string(), "C".to_string()))));
93 }
94
95 #[test]
96 fn applies_the_generator_to_a_list_item() {
97 let params = vec!(("a".to_string(), "100".to_string()), ("b".to_string(), "B1".to_string()), ("b".to_string(), "B2".to_string()), ("c".to_string(), "C".to_string()));
98 let mut form_urlencoded_handler = FormUrlEncodedHandler { params };
99
100 form_urlencoded_handler.apply_key(&DocPath::new_unwrap("$.b[1]"), &Generator::RandomInt(0, 10), &hashmap!{}, &NoopVariantMatcher.boxed());
101
102 expect!(&form_urlencoded_handler.params[2].1).to_not(be_equal_to("B2"));
103 }
104
105 #[test]
106 fn does_not_apply_the_generator_when_index_is_not_in_list() {
107 let params = vec!(("a".to_string(), "100".to_string()), ("b".to_string(), "B".to_string()), ("c".to_string(), "C".to_string()));
108 let mut form_urlencoded_handler = FormUrlEncodedHandler { params };
109
110 form_urlencoded_handler.apply_key(&DocPath::new_unwrap("$.b[3]"), &Generator::RandomInt(0, 10), &hashmap!{}, &NoopVariantMatcher.boxed());
111
112 expect!(form_urlencoded_handler.params).to(be_equal_to(vec!(("a".to_string(), "100".to_string()), ("b".to_string(), "B".to_string()), ("c".to_string(), "C".to_string()))));
113 }
114
115 #[test]
116 fn does_not_apply_the_generator_when_not_a_list() {
117 let params = vec!(("a".to_string(), "100".to_string()), ("b".to_string(), "B".to_string()), ("c".to_string(), "C".to_string()));
118 let mut form_urlencoded_handler = FormUrlEncodedHandler { params };
119
120 form_urlencoded_handler.apply_key(&DocPath::new_unwrap("$.a[0]"), &Generator::RandomInt(0, 10), &hashmap!{}, &NoopVariantMatcher.boxed());
121
122 expect!(&form_urlencoded_handler.params[0].1).to_not(be_equal_to("100"));
123 }
124
125 #[test]
126 fn applies_the_generator_to_the_root() {
127 let params = vec!(("a".to_string(), "100".to_string()), ("b".to_string(), "B".to_string()), ("c".to_string(), "C".to_string()));
128 let mut form_urlencoded_handler = FormUrlEncodedHandler { params };
129
130 form_urlencoded_handler.apply_key(&DocPath::root(), &Generator::RandomInt(0, 10), &hashmap!{}, &NoopVariantMatcher.boxed());
131
132 expect!(form_urlencoded_handler.params).to(be_equal_to(vec!(("a".to_string(), "100".to_string()), ("b".to_string(), "B".to_string()), ("c".to_string(), "C".to_string()))));
133 }
134
135 #[test]
136 fn does_not_apply_the_generator_to_long_path() {
137 let params = vec!(("a".to_string(), "100".to_string()), ("b".to_string(), "B".to_string()), ("c".to_string(), "C".to_string()));
138 let mut form_urlencoded_handler = FormUrlEncodedHandler { params };
139
140 form_urlencoded_handler.apply_key(&DocPath::new_unwrap("$.a[1].b['2']"), &Generator::RandomInt(0, 10), &hashmap!{}, &NoopVariantMatcher.boxed());
141
142 expect!(form_urlencoded_handler.params).to(be_equal_to(vec!(("a".to_string(), "100".to_string()), ("b".to_string(), "B".to_string()), ("c".to_string(), "C".to_string()))));
143 }
144
145 #[test]
146 fn applies_the_generator_to_all_map_entries() {
147 let params = vec!(("a".to_string(), "100".to_string()), ("b".to_string(), "B".to_string()), ("c".to_string(), "C".to_string()));
148 let mut form_urlencoded_handler = FormUrlEncodedHandler { params };
149
150 form_urlencoded_handler.apply_key(&DocPath::new_unwrap("$.*"), &Generator::RandomInt(0, 10), &hashmap!{}, &NoopVariantMatcher.boxed());
151
152 expect!(form_urlencoded_handler.params).to(be_equal_to(vec!(("a".to_string(), "100".to_string()), ("b".to_string(), "B".to_string()), ("c".to_string(), "C".to_string()))));
153 }
154
155 #[test]
156 fn applies_the_generator_to_all_list_items() {
157 let params = vec!(("a".to_string(), "100".to_string()), ("b".to_string(), "B".to_string()), ("c".to_string(), "C".to_string()));
158 let mut form_urlencoded_handler = FormUrlEncodedHandler { params };
159
160 form_urlencoded_handler.apply_key(&DocPath::new_unwrap("$[*]"), &Generator::RandomInt(0, 10), &hashmap!{}, &NoopVariantMatcher.boxed());
161
162 expect!(form_urlencoded_handler.params).to(be_equal_to(vec!(("a".to_string(), "100".to_string()), ("b".to_string(), "B".to_string()), ("c".to_string(), "C".to_string()))));
163 }
164
165 #[test]
166 fn applies_the_generator_to_long_path_with_wildcard() {
167 let params = vec!(("a".to_string(), "100".to_string()), ("b".to_string(), "B".to_string()), ("c".to_string(), "C".to_string()));
168 let mut form_urlencoded_handler = FormUrlEncodedHandler { params };
169
170 form_urlencoded_handler.apply_key(&DocPath::new_unwrap("$.*[1].b[*]"), &Generator::RandomInt(3, 10), &hashmap!{}, &NoopVariantMatcher.boxed());
171
172 expect!(form_urlencoded_handler.params).to(be_equal_to(vec!(("a".to_string(), "100".to_string()), ("b".to_string(), "B".to_string()), ("c".to_string(), "C".to_string()))));
173 }
174}