From 9fab267da18f6e7c8e424a2c1b074cfd562db405 Mon Sep 17 00:00:00 2001 From: Michael Bryan Date: Sun, 9 Jul 2017 04:31:30 +0800 Subject: [PATCH 1/9] Added some end-user "sanity" tests --- tests/integration_tests.rs | 197 +++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 tests/integration_tests.rs diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs new file mode 100644 index 00000000..66911e16 --- /dev/null +++ b/tests/integration_tests.rs @@ -0,0 +1,197 @@ +/// Tests which exercise the overall application, in particular the `MDBook` +/// initialization and build/rendering process. +/// +/// This will create an entire book in a temporary directory using some +/// dummy content. + +extern crate mdbook; +extern crate tempdir; +extern crate env_logger; + +use std::path::Path; +use std::fs::{self, File}; +use std::io::{Read, Write}; + +use tempdir::TempDir; +use mdbook::MDBook; + + +const SUMMARY_MD: &'static str = "# Summary + +[Introduction](intro.md) + +- [First Chapter](./first/index.md) + - [Nested Chapter](./first/nested.md) +- [Second Chapter](./second.md) + +[Conclusion](./conclusion.md) +"; + +const INTRO: &'static str = "# Introduction + +Here's some interesting text..."; + +const FIRST: &'static str = "# First Chapter + +more text."; + +const NESTED: &'static str = r#"# Nested Chapter + +This file has some testable code. + +```rust +assert!($TEST_STATUS); +```"#; + +const SECOND: &'static str = "# Second Chapter"; + +const CONCLUSION: &'static str = "# Conclusion"; + +#[test] +fn build_the_dummy_book() { + let temp = create_book(true); + let mut md = MDBook::new(temp.path()); + + md.build().unwrap(); +} + +#[test] +fn mdbook_can_correctly_test_a_passing_book() { + let temp = create_book(true); + let mut md = MDBook::new(temp.path()); + + assert!(md.test().is_ok()); +} + +#[test] +fn mdbook_detects_book_with_failing_tests() { + let temp = create_book(false); + let mut md = MDBook::new(temp.path()); + + assert!(md.test().is_err()); +} + +#[test] +fn by_default_mdbook_generates_rendered_content_in_the_book_directory() { + let temp = create_book(false); + let mut md = MDBook::new(temp.path()); + + assert!(!temp.path().join("book").exists()); + md.build().unwrap(); + + assert!(temp.path().join("book").exists()); + assert!(temp.path().join("book").join("index.html").exists()); +} + +#[test] +fn make_sure_bottom_level_files_contain_links_to_chapters() { + let temp = create_book(false); + let mut md = MDBook::new(temp.path()); + md.build().unwrap(); + + let dest = temp.path().join("book"); + let links = vec![ + "intro.html", + "first/index.html", + "first/nested.html", + "second.html", + "conclusion.html", + ]; + + let files_in_bottom_dir = vec!["index.html", "intro.html", "second.html", "conclusion.html"]; + + for filename in files_in_bottom_dir { + assert_contains_strings(dest.join(filename), &links); + } +} + +#[test] +fn check_correct_cross_links_in_nested_dir() { + let temp = create_book(false); + let mut md = MDBook::new(temp.path()); + md.build().unwrap(); + + let first = temp.path().join("book").join("first"); + let links = vec![ + r#""#, + "intro.html", + "first/index.html", + "first/nested.html", + "second.html", + "conclusion.html", + ]; + + let files_in_nested_dir = vec!["index.html", "nested.html"]; + + for filename in files_in_nested_dir { + assert_contains_strings(first.join(filename), &links); + } +} + +/// Create a dummy book in a temporary directory, using the contents of +/// `SUMMARY_MD` as a guide. +/// +/// The "Nested Chapter" file contains a code block with a single +/// `assert!($TEST_STATUS)`. If you want to check MDBook's testing +/// functionality, `$TEST_STATUS` can be substitute for either `true` or +/// `false`. This is done using the `passing_test` parameter. +fn create_book(passing_test: bool) -> TempDir { + let temp = TempDir::new("dummy_book").unwrap(); + + let src = temp.path().join("src"); + fs::create_dir_all(&src).unwrap(); + + File::create(src.join("SUMMARY.md")) + .unwrap() + .write_all(SUMMARY_MD.as_bytes()) + .unwrap(); + File::create(src.join("intro.md")) + .unwrap() + .write_all(INTRO.as_bytes()) + .unwrap(); + + let first = src.join("first"); + fs::create_dir_all(&first).unwrap(); + File::create(first.join("index.md")) + .unwrap() + .write_all(FIRST.as_bytes()) + .unwrap(); + + let to_substitute = if passing_test { "true" } else { "false" }; + let nested_text = NESTED.replace("$TEST_STATUS", to_substitute); + File::create(first.join("nested.md")) + .unwrap() + .write_all(nested_text.as_bytes()) + .unwrap(); + + File::create(src.join("second.md")) + .unwrap() + .write_all(SECOND.as_bytes()) + .unwrap(); + File::create(src.join("conclusion.md")) + .unwrap() + .write_all(CONCLUSION.as_bytes()) + .unwrap(); + + temp +} + +fn assert_contains_strings>(filename: P, strings: &[&str]) { + println!("Checking {}", filename.as_ref().display()); + println!(); + + let mut content = String::new(); + File::open(filename) + .expect("Couldn't open the provided file") + .read_to_string(&mut content) + .unwrap(); + + println!("{}", content); + println!(); + println!(); + + for s in strings { + println!("Checking for {:?}", s); + assert!(content.contains(s)); + } +} \ No newline at end of file From e3f047a35d4331996322c4f7b0ca66ee9fda3615 Mon Sep 17 00:00:00 2001 From: Michael Bryan Date: Sun, 9 Jul 2017 05:01:26 +0800 Subject: [PATCH 2/9] Added playpen and mdbook init tests --- tests/integration_tests.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 66911e16..8bd2751c 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -128,6 +128,38 @@ fn check_correct_cross_links_in_nested_dir() { } } +#[test] +fn run_mdbook_init() { + let created_files = vec!["book", "src", "src/SUMMARY.md", "src/chapter_1.md"]; + + let temp = TempDir::new("mdbook").unwrap(); + for file in &created_files { + assert!(!temp.path().join(file).exists()); + } + + let mut md = MDBook::new(temp.path()); + md.init().unwrap(); + + for file in &created_files { + assert!(temp.path().join(file).exists(), "{} doesn't exist", file); + } +} + +#[test] +fn rendered_code_has_playpen_stuff() { + let temp = create_book(true); + let mut md = MDBook::new(temp.path()); + md.build().unwrap(); + + let nested = temp.path().join("book/first/nested.html"); + let playpen_class = vec![r#"class="playpen""#]; + + assert_contains_strings(nested, &playpen_class); + + let book_js = temp.path().join("book/book.js"); + assert_contains_strings(book_js, &[".playpen"]); +} + /// Create a dummy book in a temporary directory, using the contents of /// `SUMMARY_MD` as a guide. /// From 8b7c95e02f8dcd71482ce7d7a310225855e17ce4 Mon Sep 17 00:00:00 2001 From: Michael Bryan Date: Sun, 9 Jul 2017 17:45:04 +0800 Subject: [PATCH 3/9] Made sure the rendered content actually contains the original text --- tests/integration_tests.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 8bd2751c..07a6dcf8 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -160,6 +160,28 @@ fn rendered_code_has_playpen_stuff() { assert_contains_strings(book_js, &[".playpen"]); } +#[test] +fn chapter_content_appears_in_rendered_document() { + let content = vec![ + ("index.html", "Here's some interesting text"), + ("second.html", "Second Chapter"), + ("first/nested.html", "testable code"), + ("first/index.html", "more text"), + ("conclusion.html", "Conclusion"), + ]; + + let temp = create_book(true); + let mut md = MDBook::new(temp.path()); + md.build().unwrap(); + + let destination = temp.path().join("book"); + + for (filename, text) in content { + let path = destination.join(filename); + assert_contains_strings(path, &[text]); + } +} + /// Create a dummy book in a temporary directory, using the contents of /// `SUMMARY_MD` as a guide. /// @@ -208,6 +230,8 @@ fn create_book(passing_test: bool) -> TempDir { temp } +/// Read the contents of the provided file into memory and then iterate through +/// the list of strings asserting that the file contains all of them. fn assert_contains_strings>(filename: P, strings: &[&str]) { println!("Checking {}", filename.as_ref().display()); println!(); @@ -226,4 +250,4 @@ fn assert_contains_strings>(filename: P, strings: &[&str]) { println!("Checking for {:?}", s); assert!(content.contains(s)); } -} \ No newline at end of file +} From cd11035a69445be57f10fe116c9a0f0d5f4d5fe1 Mon Sep 17 00:00:00 2001 From: Michael Bryan Date: Sun, 9 Jul 2017 18:24:45 +0800 Subject: [PATCH 4/9] trivial change to make travis run again --- tests/integration_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 07a6dcf8..ca9b6c86 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -66,7 +66,7 @@ fn mdbook_can_correctly_test_a_passing_book() { #[test] fn mdbook_detects_book_with_failing_tests() { let temp = create_book(false); - let mut md = MDBook::new(temp.path()); + let mut md: MDBook = MDBook::new(temp.path()); assert!(md.test().is_err()); } From c90c0f78488cdb86efad71f376cc8a945f28966f Mon Sep 17 00:00:00 2001 From: Michael Bryan Date: Sun, 9 Jul 2017 20:02:31 +0800 Subject: [PATCH 5/9] Updated the book testing to take into account #340 --- tests/integration_tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index ca9b6c86..a92466eb 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -60,7 +60,7 @@ fn mdbook_can_correctly_test_a_passing_book() { let temp = create_book(true); let mut md = MDBook::new(temp.path()); - assert!(md.test().is_ok()); + assert!(md.test(vec![]).is_ok()); } #[test] @@ -68,7 +68,7 @@ fn mdbook_detects_book_with_failing_tests() { let temp = create_book(false); let mut md: MDBook = MDBook::new(temp.path()); - assert!(md.test().is_err()); + assert!(md.test(vec![]).is_err()); } #[test] From 7e8819f4d280749c14c7affe8d0dbf5f5b065dad Mon Sep 17 00:00:00 2001 From: Michael Bryan Date: Sun, 9 Jul 2017 22:08:57 +0800 Subject: [PATCH 6/9] Bye bye println() debugging --- tests/integration_tests.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index a92466eb..26558be5 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -233,21 +233,15 @@ fn create_book(passing_test: bool) -> TempDir { /// Read the contents of the provided file into memory and then iterate through /// the list of strings asserting that the file contains all of them. fn assert_contains_strings>(filename: P, strings: &[&str]) { - println!("Checking {}", filename.as_ref().display()); - println!(); + let filename = filename.as_ref(); let mut content = String::new(); - File::open(filename) + File::open(&filename) .expect("Couldn't open the provided file") .read_to_string(&mut content) - .unwrap(); - - println!("{}", content); - println!(); - println!(); + .expect("Couldn't read the file's contents"); for s in strings { - println!("Checking for {:?}", s); - assert!(content.contains(s)); + assert!(content.contains(s), "Searching for {:?} in {}\n\n{}", s, filename.display(), content); } } From 29e00c0d97ed6b87da95f9460a857e64d0a22f45 Mon Sep 17 00:00:00 2001 From: Michael Bryan Date: Mon, 10 Jul 2017 18:17:19 +0800 Subject: [PATCH 7/9] Broke the integration tests out into individual sections --- tests/helpers.rs | 111 +++++++++++++++++ tests/init.rs | 23 ++++ tests/integration_tests.rs | 247 ------------------------------------- tests/rendered_output.rs | 108 ++++++++++++++++ tests/testing.rs | 22 ++++ 5 files changed, 264 insertions(+), 247 deletions(-) create mode 100644 tests/helpers.rs create mode 100644 tests/init.rs delete mode 100644 tests/integration_tests.rs create mode 100644 tests/rendered_output.rs create mode 100644 tests/testing.rs diff --git a/tests/helpers.rs b/tests/helpers.rs new file mode 100644 index 00000000..5e82bb5f --- /dev/null +++ b/tests/helpers.rs @@ -0,0 +1,111 @@ +//! Helpers for tests which exercise the overall application, in particular +//! the `MDBook` initialization and build/rendering process. +//! +//! This will create an entire book in a temporary directory using some +//! dummy content. + +#![allow(dead_code, unused_variables, unused_imports)] +extern crate tempdir; + +use std::path::Path; +use std::fs::{self, File}; +use std::io::{Read, Write}; + +use tempdir::TempDir; + + +const SUMMARY_MD: &'static str = "# Summary + +[Introduction](intro.md) + +- [First Chapter](./first/index.md) + - [Nested Chapter](./first/nested.md) +- [Second Chapter](./second.md) + +[Conclusion](./conclusion.md) +"; + +const INTRO: &'static str = "# Introduction + +Here's some interesting text..."; + +const FIRST: &'static str = "# First Chapter + +more text."; + +const NESTED: &'static str = r#"# Nested Chapter + +This file has some testable code. + +```rust +assert!($TEST_STATUS); +```"#; + +const SECOND: &'static str = "# Second Chapter"; + +const CONCLUSION: &'static str = "# Conclusion"; + + +/// Create a dummy book in a temporary directory, using the contents of +/// `SUMMARY_MD` as a guide. +/// +/// The "Nested Chapter" file contains a code block with a single +/// `assert!($TEST_STATUS)`. If you want to check MDBook's testing +/// functionality, `$TEST_STATUS` can be substitute for either `true` or +/// `false`. This is done using the `passing_test` parameter. +pub fn create_book(passing_test: bool) -> TempDir { + let temp = TempDir::new("dummy_book").unwrap(); + + let src = temp.path().join("src"); + fs::create_dir_all(&src).unwrap(); + + File::create(src.join("SUMMARY.md")) + .unwrap() + .write_all(SUMMARY_MD.as_bytes()) + .unwrap(); + File::create(src.join("intro.md")) + .unwrap() + .write_all(INTRO.as_bytes()) + .unwrap(); + + let first = src.join("first"); + fs::create_dir_all(&first).unwrap(); + File::create(first.join("index.md")) + .unwrap() + .write_all(FIRST.as_bytes()) + .unwrap(); + + let to_substitute = if passing_test { "true" } else { "false" }; + let nested_text = NESTED.replace("$TEST_STATUS", to_substitute); + File::create(first.join("nested.md")) + .unwrap() + .write_all(nested_text.as_bytes()) + .unwrap(); + + File::create(src.join("second.md")) + .unwrap() + .write_all(SECOND.as_bytes()) + .unwrap(); + File::create(src.join("conclusion.md")) + .unwrap() + .write_all(CONCLUSION.as_bytes()) + .unwrap(); + + temp +} + +/// Read the contents of the provided file into memory and then iterate through +/// the list of strings asserting that the file contains all of them. +pub fn assert_contains_strings>(filename: P, strings: &[&str]) { + let filename = filename.as_ref(); + + let mut content = String::new(); + File::open(&filename) + .expect("Couldn't open the provided file") + .read_to_string(&mut content) + .expect("Couldn't read the file's contents"); + + for s in strings { + assert!(content.contains(s), "Searching for {:?} in {}\n\n{}", s, filename.display(), content); + } +} diff --git a/tests/init.rs b/tests/init.rs new file mode 100644 index 00000000..a31abacb --- /dev/null +++ b/tests/init.rs @@ -0,0 +1,23 @@ +extern crate mdbook; +extern crate tempdir; + +use tempdir::TempDir; +use mdbook::MDBook; + + +#[test] +fn run_mdbook_init() { + let created_files = vec!["book", "src", "src/SUMMARY.md", "src/chapter_1.md"]; + + let temp = TempDir::new("mdbook").unwrap(); + for file in &created_files { + assert!(!temp.path().join(file).exists()); + } + + let mut md = MDBook::new(temp.path()); + md.init().unwrap(); + + for file in &created_files { + assert!(temp.path().join(file).exists(), "{} doesn't exist", file); + } +} diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs deleted file mode 100644 index 26558be5..00000000 --- a/tests/integration_tests.rs +++ /dev/null @@ -1,247 +0,0 @@ -/// Tests which exercise the overall application, in particular the `MDBook` -/// initialization and build/rendering process. -/// -/// This will create an entire book in a temporary directory using some -/// dummy content. - -extern crate mdbook; -extern crate tempdir; -extern crate env_logger; - -use std::path::Path; -use std::fs::{self, File}; -use std::io::{Read, Write}; - -use tempdir::TempDir; -use mdbook::MDBook; - - -const SUMMARY_MD: &'static str = "# Summary - -[Introduction](intro.md) - -- [First Chapter](./first/index.md) - - [Nested Chapter](./first/nested.md) -- [Second Chapter](./second.md) - -[Conclusion](./conclusion.md) -"; - -const INTRO: &'static str = "# Introduction - -Here's some interesting text..."; - -const FIRST: &'static str = "# First Chapter - -more text."; - -const NESTED: &'static str = r#"# Nested Chapter - -This file has some testable code. - -```rust -assert!($TEST_STATUS); -```"#; - -const SECOND: &'static str = "# Second Chapter"; - -const CONCLUSION: &'static str = "# Conclusion"; - -#[test] -fn build_the_dummy_book() { - let temp = create_book(true); - let mut md = MDBook::new(temp.path()); - - md.build().unwrap(); -} - -#[test] -fn mdbook_can_correctly_test_a_passing_book() { - let temp = create_book(true); - let mut md = MDBook::new(temp.path()); - - assert!(md.test(vec![]).is_ok()); -} - -#[test] -fn mdbook_detects_book_with_failing_tests() { - let temp = create_book(false); - let mut md: MDBook = MDBook::new(temp.path()); - - assert!(md.test(vec![]).is_err()); -} - -#[test] -fn by_default_mdbook_generates_rendered_content_in_the_book_directory() { - let temp = create_book(false); - let mut md = MDBook::new(temp.path()); - - assert!(!temp.path().join("book").exists()); - md.build().unwrap(); - - assert!(temp.path().join("book").exists()); - assert!(temp.path().join("book").join("index.html").exists()); -} - -#[test] -fn make_sure_bottom_level_files_contain_links_to_chapters() { - let temp = create_book(false); - let mut md = MDBook::new(temp.path()); - md.build().unwrap(); - - let dest = temp.path().join("book"); - let links = vec![ - "intro.html", - "first/index.html", - "first/nested.html", - "second.html", - "conclusion.html", - ]; - - let files_in_bottom_dir = vec!["index.html", "intro.html", "second.html", "conclusion.html"]; - - for filename in files_in_bottom_dir { - assert_contains_strings(dest.join(filename), &links); - } -} - -#[test] -fn check_correct_cross_links_in_nested_dir() { - let temp = create_book(false); - let mut md = MDBook::new(temp.path()); - md.build().unwrap(); - - let first = temp.path().join("book").join("first"); - let links = vec![ - r#""#, - "intro.html", - "first/index.html", - "first/nested.html", - "second.html", - "conclusion.html", - ]; - - let files_in_nested_dir = vec!["index.html", "nested.html"]; - - for filename in files_in_nested_dir { - assert_contains_strings(first.join(filename), &links); - } -} - -#[test] -fn run_mdbook_init() { - let created_files = vec!["book", "src", "src/SUMMARY.md", "src/chapter_1.md"]; - - let temp = TempDir::new("mdbook").unwrap(); - for file in &created_files { - assert!(!temp.path().join(file).exists()); - } - - let mut md = MDBook::new(temp.path()); - md.init().unwrap(); - - for file in &created_files { - assert!(temp.path().join(file).exists(), "{} doesn't exist", file); - } -} - -#[test] -fn rendered_code_has_playpen_stuff() { - let temp = create_book(true); - let mut md = MDBook::new(temp.path()); - md.build().unwrap(); - - let nested = temp.path().join("book/first/nested.html"); - let playpen_class = vec![r#"class="playpen""#]; - - assert_contains_strings(nested, &playpen_class); - - let book_js = temp.path().join("book/book.js"); - assert_contains_strings(book_js, &[".playpen"]); -} - -#[test] -fn chapter_content_appears_in_rendered_document() { - let content = vec![ - ("index.html", "Here's some interesting text"), - ("second.html", "Second Chapter"), - ("first/nested.html", "testable code"), - ("first/index.html", "more text"), - ("conclusion.html", "Conclusion"), - ]; - - let temp = create_book(true); - let mut md = MDBook::new(temp.path()); - md.build().unwrap(); - - let destination = temp.path().join("book"); - - for (filename, text) in content { - let path = destination.join(filename); - assert_contains_strings(path, &[text]); - } -} - -/// Create a dummy book in a temporary directory, using the contents of -/// `SUMMARY_MD` as a guide. -/// -/// The "Nested Chapter" file contains a code block with a single -/// `assert!($TEST_STATUS)`. If you want to check MDBook's testing -/// functionality, `$TEST_STATUS` can be substitute for either `true` or -/// `false`. This is done using the `passing_test` parameter. -fn create_book(passing_test: bool) -> TempDir { - let temp = TempDir::new("dummy_book").unwrap(); - - let src = temp.path().join("src"); - fs::create_dir_all(&src).unwrap(); - - File::create(src.join("SUMMARY.md")) - .unwrap() - .write_all(SUMMARY_MD.as_bytes()) - .unwrap(); - File::create(src.join("intro.md")) - .unwrap() - .write_all(INTRO.as_bytes()) - .unwrap(); - - let first = src.join("first"); - fs::create_dir_all(&first).unwrap(); - File::create(first.join("index.md")) - .unwrap() - .write_all(FIRST.as_bytes()) - .unwrap(); - - let to_substitute = if passing_test { "true" } else { "false" }; - let nested_text = NESTED.replace("$TEST_STATUS", to_substitute); - File::create(first.join("nested.md")) - .unwrap() - .write_all(nested_text.as_bytes()) - .unwrap(); - - File::create(src.join("second.md")) - .unwrap() - .write_all(SECOND.as_bytes()) - .unwrap(); - File::create(src.join("conclusion.md")) - .unwrap() - .write_all(CONCLUSION.as_bytes()) - .unwrap(); - - temp -} - -/// Read the contents of the provided file into memory and then iterate through -/// the list of strings asserting that the file contains all of them. -fn assert_contains_strings>(filename: P, strings: &[&str]) { - let filename = filename.as_ref(); - - let mut content = String::new(); - File::open(&filename) - .expect("Couldn't open the provided file") - .read_to_string(&mut content) - .expect("Couldn't read the file's contents"); - - for s in strings { - assert!(content.contains(s), "Searching for {:?} in {}\n\n{}", s, filename.display(), content); - } -} diff --git a/tests/rendered_output.rs b/tests/rendered_output.rs new file mode 100644 index 00000000..077d3366 --- /dev/null +++ b/tests/rendered_output.rs @@ -0,0 +1,108 @@ +extern crate mdbook; +extern crate tempdir; + +mod helpers; +use mdbook::MDBook; + + +#[test] +fn build_the_dummy_book() { + let temp = helpers::create_book(true); + let mut md = MDBook::new(temp.path()); + + md.build().unwrap(); +} + +#[test] +fn by_default_mdbook_generates_rendered_content_in_the_book_directory() { + let temp = helpers::create_book(false); + let mut md = MDBook::new(temp.path()); + + assert!(!temp.path().join("book").exists()); + md.build().unwrap(); + + assert!(temp.path().join("book").exists()); + assert!(temp.path().join("book").join("index.html").exists()); +} + +#[test] +fn make_sure_bottom_level_files_contain_links_to_chapters() { + let temp = helpers::create_book(false); + let mut md = MDBook::new(temp.path()); + md.build().unwrap(); + + let dest = temp.path().join("book"); + let links = vec![ + "intro.html", + "first/index.html", + "first/nested.html", + "second.html", + "conclusion.html", + ]; + + let files_in_bottom_dir = vec!["index.html", "intro.html", "second.html", "conclusion.html"]; + + for filename in files_in_bottom_dir { + helpers::assert_contains_strings(dest.join(filename), &links); + } +} + +#[test] +fn check_correct_cross_links_in_nested_dir() { + let temp = helpers::create_book(false); + let mut md = MDBook::new(temp.path()); + md.build().unwrap(); + + let first = temp.path().join("book").join("first"); + let links = vec![ + r#""#, + "intro.html", + "first/index.html", + "first/nested.html", + "second.html", + "conclusion.html", + ]; + + let files_in_nested_dir = vec!["index.html", "nested.html"]; + + for filename in files_in_nested_dir { + helpers::assert_contains_strings(first.join(filename), &links); + } +} + +#[test] +fn rendered_code_has_playpen_stuff() { + let temp = helpers::create_book(true); + let mut md = MDBook::new(temp.path()); + md.build().unwrap(); + + let nested = temp.path().join("book/first/nested.html"); + let playpen_class = vec![r#"class="playpen""#]; + + helpers::assert_contains_strings(nested, &playpen_class); + + let book_js = temp.path().join("book/book.js"); + helpers::assert_contains_strings(book_js, &[".playpen"]); +} + +#[test] +fn chapter_content_appears_in_rendered_document() { + let content = vec![ + ("index.html", "Here's some interesting text"), + ("second.html", "Second Chapter"), + ("first/nested.html", "testable code"), + ("first/index.html", "more text"), + ("conclusion.html", "Conclusion"), + ]; + + let temp = helpers::create_book(true); + let mut md = MDBook::new(temp.path()); + md.build().unwrap(); + + let destination = temp.path().join("book"); + + for (filename, text) in content { + let path = destination.join(filename); + helpers::assert_contains_strings(path, &[text]); + } +} \ No newline at end of file diff --git a/tests/testing.rs b/tests/testing.rs new file mode 100644 index 00000000..e2d1baac --- /dev/null +++ b/tests/testing.rs @@ -0,0 +1,22 @@ +extern crate tempdir; +extern crate mdbook; + +mod helpers; +use mdbook::MDBook; + + +#[test] +fn mdbook_can_correctly_test_a_passing_book() { + let temp = helpers::create_book(true); + let mut md = MDBook::new(temp.path()); + + assert!(md.test(vec![]).is_ok()); +} + +#[test] +fn mdbook_detects_book_with_failing_tests() { + let temp = helpers::create_book(false); + let mut md: MDBook = MDBook::new(temp.path()); + + assert!(md.test(vec![]).is_err()); +} \ No newline at end of file From 0c3a2b80f83971e65df13b91983dfb44e7463914 Mon Sep 17 00:00:00 2001 From: Michael Bryan Date: Mon, 10 Jul 2017 18:23:51 +0800 Subject: [PATCH 8/9] Tested MDBook::init with custom args --- tests/init.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/init.rs b/tests/init.rs index a31abacb..2e0fcf8c 100644 --- a/tests/init.rs +++ b/tests/init.rs @@ -21,3 +21,23 @@ fn run_mdbook_init() { assert!(temp.path().join(file).exists(), "{} doesn't exist", file); } } + +#[test] +fn run_mdbook_init_with_custom_args() { + let created_files = vec!["out", "in", "in/SUMMARY.md", "in/chapter_1.md"]; + + let temp = TempDir::new("mdbook").unwrap(); + for file in &created_files { + assert!(!temp.path().join(file).exists()); + } + + let mut md = MDBook::new(temp.path()) + .with_source("in") + .with_destination("out"); + + md.init().unwrap(); + + for file in &created_files { + assert!(temp.path().join(file).exists(), "{} doesn't exist", file); + } +} From e2eb40bded15edcc09876c06763a79e916784a90 Mon Sep 17 00:00:00 2001 From: Michael Bryan Date: Wed, 2 Aug 2017 22:29:28 +0800 Subject: [PATCH 9/9] Got some feedback from azerupi and added a DummyBook builder --- tests/dummy-book/SUMMARY.md | 9 ++ tests/dummy-book/conclusion.md | 1 + tests/dummy-book/first/index.md | 3 + tests/dummy-book/first/nested.md | 7 ++ tests/dummy-book/intro.md | 3 + tests/dummy-book/second.md | 1 + tests/helpers.rs | 139 +++++++++++++++---------------- tests/init.rs | 12 ++- tests/rendered_output.rs | 13 +-- tests/testing.rs | 8 +- 10 files changed, 114 insertions(+), 82 deletions(-) create mode 100644 tests/dummy-book/SUMMARY.md create mode 100644 tests/dummy-book/conclusion.md create mode 100644 tests/dummy-book/first/index.md create mode 100644 tests/dummy-book/first/nested.md create mode 100644 tests/dummy-book/intro.md create mode 100644 tests/dummy-book/second.md diff --git a/tests/dummy-book/SUMMARY.md b/tests/dummy-book/SUMMARY.md new file mode 100644 index 00000000..f5f3a4c4 --- /dev/null +++ b/tests/dummy-book/SUMMARY.md @@ -0,0 +1,9 @@ +# Summary + +[Introduction](intro.md) + +- [First Chapter](./first/index.md) + - [Nested Chapter](./first/nested.md) +- [Second Chapter](./second.md) + +[Conclusion](./conclusion.md) diff --git a/tests/dummy-book/conclusion.md b/tests/dummy-book/conclusion.md new file mode 100644 index 00000000..b6a587e7 --- /dev/null +++ b/tests/dummy-book/conclusion.md @@ -0,0 +1 @@ +# Conclusion \ No newline at end of file diff --git a/tests/dummy-book/first/index.md b/tests/dummy-book/first/index.md new file mode 100644 index 00000000..d778d9db --- /dev/null +++ b/tests/dummy-book/first/index.md @@ -0,0 +1,3 @@ +# First Chapter + +more text. \ No newline at end of file diff --git a/tests/dummy-book/first/nested.md b/tests/dummy-book/first/nested.md new file mode 100644 index 00000000..dc09383f --- /dev/null +++ b/tests/dummy-book/first/nested.md @@ -0,0 +1,7 @@ +# Nested Chapter + +This file has some testable code. + +```rust +assert!($TEST_STATUS); +``` \ No newline at end of file diff --git a/tests/dummy-book/intro.md b/tests/dummy-book/intro.md new file mode 100644 index 00000000..1990ef58 --- /dev/null +++ b/tests/dummy-book/intro.md @@ -0,0 +1,3 @@ +# Introduction + +Here's some interesting text... \ No newline at end of file diff --git a/tests/dummy-book/second.md b/tests/dummy-book/second.md new file mode 100644 index 00000000..abeaa6af --- /dev/null +++ b/tests/dummy-book/second.md @@ -0,0 +1 @@ +# Second Chapter \ No newline at end of file diff --git a/tests/helpers.rs b/tests/helpers.rs index 5e82bb5f..b626ec46 100644 --- a/tests/helpers.rs +++ b/tests/helpers.rs @@ -2,7 +2,8 @@ //! the `MDBook` initialization and build/rendering process. //! //! This will create an entire book in a temporary directory using some -//! dummy content. +//! dummy contents from the `tests/dummy-book/` directory. + #![allow(dead_code, unused_variables, unused_imports)] extern crate tempdir; @@ -14,36 +15,12 @@ use std::io::{Read, Write}; use tempdir::TempDir; -const SUMMARY_MD: &'static str = "# Summary - -[Introduction](intro.md) - -- [First Chapter](./first/index.md) - - [Nested Chapter](./first/nested.md) -- [Second Chapter](./second.md) - -[Conclusion](./conclusion.md) -"; - -const INTRO: &'static str = "# Introduction - -Here's some interesting text..."; - -const FIRST: &'static str = "# First Chapter - -more text."; - -const NESTED: &'static str = r#"# Nested Chapter - -This file has some testable code. - -```rust -assert!($TEST_STATUS); -```"#; - -const SECOND: &'static str = "# Second Chapter"; - -const CONCLUSION: &'static str = "# Conclusion"; +const SUMMARY_MD: &'static str = include_str!("dummy-book/SUMMARY.md"); +const INTRO: &'static str = include_str!("dummy-book/intro.md"); +const FIRST: &'static str = include_str!("dummy-book/first/index.md"); +const NESTED: &'static str = include_str!("dummy-book/first/nested.md"); +const SECOND: &'static str = include_str!("dummy-book/second.md"); +const CONCLUSION: &'static str = include_str!("dummy-book/conclusion.md"); /// Create a dummy book in a temporary directory, using the contents of @@ -53,47 +30,69 @@ const CONCLUSION: &'static str = "# Conclusion"; /// `assert!($TEST_STATUS)`. If you want to check MDBook's testing /// functionality, `$TEST_STATUS` can be substitute for either `true` or /// `false`. This is done using the `passing_test` parameter. -pub fn create_book(passing_test: bool) -> TempDir { - let temp = TempDir::new("dummy_book").unwrap(); - - let src = temp.path().join("src"); - fs::create_dir_all(&src).unwrap(); - - File::create(src.join("SUMMARY.md")) - .unwrap() - .write_all(SUMMARY_MD.as_bytes()) - .unwrap(); - File::create(src.join("intro.md")) - .unwrap() - .write_all(INTRO.as_bytes()) - .unwrap(); - - let first = src.join("first"); - fs::create_dir_all(&first).unwrap(); - File::create(first.join("index.md")) - .unwrap() - .write_all(FIRST.as_bytes()) - .unwrap(); - - let to_substitute = if passing_test { "true" } else { "false" }; - let nested_text = NESTED.replace("$TEST_STATUS", to_substitute); - File::create(first.join("nested.md")) - .unwrap() - .write_all(nested_text.as_bytes()) - .unwrap(); - - File::create(src.join("second.md")) - .unwrap() - .write_all(SECOND.as_bytes()) - .unwrap(); - File::create(src.join("conclusion.md")) - .unwrap() - .write_all(CONCLUSION.as_bytes()) - .unwrap(); - - temp +#[derive(Clone, Debug, PartialEq)] +pub struct DummyBook { + passing_test: bool, } +impl DummyBook { + /// Create a new `DummyBook` with all the defaults. + pub fn new() -> DummyBook { + DummyBook::default() + } + + /// Whether the doc-test included in the "Nested Chapter" should pass or + /// fail (it passes by default). + pub fn with_passing_test(&mut self, test_passes: bool) -> &mut Self { + self.passing_test = test_passes; + self + } + + /// Write a book to a temporary directory using the provided settings. + /// + /// # Note + /// + /// If this fails for any reason it will `panic!()`. If we can't write to a + /// temporary directory then chances are you've got bigger problems... + pub fn build(&self) -> TempDir { + let temp = TempDir::new("dummy_book").unwrap(); + + let src = temp.path().join("src"); + fs::create_dir_all(&src).unwrap(); + + let first = src.join("first"); + fs::create_dir_all(&first).unwrap(); + + let to_substitute = if self.passing_test { "true" } else { "false" }; + let nested_text = NESTED.replace("$TEST_STATUS", to_substitute); + + let inputs = vec![ + (src.join("SUMMARY.md"), SUMMARY_MD), + (src.join("intro.md"), INTRO), + (first.join("index.md"), FIRST), + (first.join("nested.md"), &nested_text), + (src.join("second.md"), SECOND), + (src.join("conclusion.md"), CONCLUSION), + ]; + + for (path, content) in inputs { + File::create(path) + .unwrap() + .write_all(content.as_bytes()) + .unwrap(); + } + + temp + } +} + +impl Default for DummyBook { + fn default() -> DummyBook { + DummyBook { passing_test: true } + } +} + + /// Read the contents of the provided file into memory and then iterate through /// the list of strings asserting that the file contains all of them. pub fn assert_contains_strings>(filename: P, strings: &[&str]) { diff --git a/tests/init.rs b/tests/init.rs index 2e0fcf8c..e7518fde 100644 --- a/tests/init.rs +++ b/tests/init.rs @@ -5,8 +5,10 @@ use tempdir::TempDir; use mdbook::MDBook; +/// Run `mdbook init` in an empty directory and make sure the default files +/// are created. #[test] -fn run_mdbook_init() { +fn base_mdbook_init_should_create_default_content() { let created_files = vec!["book", "src", "src/SUMMARY.md", "src/chapter_1.md"]; let temp = TempDir::new("mdbook").unwrap(); @@ -22,13 +24,15 @@ fn run_mdbook_init() { } } +/// Set some custom arguments for where to place the source and destination +/// files, then call `mdbook init`. #[test] -fn run_mdbook_init_with_custom_args() { +fn run_mdbook_init_with_custom_book_and_src_locations() { let created_files = vec!["out", "in", "in/SUMMARY.md", "in/chapter_1.md"]; let temp = TempDir::new("mdbook").unwrap(); for file in &created_files { - assert!(!temp.path().join(file).exists()); + assert!(!temp.path().join(file).exists(), "{} shouldn't exist yet!", file); } let mut md = MDBook::new(temp.path()) @@ -38,6 +42,6 @@ fn run_mdbook_init_with_custom_args() { md.init().unwrap(); for file in &created_files { - assert!(temp.path().join(file).exists(), "{} doesn't exist", file); + assert!(temp.path().join(file).exists(), "{} should have been created by `mdbook init`", file); } } diff --git a/tests/rendered_output.rs b/tests/rendered_output.rs index 077d3366..84866f1a 100644 --- a/tests/rendered_output.rs +++ b/tests/rendered_output.rs @@ -5,9 +5,10 @@ mod helpers; use mdbook::MDBook; +/// Make sure you can load the dummy book and build it without panicking. #[test] fn build_the_dummy_book() { - let temp = helpers::create_book(true); + let temp = helpers::DummyBook::default().build(); let mut md = MDBook::new(temp.path()); md.build().unwrap(); @@ -15,7 +16,7 @@ fn build_the_dummy_book() { #[test] fn by_default_mdbook_generates_rendered_content_in_the_book_directory() { - let temp = helpers::create_book(false); + let temp = helpers::DummyBook::default().build(); let mut md = MDBook::new(temp.path()); assert!(!temp.path().join("book").exists()); @@ -27,7 +28,7 @@ fn by_default_mdbook_generates_rendered_content_in_the_book_directory() { #[test] fn make_sure_bottom_level_files_contain_links_to_chapters() { - let temp = helpers::create_book(false); + let temp = helpers::DummyBook::default().build(); let mut md = MDBook::new(temp.path()); md.build().unwrap(); @@ -49,7 +50,7 @@ fn make_sure_bottom_level_files_contain_links_to_chapters() { #[test] fn check_correct_cross_links_in_nested_dir() { - let temp = helpers::create_book(false); + let temp = helpers::DummyBook::default().build(); let mut md = MDBook::new(temp.path()); md.build().unwrap(); @@ -72,7 +73,7 @@ fn check_correct_cross_links_in_nested_dir() { #[test] fn rendered_code_has_playpen_stuff() { - let temp = helpers::create_book(true); + let temp = helpers::DummyBook::default().build(); let mut md = MDBook::new(temp.path()); md.build().unwrap(); @@ -95,7 +96,7 @@ fn chapter_content_appears_in_rendered_document() { ("conclusion.html", "Conclusion"), ]; - let temp = helpers::create_book(true); + let temp = helpers::DummyBook::default().build(); let mut md = MDBook::new(temp.path()); md.build().unwrap(); diff --git a/tests/testing.rs b/tests/testing.rs index e2d1baac..b4d22394 100644 --- a/tests/testing.rs +++ b/tests/testing.rs @@ -7,7 +7,9 @@ use mdbook::MDBook; #[test] fn mdbook_can_correctly_test_a_passing_book() { - let temp = helpers::create_book(true); + let temp = helpers::DummyBook::default() + .with_passing_test(true) + .build(); let mut md = MDBook::new(temp.path()); assert!(md.test(vec![]).is_ok()); @@ -15,7 +17,9 @@ fn mdbook_can_correctly_test_a_passing_book() { #[test] fn mdbook_detects_book_with_failing_tests() { - let temp = helpers::create_book(false); + let temp = helpers::DummyBook::default() + .with_passing_test(false) + .build(); let mut md: MDBook = MDBook::new(temp.path()); assert!(md.test(vec![]).is_err());