提交 d27918ac 编写于 作者: S Steven Fackler 提交者: Alex Crichton

Restructure test harness

We now build up a set of modules that reexport everything the test
framework needs, instead of turning off privacy.
上级 456884b7
......@@ -18,6 +18,7 @@
use std::gc::{Gc, GC};
use std::slice;
use std::mem;
use std::vec;
use syntax::ast_util::*;
use syntax::attr::AttrMetaMethods;
......@@ -25,6 +26,7 @@
use syntax::codemap::{DUMMY_SP, Span, ExpnInfo, NameAndSpan, MacroAttribute};
use syntax::codemap;
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::ext::expand::ExpansionConfig;
use syntax::fold::Folder;
use syntax::fold;
......@@ -46,8 +48,10 @@ struct Test {
struct TestCtxt<'a> {
sess: &'a Session,
path: Vec<ast::Ident>,
reexports: Vec<Vec<ast::Ident>>,
ext_cx: ExtCtxt<'a>,
testfns: Vec<Test>,
reexport_mod_ident: ast::Ident,
is_test_crate: bool,
config: ast::CrateConfig,
}
......@@ -107,25 +111,35 @@ fn fold_item(&mut self, i: Gc<ast::Item>) -> SmallVector<Gc<ast::Item>> {
should_fail: should_fail(i)
};
self.cx.testfns.push(test);
self.cx.reexports.push(self.cx.path.clone());
// debug!("have {} test/bench functions",
// cx.testfns.len());
}
}
}
let res = fold::noop_fold_item(&*i, self);
// We don't want to recurse into anything other than mods, since
// mods or tests inside of functions will break things
let res = match i.node {
ast::ItemMod(..) => fold::noop_fold_item(&*i, self),
_ => SmallVector::one(i),
};
self.cx.path.pop();
res
}
fn fold_mod(&mut self, m: &ast::Mod) -> ast::Mod {
let reexports = mem::replace(&mut self.cx.reexports, Vec::new());
let mut mod_folded = fold::noop_fold_mod(m, self);
let reexports = mem::replace(&mut self.cx.reexports, reexports);
// Remove any #[main] from the AST so it doesn't clash with
// the one we're going to add. Only if compiling an executable.
fn nomain(item: Gc<ast::Item>) -> Gc<ast::Item> {
box(GC) ast::Item {
attrs: item.attrs.iter().filter_map(|attr| {
if !attr.name().equiv(&("main")) {
if !attr.check_name("main") {
Some(*attr)
} else {
None
......@@ -135,18 +149,37 @@ fn nomain(item: Gc<ast::Item>) -> Gc<ast::Item> {
}
}
let mod_nomain = ast::Mod {
inner: m.inner,
view_items: m.view_items.clone(),
items: m.items.iter().map(|i| nomain(*i)).collect(),
};
for i in mod_folded.items.mut_iter() {
*i = nomain(*i);
}
mod_folded.items.push(mk_reexport_mod(&mut self.cx, reexports));
self.cx.reexports.push(self.cx.path.clone());
mod_folded
}
}
fold::noop_fold_mod(&mod_nomain, self)
fn mk_reexport_mod(cx: &mut TestCtxt, reexports: Vec<Vec<ast::Ident>>)
-> Gc<ast::Item> {
let view_items = reexports.move_iter().map(|r| {
cx.ext_cx.view_use_simple(DUMMY_SP, ast::Public, cx.ext_cx.path(DUMMY_SP, r))
}).collect();
let reexport_mod = ast::Mod {
inner: DUMMY_SP,
view_items: view_items,
items: Vec::new(),
};
box(GC) ast::Item {
ident: cx.reexport_mod_ident.clone(),
attrs: Vec::new(),
id: ast::DUMMY_NODE_ID,
node: ast::ItemMod(reexport_mod),
vis: ast::Public,
span: DUMMY_SP,
}
}
fn generate_test_harness(sess: &Session, krate: ast::Crate)
-> ast::Crate {
fn generate_test_harness(sess: &Session, krate: ast::Crate) -> ast::Crate {
let mut cx: TestCtxt = TestCtxt {
sess: sess,
ext_cx: ExtCtxt::new(&sess.parse_sess, sess.opts.cfg.clone(),
......@@ -155,7 +188,9 @@ fn generate_test_harness(sess: &Session, krate: ast::Crate)
crate_name: "test".to_string(),
}),
path: Vec::new(),
reexports: Vec::new(),
testfns: Vec::new(),
reexport_mod_ident: token::str_to_ident("__test_reexports"),
is_test_crate: is_test_crate(&krate),
config: krate.config.clone(),
};
......@@ -170,7 +205,7 @@ fn generate_test_harness(sess: &Session, krate: ast::Crate)
});
let mut fold = TestHarnessGenerator {
cx: cx
cx: cx,
};
let res = fold.fold_crate(krate);
fold.cx.ext_cx.bt_pop();
......@@ -274,7 +309,6 @@ fn add_test_module(cx: &TestCtxt, m: &ast::Mod) -> ast::Mod {
We're going to be building a module that looks more or less like:
mod __test {
#![!resolve_unexported]
extern crate test (name = "test", vers = "...");
fn main() {
test::test_main_static(::os::args().as_slice(), tests)
......@@ -331,15 +365,9 @@ pub fn main() {
};
let item_ = ast::ItemMod(testmod);
// This attribute tells resolve to let us call unexported functions
let resolve_unexported_str = InternedString::new("!resolve_unexported");
let resolve_unexported_attr =
attr::mk_attr_inner(attr::mk_attr_id(),
attr::mk_word_item(resolve_unexported_str));
let item = ast::Item {
ident: token::str_to_ident("__test"),
attrs: vec!(resolve_unexported_attr),
attrs: Vec::new(),
id: ast::DUMMY_NODE_ID,
node: item_,
vis: ast::Public,
......@@ -367,18 +395,6 @@ fn path_node(ids: Vec<ast::Ident> ) -> ast::Path {
}
}
fn path_node_global(ids: Vec<ast::Ident> ) -> ast::Path {
ast::Path {
span: DUMMY_SP,
global: true,
segments: ids.move_iter().map(|identifier| ast::PathSegment {
identifier: identifier,
lifetimes: Vec::new(),
types: OwnedSlice::empty(),
}).collect()
}
}
fn mk_tests(cx: &TestCtxt) -> Gc<ast::Item> {
// The vector of test_descs for this crate
let test_descs = mk_test_descs(cx);
......@@ -430,7 +446,12 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> Gc<ast::Expr> {
span: span
};
let fn_path = path_node_global(path);
let mut visible_path = Vec::new();
for ident in path.move_iter() {
visible_path.push(cx.reexport_mod_ident.clone());
visible_path.push(ident);
}
let fn_path = cx.ext_cx.path_global(DUMMY_SP, visible_path);
let fn_expr = box(GC) ast::Expr {
id: ast::DUMMY_NODE_ID,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册