From f7ebe23ae185991b0fee05b32fbb3e29b89a41bf Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 29 Oct 2011 17:35:45 -0700 Subject: [PATCH] Add the ability to ignore tests by compiler config [test] [ignore(cfg(target_os = "win32"))] --- src/comp/front/attr.rs | 8 +++++++ src/comp/front/config.rs | 30 +++++++++++---------------- src/comp/front/test.rs | 17 ++++++++++++--- src/test/run-pass/test-ignore-cfg.rs | 31 ++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 21 deletions(-) create mode 100644 src/test/run-pass/test-ignore-cfg.rs diff --git a/src/comp/front/attr.rs b/src/comp/front/attr.rs index a9da327fcef..61b3032abd2 100644 --- a/src/comp/front/attr.rs +++ b/src/comp/front/attr.rs @@ -18,6 +18,7 @@ export require_unique_names; export get_attr_name; export get_meta_item_name; export get_meta_item_value_str; +export get_meta_item_list; export mk_name_value_item_str; export mk_name_value_item; export mk_list_item; @@ -85,6 +86,13 @@ fn get_meta_item_value_str(meta: @ast::meta_item) -> option::t { } } +fn get_meta_item_list(meta: @ast::meta_item) -> option::t<[@ast::meta_item]> { + alt meta.node { + ast::meta_list(_, l) { option::some(l) } + _ { option::none } + } +} + fn attr_meta(attr: ast::attribute) -> @ast::meta_item { @attr.node.value } // Get the meta_items from inside a vector of attributes diff --git a/src/comp/front/config.rs b/src/comp/front/config.rs index 676f77c95b3..f0eceb093b3 100644 --- a/src/comp/front/config.rs +++ b/src/comp/front/config.rs @@ -3,6 +3,7 @@ import syntax::{ast, fold}; import attr; export strip_unconfigured_items; +export metas_in_cfg; // Support conditional compilation by transforming the AST, stripping out // any items that do not belong in the current configuration @@ -88,31 +89,24 @@ fn native_item_in_cfg(cfg: ast::crate_cfg, item: @ast::native_item) -> bool { // Determine if an item should be translated in the current crate // configuration based on the item's attributes fn in_cfg(cfg: ast::crate_cfg, attrs: [ast::attribute]) -> bool { + metas_in_cfg(cfg, attr::attr_metas(attrs)) +} + +fn metas_in_cfg(cfg: ast::crate_cfg, metas: [@ast::meta_item]) -> bool { // The "cfg" attributes on the item - let item_cfg_attrs = attr::find_attrs_by_name(attrs, "cfg"); - let item_has_cfg_attrs = vec::len(item_cfg_attrs) > 0u; - if !item_has_cfg_attrs { ret true; } + let cfg_metas = attr::find_meta_items_by_name(metas, "cfg"); // Pull the inner meta_items from the #[cfg(meta_item, ...)] attributes, // so we can match against them. This is the list of configurations for // which the item is valid - let item_cfg_metas = { - fn extract_metas(&&inner_items: [@ast::meta_item], - &&cfg_item: @ast::meta_item) -> [@ast::meta_item] { - alt cfg_item.node { - ast::meta_list(name, items) { - assert (name == "cfg"); - inner_items + items - } - _ { inner_items } - } - } - let cfg_metas = attr::attr_metas(item_cfg_attrs); - vec::foldl(extract_metas, [], cfg_metas) - }; + let cfg_metas = vec::concat(vec::filter_map( + {|&&i| attr::get_meta_item_list(i)}, cfg_metas)); - for cfg_mi: @ast::meta_item in item_cfg_metas { + let has_cfg_metas = vec::len(cfg_metas) > 0u; + if !has_cfg_metas { ret true; } + + for cfg_mi: @ast::meta_item in cfg_metas { if attr::contains(cfg, cfg_mi) { ret true; } } diff --git a/src/comp/front/test.rs b/src/comp/front/test.rs index 255a83712f8..7c0d11b8fd6 100644 --- a/src/comp/front/test.rs +++ b/src/comp/front/test.rs @@ -18,6 +18,7 @@ type test = {span: span, path: [ast::ident], ignore: bool}; type test_ctxt = @{sess: session::session, + crate: @ast::crate, next_node_id: node_id_gen, mutable path: [ast::ident], mutable testfns: [test]}; @@ -41,6 +42,7 @@ fn modify_for_testing(sess: session::session, let cx: test_ctxt = @{sess: sess, + crate: crate, next_node_id: next_node_id_fn, mutable path: [], mutable testfns: []}; @@ -102,7 +104,8 @@ fn fold_item(cx: test_ctxt, &&i: @ast::item, fld: fold::ast_fold) -> } _ { log "this is a test function"; - let test = {span: i.span, path: cx.path, ignore: is_ignored(i)}; + let test = {span: i.span, + path: cx.path, ignore: is_ignored(cx, i)}; cx.testfns += [test]; log #fmt["have %u test functions", vec::len(cx.testfns)]; } @@ -133,8 +136,16 @@ fn is_test_fn(i: @ast::item) -> bool { ret has_test_attr && has_test_signature(i); } -fn is_ignored(i: @ast::item) -> bool { - attr::contains_name(attr::attr_metas(i.attrs), "ignore") +fn is_ignored(cx: test_ctxt, i: @ast::item) -> bool { + let ignoreattrs = attr::find_attrs_by_name(i.attrs, "ignore"); + let ignoreitems = attr::attr_metas(ignoreattrs); + let cfg_metas = vec::concat(vec::filter_map( + {|&&i| attr::get_meta_item_list(i)}, ignoreitems)); + ret if vec::is_not_empty(ignoreitems) { + config::metas_in_cfg(cx.crate.node.config, cfg_metas) + } else { + false + } } fn add_test_module(cx: test_ctxt, m: ast::_mod) -> ast::_mod { diff --git a/src/test/run-pass/test-ignore-cfg.rs b/src/test/run-pass/test-ignore-cfg.rs new file mode 100644 index 00000000000..e88987bc2cb --- /dev/null +++ b/src/test/run-pass/test-ignore-cfg.rs @@ -0,0 +1,31 @@ +// compile-flags: --test --cfg ignorecfg +// xfail-fast +// xfail-pretty + +use std; +import std::option; +import std::vec; + +#[test] +#[ignore(cfg(ignorecfg))] +fn shouldignore() { +} + +#[test] +#[ignore(cfg(noignorecfg))] +fn shouldnotignore() { +} + +#[test] +fn checktests() { + // Pull the tests out of the secret test module + let tests = __test::tests(); + + let shouldignore = option::get( + vec::find({|t| t.name == "shouldignore"}, tests)); + assert shouldignore.ignore == true; + + let shouldnotignore = option::get( + vec::find({|t| t.name == "shouldnotignore"}, tests)); + assert shouldnotignore.ignore == false; +} \ No newline at end of file