blob: dc351ef1a869fbac9f7fcd7561f246db8ee71cfc [file] [log] [blame]
David Tolnay453cfd12016-10-23 11:00:14 -07001#![cfg(feature = "expand")]
2
3extern crate syn;
4use syn::*;
5
6#[macro_use]
7extern crate quote;
8use quote::Tokens;
9
10extern crate tempdir;
11use tempdir::TempDir;
12
13use std::fs::File;
14use std::io::{Read, Write};
15
16#[test]
17fn test_cfg() {
18 let original = quote! {
19 use super::*;
20
21 #[derive(A)]
22 struct P;
23
24 #[cfg_attr(feature = "q", derive(A))]
25 struct Q;
26
27 #[derive(A)]
28 #[cfg(feature = "r")]
29 struct R;
30
31 #[cfg(feature = "s1")]
32 #[cfg(all(feature = "s2", feature = "s3"))]
33 #[cfg_attr(feature = "s4", derive(A))]
34 struct S;
35 };
36
37 let expected = quote! {
38 // Unmodified from the input
39 use super::*;
40
41 type P = ();
42
43 #[cfg(feature = "q")]
44 type Q = ();
45
46 #[cfg(feature = "r")]
47 type R = ();
48
49 #[cfg(all(feature = "s1", feature = "s2", feature = "s3", feature = "s4"))]
50 type S = ();
51 };
52
53 test_expand(original, expected);
54}
55
56#[test]
57fn test_recursive() {
58 let original = quote! {
59 #[d]
60 #[cfg_attr(feature = "f", derive(Copy, B, Clone))]
61 #[e]
62 #[cfg(feature = "e")]
63 struct T;
64 };
65
66 let expected = quote! {
67 // From #[derive(A)] on struct S produced by #[derive(B)]
68 #[cfg(all(feature = "e", feature = "f", feature = "g"))]
69 type S = ();
70
71 // From #[derive(B)] on struct T
72 #[cfg(all(feature = "e", feature = "f"))]
73 impl B for T {}
74
75 // From the input
76 #[d]
77 #[cfg_attr(feature = "f", derive(Copy, Clone))]
78 #[e]
79 #[cfg(feature = "e")]
80 struct T;
81 };
82
83 test_expand(original, expected);
84}
85
86fn test_expand(original: Tokens, expected: Tokens) {
87 let dir = TempDir::new("syn").expect("create temp dir");
88 let src_path = dir.path().join("expand.in.rs");
89 let dst_path = dir.path().join("expand.rs");
90
91 // Write the src file
92 let mut src_file = File::create(&src_path).expect("create temp file");
93 src_file.write_all(original.to_string().as_bytes()).expect("write temp file");
94
95 // Run expansion
96 let mut registry = Registry::new();
97 registry.add_derive("A", expand_a);
98 registry.add_derive("B", expand_b);
99 registry.expand_file(&src_path, &dst_path).unwrap();
100
101 // Read the dst file
102 let mut expanded = String::new();
103 let mut dst_file = File::open(&dst_path).expect("open output file");
104 dst_file.read_to_string(&mut expanded).expect("read output file");
David Tolnay9e24d4d2016-10-23 22:17:27 -0700105 let krate = parse_crate(&expanded).expect("parse output file");
David Tolnay453cfd12016-10-23 11:00:14 -0700106
David Tolnay9e24d4d2016-10-23 22:17:27 -0700107 assert_eq!(quote!(#krate), expected);
David Tolnay453cfd12016-10-23 11:00:14 -0700108}
109
110fn expand_a(input: MacroInput) -> Result<Expanded, String> {
111 let name = &input.ident;
112 let out = quote! {
113 type #name = ();
114 };
115 Ok(Expanded {
116 new_items: parse_items(&out.to_string()).unwrap(),
117 original: None,
118 })
119}
120
121fn expand_b(input: MacroInput) -> Result<Expanded, String> {
122 assert_eq!(quote!(#input), quote! {
123 #[d]
124 #[cfg_attr(feature = "f", derive(Copy, Clone))]
125 #[e]
126 struct T;
127 });
128 let out = quote! {
129 #[cfg_attr(feature = "g", derive(A))]
130 struct S;
131
132 impl B for T {}
133 };
134 Ok(Expanded {
135 new_items: parse_items(&out.to_string()).unwrap(),
136 original: Some(input),
137 })
138}