use cargo_platform::{Cfg, CfgExpr, Platform};
use std::fmt;
use std::str::FromStr;
macro_rules! c {
($a:ident) => {
Cfg::Name(stringify!($a).to_string())
};
($a:ident = $e:expr) => {
Cfg::KeyPair(stringify!($a).to_string(), $e.to_string())
};
}
macro_rules! e {
(any($($t:tt),*)) => (CfgExpr::Any(vec![$(e!($t)),*]));
(all($($t:tt),*)) => (CfgExpr::All(vec![$(e!($t)),*]));
(not($($t:tt)*)) => (CfgExpr::Not(Box ::new(e!($($t)*))));
(($($t:tt)*)) => (e!($($t)*));
($($t:tt)*) => (CfgExpr::Value(c!($($t)*)));
}
fn good<T>(s: &str, expected: T)
where
T: FromStr + PartialEq + fmt::Debug,
T::Err: fmt::Display,
{
let c = match T::from_str(s) {
Ok(c) => c,
Err(e) => panic!("failed to parse `{}`: {}" , s, e),
};
assert_eq!(c, expected);
}
fn bad<T>(s: &str, err: &str)
where
T: FromStr + fmt::Display,
T::Err: fmt::Display,
{
let e = match T::from_str(s) {
Ok(cfg) => panic!("expected `{}` to not parse but got {}" , s, cfg),
Err(e) => e.to_string(),
};
assert!(
e.contains(err),
"when parsing `{}`,\n\" {}\" not contained \
inside: {}",
s,
err,
e
);
}
#[ test]
fn cfg_syntax() {
good("foo" , c!(foo));
good("_bar" , c!(_bar));
good(" foo" , c!(foo));
good(" foo " , c!(foo));
good(" foo = \" bar\"" , c!(foo = "bar" ));
good("foo=\" \"" , c!(foo = "" ));
good(" foo=\" 3 \" " , c!(foo = "3" ));
good("foo = \" 3 e\"" , c!(foo = "3 e" ));
}
#[ test]
fn cfg_syntax_bad() {
bad::<Cfg>("" , "but cfg expression ended" );
bad::<Cfg>(" " , "but cfg expression ended" );
bad::<Cfg>("\t" , "unexpected character" );
bad::<Cfg>("7" , "unexpected character" );
bad::<Cfg>("=" , "expected identifier" );
bad::<Cfg>("," , "expected identifier" );
bad::<Cfg>("(" , "expected identifier" );
bad::<Cfg>("foo (" , "unexpected content `(` found after cfg expression" );
bad::<Cfg>("bar =" , "expected a string" );
bad::<Cfg>("bar = \" ", " unterminated string");
bad::<Cfg>(
"foo, bar" ,
"unexpected content `, bar` found after cfg expression" ,
);
}
#[ test]
fn cfg_expr() {
good("foo" , e!(foo));
good("_bar" , e!(_bar));
good(" foo" , e!(foo));
good(" foo " , e!(foo));
good(" foo = \" bar\"" , e!(foo = "bar" ));
good("foo=\" \"" , e!(foo = "" ));
good(" foo=\" 3 \" " , e!(foo = "3" ));
good("foo = \" 3 e\"" , e!(foo = "3 e" ));
good("all()" , e!(all()));
good("all(a)" , e!(all(a)));
good("all(a, b)" , e!(all(a, b)));
good("all(a, )" , e!(all(a)));
good("not(a = \" b\")" , e!(not(a = "b" )));
good("not(all(a))" , e!(not(all(a))));
}
#[ test]
fn cfg_expr_bad() {
bad::<CfgExpr>(" " , "but cfg expression ended" );
bad::<CfgExpr>(" all" , "expected `(`" );
bad::<CfgExpr>("all(a" , "expected `)`" );
bad::<CfgExpr>("not" , "expected `(`" );
bad::<CfgExpr>("not(a" , "expected `)`" );
bad::<CfgExpr>("a = " , "expected a string" );
bad::<CfgExpr>("all(not())" , "expected identifier" );
bad::<CfgExpr>(
"foo(a)" ,
"unexpected content `(a)` found after cfg expression" ,
);
}
#[ test]
fn cfg_matches() {
assert!(e!(foo).matches(&[c!(bar), c!(foo), c!(baz)]));
assert!(e!(any(foo)).matches(&[c!(bar), c!(foo), c!(baz)]));
assert!(e!(any(foo, bar)).matches(&[c!(bar)]));
assert!(e!(any(foo, bar)).matches(&[c!(foo)]));
assert!(e!(all(foo, bar)).matches(&[c!(foo), c!(bar)]));
assert!(e!(all(foo, bar)).matches(&[c!(foo), c!(bar)]));
assert!(e!(not(foo)).matches(&[c!(bar)]));
assert!(e!(not(foo)).matches(&[]));
assert!(e!(any((not(foo)), (all(foo, bar)))).matches(&[c!(bar)]));
assert!(e!(any((not(foo)), (all(foo, bar)))).matches(&[c!(foo), c!(bar)]));
assert!(!e!(foo).matches(&[]));
assert!(!e!(foo).matches(&[c!(bar)]));
assert!(!e!(foo).matches(&[c!(fo)]));
assert!(!e!(any(foo)).matches(&[]));
assert!(!e!(any(foo)).matches(&[c!(bar)]));
assert!(!e!(any(foo)).matches(&[c!(bar), c!(baz)]));
assert!(!e!(all(foo)).matches(&[c!(bar), c!(baz)]));
assert!(!e!(all(foo, bar)).matches(&[c!(bar)]));
assert!(!e!(all(foo, bar)).matches(&[c!(foo)]));
assert!(!e!(all(foo, bar)).matches(&[]));
assert!(!e!(not(bar)).matches(&[c!(bar)]));
assert!(!e!(not(bar)).matches(&[c!(baz), c!(bar)]));
assert!(!e!(any((not(foo)), (all(foo, bar)))).matches(&[c!(foo)]));
}
#[ test]
fn bad_target_name() {
bad::<Platform>(
"any(cfg(unix), cfg(windows))" ,
"failed to parse `any(cfg(unix), cfg(windows))` as a cfg expression: \
invalid target specifier: unexpected `(` character, \
cfg expressions must start with `cfg(`",
);
bad::<Platform>(
"!foo" ,
"failed to parse `!foo` as a cfg expression: \
invalid target specifier: unexpected character ! in target name",
);
}
#[ test]
fn round_trip_platform() {
fn rt(s: &str) {
let p = Platform::from_str(s).unwrap();
let s2 = p.to_string();
let p2 = Platform::from_str(&s2).unwrap();
assert_eq!(p, p2);
}
rt("x86_64-apple-darwin" );
rt("foo" );
rt("cfg(windows)" );
rt("cfg(target_os = \" windows\")" );
rt(
"cfg(any(all(any(target_os = \" android\", target_os = \" linux\"), \
any(target_arch = \"aarch64\" , target_arch = \"arm\" , target_arch = \"powerpc64\" , \
target_arch = \"x86\" , target_arch = \"x86_64\" )), \
all(target_os = \"freebsd\" , target_arch = \"x86_64\" )))",
);
}
#[ test]
fn check_cfg_attributes() {
fn ok(s: &str) {
let p = Platform::Cfg(s.parse().unwrap());
let mut warnings = Vec::new();
p.check_cfg_attributes(&mut warnings);
assert!(
warnings.is_empty(),
"Expected no warnings but got: {:?}" ,
warnings,
);
}
fn warn(s: &str, names: &[&str]) {
let p = Platform::Cfg(s.parse().unwrap());
let mut warnings = Vec::new();
p.check_cfg_attributes(&mut warnings);
assert_eq!(
warnings.len(),
names.len(),
"Expecter warnings about {:?} but got {:?}" ,
names,
warnings,
);
for (name, warning) in names.iter().zip(warnings.iter()) {
assert!(
warning.contains(name),
"Expected warning about '{}' but got: {}" ,
name,
warning,
);
}
}
ok("unix" );
ok("windows" );
ok("any(not(unix), windows)" );
ok("foo" );
ok("target_arch = \" abc\"" );
ok("target_feature = \" abc\"" );
ok("target_os = \" abc\"" );
ok("target_family = \" abc\"" );
ok("target_env = \" abc\"" );
ok("target_endian = \" abc\"" );
ok("target_pointer_width = \" abc\"" );
ok("target_vendor = \" abc\"" );
ok("bar = \" def\"" );
warn("test" , &["test" ]);
warn("debug_assertions" , &["debug_assertions" ]);
warn("proc_macro" , &["proc_macro" ]);
warn("feature = \" abc\"" , &["feature" ]);
warn("any(not(debug_assertions), windows)" , &["debug_assertions" ]);
warn(
"any(not(feature = \" def\"), target_arch = \" abc\")" ,
&["feature" ],
);
warn(
"any(not(target_os = \" windows\"), proc_macro)" ,
&["proc_macro" ],
);
warn(
"any(not(feature = \" windows\"), proc_macro)" ,
&["feature" , "proc_macro" ],
);
warn(
"all(not(debug_assertions), any(windows, proc_macro))" ,
&["debug_assertions" , "proc_macro" ],
);
}
Messung V0.5 in Prozent C=100 H=100 G=100
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-06-20)
¤
*© Formatika GbR, Deutschland