Skip to content

Commit 67663fc

Browse files
committed
added unit tests for write_shared
1 parent 17c8923 commit 67663fc

File tree

3 files changed

+257
-51
lines changed

3 files changed

+257
-51
lines changed

src/librustdoc/html/render/sorted_json.rs

+3
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,6 @@ impl fmt::Display for EscapedJson {
8080
write!(f, "{}", json)
8181
}
8282
}
83+
84+
#[cfg(test)]
85+
mod tests;

src/librustdoc/html/render/write_shared.rs

+48-51
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
1616
use std::any::Any;
1717
use std::cell::RefCell;
18-
use std::collections::hash_map::Entry;
1918
use std::ffi::OsString;
2019
use std::fs::File;
2120
use std::io::BufWriter;
@@ -52,7 +51,7 @@ use crate::html::layout;
5251
use crate::html::render::search_index::build_index;
5352
use crate::html::render::search_index::SerializedSearchIndex;
5453
use crate::html::render::sorted_json::{EscapedJson, SortedJson};
55-
use crate::html::render::sorted_template::{self, SortedTemplate};
54+
use crate::html::render::sorted_template::{self, FileFormat, SortedTemplate};
5655
use crate::html::render::{AssocItemLink, ImplRenderingParameters};
5756
use crate::html::static_files::{self, suffix_path};
5857
use crate::visit::DocVisitor;
@@ -78,33 +77,29 @@ pub(crate) fn write_shared(
7877
let crate_name = krate.name(cx.tcx());
7978
let crate_name = crate_name.as_str(); // rand
8079
let crate_name_json = SortedJson::serialize(crate_name); // "rand"
81-
let external_crates = hack_get_external_crate_names(cx)?;
80+
let external_crates = hack_get_external_crate_names(&cx.dst)?;
8281
let info = CrateInfo {
8382
src_files_js: SourcesPart::get(cx, &crate_name_json)?,
84-
search_index_js: SearchIndexPart::get(cx, index)?,
83+
search_index_js: SearchIndexPart::get(index, &cx.shared.resource_suffix)?,
8584
all_crates: AllCratesPart::get(crate_name_json.clone())?,
8685
crates_index: CratesIndexPart::get(&crate_name, &external_crates)?,
8786
trait_impl: TraitAliasPart::get(cx, &crate_name_json)?,
8887
type_impl: TypeAliasPart::get(cx, krate, &crate_name_json)?,
8988
};
9089

91-
let crates_info = vec![info]; // we have info from just one crate
90+
let crates = vec![info]; // we have info from just one crate. rest will found in out dir
9291

9392
write_static_files(cx, &opt)?;
9493
let dst = &cx.dst;
9594
if opt.emit.is_empty() || opt.emit.contains(&EmitType::InvocationSpecific) {
9695
if cx.include_sources {
97-
write_rendered_cci::<SourcesPart, _>(SourcesPart::blank, dst, &crates_info)?;
96+
write_rendered_cci::<SourcesPart, _>(SourcesPart::blank, dst, &crates)?;
9897
}
99-
write_rendered_cci::<SearchIndexPart, _>(
100-
SearchIndexPart::blank,
101-
dst,
102-
&crates_info,
103-
)?;
104-
write_rendered_cci::<AllCratesPart, _>(AllCratesPart::blank, dst, &crates_info)?;
105-
}
106-
write_rendered_cci::<TraitAliasPart, _>(TraitAliasPart::blank, dst, &crates_info)?;
107-
write_rendered_cci::<TypeAliasPart, _>(TypeAliasPart::blank, dst, &crates_info)?;
98+
write_rendered_cci::<SearchIndexPart, _>(SearchIndexPart::blank, dst, &crates)?;
99+
write_rendered_cci::<AllCratesPart, _>(AllCratesPart::blank, dst, &crates)?;
100+
}
101+
write_rendered_cci::<TraitAliasPart, _>(TraitAliasPart::blank, dst, &crates)?;
102+
write_rendered_cci::<TypeAliasPart, _>(TypeAliasPart::blank, dst, &crates)?;
108103
match &opt.index_page {
109104
Some(index_page) if opt.enable_index_page => {
110105
let mut md_opts = opt.clone();
@@ -119,7 +114,7 @@ pub(crate) fn write_shared(
119114
write_rendered_cci::<CratesIndexPart, _>(
120115
|| CratesIndexPart::blank(cx),
121116
dst,
122-
&crates_info,
117+
&crates,
123118
)?;
124119
}
125120
_ => {} // they don't want an index page
@@ -189,7 +184,8 @@ fn write_search_desc(
189184
let path = path.join(filename);
190185
let part = SortedJson::serialize(&part);
191186
let part = format!("searchState.loadedDescShard({encoded_crate_name}, {i}, {part})");
192-
write_create_parents(&path, part)?;
187+
create_parents(&path)?;
188+
try_err!(fs::write(&path, part), &path);
193189
}
194190
Ok(())
195191
}
@@ -286,8 +282,11 @@ else if (window.initSearch) window.initSearch(searchIndex);",
286282
)
287283
}
288284

