about summary refs log tree commit diff
diff options
context:
space:
mode:
authorHuon Wilson <dbau.pp+github@gmail.com>2014-08-09 00:01:05 +1000
committerHuon Wilson <dbau.pp+github@gmail.com>2014-08-09 13:00:58 +1000
commitedc9191921a9ef8ff8438a10b5f315ae9190e48c (patch)
treeee5731df5eda2b73d0d522c864fe2b6ef604aade
parentc3284733e3effa92cff2f87b7a38c27ac781411e (diff)
downloadrust-edc9191921a9ef8ff8438a10b5f315ae9190e48c.tar.gz
rust-edc9191921a9ef8ff8438a10b5f315ae9190e48c.zip
testsuite: implement #[reexport_test_harness_name] to get access to the
default entrypoint of the --test binary.

This allows one to, e.g., run tests under libgreen by starting it
manually, passing in the test entrypoint.
-rw-r--r--src/librustc/front/test.rs61
-rw-r--r--src/librustuv/lib.rs8
-rw-r--r--src/libstd/lib.rs8
-rw-r--r--src/test/run-pass/core-run-destroy.rs4
-rw-r--r--src/test/run-pass/reexport-test-harness-main.rs21
-rw-r--r--src/test/run-pass/tcp-connect-timeouts.rs3
6 files changed, 75 insertions, 30 deletions
diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs
index c2581fb888f..14cda7d62c3 100644
--- a/src/librustc/front/test.rs
+++ b/src/librustc/front/test.rs
@@ -51,6 +51,7 @@ struct TestCtxt<'a> {
     ext_cx: ExtCtxt<'a>,
     testfns: Vec<Test>,
     reexport_mod_ident: ast::Ident,
+    reexport_test_harness_main: Option<InternedString>,
     is_test_crate: bool,
     config: ast::CrateConfig,
 }
