api_testing_core/graphql/
vars.rs1use std::path::{Path, PathBuf};
2
3use anyhow::Context;
4
5use crate::Result;
6
7#[derive(Debug, Clone, PartialEq)]
8pub struct GraphqlVariablesFile {
9 pub path: PathBuf,
10 pub variables: serde_json::Value,
11 pub bumped_limit_fields: usize,
13}
14
15fn bump_limits_in_json(value: &mut serde_json::Value, min_limit: u64) -> usize {
16 match value {
17 serde_json::Value::Object(map) => {
18 let mut bumped = 0usize;
19 for (k, v) in map.iter_mut() {
20 if k == "limit"
21 && let serde_json::Value::Number(n) = v
22 && let Some(as_f64) = n.as_f64()
23 && as_f64 < (min_limit as f64)
24 {
25 *n = serde_json::Number::from(min_limit);
26 bumped += 1;
27 }
28 bumped += bump_limits_in_json(v, min_limit);
29 }
30 bumped
31 }
32 serde_json::Value::Array(values) => values
33 .iter_mut()
34 .map(|v| bump_limits_in_json(v, min_limit))
35 .sum(),
36 _ => 0,
37 }
38}
39
40impl GraphqlVariablesFile {
41 pub fn load(path: impl AsRef<Path>, min_limit: u64) -> Result<Self> {
42 let path = path.as_ref();
43 let bytes = std::fs::read(path)
44 .with_context(|| format!("read variables file: {}", path.display()))?;
45 let mut variables: serde_json::Value = serde_json::from_slice(&bytes)
46 .with_context(|| format!("Variables file is not valid JSON: {}", path.display()))?;
47
48 let bumped_limit_fields = if min_limit > 0 {
49 bump_limits_in_json(&mut variables, min_limit)
50 } else {
51 0
52 };
53
54 Ok(Self {
55 path: std::fs::canonicalize(path).unwrap_or_else(|_| path.to_path_buf()),
56 variables,
57 bumped_limit_fields,
58 })
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65 use pretty_assertions::assert_eq;
66
67 use tempfile::TempDir;
68
69 fn write(path: &Path, contents: &str) {
70 std::fs::create_dir_all(path.parent().expect("parent")).expect("mkdir");
71 std::fs::write(path, contents).expect("write");
72 }
73
74 #[test]
75 fn graphql_vars_bumps_nested_limit_fields() {
76 let tmp = TempDir::new().expect("tmp");
77 let vars_path = tmp.path().join("vars.json");
78 write(
79 &vars_path,
80 r#"{"limit":1,"nested":{"limit":2},"arr":[{"limit":3},{"limit":10}],"str":{"limit":"2"}}"#,
81 );
82
83 let vars = GraphqlVariablesFile::load(&vars_path, 5).expect("load");
84 assert_eq!(vars.bumped_limit_fields, 3);
85 assert_eq!(vars.variables["limit"], 5);
86 assert_eq!(vars.variables["nested"]["limit"], 5);
87 assert_eq!(vars.variables["arr"][0]["limit"], 5);
88 assert_eq!(vars.variables["arr"][1]["limit"], 10);
89 assert_eq!(vars.variables["str"]["limit"], "2");
90 }
91
92 #[test]
93 fn graphql_vars_invalid_json_includes_path() {
94 let tmp = TempDir::new().expect("tmp");
95 let vars_path = tmp.path().join("vars.json");
96 write(&vars_path, "{nope");
97
98 let err = GraphqlVariablesFile::load(&vars_path, 5).unwrap_err();
99 let msg = format!("{err:#}");
100 assert!(msg.contains("Variables file is not valid JSON"));
101 assert!(msg.contains(vars_path.to_string_lossy().as_ref()));
102 }
103}