Skip to content

Commit 251f957

Browse files
committed
Add directive tests, fix some bugs
1 parent 478c7b7 commit 251f957

File tree

4 files changed

+278
-8
lines changed

4 files changed

+278
-8
lines changed

src/executor_tests/directives.rs

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
use std::collections::HashMap;
2+
3+
use value::Value;
4+
use ast::InputValue;
5+
use schema::model::RootNode;
6+
7+
struct TestType;
8+
9+
graphql_object!(TestType: () |&self| {
10+
field a() -> &str {
11+
"a"
12+
}
13+
14+
field b() -> &str {
15+
"b"
16+
}
17+
});
18+
19+
fn run_variable_query<F>(query: &str, vars: HashMap<String, InputValue>, f: F)
20+
where F: Fn(&HashMap<String, Value>) -> ()
21+
{
22+
let schema = RootNode::new(TestType, ());
23+
24+
let (result, errs) = ::execute(query, None, &schema, &vars, &())
25+
.expect("Execution failed");
26+
27+
assert_eq!(errs, []);
28+
29+
println!("Result: {:?}", result);
30+
31+
let obj = result.as_object_value().expect("Result is not an object");
32+
33+
f(obj);
34+
}
35+
36+
fn run_query<F>(query: &str, f: F)
37+
where F: Fn(&HashMap<String, Value>) -> ()
38+
{
39+
run_variable_query(query, HashMap::new(), f);
40+
}
41+
42+
#[test]
43+
fn scalar_include_true() {
44+
run_query(
45+
"{ a, b @include(if: true) }",
46+
|result| {
47+
assert_eq!(result.get("a"), Some(&Value::string("a")));
48+
assert_eq!(result.get("b"), Some(&Value::string("b")));
49+
});
50+
}
51+
52+
#[test]
53+
fn scalar_include_false() {
54+
run_query(
55+
"{ a, b @include(if: false) }",
56+
|result| {
57+
assert_eq!(result.get("a"), Some(&Value::string("a")));
58+
assert_eq!(result.get("b"), None);
59+
});
60+
}
61+
62+
#[test]
63+
fn scalar_skip_false() {
64+
run_query(
65+
"{ a, b @skip(if: false) }",
66+
|result| {
67+
assert_eq!(result.get("a"), Some(&Value::string("a")));
68+
assert_eq!(result.get("b"), Some(&Value::string("b")));
69+
});
70+
}
71+
72+
#[test]
73+
fn scalar_skip_true() {
74+
run_query(
75+
"{ a, b @skip(if: true) }",
76+
|result| {
77+
assert_eq!(result.get("a"), Some(&Value::string("a")));
78+
assert_eq!(result.get("b"), None);
79+
});
80+
}
81+
82+
83+
84+
85+
#[test]
86+
fn fragment_spread_include_true() {
87+
run_query(
88+
"{ a, ...Frag @include(if: true) } fragment Frag on TestType { b }",
89+
|result| {
90+
assert_eq!(result.get("a"), Some(&Value::string("a")));
91+
assert_eq!(result.get("b"), Some(&Value::string("b")));
92+
});
93+
}
94+
95+
#[test]
96+
fn fragment_spread_include_false() {
97+
run_query(
98+
"{ a, ...Frag @include(if: false) } fragment Frag on TestType { b }",
99+
|result| {
100+
assert_eq!(result.get("a"), Some(&Value::string("a")));
101+
assert_eq!(result.get("b"), None);
102+
});
103+
}
104+
105+
#[test]
106+
fn fragment_spread_skip_false() {
107+
run_query(
108+
"{ a, ...Frag @skip(if: false) } fragment Frag on TestType { b }",
109+
|result| {
110+
assert_eq!(result.get("a"), Some(&Value::string("a")));
111+
assert_eq!(result.get("b"), Some(&Value::string("b")));
112+
});
113+
}
114+
115+
#[test]
116+
fn fragment_spread_skip_true() {
117+
run_query(
118+
"{ a, ...Frag @skip(if: true) } fragment Frag on TestType { b }",
119+
|result| {
120+
assert_eq!(result.get("a"), Some(&Value::string("a")));
121+
assert_eq!(result.get("b"), None);
122+
});
123+
}
124+
125+
126+
127+
#[test]
128+
fn inline_fragment_include_true() {
129+
run_query(
130+
"{ a, ... on TestType @include(if: true) { b } }",
131+
|result| {
132+
assert_eq!(result.get("a"), Some(&Value::string("a")));
133+
assert_eq!(result.get("b"), Some(&Value::string("b")));
134+
});
135+
}
136+
137+
#[test]
138+
fn inline_fragment_include_false() {
139+
run_query(
140+
"{ a, ... on TestType @include(if: false) { b } }",
141+
|result| {
142+
assert_eq!(result.get("a"), Some(&Value::string("a")));
143+
assert_eq!(result.get("b"), None);
144+
});
145+
}
146+
147+
#[test]
148+
fn inline_fragment_skip_false() {
149+
run_query(
150+
"{ a, ... on TestType @skip(if: false) { b } }",
151+
|result| {
152+
assert_eq!(result.get("a"), Some(&Value::string("a")));
153+
assert_eq!(result.get("b"), Some(&Value::string("b")));
154+
});
155+
}
156+
157+
#[test]
158+
fn inline_fragment_skip_true() {
159+
run_query(
160+
"{ a, ... on TestType @skip(if: true) { b } }",
161+
|result| {
162+
assert_eq!(result.get("a"), Some(&Value::string("a")));
163+
assert_eq!(result.get("b"), None);
164+
});
165+
}
166+
167+
168+
169+
170+
#[test]
171+
fn anonymous_inline_fragment_include_true() {
172+
run_query(
173+
"{ a, ... @include(if: true) { b } }",
174+
|result| {
175+
assert_eq!(result.get("a"), Some(&Value::string("a")));
176+
assert_eq!(result.get("b"), Some(&Value::string("b")));
177+
});
178+
}
179+
180+
#[test]
181+
fn anonymous_inline_fragment_include_false() {
182+
run_query(
183+
"{ a, ... @include(if: false) { b } }",
184+
|result| {
185+
assert_eq!(result.get("a"), Some(&Value::string("a")));
186+
assert_eq!(result.get("b"), None);
187+
});
188+
}
189+
190+
#[test]
191+
fn anonymous_inline_fragment_skip_false() {
192+
run_query(
193+
"{ a, ... @skip(if: false) { b } }",
194+
|result| {
195+
assert_eq!(result.get("a"), Some(&Value::string("a")));
196+
assert_eq!(result.get("b"), Some(&Value::string("b")));
197+
});
198+
}
199+
200+
#[test]
201+
fn anonymous_inline_fragment_skip_true() {
202+
run_query(
203+
"{ a, ... @skip(if: true) { b } }",
204+
|result| {
205+
assert_eq!(result.get("a"), Some(&Value::string("a")));
206+
assert_eq!(result.get("b"), None);
207+
});
208+
}
209+
210+
211+
212+
213+
#[test]
214+
fn scalar_include_true_skip_true() {
215+
run_query(
216+
"{ a, b @include(if: true) @skip(if: true) }",
217+
|result| {
218+
assert_eq!(result.get("a"), Some(&Value::string("a")));
219+
assert_eq!(result.get("b"), None);
220+
});
221+
}
222+
223+
#[test]
224+
fn scalar_include_true_skip_false() {
225+
run_query(
226+
"{ a, b @include(if: true) @skip(if: false) }",
227+
|result| {
228+
assert_eq!(result.get("a"), Some(&Value::string("a")));
229+
assert_eq!(result.get("b"), Some(&Value::string("b")));
230+
});
231+
}
232+
233+
#[test]
234+
fn scalar_include_false_skip_true() {
235+
run_query(
236+
"{ a, b @include(if: false) @skip(if: true) }",
237+
|result| {
238+
assert_eq!(result.get("a"), Some(&Value::string("a")));
239+
assert_eq!(result.get("b"), None);
240+
});
241+
}
242+
243+
#[test]
244+
fn scalar_include_false_skip_false() {
245+
run_query(
246+
"{ a, b @include(if: false) @skip(if: false) }",
247+
|result| {
248+
assert_eq!(result.get("a"), Some(&Value::string("a")));
249+
assert_eq!(result.get("b"), None);
250+
});
251+
}

