Skip to content
This repository was archived by the owner on May 20, 2020. It is now read-only.

Commit 7623b6d

Browse files
committed
Seperate doc tests into separate stages
When generating documentation tests, the following stages will happen: - tests will be gathered from the docs as a list of strings - tests will be saved to target/doc/tests as individual files - tests will be compiled into a single binary called "rustdoc-test" - tests will be run by executing the "rustdoc-test" binary Doc tests are now actual tests. This allows us to take advantage of the existing test infrastructure supplied by rustc. Fixes #32, #54
1 parent 87a9e02 commit 7623b6d

File tree

4 files changed

+261
-193
lines changed

4 files changed

+261
-193
lines changed

example/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
//
1212
// @matches "included[?id=='nested_modules::example_module'] \
1313
// .relationships.parent" []
14+
/// An example module
15+
/// ```rust
16+
/// assert!(true);
17+
/// ```
1418
pub mod example_module {
1519

1620
// For the child:

src/error.rs

+8
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,11 @@ pub struct MovedFlag {
4444
/// A message explaning where the flag moved to
4545
pub msg: String,
4646
}
47+
48+
/// Thrown whenever creation of documentation tests fail
49+
#[derive(Debug, Fail)]
50+
#[fail(display = "Unable to test documentation: \"{}\"", output)]
51+
pub struct DocTestErr {
52+
/// The output of the Command that failed
53+
pub output: String,
54+
}

src/lib.rs

+23-73
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,11 @@ use std::env;
3636
use std::fs::{self, File};
3737
use std::io::prelude::*;
3838
use std::io;
39-
use std::iter;
4039
use std::path::{Path, PathBuf};
41-
use std::process::{self, Command, Stdio};
40+
use std::process::{Command, Stdio};
4241

4342
use cargo::Target;
4443
use json::Documentation;
45-
use test::TestResult;
4644
use ui::Ui;
4745

4846
pub use json::create_documentation;
@@ -228,81 +226,33 @@ pub fn test(config: &Config) -> Result<()> {
228226
.map_err(|e| failure::Error::from(e.context("could not find generated documentation")))?;
229227
let docs: Documentation = serde_json::from_reader(doc_json)?;
230228

229+
// TODO a better way to find crate name?
231230
let krate = docs.data.as_ref().unwrap();
232-
let tests: Vec<_> = iter::once(krate)
233-
.chain(docs.included.iter().flat_map(|data| data))
234-
.map(|data| (&data.id, test::gather_tests(&data)))
235-
.collect();
236-
237-
// Run the tests.
238-
static SUCCESS_MESSAGE: &str = "ok";
239-
static FAILURE_MESSAGE: &str = "FAILED";
240-
241-
let num_tests: usize = tests.iter().map(|&(_, ref tests)| tests.len()).sum();
242-
println!("running {} tests", num_tests);
243-
244-
let mut passed = 0;
245-
let mut failures = vec![];
246-
for (id, tests) in tests {
247-
for (number, test) in tests.iter().enumerate() {
248-
// FIXME: Make the name based off the file and line number.
249-
let name = format!("{} - {}", id, number);
250-
print!("test {} ... ", name);
251-
io::stdout().flush()?;
252-
253-
let message = match test::run_test(config, test)? {
254-
TestResult::Success => {
255-
passed += 1;
256-
SUCCESS_MESSAGE
257-
}
258-
TestResult::Failure(output) => {
259-
failures.push((name, output));
260-
FAILURE_MESSAGE
261-
}
262-
};
263-
264-
println!("{}", message);
265-
}
266-
}
231+
let crate_name = krate.id.split("::").next().unwrap();
267232

268-
if !failures.is_empty() {
269-
// Print the output of each failure.
270-
for &(ref name, ref output) in &failures {
271-
let stdout = String::from_utf8_lossy(&output.stdout);
272-
let stdout = stdout.trim();
273-
274-
if !stdout.is_empty() {
275-
println!("\n---- {} stdout ----\n{}", name, stdout);
276-
}
277-
278-
let stderr = String::from_utf8_lossy(&output.stderr);
279-
let stderr = stderr.trim();
280-
281-
if !stderr.is_empty() {
282-
println!("\n---- {} stderr ----\n{}", name, stderr);
283-
}
284-
}
233+
let location = config.output_path().join("tests");
234+
let tests = {
235+
let task = config.ui.start_task("Finding tests");
236+
task.report("In Progress");
237+
test::find_tests(&docs)
238+
};
285239

286-
// Print a summary of all failures at the bottom.
287-
println!("\nfailures:");
288-
for &(ref name, _) in &failures {
289-
println!(" {}", name);
290-
}
240+
{
241+
let task = config.ui.start_task("Saving tests");
242+
task.report("In Progress");
243+
test::save_tests(&tests, &location, &crate_name)?;
291244
}
292245

293-
println!(
294-
"\ntest result: {}. {} passed; {} failed; 0 ignored; 0 measured; 0 filtered out",
295-
if failures.is_empty() {
296-
SUCCESS_MESSAGE
297-
} else {
298-
FAILURE_MESSAGE
299-
},
300-
passed,
301-
failures.len()
302-
);
303-
304-
if !failures.is_empty() {
305-
process::exit(1);
246+
let binary = {
247+
let task = config.ui.start_task("Compiling tests");
248+
task.report("In Progress");
249+
test::compile_tests(&config, &location)?
250+
};
251+
252+
{
253+
let task = config.ui.start_task("Executing tests");
254+
task.report("In Progress");
255+
test::execute_tests(&binary)?;
306256
}
307257

308258
Ok(())

0 commit comments

Comments
 (0)