This enables the smart-punctuation setting by default. The long term plan is to continue to enable more markdown extensions by default across semver breaking releases.
136 lines
5.1 KiB
Rust
136 lines
5.1 KiB
Rust
//! Tests for search support.
|
|
|
|
use crate::prelude::*;
|
|
use mdbook_core::book::{BookItem, Chapter};
|
|
use snapbox::file;
|
|
use std::path::Path;
|
|
|
|
fn read_book_index(root: &Path) -> serde_json::Value {
|
|
let index = root.join("book/searchindex.js");
|
|
let index = read_to_string(index);
|
|
let index =
|
|
index.trim_start_matches("window.search = Object.assign(window.search, JSON.parse('");
|
|
let index = index.trim_end_matches("'));");
|
|
// We need unescape the string as it's supposed to be an escaped JS string.
|
|
serde_json::from_str(&index.replace("\\'", "'").replace("\\\\", "\\")).unwrap()
|
|
}
|
|
|
|
// Some spot checks for the generation of the search index.
|
|
#[test]
|
|
fn reasonable_search_index() {
|
|
let mut test = BookTest::from_dir("search/reasonable_search_index");
|
|
test.build();
|
|
let index = read_book_index(&test.dir);
|
|
|
|
let doc_urls = index["doc_urls"].as_array().unwrap();
|
|
eprintln!("doc_urls={doc_urls:#?}",);
|
|
let get_doc_ref = |url: &str| -> String {
|
|
doc_urls
|
|
.iter()
|
|
.position(|s| s == url)
|
|
.unwrap_or_else(|| panic!("failed to find {url}"))
|
|
.to_string()
|
|
};
|
|
|
|
let first_chapter = get_doc_ref("first/index.html#first-chapter");
|
|
let introduction = get_doc_ref("intro.html#introduction");
|
|
let some_section = get_doc_ref("first/index.html#some-section");
|
|
let summary = get_doc_ref("first/includes.html#summary");
|
|
let no_headers = get_doc_ref("first/no-headers.html");
|
|
let duplicate_headers_1 = get_doc_ref("first/duplicate-headers.html#header-text-1");
|
|
let heading_attrs = get_doc_ref("first/heading-attributes.html#both");
|
|
let sneaky = get_doc_ref("intro.html#sneaky");
|
|
|
|
let bodyidx = &index["index"]["index"]["body"]["root"];
|
|
let textidx = &bodyidx["t"]["e"]["x"]["t"];
|
|
assert_eq!(textidx["df"], 5);
|
|
assert_eq!(textidx["docs"][&first_chapter]["tf"], 1.0);
|
|
assert_eq!(textidx["docs"][&introduction]["tf"], 1.0);
|
|
|
|
let docs = &index["index"]["documentStore"]["docs"];
|
|
assert_eq!(docs[&first_chapter]["body"], "more text.");
|
|
assert_eq!(docs[&some_section]["body"], "");
|
|
assert_eq!(
|
|
docs[&summary]["body"],
|
|
"Introduction First Chapter Includes Unicode No Headers Duplicate Headers Heading Attributes"
|
|
);
|
|
assert_eq!(
|
|
docs[&summary]["breadcrumbs"],
|
|
"First Chapter » Includes » Summary"
|
|
);
|
|
// See note about InlineHtml in search.rs. Ideally the `alert()` part
|
|
// should not be in the index, but we don't have a way to scrub inline
|
|
// html.
|
|
assert_eq!(
|
|
docs[&sneaky]["body"],
|
|
"I put <HTML> in here! Sneaky inline event alert(“inline”);. But regular inline is indexed."
|
|
);
|
|
assert_eq!(
|
|
docs[&no_headers]["breadcrumbs"],
|
|
"First Chapter » No Headers"
|
|
);
|
|
assert_eq!(
|
|
docs[&duplicate_headers_1]["breadcrumbs"],
|
|
"First Chapter » Duplicate Headers » Header Text"
|
|
);
|
|
assert_eq!(
|
|
docs[&no_headers]["body"],
|
|
"Capybara capybara capybara. Capybara capybara capybara. ThisLongWordIsIncludedSoWeCanCheckThatSufficientlyLongWordsAreOmittedFromTheSearchIndex."
|
|
);
|
|
assert_eq!(
|
|
docs[&heading_attrs]["breadcrumbs"],
|
|
"First Chapter » Heading Attributes » Heading with id and classes"
|
|
);
|
|
}
|
|
|
|
// This test is here to catch any unexpected changes to the search index.
|
|
#[test]
|
|
fn search_index_hasnt_changed_accidentally() {
|
|
BookTest::from_dir("search/reasonable_search_index").check_file(
|
|
"book/searchindex.js",
|
|
file!["search/reasonable_search_index/expected_index.js"],
|
|
);
|
|
}
|
|
|
|
// Ability to disable search chapters.
|
|
#[test]
|
|
fn can_disable_individual_chapters() {
|
|
let mut test = BookTest::from_dir("search/disable_search_chapter");
|
|
test.build();
|
|
let index = read_book_index(&test.dir);
|
|
let doc_urls = index["doc_urls"].as_array().unwrap();
|
|
let contains = |path| {
|
|
doc_urls
|
|
.iter()
|
|
.any(|p| p.as_str().unwrap().starts_with(path))
|
|
};
|
|
assert!(contains("second.html"));
|
|
assert!(!contains("second/"));
|
|
assert!(!contains("first/disable_me.html"));
|
|
assert!(contains("first/keep_me.html"));
|
|
}
|
|
|
|
// Test for a regression where search would fail if source_path is None.
|
|
// https://github.com/rust-lang/mdBook/pull/2550
|
|
#[test]
|
|
fn with_no_source_path() {
|
|
let test = BookTest::from_dir("search/reasonable_search_index");
|
|
let mut book = test.load_book();
|
|
let chapter = Chapter::new("Sample chapter", String::new(), "sample.html", vec![]);
|
|
book.book.sections.push(BookItem::Chapter(chapter));
|
|
book.build().unwrap();
|
|
}
|
|
|
|
// Checks that invalid settings in search chapter is rejected.
|
|
#[test]
|
|
fn chapter_settings_validation_error() {
|
|
BookTest::from_dir("search/chapter_settings_validation_error").run("build", |cmd| {
|
|
cmd.expect_failure().expect_stderr(str![[r#"
|
|
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started
|
|
[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend
|
|
[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Rendering failed
|
|
[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: [output.html.search.chapter] key `does-not-exist` does not match any chapter paths
|
|
|
|
"#]]);
|
|
});
|
|
}
|