diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index e8ff8930bdd7d..e70030912db0e 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -35,6 +35,7 @@ use std::fmt::{self, Write}; use std::slice; use std::str; use syntax::feature_gate::UnstableFeatures; +use syntax::codemap::Span; use html::render::derive_id; use html::toc::TocBuilder; @@ -429,7 +430,7 @@ pub fn render(w: &mut fmt::Formatter, } } -pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, start_line: usize) { +pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) { extern fn block(_ob: *mut hoedown_buffer, text: *const hoedown_buffer, lang: *const hoedown_buffer, @@ -454,11 +455,12 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, start_line: }); let text = lines.collect::>().join("\n"); let line = tests.get_line() + line; + let filename = tests.get_filename(); 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, - line); + line, filename); } } @@ -479,7 +481,7 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, start_line: } } - tests.set_line(start_line); + tests.set_position(position); 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 49497957be980..70ef7c597e4d7 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -18,6 +18,7 @@ use getopts; use testing; use rustc::session::search_paths::SearchPaths; use rustc::session::config::Externs; +use syntax::codemap::DUMMY_SP; use externalfiles::{ExternalHtml, LoadStringError, load_string}; @@ -154,9 +155,8 @@ 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".to_string(), - None); - find_testable_code(&input_str, &mut collector, 0); + true, opts, maybe_sysroot, None); + find_testable_code(&input_str, &mut collector, DUMMY_SP); 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 6f38da4f24b0d..930cf401e7450 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -37,7 +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 syntax_pos::{BytePos, DUMMY_SP, Pos, Span}; use errors; use errors::emitter::ColorConfig; @@ -97,7 +97,6 @@ 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 collector = Collector::new(crate_name, cfgs, libs, @@ -105,7 +104,6 @@ pub fn run(input: &str, false, opts, maybe_sysroot, - filename, Some(codemap)); { @@ -391,15 +389,14 @@ pub struct Collector { cratename: String, opts: TestOptions, maybe_sysroot: Option, - filename: String, - start_line: usize, + position: Span, codemap: Option>, } impl Collector { pub fn new(cratename: String, cfgs: Vec, libs: SearchPaths, externs: Externs, use_headers: bool, opts: TestOptions, maybe_sysroot: Option, - filename: String, codemap: Option>) -> Collector { + codemap: Option>) -> Collector { Collector { tests: Vec::new(), names: Vec::new(), @@ -412,8 +409,7 @@ impl Collector { cratename: cratename, opts: opts, maybe_sysroot: maybe_sysroot, - filename: filename, - start_line: 0, + position: DUMMY_SP, codemap: codemap, } } @@ -421,8 +417,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, - line: usize) { - let name = format!("{} - line {}", self.filename, line); + line: usize, filename: String) { + let name = format!("{} - line {}", filename, line); self.cnt += 1; let cfgs = self.cfgs.clone(); let libs = self.libs.clone(); @@ -467,16 +463,25 @@ impl Collector { } pub fn get_line(&self) -> usize { - if let Some(ref codemap) = self.codemap{ - let line = codemap.lookup_char_pos(BytePos(self.start_line as u32)).line; + if let Some(ref codemap) = self.codemap { + let line = self.position.lo.to_usize(); + let line = codemap.lookup_char_pos(BytePos(line as u32)).line; if line > 0 { line - 1 } else { line } } else { - self.start_line + 0 } } - pub fn set_line(&mut self, start_line: usize) { - self.start_line = start_line; + pub fn set_position(&mut self, position: Span) { + self.position = position; + } + + pub fn get_filename(&self) -> String { + if let Some(ref codemap) = self.codemap { + codemap.span_to_filename(self.position) + } else { + "".to_owned() + } } pub fn register_header(&mut self, name: &str, level: u32) { @@ -520,7 +525,7 @@ impl<'a, 'hir> HirCollector<'a, 'hir> { if let Some(doc) = attrs.doc_value() { self.collector.cnt = 0; markdown::find_testable_code(doc, self.collector, - attrs.span.unwrap_or(DUMMY_SP).lo.to_usize()); + attrs.span.unwrap_or(DUMMY_SP)); } nested(self); diff --git a/src/test/rustdoc/test_option_check/bar.rs b/src/test/rustdoc/test_option_check/bar.rs new file mode 100644 index 0000000000000..51daa80752622 --- /dev/null +++ b/src/test/rustdoc/test_option_check/bar.rs @@ -0,0 +1,19 @@ +// 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-test-line-numbers-match + +/// This looks like another awesome test! +/// +/// ``` +/// println!("foo?"); +/// ``` +pub fn foooo() {} diff --git a/src/test/rustdoc/test_option_check/test.rs b/src/test/rustdoc/test_option_check/test.rs index b2afe43204d41..a9578c5f434a2 100644 --- a/src/test/rustdoc/test_option_check/test.rs +++ b/src/test/rustdoc/test_option_check/test.rs @@ -11,6 +11,8 @@ // compile-flags: --test // check-test-line-numbers-match +pub mod bar; + /// This is a Foo; /// /// ``` diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index a8c46722e163b..4e527661df72e 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -30,6 +30,7 @@ use std::io::{self, BufReader}; use std::path::{Path, PathBuf}; use std::process::{Command, Output, ExitStatus}; use std::str; +use std::collections::HashMap; use extract_gdb_version; @@ -1902,17 +1903,28 @@ actual:\n\ } } - fn check_rustdoc_test_option(&self, res: ProcRes) { - let mut file = fs::File::open(&self.testpaths.file) + fn get_lines>(&self, path: &P, + mut other_files: Option<&mut Vec>) -> Vec { + 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.lines() - .enumerate() - .filter_map(|(line_nb, line)| { + content.lines() + .enumerate() + .filter_map(|(line_nb, line)| { + if (line.trim_left().starts_with("pub mod ") || + line.trim_left().starts_with("mod ")) && + line.ends_with(";") { + if let Some(ref mut other_files) = other_files { + other_files.push(line.rsplit("mod ") + .next() + .unwrap() + .replace(";", "")); + } + None + } else { let sline = line.split("///").last().unwrap_or(""); let line = sline.trim_left(); if line.starts_with("```") { @@ -1926,8 +1938,21 @@ actual:\n\ } else { None } - }) - .collect(); + } + }) + .collect() + } + + fn check_rustdoc_test_option(&self, res: ProcRes) { + let mut other_files = Vec::new(); + let mut files: HashMap> = HashMap::new(); + files.insert(self.testpaths.file.to_str().unwrap().to_owned(), + self.get_lines(&self.testpaths.file, Some(&mut other_files))); + for other_file in other_files { + let mut path = self.testpaths.file.clone(); + path.set_file_name(&format!("{}.rs", other_file)); + files.insert(path.to_str().unwrap().to_owned(), self.get_lines(&path, None)); + } let mut tested = 0; for _ in res.stdout.split("\n") @@ -1935,27 +1960,35 @@ actual:\n\ .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); + let path = tmp[0].rsplit("test ").next().unwrap(); + if let Some(ref mut v) = files.get_mut(path) { + 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, path, 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); + self.fatal_proc_rec(&format!("No test has been found... {:?}", files), &res); + } else { + for (entry, v) in &files { + if v.len() != 0 { + self.fatal_proc_rec(&format!("Not found test at line{} \"{}\":{:?}", + if v.len() > 1 { "s" } else { "" }, entry, v), + &res); + } + } } }