schemadoc_diff/checker/
added_required_parameter_check.rs

1use std::cell::RefCell;
2
3use crate::checker::{ValidationIssue, ValidationIssuer};
4use crate::core::{DiffResult, VecDiff};
5use crate::path_pointer::PathPointer;
6use crate::schema_diff::{MayBeRefDiff, OperationDiff, ParameterDiff};
7
8use crate::visitor::DiffVisitor;
9
10pub struct AddedRequiredParameterCheck {
11    pointers: RefCell<Vec<PathPointer>>,
12}
13
14impl<'s> DiffVisitor<'s> for AddedRequiredParameterCheck {
15    fn visit_operation(
16        &self,
17        pointer: &PathPointer,
18        _: &str,
19        _: &'s DiffResult<OperationDiff>,
20    ) -> bool {
21        pointer.is_updated()
22    }
23
24    fn visit_parameters(
25        &self,
26        pointer: &PathPointer,
27        _: &'s DiffResult<VecDiff<MayBeRefDiff<ParameterDiff>>>,
28    ) -> bool {
29        pointer.is_updated()
30    }
31
32    fn visit_parameter(
33        &self,
34        pointer: &PathPointer,
35        parameter_diff_result: &'s DiffResult<ParameterDiff>,
36    ) -> bool {
37        // Parameter Must be UPSERTED
38        if !pointer.is_upserted() {
39            return false;
40        }
41
42        if let Some(parameter_diff) = parameter_diff_result.get() {
43            if parameter_diff.required.is_upserted() {
44                if let Some(required) = parameter_diff.required.get() {
45                    if *required {
46                        self.pointers.borrow_mut().push(pointer.clone())
47                    }
48                }
49            }
50        }
51
52        false
53    }
54}
55
56impl Default for AddedRequiredParameterCheck {
57    fn default() -> Self {
58        AddedRequiredParameterCheck {
59            pointers: RefCell::new(vec![]),
60        }
61    }
62}
63
64impl<'s> ValidationIssuer<'s> for AddedRequiredParameterCheck {
65    fn id(&self) -> &'static str {
66        "added-required-parameter"
67    }
68
69    fn visitor(&self) -> &dyn DiffVisitor<'s> {
70        self
71    }
72
73    fn issues(&self) -> Option<Vec<ValidationIssue>> {
74        let pointers = std::mem::take(&mut *self.pointers.borrow_mut());
75
76        let issues = pointers
77            .into_iter()
78            .map(|path| ValidationIssue::new(path, self.id(), true))
79            .collect::<Vec<ValidationIssue>>();
80
81        Some(issues)
82    }
83}
84
85#[cfg(test)]
86mod tests {
87    use crate::checker::added_required_parameter_check::AddedRequiredParameterCheck;
88    use crate::checker::ValidationIssuer;
89    use crate::get_schema_diff;
90    use crate::schema::HttpSchema;
91    use crate::schemas::openapi303::schema::OpenApi303;
92
93    #[test]
94    fn test_added_required_parameter_check() {
95        let src_schema: HttpSchema = serde_json::from_str::<OpenApi303>(include_str!(
96            "../../data/checks/added-required-parameter/schema-with-parameters.json"
97        ))
98        .unwrap()
99        .into();
100
101        let tgt_schema: HttpSchema = serde_json::from_str::<OpenApi303>(include_str!(
102            "../../data/checks/added-required-parameter/schema-with-update-parameters.json"
103        ))
104        .unwrap()
105        .into();
106
107        let diff = get_schema_diff(src_schema, tgt_schema);
108
109        let checker = AddedRequiredParameterCheck::default();
110        crate::visitor::dispatch_visitor(diff.get().unwrap(), &checker);
111        let issues = checker.issues().unwrap();
112
113        assert_eq!(issues.len(), 2);
114        // `param4defaultToUpdate` updated to required=true
115        assert_eq!(
116            issues.get(0).unwrap().path.get_path(),
117            "paths//test/get/parameters/1",
118        );
119        // `param6newRequired` added with required=true
120        assert_eq!(
121            issues.get(1).unwrap().path.get_path(),
122            "paths//test/get/parameters/5",
123        );
124    }
125}