289-
fn get(cx: &Context<'_>, search_index: SortedJson) -> Result<PartsAndLocations<Self>, Error> {
290-
let path = suffix_path("search-index.js", &cx.shared.resource_suffix);
285+
fn get(
286+
search_index: SortedJson,
287+
resource_suffix: &str,
288+
) -> Result<PartsAndLocations<Self>, Error> {
289+
let path = suffix_path("search-index.js", resource_suffix);
291290
let search_index = EscapedJson::from(search_index);
292291
Ok(PartsAndLocations::with(path, search_index))
293292
}
@@ -319,8 +318,8 @@ impl AllCratesPart {
319318
///
320319
/// This is to match the current behavior of rustdoc, which allows you to get all crates
321320
/// on the index page, even if --enable-index-page is only passed to the last crate.
322-
fn hack_get_external_crate_names(cx: &Context<'_>) -> Result<Vec<String>, Error> {
323-
let path = cx.dst.join("crates.js");
321+
fn hack_get_external_crate_names(doc_root: &Path) -> Result<Vec<String>, Error> {
322+
let path = doc_root.join("crates.js");
324323
let Ok(content) = fs::read_to_string(&path) else {
325324
// they didn't emit invocation specific, so we just say there were no crates
326325
return Ok(Vec::default());
@@ -361,7 +360,7 @@ impl CratesIndexPart {
361360
match SortedTemplate::magic(&template, MAGIC) {
362361
Ok(template) => template,
363362
Err(e) => panic!(
364-
"{e}: Object Replacement Character (U+FFFC) should not appear in the --index-page"
363+
"Object Replacement Character (U+FFFC) should not appear in the --index-page: {e}"
365364
),
366365
}
367366
}
@@ -860,27 +859,35 @@ impl Serialize for AliasSerializableImpl {
860859
}
861860
}
862861

862+
fn get_path_parts<T: CciPart>(
863+
dst: &Path,
864+
crates_info: &[CrateInfo],
865+
) -> FxHashMap<PathBuf, Vec<String>> {
866+
let mut templates: FxHashMap<PathBuf, Vec<String>> = FxHashMap::default();
867+
crates_info.iter().map(|crate_info| crate_info.get::<T>().parts.iter()).flatten().for_each(
868+
|(path, part)| {
869+
let path = dst.join(&path);
870+
let part = part.to_string();
871+
templates.entry(path).or_default().push(part);
872+
},
873+
);
874+
templates
875+
}
876+
863877
/// Create all parents
864878
fn create_parents(path: &Path) -> Result<(), Error> {
865879
let parent = path.parent().expect("should not have an empty path here");
866880
try_err!(fs::create_dir_all(parent), parent);
867881
Ok(())
868882
}
869883

870-
/// Create parents and then write
871-
fn write_create_parents(path: &Path, content: String) -> Result<(), Error> {
872-
create_parents(path)?;
873-
try_err!(fs::write(path, content), path);
874-
Ok(())
875-
}
876-
877884
/// Returns a blank template unless we could find one to append to
878-
fn read_template_or_blank<F, T: CciPart>(
885+
fn read_template_or_blank<F, T: FileFormat>(
879886
mut make_blank: F,
880887
path: &Path,
881-
) -> Result<SortedTemplate<T::FileFormat>, Error>
888+
) -> Result<SortedTemplate<T>, Error>
882889
where
883-
F: FnMut() -> SortedTemplate<T::FileFormat>,
890+
F: FnMut() -> SortedTemplate<T>,
884891
{
885892
match fs::read_to_string(&path) {
886893
Ok(template) => Ok(try_err!(SortedTemplate::from_str(&template), &path)),
@@ -898,31 +905,21 @@ fn write_rendered_cci<T: CciPart, F>(
898905
where
899906
F: FnMut() -> SortedTemplate<T::FileFormat>,
900907
{
901-
// read parts from disk
902-
let path_parts =
903-
crates_info.iter().map(|crate_info| crate_info.get::<T>().parts.iter()).flatten();
904-
// read previous rendered cci from storage, append to them
905-
let mut templates: FxHashMap<PathBuf, SortedTemplate<T::FileFormat>> = Default::default();
906-
for (path, part) in path_parts {
907-
let part = format!("{part}");
908-
let path = dst.join(&path);
909-
match templates.entry(path.clone()) {
910-
Entry::Vacant(entry) => {
911-
let template = read_template_or_blank::<_, T>(&mut make_blank, &path)?;
912-
let template = entry.insert(template);
913-
template.append(part);
914-
}
915-
Entry::Occupied(mut t) => t.get_mut().append(part),
916-
}
917-
}
918-
919908
// write the merged cci to disk
920-
for (path, template) in templates {
909+
for (path, parts) in get_path_parts::<T>(dst, crates_info) {
921910
create_parents(&path)?;
911+
// read previous rendered cci from storage, append to them
912+
let mut template = read_template_or_blank::<_, T::FileFormat>(&mut make_blank, &path)?;
913+
for part in parts {
914+
template.append(part);
915+
}
922916
let file = try_err!(File::create(&path), &path);
923917
let mut file = BufWriter::new(file);
924918
try_err!(write!(file, "{template}"), &path);
925919
try_err!(file.flush(), &path);
926920
}
927921
Ok(())
928922
}
923+
924+
#[cfg(test)]
925+
mod tests;

0 commit comments

Comments
 (0)