1 use cargo_platform::{Cfg, CfgExpr, Platform};
7 Cfg::Name(stringify!($a).to_string())
9 ($a:ident = $e:expr) => {
10 Cfg::KeyPair(stringify!($a).to_string(), $e.to_string())
15 (any($($t:tt),*)) => (CfgExpr::Any(vec![$(e!($t)),*]));
16 (all($($t:tt),*)) => (CfgExpr::All(vec![$(e!($t)),*]));
17 (not($($t:tt)*)) => (CfgExpr::Not(Box::new(e!($($t)*))));
18 (($($t:tt)*)) => (e!($($t)*));
19 ($($t:tt)*) => (CfgExpr::Value(c!($($t)*)));
22 fn good<T>(s: &str, expected: T)
24 T: FromStr + PartialEq + fmt::Debug,
27 let c = match T::from_str(s) {
29 Err(e) => panic!("failed to parse `{}`: {}", s, e),
31 assert_eq!(c, expected);
34 fn bad<T>(s: &str, err: &str)
36 T: FromStr + fmt::Display,
39 let e = match T::from_str(s) {
40 Ok(cfg) => panic!("expected `{}` to not parse but got {}", s, cfg),
41 Err(e) => e.to_string(),
45 "when parsing `{}`,\n\"{}\" not contained \
56 good("_bar", c!(_bar));
57 good(" foo", c!(foo));
58 good(" foo ", c!(foo));
59 good(" foo = \"bar\"", c!(foo = "bar"));
60 good("foo=\"\"", c!(foo = ""));
61 good(" foo=\"3\" ", c!(foo = "3"));
62 good("foo = \"3 e\"", c!(foo = "3 e"));
67 bad::<Cfg>("", "but cfg expression ended");
68 bad::<Cfg>(" ", "but cfg expression ended");
69 bad::<Cfg>("\t", "unexpected character");
70 bad::<Cfg>("7", "unexpected character");
71 bad::<Cfg>("=", "expected identifier");
72 bad::<Cfg>(",", "expected identifier");
73 bad::<Cfg>("(", "expected identifier");
74 bad::<Cfg>("foo (", "unexpected content `(` found after cfg expression");
75 bad::<Cfg>("bar =", "expected a string");
76 bad::<Cfg>("bar = \"", "unterminated string");
79 "unexpected content `, bar` found after cfg expression",
86 good("_bar", e!(_bar));
87 good(" foo", e!(foo));
88 good(" foo ", e!(foo));
89 good(" foo = \"bar\"", e!(foo = "bar"));
90 good("foo=\"\"", e!(foo = ""));
91 good(" foo=\"3\" ", e!(foo = "3"));
92 good("foo = \"3 e\"", e!(foo = "3 e"));
94 good("all()", e!(all()));
95 good("all(a)", e!(all(a)));
96 good("all(a, b)", e!(all(a, b)));
97 good("all(a, )", e!(all(a)));
98 good("not(a = \"b\")", e!(not(a = "b")));
99 good("not(all(a))", e!(not(all(a))));
104 bad::<CfgExpr>(" ", "but cfg expression ended");
105 bad::<CfgExpr>(" all", "expected `(`");
106 bad::<CfgExpr>("all(a", "expected `)`");
107 bad::<CfgExpr>("not", "expected `(`");
108 bad::<CfgExpr>("not(a", "expected `)`");
109 bad::<CfgExpr>("a = ", "expected a string");
110 bad::<CfgExpr>("all(not())", "expected identifier");
113 "unexpected content `(a)` found after cfg expression",
119 assert!(e!(foo).matches(&[c!(bar), c!(foo), c!(baz)]));
120 assert!(e!(any(foo)).matches(&[c!(bar), c!(foo), c!(baz)]));
121 assert!(e!(any(foo, bar)).matches(&[c!(bar)]));
122 assert!(e!(any(foo, bar)).matches(&[c!(foo)]));
123 assert!(e!(all(foo, bar)).matches(&[c!(foo), c!(bar)]));
124 assert!(e!(all(foo, bar)).matches(&[c!(foo), c!(bar)]));
125 assert!(e!(not(foo)).matches(&[c!(bar)]));
126 assert!(e!(not(foo)).matches(&[]));
127 assert!(e!(any((not(foo)), (all(foo, bar)))).matches(&[c!(bar)]));
128 assert!(e!(any((not(foo)), (all(foo, bar)))).matches(&[c!(foo), c!(bar)]));
130 assert!(!e!(foo).matches(&[]));
131 assert!(!e!(foo).matches(&[c!(bar)]));
132 assert!(!e!(foo).matches(&[c!(fo)]));
133 assert!(!e!(any(foo)).matches(&[]));
134 assert!(!e!(any(foo)).matches(&[c!(bar)]));
135 assert!(!e!(any(foo)).matches(&[c!(bar), c!(baz)]));
136 assert!(!e!(all(foo)).matches(&[c!(bar), c!(baz)]));
137 assert!(!e!(all(foo, bar)).matches(&[c!(bar)]));
138 assert!(!e!(all(foo, bar)).matches(&[c!(foo)]));
139 assert!(!e!(all(foo, bar)).matches(&[]));
140 assert!(!e!(not(bar)).matches(&[c!(bar)]));
141 assert!(!e!(not(bar)).matches(&[c!(baz), c!(bar)]));
142 assert!(!e!(any((not(foo)), (all(foo, bar)))).matches(&[c!(foo)]));
146 fn bad_target_name() {
148 "any(cfg(unix), cfg(windows))",
149 "failed to parse `any(cfg(unix), cfg(windows))` as a cfg expression: \
150 invalid target specifier: unexpected `(` character, \
151 cfg expressions must start with `cfg(`",
155 "failed to parse `!foo` as a cfg expression: \
156 invalid target specifier: unexpected character ! in target name",
161 fn round_trip_platform() {
163 let p = Platform::from_str(s).unwrap();
164 let s2 = p.to_string();
165 let p2 = Platform::from_str(&s2).unwrap();
168 rt("x86_64-apple-darwin");
171 rt("cfg(target_os = \"windows\")");
173 "cfg(any(all(any(target_os = \"android\", target_os = \"linux\"), \
174 any(target_arch = \"aarch64\", target_arch = \"arm\", target_arch = \"powerpc64\", \
175 target_arch = \"x86\", target_arch = \"x86_64\")), \
176 all(target_os = \"freebsd\", target_arch = \"x86_64\")))",
181 fn check_cfg_attributes() {
183 let p = Platform::Cfg(s.parse().unwrap());
184 let mut warnings = Vec::new();
185 p.check_cfg_attributes(&mut warnings);
188 "Expected no warnings but got: {:?}",
193 fn warn(s: &str, names: &[&str]) {
194 let p = Platform::Cfg(s.parse().unwrap());
195 let mut warnings = Vec::new();
196 p.check_cfg_attributes(&mut warnings);
200 "Expecter warnings about {:?} but got {:?}",
204 for (name, warning) in names.iter().zip(warnings.iter()) {
206 warning.contains(name),
207 "Expected warning about '{}' but got: {}",
216 ok("any(not(unix), windows)");
219 ok("target_arch = \"abc\"");
220 ok("target_feature = \"abc\"");
221 ok("target_os = \"abc\"");
222 ok("target_family = \"abc\"");
223 ok("target_env = \"abc\"");
224 ok("target_endian = \"abc\"");
225 ok("target_pointer_width = \"abc\"");
226 ok("target_vendor = \"abc\"");
229 warn("test", &["test"]);
230 warn("debug_assertions", &["debug_assertions"]);
231 warn("proc_macro", &["proc_macro"]);
232 warn("feature = \"abc\"", &["feature"]);
234 warn("any(not(debug_assertions), windows)", &["debug_assertions"]);
236 "any(not(feature = \"def\"), target_arch = \"abc\")",
240 "any(not(target_os = \"windows\"), proc_macro)",
244 "any(not(feature = \"windows\"), proc_macro)",
245 &["feature", "proc_macro"],
248 "all(not(debug_assertions), any(windows, proc_macro))",
249 &["debug_assertions", "proc_macro"],