Skip to content

Commit f3469dd

Browse files
committed
Add object macro tests, fix minor issues
1 parent 88c967f commit f3469dd

File tree

4 files changed

+303
-1
lines changed

4 files changed

+303
-1
lines changed

src/macros/field.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ macro_rules! __graphql__build_field_matches {
5959
__graphql__build_field_matches!($resolveargs, $acc, $( $rest )*);
6060
};
6161

62+
( $resolveargs:tt, $acc:tt, , $( $rest:tt )*) => {
63+
__graphql__build_field_matches!($resolveargs, $acc, $( $rest )*);
64+
};
65+
6266
(
6367
($outname:tt, $selfvar:ident, $fieldvar:ident, $argsvar:ident, $executorvar:ident),
6468
( $( ( $name:ident; ( $($args:tt)* ); $t:ty; $body:block ) )* ),

src/macros/object.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,10 +333,18 @@ macro_rules! graphql_object {
333333
graphql_object!(@gather_object_meta, $reg, $acc, $descr, $ifaces, $( $rest )*)
334334
};
335335

336+
// eat commas
337+
(
338+
@gather_object_meta,
339+
$reg:expr, $acc:expr, $descr:expr, $ifaces:expr, , $( $rest:tt )*
340+
) => {
341+
graphql_object!(@gather_object_meta, $reg, $acc, $descr, $ifaces, $( $rest )*)
342+
};
343+
336344
// base case
337345
(
338346
@gather_object_meta,
339-
$reg:expr, $acc:expr, $descr:expr, $ifaces:expr, $(,)*
347+
$reg:expr, $acc:expr, $descr:expr, $ifaces:expr,
340348
) => {};
341349

342350
( @assign_interfaces, $reg:expr, $tgt:expr, [ $($t:ty,)* ] ) => {
@@ -418,4 +426,13 @@ macro_rules! graphql_object {
418426
graphql_object!(
419427
( ); $name; $ctxt; $outname; $mainself; $( $items )*);
420428
};
429+
430+
(
431+
$name:ty : $ctxt:ty | &$mainself:ident | {
432+
$( $items:tt )*
433+
}
434+
) => {
435+
graphql_object!(
436+
( ); $name; $ctxt; (stringify!($name)); $mainself; $( $items )*);
437+
};
421438
}

src/macros/tests/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ mod scalar;
33
#[allow(dead_code)] mod input_object;
44
mod args;
55
mod field;
6+
mod object;

src/macros/tests/object.rs

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
use std::collections::HashMap;
2+
3+
use ast::InputValue;
4+
use executor::FieldResult;
5+
use value::Value;
6+
use schema::model::RootNode;
7+
8+
/*
9+
10+
Syntax to validate:
11+
12+
* Order of items: fields, description, interfaces
13+
* Optional Generics/lifetimes
14+
* Custom name vs. default name
15+
* Optional commas between items
16+
17+
*/
18+
19+
struct Interface;
20+
21+
struct DefaultName;
22+
23+
struct WithLifetime;
24+
struct WithGenerics;
25+
26+
struct DescriptionFirst;
27+
struct FieldsFirst;
28+
struct InterfacesFirst;
29+
30+
struct CommasWithTrailing;
31+
struct CommasOnMeta;
32+
33+
struct Root;
34+
35+
graphql_object!(DefaultName: () |&self| {
36+
field simple() -> FieldResult<i64> { Ok(0) }
37+
});
38+
39+
40+
graphql_object!(<'a> &'a WithLifetime: () as "WithLifetime" |&self| {
41+
field simple() -> FieldResult<i64> { Ok(0) }
42+
});
43+
44+
graphql_object!(<CtxT> WithGenerics: CtxT as "WithGenerics" |&self| {
45+
field simple() -> FieldResult<i64> { Ok(0) }
46+
});
47+
48+
graphql_interface!(Interface: () as "Interface" |&self| {
49+
field simple() -> FieldResult<i64> { Ok(0) }
50+
51+
instance_resolvers: |_| [
52+
Some(DescriptionFirst {}),
53+
]
54+
});
55+
56+
graphql_object!(DescriptionFirst: () as "DescriptionFirst" |&self| {
57+
description: "A description"
58+
59+
field simple() -> FieldResult<i64> { Ok(0) }
60+
61+
interfaces: [Interface]
62+
});
63+
64+
graphql_object!(FieldsFirst: () as "FieldsFirst" |&self| {
65+
field simple() -> FieldResult<i64> { Ok(0) }
66+
67+
description: "A description"
68+
69+
interfaces: [Interface]
70+
});
71+
72+
graphql_object!(InterfacesFirst: () as "InterfacesFirst" |&self| {
73+
interfaces: [Interface]
74+
75+
field simple() -> FieldResult<i64> { Ok(0) }
76+
77+
description: "A description"
78+
});
79+
80+
graphql_object!(CommasWithTrailing: () as "CommasWithTrailing" |&self| {
81+
interfaces: [Interface],
82+
83+
field simple() -> FieldResult<i64> { Ok(0) },
84+
85+
description: "A description",
86+
});
87+
88+
89+
graphql_object!(CommasOnMeta: () as "CommasOnMeta" |&self| {
90+
interfaces: [Interface],
91+
description: "A description",
92+
93+
field simple() -> FieldResult<i64> { Ok(0) }
94+
});
95+
96+
graphql_object!(Root: () as "Root" |&self| {
97+
field default_name() -> FieldResult<DefaultName> { Ok(DefaultName {}) }
98+
99+
field with_lifetime() -> FieldResult<&WithLifetime> { Err("Nope".to_owned()) }
100+
field with_generics() -> FieldResult<WithGenerics> { Ok(WithGenerics {}) }
101+
102+
field description_first() -> FieldResult<DescriptionFirst> { Ok(DescriptionFirst {}) }
103+
field fields_first() -> FieldResult<FieldsFirst> { Ok(FieldsFirst {}) }
104+
field interfaces_first() -> FieldResult<InterfacesFirst> { Ok(InterfacesFirst {}) }
105+
106+
field commas_with_trailing() -> FieldResult<CommasWithTrailing> { Ok(CommasWithTrailing {}) }
107+
field commas_on_meta() -> FieldResult<CommasOnMeta> { Ok(CommasOnMeta {}) }
108+
});
109+
110+
111+
fn run_type_info_query<F>(type_name: &str, f: F)
112+
where F: Fn(&HashMap<String, Value>, &Vec<Value>) -> ()
113+
{
114+
let doc = r#"
115+
query ($typeName: String!) {
116+
__type(name: $typeName) {
117+
name
118+
description
119+
fields(includeDeprecated: true) {
120+
name
121+
}
122+
interfaces {
123+
name
124+
kind
125+
}
126+
}
127+
}
128+
"#;
129+
let schema = RootNode::new(Root {}, ());
130+
let vars = vec![
131+
("typeName".to_owned(), InputValue::string(type_name)),
132+
].into_iter().collect();
133+
134+
let (result, errs) = ::execute(doc, None, &schema, &vars, &())
135+
.expect("Execution failed");
136+
137+
assert_eq!(errs, []);
138+
139+
println!("Result: {:?}", result);
140+
141+
let type_info = result
142+
.as_object_value().expect("Result is not an object")
143+
.get("__type").expect("__type field missing")
144+
.as_object_value().expect("__type field not an object value");
145+
146+
let fields = type_info
147+
.get("fields").expect("fields field missing")
148+
.as_list_value().expect("fields field not a list value");
149+
150+
f(type_info, fields);
151+
}
152+
153+
#[test]
154+
fn introspect_default_name() {
155+
run_type_info_query("DefaultName", |object, fields| {
156+
assert_eq!(object.get("name"), Some(&Value::string("DefaultName")));
157+
assert_eq!(object.get("description"), Some(&Value::null()));
158+
assert_eq!(object.get("interfaces"), Some(&Value::list(vec![])));
159+
160+
assert!(fields.contains(&Value::object(vec![
161+
("name", Value::string("simple")),
162+
].into_iter().collect())));
163+
});
164+
}
165+
166+
#[test]
167+
fn introspect_with_lifetime() {
168+
run_type_info_query("WithLifetime", |object, fields| {
169+
assert_eq!(object.get("name"), Some(&Value::string("WithLifetime")));
170+
assert_eq!(object.get("description"), Some(&Value::null()));
171+
assert_eq!(object.get("interfaces"), Some(&Value::list(vec![])));
172+
173+
assert!(fields.contains(&Value::object(vec![
174+
("name", Value::string("simple")),
175+
].into_iter().collect())));
176+
});
177+
}
178+
179+
#[test]
180+
fn introspect_with_generics() {
181+
run_type_info_query("WithGenerics", |object, fields| {
182+
assert_eq!(object.get("name"), Some(&Value::string("WithGenerics")));
183+
assert_eq!(object.get("description"), Some(&Value::null()));
184+
assert_eq!(object.get("interfaces"), Some(&Value::list(vec![])));
185+
186+
assert!(fields.contains(&Value::object(vec![
187+
("name", Value::string("simple")),
188+
].into_iter().collect())));
189+
});
190+
}
191+
192+
#[test]
193+
fn introspect_description_first() {
194+
run_type_info_query("DescriptionFirst", |object, fields| {
195+
assert_eq!(object.get("name"), Some(&Value::string("DescriptionFirst")));
196+
assert_eq!(object.get("description"), Some(&Value::string("A description")));
197+
assert_eq!(object.get("interfaces"), Some(&Value::list(vec![
198+
Value::object(vec![
199+
("name", Value::string("Interface")),
200+
("kind", Value::string("INTERFACE")),
201+
].into_iter().collect()),
202+
])));
203+
204+
assert!(fields.contains(&Value::object(vec![
205+
("name", Value::string("simple")),
206+
].into_iter().collect())));
207+
});
208+
}
209+
210+
#[test]
211+
fn introspect_fields_first() {
212+
run_type_info_query("FieldsFirst", |object, fields| {
213+
assert_eq!(object.get("name"), Some(&Value::string("FieldsFirst")));
214+
assert_eq!(object.get("description"), Some(&Value::string("A description")));
215+
assert_eq!(object.get("interfaces"), Some(&Value::list(vec![
216+
Value::object(vec![
217+
("name", Value::string("Interface")),
218+
("kind", Value::string("INTERFACE")),
219+
].into_iter().collect()),
220+
])));
221+
222+
assert!(fields.contains(&Value::object(vec![
223+
("name", Value::string("simple")),
224+
].into_iter().collect())));
225+
});
226+
}
227+
228+
#[test]
229+
fn introspect_interfaces_first() {
230+
run_type_info_query("InterfacesFirst", |object, fields| {
231+
assert_eq!(object.get("name"), Some(&Value::string("InterfacesFirst")));
232+
assert_eq!(object.get("description"), Some(&Value::string("A description")));
233+
assert_eq!(object.get("interfaces"), Some(&Value::list(vec![
234+
Value::object(vec![
235+
("name", Value::string("Interface")),
236+
("kind", Value::string("INTERFACE")),
237+
].into_iter().collect()),
238+
])));
239+
240+
assert!(fields.contains(&Value::object(vec![
241+
("name", Value::string("simple")),
242+
].into_iter().collect())));
243+
});
244+
}
245+
246+
#[test]
247+
fn introspect_commas_with_trailing() {
248+
run_type_info_query("CommasWithTrailing", |object, fields| {
249+
assert_eq!(object.get("name"), Some(&Value::string("CommasWithTrailing")));
250+
assert_eq!(object.get("description"), Some(&Value::string("A description")));
251+
assert_eq!(object.get("interfaces"), Some(&Value::list(vec![
252+
Value::object(vec![
253+
("name", Value::string("Interface")),
254+
("kind", Value::string("INTERFACE")),
255+
].into_iter().collect()),
256+
])));
257+
258+
assert!(fields.contains(&Value::object(vec![
259+
("name", Value::string("simple")),
260+
].into_iter().collect())));
261+
});
262+
}
263+
264+
#[test]
265+
fn introspect_commas_on_meta() {
266+
run_type_info_query("CommasOnMeta", |object, fields| {
267+
assert_eq!(object.get("name"), Some(&Value::string("CommasOnMeta")));
268+
assert_eq!(object.get("description"), Some(&Value::string("A description")));
269+
assert_eq!(object.get("interfaces"), Some(&Value::list(vec![
270+
Value::object(vec![
271+
("name", Value::string("Interface")),
272+
("kind", Value::string("INTERFACE")),
273+
].into_iter().collect()),
274+
])));
275+
276+
assert!(fields.contains(&Value::object(vec![
277+
("name", Value::string("simple")),
278+
].into_iter().collect())));
279+
});
280+
}

0 commit comments

Comments
 (0)