From 230234f3a8eb38dcfa26d086c9c6e61be48f46ac Mon Sep 17 00:00:00 2001 From: ggomez Date: Wed, 7 Sep 2016 16:43:18 +0200 Subject: [PATCH 01/15] Add information in case of markdown block code test failure --- src/librustdoc/html/markdown.rs | 7 ++++++- src/librustdoc/test.rs | 35 ++++++++++++++++++++------------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 442a2f4074215..3df476907d953 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -448,7 +448,8 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) { tests.add_test(text.to_owned(), block_info.should_panic, block_info.no_run, block_info.ignore, block_info.test_harness, - block_info.compile_fail, block_info.error_codes); + block_info.compile_fail, block_info.error_codes, + block_info.original); } } @@ -488,6 +489,7 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) { #[derive(Eq, PartialEq, Clone, Debug)] struct LangString { + original: String, should_panic: bool, no_run: bool, ignore: bool, @@ -500,6 +502,7 @@ struct LangString { impl LangString { fn all_false() -> LangString { LangString { + original: String::new(), should_panic: false, no_run: false, ignore: false, @@ -521,6 +524,7 @@ impl LangString { allow_error_code_check = true; } + data.original = string.to_owned(); let tokens = string.split(|c: char| !(c == '_' || c == '-' || c.is_alphanumeric()) ); @@ -647,6 +651,7 @@ mod tests { test_harness: test_harness, compile_fail: compile_fail, error_codes: error_codes, + original: s.to_owned(), }) } diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index ab0ac02fd88f1..00327007dd00d 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -161,13 +161,15 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, should_panic: bool, no_run: bool, as_test_harness: bool, compile_fail: bool, mut error_codes: Vec, opts: &TestOptions, - maybe_sysroot: Option) { + maybe_sysroot: Option, + original: &str) { // the test harness wants its own `main` & top level functions, so // never wrap the test in `fn main() { ... }` - let test = maketest(test, Some(cratename), as_test_harness, opts); + let new_test = maketest(test, Some(cratename), as_test_harness, opts); + let test = format!("```{}\n{}\n```\n", original, test); let input = config::Input::Str { name: driver::anon_src(), - input: test.to_owned(), + input: new_test.to_owned(), }; let outputs = OutputTypes::new(&[(OutputType::Exe, None)]); @@ -249,20 +251,22 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, if count > 0 && !compile_fail { sess.fatal("aborting due to previous error(s)") } else if count == 0 && compile_fail { - panic!("test compiled while it wasn't supposed to") + panic!("test compiled while it wasn't supposed to:\n\n{}\n", test) } if count > 0 && error_codes.len() > 0 { let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap(); error_codes.retain(|err| !out.contains(err)); } } - Ok(()) if compile_fail => panic!("test compiled while it wasn't supposed to"), + Ok(()) if compile_fail => { + panic!("test compiled while it wasn't supposed to:\n\n{}\n", test) + } _ => {} } } Err(_) => { if !compile_fail { - panic!("couldn't compile the test"); + panic!("couldn't compile the test:\n\n{}\n", test); } if error_codes.len() > 0 { let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap(); @@ -272,7 +276,7 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, } if error_codes.len() > 0 { - panic!("Some expected error codes were not found: {:?}", error_codes); + panic!("Some expected error codes were not found: {:?}\n\n{}\n", error_codes, test); } if no_run { return } @@ -294,17 +298,18 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, cmd.env(var, &newpath); match cmd.output() { - Err(e) => panic!("couldn't run the test: {}{}", e, + Err(e) => panic!("couldn't run the test: {}{}\n\n{}\n", e, if e.kind() == io::ErrorKind::PermissionDenied { " - maybe your tempdir is mounted with noexec?" - } else { "" }), + } else { "" }, test), Ok(out) => { if should_panic && out.status.success() { - panic!("test executable succeeded when it should have failed"); + panic!("test executable succeeded when it should have failed\n\n{}\n", test); } else if !should_panic && !out.status.success() { - panic!("test executable failed:\n{}\n{}", + panic!("test executable failed:\n{}\n{}\n\n{}\n", str::from_utf8(&out.stdout).unwrap_or(""), - str::from_utf8(&out.stderr).unwrap_or("")); + str::from_utf8(&out.stderr).unwrap_or(""), + test); } } } @@ -406,7 +411,8 @@ impl Collector { pub fn add_test(&mut self, test: String, should_panic: bool, no_run: bool, should_ignore: bool, - as_test_harness: bool, compile_fail: bool, error_codes: Vec) { + as_test_harness: bool, compile_fail: bool, error_codes: Vec, + original: String) { let name = if self.use_headers { let s = self.current_header.as_ref().map(|s| &**s).unwrap_or(""); format!("{}_{}", s, self.cnt) @@ -446,7 +452,8 @@ impl Collector { compile_fail, error_codes, &opts, - maybe_sysroot) + maybe_sysroot, + &original) }) } { Ok(()) => (), From 902460d2182198e096de47850c3e8ab72fbbafc5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 2 Oct 2016 02:11:45 +0200 Subject: [PATCH 02/15] Add line number and filename in error message --- src/librustdoc/markdown.rs | 2 +- src/librustdoc/test.rs | 59 ++++++++++++++++++++++++++++++++++---- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 369e18948ad5b..50f748deb0b9e 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -154,7 +154,7 @@ pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, let mut opts = TestOptions::default(); opts.no_crate_inject = true; let mut collector = Collector::new(input.to_string(), cfgs, libs, externs, - true, opts, maybe_sysroot); + true, opts, maybe_sysroot, &input_str, "input".to_string()); find_testable_code(&input_str, &mut collector); test_args.insert(0, "rustdoctest".to_string()); testing::test_main(&test_args, collector.tests); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 00327007dd00d..a772a52da727a 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -8,8 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::collections::HashMap; use std::env; use std::ffi::OsString; +use std::fs::File; use std::io::prelude::*; use std::io; use std::path::PathBuf; @@ -96,13 +98,24 @@ pub fn run(input: &str, link::find_crate_name(None, &hir_forest.krate().attrs, &input) }); let opts = scrape_test_config(hir_forest.krate()); + let filename = input_path.to_str().unwrap_or("").to_owned(); + let mut f = match File::open(input_path) { + Ok(f) => f, + _ => return 1, + }; + let mut file_content = String::new(); + if let Err(_) = f.read_to_string(&mut file_content) { + return 1; + } let mut collector = Collector::new(crate_name, cfgs, libs, externs, false, opts, - maybe_sysroot); + maybe_sysroot, + &file_content, + filename); { let dep_graph = DepGraph::new(false); @@ -162,11 +175,12 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, should_panic: bool, no_run: bool, as_test_harness: bool, compile_fail: bool, mut error_codes: Vec, opts: &TestOptions, maybe_sysroot: Option, - original: &str) { + original: &str, line_number: u32, filename: &str) { // the test harness wants its own `main` & top level functions, so // never wrap the test in `fn main() { ... }` let new_test = maketest(test, Some(cratename), as_test_harness, opts); - let test = format!("```{}\n{}\n```\n", original, test); + let test = format!("Error on {}:{}\n\n```{}\n{}\n```\n", + filename, line_number, original, test); let input = config::Input::Str { name: driver::anon_src(), input: new_test.to_owned(), @@ -389,11 +403,27 @@ pub struct Collector { cratename: String, opts: TestOptions, maybe_sysroot: Option, + code_blocks: HashMap>, + filename: String, } impl Collector { pub fn new(cratename: String, cfgs: Vec, libs: SearchPaths, externs: Externs, - use_headers: bool, opts: TestOptions, maybe_sysroot: Option) -> Collector { + use_headers: bool, opts: TestOptions, maybe_sysroot: Option, + file_content: &str, filename: String) -> Collector { + let mut line_number = 1; + let mut block_lines = HashMap::new(); + for (pos, block) in file_content.split("```").enumerate() { + if (pos & 1) != 0 { + let key = format!("{}", block.replace("/// ", "").replace("//!", "")); + if !block_lines.contains_key(&key) { + block_lines.insert(key.clone(), Vec::new()); + } + block_lines.get_mut(&key).unwrap().push(line_number); + } + line_number += block.lines().count() as u32 - 1; + } + Collector { tests: Vec::new(), names: Vec::new(), @@ -406,7 +436,22 @@ impl Collector { cratename: cratename, opts: opts, maybe_sysroot: maybe_sysroot, + code_blocks: block_lines, + filename: filename, + } + } + + fn get_line_from_key(&mut self, key: &String) -> u32 { + let (line, need_removal) = if let Some(l) = self.code_blocks.get_mut(key) { + let need_removal = l.len() > 1; + (l.pop().unwrap_or(1), need_removal) + } else { + return 1; + }; + if need_removal { + self.code_blocks.remove(key); } + line } pub fn add_test(&mut self, test: String, @@ -427,6 +472,8 @@ impl Collector { let opts = self.opts.clone(); let maybe_sysroot = self.maybe_sysroot.clone(); debug!("Creating test {}: {}", name, test); + let line_number = self.get_line_from_key(&format!("{}\n{}\n", original, test)); + let filename = self.filename.clone(); self.tests.push(testing::TestDescAndFn { desc: testing::TestDesc { name: testing::DynTestName(name), @@ -453,7 +500,9 @@ impl Collector { error_codes, &opts, maybe_sysroot, - &original) + &original, + line_number, + &filename) }) } { Ok(()) => (), From 59ac401b39b8cf18327acea5ce144ac94e9ed537 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 9 Oct 2016 14:14:49 +0200 Subject: [PATCH 03/15] Truncate output example to 10 lines --- src/librustdoc/test.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index a772a52da727a..bba9fa5ed7524 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -178,9 +178,14 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, original: &str, line_number: u32, filename: &str) { // the test harness wants its own `main` & top level functions, so // never wrap the test in `fn main() { ... }` + let mut trunc_test = test.split("\n").take(11).collect::>(); + if trunc_test.len() == 11 { + trunc_test[10] = "..."; + } let new_test = maketest(test, Some(cratename), as_test_harness, opts); let test = format!("Error on {}:{}\n\n```{}\n{}\n```\n", - filename, line_number, original, test); + filename, line_number, original, + trunc_test.join("\n")); let input = config::Input::Str { name: driver::anon_src(), input: new_test.to_owned(), From 5fe3915a05deac257dade7cf0839e3150221c18a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 15 Nov 2016 22:29:46 +0100 Subject: [PATCH 04/15] Rework rustdoc test output a bit --- src/librustdoc/test.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index bba9fa5ed7524..566e78e34e573 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -178,18 +178,13 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, original: &str, line_number: u32, filename: &str) { // the test harness wants its own `main` & top level functions, so // never wrap the test in `fn main() { ... }` - let mut trunc_test = test.split("\n").take(11).collect::>(); - if trunc_test.len() == 11 { - trunc_test[10] = "..."; - } - let new_test = maketest(test, Some(cratename), as_test_harness, opts); - let test = format!("Error on {}:{}\n\n```{}\n{}\n```\n", - filename, line_number, original, - trunc_test.join("\n")); + let test = maketest(test, Some(cratename), as_test_harness, opts); let input = config::Input::Str { name: driver::anon_src(), - input: new_test.to_owned(), + input: test.to_owned(), }; + let test = format!("Error in \"{}\" at line {}.\n", + filename, line_number); let outputs = OutputTypes::new(&[(OutputType::Exe, None)]); let sessopts = config::Options { From a0ad4adf5977316494f8be2d549e6352c6a9b620 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 19 Nov 2016 17:51:25 +0100 Subject: [PATCH 05/15] Change thread name --- src/librustdoc/test.rs | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 566e78e34e573..3b910c276ee0c 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -88,7 +88,7 @@ pub fn run(input: &str, config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone())); let krate = panictry!(driver::phase_1_parse_input(&sess, &input)); - let driver::ExpansionResult { defs, mut hir_forest, .. } = { + let driver::ExpansionResult { hir_forest, .. } = { phase_2_configure_and_expand( &sess, &cstore, krate, None, "rustdoc-test", None, MakeGlobMap::No, |_| Ok(()) ).expect("phase_2_configure_and_expand aborted in rustdoc!") @@ -183,8 +183,6 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, name: driver::anon_src(), input: test.to_owned(), }; - let test = format!("Error in \"{}\" at line {}.\n", - filename, line_number); let outputs = OutputTypes::new(&[(OutputType::Exe, None)]); let sessopts = config::Options { @@ -265,7 +263,7 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, if count > 0 && !compile_fail { sess.fatal("aborting due to previous error(s)") } else if count == 0 && compile_fail { - panic!("test compiled while it wasn't supposed to:\n\n{}\n", test) + panic!("test compiled while it wasn't supposed to") } if count > 0 && error_codes.len() > 0 { let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap(); @@ -273,14 +271,14 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, } } Ok(()) if compile_fail => { - panic!("test compiled while it wasn't supposed to:\n\n{}\n", test) + panic!("test compiled while it wasn't supposed to") } _ => {} } } Err(_) => { if !compile_fail { - panic!("couldn't compile the test:\n\n{}\n", test); + panic!("couldn't compile the test"); } if error_codes.len() > 0 { let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap(); @@ -290,7 +288,7 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, } if error_codes.len() > 0 { - panic!("Some expected error codes were not found: {:?}\n\n{}\n", error_codes, test); + panic!("Some expected error codes were not found: {:?}", error_codes); } if no_run { return } @@ -312,18 +310,17 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, cmd.env(var, &newpath); match cmd.output() { - Err(e) => panic!("couldn't run the test: {}{}\n\n{}\n", e, + Err(e) => panic!("couldn't run the test: {}{}", e, if e.kind() == io::ErrorKind::PermissionDenied { " - maybe your tempdir is mounted with noexec?" - } else { "" }, test), + } else { "" }), Ok(out) => { if should_panic && out.status.success() { - panic!("test executable succeeded when it should have failed\n\n{}\n", test); + panic!("test executable succeeded when it should have failed"); } else if !should_panic && !out.status.success() { - panic!("test executable failed:\n{}\n{}\n\n{}\n", + panic!("test executable failed:\n{}\n{}\n", str::from_utf8(&out.stdout).unwrap_or(""), - str::from_utf8(&out.stderr).unwrap_or(""), - test); + str::from_utf8(&out.stderr).unwrap_or("")); } } } @@ -458,12 +455,8 @@ impl Collector { should_panic: bool, no_run: bool, should_ignore: bool, as_test_harness: bool, compile_fail: bool, error_codes: Vec, original: String) { - let name = if self.use_headers { - let s = self.current_header.as_ref().map(|s| &**s).unwrap_or(""); - format!("{}_{}", s, self.cnt) - } else { - format!("{}_{}", self.names.join("::"), self.cnt) - }; + let line_number = self.get_line_from_key(&format!("{}\n{}\n", original, test)); + let name = format!("{} - line {}", self.filename, line_number); self.cnt += 1; let cfgs = self.cfgs.clone(); let libs = self.libs.clone(); @@ -472,8 +465,6 @@ impl Collector { let opts = self.opts.clone(); let maybe_sysroot = self.maybe_sysroot.clone(); debug!("Creating test {}: {}", name, test); - let line_number = self.get_line_from_key(&format!("{}\n{}\n", original, test)); - let filename = self.filename.clone(); self.tests.push(testing::TestDescAndFn { desc: testing::TestDesc { name: testing::DynTestName(name), From 409e8ba34e03fd48d9a2395d5f602ddc4e8bc97a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 12 Jan 2017 20:33:01 +0100 Subject: [PATCH 06/15] Move to my own hoedown repository --- .gitmodules | 2 +- src/librustdoc/html/markdown.rs | 45 ++++++++++++++++++++------------- src/librustdoc/test.rs | 10 +++----- src/rt/hoedown | 2 +- 4 files changed, 33 insertions(+), 26 deletions(-) diff --git a/.gitmodules b/.gitmodules index 39288a7ae4907..73824b7b42c9c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,7 +7,7 @@ url = https://github.com/rust-lang/compiler-rt.git [submodule "src/rt/hoedown"] path = src/rt/hoedown - url = https://github.com/rust-lang/hoedown.git + url = https://github.com/GuillaumeGomez/hoedown.git [submodule "src/jemalloc"] path = src/jemalloc url = https://github.com/rust-lang/jemalloc.git diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 3df476907d953..c35342e25b523 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -71,29 +71,31 @@ const HOEDOWN_EXTENSIONS: libc::c_uint = enum hoedown_document {} type blockcodefn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_buffer, *const hoedown_renderer_data); + *const hoedown_buffer, *const hoedown_renderer_data, + libc::size_t); type blockquotefn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_renderer_data); + *const hoedown_renderer_data, libc::size_t); type headerfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - libc::c_int, *const hoedown_renderer_data); + libc::c_int, *const hoedown_renderer_data, + libc::size_t); type blockhtmlfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_renderer_data); + *const hoedown_renderer_data, libc::size_t); type codespanfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_renderer_data) -> libc::c_int; + *const hoedown_renderer_data, libc::size_t) -> libc::c_int; type linkfn = extern "C" fn (*mut hoedown_buffer, *const hoedown_buffer, *const hoedown_buffer, *const hoedown_buffer, - *const hoedown_renderer_data) -> libc::c_int; + *const hoedown_renderer_data, libc::size_t) -> libc::c_int; type entityfn = extern "C" fn (*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_renderer_data); + *const hoedown_renderer_data, libc::size_t); type normaltextfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_renderer_data); + *const hoedown_renderer_data, libc::size_t); #[repr(C)] struct hoedown_renderer_data { @@ -147,7 +149,8 @@ struct html_toc_data { struct MyOpaque { dfltblk: extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_buffer, *const hoedown_renderer_data), + *const hoedown_buffer, *const hoedown_renderer_data, + libc::size_t), toc_builder: Option, } @@ -229,7 +232,8 @@ pub fn render(w: &mut fmt::Formatter, print_toc: bool, html_flags: libc::c_uint) -> fmt::Result { extern fn block(ob: *mut hoedown_buffer, orig_text: *const hoedown_buffer, - lang: *const hoedown_buffer, data: *const hoedown_renderer_data) { + lang: *const hoedown_buffer, data: *const hoedown_renderer_data, + line: libc::size_t) { unsafe { if orig_text.is_null() { return } @@ -246,7 +250,8 @@ pub fn render(w: &mut fmt::Formatter, let rlang = str::from_utf8(rlang).unwrap(); if !LangString::parse(rlang).rust { (my_opaque.dfltblk)(ob, orig_text, lang, - opaque as *const hoedown_renderer_data); + opaque as *const hoedown_renderer_data, + line); true } else { false @@ -312,7 +317,8 @@ pub fn render(w: &mut fmt::Formatter, } extern fn header(ob: *mut hoedown_buffer, text: *const hoedown_buffer, - level: libc::c_int, data: *const hoedown_renderer_data) { + level: libc::c_int, data: *const hoedown_renderer_data, + _: libc::size_t) { // hoedown does this, we may as well too unsafe { hoedown_buffer_puts(ob, "\n\0".as_ptr() as *const _); } @@ -373,6 +379,7 @@ pub fn render(w: &mut fmt::Formatter, ob: *mut hoedown_buffer, text: *const hoedown_buffer, _: *const hoedown_renderer_data, + _: libc::size_t ) -> libc::c_int { let content = if text.is_null() { "".to_owned() @@ -426,7 +433,8 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) { extern fn block(_ob: *mut hoedown_buffer, text: *const hoedown_buffer, lang: *const hoedown_buffer, - data: *const hoedown_renderer_data) { + data: *const hoedown_renderer_data, + _: libc::size_t) { unsafe { if text.is_null() { return } let block_info = if lang.is_null() { @@ -455,7 +463,8 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) { extern fn header(_ob: *mut hoedown_buffer, text: *const hoedown_buffer, - level: libc::c_int, data: *const hoedown_renderer_data) { + level: libc::c_int, data: *const hoedown_renderer_data, + _: libc::size_t) { unsafe { let opaque = (*data).opaque as *mut hoedown_html_renderer_state; let tests = &mut *((*opaque).opaque as *mut ::test::Collector); @@ -590,7 +599,8 @@ pub fn plain_summary_line(md: &str) -> String { _link: *const hoedown_buffer, _title: *const hoedown_buffer, content: *const hoedown_buffer, - data: *const hoedown_renderer_data) -> libc::c_int + data: *const hoedown_renderer_data, + _: libc::size_t) -> libc::c_int { unsafe { if !content.is_null() && (*content).size > 0 { @@ -603,8 +613,9 @@ pub fn plain_summary_line(md: &str) -> String { } extern fn normal_text(_ob: *mut hoedown_buffer, - text: *const hoedown_buffer, - data: *const hoedown_renderer_data) + text: *const hoedown_buffer, + data: *const hoedown_renderer_data, + _: libc::size_t) { unsafe { let ob = (*data).opaque as *mut hoedown_buffer; diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 3b910c276ee0c..bad2986ab628b 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -88,7 +88,7 @@ pub fn run(input: &str, config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone())); let krate = panictry!(driver::phase_1_parse_input(&sess, &input)); - let driver::ExpansionResult { hir_forest, .. } = { + let driver::ExpansionResult { defs, mut hir_forest, .. } = { phase_2_configure_and_expand( &sess, &cstore, krate, None, "rustdoc-test", None, MakeGlobMap::No, |_| Ok(()) ).expect("phase_2_configure_and_expand aborted in rustdoc!") @@ -174,8 +174,7 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, should_panic: bool, no_run: bool, as_test_harness: bool, compile_fail: bool, mut error_codes: Vec, opts: &TestOptions, - maybe_sysroot: Option, - original: &str, line_number: u32, filename: &str) { + maybe_sysroot: Option) { // the test harness wants its own `main` & top level functions, so // never wrap the test in `fn main() { ... }` let test = maketest(test, Some(cratename), as_test_harness, opts); @@ -490,10 +489,7 @@ impl Collector { compile_fail, error_codes, &opts, - maybe_sysroot, - &original, - line_number, - &filename) + maybe_sysroot) }) } { Ok(()) => (), diff --git a/src/rt/hoedown b/src/rt/hoedown index a3736a0a1907c..78e7b6f69d3fa 160000 --- a/src/rt/hoedown +++ b/src/rt/hoedown @@ -1 +1 @@ -Subproject commit a3736a0a1907cbc8bf619708738815a5fd789c80 +Subproject commit 78e7b6f69d3fa0cb6ae6e7fb9278c3fd167ec0d1 From 62fb7fc54a6b7cca2c690ca84ee54e4a86ab5ba4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 17 Jan 2017 23:54:51 +0100 Subject: [PATCH 07/15] Switch logic to Span instead of HashMap --- src/librustdoc/clean/mod.rs | 10 ++++- src/librustdoc/html/markdown.rs | 8 ++-- src/librustdoc/markdown.rs | 5 ++- src/librustdoc/test.rs | 71 ++++++++++++--------------------- src/libsyntax/attr.rs | 12 +++--- src/libsyntax/print/pprust.rs | 5 ++- src/libsyntax/std_inject.rs | 3 +- src/libsyntax/test.rs | 3 +- 8 files changed, 54 insertions(+), 63 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index cdb24a56367fc..fe2edcad25c20 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -521,17 +521,22 @@ impl<'a, I: IntoIterator> NestedAttributesExt for #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug, Default)] pub struct Attributes { pub doc_strings: Vec, - pub other_attrs: Vec + pub other_attrs: Vec, + pub span: Option, } impl Attributes { pub fn from_ast(attrs: &[ast::Attribute]) -> Attributes { let mut doc_strings = vec![]; + let mut sp = None; let other_attrs = attrs.iter().filter_map(|attr| { attr.with_desugared_doc(|attr| { if let Some(value) = attr.value_str() { if attr.check_name("doc") { doc_strings.push(value.to_string()); + if sp.is_none() { + sp = Some(attr.span); + } return None; } } @@ -541,7 +546,8 @@ impl Attributes { }).collect(); Attributes { doc_strings: doc_strings, - other_attrs: other_attrs + other_attrs: other_attrs, + span: sp, } } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index c35342e25b523..e8ff8930bdd7d 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -429,12 +429,12 @@ pub fn render(w: &mut fmt::Formatter, } } -pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) { +pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, start_line: usize) { extern fn block(_ob: *mut hoedown_buffer, text: *const hoedown_buffer, lang: *const hoedown_buffer, data: *const hoedown_renderer_data, - _: libc::size_t) { + line: libc::size_t) { unsafe { if text.is_null() { return } let block_info = if lang.is_null() { @@ -453,11 +453,12 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) { stripped_filtered_line(l).unwrap_or(l) }); let text = lines.collect::>().join("\n"); + let line = tests.get_line() + line; tests.add_test(text.to_owned(), block_info.should_panic, block_info.no_run, block_info.ignore, block_info.test_harness, block_info.compile_fail, block_info.error_codes, - block_info.original); + line); } } @@ -478,6 +479,7 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) { } } + tests.set_line(start_line); unsafe { let ob = hoedown_buffer_new(DEF_OUNIT); let renderer = hoedown_html_renderer_new(0, 0); diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 50f748deb0b9e..49497957be980 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -154,8 +154,9 @@ pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, let mut opts = TestOptions::default(); opts.no_crate_inject = true; let mut collector = Collector::new(input.to_string(), cfgs, libs, externs, - true, opts, maybe_sysroot, &input_str, "input".to_string()); - find_testable_code(&input_str, &mut collector); + true, opts, maybe_sysroot, "input".to_string(), + None); + find_testable_code(&input_str, &mut collector, 0); test_args.insert(0, "rustdoctest".to_string()); testing::test_main(&test_args, collector.tests); 0 diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index bad2986ab628b..d5451d6a6c37d 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -8,10 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::collections::HashMap; use std::env; use std::ffi::OsString; -use std::fs::File; use std::io::prelude::*; use std::io; use std::path::PathBuf; @@ -39,6 +37,7 @@ use rustc_trans::back::link; use syntax::ast; use syntax::codemap::CodeMap; use syntax::feature_gate::UnstableFeatures; +use syntax_pos::{BytePos, DUMMY_SP, Pos}; use errors; use errors::emitter::ColorConfig; @@ -81,7 +80,7 @@ pub fn run(input: &str, let _ignore = dep_graph.in_ignore(); let cstore = Rc::new(CStore::new(&dep_graph)); let mut sess = session::build_session_( - sessopts, &dep_graph, Some(input_path.clone()), handler, codemap, cstore.clone(), + sessopts, &dep_graph, Some(input_path.clone()), handler, codemap.clone(), cstore.clone(), ); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); sess.parse_sess.config = @@ -99,14 +98,6 @@ pub fn run(input: &str, }); let opts = scrape_test_config(hir_forest.krate()); let filename = input_path.to_str().unwrap_or("").to_owned(); - let mut f = match File::open(input_path) { - Ok(f) => f, - _ => return 1, - }; - let mut file_content = String::new(); - if let Err(_) = f.read_to_string(&mut file_content) { - return 1; - } let mut collector = Collector::new(crate_name, cfgs, libs, @@ -114,8 +105,8 @@ pub fn run(input: &str, false, opts, maybe_sysroot, - &file_content, - filename); + filename, + Some(codemap)); { let dep_graph = DepGraph::new(false); @@ -399,27 +390,15 @@ pub struct Collector { cratename: String, opts: TestOptions, maybe_sysroot: Option, - code_blocks: HashMap>, filename: String, + start_line: usize, + codemap: Option>, } impl Collector { pub fn new(cratename: String, cfgs: Vec, libs: SearchPaths, externs: Externs, use_headers: bool, opts: TestOptions, maybe_sysroot: Option, - file_content: &str, filename: String) -> Collector { - let mut line_number = 1; - let mut block_lines = HashMap::new(); - for (pos, block) in file_content.split("```").enumerate() { - if (pos & 1) != 0 { - let key = format!("{}", block.replace("/// ", "").replace("//!", "")); - if !block_lines.contains_key(&key) { - block_lines.insert(key.clone(), Vec::new()); - } - block_lines.get_mut(&key).unwrap().push(line_number); - } - line_number += block.lines().count() as u32 - 1; - } - + filename: String, codemap: Option>) -> Collector { Collector { tests: Vec::new(), names: Vec::new(), @@ -432,30 +411,17 @@ impl Collector { cratename: cratename, opts: opts, maybe_sysroot: maybe_sysroot, - code_blocks: block_lines, filename: filename, + start_line: 0, + codemap: codemap, } } - fn get_line_from_key(&mut self, key: &String) -> u32 { - let (line, need_removal) = if let Some(l) = self.code_blocks.get_mut(key) { - let need_removal = l.len() > 1; - (l.pop().unwrap_or(1), need_removal) - } else { - return 1; - }; - if need_removal { - self.code_blocks.remove(key); - } - line - } - pub fn add_test(&mut self, test: String, should_panic: bool, no_run: bool, should_ignore: bool, as_test_harness: bool, compile_fail: bool, error_codes: Vec, - original: String) { - let line_number = self.get_line_from_key(&format!("{}\n{}\n", original, test)); - let name = format!("{} - line {}", self.filename, line_number); + line: usize) { + let name = format!("{} - line {}", self.filename, line); self.cnt += 1; let cfgs = self.cfgs.clone(); let libs = self.libs.clone(); @@ -499,6 +465,18 @@ impl Collector { }); } + pub fn get_line(&self) -> usize { + if let Some(ref codemap) = self.codemap{ + codemap.lookup_char_pos(BytePos(self.start_line as u32)).line - 1 + } else { + self.start_line + } + } + + pub fn set_line(&mut self, start_line: usize) { + self.start_line = start_line; + } + pub fn register_header(&mut self, name: &str, level: u32) { if self.use_headers && level == 1 { // we use these headings as test names, so it's good if @@ -539,7 +517,8 @@ impl<'a, 'hir> HirCollector<'a, 'hir> { attrs.unindent_doc_comments(); if let Some(doc) = attrs.doc_value() { self.collector.cnt = 0; - markdown::find_testable_code(doc, self.collector); + markdown::find_testable_code(doc, self.collector, + attrs.span.unwrap_or(DUMMY_SP).lo.to_usize()); } nested(self); diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 099ca8f02d2b2..455a6a0fb32e2 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -280,9 +280,9 @@ impl Attribute { Symbol::intern("doc"), Symbol::intern(&strip_doc_comment_decoration(&comment.as_str()))); if self.style == ast::AttrStyle::Outer { - f(&mk_attr_outer(self.id, meta)) + f(&mk_attr_outer(self.span, self.id, meta)) } else { - f(&mk_attr_inner(self.id, meta)) + f(&mk_attr_inner(self.span, self.id, meta)) } } else { f(self) @@ -339,8 +339,8 @@ pub fn mk_attr_id() -> AttrId { } /// Returns an inner attribute with the given value. -pub fn mk_attr_inner(id: AttrId, item: MetaItem) -> Attribute { - mk_spanned_attr_inner(DUMMY_SP, id, item) +pub fn mk_attr_inner(span: Span, id: AttrId, item: MetaItem) -> Attribute { + mk_spanned_attr_inner(span, id, item) } /// Returns an innter attribute with the given value and span. @@ -356,8 +356,8 @@ pub fn mk_spanned_attr_inner(sp: Span, id: AttrId, item: MetaItem) -> Attribute /// Returns an outer attribute with the given value. -pub fn mk_attr_outer(id: AttrId, item: MetaItem) -> Attribute { - mk_spanned_attr_outer(DUMMY_SP, id, item) +pub fn mk_attr_outer(span: Span, id: AttrId, item: MetaItem) -> Attribute { + mk_spanned_attr_outer(span, id, item) } /// Returns an outer attribute with the given value and span. diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index e75671d27aa24..9d7f57b2af934 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -27,6 +27,7 @@ use print::pp::Breaks::{Consistent, Inconsistent}; use ptr::P; use std_inject; use symbol::{Symbol, keywords}; +use syntax_pos::DUMMY_SP; use tokenstream::{self, TokenTree}; use rustc_i128::i128; @@ -118,12 +119,12 @@ pub fn print_crate<'a>(cm: &'a CodeMap, // #![feature(prelude_import)] let prelude_import_meta = attr::mk_list_word_item(Symbol::intern("prelude_import")); let list = attr::mk_list_item(Symbol::intern("feature"), vec![prelude_import_meta]); - let fake_attr = attr::mk_attr_inner(attr::mk_attr_id(), list); + let fake_attr = attr::mk_attr_inner(DUMMY_SP, attr::mk_attr_id(), list); s.print_attribute(&fake_attr)?; // #![no_std] let no_std_meta = attr::mk_word_item(Symbol::intern("no_std")); - let fake_attr = attr::mk_attr_inner(attr::mk_attr_id(), no_std_meta); + let fake_attr = attr::mk_attr_inner(DUMMY_SP, attr::mk_attr_id(), no_std_meta); s.print_attribute(&fake_attr)?; } diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 68d807b24a788..4a2dfaf61247c 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -56,7 +56,8 @@ pub fn maybe_inject_crates_ref(sess: &ParseSess, let crate_name = Symbol::intern(&alt_std_name.unwrap_or(name.to_string())); krate.module.items.insert(0, P(ast::Item { - attrs: vec![attr::mk_attr_outer(attr::mk_attr_id(), + attrs: vec![attr::mk_attr_outer(DUMMY_SP, + attr::mk_attr_id(), attr::mk_word_item(Symbol::intern("macro_use")))], vis: ast::Visibility::Inherited, node: ast::ItemKind::ExternCrate(Some(crate_name)), diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 74ec33fdd2a85..dd2756cd2b22c 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -195,7 +195,8 @@ impl fold::Folder for EntryPointCleaner { let dead_code_str = Symbol::intern("dead_code"); let word_vec = vec![attr::mk_list_word_item(dead_code_str)]; let allow_dead_code_item = attr::mk_list_item(allow_str, word_vec); - let allow_dead_code = attr::mk_attr_outer(attr::mk_attr_id(), + let allow_dead_code = attr::mk_attr_outer(DUMMY_SP, + attr::mk_attr_id(), allow_dead_code_item); ast::Item { From d97226c132e820b4636df6e7f8287d45377c64b7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 19 Jan 2017 16:47:17 +0100 Subject: [PATCH 08/15] Add new rustdoc ui tests --- src/bootstrap/check.rs | 71 +++++++++++++++++++++++++++++++++++ src/bootstrap/step.rs | 5 +++ src/test/rustdoc-test/test.rs | 14 +++++++ 3 files changed, 90 insertions(+) create mode 100644 src/test/rustdoc-test/test.rs diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 19aac0f36bb27..1801d5bdd80e1 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -19,6 +19,7 @@ use std::collections::HashSet; use std::env; use std::fmt; use std::fs; +use std::io::Read; use std::path::{PathBuf, Path}; use std::process::Command; @@ -316,6 +317,76 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) { build.run(&mut cmd); } +pub fn markdown_test_output_check(build: &Build, compiler: &Compiler) { + let _time = util::timeit(); + for entry in fs::read_dir("src/test/rustdoc-test") + .expect("markdown_test_output_check: read_dir failed") { + if let Ok(entry) = entry { + if entry.path().extension().and_then(|s| s.to_str()) != Some("rs") { + continue + } + markdown_test_output_check_entry(build, compiler, entry.path().as_path()); + } + } +} + +fn markdown_test_output_check_entry(build: &Build, compiler: &Compiler, path: &Path) { + let mut file = fs::File::open(path) + .expect("markdown_test_output_check_entry File::open failed"); + let mut content = String::new(); + file.read_to_string(&mut content) + .expect("markdown_test_output_check_entry read_to_string failed"); + let mut ignore = false; + let mut v: Vec = + content.split("\n") + .enumerate() + .filter_map(|(line_nb, line)| { + let sline = line.split("///").last().unwrap_or(""); + let line = sline.trim_left(); + if line.starts_with("```") && + !line.contains("ignore") { + if ignore { + ignore = false; + None + } else { + ignore = true; + Some(line_nb + 1) + } + } else { + None + } + }) + .collect(); + let mut cmd = Command::new(build.rustdoc(compiler)); + build.add_rustc_lib_path(compiler, &mut cmd); + build.add_rust_test_threads(&mut cmd); + cmd.arg("--test"); + cmd.arg(path); + cmd.env("RUSTC_BOOTSTRAP", "1"); + + cmd.arg("--test-args").arg(build.flags.cmd.test_args().join(" ")); + + output(&mut cmd).split("\n") + .filter(|s| s.starts_with("test ")) + .inspect(|s| { + let tmp: Vec<&str> = s.split(" - line ").collect(); + if tmp.len() == 2 { + let line = usize::from_str_radix(tmp[1].split(" ...") + .next() + .unwrap_or("0"), 10) + .unwrap_or(0); + if let Ok(pos) = v.binary_search(&line) { + v.remove(pos); + } else { + panic!("Not found doc test: \"{}\" in {:?}", s, v); + } + } + }).all(|_| true); + if v.len() != 0 { + panic!("Not found test at line{} {:?}", if v.len() > 1 { "s" } else { "" }, v); + } +} + /// Run all unit tests plus documentation tests for an entire crate DAG defined /// by a `Cargo.toml` /// diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 3932a7cf8c563..c3e0e08223065 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -474,6 +474,11 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .default(true) .host(true) .run(move |s| check::docs(build, &s.compiler())); + rules.test("check-rustdoc-output", "src/test/rustdoc-test") + .dep(|s| s.name("libtest")) + .default(true) + .host(true) + .run(move |s| check::markdown_test_output_check(build, &s.compiler())); rules.test("check-distcheck", "distcheck") .dep(|s| s.name("dist-src")) .run(move |_| check::distcheck(build)); diff --git a/src/test/rustdoc-test/test.rs b/src/test/rustdoc-test/test.rs new file mode 100644 index 0000000000000..96a4a35282beb --- /dev/null +++ b/src/test/rustdoc-test/test.rs @@ -0,0 +1,14 @@ +/// This is a Foo; +/// +/// ``` +/// println!("baaaaaar"); +/// ``` +#[unstable] +pub struct Foo; + +/// This is a Bar; +/// +/// ``` +/// println!("fooooo"); +/// ``` +pub struct Bar; From aea6f3234af12f0a7c098c2a80803061aba76608 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 20 Jan 2017 19:03:09 +0100 Subject: [PATCH 09/15] Put rustdoc --test ui check at the end of docs check --- src/bootstrap/check.rs | 3 +-- src/bootstrap/step.rs | 5 ----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 1801d5bdd80e1..f8c31d7337191 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -275,6 +275,7 @@ pub fn docs(build: &Build, compiler: &Compiler) { println!("doc tests for: {}", p.display()); markdown_test(build, compiler, &p); } + markdown_test(build, compiler, &output); } /// Run the error index generator tool to execute the tests located in the error @@ -296,8 +297,6 @@ pub fn error_index(build: &Build, compiler: &Compiler) { .arg("markdown") .arg(&output) .env("CFG_BUILD", &build.config.build)); - - markdown_test(build, compiler, &output); } fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) { diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index c3e0e08223065..3932a7cf8c563 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -474,11 +474,6 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .default(true) .host(true) .run(move |s| check::docs(build, &s.compiler())); - rules.test("check-rustdoc-output", "src/test/rustdoc-test") - .dep(|s| s.name("libtest")) - .default(true) - .host(true) - .run(move |s| check::markdown_test_output_check(build, &s.compiler())); rules.test("check-distcheck", "distcheck") .dep(|s| s.name("dist-src")) .run(move |_| check::distcheck(build)); From 44b59be0f2ad38c39b67a6c8ebfe826c4c30cbd9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 20 Jan 2017 23:24:20 +0100 Subject: [PATCH 10/15] Move test from bootstrap to compiletest --- src/bootstrap/check.rs | 74 +--------------- src/test/rustdoc-test/test.rs | 14 ---- src/test/rustdoc/test_option_check/test.rs | 27 ++++++ src/tools/compiletest/src/runtest.rs | 98 ++++++++++++++++++---- 4 files changed, 113 insertions(+), 100 deletions(-) delete mode 100644 src/test/rustdoc-test/test.rs create mode 100644 src/test/rustdoc/test_option_check/test.rs diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index f8c31d7337191..19aac0f36bb27 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -19,7 +19,6 @@ use std::collections::HashSet; use std::env; use std::fmt; use std::fs; -use std::io::Read; use std::path::{PathBuf, Path}; use std::process::Command; @@ -275,7 +274,6 @@ pub fn docs(build: &Build, compiler: &Compiler) { println!("doc tests for: {}", p.display()); markdown_test(build, compiler, &p); } - markdown_test(build, compiler, &output); } /// Run the error index generator tool to execute the tests located in the error @@ -297,6 +295,8 @@ pub fn error_index(build: &Build, compiler: &Compiler) { .arg("markdown") .arg(&output) .env("CFG_BUILD", &build.config.build)); + + markdown_test(build, compiler, &output); } fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) { @@ -316,76 +316,6 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) { build.run(&mut cmd); } -pub fn markdown_test_output_check(build: &Build, compiler: &Compiler) { - let _time = util::timeit(); - for entry in fs::read_dir("src/test/rustdoc-test") - .expect("markdown_test_output_check: read_dir failed") { - if let Ok(entry) = entry { - if entry.path().extension().and_then(|s| s.to_str()) != Some("rs") { - continue - } - markdown_test_output_check_entry(build, compiler, entry.path().as_path()); - } - } -} - -fn markdown_test_output_check_entry(build: &Build, compiler: &Compiler, path: &Path) { - let mut file = fs::File::open(path) - .expect("markdown_test_output_check_entry File::open failed"); - let mut content = String::new(); - file.read_to_string(&mut content) - .expect("markdown_test_output_check_entry read_to_string failed"); - let mut ignore = false; - let mut v: Vec = - content.split("\n") - .enumerate() - .filter_map(|(line_nb, line)| { - let sline = line.split("///").last().unwrap_or(""); - let line = sline.trim_left(); - if line.starts_with("```") && - !line.contains("ignore") { - if ignore { - ignore = false; - None - } else { - ignore = true; - Some(line_nb + 1) - } - } else { - None - } - }) - .collect(); - let mut cmd = Command::new(build.rustdoc(compiler)); - build.add_rustc_lib_path(compiler, &mut cmd); - build.add_rust_test_threads(&mut cmd); - cmd.arg("--test"); - cmd.arg(path); - cmd.env("RUSTC_BOOTSTRAP", "1"); - - cmd.arg("--test-args").arg(build.flags.cmd.test_args().join(" ")); - - output(&mut cmd).split("\n") - .filter(|s| s.starts_with("test ")) - .inspect(|s| { - let tmp: Vec<&str> = s.split(" - line ").collect(); - if tmp.len() == 2 { - let line = usize::from_str_radix(tmp[1].split(" ...") - .next() - .unwrap_or("0"), 10) - .unwrap_or(0); - if let Ok(pos) = v.binary_search(&line) { - v.remove(pos); - } else { - panic!("Not found doc test: \"{}\" in {:?}", s, v); - } - } - }).all(|_| true); - if v.len() != 0 { - panic!("Not found test at line{} {:?}", if v.len() > 1 { "s" } else { "" }, v); - } -} - /// Run all unit tests plus documentation tests for an entire crate DAG defined /// by a `Cargo.toml` /// diff --git a/src/test/rustdoc-test/test.rs b/src/test/rustdoc-test/test.rs deleted file mode 100644 index 96a4a35282beb..0000000000000 --- a/src/test/rustdoc-test/test.rs +++ /dev/null @@ -1,14 +0,0 @@ -/// This is a Foo; -/// -/// ``` -/// println!("baaaaaar"); -/// ``` -#[unstable] -pub struct Foo; - -/// This is a Bar; -/// -/// ``` -/// println!("fooooo"); -/// ``` -pub struct Bar; diff --git a/src/test/rustdoc/test_option_check/test.rs b/src/test/rustdoc/test_option_check/test.rs new file mode 100644 index 0000000000000..772d258bc800f --- /dev/null +++ b/src/test/rustdoc/test_option_check/test.rs @@ -0,0 +1,27 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:--test +// check-stdout + +/// This is a Foo; +/// +/// ``` +/// println!("baaaaaar"); +/// ``` +#[unstable] +pub struct Foo; + +/// This is a Bar; +/// +/// ``` +/// println!("fooooo"); +/// ``` +pub struct Bar; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 86fa5e70c9c28..11c43b7150f9d 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -43,7 +43,7 @@ pub fn run(config: Config, testpaths: &TestPaths) { } _ => { - // android has it's own gdb handling + // android has its own gdb handling if config.mode == DebugInfoGdb && config.gdb.is_none() { panic!("gdb not available but debuginfo gdb debuginfo test requested"); } @@ -1879,22 +1879,92 @@ actual:\n\ fn run_rustdoc_test(&self) { assert!(self.revision.is_none(), "revisions not relevant here"); - let out_dir = self.output_base_name(); - let _ = fs::remove_dir_all(&out_dir); - self.create_dir_racy(&out_dir); + if self.props.compile_flags.contains(&"--test".to_owned()) && + self.props.check_stdout == true { + self.check_rustdoc_test_option(); + } else { + let out_dir = self.output_base_name(); + let _ = fs::remove_dir_all(&out_dir); + self.create_dir_racy(&out_dir); - let proc_res = self.document(&out_dir); - if !proc_res.status.success() { - self.fatal_proc_rec("rustdoc failed!", &proc_res); + let proc_res = self.document(&out_dir); + if !proc_res.status.success() { + self.fatal_proc_rec("rustdoc failed!", &proc_res); + } + let root = self.find_rust_src_root().unwrap(); + + let res = self.cmd2procres(Command::new(&self.config.docck_python) + .arg(root.join("src/etc/htmldocck.py")) + .arg(out_dir) + .arg(&self.testpaths.file)); + if !res.status.success() { + self.fatal_proc_rec("htmldocck failed!", &res); + } } - let root = self.find_rust_src_root().unwrap(); + } + + fn check_rustdoc_test_option(&self) { + let mut file = fs::File::open(&self.testpaths.file) + .expect("markdown_test_output_check_entry File::open failed"); + let mut content = String::new(); + file.read_to_string(&mut content) + .expect("markdown_test_output_check_entry read_to_string failed"); + let mut ignore = false; + let mut v: Vec = + content.split("\n") + .enumerate() + .filter_map(|(line_nb, line)| { + let sline = line.split("///").last().unwrap_or(""); + let line = sline.trim_left(); + if line.starts_with("```") && + !line.contains("ignore") { + if ignore { + ignore = false; + None + } else { + ignore = true; + Some(line_nb + 1) + } + } else { + None + } + }) + .collect(); - let res = self.cmd2procres(Command::new(&self.config.docck_python) - .arg(root.join("src/etc/htmldocck.py")) - .arg(out_dir) - .arg(&self.testpaths.file)); - if !res.status.success() { - self.fatal_proc_rec("htmldocck failed!", &res); + let args = ProcArgs { + prog: self.config.rustdoc_path.to_str().unwrap().to_owned(), + args: vec!["--test".to_owned(), self.testpaths.file.to_str().unwrap().to_owned()], + }; + let env = self.props.exec_env.clone(); + let res = self.compose_and_run(args, + env, + self.config.run_lib_path.to_str().unwrap(), + None, + None); + + res.stdout.split("\n") + .filter(|s| s.starts_with("test ")) + .inspect(|s| { + let tmp: Vec<&str> = s.split(" - line ").collect(); + if tmp.len() == 2 { + let line = usize::from_str_radix(tmp[1].split(" ...") + .next() + .unwrap_or("0"), 10) + .unwrap_or(0); + if let Ok(pos) = v.binary_search(&line) { + v.remove(pos); + } else { + self.fatal_proc_rec(&format!("Not found doc test: \"{}\" in {:?}", + s, v), + &res); + } + } + }) + .all(|_| true); + if v.len() != 0 { + self.fatal_proc_rec(&format!("Not found test at line{} {:?}", + if v.len() > 1 { "s" } else { "" }, v), + &res); } } From 6756b72a1ddbebe657e36b40064170685c7e140f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 23 Jan 2017 22:46:18 +0100 Subject: [PATCH 11/15] Create new flag to test rustdoc --test --- .gitmodules | 2 +- src/librustdoc/test.rs | 3 +- src/rt/hoedown | 2 +- src/test/rustdoc/test_option_check/test.rs | 5 +- src/tools/compiletest/src/header.rs | 11 +++ src/tools/compiletest/src/runtest.rs | 85 ++++++++++------------ 6 files changed, 55 insertions(+), 53 deletions(-) diff --git a/.gitmodules b/.gitmodules index 73824b7b42c9c..39288a7ae4907 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,7 +7,7 @@ url = https://github.com/rust-lang/compiler-rt.git [submodule "src/rt/hoedown"] path = src/rt/hoedown - url = https://github.com/GuillaumeGomez/hoedown.git + url = https://github.com/rust-lang/hoedown.git [submodule "src/jemalloc"] path = src/jemalloc url = https://github.com/rust-lang/jemalloc.git diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index d5451d6a6c37d..6b6330ef12a94 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -467,7 +467,8 @@ impl Collector { pub fn get_line(&self) -> usize { if let Some(ref codemap) = self.codemap{ - codemap.lookup_char_pos(BytePos(self.start_line as u32)).line - 1 + let line = codemap.lookup_char_pos(BytePos(self.start_line as u32)).line; + if line > 0 { line - 1 } else { line } } else { self.start_line } diff --git a/src/rt/hoedown b/src/rt/hoedown index 78e7b6f69d3fa..a3736a0a1907c 160000 --- a/src/rt/hoedown +++ b/src/rt/hoedown @@ -1 +1 @@ -Subproject commit 78e7b6f69d3fa0cb6ae6e7fb9278c3fd167ec0d1 +Subproject commit a3736a0a1907cbc8bf619708738815a5fd789c80 diff --git a/src/test/rustdoc/test_option_check/test.rs b/src/test/rustdoc/test_option_check/test.rs index 772d258bc800f..b2afe43204d41 100644 --- a/src/test/rustdoc/test_option_check/test.rs +++ b/src/test/rustdoc/test_option_check/test.rs @@ -8,15 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags:--test -// check-stdout +// compile-flags: --test +// check-test-line-numbers-match /// This is a Foo; /// /// ``` /// println!("baaaaaar"); /// ``` -#[unstable] pub struct Foo; /// This is a Bar; diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index ac1ac1c2f6c08..71d8d62c75b69 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -224,6 +224,8 @@ pub struct TestProps { pub incremental_dir: Option, // Specifies that a cfail test must actually compile without errors. pub must_compile_successfully: bool, + // rustdoc will test the output of the `--test` option + pub check_test_line_numbers_match: bool, } impl TestProps { @@ -248,6 +250,7 @@ impl TestProps { forbid_output: vec![], incremental_dir: None, must_compile_successfully: false, + check_test_line_numbers_match: false, } } @@ -347,6 +350,10 @@ impl TestProps { if !self.must_compile_successfully { self.must_compile_successfully = parse_must_compile_successfully(ln); } + + if !self.check_test_line_numbers_match { + self.check_test_line_numbers_match = parse_check_test_line_numbers_match(ln); + } }); for key in vec!["RUST_TEST_NOCAPTURE", "RUST_TEST_THREADS"] { @@ -458,6 +465,10 @@ fn parse_must_compile_successfully(line: &str) -> bool { parse_name_directive(line, "must-compile-successfully") } +fn parse_check_test_line_numbers_match(line: &str) -> bool { + parse_name_directive(line, "check-test-line-numbers-match") +} + fn parse_env(line: &str, name: &str) -> Option<(String, String)> { parse_name_value_directive(line, name).map(|nv| { // nv is either FOO or FOO=BAR diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 11c43b7150f9d..a8c46722e163b 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1879,20 +1879,19 @@ actual:\n\ fn run_rustdoc_test(&self) { assert!(self.revision.is_none(), "revisions not relevant here"); - if self.props.compile_flags.contains(&"--test".to_owned()) && - self.props.check_stdout == true { - self.check_rustdoc_test_option(); - } else { - let out_dir = self.output_base_name(); - let _ = fs::remove_dir_all(&out_dir); - self.create_dir_racy(&out_dir); + let out_dir = self.output_base_name(); + let _ = fs::remove_dir_all(&out_dir); + self.create_dir_racy(&out_dir); - let proc_res = self.document(&out_dir); - if !proc_res.status.success() { - self.fatal_proc_rec("rustdoc failed!", &proc_res); - } - let root = self.find_rust_src_root().unwrap(); + let proc_res = self.document(&out_dir); + if !proc_res.status.success() { + self.fatal_proc_rec("rustdoc failed!", &proc_res); + } + if self.props.check_test_line_numbers_match == true { + self.check_rustdoc_test_option(proc_res); + } else { + let root = self.find_rust_src_root().unwrap(); let res = self.cmd2procres(Command::new(&self.config.docck_python) .arg(root.join("src/etc/htmldocck.py")) .arg(out_dir) @@ -1903,7 +1902,7 @@ actual:\n\ } } - fn check_rustdoc_test_option(&self) { + fn check_rustdoc_test_option(&self, res: ProcRes) { let mut file = fs::File::open(&self.testpaths.file) .expect("markdown_test_output_check_entry File::open failed"); let mut content = String::new(); @@ -1911,13 +1910,12 @@ actual:\n\ .expect("markdown_test_output_check_entry read_to_string failed"); let mut ignore = false; let mut v: Vec = - content.split("\n") + content.lines() .enumerate() .filter_map(|(line_nb, line)| { let sline = line.split("///").last().unwrap_or(""); let line = sline.trim_left(); - if line.starts_with("```") && - !line.contains("ignore") { + if line.starts_with("```") { if ignore { ignore = false; None @@ -1931,37 +1929,30 @@ actual:\n\ }) .collect(); - let args = ProcArgs { - prog: self.config.rustdoc_path.to_str().unwrap().to_owned(), - args: vec!["--test".to_owned(), self.testpaths.file.to_str().unwrap().to_owned()], - }; - let env = self.props.exec_env.clone(); - let res = self.compose_and_run(args, - env, - self.config.run_lib_path.to_str().unwrap(), - None, - None); - - res.stdout.split("\n") - .filter(|s| s.starts_with("test ")) - .inspect(|s| { - let tmp: Vec<&str> = s.split(" - line ").collect(); - if tmp.len() == 2 { - let line = usize::from_str_radix(tmp[1].split(" ...") - .next() - .unwrap_or("0"), 10) - .unwrap_or(0); - if let Ok(pos) = v.binary_search(&line) { - v.remove(pos); - } else { - self.fatal_proc_rec(&format!("Not found doc test: \"{}\" in {:?}", - s, v), - &res); - } - } - }) - .all(|_| true); - if v.len() != 0 { + let mut tested = 0; + for _ in res.stdout.split("\n") + .filter(|s| s.starts_with("test ")) + .inspect(|s| { + let tmp: Vec<&str> = s.split(" - line ").collect(); + if tmp.len() == 2 { + tested += 1; + let line = tmp[1].split(" ...") + .next() + .unwrap_or("0") + .parse() + .unwrap_or(0); + if let Ok(pos) = v.binary_search(&line) { + v.remove(pos); + } else { + self.fatal_proc_rec( + &format!("Not found doc test: \"{}\" in {:?}", s, v), + &res); + } + } + }) {} + if tested == 0 { + self.fatal_proc_rec("No test has been found", &res); + } else if v.len() != 0 { self.fatal_proc_rec(&format!("Not found test at line{} {:?}", if v.len() > 1 { "s" } else { "" }, v), &res); From f14479505882170f6394eedf4856ed1f5307b3a6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 28 Jan 2017 16:38:12 +0100 Subject: [PATCH 12/15] Set correct hoedown submodule branch --- .gitmodules | 1 + src/rt/hoedown | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 39288a7ae4907..86c5c780c5eb2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -8,6 +8,7 @@ [submodule "src/rt/hoedown"] path = src/rt/hoedown url = https://github.com/rust-lang/hoedown.git + branch = rust-2015-09-21-do-not-delete [submodule "src/jemalloc"] path = src/jemalloc url = https://github.com/rust-lang/jemalloc.git diff --git a/src/rt/hoedown b/src/rt/hoedown index a3736a0a1907c..da282f1bb7277 160000 --- a/src/rt/hoedown +++ b/src/rt/hoedown @@ -1 +1 @@ -Subproject commit a3736a0a1907cbc8bf619708738815a5fd789c80 +Subproject commit da282f1bb7277b4d30fa1599ee29ad8eb4dd2a92 From 7c4b79c80aafe0fc5c900ce5e31795dd973f7794 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 28 Jan 2017 18:26:37 +0100 Subject: [PATCH 13/15] Update run-make/issue-22131 to new rustdoc --test format --- src/test/run-make/issue-22131/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-make/issue-22131/Makefile b/src/test/run-make/issue-22131/Makefile index 1e8568626a6a1..f65cc9e06a329 100644 --- a/src/test/run-make/issue-22131/Makefile +++ b/src/test/run-make/issue-22131/Makefile @@ -4,4 +4,4 @@ all: foo.rs $(RUSTC) --cfg 'feature="bar"' --crate-type lib foo.rs $(HOST_RPATH_ENV) '$(RUSTDOC)' --test --cfg 'feature="bar"' \ -L $(TMPDIR) foo.rs |\ - grep -q 'test foo_0 ... ok' + grep -q 'foo.rs - line 11 ... ok' From 723eed32287d1de64f4d49c3108f863966c2cecd Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 2 Feb 2017 19:53:37 +0100 Subject: [PATCH 14/15] Update cargo version to last master --- src/tools/cargotest/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index 83fd766c54739..2dc8837a7d878 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -25,7 +25,7 @@ const TEST_REPOS: &'static [Test] = &[ Test { name: "cargo", repo: "https://github.com/rust-lang/cargo", - sha: "2324c2bbaf7fc6ea9cbdd77c034ef1af769cb617", + sha: "38f52ea846db202f322071f00b083ae8defdda3a", lock: None, }, Test { From b7f1d7a4bdf1a06d4ac1fc1d01eb7568608351a0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 3 Feb 2017 13:55:18 +0100 Subject: [PATCH 15/15] Update to last cargo version --- src/tools/cargotest/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index 2dc8837a7d878..786b3192e0675 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -25,7 +25,7 @@ const TEST_REPOS: &'static [Test] = &[ Test { name: "cargo", repo: "https://github.com/rust-lang/cargo", - sha: "38f52ea846db202f322071f00b083ae8defdda3a", + sha: "0e1e34be7540bdaed4918457654fbf028cf69e56", lock: None, }, Test {