From a58d1b5346806ecfe53e27916792b13c2ac42e89 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Fri, 9 Feb 2018 09:24:23 -0600 Subject: [PATCH 1/3] trim the body of doctests after partitioning --- src/librustdoc/test.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 087d88419bc84..6f126a1ed6306 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -345,6 +345,7 @@ pub fn make_test(s: &str, opts: &TestOptions) -> (String, usize) { let (crate_attrs, everything_else) = partition_source(s); + let everything_else = everything_else.trim(); let mut line_offset = 0; let mut prog = String::new(); @@ -392,12 +393,11 @@ pub fn make_test(s: &str, .any(|code| code.contains("fn main")); if dont_insert_main || already_has_main { - prog.push_str(&everything_else); + prog.push_str(everything_else); } else { prog.push_str("fn main() {\n"); line_offset += 1; - prog.push_str(&everything_else); - prog = prog.trim().into(); + prog.push_str(everything_else); prog.push_str("\n}"); } From 70b5c458e6cfdf7c9bcb45a24e1ac99f12d68dd5 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Fri, 9 Feb 2018 10:40:27 -0600 Subject: [PATCH 2/3] add tests for the doctest construction functionality --- src/librustdoc/test.rs | 214 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 6f126a1ed6306..08258489a2ec2 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -753,3 +753,217 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirCollector<'a, 'hir> { self.visit_testable(macro_def.name.to_string(), ¯o_def.attrs, |_| ()); } } + +#[cfg(test)] +mod tests { + use super::{TestOptions, make_test}; + + #[test] + fn make_test_basic() { + //basic use: wraps with `fn main`, adds `#![allow(unused)]` + let opts = TestOptions::default(); + let input = +"assert_eq!(2+2, 4);"; + let expected = +"#![allow(unused)] +fn main() { +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, None, false, &opts); + assert_eq!(output, (expected.clone(), 2)); + } + + #[test] + fn make_test_crate_name_no_use() { + //if you give a crate name but *don't* use it within the test, it won't bother inserting + //the `extern crate` statement + let opts = TestOptions::default(); + let input = +"assert_eq!(2+2, 4);"; + let expected = +"#![allow(unused)] +fn main() { +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, Some("asdf"), false, &opts); + assert_eq!(output, (expected, 2)); + } + + #[test] + fn make_test_crate_name() { + //if you give a crate name and use it within the test, it will insert an `extern crate` + //statement before `fn main` + let opts = TestOptions::default(); + let input = +"use asdf::qwop; +assert_eq!(2+2, 4);"; + let expected = +"#![allow(unused)] +extern crate asdf; +fn main() { +use asdf::qwop; +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, Some("asdf"), false, &opts); + assert_eq!(output, (expected, 3)); + } + + #[test] + fn make_test_no_crate_inject() { + //even if you do use the crate within the test, setting `opts.no_crate_inject` will skip + //adding it anyway + let opts = TestOptions { + no_crate_inject: true, + attrs: vec![], + }; + let input = +"use asdf::qwop; +assert_eq!(2+2, 4);"; + let expected = +"#![allow(unused)] +fn main() { +use asdf::qwop; +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, Some("asdf"), false, &opts); + assert_eq!(output, (expected, 2)); + } + + #[test] + fn make_test_ignore_std() { + //even if you include a crate name, and use it in the doctest, we still won't include an + //`extern crate` statement if the crate is "std" - that's included already by the compiler! + let opts = TestOptions::default(); + let input = +"use std::*; +assert_eq!(2+2, 4);"; + let expected = +"#![allow(unused)] +fn main() { +use std::*; +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, Some("std"), false, &opts); + assert_eq!(output, (expected, 2)); + } + + #[test] + fn make_test_manual_extern_crate() { + //when you manually include an `extern crate` statement in your doctest, make_test assumes + //you've included one for your own crate too + let opts = TestOptions::default(); + let input = +"extern crate asdf; +use asdf::qwop; +assert_eq!(2+2, 4);"; + let expected = +"#![allow(unused)] +fn main() { +extern crate asdf; +use asdf::qwop; +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, Some("asdf"), false, &opts); + assert_eq!(output, (expected, 2)); + } + + #[test] + fn make_test_opts_attrs() { + //if you supplied some doctest attributes with #![doc(test(attr(...)))], it will use those + //instead of the stock #![allow(unused)] + let mut opts = TestOptions::default(); + opts.attrs.push("feature(sick_rad)".to_string()); + let input = +"use asdf::qwop; +assert_eq!(2+2, 4);"; + let expected = +"#![feature(sick_rad)] +extern crate asdf; +fn main() { +use asdf::qwop; +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, Some("asdf"), false, &opts); + assert_eq!(output, (expected, 3)); + + //adding more will also bump the returned line offset + opts.attrs.push("feature(hella_dope)".to_string()); + let expected = +"#![feature(sick_rad)] +#![feature(hella_dope)] +extern crate asdf; +fn main() { +use asdf::qwop; +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, Some("asdf"), false, &opts); + assert_eq!(output, (expected, 4)); + } + + #[test] + fn make_test_crate_attrs() { + //including inner attributes in your doctest will apply them to the whole "crate", pasting + //them outside the generated main function + let opts = TestOptions::default(); + let input = +"#![feature(sick_rad)] +assert_eq!(2+2, 4);"; + let expected = +"#![allow(unused)] +#![feature(sick_rad)] +fn main() { +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, None, false, &opts); + assert_eq!(output, (expected, 2)); + } + + #[test] + fn make_test_with_main() { + //including your own `fn main` wrapper lets the test use it verbatim + let opts = TestOptions::default(); + let input = +"fn main() { + assert_eq!(2+2, 4); +}"; + let expected = +"#![allow(unused)] +fn main() { + assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, None, false, &opts); + assert_eq!(output, (expected, 1)); + } + + #[test] + fn make_test_fake_main() { + //...but putting it in a comment will still provide a wrapper + let opts = TestOptions::default(); + let input = +"//Ceci n'est pas une `fn main` +assert_eq!(2+2, 4);"; + let expected = +"#![allow(unused)] +fn main() { +//Ceci n'est pas une `fn main` +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, None, false, &opts); + assert_eq!(output, (expected.clone(), 2)); + } + + #[test] + fn make_test_dont_insert_main() { + //even with that, if you set `dont_insert_main`, it won't create the `fn main` wrapper + let opts = TestOptions::default(); + let input = +"//Ceci n'est pas une `fn main` +assert_eq!(2+2, 4);"; + let expected = +"#![allow(unused)] +//Ceci n'est pas une `fn main` +assert_eq!(2+2, 4);".to_string(); + let output = make_test(input, None, true, &opts); + assert_eq!(output, (expected.clone(), 1)); + } +} From 72779936ec89a92731e40e0c406c4620a7c33d7d Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Fri, 9 Feb 2018 13:48:59 -0600 Subject: [PATCH 3/3] fix playground test for newly-trimmed doctests --- src/test/rustdoc/playground.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/rustdoc/playground.rs b/src/test/rustdoc/playground.rs index 8e193efaf8504..9e7c3aa490180 100644 --- a/src/test/rustdoc/playground.rs +++ b/src/test/rustdoc/playground.rs @@ -34,6 +34,6 @@ //! } //! ``` -// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D%0A"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D"]' "Run" // @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0Aprintln!(%22Hello%2C%20world!%22)%3B%0A%7D"]' "Run" -// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D%0A&version=nightly"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&version=nightly"]' "Run"