From a246d4f599dcf2612fa99720fb4ca98101ed93fb Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 23 Oct 2020 12:14:58 +0200 Subject: cfg: move tests to separate file that way we don't have to re-check the entire project when a test is changed --- crates/cfg/src/cfg_expr.rs | 50 ------------ crates/cfg/src/dnf.rs | 158 ------------------------------------- crates/cfg/src/lib.rs | 2 + crates/cfg/src/tests.rs | 193 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 195 insertions(+), 208 deletions(-) create mode 100644 crates/cfg/src/tests.rs diff --git a/crates/cfg/src/cfg_expr.rs b/crates/cfg/src/cfg_expr.rs index 283ff968f..42327f1e1 100644 --- a/crates/cfg/src/cfg_expr.rs +++ b/crates/cfg/src/cfg_expr.rs @@ -128,53 +128,3 @@ fn next_cfg_expr(it: &mut SliceIter) -> Option { } Some(ret) } - -#[cfg(test)] -mod tests { - use super::*; - - use mbe::ast_to_token_tree; - use syntax::ast::{self, AstNode}; - - fn assert_parse_result(input: &str, expected: CfgExpr) { - let (tt, _) = { - let source_file = ast::SourceFile::parse(input).ok().unwrap(); - let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); - ast_to_token_tree(&tt).unwrap() - }; - let cfg = CfgExpr::parse(&tt); - assert_eq!(cfg, expected); - } - - #[test] - fn test_cfg_expr_parser() { - assert_parse_result("#![cfg(foo)]", CfgAtom::Flag("foo".into()).into()); - assert_parse_result("#![cfg(foo,)]", CfgAtom::Flag("foo".into()).into()); - assert_parse_result( - "#![cfg(not(foo))]", - CfgExpr::Not(Box::new(CfgAtom::Flag("foo".into()).into())), - ); - assert_parse_result("#![cfg(foo(bar))]", CfgExpr::Invalid); - - // Only take the first - assert_parse_result(r#"#![cfg(foo, bar = "baz")]"#, CfgAtom::Flag("foo".into()).into()); - - assert_parse_result( - r#"#![cfg(all(foo, bar = "baz"))]"#, - CfgExpr::All(vec![ - CfgAtom::Flag("foo".into()).into(), - CfgAtom::KeyValue { key: "bar".into(), value: "baz".into() }.into(), - ]), - ); - - assert_parse_result( - r#"#![cfg(any(not(), all(), , bar = "baz",))]"#, - CfgExpr::Any(vec![ - CfgExpr::Not(Box::new(CfgExpr::Invalid)), - CfgExpr::All(vec![]), - CfgExpr::Invalid, - CfgAtom::KeyValue { key: "bar".into(), value: "baz".into() }.into(), - ]), - ); - } -} diff --git a/crates/cfg/src/dnf.rs b/crates/cfg/src/dnf.rs index 7ee7b0062..580c9a9a2 100644 --- a/crates/cfg/src/dnf.rs +++ b/crates/cfg/src/dnf.rs @@ -318,161 +318,3 @@ fn make_nnf(expr: CfgExpr) -> CfgExpr { }, } } - -#[cfg(test)] -mod test { - use expect_test::{expect, Expect}; - use mbe::ast_to_token_tree; - use syntax::{ast, AstNode}; - - use super::*; - - fn check_dnf(input: &str, expect: Expect) { - let (tt, _) = { - let source_file = ast::SourceFile::parse(input).ok().unwrap(); - let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); - ast_to_token_tree(&tt).unwrap() - }; - let cfg = CfgExpr::parse(&tt); - let actual = format!("#![cfg({})]", DnfExpr::new(cfg)); - expect.assert_eq(&actual); - } - - fn check_why_inactive(input: &str, opts: &CfgOptions, expect: Expect) { - let (tt, _) = { - let source_file = ast::SourceFile::parse(input).ok().unwrap(); - let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); - ast_to_token_tree(&tt).unwrap() - }; - let cfg = CfgExpr::parse(&tt); - let dnf = DnfExpr::new(cfg); - let why_inactive = dnf.why_inactive(opts).unwrap().to_string(); - expect.assert_eq(&why_inactive); - } - - #[track_caller] - fn check_enable_hints(input: &str, opts: &CfgOptions, expected_hints: &[&str]) { - let (tt, _) = { - let source_file = ast::SourceFile::parse(input).ok().unwrap(); - let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); - ast_to_token_tree(&tt).unwrap() - }; - let cfg = CfgExpr::parse(&tt); - let dnf = DnfExpr::new(cfg); - let hints = dnf.compute_enable_hints(opts).map(|diff| diff.to_string()).collect::>(); - assert_eq!(hints, expected_hints); - } - - #[test] - fn smoke() { - check_dnf("#![cfg(test)]", expect![[r#"#![cfg(test)]"#]]); - check_dnf("#![cfg(not(test))]", expect![[r#"#![cfg(not(test))]"#]]); - check_dnf("#![cfg(not(not(test)))]", expect![[r#"#![cfg(test)]"#]]); - - check_dnf("#![cfg(all(a, b))]", expect![[r#"#![cfg(all(a, b))]"#]]); - check_dnf("#![cfg(any(a, b))]", expect![[r#"#![cfg(any(a, b))]"#]]); - - check_dnf("#![cfg(not(a))]", expect![[r#"#![cfg(not(a))]"#]]); - } - - #[test] - fn distribute() { - check_dnf("#![cfg(all(any(a, b), c))]", expect![[r#"#![cfg(any(all(a, c), all(b, c)))]"#]]); - check_dnf("#![cfg(all(c, any(a, b)))]", expect![[r#"#![cfg(any(all(c, a), all(c, b)))]"#]]); - check_dnf( - "#![cfg(all(any(a, b), any(c, d)))]", - expect![[r#"#![cfg(any(all(a, c), all(a, d), all(b, c), all(b, d)))]"#]], - ); - - check_dnf( - "#![cfg(all(any(a, b, c), any(d, e, f), g))]", - expect![[ - 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)))]"# - ]], - ); - } - - #[test] - fn demorgan() { - check_dnf("#![cfg(not(all(a, b)))]", expect![[r#"#![cfg(any(not(a), not(b)))]"#]]); - check_dnf("#![cfg(not(any(a, b)))]", expect![[r#"#![cfg(all(not(a), not(b)))]"#]]); - - check_dnf("#![cfg(not(all(not(a), b)))]", expect![[r#"#![cfg(any(a, not(b)))]"#]]); - check_dnf("#![cfg(not(any(a, not(b))))]", expect![[r#"#![cfg(all(not(a), b))]"#]]); - } - - #[test] - fn nested() { - check_dnf( - "#![cfg(all(any(a), not(all(any(b)))))]", - expect![[r#"#![cfg(all(a, not(b)))]"#]], - ); - - check_dnf("#![cfg(any(any(a, b)))]", expect![[r#"#![cfg(any(a, b))]"#]]); - check_dnf("#![cfg(not(any(any(a, b))))]", expect![[r#"#![cfg(all(not(a), not(b)))]"#]]); - check_dnf("#![cfg(all(all(a, b)))]", expect![[r#"#![cfg(all(a, b))]"#]]); - check_dnf("#![cfg(not(all(all(a, b))))]", expect![[r#"#![cfg(any(not(a), not(b)))]"#]]); - } - - #[test] - fn hints() { - let mut opts = CfgOptions::default(); - - check_enable_hints("#![cfg(test)]", &opts, &["enable test"]); - check_enable_hints("#![cfg(not(test))]", &opts, &[]); - - check_enable_hints("#![cfg(any(a, b))]", &opts, &["enable a", "enable b"]); - check_enable_hints("#![cfg(any(b, a))]", &opts, &["enable b", "enable a"]); - - check_enable_hints("#![cfg(all(a, b))]", &opts, &["enable a and b"]); - - opts.insert_atom("test".into()); - - check_enable_hints("#![cfg(test)]", &opts, &[]); - check_enable_hints("#![cfg(not(test))]", &opts, &["disable test"]); - } - - /// Tests that we don't suggest hints for cfgs that express an inconsistent formula. - #[test] - fn hints_impossible() { - let mut opts = CfgOptions::default(); - - check_enable_hints("#![cfg(all(test, not(test)))]", &opts, &[]); - - opts.insert_atom("test".into()); - - check_enable_hints("#![cfg(all(test, not(test)))]", &opts, &[]); - } - - #[test] - fn why_inactive() { - let mut opts = CfgOptions::default(); - opts.insert_atom("test".into()); - opts.insert_atom("test2".into()); - - check_why_inactive("#![cfg(a)]", &opts, expect![["a is disabled"]]); - check_why_inactive("#![cfg(not(test))]", &opts, expect![["test is enabled"]]); - - check_why_inactive( - "#![cfg(all(not(test), not(test2)))]", - &opts, - expect![["test and test2 are enabled"]], - ); - check_why_inactive("#![cfg(all(a, b))]", &opts, expect![["a and b are disabled"]]); - check_why_inactive( - "#![cfg(all(not(test), a))]", - &opts, - expect![["test is enabled and a is disabled"]], - ); - check_why_inactive( - "#![cfg(all(not(test), test2, a))]", - &opts, - expect![["test is enabled and a is disabled"]], - ); - check_why_inactive( - "#![cfg(all(not(test), not(test2), a))]", - &opts, - expect![["test and test2 are enabled and a is disabled"]], - ); - } -} diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs index 28a40a082..d0e08cf5f 100644 --- a/crates/cfg/src/lib.rs +++ b/crates/cfg/src/lib.rs @@ -2,6 +2,8 @@ mod cfg_expr; mod dnf; +#[cfg(test)] +mod tests; use std::fmt; 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 @@ +use expect_test::{expect, Expect}; +use mbe::ast_to_token_tree; +use syntax::{ast, AstNode}; + +use crate::{CfgAtom, CfgExpr, CfgOptions, DnfExpr}; + +fn assert_parse_result(input: &str, expected: CfgExpr) { + let (tt, _) = { + let source_file = ast::SourceFile::parse(input).ok().unwrap(); + let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); + ast_to_token_tree(&tt).unwrap() + }; + let cfg = CfgExpr::parse(&tt); + assert_eq!(cfg, expected); +} + +fn check_dnf(input: &str, expect: Expect) { + let (tt, _) = { + let source_file = ast::SourceFile::parse(input).ok().unwrap(); + let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); + ast_to_token_tree(&tt).unwrap() + }; + let cfg = CfgExpr::parse(&tt); + let actual = format!("#![cfg({})]", DnfExpr::new(cfg)); + expect.assert_eq(&actual); +} + +fn check_why_inactive(input: &str, opts: &CfgOptions, expect: Expect) { + let (tt, _) = { + let source_file = ast::SourceFile::parse(input).ok().unwrap(); + let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); + ast_to_token_tree(&tt).unwrap() + }; + let cfg = CfgExpr::parse(&tt); + let dnf = DnfExpr::new(cfg); + let why_inactive = dnf.why_inactive(opts).unwrap().to_string(); + expect.assert_eq(&why_inactive); +} + +#[track_caller] +fn check_enable_hints(input: &str, opts: &CfgOptions, expected_hints: &[&str]) { + let (tt, _) = { + let source_file = ast::SourceFile::parse(input).ok().unwrap(); + let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); + ast_to_token_tree(&tt).unwrap() + }; + let cfg = CfgExpr::parse(&tt); + let dnf = DnfExpr::new(cfg); + let hints = dnf.compute_enable_hints(opts).map(|diff| diff.to_string()).collect::>(); + assert_eq!(hints, expected_hints); +} + +#[test] +fn test_cfg_expr_parser() { + assert_parse_result("#![cfg(foo)]", CfgAtom::Flag("foo".into()).into()); + assert_parse_result("#![cfg(foo,)]", CfgAtom::Flag("foo".into()).into()); + assert_parse_result( + "#![cfg(not(foo))]", + CfgExpr::Not(Box::new(CfgAtom::Flag("foo".into()).into())), + ); + assert_parse_result("#![cfg(foo(bar))]", CfgExpr::Invalid); + + // Only take the first + assert_parse_result(r#"#![cfg(foo, bar = "baz")]"#, CfgAtom::Flag("foo".into()).into()); + + assert_parse_result( + r#"#![cfg(all(foo, bar = "baz"))]"#, + CfgExpr::All(vec![ + CfgAtom::Flag("foo".into()).into(), + CfgAtom::KeyValue { key: "bar".into(), value: "baz".into() }.into(), + ]), + ); + + assert_parse_result( + r#"#![cfg(any(not(), all(), , bar = "baz",))]"#, + CfgExpr::Any(vec![ + CfgExpr::Not(Box::new(CfgExpr::Invalid)), + CfgExpr::All(vec![]), + CfgExpr::Invalid, + CfgAtom::KeyValue { key: "bar".into(), value: "baz".into() }.into(), + ]), + ); +} + +#[test] +fn smoke() { + check_dnf("#![cfg(test)]", expect![[r#"#![cfg(test)]"#]]); + check_dnf("#![cfg(not(test))]", expect![[r#"#![cfg(not(test))]"#]]); + check_dnf("#![cfg(not(not(test)))]", expect![[r#"#![cfg(test)]"#]]); + + check_dnf("#![cfg(all(a, b))]", expect![[r#"#![cfg(all(a, b))]"#]]); + check_dnf("#![cfg(any(a, b))]", expect![[r#"#![cfg(any(a, b))]"#]]); + + check_dnf("#![cfg(not(a))]", expect![[r#"#![cfg(not(a))]"#]]); +} + +#[test] +fn distribute() { + check_dnf("#![cfg(all(any(a, b), c))]", expect![[r#"#![cfg(any(all(a, c), all(b, c)))]"#]]); + check_dnf("#![cfg(all(c, any(a, b)))]", expect![[r#"#![cfg(any(all(c, a), all(c, b)))]"#]]); + check_dnf( + "#![cfg(all(any(a, b), any(c, d)))]", + expect![[r#"#![cfg(any(all(a, c), all(a, d), all(b, c), all(b, d)))]"#]], + ); + + check_dnf( + "#![cfg(all(any(a, b, c), any(d, e, f), g))]", + expect![[ + 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)))]"# + ]], + ); +} + +#[test] +fn demorgan() { + check_dnf("#![cfg(not(all(a, b)))]", expect![[r#"#![cfg(any(not(a), not(b)))]"#]]); + check_dnf("#![cfg(not(any(a, b)))]", expect![[r#"#![cfg(all(not(a), not(b)))]"#]]); + + check_dnf("#![cfg(not(all(not(a), b)))]", expect![[r#"#![cfg(any(a, not(b)))]"#]]); + check_dnf("#![cfg(not(any(a, not(b))))]", expect![[r#"#![cfg(all(not(a), b))]"#]]); +} + +#[test] +fn nested() { + check_dnf("#![cfg(all(any(a), not(all(any(b)))))]", expect![[r#"#![cfg(all(a, not(b)))]"#]]); + + check_dnf("#![cfg(any(any(a, b)))]", expect![[r#"#![cfg(any(a, b))]"#]]); + check_dnf("#![cfg(not(any(any(a, b))))]", expect![[r#"#![cfg(all(not(a), not(b)))]"#]]); + check_dnf("#![cfg(all(all(a, b)))]", expect![[r#"#![cfg(all(a, b))]"#]]); + check_dnf("#![cfg(not(all(all(a, b))))]", expect![[r#"#![cfg(any(not(a), not(b)))]"#]]); +} + +#[test] +fn hints() { + let mut opts = CfgOptions::default(); + + check_enable_hints("#![cfg(test)]", &opts, &["enable test"]); + check_enable_hints("#![cfg(not(test))]", &opts, &[]); + + check_enable_hints("#![cfg(any(a, b))]", &opts, &["enable a", "enable b"]); + check_enable_hints("#![cfg(any(b, a))]", &opts, &["enable b", "enable a"]); + + check_enable_hints("#![cfg(all(a, b))]", &opts, &["enable a and b"]); + + opts.insert_atom("test".into()); + + check_enable_hints("#![cfg(test)]", &opts, &[]); + check_enable_hints("#![cfg(not(test))]", &opts, &["disable test"]); +} + +/// Tests that we don't suggest hints for cfgs that express an inconsistent formula. +#[test] +fn hints_impossible() { + let mut opts = CfgOptions::default(); + + check_enable_hints("#![cfg(all(test, not(test)))]", &opts, &[]); + + opts.insert_atom("test".into()); + + check_enable_hints("#![cfg(all(test, not(test)))]", &opts, &[]); +} + +#[test] +fn why_inactive() { + let mut opts = CfgOptions::default(); + opts.insert_atom("test".into()); + opts.insert_atom("test2".into()); + + check_why_inactive("#![cfg(a)]", &opts, expect![["a is disabled"]]); + check_why_inactive("#![cfg(not(test))]", &opts, expect![["test is enabled"]]); + + check_why_inactive( + "#![cfg(all(not(test), not(test2)))]", + &opts, + expect![["test and test2 are enabled"]], + ); + check_why_inactive("#![cfg(all(a, b))]", &opts, expect![["a and b are disabled"]]); + check_why_inactive( + "#![cfg(all(not(test), a))]", + &opts, + expect![["test is enabled and a is disabled"]], + ); + check_why_inactive( + "#![cfg(all(not(test), test2, a))]", + &opts, + expect![["test is enabled and a is disabled"]], + ); + check_why_inactive( + "#![cfg(all(not(test), not(test2), a))]", + &opts, + expect![["test and test2 are enabled and a is disabled"]], + ); +} -- cgit v1.2.3