Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generating a documentation for tests #130463

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions src/doc/rustdoc/src/unstable-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -627,3 +627,34 @@ add the `--scrape-tests` flag.

This flag enables the generation of links in the source code pages which allow the reader
to jump to a type definition.

### `--document-tests`: show test items

Using this flag looks like this:

```bash
$ rustdoc src/lib.rs -Z unstable-options --cfg test --document-private-items --document-tests
```

By default, `rustdoc` does not document test items.

```rust
/// by default this test function would not be documented
#[test]
fn test_in_module() {
assert_eq!(2, 1 + 1);
}
/// by default this test module would not be documented
#[cfg(test)]
mod tests {
/// by default this test function would not be documented
#[test]
fn test_in_a_test_module() {
assert_eq!(2, 1 + 1);
}
}
```

Note:
* `--cfg test` must be set because tests are guarded by #[cfg(test)].
* `--document-private-items` is typically required because it is standard practice to keep test items private. By enabling this option, you ensure that private items, including tests, are documented as needed while maintaining their non-public status.
6 changes: 5 additions & 1 deletion src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1022,7 +1022,11 @@ fn clean_fn_or_proc_macro<'tcx>(
None => {
let mut func = clean_function(cx, sig, generics, FunctionArgs::Body(body_id));
clean_fn_decl_legacy_const_generics(&mut func, attrs);
FunctionItem(func)
if cx.cache.document_tests && cx.cache.tests.contains(&item.owner_id.to_def_id()) {
TestItem(func)
} else {
FunctionItem(func)
}
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,10 @@ impl Item {
asyncness: hir::IsAsync::NotAsync,
}
}
ItemKind::FunctionItem(_) | ItemKind::MethodItem(_, _) | ItemKind::TyMethodItem(_) => {
ItemKind::FunctionItem(_)
| ItemKind::MethodItem(_, _)
| ItemKind::TyMethodItem(_)
| ItemKind::TestItem(_) => {
Comment on lines +677 to +680
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modelling a #[test] fn as a distinct ItemKind seems a bit strange: #[test] fns are still function items, I wonder if you can distinguish non-#[test] fns versus #[test] fns by looking at the existence/absence of the #[test] attribute.

But yeah, rendering docs for tests do seem useful. Though a question that immediately comes to my mind is that do test-affiliated module docs get rendered too? As in e.g. docs on #[cfg(test)] mod tests;. I would think that they do, but I haven't looked closely if they do in this implementation.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, they are rendered in this implementation though they are most likely not pub therefore the additional flag --document-private-items may be needed.

Copy link
Member

@GuillaumeGomez GuillaumeGomez Sep 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @jieyouxu, but also I like this difference as it makes it simpler to know what's being manipulated... I suppose it's fine as is for now. :)

Another approach could be to add a bool value saying whether or not it's a test function.

As for cfged out items, unfortunately you will need to pass --cfg test to have them (alongside --document-private-items).

let def_id = self.def_id().unwrap();
build_fn_header(def_id, tcx, tcx.asyncness(def_id))
}
Expand Down Expand Up @@ -841,6 +844,7 @@ pub(crate) enum ItemKind {
UnionItem(Union),
EnumItem(Enum),
FunctionItem(Box<Function>),
TestItem(Box<Function>),
ModuleItem(Module),
TypeAliasItem(Box<TypeAlias>),
StaticItem(Static),
Expand Down Expand Up @@ -899,6 +903,7 @@ impl ItemKind {
ExternCrateItem { .. }
| ImportItem(_)
| FunctionItem(_)
| TestItem(_)
| TypeAliasItem(_)
| StaticItem(_)
| ConstantItem(_)
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/clean/types/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ fn should_not_trim() {
fn is_same_generic() {
use crate::clean::types::{PrimitiveType, Type};
use crate::formats::cache::Cache;
let cache = Cache::new(false, false);
let cache = Cache::new(false, false, false);
let generic = Type::Generic(rustc_span::symbol::sym::Any);
let unit = Type::Primitive(PrimitiveType::Unit);
assert!(!generic.is_doc_subtype_of(&unit, &cache));
Expand Down
4 changes: 4 additions & 0 deletions src/librustdoc/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,8 @@ pub(crate) struct RenderOptions {
pub(crate) document_private: bool,
/// Document items that have `doc(hidden)`.
pub(crate) document_hidden: bool,
/// Document tests.
pub(crate) document_tests: bool,
/// If `true`, generate a JSON file in the crate folder instead of HTML redirection files.
pub(crate) generate_redirect_map: bool,
/// Show the memory layout of types in the docs.
Expand Down Expand Up @@ -772,6 +774,7 @@ impl Options {
}

let scrape_examples_options = ScrapeExamplesOptions::new(matches, dcx);
let document_tests = matches.opt_present("document-tests");
let with_examples = matches.opt_strs("with-examples");
let call_locations = crate::scrape_examples::load_call_locations(with_examples, dcx);

Expand Down Expand Up @@ -840,6 +843,7 @@ impl Options {
markdown_playground_url,
document_private,
document_hidden,
document_tests,
generate_redirect_map,
show_type_layout,
unstable_features,
Expand Down
11 changes: 8 additions & 3 deletions src/librustdoc/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ pub(crate) fn create_config(
remap_path_prefix,
..
}: RustdocOptions,
RenderOptions { document_private, .. }: &RenderOptions,
RenderOptions { document_private, document_tests, .. }: &RenderOptions,
using_internal_features: Arc<AtomicBool>,
) -> rustc_interface::Config {
// Add the doc cfg into the doc build.
Expand Down Expand Up @@ -227,7 +227,8 @@ pub(crate) fn create_config(
if proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] };
let resolve_doc_links =
if *document_private { ResolveDocLinks::All } else { ResolveDocLinks::Exported };
let test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false);
let test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false)
|| (cfgs.iter().any(|cfg| cfg == "test") && *document_tests);
// plays with error output here!
let sessopts = config::Options {
maybe_sysroot,
Expand Down Expand Up @@ -341,7 +342,11 @@ pub(crate) fn run_global_ctxt(
impl_trait_bounds: Default::default(),
generated_synthetics: Default::default(),
auto_traits,
cache: Cache::new(render_options.document_private, render_options.document_hidden),
cache: Cache::new(
render_options.document_private,
render_options.document_hidden,
render_options.document_tests,
),
inlined: FxHashSet::default(),
output_format,
render_options,
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ pub(crate) trait DocFolder: Sized {
ExternCrateItem { src: _ }
| ImportItem(_)
| FunctionItem(_)
| TestItem(_)
| StaticItem(_)
| ConstantItem(..)
| TraitAliasItem(_)
Expand Down
10 changes: 8 additions & 2 deletions src/librustdoc/formats/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ pub(crate) struct Cache {
/// Whether to document hidden items.
/// This is stored in `Cache` so it doesn't need to be passed through all rustdoc functions.
pub(crate) document_hidden: bool,
/// Whether to document tests.
/// This is stored in `Cache` so it doesn't need to be passed through all rustdoc functions.
pub(crate) document_tests: bool,
/// DefIds of all functions which are tests.
pub(crate) tests: FxHashSet<DefId>,

/// Crates marked with [`#[doc(masked)]`][doc_masked].
///
Expand Down Expand Up @@ -142,8 +147,8 @@ struct CacheBuilder<'a, 'tcx> {
}

impl Cache {
pub(crate) fn new(document_private: bool, document_hidden: bool) -> Self {
Cache { document_private, document_hidden, ..Cache::default() }
pub(crate) fn new(document_private: bool, document_hidden: bool, document_tests: bool) -> Self {
Cache { document_private, document_hidden, document_tests, ..Cache::default() }
}

/// Populates the `Cache` with more data. The returned `Crate` will be missing some data that was
Expand Down Expand Up @@ -295,6 +300,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
| clean::TraitItem(..)
| clean::TraitAliasItem(..)
| clean::FunctionItem(..)
| clean::TestItem(..)
| clean::ModuleItem(..)
| clean::ForeignFunctionItem(..)
| clean::ForeignStaticItem(..)
Expand Down
3 changes: 3 additions & 0 deletions src/librustdoc/formats/item_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ pub(crate) enum ItemType {
TraitAlias = 25,
// This number is reserved for use in JavaScript
// Generic = 26,
Test = 27,
ifxfrancois marked this conversation as resolved.
Show resolved Hide resolved
}

impl Serialize for ItemType {
Expand All @@ -83,6 +84,7 @@ impl<'a> From<&'a clean::Item> for ItemType {
clean::UnionItem(..) => ItemType::Union,
clean::EnumItem(..) => ItemType::Enum,
clean::FunctionItem(..) => ItemType::Function,
clean::TestItem(..) => ItemType::Test,
clean::TypeAliasItem(..) => ItemType::TypeAlias,
clean::StaticItem(..) => ItemType::Static,
clean::ConstantItem(..) => ItemType::Constant,
Expand Down Expand Up @@ -176,6 +178,7 @@ impl ItemType {
ItemType::Union => "union",
ItemType::Enum => "enum",
ItemType::Function => "fn",
ItemType::Test => "test",
ItemType::TypeAlias => "type",
ItemType::Static => "static",
ItemType::Trait => "trait",
Expand Down
15 changes: 15 additions & 0 deletions src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ struct AllTypes {
attribute_macros: FxIndexSet<ItemEntry>,
derive_macros: FxIndexSet<ItemEntry>,
trait_aliases: FxIndexSet<ItemEntry>,
tests: FxIndexSet<ItemEntry>,
}

impl AllTypes {
Expand All @@ -360,6 +361,7 @@ impl AllTypes {
attribute_macros: new_set(100),
derive_macros: new_set(100),
trait_aliases: new_set(100),
tests: new_set(100),
}
}

Expand All @@ -385,6 +387,7 @@ impl AllTypes {
}
ItemType::ProcDerive => self.derive_macros.insert(ItemEntry::new(new_url, name)),
ItemType::TraitAlias => self.trait_aliases.insert(ItemEntry::new(new_url, name)),
ItemType::Test => self.tests.insert(ItemEntry::new(new_url, name)),
_ => true,
};
}
Expand Down Expand Up @@ -414,6 +417,9 @@ impl AllTypes {
if !self.functions.is_empty() {
sections.insert(ItemSection::Functions);
}
if !self.tests.is_empty() {
ifxfrancois marked this conversation as resolved.
Show resolved Hide resolved
sections.insert(ItemSection::Tests);
}
if !self.type_aliases.is_empty() {
sections.insert(ItemSection::TypeAliases);
}
Expand All @@ -432,6 +438,9 @@ impl AllTypes {
if !self.trait_aliases.is_empty() {
sections.insert(ItemSection::TraitAliases);
}
if !self.tests.is_empty() {
sections.insert(ItemSection::Tests);
}

sections
}
Expand Down Expand Up @@ -468,6 +477,7 @@ impl AllTypes {
print_entries(f, &self.attribute_macros, ItemSection::AttributeMacros);
print_entries(f, &self.derive_macros, ItemSection::DeriveMacros);
print_entries(f, &self.functions, ItemSection::Functions);
print_entries(f, &self.tests, ItemSection::Tests);
print_entries(f, &self.type_aliases, ItemSection::TypeAliases);
print_entries(f, &self.trait_aliases, ItemSection::TraitAliases);
print_entries(f, &self.statics, ItemSection::Statics);
Expand Down Expand Up @@ -2227,6 +2237,7 @@ pub(crate) enum ItemSection {
Statics,
Traits,
Functions,
Tests,
TypeAliases,
Unions,
Implementations,
Expand Down Expand Up @@ -2259,6 +2270,7 @@ impl ItemSection {
Statics,
Traits,
Functions,
Tests,
TypeAliases,
Unions,
Implementations,
Expand All @@ -2284,6 +2296,7 @@ impl ItemSection {
Self::Unions => "unions",
Self::Enums => "enums",
Self::Functions => "functions",
Self::Tests => "tests",
Self::TypeAliases => "types",
Self::Statics => "statics",
Self::Constants => "constants",
Expand Down Expand Up @@ -2313,6 +2326,7 @@ impl ItemSection {
Self::Unions => "Unions",
Self::Enums => "Enums",
Self::Functions => "Functions",
Self::Tests => "Tests",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe "Unit tests" instead? Same above.

Self::TypeAliases => "Type Aliases",
Self::Statics => "Statics",
Self::Constants => "Constants",
Expand Down Expand Up @@ -2343,6 +2357,7 @@ fn item_ty_to_section(ty: ItemType) -> ItemSection {
ItemType::Union => ItemSection::Unions,
ItemType::Enum => ItemSection::Enums,
ItemType::Function => ItemSection::Functions,
ItemType::Test => ItemSection::Tests,
ItemType::TypeAlias => ItemSection::TypeAliases,
ItemType::Static => ItemSection::Statics,
ItemType::Constant => ItemSection::Constants,
Expand Down
8 changes: 5 additions & 3 deletions src/librustdoc/html/render/print_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf
}
}
clean::FunctionItem(..) | clean::ForeignFunctionItem(..) => "Function ",
clean::TestItem(..) => "Test ",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Unit test "

Copy link
Author

@ifxfrancois ifxfrancois Sep 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@GuillaumeGomez We also want to call this documentation build on integration tests. If we change this to "Unit Test", the integration tests will also appear as Unit tests.
With a command like cargo rustdoc --test lib_test -- -Z unstable-options --document-tests --document-private-items

clean::TraitItem(..) => "Trait ",
clean::StructItem(..) => "Struct ",
clean::UnionItem(..) => "Union ",
Expand Down Expand Up @@ -254,9 +255,9 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf

match &item.kind {
clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items),
clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f, _) => {
item_function(buf, cx, item, f)
}
clean::FunctionItem(ref f)
| clean::ForeignFunctionItem(ref f, _)
| clean::TestItem(ref f) => item_function(buf, cx, item, f),
clean::TraitItem(ref t) => item_trait(buf, cx, item, t),
clean::StructItem(ref s) => item_struct(buf, cx, item, s),
clean::UnionItem(ref s) => item_union(buf, cx, item, s),
Expand Down Expand Up @@ -332,6 +333,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
ItemType::Static => 8,
ItemType::Trait => 9,
ItemType::Function => 10,
ItemType::Test => 11,
ItemType::TypeAlias => 12,
ItemType::Union => 13,
_ => 14 + ty as u8,
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/html/static/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,7 @@ function preLoadCss(cssUrl) {
block("static", "static", "Statics");
block("trait", "traits", "Traits");
block("fn", "functions", "Functions");
block("test", "tests", "Tests");
block("type", "types", "Type Aliases");
block("union", "unions", "Unions");
// No point, because these items don't appear in modules
Expand Down
6 changes: 4 additions & 2 deletions src/librustdoc/json/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,9 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
StructFieldItem(f) => ItemEnum::StructField(f.into_tcx(tcx)),
EnumItem(e) => ItemEnum::Enum(e.into_tcx(tcx)),
VariantItem(v) => ItemEnum::Variant(v.into_tcx(tcx)),
FunctionItem(f) => ItemEnum::Function(from_function(f, true, header.unwrap(), tcx)),
FunctionItem(f) | TestItem(f) => {
ItemEnum::Function(from_function(f, true, header.unwrap(), tcx))
}
ForeignFunctionItem(f, _) => {
ItemEnum::Function(from_function(f, false, header.unwrap(), tcx))
}
Expand Down Expand Up @@ -858,7 +860,7 @@ impl FromWithTcx<ItemType> for ItemKind {
Struct => ItemKind::Struct,
Union => ItemKind::Union,
Enum => ItemKind::Enum,
Function | TyMethod | Method => ItemKind::Function,
Function | Test | TyMethod | Method => ItemKind::Function,
TypeAlias => ItemKind::TypeAlias,
Static => ItemKind::Static,
Constant => ItemKind::Constant,
Expand Down
3 changes: 3 additions & 0 deletions src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,9 @@ fn opts() -> Vec<RustcOptGroup> {
unstable("scrape-tests", |o| {
o.optflag("", "scrape-tests", "Include test code when scraping examples")
}),
unstable("document-tests", |o| {
o.optflagmulti("", "document-tests", "Generate documentation for tests")
}),
unstable("with-examples", |o| {
o.optmulti(
"",
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/passes/stripper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> {
| clean::EnumItem(..)
| clean::TraitItem(..)
| clean::FunctionItem(..)
| clean::TestItem(..)
| clean::VariantItem(..)
| clean::ForeignFunctionItem(..)
| clean::ForeignStaticItem(..)
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub(crate) trait DocVisitor<'a>: Sized {
ExternCrateItem { src: _ }
| ImportItem(_)
| FunctionItem(_)
| TestItem(_)
| TypeAliasItem(_)
| StaticItem(_)
| ConstantItem(..)
Expand Down
Loading
Loading