schemadoc_diff/checker/
removed_response_property_check.rs1use std::cell::RefCell;
2
3use crate::checker::{ValidationIssue, ValidationIssuer};
4use crate::core::{DiffResult, MapDiff};
5use crate::path_pointer::{PathPointer, PointerAncestor};
6use crate::schema_diff::{
7 MayBeRefDiff, MediaTypeDiff, OperationDiff, ResponseDiff, SchemaDiff,
8};
9use crate::visitor::DiffVisitor;
10
11pub struct RemovedResponsePropertyCheck {
12 pointers: RefCell<Vec<PathPointer>>,
13}
14
15impl<'s> DiffVisitor<'s> for RemovedResponsePropertyCheck {
16 fn visit_operation(
17 &self,
18 pointer: &PathPointer,
19 _: &str,
20 _: &'s DiffResult<OperationDiff>,
21 ) -> bool {
22 pointer.is_updated()
23 }
24
25 fn visit_responses(
26 &self,
27 pointer: &PathPointer,
28 _: &'s DiffResult<MapDiff<MayBeRefDiff<ResponseDiff>>>,
29 ) -> bool {
30 pointer.is_updated()
31 }
32
33 fn visit_media_types(
34 &self,
35 pointer: &PathPointer,
36 _: &'s DiffResult<MapDiff<MediaTypeDiff>>,
37 ) -> bool {
38 pointer.is_updated()
39 }
40
41 fn visit_media_type(
42 &self,
43 pointer: &PathPointer,
44 _: &'s DiffResult<MediaTypeDiff>,
45 ) -> bool {
46 pointer.is_updated()
47 }
48
49 fn visit_schema(
50 &self,
51 pointer: &PathPointer,
52 _: &'s DiffResult<SchemaDiff>,
53 ) -> bool {
54 if pointer.ancestor(PointerAncestor::schema()).is_removed() {
55 return false;
56 }
57
58 if pointer
59 .ancestor(PointerAncestor::schema_property())
60 .is_removed()
61 {
62 self.pointers.borrow_mut().push(pointer.clone());
63 return false;
64 }
65
66 pointer.is_updated()
67 }
68}
69
70impl Default for RemovedResponsePropertyCheck {
71 fn default() -> Self {
72 Self {
73 pointers: RefCell::new(vec![]),
74 }
75 }
76}
77
78impl<'s> ValidationIssuer<'s> for RemovedResponsePropertyCheck {
79 fn id(&self) -> &'static str {
80 "removed-response-property"
81 }
82
83 fn visitor(&self) -> &dyn DiffVisitor<'s> {
84 self
85 }
86
87 fn issues(&self) -> Option<Vec<ValidationIssue>> {
88 let pointers = std::mem::take(&mut *self.pointers.borrow_mut());
89
90 let issues = pointers
91 .into_iter()
92 .map(|path| ValidationIssue::new(path, self.id(), true))
93 .collect::<Vec<ValidationIssue>>();
94
95 Some(issues)
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use crate::checker::removed_response_property_check::RemovedResponsePropertyCheck;
102 use crate::checker::ValidationIssuer;
103 use crate::get_schema_diff;
104 use crate::schema::HttpSchema;
105 use crate::schemas::openapi303::schema::OpenApi303;
106
107 #[test]
108 fn test_removed_response_property_check() {
109 let src_schema: HttpSchema = serde_json::from_str::<OpenApi303>(include_str!(
110 "../../data/checks/removed-response-property/schema-with-responses.json"
111 ))
112 .unwrap()
113 .into();
114
115 let tgt_schema: HttpSchema = serde_json::from_str::<OpenApi303>(include_str!(
116 "../../data/checks/removed-response-property/schema-with-responses-altered.json"
117 ))
118 .unwrap()
119 .into();
120
121 let diff = get_schema_diff(src_schema, tgt_schema);
122
123 let checker = RemovedResponsePropertyCheck::default();
124 crate::visitor::dispatch_visitor(diff.get().unwrap(), &checker);
125 let issues = checker.issues().unwrap();
126
127 assert_eq!(issues.len(), 3);
128 assert_eq!(
130 issues.get(0).unwrap().path.get_path(),
131 "paths//test/post/responses/200/content/application/json/schema/properties/description",
132 );
133 assert_eq!(
135 issues.get(1).unwrap().path.get_path(),
136 "paths//test/post/responses/200/content/application/json/schema/properties/settings/properties/s2",
137 );
138 assert_eq!(
140 issues.get(2).unwrap().path.get_path(),
141 "paths//test/put/responses/200/content/application/json/schema/properties/id",
142 );
143 }
144}