Add tests for `custom_code_classes_in_docs` feature

This commit is contained in:
Guillaume Gomez 2023-04-25 15:04:46 +02:00
parent 5515fc88dc
commit f5561842e3
9 changed files with 268 additions and 27 deletions

View File

@ -1,5 +1,8 @@
use super::{find_testable_code, plain_text_summary, short_markdown_summary};
use super::{ErrorCodes, HeadingOffset, IdMap, Ignore, LangString, Markdown, MarkdownItemInfo};
use super::{
ErrorCodes, HeadingOffset, IdMap, Ignore, LangString, Markdown, MarkdownItemInfo, TagIterator,
TokenKind,
};
use rustc_span::edition::{Edition, DEFAULT_EDITION};
#[test]
@ -51,10 +54,25 @@ fn test_lang_string_parse() {
t(Default::default());
t(LangString { original: "rust".into(), ..Default::default() });
t(LangString { original: ".rust".into(), ..Default::default() });
t(LangString { original: "{rust}".into(), ..Default::default() });
t(LangString { original: "{.rust}".into(), ..Default::default() });
t(LangString { original: "sh".into(), rust: false, ..Default::default() });
t(LangString {
original: ".rust".into(),
rust: false,
unknown: vec![".rust".into()],
..Default::default()
});
t(LangString { original: "{rust}".into(), rust: false, ..Default::default() });
t(LangString {
original: "{.rust}".into(),
rust: false,
added_classes: vec!["rust".into()],
..Default::default()
});
t(LangString {
original: "sh".into(),
rust: false,
unknown: vec!["sh".into()],
..Default::default()
});
t(LangString { original: "ignore".into(), ignore: Ignore::All, ..Default::default() });
t(LangString {
original: "ignore-foo".into(),
@ -70,41 +88,56 @@ fn test_lang_string_parse() {
compile_fail: true,
..Default::default()
});
t(LangString { original: "no_run,example".into(), no_run: true, ..Default::default() });
t(LangString {
original: "no_run,example".into(),
no_run: true,
unknown: vec!["example".into()],
..Default::default()
});
t(LangString {
original: "sh,should_panic".into(),
should_panic: true,
rust: false,
unknown: vec!["sh".into()],
..Default::default()
});
t(LangString {
original: "example,rust".into(),
unknown: vec!["example".into()],
..Default::default()
});
t(LangString { original: "example,rust".into(), ..Default::default() });
t(LangString {
original: "test_harness,.rust".into(),
test_harness: true,
unknown: vec![".rust".into()],
..Default::default()
});
t(LangString {
original: "text, no_run".into(),
no_run: true,
rust: false,
unknown: vec!["text".into()],
..Default::default()
});
t(LangString {
original: "text,no_run".into(),
no_run: true,
rust: false,
unknown: vec!["text".into()],
..Default::default()
});
t(LangString {
original: "text,no_run, ".into(),
no_run: true,
rust: false,
unknown: vec!["text".into()],
..Default::default()
});
t(LangString {
original: "text,no_run,".into(),
no_run: true,
rust: false,
unknown: vec!["text".into()],
..Default::default()
});
t(LangString {
@ -118,52 +151,96 @@ fn test_lang_string_parse() {
..Default::default()
});
t(LangString {
original: "class:test".into(),
original: "{class=test}".into(),
added_classes: vec!["test".into()],
rust: false,
..Default::default()
});
t(LangString {
original: "rust,class:test".into(),
original: "{.test}".into(),
added_classes: vec!["test".into()],
rust: false,
..Default::default()
});
t(LangString {
original: "rust,{class=test,.test2}".into(),
added_classes: vec!["test".into(), "test2".into()],
rust: true,
..Default::default()
});
t(LangString {
original: "class:test:with:colon".into(),
added_classes: vec!["test:with:colon".into()],
original: "{class=test:with:colon .test1}".into(),
added_classes: vec!["test:with:colon".into(), "test1".into()],
rust: false,
..Default::default()
});
t(LangString {
original: "class:first,class:second".into(),
original: "{class=first,class=second}".into(),
added_classes: vec!["first".into(), "second".into()],
rust: false,
..Default::default()
});
t(LangString {
original: "{class=first,.second},unknown".into(),
added_classes: vec!["first".into(), "second".into()],
rust: false,
unknown: vec!["unknown".into()],
..Default::default()
});
t(LangString {
original: "{class=first .second} unknown".into(),
added_classes: vec!["first".into(), "second".into()],
rust: false,
unknown: vec!["unknown".into()],
..Default::default()
});
t(LangString {
original: "{.first.second}".into(),
added_classes: vec!["first.second".into()],
rust: false,
..Default::default()
});
t(LangString {
original: "{class=first=second}".into(),
added_classes: vec!["first=second".into()],
rust: false,
..Default::default()
});
t(LangString {
original: "{class=first.second}".into(),
added_classes: vec!["first.second".into()],
rust: false,
..Default::default()
});
t(LangString {
original: "{class=.first}".into(),
added_classes: vec![".first".into()],
rust: false,
..Default::default()
});
}
#[test]
fn test_lang_string_tokenizer() {
fn case(lang_string: &str, want: &[&str]) {
let have = LangString::tokens(lang_string).collect::<Vec<&str>>();
fn case(lang_string: &str, want: &[TokenKind<'_>]) {
let have = TagIterator::new(lang_string, None).collect::<Vec<_>>();
assert_eq!(have, want, "Unexpected lang string split for `{}`", lang_string);
}
case("", &[]);
case("foo", &["foo"]);
case("foo,bar", &["foo", "bar"]);
case(".foo,.bar", &["foo", "bar"]);
case("{.foo,.bar}", &["foo", "bar"]);
case(" {.foo,.bar} ", &["foo", "bar"]);
case("foo bar", &["foo", "bar"]);
case("foo\tbar", &["foo", "bar"]);
case("foo\t, bar", &["foo", "bar"]);
case(" foo , bar ", &["foo", "bar"]);
case(",,foo,,bar,,", &["foo", "bar"]);
case("foo=bar", &["foo=bar"]);
case("a-b-c", &["a-b-c"]);
case("a_b_c", &["a_b_c"]);
case("foo", &[TokenKind::Token("foo")]);
case("foo,bar", &[TokenKind::Token("foo"), TokenKind::Token("bar")]);
case(".foo,.bar", &[TokenKind::Token(".foo"), TokenKind::Token(".bar")]);
case("{.foo,.bar}", &[TokenKind::Attribute(".foo"), TokenKind::Attribute(".bar")]);
case(" {.foo,.bar} ", &[TokenKind::Attribute(".foo"), TokenKind::Attribute(".bar")]);
case("foo bar", &[TokenKind::Token("foo"), TokenKind::Token("bar")]);
case("foo\tbar", &[TokenKind::Token("foo"), TokenKind::Token("bar")]);
case("foo\t, bar", &[TokenKind::Token("foo"), TokenKind::Token("bar")]);
case(" foo , bar ", &[TokenKind::Token("foo"), TokenKind::Token("bar")]);
case(",,foo,,bar,,", &[TokenKind::Token("foo"), TokenKind::Token("bar")]);
case("foo=bar", &[TokenKind::Token("foo=bar")]);
case("a-b-c", &[TokenKind::Token("a-b-c")]);
case("a_b_c", &[TokenKind::Token("a_b_c")]);
}
#[test]

View File

@ -0,0 +1,19 @@
// This test ensures that warnings are working as expected for "custom_code_classes_in_docs"
// feature.
#![feature(custom_code_classes_in_docs)]
#![deny(warnings)]
#![feature(no_core)]
#![no_core]
/// ```{. class= whatever=hehe #id} } {{
/// main;
/// ```
//~^^^ ERROR missing class name after `.`
//~| ERROR missing class name after `class=`
//~| ERROR unsupported attribute `whatever=hehe`
//~| ERROR unsupported attribute `#id`
//~| ERROR unexpected `}` outside attribute block (`{}`)
//~| ERROR unclosed attribute block (`{}`): missing `}` at the end
//~| ERROR unexpected `{` inside attribute block (`{}`)
pub fn foo() {}

View File

@ -0,0 +1,65 @@
error: missing class name after `.`
--> $DIR/custom_code_classes_in_docs-warning.rs:9:1
|
LL | / /// ```{. class= whatever=hehe #id} } {{
LL | | /// main;
LL | | /// ```
| |_______^
|
note: the lint level is defined here
--> $DIR/custom_code_classes_in_docs-warning.rs:5:9
|
LL | #![deny(warnings)]
| ^^^^^^^^
= note: `#[deny(rustdoc::invalid_codeblock_attributes)]` implied by `#[deny(warnings)]`
error: missing class name after `class=`
--> $DIR/custom_code_classes_in_docs-warning.rs:9:1
|
LL | / /// ```{. class= whatever=hehe #id} } {{
LL | | /// main;
LL | | /// ```
| |_______^
error: unsupported attribute `whatever=hehe`
--> $DIR/custom_code_classes_in_docs-warning.rs:9:1
|
LL | / /// ```{. class= whatever=hehe #id} } {{
LL | | /// main;
LL | | /// ```
| |_______^
error: unsupported attribute `#id`
--> $DIR/custom_code_classes_in_docs-warning.rs:9:1
|
LL | / /// ```{. class= whatever=hehe #id} } {{
LL | | /// main;
LL | | /// ```
| |_______^
error: unexpected `}` outside attribute block (`{}`)
--> $DIR/custom_code_classes_in_docs-warning.rs:9:1
|
LL | / /// ```{. class= whatever=hehe #id} } {{
LL | | /// main;
LL | | /// ```
| |_______^
error: unexpected `{` inside attribute block (`{}`)
--> $DIR/custom_code_classes_in_docs-warning.rs:9:1
|
LL | / /// ```{. class= whatever=hehe #id} } {{
LL | | /// main;
LL | | /// ```
| |_______^
error: unclosed attribute block (`{}`): missing `}` at the end
--> $DIR/custom_code_classes_in_docs-warning.rs:9:1
|
LL | / /// ```{. class= whatever=hehe #id} } {{
LL | | /// main;
LL | | /// ```
| |_______^
error: aborting due to 7 previous errors

View File

@ -0,0 +1,13 @@
// This test ensures that warnings are working as expected for "custom_code_classes_in_docs"
// feature.
#![feature(custom_code_classes_in_docs)]
#![deny(warnings)]
#![feature(no_core)]
#![no_core]
/// ```{class=}
/// main;
/// ```
//~^^^ ERROR missing class name after `class=`
pub fn foo() {}

View File

@ -0,0 +1,17 @@
error: missing class name after `class=`
--> $DIR/custom_code_classes_in_docs-warning2.rs:9:1
|
LL | / /// ```{class=}
LL | | /// main;
LL | | /// ```
| |_______^
|
note: the lint level is defined here
--> $DIR/custom_code_classes_in_docs-warning2.rs:5:9
|
LL | #![deny(warnings)]
| ^^^^^^^^
= note: `#[deny(rustdoc::invalid_codeblock_attributes)]` implied by `#[deny(warnings)]`
error: aborting due to previous error

View File

@ -0,0 +1,5 @@
/// ```{class=language-c}
/// int main(void) { return 0; }
/// ```
//~^^^ ERROR 1:1: 3:8: custom classes in code blocks are unstable [E0658]
pub struct Bar;

View File

@ -0,0 +1,15 @@
error[E0658]: custom classes in code blocks are unstable
--> $DIR/feature-gate-custom_code_classes_in_docs.rs:1:1
|
LL | / /// ```{class=language-c}
LL | | /// int main(void) { return 0; }
LL | | /// ```
| |_______^
|
= note: see issue #79483 <https://github.com/rust-lang/rust/issues/79483> for more information
= help: add `#![feature(custom_code_classes_in_docs)]` to the crate attributes to enable
= note: found these custom classes: class=language-c
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View File

@ -1,4 +1,5 @@
Available passes for running rustdoc:
check-custom-code-classes - check for custom code classes without the feature-gate enabled
check_doc_test_visibility - run various visibility-related lints on doctests
strip-hidden - strips all `#[doc(hidden)]` items from the output
strip-private - strips all private items from a crate which cannot be seen externally, implies strip-priv-imports
@ -10,6 +11,7 @@ calculate-doc-coverage - counts the number of items with and without documentati
run-lints - runs some of rustdoc's lints
Default passes for rustdoc:
check-custom-code-classes
collect-trait-impls
check_doc_test_visibility
strip-hidden (when not --document-hidden-items)

View File

@ -0,0 +1,28 @@
// Test for `custom_code_classes_in_docs` feature.
#![feature(custom_code_classes_in_docs)]
#![crate_name = "foo"]
#![feature(no_core)]
#![no_core]
// @has 'foo/struct.Bar.html'
// @has - '//*[@id="main-content"]//pre[@class="language-whatever hoho-c"]' 'main;'
// @has - '//*[@id="main-content"]//pre[@class="language-whatever2 haha-c"]' 'main;'
// @has - '//*[@id="main-content"]//pre[@class="language-whatever4 huhu-c"]' 'main;'
/// ```{class=hoho-c},whatever
/// main;
/// ```
///
/// Testing multiple kinds of orders.
///
/// ```whatever2 {class=haha-c}
/// main;
/// ```
///
/// Testing with multiple "unknown". Only the first should be used.
///
/// ```whatever4{.huhu-c} whatever5
/// main;
/// ```
pub struct Bar;