Auto merge of #36320 - GuillaumeGomez:rustdoc_test_info, r=alexcrichton
Add information in case of markdown block code test failure r? @steveklabnik cc @jonathandturner
This commit is contained in:
commit
c781fc4a6a
1
.gitmodules
vendored
1
.gitmodules
vendored
@ -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
|
||||
|
@ -521,17 +521,22 @@ impl<'a, I: IntoIterator<Item=&'a ast::NestedMetaItem>> NestedAttributesExt for
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug, Default)]
|
||||
pub struct Attributes {
|
||||
pub doc_strings: Vec<String>,
|
||||
pub other_attrs: Vec<ast::Attribute>
|
||||
pub other_attrs: Vec<ast::Attribute>,
|
||||
pub span: Option<syntax_pos::Span>,
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<TocBuilder>,
|
||||
}
|
||||
|
||||
@ -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()
|
||||
@ -422,11 +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) {
|
||||
data: *const hoedown_renderer_data,
|
||||
line: libc::size_t) {
|
||||
unsafe {
|
||||
if text.is_null() { return }
|
||||
let block_info = if lang.is_null() {
|
||||
@ -445,16 +453,19 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) {
|
||||
stripped_filtered_line(l).unwrap_or(l)
|
||||
});
|
||||
let text = lines.collect::<Vec<&str>>().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.compile_fail, block_info.error_codes,
|
||||
line);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@ -468,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);
|
||||
@ -488,6 +500,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 +513,7 @@ struct LangString {
|
||||
impl LangString {
|
||||
fn all_false() -> LangString {
|
||||
LangString {
|
||||
original: String::new(),
|
||||
should_panic: false,
|
||||
no_run: false,
|
||||
ignore: false,
|
||||
@ -521,6 +535,7 @@ impl LangString {
|
||||
allow_error_code_check = true;
|
||||
}
|
||||
|
||||
data.original = string.to_owned();
|
||||
let tokens = string.split(|c: char|
|
||||
!(c == '_' || c == '-' || c.is_alphanumeric())
|
||||
);
|
||||
@ -586,7 +601,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 {
|
||||
@ -599,8 +615,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;
|
||||
@ -647,6 +664,7 @@ mod tests {
|
||||
test_harness: test_harness,
|
||||
compile_fail: compile_fail,
|
||||
error_codes: error_codes,
|
||||
original: s.to_owned(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -154,8 +154,9 @@ pub fn test(input: &str, cfgs: Vec<String>, 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);
|
||||
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
|
||||
|
@ -37,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;
|
||||
|
||||
@ -79,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 =
|
||||
@ -96,13 +97,16 @@ 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,
|
||||
externs,
|
||||
false,
|
||||
opts,
|
||||
maybe_sysroot);
|
||||
maybe_sysroot,
|
||||
filename,
|
||||
Some(codemap));
|
||||
|
||||
{
|
||||
let dep_graph = DepGraph::new(false);
|
||||
@ -256,7 +260,9 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec<String>, libs: SearchPaths,
|
||||
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")
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -302,7 +308,7 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec<String>, libs: SearchPaths,
|
||||
if should_panic && out.status.success() {
|
||||
panic!("test executable succeeded when it should have failed");
|
||||
} else if !should_panic && !out.status.success() {
|
||||
panic!("test executable failed:\n{}\n{}",
|
||||
panic!("test executable failed:\n{}\n{}\n",
|
||||
str::from_utf8(&out.stdout).unwrap_or(""),
|
||||
str::from_utf8(&out.stderr).unwrap_or(""));
|
||||
}
|
||||
@ -384,11 +390,15 @@ pub struct Collector {
|
||||
cratename: String,
|
||||
opts: TestOptions,
|
||||
maybe_sysroot: Option<PathBuf>,
|
||||
filename: String,
|
||||
start_line: usize,
|
||||
codemap: Option<Rc<CodeMap>>,
|
||||
}
|
||||
|
||||
impl Collector {
|
||||
pub fn new(cratename: String, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
|
||||
use_headers: bool, opts: TestOptions, maybe_sysroot: Option<PathBuf>) -> Collector {
|
||||
use_headers: bool, opts: TestOptions, maybe_sysroot: Option<PathBuf>,
|
||||
filename: String, codemap: Option<Rc<CodeMap>>) -> Collector {
|
||||
Collector {
|
||||
tests: Vec::new(),
|
||||
names: Vec::new(),
|
||||
@ -401,18 +411,17 @@ impl Collector {
|
||||
cratename: cratename,
|
||||
opts: opts,
|
||||
maybe_sysroot: maybe_sysroot,
|
||||
filename: filename,
|
||||
start_line: 0,
|
||||
codemap: codemap,
|
||||
}
|
||||
}
|
||||
|
||||
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<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)
|
||||
};
|
||||
as_test_harness: bool, compile_fail: bool, error_codes: Vec<String>,
|
||||
line: usize) {
|
||||
let name = format!("{} - line {}", self.filename, line);
|
||||
self.cnt += 1;
|
||||
let cfgs = self.cfgs.clone();
|
||||
let libs = self.libs.clone();
|
||||
@ -456,6 +465,19 @@ 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 line > 0 { line - 1 } else { line }
|
||||
} 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
|
||||
@ -496,7 +518,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);
|
||||
|
@ -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.
|
||||
|
@ -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 std::ascii;
|
||||
@ -116,12 +117,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)?;
|
||||
}
|
||||
|
||||
|
@ -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)),
|
||||
|
@ -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 {
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit a3736a0a1907cbc8bf619708738815a5fd789c80
|
||||
Subproject commit da282f1bb7277b4d30fa1599ee29ad8eb4dd2a92
|
@ -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'
|
||||
|
26
src/test/rustdoc/test_option_check/test.rs
Normal file
26
src/test/rustdoc/test_option_check/test.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// 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 <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.
|
||||
|
||||
// compile-flags: --test
|
||||
// check-test-line-numbers-match
|
||||
|
||||
/// This is a Foo;
|
||||
///
|
||||
/// ```
|
||||
/// println!("baaaaaar");
|
||||
/// ```
|
||||
pub struct Foo;
|
||||
|
||||
/// This is a Bar;
|
||||
///
|
||||
/// ```
|
||||
/// println!("fooooo");
|
||||
/// ```
|
||||
pub struct Bar;
|
@ -25,7 +25,7 @@ const TEST_REPOS: &'static [Test] = &[
|
||||
Test {
|
||||
name: "cargo",
|
||||
repo: "https://github.com/rust-lang/cargo",
|
||||
sha: "2324c2bbaf7fc6ea9cbdd77c034ef1af769cb617",
|
||||
sha: "0e1e34be7540bdaed4918457654fbf028cf69e56",
|
||||
lock: None,
|
||||
},
|
||||
Test {
|
||||
|
@ -224,6 +224,8 @@ pub struct TestProps {
|
||||
pub incremental_dir: Option<PathBuf>,
|
||||
// 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
|
||||
|
@ -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");
|
||||
}
|
||||
@ -1887,14 +1887,75 @@ actual:\n\
|
||||
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);
|
||||
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)
|
||||
.arg(&self.testpaths.file));
|
||||
if !res.status.success() {
|
||||
self.fatal_proc_rec("htmldocck failed!", &res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
file.read_to_string(&mut content)
|
||||
.expect("markdown_test_output_check_entry read_to_string failed");
|
||||
let mut ignore = false;
|
||||
let mut v: Vec<usize> =
|
||||
content.lines()
|
||||
.enumerate()
|
||||
.filter_map(|(line_nb, line)| {
|
||||
let sline = line.split("///").last().unwrap_or("");
|
||||
let line = sline.trim_left();
|
||||
if line.starts_with("```") {
|
||||
if ignore {
|
||||
ignore = false;
|
||||
None
|
||||
} else {
|
||||
ignore = true;
|
||||
Some(line_nb + 1)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user