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