src/executor_tests/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
mod introspection;
22
mod variables;
33
mod enums;
4+
mod directives;

src/parser/document.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,20 @@ fn parse_fragment<'a>(parser: &mut Parser<'a>) -> UnlocatedParseResult<'a, Selec
171171
directives: directives.map(|s| s.item),
172172
})))
173173
},
174+
Token::At => {
175+
let directives = try!(parse_directives(parser));
176+
let selection_set = try!(parse_selection_set(parser));
177+
178+
Ok(Selection::InlineFragment(
179+
Spanning::start_end(
180+
&start_pos.clone(),
181+
&selection_set.end,
182+
InlineFragment {
183+
type_condition: None,
184+
directives: directives.map(|s| s.item),
185+
selection_set: selection_set.item,
186+
})))
187+
},
174188
_ => Err(parser.next().map(ParseError::UnexpectedToken)),
175189
}
176190
}

src/types/base.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -218,31 +218,35 @@ pub trait GraphQLType<CtxT>: Sized {
218218
///
219219
/// The executor can be used to drive selections into sub-objects.
220220
///
221-
/// The default implementation panics through `unimplemented!()`.
221+
/// The default implementation panics.
222222
#[allow(unused_variables)]
223223
fn resolve_field(&self, field_name: &str, arguments: &Arguments, executor: &mut Executor<CtxT>)
224224
-> ExecutionResult
225225
{
226-
unimplemented!()
226+
panic!("resolve_field must be implemented by object types");
227227
}
228228

229229
/// Resolve this interface or union into a concrete type
230230
///
231231
/// Try to resolve the current type into the type name provided. If the
232232
/// type matches, pass the instance along to `executor.resolve`.
233233
///
234-
/// The default implementation panics through `unimplemented()`.
234+
/// The default implementation panics.
235235
#[allow(unused_variables)]
236236
fn resolve_into_type(&self, type_name: &str, selection_set: Option<Vec<Selection>>, executor: &mut Executor<CtxT>) -> ExecutionResult {
237-
unimplemented!();
237+
if Self::name().unwrap() == type_name {
238+
Ok(self.resolve(selection_set, executor))
239+
} else {
240+
panic!("resolve_into_type must be implemented by unions and interfaces");
241+
}
238242
}
239243

240244
/// Return the concrete type name for this instance/union.
241245
///
242-
/// The default implementation panics through `unimplemented()`.
246+
/// The default implementation panics.
243247
#[allow(unused_variables)]
244248
fn concrete_type_name(&self, context: &CtxT) -> String {
245-
unimplemented!();
249+
panic!("concrete_type_name must be implemented by unions and interfaces");
246250
}
247251

248252
/// Resolve the provided selection set against the current object.
@@ -254,15 +258,15 @@ pub trait GraphQLType<CtxT>: Sized {
254258
///
255259
/// The default implementation uses `resolve_field` to resolve all fields,
256260
/// including those through fragment expansion, for object types. For
257-
/// non-object types, this method panics through `unimplemented!()`.
261+
/// non-object types, this method panics.
258262
fn resolve(&self, selection_set: Option<Vec<Selection>>, executor: &mut Executor<CtxT>) -> Value {
259263
if let Some(selection_set) = selection_set {
260264
let mut result = HashMap::new();
261265
resolve_selection_set_into(self, selection_set, executor, &mut result);
262266
Value::object(result)
263267
}
264268
else {
265-
unimplemented!();
269+
panic!("resolve() must be implemented by non-object output types");
266270
}
267271
}
268272
}

0 commit comments

Comments
 (0)