diff --git a/Cargo.toml b/Cargo.toml index 95ea8df4c29..1a361fa1d1b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -203,6 +203,7 @@ libc = "*" regex="*" rand="*" tempdir="*" +choose = { path = "tests/choose" } [[bin]] name = "uutils" diff --git a/tests/choose/Cargo.toml b/tests/choose/Cargo.toml new file mode 100644 index 00000000000..5eb9124c002 --- /dev/null +++ b/tests/choose/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "choose" +version = "0.1.0" +authors = ["Knight "] + +[lib] +plugin = true diff --git a/tests/choose/src/lib.rs b/tests/choose/src/lib.rs new file mode 100644 index 00000000000..6f6c7f3470a --- /dev/null +++ b/tests/choose/src/lib.rs @@ -0,0 +1,121 @@ +#![feature(plugin_registrar, rustc_private)] + +extern crate syntax; +extern crate rustc_plugin; + +use syntax::ast; +use syntax::ptr::P; +use syntax::codemap::Span; +use syntax::parse::{self, token}; +use syntax::tokenstream::TokenTree; +use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; +use syntax::ext::build::AstBuilder; +use syntax::errors::FatalError; +use syntax::util::small_vector::SmallVector; +use rustc_plugin::Registry; + +use ::std::path::Path; +use ::std::path::PathBuf; + +macro_rules! panictry { + ($e:expr) => ({ + match $e { + Ok(e) => e, + Err(mut e) => { + e.emit(); + panic!(FatalError); + } + } + }) +} + +pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, file: &Path) -> Vec> { + let mut p = parse::new_sub_parser_from_file(cx.parse_sess(), cx.cfg(), file, true, None, sp); + let mut ret = vec![]; + while p.token != token::Eof { + match panictry!(p.parse_item()) { + Some(item) => ret.push(item), + None => { + panic!(p.diagnostic().span_fatal(p.span, + &format!("expected item, found `{}`", p.this_token_to_string()))) + } + } + } + ret +} + +fn intern(s: &str) -> token::InternedString { + token::intern_and_get_ident(s) +} + +fn choose(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) -> Box { + let mut parser = cx.new_parser_from_tts(args); + let mut test_mods = SmallVector::zero(); + let cfg_str = intern("cfg"); + let feat_str = intern("feature"); + while !parser.eat(&token::Eof) { + if let Ok(s) = parser.parse_ident() { + let unix_only; + match s.to_string().as_str() { + "unix" => unix_only = true, + "generic" => unix_only = false, + _ => { + cx.span_err(sp, "only `unix` and `generic` are supported now"); + return DummyResult::any(sp); + } + } + parser.eat(&token::FatArrow); + parser.eat(&token::OpenDelim(token::Brace)); + while !parser.eat(&token::CloseDelim(token::Brace)) { + match parser.parse_ident() { + Ok(s) => { + let mod_name = s.to_string(); + let mut attrs = vec![cx.attribute(sp, + cx.meta_list(sp, + cfg_str.clone(), + vec![cx.meta_name_value(sp, + feat_str.clone(), + ast::LitKind::Str(intern(mod_name.trim_left_matches("test_")), ast::StrStyle::Cooked))]))]; + + if unix_only { + attrs.push(cx.attribute(sp, + cx.meta_list(sp, + cfg_str.clone(), + vec![cx.meta_word(sp, intern("unix"))]))); + } + + let mut mod_path = PathBuf::from(&cx.codemap().span_to_filename(sp)); + mod_path.set_file_name(mod_name.as_str()); + mod_path.set_extension("rs"); + test_mods.push(P(ast::Item { + ident: cx.ident_of(mod_name.as_str()), + attrs: attrs, + id: ast::DUMMY_NODE_ID, + node: ast::ItemKind::Mod(ast::Mod { + inner: sp, + items: expand_include(cx, sp, &mod_path), + }), + vis: ast::Visibility::Inherited, + span: sp, + })); + } + _ => { + cx.span_err(sp, "expect a single identifier"); + return DummyResult::any(sp); + } + } + parser.eat(&token::Semi); + parser.eat(&token::Comma); + } + } else { + cx.span_err(sp, "expect a single identifier"); + return DummyResult::any(sp); + } + } + MacEager::items(test_mods) +} + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + reg.register_macro("choose", choose); +} diff --git a/tests/tests.rs b/tests/tests.rs index 3897935e2a1..e5131d7ee23 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,88 +1,71 @@ +#![cfg_attr(test, feature(plugin))] +#![cfg_attr(test, plugin(choose))] + #[macro_use] mod common; -// For conditional compilation -macro_rules! unix_only { - ($($fea:expr, $m:ident);+) => { - $( - #[cfg(unix)] - #[cfg(feature = $fea)] - mod $m; - )+ - }; -} -unix_only! { - "chmod", test_chmod; - "chown", test_chown; - "chgrp", test_chgrp; - "install", test_install; - "mv", test_mv; - "pathchk", test_pathchk; - "pinky", test_pinky; - "stdbuf", test_stdbuf; - "touch", test_touch; - "unlink", test_unlink; - "who", test_who; - // Be aware of the trailing semicolon after the last item - "stat", test_stat -} - - -macro_rules! generic { - ($($fea:expr, $m:ident);+) => { - $( - #[cfg(feature = $fea)] - mod $m; - )+ - }; -} -generic! { - "base32", test_base32; - "base64", test_base64; - "basename", test_basename; - "cat", test_cat; - "cksum", test_cksum; - "comm", test_comm; - "cp", test_cp; - "cut", test_cut; - "dircolors", test_dircolors; - "dirname", test_dirname; - "echo", test_echo; - "env", test_env; - "expr", test_expr; - "factor", test_factor; - "false", test_false; - "fold", test_fold; - "hashsum", test_hashsum; - "head", test_head; - "link", test_link; - "ln", test_ln; - "ls", test_ls; - "mkdir", test_mkdir; - "mktemp", test_mktemp; - "nl", test_nl; - "od", test_od; - "paste", test_paste; - "printf", test_printf; - "ptx", test_ptx; - "pwd", test_pwd; - "readlink", test_readlink; - "realpath", test_realpath; - "rm", test_rm; - "rmdir", test_rmdir; - "seq", test_seq; - "sort", test_sort; - "split", test_split; - "sum", test_sum; - "tac", test_tac; - "tail", test_tail; - "test", test_test; - "tr", test_tr; - "true", test_true; - "truncate", test_truncate; - "tsort", test_tsort; - "unexpand", test_unexpand; - "uniq", test_uniq; - // Be aware of the trailing semicolon after the last item - "wc", test_wc +choose! { + unix => { + test_chmod + test_chown + test_chgrp + test_install + test_mv + test_pathchk + test_pinky + test_stdbuf + test_touch + test_unlink + test_who + test_stat + } + generic => { + test_base32 + test_base64 + test_basename + test_cat + test_cksum + test_comm + test_cp + test_cut + test_dircolors + test_dirname + test_echo + test_env + test_expr + test_factor + test_false + test_fold + test_hashsum + test_head + test_link + test_ln + test_ls + test_mkdir + test_mktemp + test_nl + test_od + test_paste + test_printf + test_ptx + test_pwd + test_readlink + test_realpath + test_rm + test_rmdir + test_seq + test_sort + test_split + test_sum + test_tac + test_tail + test_test + test_tr + test_true + test_truncate + test_tsort + test_unexpand + test_uniq + test_wc + } }