",
@@ -470,27 +472,17 @@ fn id_from_content(content: &str) -> String {
"'",
""",
];
- for sub in repl_sub {
+ for sub in REPL_SUB {
content = content.replace(sub, "");
}
- let mut id = String::new();
-
- for c in content.chars() {
- if c.is_alphanumeric() || c == '-' || c == '_' {
- id.push(c.to_ascii_lowercase());
- } else if c.is_whitespace() {
- id.push(c);
- }
- }
-
- id
+ normalize_id(&content)
}
// anchors to the same page (href="#anchor") do not work because of
// pointing to the root folder. This function *fixes*
// that in a very inelegant way
-fn fix_anchor_links(html: &str, filename: &str) -> String {
+fn fix_anchor_links(html: &str, filepath: &str) -> String {
let regex = Regex::new(r##"]+)href="#([^"]+)"([^>]*)>"##).unwrap();
regex
.replace_all(html, |caps: &Captures| {
@@ -499,9 +491,9 @@ fn fix_anchor_links(html: &str, filename: &str) -> String {
let after = &caps[3];
format!(
- "",
+ "",
before = before,
- filename = filename,
+ filepath = filepath,
anchor = anchor,
after = after
)
@@ -592,6 +584,26 @@ struct RenderItemContext<'a> {
is_index: bool,
}
+pub fn normalize_path(path: &str) -> String {
+ use std::path::is_separator;
+ path.chars()
+ .map(|ch| if is_separator(ch) { '/' } else { ch })
+ .collect::()
+}
+
+pub fn normalize_id(content: &str) -> String {
+ content.chars()
+ .filter_map(|ch|
+ if ch.is_alphanumeric() || ch == '_' {
+ Some(ch.to_ascii_lowercase())
+ } else if ch.is_whitespace() {
+ Some('-')
+ } else {
+ None
+ }
+ )
+ .collect::()
+}
#[cfg(test)]
@@ -601,17 +613,39 @@ mod tests {
#[test]
fn original_build_header_links() {
let inputs = vec![
- ("blah blah Foo
", r#"blah blah Foo
"#),
- ("Foo
", r#"Foo
"#),
- ("Foo^bar
", r#"Foo^bar
"#),
- ("", r#""#),
- ("Hï
", r#"Hï
"#),
- ("Foo
Foo
",
- r#"Foo
Foo
"#),
+ (
+ "blah blah Foo
",
+ r##"blah blah Foo
"##,
+ ),
+ (
+ "Foo
",
+ r##"Foo
"##,
+ ),
+ (
+ "Foo^bar
",
+ r##"Foo^bar
"##,
+ ),
+ (
+ "",
+ r##""##
+ ),
+ (
+ "Hï
",
+ r##"Hï
"##
+ ),
+ (
+ "Foo
Foo
",
+ r##"Foo
Foo
"##
+ ),
];
for (src, should_be) in inputs {
- let got = build_header_links(src, "bar.rs");
+ let filepath = "./some_chapter/some_section.html";
+ let got = build_header_links(&src, filepath);
+ assert_eq!(got, should_be);
+
+ // This is redundant for most cases
+ let got = fix_anchor_links(&got, filepath);
assert_eq!(got, should_be);
}
}
diff --git a/tests/dummy-book/first/index.md b/tests/dummy-book/first/index.md
deleted file mode 100644
index d778d9db..00000000
--- a/tests/dummy-book/first/index.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# First Chapter
-
-more text.
\ No newline at end of file
diff --git a/tests/dummy-book/SUMMARY.md b/tests/dummy/book/SUMMARY.md
similarity index 100%
rename from tests/dummy-book/SUMMARY.md
rename to tests/dummy/book/SUMMARY.md
diff --git a/tests/dummy-book/conclusion.md b/tests/dummy/book/conclusion.md
similarity index 100%
rename from tests/dummy-book/conclusion.md
rename to tests/dummy/book/conclusion.md
diff --git a/tests/dummy/book/first/index.md b/tests/dummy/book/first/index.md
new file mode 100644
index 00000000..200672b9
--- /dev/null
+++ b/tests/dummy/book/first/index.md
@@ -0,0 +1,5 @@
+# First Chapter
+
+more text.
+
+## Some Section
diff --git a/tests/dummy-book/first/nested.md b/tests/dummy/book/first/nested.md
similarity index 80%
rename from tests/dummy-book/first/nested.md
rename to tests/dummy/book/first/nested.md
index dc09383f..a7a1cdda 100644
--- a/tests/dummy-book/first/nested.md
+++ b/tests/dummy/book/first/nested.md
@@ -4,4 +4,6 @@ This file has some testable code.
```rust
assert!($TEST_STATUS);
-```
\ No newline at end of file
+```
+
+## Some Section
diff --git a/tests/dummy-book/intro.md b/tests/dummy/book/intro.md
similarity index 100%
rename from tests/dummy-book/intro.md
rename to tests/dummy/book/intro.md
diff --git a/tests/dummy-book/second.md b/tests/dummy/book/second.md
similarity index 100%
rename from tests/dummy-book/second.md
rename to tests/dummy/book/second.md
diff --git a/tests/helpers.rs b/tests/dummy/mod.rs
similarity index 61%
rename from tests/helpers.rs
rename to tests/dummy/mod.rs
index b626ec46..ca561d86 100644
--- a/tests/helpers.rs
+++ b/tests/dummy/mod.rs
@@ -1,26 +1,23 @@
-//! 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 contents from the `tests/dummy-book/` directory.
+// Not all features are used in all test crates, so...
+#![allow(dead_code, unused_extern_crates)]
-#![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 std::fs::{create_dir_all, File};
+use std::io::Write;
use tempdir::TempDir;
-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");
+const SUMMARY_MD: &'static str = include_str!("book/SUMMARY.md");
+const INTRO: &'static str = include_str!("book/intro.md");
+const FIRST: &'static str = include_str!("book/first/index.md");
+const NESTED: &'static str = include_str!("book/first/nested.md");
+const SECOND: &'static str = include_str!("book/second.md");
+const CONCLUSION: &'static str = include_str!("book/conclusion.md");
/// Create a dummy book in a temporary directory, using the contents of
@@ -58,10 +55,10 @@ impl DummyBook {
let temp = TempDir::new("dummy_book").unwrap();
let src = temp.path().join("src");
- fs::create_dir_all(&src).unwrap();
+ create_dir_all(&src).unwrap();
let first = src.join("first");
- fs::create_dir_all(&first).unwrap();
+ create_dir_all(&first).unwrap();
let to_substitute = if self.passing_test { "true" } else { "false" };
let nested_text = NESTED.replace("$TEST_STATUS", to_substitute);
@@ -91,20 +88,3 @@ impl Default for 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]) {
- 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/helpers/mod.rs b/tests/helpers/mod.rs
new file mode 100644
index 00000000..da6af35c
--- /dev/null
+++ b/tests/helpers/mod.rs
@@ -0,0 +1,24 @@
+//! Helpers for tests which exercise the overall application, in particular
+//! the `MDBook` initialization and build/rendering process.
+
+
+use std::path::Path;
+use std::fs::File;
+use std::io::Read;
+
+
+/// 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/rendered_output.rs b/tests/rendered_output.rs
index 84866f1a..7de0838f 100644
--- a/tests/rendered_output.rs
+++ b/tests/rendered_output.rs
@@ -1,14 +1,18 @@
extern crate mdbook;
extern crate tempdir;
+mod dummy;
mod helpers;
+
+use dummy::DummyBook;
+use helpers::assert_contains_strings;
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::DummyBook::default().build();
+ let temp = DummyBook::default().build();
let mut md = MDBook::new(temp.path());
md.build().unwrap();
@@ -16,7 +20,7 @@ fn build_the_dummy_book() {
#[test]
fn by_default_mdbook_generates_rendered_content_in_the_book_directory() {
- let temp = helpers::DummyBook::default().build();
+ let temp = DummyBook::default().build();
let mut md = MDBook::new(temp.path());
assert!(!temp.path().join("book").exists());
@@ -28,62 +32,76 @@ 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::DummyBook::default().build();
+ let temp = DummyBook::default().build();
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",
+ r#"href="intro.html""#,
+ r#"href="./first/index.html""#,
+ r#"href="./first/nested.html""#,
+ r#"href="./second.html""#,
+ r#"href="./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);
+ assert_contains_strings(dest.join(filename), &links);
}
}
#[test]
fn check_correct_cross_links_in_nested_dir() {
- let temp = helpers::DummyBook::default().build();
+ let temp = DummyBook::default().build();
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",
+ r#"href="intro.html""#,
+ r#"href="./first/index.html""#,
+ r#"href="./first/nested.html""#,
+ r#"href="./second.html""#,
+ r#"href="./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);
+ assert_contains_strings(first.join(filename), &links);
}
+
+ assert_contains_strings(
+ first.join("index.html"),
+ &[
+ r##"href="./first/index.html#some-section" id="some-section""##
+ ],
+ );
+
+ assert_contains_strings(
+ first.join("nested.html"),
+ &[
+ r##"href="./first/nested.html#some-section" id="some-section""##
+ ],
+ );
}
#[test]
fn rendered_code_has_playpen_stuff() {
- let temp = helpers::DummyBook::default().build();
+ let temp = DummyBook::default().build();
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);
+ assert_contains_strings(nested, &playpen_class);
let book_js = temp.path().join("book/book.js");
- helpers::assert_contains_strings(book_js, &[".playpen"]);
+ assert_contains_strings(book_js, &[".playpen"]);
}
#[test]
@@ -96,7 +114,7 @@ fn chapter_content_appears_in_rendered_document() {
("conclusion.html", "Conclusion"),
];
- let temp = helpers::DummyBook::default().build();
+ let temp = DummyBook::default().build();
let mut md = MDBook::new(temp.path());
md.build().unwrap();
@@ -104,6 +122,6 @@ fn chapter_content_appears_in_rendered_document() {
for (filename, text) in content {
let path = destination.join(filename);
- helpers::assert_contains_strings(path, &[text]);
+ assert_contains_strings(path, &[text]);
}
-}
\ No newline at end of file
+}
diff --git a/tests/testing.rs b/tests/testing.rs
index b4d22394..e4cf8da5 100644
--- a/tests/testing.rs
+++ b/tests/testing.rs
@@ -1,13 +1,15 @@
-extern crate tempdir;
extern crate mdbook;
+extern crate tempdir;
-mod helpers;
+mod dummy;
+
+use dummy::DummyBook;
use mdbook::MDBook;
#[test]
fn mdbook_can_correctly_test_a_passing_book() {
- let temp = helpers::DummyBook::default()
+ let temp = DummyBook::default()
.with_passing_test(true)
.build();
let mut md = MDBook::new(temp.path());
@@ -17,10 +19,10 @@ fn mdbook_can_correctly_test_a_passing_book() {
#[test]
fn mdbook_detects_book_with_failing_tests() {
- let temp = helpers::DummyBook::default()
+ let temp = DummyBook::default()
.with_passing_test(false)
.build();
let mut md: MDBook = MDBook::new(temp.path());
assert!(md.test(vec![]).is_err());
-}
\ No newline at end of file
+}