diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-10-23 11:38:30 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-10-23 11:38:30 +0100 |
commit | 81609960fa30ea92e37b23dc7b025d1939626812 (patch) | |
tree | 835866b358bd597e1a2c481b93641418c2562c86 /crates/cfg/src/tests.rs | |
parent | 8b3c851dd37f39f79e7e8807378f45fdde7f6411 (diff) | |
parent | a246d4f599dcf2612fa99720fb4ca98101ed93fb (diff) |
Merge #6324
6324: Improve #[cfg] diagnostics r=jonas-schievink a=jonas-schievink
Unfortunately I ran into https://github.com/rust-analyzer/rust-analyzer/issues/4058 while testing this on https://github.com/nrf-rs/nrf-hal/, so I didn't see much of it in action yet, but it does seem to work.
Co-authored-by: Jonas Schievink <[email protected]>
Co-authored-by: Jonas Schievink <[email protected]>
Diffstat (limited to 'crates/cfg/src/tests.rs')
-rw-r--r-- | crates/cfg/src/tests.rs | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/crates/cfg/src/tests.rs b/crates/cfg/src/tests.rs new file mode 100644 index 000000000..bd0f9ec48 --- /dev/null +++ b/crates/cfg/src/tests.rs | |||
@@ -0,0 +1,193 @@ | |||
1 | use expect_test::{expect, Expect}; | ||
2 | use mbe::ast_to_token_tree; | ||
3 | use syntax::{ast, AstNode}; | ||
4 | |||
5 | use crate::{CfgAtom, CfgExpr, CfgOptions, DnfExpr}; | ||
6 | |||
7 | fn assert_parse_result(input: &str, expected: CfgExpr) { | ||
8 | let (tt, _) = { | ||
9 | let source_file = ast::SourceFile::parse(input).ok().unwrap(); | ||
10 | let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); | ||
11 | ast_to_token_tree(&tt).unwrap() | ||
12 | }; | ||
13 | let cfg = CfgExpr::parse(&tt); | ||
14 | assert_eq!(cfg, expected); | ||
15 | } | ||
16 | |||
17 | fn check_dnf(input: &str, expect: Expect) { | ||
18 | let (tt, _) = { | ||
19 | let source_file = ast::SourceFile::parse(input).ok().unwrap(); | ||
20 | let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); | ||
21 | ast_to_token_tree(&tt).unwrap() | ||
22 | }; | ||
23 | let cfg = CfgExpr::parse(&tt); | ||
24 | let actual = format!("#![cfg({})]", DnfExpr::new(cfg)); | ||
25 | expect.assert_eq(&actual); | ||
26 | } | ||
27 | |||
28 | fn check_why_inactive(input: &str, opts: &CfgOptions, expect: Expect) { | ||
29 | let (tt, _) = { | ||
30 | let source_file = ast::SourceFile::parse(input).ok().unwrap(); | ||
31 | let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); | ||
32 | ast_to_token_tree(&tt).unwrap() | ||
33 | }; | ||
34 | let cfg = CfgExpr::parse(&tt); | ||
35 | let dnf = DnfExpr::new(cfg); | ||
36 | let why_inactive = dnf.why_inactive(opts).unwrap().to_string(); | ||
37 | expect.assert_eq(&why_inactive); | ||
38 | } | ||
39 | |||
40 | #[track_caller] | ||
41 | fn check_enable_hints(input: &str, opts: &CfgOptions, expected_hints: &[&str]) { | ||
42 | let (tt, _) = { | ||
43 | let source_file = ast::SourceFile::parse(input).ok().unwrap(); | ||
44 | let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); | ||
45 | ast_to_token_tree(&tt).unwrap() | ||
46 | }; | ||
47 | let cfg = CfgExpr::parse(&tt); | ||
48 | let dnf = DnfExpr::new(cfg); | ||
49 | let hints = dnf.compute_enable_hints(opts).map(|diff| diff.to_string()).collect::<Vec<_>>(); | ||
50 | assert_eq!(hints, expected_hints); | ||
51 | } | ||
52 | |||
53 | #[test] | ||
54 | fn test_cfg_expr_parser() { | ||
55 | assert_parse_result("#![cfg(foo)]", CfgAtom::Flag("foo".into()).into()); | ||
56 | assert_parse_result("#![cfg(foo,)]", CfgAtom::Flag("foo".into()).into()); | ||
57 | assert_parse_result( | ||
58 | "#![cfg(not(foo))]", | ||
59 | CfgExpr::Not(Box::new(CfgAtom::Flag("foo".into()).into())), | ||
60 | ); | ||
61 | assert_parse_result("#![cfg(foo(bar))]", CfgExpr::Invalid); | ||
62 | |||
63 | // Only take the first | ||
64 | assert_parse_result(r#"#![cfg(foo, bar = "baz")]"#, CfgAtom::Flag("foo".into()).into()); | ||
65 | |||
66 | assert_parse_result( | ||
67 | r#"#![cfg(all(foo, bar = "baz"))]"#, | ||
68 | CfgExpr::All(vec![ | ||
69 | CfgAtom::Flag("foo".into()).into(), | ||
70 | CfgAtom::KeyValue { key: "bar".into(), value: "baz".into() }.into(), | ||
71 | ]), | ||
72 | ); | ||
73 | |||
74 | assert_parse_result( | ||
75 | r#"#![cfg(any(not(), all(), , bar = "baz",))]"#, | ||
76 | CfgExpr::Any(vec![ | ||
77 | CfgExpr::Not(Box::new(CfgExpr::Invalid)), | ||
78 | CfgExpr::All(vec![]), | ||
79 | CfgExpr::Invalid, | ||
80 | CfgAtom::KeyValue { key: "bar".into(), value: "baz".into() }.into(), | ||
81 | ]), | ||
82 | ); | ||
83 | } | ||
84 | |||
85 | #[test] | ||
86 | fn smoke() { | ||
87 | check_dnf("#![cfg(test)]", expect![[r#"#![cfg(test)]"#]]); | ||
88 | check_dnf("#![cfg(not(test))]", expect![[r#"#![cfg(not(test))]"#]]); | ||
89 | check_dnf("#![cfg(not(not(test)))]", expect![[r#"#![cfg(test)]"#]]); | ||
90 | |||
91 | check_dnf("#![cfg(all(a, b))]", expect![[r#"#![cfg(all(a, b))]"#]]); | ||
92 | check_dnf("#![cfg(any(a, b))]", expect![[r#"#![cfg(any(a, b))]"#]]); | ||
93 | |||
94 | check_dnf("#![cfg(not(a))]", expect![[r#"#![cfg(not(a))]"#]]); | ||
95 | } | ||
96 | |||
97 | #[test] | ||
98 | fn distribute() { | ||
99 | check_dnf("#![cfg(all(any(a, b), c))]", expect![[r#"#![cfg(any(all(a, c), all(b, c)))]"#]]); | ||
100 | check_dnf("#![cfg(all(c, any(a, b)))]", expect![[r#"#![cfg(any(all(c, a), all(c, b)))]"#]]); | ||
101 | check_dnf( | ||
102 | "#![cfg(all(any(a, b), any(c, d)))]", | ||
103 | expect![[r#"#![cfg(any(all(a, c), all(a, d), all(b, c), all(b, d)))]"#]], | ||
104 | ); | ||
105 | |||
106 | check_dnf( | ||
107 | "#![cfg(all(any(a, b, c), any(d, e, f), g))]", | ||
108 | expect![[ | ||
109 | r#"#![cfg(any(all(a, d, g), all(a, e, g), all(a, f, g), all(b, d, g), all(b, e, g), all(b, f, g), all(c, d, g), all(c, e, g), all(c, f, g)))]"# | ||
110 | ]], | ||
111 | ); | ||
112 | } | ||
113 | |||
114 | #[test] | ||
115 | fn demorgan() { | ||
116 | check_dnf("#![cfg(not(all(a, b)))]", expect![[r#"#![cfg(any(not(a), not(b)))]"#]]); | ||
117 | check_dnf("#![cfg(not(any(a, b)))]", expect![[r#"#![cfg(all(not(a), not(b)))]"#]]); | ||
118 | |||
119 | check_dnf("#![cfg(not(all(not(a), b)))]", expect![[r#"#![cfg(any(a, not(b)))]"#]]); | ||
120 | check_dnf("#![cfg(not(any(a, not(b))))]", expect![[r#"#![cfg(all(not(a), b))]"#]]); | ||
121 | } | ||
122 | |||
123 | #[test] | ||
124 | fn nested() { | ||
125 | check_dnf("#![cfg(all(any(a), not(all(any(b)))))]", expect![[r#"#![cfg(all(a, not(b)))]"#]]); | ||
126 | |||
127 | check_dnf("#![cfg(any(any(a, b)))]", expect![[r#"#![cfg(any(a, b))]"#]]); | ||
128 | check_dnf("#![cfg(not(any(any(a, b))))]", expect![[r#"#![cfg(all(not(a), not(b)))]"#]]); | ||
129 | check_dnf("#![cfg(all(all(a, b)))]", expect![[r#"#![cfg(all(a, b))]"#]]); | ||
130 | check_dnf("#![cfg(not(all(all(a, b))))]", expect![[r#"#![cfg(any(not(a), not(b)))]"#]]); | ||
131 | } | ||
132 | |||
133 | #[test] | ||
134 | fn hints() { | ||
135 | let mut opts = CfgOptions::default(); | ||
136 | |||
137 | check_enable_hints("#![cfg(test)]", &opts, &["enable test"]); | ||
138 | check_enable_hints("#![cfg(not(test))]", &opts, &[]); | ||
139 | |||
140 | check_enable_hints("#![cfg(any(a, b))]", &opts, &["enable a", "enable b"]); | ||
141 | check_enable_hints("#![cfg(any(b, a))]", &opts, &["enable b", "enable a"]); | ||
142 | |||
143 | check_enable_hints("#![cfg(all(a, b))]", &opts, &["enable a and b"]); | ||
144 | |||
145 | opts.insert_atom("test".into()); | ||
146 | |||
147 | check_enable_hints("#![cfg(test)]", &opts, &[]); | ||
148 | check_enable_hints("#![cfg(not(test))]", &opts, &["disable test"]); | ||
149 | } | ||
150 | |||
151 | /// Tests that we don't suggest hints for cfgs that express an inconsistent formula. | ||
152 | #[test] | ||
153 | fn hints_impossible() { | ||
154 | let mut opts = CfgOptions::default(); | ||
155 | |||
156 | check_enable_hints("#![cfg(all(test, not(test)))]", &opts, &[]); | ||
157 | |||
158 | opts.insert_atom("test".into()); | ||
159 | |||
160 | check_enable_hints("#![cfg(all(test, not(test)))]", &opts, &[]); | ||
161 | } | ||
162 | |||
163 | #[test] | ||
164 | fn why_inactive() { | ||
165 | let mut opts = CfgOptions::default(); | ||
166 | opts.insert_atom("test".into()); | ||
167 | opts.insert_atom("test2".into()); | ||
168 | |||
169 | check_why_inactive("#![cfg(a)]", &opts, expect![["a is disabled"]]); | ||
170 | check_why_inactive("#![cfg(not(test))]", &opts, expect![["test is enabled"]]); | ||
171 | |||
172 | check_why_inactive( | ||
173 | "#![cfg(all(not(test), not(test2)))]", | ||
174 | &opts, | ||
175 | expect![["test and test2 are enabled"]], | ||
176 | ); | ||
177 | check_why_inactive("#![cfg(all(a, b))]", &opts, expect![["a and b are disabled"]]); | ||
178 | check_why_inactive( | ||
179 | "#![cfg(all(not(test), a))]", | ||
180 | &opts, | ||
181 | expect![["test is enabled and a is disabled"]], | ||
182 | ); | ||
183 | check_why_inactive( | ||
184 | "#![cfg(all(not(test), test2, a))]", | ||
185 | &opts, | ||
186 | expect![["test is enabled and a is disabled"]], | ||
187 | ); | ||
188 | check_why_inactive( | ||
189 | "#![cfg(all(not(test), not(test2), a))]", | ||
190 | &opts, | ||
191 | expect![["test and test2 are enabled and a is disabled"]], | ||
192 | ); | ||
193 | } | ||