use dir_indexer::get_relative_file_paths_set;
use expect_test::{expect, Expect};
use forc_doc::{self, generate_docs, Command, DocResult};
use std::{
collections::HashSet,
path::{Path, PathBuf},
};
/// The path to the generated HTML of the type the traits are implemented on.
const IMPL_FOR: &str = "bar/struct.Bar.html";
const DATA_DIR: &str = "tests/fixtures";
const JS_SEARCH_FILE_PATH: &str = "search.js";
#[test]
fn builds_lib_std_docs() {
let path = Path::new("./../../sway-lib-std");
let build_instructions = Command {
path: Some(path.to_str().unwrap().to_string()),
..Default::default()
};
println!("Building docs for {:?}", build_instructions.path);
let res = generate_docs(&build_instructions);
assert!(res.is_ok());
}
#[test]
fn test_impl_traits_default() {
let doc_dir_name: &str = "impl_traits_default";
let project_name = "impl_traits";
let command = Command {
path: Some(format!("{}/{}", DATA_DIR, project_name)),
doc_path: Some(doc_dir_name.into()),
..Default::default()
};
let (doc_path, _doc_result) = generate_docs(&command).unwrap();
assert_index_html(
&doc_path,
project_name,
&expect![[r##"
Bar in bar - Sway something more about foo();
"##]],
);
assert_search_js(
&doc_path,
&expect![[
r#"var SEARCH_INDEX={"impl_traits":[{"html_filename":"trait.Foo.html","module_info":["impl_traits","foo"],"name":"Foo","preview":"","type_name":"trait"},{"html_filename":"trait.Baz.html","module_info":["impl_traits","foo"],"name":"Baz","preview":"","type_name":"trait"},{"html_filename":"struct.Bar.html","module_info":["impl_traits","bar"],"name":"Bar","preview":"","type_name":"struct"},{"html_filename":"index.html","module_info":["impl_traits","bar"],"name":"bar","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["impl_traits","foo"],"name":"foo","preview":"","type_name":"module"}],"ops":[{"html_filename":"trait.Add.html","module_info":["ops"],"name":"Add","preview":"","type_name":"trait"},{"html_filename":"trait.Subtract.html","module_info":["ops"],"name":"Subtract","preview":"","type_name":"trait"},{"html_filename":"index.html","module_info":["ops"],"name":"ops","preview":"","type_name":"module"}]};
"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=SEARCH_INDEX);"#
]],
);
assert_file_tree(
doc_dir_name,
project_name,
vec![
"impl_traits/foo/trait.Foo.html",
"impl_traits/foo/index.html",
"impl_traits/all.html",
"ops/trait.Subtract.html",
"ops/all.html",
"impl_traits/bar/struct.Bar.html",
"impl_traits/bar/index.html",
"ops/trait.Add.html",
"search.js",
"impl_traits/index.html",
"ops/index.html",
"impl_traits/foo/trait.Baz.html",
],
);
}
#[test]
fn test_workspace_docs() {
let doc_dir_name: &str = "workspace_docs";
let workspace_name = "sample_workspace";
let command = Command {
path: Some(format!("{}/{}", DATA_DIR, workspace_name)),
doc_path: Some(doc_dir_name.into()),
..Default::default()
};
let (doc_path, doc_result) = generate_docs(&command).unwrap();
// Verify that we got a workspace result
match &doc_result {
DocResult::Workspace { name, libraries } => {
assert_eq!(name, workspace_name);
assert_eq!(
libraries.len(),
2,
"Expected 2 libraries, found {}: {:?}",
libraries.len(),
libraries
);
assert!(libraries.iter().any(|lib| lib.name == "lib_a"));
assert!(libraries.iter().any(|lib| lib.name == "lib_b"));
}
DocResult::Package(_) => panic!("Expected workspace result, got package"),
}
// Check that workspace index.html was created
let workspace_index_path = doc_path.join("index.html");
assert!(
workspace_index_path.exists(),
"Workspace index.html should exist"
);
// Check that library-specific docs were created
let lib_a_index = doc_path.join("lib_a").join("index.html");
let lib_b_index = doc_path.join("lib_b").join("index.html");
assert!(lib_a_index.exists(), "lib_a index.html should exist");
assert!(lib_b_index.exists(), "lib_b index.html should exist");
// Check that search.js was created
let search_js = doc_path.join("search.js");
assert!(search_js.exists(), "search.js should exist");
// Read and verify the workspace index contains library links
let workspace_content = std::fs::read_to_string(&workspace_index_path).unwrap();
assert!(
workspace_content.contains("lib_a/index.html"),
"Workspace index should link to lib_a"
);
assert!(
workspace_content.contains("lib_b/index.html"),
"Workspace index should link to lib_b"
);
assert!(
workspace_content.contains("This workspace contains the following libraries"),
"Should contain workspace description"
);
}
#[test]
fn test_impl_traits_no_deps() {
let doc_dir_name: &str = "impl_traits_no_deps";
let project_name: &str = "impl_traits_generic";
let command = Command {
path: Some(format!("{}/{}", DATA_DIR, project_name)),
doc_path: Some(doc_dir_name.into()),
no_deps: true,
..Default::default()
};
let (doc_path, _doc_result) = generate_docs(&command).unwrap();
assert_index_html(
&doc_path,
project_name,
&expect![[r##"
Bar in bar - Sway something more about foo();
"##]],
);
assert_search_js(
&doc_path,
&expect![[
r#"var SEARCH_INDEX={"impl_traits_generic":[{"html_filename":"trait.Foo.html","module_info":["impl_traits_generic","foo"],"name":"Foo","preview":"","type_name":"trait"},{"html_filename":"trait.Baz.html","module_info":["impl_traits_generic","foo"],"name":"Baz","preview":"","type_name":"trait"},{"html_filename":"struct.Bar.html","module_info":["impl_traits_generic","bar"],"name":"Bar","preview":"","type_name":"struct"},{"html_filename":"index.html","module_info":["impl_traits_generic","bar"],"name":"bar","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["impl_traits_generic","foo"],"name":"foo","preview":"","type_name":"module"}]};
"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=SEARCH_INDEX);"#
]],
);
assert_file_tree(
doc_dir_name,
project_name,
vec![
"impl_traits_generic/index.html",
"impl_traits_generic/all.html",
"impl_traits_generic/foo/trait.Foo.html",
"impl_traits_generic/bar/index.html",
"impl_traits_generic/foo/index.html",
"impl_traits_generic/foo/trait.Baz.html",
"search.js",
"impl_traits_generic/bar/struct.Bar.html",
],
);
}
fn assert_index_html(doc_path: &Path, project_name: &str, expect: &Expect) {
let path_to_file = PathBuf::from(format!("{}/{}", project_name, IMPL_FOR));
check_file(doc_path, &path_to_file, expect);
}
fn assert_search_js(doc_path: &Path, expect: &Expect) {
let path_to_file = PathBuf::from(JS_SEARCH_FILE_PATH);
check_file(doc_path, &path_to_file, expect);
}
fn check_file(doc_path: &Path, path_to_file: &PathBuf, expect: &Expect) {
let path = doc_path.join(path_to_file);
let actual = std::fs::read_to_string(path.clone())
.unwrap_or_else(|_| panic!("failed to read file: {:?}", path));
expect.assert_eq(&actual)
}
fn assert_file_tree(doc_dir_name: &str, project_name: &str, expected_files: Vec<&str>) {
let doc_root: PathBuf = format!("{}/{}/out/{}", DATA_DIR, project_name, doc_dir_name).into();
let expected = expected_files
.iter()
.map(PathBuf::from)
.collect::>();
let files = get_relative_file_paths_set(doc_root.clone());
if files != expected {
let diffs = files.symmetric_difference(&expected);
assert_eq!(
files, expected,
"Symmetric Difference: {diffs:?} at {doc_root:?}"
);
}
}