@@ -64,8 +65,16 @@ pub fn modify_for_testing(sess: &Session,
     // command line options.
     let should_test = attr::contains_name(krate.config.as_slice(), "test");
 
+    // Check for #[reexport_test_harness_main = "some_name"] which
+    // creates a `use some_name = __test::main;`. This needs to be
+    // unconditional, so that the attribute is still marked as used in
+    // non-test builds.
+    let reexport_test_harness_main =
+        attr::first_attr_value_str_by_name(krate.attrs.as_slice(),
+                                           "reexport_test_harness_main");
+
     if should_test {
-        generate_test_harness(sess, krate)
+        generate_test_harness(sess, reexport_test_harness_main, krate)
     } else {
         strip_test_functions(krate)
     }
@@ -79,14 +88,17 @@ struct TestHarnessGenerator<'a> {
 
 impl<'a> fold::Folder for TestHarnessGenerator<'a> {
     fn fold_crate(&mut self, c: ast::Crate) -> ast::Crate {
-        let folded = fold::noop_fold_crate(c, self);
+        let mut folded = fold::noop_fold_crate(c, self);
 
         // Add a special __test module to the crate that will contain code
         // generated for the test harness
-        ast::Crate {
-            module: add_test_module(&self.cx, &folded.module),
-            .. folded
+        let (mod_, reexport) = mk_test_module(&self.cx, &self.cx.reexport_test_harness_main);
+        folded.module.items.push(mod_);
+        match reexport {
+            Some(re) => folded.module.view_items.push(re),
+            None => {}
         }
+        folded
     }
 
     fn fold_item(&mut self, i: Gc<ast::Item>) -> SmallVector<Gc<ast::Item>> {
@@ -196,7 +208,9 @@ fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec<ast::Ident>,
     }
 }
 
-fn generate_test_harness(sess: &Session, krate: ast::Crate) -> ast::Crate {
+fn generate_test_harness(sess: &Session,
+                         reexport_test_harness_main: Option<InternedString>,
+                         krate: ast::Crate) -> ast::Crate {
     let mut cx: TestCtxt = TestCtxt {
         sess: sess,
         ext_cx: ExtCtxt::new(&sess.parse_sess, sess.opts.cfg.clone(),
@@ -207,6 +221,7 @@ fn generate_test_harness(sess: &Session, krate: ast::Crate) -> ast::Crate {
         path: Vec::new(),
         testfns: Vec::new(),
         reexport_mod_ident: token::gensym_ident("__test_reexports"),
+        reexport_test_harness_main: reexport_test_harness_main,
         is_test_crate: is_test_crate(&krate),
         config: krate.config.clone(),
     };
@@ -314,14 +329,6 @@ fn should_fail(i: Gc<ast::Item>) -> bool {
     attr::contains_name(i.attrs.as_slice(), "should_fail")
 }
 
-fn add_test_module(cx: &TestCtxt, m: &ast::Mod) -> ast::Mod {
-    let testmod = mk_test_module(cx);
-    ast::Mod {
-        items: m.items.clone().append_one(testmod),
-        ..(*m).clone()
-    }
-}
-
 /*
 
 We're going to be building a module that looks more or less like:
@@ -359,7 +366,8 @@ fn mk_std(cx: &TestCtxt) -> ast::ViewItem {
     }
 }
 
-fn mk_test_module(cx: &TestCtxt) -> Gc<ast::Item> {
+fn mk_test_module(cx: &TestCtxt, reexport_test_harness_main: &Option<InternedString>)
+                  -> (Gc<ast::Item>, Option<ast::ViewItem>) {
     // Link to test crate
     let view_items = vec!(mk_std(cx));
 
@@ -383,18 +391,35 @@ fn mk_test_module(cx: &TestCtxt) -> Gc<ast::Item> {
     };
     let item_ = ast::ItemMod(testmod);
 
+    let mod_ident = token::gensym_ident("__test");
     let item = ast::Item {
-        ident: token::gensym_ident("__test"),
+        ident: mod_ident,
         attrs: Vec::new(),
         id: ast::DUMMY_NODE_ID,
         node: item_,
         vis: ast::Public,
         span: DUMMY_SP,
-     };
+    };
+    let reexport = reexport_test_harness_main.as_ref().map(|s| {
+        // building `use <ident> = __test::main`
+        let reexport_ident = token::str_to_ident(s.get());
+
+        let use_path =
+            nospan(ast::ViewPathSimple(reexport_ident,
+                                       path_node(vec![mod_ident, token::str_to_ident("main")]),
+                                       ast::DUMMY_NODE_ID));
+
+        ast::ViewItem {
+            node: ast::ViewItemUse(box(GC) use_path),
+            attrs: vec![],
+            vis: ast::Inherited,
+            span: DUMMY_SP
+        }
+    });
 
     debug!("Synthetic test module:\n{}\n", pprust::item_to_string(&item));
 
-    box(GC) item
+    (box(GC) item, reexport)
 }
 
 fn nospan<T>(t: T) -> codemap::Spanned<T> {
diff --git a/src/librustuv/lib.rs b/src/librustuv/lib.rs
index 24b8c297858..dd80ab3ee78 100644
--- a/src/librustuv/lib.rs
+++ b/src/librustuv/lib.rs
@@ -48,6 +48,8 @@ via `close` and `delete` methods.
 #![deny(unused_result, unused_must_use)]
 #![allow(visible_private_types)]
 
+#![reexport_test_harness_main = "test_main"]
+
 #[cfg(test)] extern crate green;
 #[cfg(test)] extern crate debug;
 #[cfg(test)] extern crate realrustuv = "rustuv";
@@ -76,13 +78,9 @@ pub use self::timer::TimerWatcher;
 pub use self::tty::TtyWatcher;
 
 // Run tests with libgreen instead of libnative.
-//
-// FIXME: This egregiously hacks around starting the test runner in a different
-//        threading mode than the default by reaching into the auto-generated
-//        '__test' module.
 #[cfg(test)] #[start]
 fn start(argc: int, argv: *const *const u8) -> int {
-    green::start(argc, argv, event_loop, __test::main)
+    green::start(argc, argv, event_loop, test_main)
 }
 
 mod macros;
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 125c3fdf5d9..20fc7efeb57 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -114,6 +114,8 @@
 #![allow(deprecated)]
 #![deny(missing_doc)]
 
+#![reexport_test_harness_main = "test_main"]
+
 // When testing libstd, bring in libuv as the I/O backend so tests can print
 // things and all of the std::io tests have an I/O interface to run on top
 // of
@@ -186,13 +188,9 @@ pub use unicode::char;
 pub use core_sync::comm;
 
 // Run tests with libgreen instead of libnative.
-//
-// FIXME: This egregiously hacks around starting the test runner in a different
-//        threading mode than the default by reaching into the auto-generated
-//        '__test' module.
 #[cfg(test)] #[start]
 fn start(argc: int, argv: *const *const u8) -> int {
-    green::start(argc, argv, rustuv::event_loop, __test::main)
+    green::start(argc, argv, rustuv::event_loop, test_main)
 }
 
 /* Exported macros */
diff --git a/src/test/run-pass/core-run-destroy.rs b/src/test/run-pass/core-run-destroy.rs
index 8e84278c10e..d187a6a8afe 100644
--- a/src/test/run-pass/core-run-destroy.rs
+++ b/src/test/run-pass/core-run-destroy.rs
@@ -16,6 +16,8 @@
 // instead of in std.
 
 #![feature(macro_rules)]
+#![reexport_test_harness_main = "test_main"]
+
 extern crate libc;
 
 extern crate native;
@@ -55,7 +57,7 @@ macro_rules! iotest (
 
 #[cfg(test)] #[start]
 fn start(argc: int, argv: *const *const u8) -> int {
-    green::start(argc, argv, rustuv::event_loop, __test::main)
+    green::start(argc, argv, rustuv::event_loop, test_main)
 }
 
 iotest!(fn test_destroy_once() {
diff --git a/src/test/run-pass/reexport-test-harness-main.rs b/src/test/run-pass/reexport-test-harness-main.rs
new file mode 100644
index 00000000000..309ae1bcc56
--- /dev/null
+++ b/src/test/run-pass/reexport-test-harness-main.rs
@@ -0,0 +1,21 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-pretty
+// compile-flags:--test
+
+#![reexport_test_harness_main = "test_main"]
+
+#[cfg(test)]
+fn _unused() {
+    // should resolve to the entry point function the --test harness
+    // creates.
+    test_main();
+}
diff --git a/src/test/run-pass/tcp-connect-timeouts.rs b/src/test/run-pass/tcp-connect-timeouts.rs
index d2408509fc5..6f6fff15814 100644
--- a/src/test/run-pass/tcp-connect-timeouts.rs
+++ b/src/test/run-pass/tcp-connect-timeouts.rs
@@ -18,6 +18,7 @@
 
 #![feature(macro_rules, globs)]
 #![allow(experimental)]
+#![reexport_test_harness_main = "test_main"]
 
 extern crate native;
 extern crate green;
@@ -25,7 +26,7 @@ extern crate rustuv;
 
 #[cfg(test)] #[start]
 fn start(argc: int, argv: *const *const u8) -> int {
-    green::start(argc, argv, rustuv::event_loop, __test::main)
+    green::start(argc, argv, rustuv::event_loop, test_main)
 }
 
 macro_rules! iotest (