ruspec/
lib.rs

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                    // FIXME Expected code is
136                    // assert!(true)
137                    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}