1extern crate proc_macro;
2extern crate syn;
3
4use colored::*;
5use proc_macro2::TokenStream;
6use types::DescribeStatement;
7
8mod parser;
9mod types;
10
11#[proc_macro]
12pub fn ruspec(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
13 let input = proc_macro2::TokenStream::from(input);
14
15 let expanded = match _ruspec(input) {
16 Ok(token_stream) => token_stream,
17 Err(e) => {
18 eprintln!("{}: {}", "error".red().bold(), e);
19 std::process::exit(1);
20 }
21 };
22
23 proc_macro::TokenStream::from(expanded)
24}
25
26fn _ruspec(input: proc_macro2::TokenStream) -> Result<TokenStream, failure::Error> {
27 let describe_statements = parser::Parser::new(input).parse()?;
28 Ok(DescribeStatement::expands(describe_statements))
29}
30
31#[cfg(test)]
32mod tests {
33 use crate::_ruspec;
34 use quote::quote;
35
36 #[test]
37 fn should_output_expected_stream() {
38 let input = quote! {
39 describe "hoge" {
40 it "hoge" {
41 assert!(true);
42 }
43 }
44 };
45
46 let expected = quote! {
47 mod hoge {
48 #[allow(unused_imports)]
49 use super::*;
50
51 #[test]
52 fn hoge() {
53 assert!(true);
54 }
55 }
56 };
57
58 let output = crate::_ruspec(input).unwrap();
59 assert_eq!(output.to_string(), expected.to_string())
60 }
61
62 #[test]
63 fn should_expand_before() {
64 let input = quote! {
65 describe "hoge" {
66 before { let hoge = 1234; }
67 it "hoge" {
68 assert!(true);
69 }
70 }
71 };
72
73 let expected = quote! {
74 mod hoge {
75 #[allow(unused_imports)]
76 use super::*;
77 #[test]
78 fn hoge() {
79 let hoge = 1234;
80 assert!(true);
81 }
82 }
83 };
84
85 let output = crate::_ruspec(input).unwrap();
86 assert_eq!(output.to_string(), expected.to_string())
87 }
88
89 #[test]
90 fn should_expand_after() {
91 let input = quote! {
92 describe "hoge" {
93 after { let hoge = 1234; }
94 it "hoge" {
95 assert!(true);
96 }
97 }
98 };
99
100 let expected = quote! {
101 mod hoge {
102 #[allow(unused_imports)]
103 use super::*;
104
105 #[test]
106 fn hoge() {
107 assert!(true);
108 let hoge = 1234;
109 }
110 }
111 };
112
113 let output = crate::_ruspec(input).unwrap();
114 assert_eq!(output.to_string(), expected.to_string())
115 }
116
117 #[test]
118 fn should_expand_subject() {
119 let input = quote! {
120 describe "hoge" {
121 subject { true }
122 it "hoge" {
123 assert!(subject);
124 }
125 }
126 };
127
128 let expected = quote! {
129 mod hoge {
130 #[allow(unused_imports)]
131 use super::*;
132
133 #[test]
134 fn hoge() {
135 let subject = (true);
138 assert!(subject);
139 }
140 }
141 };
142
143 let output = crate::_ruspec(input).unwrap();
144 assert_eq!(output.to_string(), expected.to_string())
145 }
146
147 #[test]
148 fn should_context_is_aliase_describe() {
149 let input = quote! {
150 context "hoge" {
151 it "hoge" {
152 assert!(true);
153 }
154 }
155 };
156
157 let expected = quote! {
158 mod hoge {
159 #[allow(unused_imports)]
160 use super::*;
161
162 #[test]
163 fn hoge() {
164 assert!(true);
165 }
166 }
167 };
168
169 let output = crate::_ruspec(input).unwrap();
170 assert_eq!(output.to_string(), expected.to_string())
171 }
172
173 #[test]
174 fn should_parse_conplex_describe() {
175 let input = quote! {
176 context "hoge" {
177 before { let hoge = 1; }
178 after { let fug = 1; }
179 it "hoge" {
180 assert!(true);
181 }
182
183 it "fug" {
184 assert!(true);
185 }
186 }
187 };
188
189 let expected = quote! {
190 mod hoge {
191 #[allow(unused_imports)]
192 use super::*;
193
194 #[test]
195 fn hoge() {
196 let hoge = 1;
197 assert!(true);
198 let fug = 1;
199 }
200 #[test]
201 fn fug() {
202 let hoge = 1;
203 assert!(true);
204 let fug = 1;
205 }
206 }
207 };
208
209 let output = crate::_ruspec(input).unwrap();
210 assert_eq!(output.to_string(), expected.to_string())
211 }
212
213 #[test]
214 fn should_parse_error_when_not_include_it() {
215 let input = quote! {
216 describe "hoge" {
217 }
218 };
219
220 let output = _ruspec(input);
221 assert!(output.is_err());
222
223 let e = output.err().unwrap();
224 assert_eq!(
225 format!("{}", e),
226 "not found expected keyword (it subject before after)"
227 );
228 }
229
230 #[test]
231 fn should_parse_error_when_not_include_describe_str() {
232 let input = quote! {
233 describe {
234 it "hoge" {}
235 }
236 };
237
238 let output = _ruspec(input);
239 assert!(output.is_err());
240
241 let e = output.err().unwrap();
242 assert_eq!(format!("{}", e), "not found expected describe string");
243 }
244
245 #[test]
246 fn should_parse_error_when_not_include_it_str() {
247 let input = quote! {
248 describe "hoge" {
249 it {}
250 }
251 };
252
253 let output = _ruspec(input);
254 assert!(output.is_err());
255
256 let e = output.err().unwrap();
257 assert_eq!(format!("{}", e), "not found expected it string");
258 }
259}