pact_models/generators/
form_urlencoded.rs

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
14/// Implementation of a content type handler for FORM URLENCODED
15pub struct FormUrlEncodedHandler {
16  /// Query params to apply the generators to.
17  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(&param_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}