Added ability to crosscompile doctests

This commit is contained in:
Dario Gonzalez
2019-04-26 13:52:56 -07:00
parent b9de4ef89e
commit 98bd8fd88c
5 changed files with 109 additions and 33 deletions

View File

@@ -77,6 +77,10 @@ pub struct Options {
/// Optional path to persist the doctest executables to, defaults to a
/// temporary directory if not set.
pub persist_doctests: Option<PathBuf>,
/// Runtool to run doctests with
pub runtool: Option<String>,
/// Arguments to pass to the runtool
pub runtool_args: Vec<String>,
// Options that affect the documentation process
@@ -140,6 +144,8 @@ impl fmt::Debug for Options {
.field("show_coverage", &self.show_coverage)
.field("crate_version", &self.crate_version)
.field("render_options", &self.render_options)
.field("runtool", &self.runtool)
.field("runtool_args", &self.runtool_args)
.finish()
}
}
@@ -466,6 +472,8 @@ impl Options {
let codegen_options_strs = matches.opt_strs("C");
let lib_strs = matches.opt_strs("L");
let extern_strs = matches.opt_strs("extern");
let runtool = matches.opt_str("runtool");
let runtool_args = matches.opt_strs("runtool-arg");
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
@@ -496,6 +504,8 @@ impl Options {
show_coverage,
crate_version,
persist_doctests,
runtool,
runtool_args,
render_options: RenderOptions {
output,
external_html,

View File

@@ -272,7 +272,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
))
});
let tooltip = if ignore {
let tooltip = if ignore != Ignore::None {
Some(("This example is not tested".to_owned(), "ignore"))
} else if compile_fail {
Some(("This example deliberately fails to compile".to_owned(), "compile_fail"))
@@ -286,7 +286,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
s.push_str(&highlight::render_with_highlighting(
&text,
Some(&format!("rust-example-rendered{}",
if ignore { " ignore" }
if ignore != Ignore::None { " ignore" }
else if compile_fail { " compile_fail" }
else if explicit_edition { " edition " }
else { "" })),
@@ -297,7 +297,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
s.push_str(&highlight::render_with_highlighting(
&text,
Some(&format!("rust-example-rendered{}",
if ignore { " ignore" }
if ignore != Ignore::None { " ignore" }
else if compile_fail { " compile_fail" }
else if explicit_edition { " edition " }
else { "" })),
@@ -607,7 +607,7 @@ pub struct LangString {
original: String,
pub should_panic: bool,
pub no_run: bool,
pub ignore: bool,
pub ignore: Ignore,
pub rust: bool,
pub test_harness: bool,
pub compile_fail: bool,
@@ -616,13 +616,20 @@ pub struct LangString {
pub edition: Option<Edition>
}
#[derive(Eq, PartialEq, Clone, Debug)]
pub enum Ignore {
All,
None,
Some(Vec<String>),
}
impl LangString {
fn all_false() -> LangString {
LangString {
original: String::new(),
should_panic: false,
no_run: false,
ignore: false,
ignore: Ignore::None,
rust: true, // NB This used to be `notrust = false`
test_harness: false,
compile_fail: false,
@@ -637,6 +644,7 @@ impl LangString {
let mut seen_rust_tags = false;
let mut seen_other_tags = false;
let mut data = LangString::all_false();
let mut ignores = vec![];
data.original = string.to_owned();
let tokens = string.split(|c: char|
@@ -651,7 +659,11 @@ impl LangString {
seen_rust_tags = seen_other_tags == false;
}
"no_run" => { data.no_run = true; seen_rust_tags = !seen_other_tags; }
"ignore" => { data.ignore = true; seen_rust_tags = !seen_other_tags; }
"ignore" => { data.ignore = Ignore::All; seen_rust_tags = !seen_other_tags; }
x if x.starts_with("ignore-") => {
ignores.push(x.trim_start_matches("ignore-").to_owned());
seen_rust_tags = !seen_other_tags;
}
"allow_fail" => { data.allow_fail = true; seen_rust_tags = !seen_other_tags; }
"rust" => { data.rust = true; seen_rust_tags = true; }
"test_harness" => {
@@ -680,6 +692,16 @@ impl LangString {
}
}
match data.ignore {
Ignore::All => {},
Ignore::None => {
if !ignores.is_empty() {
data.ignore = Ignore::Some(ignores);
}
},
_ => unreachable!(),
}
data.rust &= !seen_other_tags || seen_rust_tags;
data

View File

@@ -1,4 +1,4 @@
use super::{ErrorCodes, LangString, Markdown, MarkdownHtml, IdMap};
use super::{ErrorCodes, LangString, Markdown, MarkdownHtml, IdMap, Ignore};
use super::plain_summary_line;
use std::cell::RefCell;
use syntax::edition::{Edition, DEFAULT_EDITION};
@@ -26,10 +26,10 @@ fn test_unique_id() {
#[test]
fn test_lang_string_parse() {
fn t(s: &str,
should_panic: bool, no_run: bool, ignore: bool, rust: bool, test_harness: bool,
should_panic: bool, no_run: bool, ignore: Ignore, rust: bool, test_harness: bool,
compile_fail: bool, allow_fail: bool, error_codes: Vec<String>,
edition: Option<Edition>) {
assert_eq!(LangString::parse(s, ErrorCodes::Yes), LangString {
assert_eq!(LangString::parse(s, ErrorCodes::Yes, true), LangString {
should_panic,
no_run,
ignore,
@@ -42,6 +42,7 @@ fn test_lang_string_parse() {
edition,
})
}
let ignore_foo = Ignore::Some(vec!("foo".to_string()));
fn v() -> Vec<String> {
Vec::new()
@@ -50,23 +51,24 @@ fn test_lang_string_parse() {
// ignore-tidy-linelength
// marker | should_panic | no_run | ignore | rust | test_harness
// | compile_fail | allow_fail | error_codes | edition
t("", false, false, false, true, false, false, false, v(), None);
t("rust", false, false, false, true, false, false, false, v(), None);
t("sh", false, false, false, false, false, false, false, v(), None);
t("ignore", false, false, true, true, false, false, false, v(), None);
t("should_panic", true, false, false, true, false, false, false, v(), None);
t("no_run", false, true, false, true, false, false, false, v(), None);
t("test_harness", false, false, false, true, true, false, false, v(), None);
t("compile_fail", false, true, false, true, false, true, false, v(), None);
t("allow_fail", false, false, false, true, false, false, true, v(), None);
t("{.no_run .example}", false, true, false, true, false, false, false, v(), None);
t("{.sh .should_panic}", true, false, false, false, false, false, false, v(), None);
t("{.example .rust}", false, false, false, true, false, false, false, v(), None);
t("{.test_harness .rust}", false, false, false, true, true, false, false, v(), None);
t("text, no_run", false, true, false, false, false, false, false, v(), None);
t("text,no_run", false, true, false, false, false, false, false, v(), None);
t("edition2015", false, false, false, true, false, false, false, v(), Some(Edition::Edition2015));
t("edition2018", false, false, false, true, false, false, false, v(), Some(Edition::Edition2018));
t("", false, false, Ignore::None, true, false, false, false, v(), None);
t("rust", false, false, Ignore::None, true, false, false, false, v(), None);
t("sh", false, false, Ignore::None, false, false, false, false, v(), None);
t("ignore", false, false, Ignore::All, true, false, false, false, v(), None);
t("ignore-foo", false, false, ignore_foo, true, false, false, false, v(), None);
t("should_panic", true, false, Ignore::None, true, false, false, false, v(), None);
t("no_run", false, true, Ignore::None, true, false, false, false, v(), None);
t("test_harness", false, false, Ignore::None, true, true, false, false, v(), None);
t("compile_fail", false, true, Ignore::None, true, false, true, false, v(), None);
t("allow_fail", false, false, Ignore::None, true, false, false, true, v(), None);
t("{.no_run .example}", false, true, Ignore::None, true, false, false, false, v(), None);
t("{.sh .should_panic}", true, false, Ignore::None, false, false, false, false, v(), None);
t("{.example .rust}", false, false, Ignore::None, true, false, false, false, v(), None);
t("{.test_harness .rust}", false, false, Ignore::None, true, true, false, false, v(), None);
t("text, no_run", false, true, Ignore::None, false, false, false, false, v(), None);
t("text,no_run", false, true, Ignore::None, false, false, false, false, v(), None);
t("edition2015", false, false, Ignore::None, true, false, false, false, v(), Some(Edition::Edition2015));
t("edition2018", false, false, Ignore::None, true, false, false, false, v(), Some(Edition::Edition2018));
}
#[test]

View File

@@ -355,6 +355,18 @@ fn opts() -> Vec<RustcOptGroup> {
"show-coverage",
"calculate percentage of public items with documentation")
}),
unstable("runtool", |o| {
o.optopt("",
"runtool",
"",
"The tool to run tests with when building for a different target than host")
}),
unstable("runtool-arg", |o| {
o.optmulti("",
"runtool-arg",
"",
"One (of possibly many) arguments to pass to the runtool")
}),
]
}

View File

@@ -1,5 +1,6 @@
use rustc_data_structures::sync::Lrc;
use rustc_interface::interface;
use rustc_target::spec::TargetTriple;
use rustc::hir;
use rustc::hir::intravisit;
use rustc::session::{self, config, DiagnosticOutput};
@@ -22,7 +23,7 @@ use testing;
use crate::clean::Attributes;
use crate::config::Options;
use crate::html::markdown::{self, ErrorCodes, LangString};
use crate::html::markdown::{self, ErrorCodes, LangString, Ignore};
#[derive(Clone, Default)]
pub struct TestOptions {
@@ -44,7 +45,7 @@ pub fn run(options: Options) -> i32 {
vec![config::CrateType::Dylib]
};
let sessopts = config::Options {
let mut sessopts = config::Options {
maybe_sysroot: options.maybe_sysroot.clone(),
search_paths: options.libs.clone(),
crate_types,
@@ -59,7 +60,7 @@ pub fn run(options: Options) -> i32 {
edition: options.edition,
..config::Options::default()
};
options.target.as_ref().map(|t| { sessopts.target_triple = t.clone() });
let config = interface::Config {
opts: sessopts,
crate_cfg: config::parse_cfgspecs(options.cfgs.clone()),
@@ -181,6 +182,9 @@ fn run_test(
should_panic: bool,
no_run: bool,
as_test_harness: bool,
runtool: Option<String>,
runtool_args: Vec<String>,
target: Option<TargetTriple>,
compile_fail: bool,
mut error_codes: Vec<String>,
opts: &TestOptions,
@@ -315,7 +319,15 @@ fn run_test(
}
// Run the code!
let mut cmd = Command::new(output_file);
let mut cmd;
if let Some(tool) = runtool {
cmd = Command::new(tool);
cmd.arg(output_file);
cmd.args(runtool_args);
}else{
cmd = Command::new(output_file);
}
match cmd.output() {
Err(e) => return Err(TestFailure::ExecutionError(e)),
@@ -661,12 +673,27 @@ impl Tester for Collector {
let opts = self.opts.clone();
let edition = config.edition.unwrap_or(self.options.edition.clone());
let options = self.options.clone();
let maybe_sysroot = self.maybe_sysroot.clone();
let linker = self.linker.clone();
let edition = config.edition.unwrap_or(self.edition);
let persist_doctests = self.persist_doctests.clone();
let runtool = self.runtool.clone();
let runtool_args = self.runtool_args.clone();
let target = self.target.clone();
let target_str = target.as_ref().map(|t| t.to_string());
debug!("creating test {}: {}", name, test);
self.tests.push(testing::TestDescAndFn {
desc: testing::TestDesc {
name: testing::DynTestName(name),
ignore: config.ignore,
name: testing::DynTestName(name.clone()),
ignore: match config.ignore {
Ignore::All => true,
Ignore::None => false,
Ignore::Some(ref ignores) => {
target_str.map_or(false,
|s| ignores.iter().any(|t| s.contains(t)))
},
},
// compiler failures are test failures
should_panic: testing::ShouldPanic::No,
allow_fail: config.allow_fail,
@@ -681,6 +708,9 @@ impl Tester for Collector {
config.should_panic,
config.no_run,
config.test_harness,
runtool,
runtool_args,
target,
config.compile_fail,
config.error_codes,
&opts,