anicca/diff/
mod.rs

1pub(crate) mod common;
2pub(crate) mod content;
3pub(crate) mod media_type;
4pub(crate) mod operations;
5pub(crate) mod parameter;
6pub(crate) mod parameters;
7pub(crate) mod path_items;
8pub(crate) mod paths;
9pub(crate) mod request_body;
10pub(crate) mod response;
11pub(crate) mod responses;
12pub(crate) mod schema;
13
14use crate::openapi::OpenAPI;
15use common::StringDiff;
16use paths::PathsDiff;
17use serde::Serialize;
18use std::path::PathBuf;
19use thiserror::Error;
20
21/// DiffError enumerates all possible errors returned by this library.
22#[derive(Error, Debug)]
23pub enum DiffError {
24    /// Represents an unsupported feature by this library.
25    #[error("Unsupported feature: {0}")]
26    UnsupportedFeature(String),
27
28    /// Represents all cases of `std::io::Error`.
29    #[error(transparent)]
30    IOError(#[from] std::io::Error),
31
32    /// Represents all cases of `serde_json::Error`.
33    #[error(transparent)]
34    SerdeError(#[from] serde_yaml::Error),
35}
36
37#[derive(Debug, Serialize)]
38pub struct Diff {
39    pub version: Option<StringDiff>,
40    pub paths: PathsDiff,
41}
42
43pub fn diff_files(base: PathBuf, head: PathBuf) -> Result<Diff, DiffError> {
44    let base_contents = std::fs::read_to_string(base)?;
45    let head_contents = std::fs::read_to_string(head)?;
46    let base_openapi: OpenAPI = serde_yaml::from_str(&base_contents)?;
47    let head_openapi: OpenAPI = serde_yaml::from_str(&head_contents)?;
48    diff(base_openapi, head_openapi)
49}
50
51pub fn diff(base: OpenAPI, head: OpenAPI) -> Result<Diff, DiffError> {
52    let version_diff = StringDiff::from_strings(base.openapi, head.openapi);
53    let paths_diff = PathsDiff::from_paths(&base.paths, &head.paths)?;
54    Ok(Diff {
55        version: version_diff,
56        paths: paths_diff,
57    })
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn from_json_files() {
66        let diff = diff_files(
67            PathBuf::from("fixtures/pet-store.json"),
68            PathBuf::from("fixtures/pet-store-changed.json"),
69        )
70        .expect("Failed to diff JSON");
71
72        let version_change = diff.version.unwrap();
73
74        assert_eq!("3.0.0", version_change.from);
75        assert_eq!("3.1.0", version_change.to);
76    }
77
78    #[test]
79    fn from_yaml_files() {
80        let diff = diff_files(
81            PathBuf::from("fixtures/pet-store.yaml"),
82            PathBuf::from("fixtures/pet-store-changed.yaml"),
83        )
84        .expect("Failed to diff JSON");
85
86        let version_change = diff.version.unwrap();
87
88        assert_eq!("3.0.0", version_change.from);
89        assert_eq!("3.1.0", version_change.to);
90    }
91
92    #[test]
93    fn openapi_version_change() {
94        let mut base = OpenAPI::default();
95        base.openapi = String::from("3.0.0");
96        let mut head = OpenAPI::default();
97        head.openapi = String::from("4.0.0");
98
99        let result = diff(base, head);
100        let diff = result.expect("Failed to diff");
101
102        let version_change = diff.version.unwrap();
103
104        assert_eq!("3.0.0", version_change.from);
105        assert_eq!("4.0.0", version_change.to);
106    }
107}