schemadoc_diff/checker/
removed_schema_enum_value_check.rs

1use std::cell::RefCell;
2
3use crate::core::{DiffResult, MapDiff, VecDiff};
4use crate::path_pointer::PathPointer;
5
6use crate::checker::{ValidationIssue, ValidationIssuer};
7use crate::schema_diff::{
8    MayBeRefDiff, MediaTypeDiff, OperationDiff, ParameterDiff,
9    RequestBodyDiff, ResponseDiff, SchemaDiff,
10};
11use crate::visitor::DiffVisitor;
12
13pub struct RemovedSchemaEnumValueCheck {
14    pointers: RefCell<Vec<PathPointer>>,
15}
16
17impl<'s> DiffVisitor<'s> for RemovedSchemaEnumValueCheck {
18    fn visit_operation(
19        &self,
20        pointer: &PathPointer,
21        _: &str,
22        _: &'s DiffResult<OperationDiff>,
23    ) -> bool {
24        pointer.is_updated()
25    }
26
27    fn visit_request_body(
28        &self,
29        pointer: &PathPointer,
30        _: &'s DiffResult<RequestBodyDiff>,
31    ) -> bool {
32        pointer.is_updated()
33    }
34
35    fn visit_responses(
36        &self,
37        pointer: &PathPointer,
38        _: &'s DiffResult<MapDiff<MayBeRefDiff<ResponseDiff>>>,
39    ) -> bool {
40        pointer.is_updated()
41    }
42
43    fn visit_media_types(
44        &self,
45        pointer: &PathPointer,
46        _: &'s DiffResult<MapDiff<MediaTypeDiff>>,
47    ) -> bool {
48        pointer.is_updated()
49    }
50
51    fn visit_media_type(
52        &self,
53        pointer: &PathPointer,
54        _: &'s DiffResult<MediaTypeDiff>,
55    ) -> bool {
56        pointer.is_updated()
57    }
58
59    fn visit_parameters(
60        &self,
61        pointer: &PathPointer,
62        _: &'s DiffResult<VecDiff<MayBeRefDiff<ParameterDiff>>>,
63    ) -> bool {
64        pointer.is_updated()
65    }
66
67    fn visit_parameter(
68        &self,
69        pointer: &PathPointer,
70        _: &'s DiffResult<ParameterDiff>,
71    ) -> bool {
72        pointer.is_updated()
73    }
74
75    fn visit_schema(
76        &self,
77        pointer: &PathPointer,
78        schema_diff_result: &'s DiffResult<SchemaDiff>,
79    ) -> bool {
80        if !pointer.is_updated() {
81            return false;
82        }
83
84        let Some(schema) = schema_diff_result.get() else {
85            return false;
86        };
87
88        if schema.r#enum.is_updated() {
89            let has_removed = match schema.r#enum.get() {
90                None => false,
91                Some(values) => values.iter().any(|v| v.is_removed()),
92            };
93            if has_removed {
94                self.pointers.borrow_mut().push(pointer.add_component(
95                    &schema.r#enum,
96                    Some("enum"),
97                    None,
98                ))
99            }
100        }
101
102        true
103    }
104}
105
106impl Default for RemovedSchemaEnumValueCheck {
107    fn default() -> Self {
108        Self {
109            pointers: RefCell::new(vec![]),
110        }
111    }
112}
113
114impl<'s> ValidationIssuer<'s> for RemovedSchemaEnumValueCheck {
115    fn id(&self) -> &'static str {
116        "removed-schema-enum-value"
117    }
118
119    fn visitor(&self) -> &dyn DiffVisitor<'s> {
120        self
121    }
122
123    fn issues(&self) -> Option<Vec<ValidationIssue>> {
124        let pointers = std::mem::take(&mut *self.pointers.borrow_mut());
125
126        let issues = pointers
127            .into_iter()
128            .map(|path| ValidationIssue::new(path, self.id(), true))
129            .collect::<Vec<ValidationIssue>>();
130
131        Some(issues)
132    }
133}
134
135#[cfg(test)]
136mod tests {
137    use crate::checker::removed_schema_enum_value_check::RemovedSchemaEnumValueCheck;
138    use crate::checker::ValidationIssuer;
139    use crate::get_schema_diff;
140    use crate::schema::HttpSchema;
141    use crate::schemas::openapi303::schema::OpenApi303;
142
143    #[test]
144    fn test_removed_schema_enum_value_check() {
145        let src_schema: HttpSchema = serde_json::from_str::<OpenApi303>(include_str!(
146            "../../data/checks/removed-schema-enum-value/schema-with-enums.json"
147        ))
148            .unwrap()
149            .into();
150
151        let tgt_schema: HttpSchema = serde_json::from_str::<OpenApi303>(include_str!(
152            "../../data/checks/removed-schema-enum-value/schema-with-enums-altered.json"
153        ))
154            .unwrap()
155            .into();
156
157        let diff = get_schema_diff(src_schema, tgt_schema);
158
159        let checker = RemovedSchemaEnumValueCheck::default();
160        crate::visitor::dispatch_visitor(diff.get().unwrap(), &checker);
161        let issues = checker.issues().unwrap();
162
163        assert_eq!(issues.len(), 2);
164        assert_eq!(
165            issues.get(0).unwrap().path.get_path(),
166            "paths//test/post/requestBody/content/application/json/schema/enum",
167        );
168        assert_eq!(
169            issues.get(1).unwrap().path.get_path(),
170            "paths//test/post/responses/200/content/application/json/schema/properties/prop1/enum",
171        );
172    }
173}