graphql_tools/validation/rules/
no_unused_fragments.rs1use super::ValidationRule;
2use crate::ast::{visit_document, OperationVisitor, OperationVisitorContext};
3use crate::static_graphql::query::*;
4use crate::validation::utils::{ValidationError, ValidationErrorContext};
5
6pub struct NoUnusedFragments<'a> {
13 fragments_in_use: Vec<&'a str>,
14}
15
16impl<'a> OperationVisitor<'a, ValidationErrorContext> for NoUnusedFragments<'a> {
17 fn enter_fragment_spread(
18 &mut self,
19 _: &mut OperationVisitorContext,
20 _: &mut ValidationErrorContext,
21 fragment_spread: &'a FragmentSpread,
22 ) {
23 self.fragments_in_use
24 .push(fragment_spread.fragment_name.as_str());
25 }
26
27 fn leave_document(
28 &mut self,
29 visitor_context: &mut OperationVisitorContext,
30 user_context: &mut ValidationErrorContext,
31 _document: &Document,
32 ) {
33 visitor_context
34 .known_fragments
35 .iter()
36 .filter_map(|(fragment_name, _fragment)| {
37 if !self.fragments_in_use.contains(fragment_name) {
38 Some(fragment_name)
39 } else {
40 None
41 }
42 })
43 .for_each(|unused_fragment_name| {
44 user_context.report_error(ValidationError {
45 error_code: self.error_code(),
46 locations: vec![],
47 message: format!("Fragment \"{}\" is never used.", unused_fragment_name),
48 });
49 });
50 }
51}
52
53impl<'a> Default for NoUnusedFragments<'a> {
54 fn default() -> Self {
55 Self::new()
56 }
57}
58
59impl<'a> NoUnusedFragments<'a> {
60 pub fn new() -> Self {
61 NoUnusedFragments {
62 fragments_in_use: Vec::new(),
63 }
64 }
65}
66
67impl<'n> ValidationRule for NoUnusedFragments<'n> {
68 fn error_code<'a>(&self) -> &'a str {
69 "NoUnusedFragments"
70 }
71
72 fn validate(
73 &self,
74 ctx: &mut OperationVisitorContext,
75 error_collector: &mut ValidationErrorContext,
76 ) {
77 visit_document(
78 &mut NoUnusedFragments::new(),
79 ctx.operation,
80 ctx,
81 error_collector,
82 );
83 }
84}
85
86#[test]
87fn all_fragment_names_are_used() {
88 use crate::validation::test_utils::*;
89
90 let mut plan = create_plan_from_rule(Box::new(NoUnusedFragments::new()));
91 let errors = test_operation_with_schema(
92 "{
93 human(id: 4) {
94 ...HumanFields1
95 ... on Human {
96 ...HumanFields2
97 }
98 }
99 }
100 fragment HumanFields1 on Human {
101 name
102 ...HumanFields3
103 }
104 fragment HumanFields2 on Human {
105 name
106 }
107 fragment HumanFields3 on Human {
108 name
109 }",
110 TEST_SCHEMA,
111 &mut plan,
112 );
113
114 assert_eq!(get_messages(&errors).len(), 0);
115}
116
117#[test]
118fn all_fragment_names_are_used_by_multiple_operations() {
119 use crate::validation::test_utils::*;
120
121 let mut plan = create_plan_from_rule(Box::new(NoUnusedFragments::new()));
122 let errors = test_operation_with_schema(
123 "query Foo {
124 human(id: 4) {
125 ...HumanFields1
126 }
127 }
128 query Bar {
129 human(id: 4) {
130 ...HumanFields2
131 }
132 }
133 fragment HumanFields1 on Human {
134 name
135 ...HumanFields3
136 }
137 fragment HumanFields2 on Human {
138 name
139 }
140 fragment HumanFields3 on Human {
141 name
142 }
143 ",
144 TEST_SCHEMA,
145 &mut plan,
146 );
147
148 assert_eq!(get_messages(&errors).len(), 0);
149}
150
151#[test]
152fn contains_unknown_fragments() {
153 use crate::validation::test_utils::*;
154
155 let mut plan = create_plan_from_rule(Box::new(NoUnusedFragments::new()));
156 let errors = test_operation_with_schema(
157 "query Foo {
158 human(id: 4) {
159 ...HumanFields1
160 }
161 }
162 query Bar {
163 human(id: 4) {
164 ...HumanFields2
165 }
166 }
167 fragment HumanFields1 on Human {
168 name
169 ...HumanFields3
170 }
171 fragment HumanFields2 on Human {
172 name
173 }
174 fragment HumanFields3 on Human {
175 name
176 }
177 fragment Unused1 on Human {
178 name
179 }
180 fragment Unused2 on Human {
181 name
182 }
183 ",
184 TEST_SCHEMA,
185 &mut plan,
186 );
187
188 let messages = get_messages(&errors);
189 assert_eq!(messages.len(), 2);
190}
191
192#[test]
194#[ignore = "Fix this one :( It's not working"]
195fn contains_unknown_fragments_with_ref_cycle() {
196 use crate::validation::test_utils::*;
197
198 let mut plan = create_plan_from_rule(Box::new(NoUnusedFragments::new()));
199 let errors = test_operation_with_schema(
200 "query Foo {
201 human(id: 4) {
202 ...HumanFields1
203 }
204 }
205 query Bar {
206 human(id: 4) {
207 ...HumanFields2
208 }
209 }
210 fragment HumanFields1 on Human {
211 name
212 ...HumanFields3
213 }
214 fragment HumanFields2 on Human {
215 name
216 }
217 fragment HumanFields3 on Human {
218 name
219 }
220 fragment Unused1 on Human {
221 name
222 ...Unused2
223 }
224 fragment Unused2 on Human {
225 name
226 ...Unused1
227 }
228 ",
229 TEST_SCHEMA,
230 &mut plan,
231 );
232
233 let messages = get_messages(&errors);
234 assert_eq!(messages.len(), 2);
235 assert_eq!(
236 messages,
237 vec![
238 "Fragment \"Unused1\" is never used.",
239 "Fragment \"Unused2\" is never used."
240 ]
241 );
242}
243
244#[test]
245fn contains_unknown_and_undef_fragments() {
246 use crate::validation::test_utils::*;
247
248 let mut plan = create_plan_from_rule(Box::new(NoUnusedFragments::new()));
249 let errors = test_operation_with_schema(
250 "query Foo {
251 human(id: 4) {
252 ...bar
253 }
254 }
255 fragment foo on Human {
256 name
257 }
258 ",
259 TEST_SCHEMA,
260 &mut plan,
261 );
262
263 let messages = get_messages(&errors);
264 assert_eq!(messages.len(), 1);
265 assert_eq!(messages, vec!["Fragment \"foo\" is never used.",]);
266}