postman_collection/
lib.rs1use std::{fs::File, io::Read, path::Path};
2
3pub use errors::{Result, ResultExt};
4use serde::{Deserialize, Serialize};
5
6pub mod v1_0_0;
7pub mod v2_0_0;
8pub mod v2_1_0;
9
10const MINIMUM_POSTMAN_COLLECTION_VERSION: &str = ">= 1.0.0";
11
12pub mod errors {
14 use error_chain::error_chain;
15
16 use crate::MINIMUM_POSTMAN_COLLECTION_VERSION;
17
18 error_chain! {
19 foreign_links {
20 Io(::std::io::Error);
21 Yaml(::serde_yaml::Error);
22 Serialize(::serde_json::Error);
23 SemVerError(::semver::Error);
24 }
25
26 errors {
27 UnsupportedSpecFileVersion(version: ::semver::Version) {
28 description("Unsupported Postman Collection file version")
29 display("Unsupported Postman Collection file version ({}). Expected {}", version, MINIMUM_POSTMAN_COLLECTION_VERSION)
30 }
31 }
32 }
33}
34
35#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
37#[serde(untagged)]
38pub enum PostmanCollection {
39 #[allow(non_camel_case_types)]
45 V1_0_0(v1_0_0::Spec),
46 #[allow(non_camel_case_types)]
52 V2_0_0(v2_0_0::Spec),
53 #[allow(non_camel_case_types)]
59 V2_1_0(v2_1_0::Spec),
60}
61
62pub fn from_path<P>(path: P) -> errors::Result<PostmanCollection>
64where
65 P: AsRef<Path>,
66{
67 from_reader(File::open(path)?)
68}
69
70pub fn from_reader<R>(read: R) -> errors::Result<PostmanCollection>
72where
73 R: Read,
74{
75 Ok(serde_yaml::from_reader::<R, PostmanCollection>(read)?)
76}
77
78pub fn to_yaml(spec: &PostmanCollection) -> errors::Result<String> {
80 Ok(serde_yaml::to_string(spec)?)
81}
82
83pub fn to_json(spec: &PostmanCollection) -> errors::Result<String> {
85 Ok(serde_json::to_string_pretty(spec)?)
86}
87
88#[cfg(test)]
89mod tests {
90 use std::fs::File;
91 use std::io::Write;
92
93 use glob::glob;
94
95 use super::*;
96
97 fn read_file<P>(path: P) -> String
99 where
100 P: AsRef<Path>,
101 {
102 let mut f = File::open(path).unwrap();
103 let mut content = String::new();
104 f.read_to_string(&mut content).unwrap();
105 content
106 }
107
108 fn write_to_file<P>(path: P, filename: &str, data: &str)
110 where
111 P: AsRef<Path> + std::fmt::Debug,
112 {
113 println!(" Saving string to {:?}...", path);
114 std::fs::create_dir_all(&path).unwrap();
115 let full_filename = path.as_ref().to_path_buf().join(filename);
116 let mut f = File::create(&full_filename).unwrap();
117 f.write_all(data.as_bytes()).unwrap();
118 }
119
120 fn convert_yaml_str_to_json(yaml_str: &str) -> String {
122 let yaml: serde_yaml::Value = serde_yaml::from_str(yaml_str).unwrap();
123 let json: serde_json::Value = serde_yaml::from_value(yaml).unwrap();
124 serde_json::to_string_pretty(&json).unwrap()
125 }
126
127 fn compare_spec_through_json(
139 input_file: &Path,
140 save_path_base: &Path,
141 ) -> (String, String, String) {
142 let spec_yaml_str = read_file(&input_file);
147 let spec_json_str = convert_yaml_str_to_json(&spec_yaml_str);
149
150 let parsed_spec = from_path(&input_file).unwrap();
155 let parsed_spec_json: serde_json::Value = serde_json::to_value(parsed_spec).unwrap();
157 let parsed_spec_json_str: String = serde_json::to_string_pretty(&parsed_spec_json).unwrap();
159
160 let api_filename = input_file
162 .file_name()
163 .unwrap()
164 .to_str()
165 .unwrap()
166 .replace(".yaml", ".json");
167
168 let mut save_path = save_path_base.to_path_buf();
169 save_path.push("yaml_to_json");
170 write_to_file(&save_path, &api_filename, &spec_json_str);
171
172 let mut save_path = save_path_base.to_path_buf();
173 save_path.push("yaml_to_spec_to_json");
174 write_to_file(&save_path, &api_filename, &parsed_spec_json_str);
175
176 (api_filename, parsed_spec_json_str, spec_json_str)
178 }
179
180 #[test]
182 fn can_deserialize() {
183 for entry in glob("/tests/fixtures/collection/*.json").expect("Failed to read glob pattern")
184 {
185 let entry = entry.unwrap();
186 let path = entry.as_path();
187 println!("Testing if {:?} is deserializable", path);
189 from_path(path).unwrap();
190 }
191 }
192
193 #[test]
194 fn can_deserialize_and_reserialize() {
195 let save_path_base: std::path::PathBuf =
196 ["target", "tests", "can_deserialize_and_reserialize"]
197 .iter()
198 .collect();
199 let mut invalid_diffs = Vec::new();
200
201 for entry in glob("/tests/fixtures/collection/*.json").expect("Failed to read glob pattern")
202 {
203 let entry = entry.unwrap();
204 let path = entry.as_path();
205
206 println!("Testing if {:?} is deserializable", path);
207
208 let (api_filename, parsed_spec_json_str, spec_json_str) =
209 compare_spec_through_json(path, &save_path_base);
210
211 if parsed_spec_json_str != spec_json_str {
212 invalid_diffs.push((api_filename, parsed_spec_json_str, spec_json_str));
213 }
214 }
215
216 for invalid_diff in &invalid_diffs {
217 println!("File {} failed JSON comparison!", invalid_diff.0);
218 }
219 assert_eq!(invalid_diffs.len(), 0);
220 }
221}