]> git.lizzy.rs Git - rust.git/commitdiff
rustdoc: add the ability to run tests with --test.
authorHuon Wilson <dbau.pp+github@gmail.com>
Thu, 19 Jun 2014 13:11:18 +0000 (23:11 +1000)
committerHuon Wilson <dbau.pp+github@gmail.com>
Thu, 19 Jun 2014 13:11:18 +0000 (23:11 +1000)
This adds the `test_harness` directive that runs a code block using the
test runner, to allow for `#[test]` items to be demonstrated and still
tested (currently they are just stripped and not even compiled, let
alone run).

src/doc/rustdoc.md
src/librustdoc/html/markdown.rs
src/librustdoc/test.rs

index af69c6c1f7f159ada6e2115c991d707b55b0277d..2287bcabff7625ef60863837170fddec3fa5d745 100644 (file)
@@ -171,6 +171,18 @@ You can specify that the code block should be compiled but not run with the
 ```
 ~~~
 
+Lastly, you can specify that a code block be compiled as if `--test`
+were passed to the compiler using the `test_harness` directive.
+
+~~~md
+```test_harness
+#[test]
+fn foo() {
+    fail!("oops! (will run & register as failure)")
+}
+```
+~~~
+
 Rustdoc also supplies some extra sugar for helping with some tedious
 documentation examples. If a line is prefixed with `# `, then the line
 will not show up in the HTML documentation, but it will be used when
index 625dd3b4810a957d58953c25a19ad79b11d92a80..ccd11c6761107318318701ee01f0894958ae894a 100644 (file)
@@ -195,7 +195,7 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
                             stripped_filtered_line(l).unwrap_or(l)
                         }).collect::<Vec<&str>>().connect("\n");
                         let krate = krate.as_ref().map(|s| s.as_slice());
-                        let test = test::maketest(test.as_slice(), krate, false);
+                        let test = test::maketest(test.as_slice(), krate, false, false);
                         s.push_str(format!("<span id='rust-example-raw-{}' \
                                              class='rusttest'>{}</span>",
                                            i, Escape(test.as_slice())).as_slice());
@@ -328,7 +328,7 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) {
                 let text = lines.collect::<Vec<&str>>().connect("\n");
                 tests.add_test(text.to_string(),
                                block_info.should_fail, block_info.no_run,
-                               block_info.ignore);
+                               block_info.ignore, block_info.test_harness);
             })
         }
     }
@@ -372,6 +372,7 @@ struct LangString {
     no_run: bool,
     ignore: bool,
     notrust: bool,
+    test_harness: bool,
 }
 
 impl LangString {
@@ -381,6 +382,7 @@ fn all_false() -> LangString {
             no_run: false,
             ignore: false,
             notrust: false,
+            test_harness: false,
         }
     }
 
@@ -401,6 +403,7 @@ fn parse(string: &str) -> LangString {
                 "ignore" => { data.ignore = true; seen_rust_tags = true; },
                 "notrust" => { data.notrust = true; seen_rust_tags = true; },
                 "rust" => { data.notrust = false; seen_rust_tags = true; },
+                "test_harness" => { data.test_harness = true; seen_rust_tags = true; }
                 _ => { seen_other_tags = true }
             }
         }
@@ -446,24 +449,28 @@ mod tests {
 
     #[test]
     fn test_lang_string_parse() {
-        fn t(s: &str, should_fail: bool, no_run: bool, ignore: bool, notrust: bool) {
+        fn t(s: &str,
+             should_fail: bool, no_run: bool, ignore: bool, notrust: bool, test_harness: bool) {
             assert_eq!(LangString::parse(s), LangString {
                 should_fail: should_fail,
                 no_run: no_run,
                 ignore: ignore,
                 notrust: notrust,
+                test_harness: test_harness,
             })
         }
 
-        t("", false,false,false,false);
-        t("rust", false,false,false,false);
-        t("sh", false,false,false,true);
-        t("notrust", false,false,false,true);
-        t("ignore", false,false,true,false);
-        t("should_fail", true,false,false,false);
-        t("no_run", false,true,false,false);
-        t("{.no_run .example}", false,true,false,false);
-        t("{.sh .should_fail}", true,false,false,false);
-        t("{.example .rust}", false,false,false,false);
+        t("", false,false,false,false,false);
+        t("rust", false,false,false,false,false);
+        t("sh", false,false,false,true,false);
+        t("notrust", false,false,false,true,false);
+        t("ignore", false,false,true,false,false);
+        t("should_fail", true,false,false,false,false);
+        t("no_run", false,true,false,false,false);
+        t("test_harness", false,false,false,false,true);
+        t("{.no_run .example}", false,true,false,false,false);
+        t("{.sh .should_fail}", true,false,false,false,false);
+        t("{.example .rust}", false,false,false,false,false);
+        t("{.test_harness .rust}", false,false,false,false,true);
     }
 }
index 907d9fc7561d400eae83a41c513fe31c46f0dfcf..b43af03011c20ec5e700d789a70620f16a7b5a0f 100644 (file)
@@ -102,8 +102,10 @@ pub fn run(input: &str,
 }
 
 fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, should_fail: bool,
-           no_run: bool) {
-    let test = maketest(test, Some(cratename), true);
+           no_run: bool, as_test_harness: bool) {
+    // the test harness wants its own `main` & top level functions, so
+    // never wrap the test in `fn main() { ... }`
+    let test = maketest(test, Some(cratename), true, as_test_harness);
     let input = driver::StrInput(test.to_string());
 
     let sessopts = config::Options {
@@ -116,6 +118,7 @@ fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, should_fail: bool,
             prefer_dynamic: true,
             .. config::basic_codegen_options()
         },
+        test: as_test_harness,
         ..config::basic_options().clone()
     };
 
@@ -200,7 +203,7 @@ fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, should_fail: bool,
     }
 }
 
-pub fn maketest(s: &str, cratename: Option<&str>, lints: bool) -> String {
+pub fn maketest(s: &str, cratename: Option<&str>, lints: bool, dont_insert_main: bool) -> String {
     let mut prog = String::new();
     if lints {
         prog.push_str(r"
@@ -220,7 +223,7 @@ pub fn maketest(s: &str, cratename: Option<&str>, lints: bool) -> String {
             None => {}
         }
     }
-    if s.contains("fn main") {
+    if dont_insert_main || s.contains("fn main") {
         prog.push_str(s);
     } else {
         prog.push_str("fn main() {\n    ");
@@ -255,7 +258,8 @@ pub fn new(cratename: String, libs: HashSet<Path>,
         }
     }
 
-    pub fn add_test(&mut self, test: String, should_fail: bool, no_run: bool, should_ignore: bool) {
+    pub fn add_test(&mut self, test: String,
+                    should_fail: bool, no_run: bool, should_ignore: bool, as_test_harness: bool) {
         let name = if self.use_headers {
             let s = self.current_header.as_ref().map(|s| s.as_slice()).unwrap_or("");
             format!("{}_{}", s, self.cnt)
@@ -277,7 +281,8 @@ pub fn add_test(&mut self, test: String, should_fail: bool, no_run: bool, should
                         cratename.as_slice(),
                         libs,
                         should_fail,
-                        no_run);
+                        no_run,
+                        as_test_harness);
             }),
         });
     }