1 use super::*;
2 
3 use rustc_ast::attr;
4 use rustc_ast::Path;
5 use rustc_span::create_default_session_globals_then;
6 use rustc_span::symbol::{Ident, Symbol};
7 use rustc_span::DUMMY_SP;
8 
word_cfg(s: &str) -> Cfg9 fn word_cfg(s: &str) -> Cfg {
10     Cfg::Cfg(Symbol::intern(s), None)
11 }
12 
name_value_cfg(name: &str, value: &str) -> Cfg13 fn name_value_cfg(name: &str, value: &str) -> Cfg {
14     Cfg::Cfg(Symbol::intern(name), Some(Symbol::intern(value)))
15 }
16 
dummy_meta_item_word(name: &str) -> MetaItem17 fn dummy_meta_item_word(name: &str) -> MetaItem {
18     MetaItem {
19         path: Path::from_ident(Ident::from_str(name)),
20         kind: MetaItemKind::Word,
21         span: DUMMY_SP,
22     }
23 }
24 
25 macro_rules! dummy_meta_item_list {
26     ($name:ident, [$($list:ident),* $(,)?]) => {
27         MetaItem {
28             path: Path::from_ident(Ident::from_str(stringify!($name))),
29             kind: MetaItemKind::List(vec![
30                 $(
31                     NestedMetaItem::MetaItem(
32                         dummy_meta_item_word(stringify!($list)),
33                     ),
34                 )*
35             ]),
36             span: DUMMY_SP,
37         }
38     };
39 
40     ($name:ident, [$($list:expr),* $(,)?]) => {
41         MetaItem {
42             path: Path::from_ident(Ident::from_str(stringify!($name))),
43             kind: MetaItemKind::List(vec![
44                 $(
45                     NestedMetaItem::MetaItem($list),
46                 )*
47             ]),
48             span: DUMMY_SP,
49         }
50     };
51 }
52 
53 #[test]
test_cfg_not()54 fn test_cfg_not() {
55     create_default_session_globals_then(|| {
56         assert_eq!(!Cfg::False, Cfg::True);
57         assert_eq!(!Cfg::True, Cfg::False);
58         assert_eq!(!word_cfg("test"), Cfg::Not(Box::new(word_cfg("test"))));
59         assert_eq!(
60             !Cfg::All(vec![word_cfg("a"), word_cfg("b")]),
61             Cfg::Not(Box::new(Cfg::All(vec![word_cfg("a"), word_cfg("b")])))
62         );
63         assert_eq!(
64             !Cfg::Any(vec![word_cfg("a"), word_cfg("b")]),
65             Cfg::Not(Box::new(Cfg::Any(vec![word_cfg("a"), word_cfg("b")])))
66         );
67         assert_eq!(!Cfg::Not(Box::new(word_cfg("test"))), word_cfg("test"));
68     })
69 }
70 
71 #[test]
test_cfg_and()72 fn test_cfg_and() {
73     create_default_session_globals_then(|| {
74         let mut x = Cfg::False;
75         x &= Cfg::True;
76         assert_eq!(x, Cfg::False);
77 
78         x = word_cfg("test");
79         x &= Cfg::False;
80         assert_eq!(x, Cfg::False);
81 
82         x = word_cfg("test2");
83         x &= Cfg::True;
84         assert_eq!(x, word_cfg("test2"));
85 
86         x = Cfg::True;
87         x &= word_cfg("test3");
88         assert_eq!(x, word_cfg("test3"));
89 
90         x &= word_cfg("test3");
91         assert_eq!(x, word_cfg("test3"));
92 
93         x &= word_cfg("test4");
94         assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4")]));
95 
96         x &= word_cfg("test4");
97         assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4")]));
98 
99         x &= word_cfg("test5");
100         assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4"), word_cfg("test5")]));
101 
102         x &= Cfg::All(vec![word_cfg("test6"), word_cfg("test7")]);
103         assert_eq!(
104             x,
105             Cfg::All(vec![
106                 word_cfg("test3"),
107                 word_cfg("test4"),
108                 word_cfg("test5"),
109                 word_cfg("test6"),
110                 word_cfg("test7"),
111             ])
112         );
113 
114         x &= Cfg::All(vec![word_cfg("test6"), word_cfg("test7")]);
115         assert_eq!(
116             x,
117             Cfg::All(vec![
118                 word_cfg("test3"),
119                 word_cfg("test4"),
120                 word_cfg("test5"),
121                 word_cfg("test6"),
122                 word_cfg("test7"),
123             ])
124         );
125 
126         let mut y = Cfg::Any(vec![word_cfg("a"), word_cfg("b")]);
127         y &= x;
128         assert_eq!(
129             y,
130             Cfg::All(vec![
131                 word_cfg("test3"),
132                 word_cfg("test4"),
133                 word_cfg("test5"),
134                 word_cfg("test6"),
135                 word_cfg("test7"),
136                 Cfg::Any(vec![word_cfg("a"), word_cfg("b")]),
137             ])
138         );
139 
140         let mut z = word_cfg("test8");
141         z &= Cfg::All(vec![word_cfg("test9"), word_cfg("test10")]);
142         assert_eq!(z, Cfg::All(vec![word_cfg("test9"), word_cfg("test10"), word_cfg("test8")]));
143 
144         let mut z = word_cfg("test11");
145         z &= Cfg::All(vec![word_cfg("test11"), word_cfg("test12")]);
146         assert_eq!(z, Cfg::All(vec![word_cfg("test11"), word_cfg("test12")]));
147 
148         assert_eq!(
149             word_cfg("a") & word_cfg("b") & word_cfg("c"),
150             Cfg::All(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")])
151         );
152     })
153 }
154 
155 #[test]
test_cfg_or()156 fn test_cfg_or() {
157     create_default_session_globals_then(|| {
158         let mut x = Cfg::True;
159         x |= Cfg::False;
160         assert_eq!(x, Cfg::True);
161 
162         x = word_cfg("test");
163         x |= Cfg::True;
164         assert_eq!(x, Cfg::True);
165 
166         x = word_cfg("test2");
167         x |= Cfg::False;
168         assert_eq!(x, word_cfg("test2"));
169 
170         x = Cfg::False;
171         x |= word_cfg("test3");
172         assert_eq!(x, word_cfg("test3"));
173 
174         x |= word_cfg("test3");
175         assert_eq!(x, word_cfg("test3"));
176 
177         x |= word_cfg("test4");
178         assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4")]));
179 
180         x |= word_cfg("test4");
181         assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4")]));
182 
183         x |= word_cfg("test5");
184         assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4"), word_cfg("test5")]));
185 
186         x |= Cfg::Any(vec![word_cfg("test6"), word_cfg("test7")]);
187         assert_eq!(
188             x,
189             Cfg::Any(vec![
190                 word_cfg("test3"),
191                 word_cfg("test4"),
192                 word_cfg("test5"),
193                 word_cfg("test6"),
194                 word_cfg("test7"),
195             ])
196         );
197 
198         x |= Cfg::Any(vec![word_cfg("test6"), word_cfg("test7")]);
199         assert_eq!(
200             x,
201             Cfg::Any(vec![
202                 word_cfg("test3"),
203                 word_cfg("test4"),
204                 word_cfg("test5"),
205                 word_cfg("test6"),
206                 word_cfg("test7"),
207             ])
208         );
209 
210         let mut y = Cfg::All(vec![word_cfg("a"), word_cfg("b")]);
211         y |= x;
212         assert_eq!(
213             y,
214             Cfg::Any(vec![
215                 word_cfg("test3"),
216                 word_cfg("test4"),
217                 word_cfg("test5"),
218                 word_cfg("test6"),
219                 word_cfg("test7"),
220                 Cfg::All(vec![word_cfg("a"), word_cfg("b")]),
221             ])
222         );
223 
224         let mut z = word_cfg("test8");
225         z |= Cfg::Any(vec![word_cfg("test9"), word_cfg("test10")]);
226         assert_eq!(z, Cfg::Any(vec![word_cfg("test9"), word_cfg("test10"), word_cfg("test8")]));
227 
228         let mut z = word_cfg("test11");
229         z |= Cfg::Any(vec![word_cfg("test11"), word_cfg("test12")]);
230         assert_eq!(z, Cfg::Any(vec![word_cfg("test11"), word_cfg("test12")]));
231 
232         assert_eq!(
233             word_cfg("a") | word_cfg("b") | word_cfg("c"),
234             Cfg::Any(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")])
235         );
236     })
237 }
238 
239 #[test]
test_parse_ok()240 fn test_parse_ok() {
241     create_default_session_globals_then(|| {
242         let mi = dummy_meta_item_word("all");
243         assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all")));
244 
245         let mi =
246             attr::mk_name_value_item_str(Ident::from_str("all"), Symbol::intern("done"), DUMMY_SP);
247         assert_eq!(Cfg::parse(&mi), Ok(name_value_cfg("all", "done")));
248 
249         let mi = dummy_meta_item_list!(all, [a, b]);
250         assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") & word_cfg("b")));
251 
252         let mi = dummy_meta_item_list!(any, [a, b]);
253         assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") | word_cfg("b")));
254 
255         let mi = dummy_meta_item_list!(not, [a]);
256         assert_eq!(Cfg::parse(&mi), Ok(!word_cfg("a")));
257 
258         let mi = dummy_meta_item_list!(
259             not,
260             [dummy_meta_item_list!(
261                 any,
262                 [dummy_meta_item_word("a"), dummy_meta_item_list!(all, [b, c]),]
263             ),]
264         );
265         assert_eq!(Cfg::parse(&mi), Ok(!(word_cfg("a") | (word_cfg("b") & word_cfg("c")))));
266 
267         let mi = dummy_meta_item_list!(all, [a, b, c]);
268         assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") & word_cfg("b") & word_cfg("c")));
269     })
270 }
271 
272 #[test]
test_parse_err()273 fn test_parse_err() {
274     create_default_session_globals_then(|| {
275         let mi = attr::mk_name_value_item(Ident::from_str("foo"), LitKind::Bool(false), DUMMY_SP);
276         assert!(Cfg::parse(&mi).is_err());
277 
278         let mi = dummy_meta_item_list!(not, [a, b]);
279         assert!(Cfg::parse(&mi).is_err());
280 
281         let mi = dummy_meta_item_list!(not, []);
282         assert!(Cfg::parse(&mi).is_err());
283 
284         let mi = dummy_meta_item_list!(foo, []);
285         assert!(Cfg::parse(&mi).is_err());
286 
287         let mi = dummy_meta_item_list!(
288             all,
289             [dummy_meta_item_list!(foo, []), dummy_meta_item_word("b"),]
290         );
291         assert!(Cfg::parse(&mi).is_err());
292 
293         let mi = dummy_meta_item_list!(
294             any,
295             [dummy_meta_item_word("a"), dummy_meta_item_list!(foo, []),]
296         );
297         assert!(Cfg::parse(&mi).is_err());
298 
299         let mi = dummy_meta_item_list!(not, [dummy_meta_item_list!(foo, []),]);
300         assert!(Cfg::parse(&mi).is_err());
301     })
302 }
303 
304 #[test]
test_render_short_html()305 fn test_render_short_html() {
306     create_default_session_globals_then(|| {
307         assert_eq!(word_cfg("unix").render_short_html(), "Unix");
308         assert_eq!(name_value_cfg("target_os", "macos").render_short_html(), "macOS");
309         assert_eq!(name_value_cfg("target_pointer_width", "16").render_short_html(), "16-bit");
310         assert_eq!(name_value_cfg("target_endian", "little").render_short_html(), "Little-endian");
311         assert_eq!((!word_cfg("windows")).render_short_html(), "Non-Windows");
312         assert_eq!(
313             (word_cfg("unix") & word_cfg("windows")).render_short_html(),
314             "Unix and Windows"
315         );
316         assert_eq!((word_cfg("unix") | word_cfg("windows")).render_short_html(), "Unix or Windows");
317         assert_eq!(
318             (word_cfg("unix") & word_cfg("windows") & word_cfg("debug_assertions"))
319                 .render_short_html(),
320             "Unix and Windows and debug-assertions enabled"
321         );
322         assert_eq!(
323             (word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions"))
324                 .render_short_html(),
325             "Unix or Windows or debug-assertions enabled"
326         );
327         assert_eq!(
328             (!(word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions")))
329                 .render_short_html(),
330             "Neither Unix nor Windows nor debug-assertions enabled"
331         );
332         assert_eq!(
333             ((word_cfg("unix") & name_value_cfg("target_arch", "x86_64"))
334                 | (word_cfg("windows") & name_value_cfg("target_pointer_width", "64")))
335             .render_short_html(),
336             "Unix and x86-64, or Windows and 64-bit"
337         );
338         assert_eq!(
339             (!(word_cfg("unix") & word_cfg("windows"))).render_short_html(),
340             "Not (Unix and Windows)"
341         );
342         assert_eq!(
343             ((word_cfg("debug_assertions") | word_cfg("windows")) & word_cfg("unix"))
344                 .render_short_html(),
345             "(Debug-assertions enabled or Windows) and Unix"
346         );
347         assert_eq!(
348             name_value_cfg("target_feature", "sse2").render_short_html(),
349             "<code>sse2</code>"
350         );
351         assert_eq!(
352             (name_value_cfg("target_arch", "x86_64") & name_value_cfg("target_feature", "sse2"))
353                 .render_short_html(),
354             "x86-64 and <code>sse2</code>"
355         );
356     })
357 }
358 
359 #[test]
test_render_long_html()360 fn test_render_long_html() {
361     create_default_session_globals_then(|| {
362         assert_eq!(
363             word_cfg("unix").render_long_html(),
364             "This is supported on <strong>Unix</strong> only."
365         );
366         assert_eq!(
367             name_value_cfg("target_os", "macos").render_long_html(),
368             "This is supported on <strong>macOS</strong> only."
369         );
370         assert_eq!(
371             name_value_cfg("target_os", "wasi").render_long_html(),
372             "This is supported on <strong>WASI</strong> only."
373         );
374         assert_eq!(
375             name_value_cfg("target_pointer_width", "16").render_long_html(),
376             "This is supported on <strong>16-bit</strong> only."
377         );
378         assert_eq!(
379             name_value_cfg("target_endian", "little").render_long_html(),
380             "This is supported on <strong>little-endian</strong> only."
381         );
382         assert_eq!(
383             (!word_cfg("windows")).render_long_html(),
384             "This is supported on <strong>non-Windows</strong> only."
385         );
386         assert_eq!(
387             (word_cfg("unix") & word_cfg("windows")).render_long_html(),
388             "This is supported on <strong>Unix and Windows</strong> only."
389         );
390         assert_eq!(
391             (word_cfg("unix") | word_cfg("windows")).render_long_html(),
392             "This is supported on <strong>Unix or Windows</strong> only."
393         );
394         assert_eq!(
395             (word_cfg("unix") & word_cfg("windows") & word_cfg("debug_assertions"))
396                 .render_long_html(),
397             "This is supported on <strong>Unix and Windows and debug-assertions enabled\
398              </strong> only."
399         );
400         assert_eq!(
401             (word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions"))
402                 .render_long_html(),
403             "This is supported on <strong>Unix or Windows or debug-assertions enabled\
404              </strong> only."
405         );
406         assert_eq!(
407             (!(word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions")))
408                 .render_long_html(),
409             "This is supported on <strong>neither Unix nor Windows nor debug-assertions \
410              enabled</strong>."
411         );
412         assert_eq!(
413             ((word_cfg("unix") & name_value_cfg("target_arch", "x86_64"))
414                 | (word_cfg("windows") & name_value_cfg("target_pointer_width", "64")))
415             .render_long_html(),
416             "This is supported on <strong>Unix and x86-64, or Windows and 64-bit</strong> only."
417         );
418         assert_eq!(
419             (!(word_cfg("unix") & word_cfg("windows"))).render_long_html(),
420             "This is supported on <strong>not (Unix and Windows)</strong>."
421         );
422         assert_eq!(
423             ((word_cfg("debug_assertions") | word_cfg("windows")) & word_cfg("unix"))
424                 .render_long_html(),
425             "This is supported on <strong>(debug-assertions enabled or Windows) and Unix\
426              </strong> only."
427         );
428         assert_eq!(
429             name_value_cfg("target_feature", "sse2").render_long_html(),
430             "This is supported with <strong>target feature <code>sse2</code></strong> only."
431         );
432         assert_eq!(
433             (name_value_cfg("target_arch", "x86_64") & name_value_cfg("target_feature", "sse2"))
434                 .render_long_html(),
435             "This is supported on <strong>x86-64 and target feature \
436              <code>sse2</code></strong> only."
437         );
438     })
439 }
440 
441 #[test]
test_simplify_with()442 fn test_simplify_with() {
443     // This is a tiny subset of things that could be simplified, but it likely covers 90% of
444     // real world usecases well.
445     create_default_session_globals_then(|| {
446         let foo = word_cfg("foo");
447         let bar = word_cfg("bar");
448         let baz = word_cfg("baz");
449         let quux = word_cfg("quux");
450 
451         let foobar = Cfg::All(vec![foo.clone(), bar.clone()]);
452         let barbaz = Cfg::All(vec![bar.clone(), baz.clone()]);
453         let foobarbaz = Cfg::All(vec![foo.clone(), bar.clone(), baz.clone()]);
454         let bazquux = Cfg::All(vec![baz.clone(), quux.clone()]);
455 
456         // Unrelated cfgs don't affect each other
457         assert_eq!(foo.simplify_with(&bar).as_ref(), Some(&foo));
458         assert_eq!(foobar.simplify_with(&bazquux).as_ref(), Some(&foobar));
459 
460         // Identical cfgs are eliminated
461         assert_eq!(foo.simplify_with(&foo), None);
462         assert_eq!(foobar.simplify_with(&foobar), None);
463 
464         // Multiple cfgs eliminate a single assumed cfg
465         assert_eq!(foobar.simplify_with(&foo).as_ref(), Some(&bar));
466         assert_eq!(foobar.simplify_with(&bar).as_ref(), Some(&foo));
467 
468         // A single cfg is eliminated by multiple assumed cfg containing it
469         assert_eq!(foo.simplify_with(&foobar), None);
470 
471         // Multiple cfgs eliminate the matching subset of multiple assumed cfg
472         assert_eq!(foobar.simplify_with(&barbaz).as_ref(), Some(&foo));
473         assert_eq!(foobar.simplify_with(&foobarbaz), None);
474     });
475 }
476