Rollup merge of #141399 - GuillaumeGomez:extracted-doctest, r=aDotInTheVoid
[rustdoc] Give more information into extracted doctest information Follow-up of https://github.com/rust-lang/rust/pull/134531. This update fragment the doctest code into its sub-parts to give more control to the end users on how they want to use it. The new JSON looks like this: ```json { "format_version":2, "doctests":[ { "file":"$DIR/extract-doctests-result.rs", "line":8, "doctest_attributes":{ "original":"", "should_panic":false, "no_run":false, "ignore":"None", "rust":true, "test_harness":false, "compile_fail":false, "standalone_crate":false, "error_codes":[], "edition":null, "added_css_classes":[], "unknown":[] }, "original_code":"let x = 12;\nOk(())", "doctest_code":{ "crate_level":"#![allow(unused)]\n", "code":"let x = 12;\nOk(())", "wrapper":{ "before":"fn main() { fn _inner() -> core::result::Result<(), impl core::fmt::Debug> {\n", "after":"\n} _inner().unwrap() }", "returns_result":true } }, "name":"$DIR/extract-doctests-result.rs - (line 8)" } ] } ``` for this doctest: ```rust let x = 12; Ok(()) ``` With this, I think it matches what you need ``@ojeda?`` If so, once merged I'll update the patch I sent to RfL. r? ``@aDotInTheVoid``
This commit is contained in:
commit
9bdf5d371f
9 changed files with 251 additions and 56 deletions
|
|
@ -581,7 +581,9 @@ For this rust code:
|
|||
|
||||
```rust
|
||||
/// ```
|
||||
/// #![allow(dead_code)]
|
||||
/// let x = 12;
|
||||
/// Ok(())
|
||||
/// ```
|
||||
pub trait Trait {}
|
||||
```
|
||||
|
|
@ -590,10 +592,10 @@ The generated output (formatted) will look like this:
|
|||
|
||||
```json
|
||||
{
|
||||
"format_version": 1,
|
||||
"format_version": 2,
|
||||
"doctests": [
|
||||
{
|
||||
"file": "foo.rs",
|
||||
"file": "src/lib.rs",
|
||||
"line": 1,
|
||||
"doctest_attributes": {
|
||||
"original": "",
|
||||
|
|
@ -609,9 +611,17 @@ The generated output (formatted) will look like this:
|
|||
"added_css_classes": [],
|
||||
"unknown": []
|
||||
},
|
||||
"original_code": "let x = 12;",
|
||||
"doctest_code": "#![allow(unused)]\nfn main() {\nlet x = 12;\n}",
|
||||
"name": "foo.rs - Trait (line 1)"
|
||||
"original_code": "#![allow(dead_code)]\nlet x = 12;\nOk(())",
|
||||
"doctest_code": {
|
||||
"crate_level": "#![allow(unused)]\n#![allow(dead_code)]\n\n",
|
||||
"code": "let x = 12;\nOk(())",
|
||||
"wrapper": {
|
||||
"before": "fn main() { fn _inner() -> core::result::Result<(), impl core::fmt::Debug> {\n",
|
||||
"after": "\n} _inner().unwrap() }",
|
||||
"returns_result": true
|
||||
}
|
||||
},
|
||||
"name": "src/lib.rs - (line 1)"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -624,6 +634,10 @@ The generated output (formatted) will look like this:
|
|||
* `doctest_attributes` contains computed information about the attributes used on the doctests. For more information about doctest attributes, take a look [here](write-documentation/documentation-tests.html#attributes).
|
||||
* `original_code` is the code as written in the source code before rustdoc modifies it.
|
||||
* `doctest_code` is the code modified by rustdoc that will be run. If there is a fatal syntax error, this field will not be present.
|
||||
* `crate_level` is the crate level code (like attributes or `extern crate`) that will be added at the top-level of the generated doctest.
|
||||
* `code` is "naked" doctest without anything from `crate_level` and `wrapper` content.
|
||||
* `wrapper` contains extra code that will be added before and after `code`.
|
||||
* `returns_result` is a boolean. If `true`, it means that the doctest returns a `Result` type.
|
||||
* `name` is the name generated by rustdoc which represents this doctest.
|
||||
|
||||
### html
|
||||
|
|
|
|||
|
|
@ -1053,14 +1053,14 @@ fn doctest_run_fn(
|
|||
let report_unused_externs = |uext| {
|
||||
unused_externs.lock().unwrap().push(uext);
|
||||
};
|
||||
let (full_test_code, full_test_line_offset) = doctest.generate_unique_doctest(
|
||||
let (wrapped, full_test_line_offset) = doctest.generate_unique_doctest(
|
||||
&scraped_test.text,
|
||||
scraped_test.langstr.test_harness,
|
||||
&global_opts,
|
||||
Some(&global_opts.crate_name),
|
||||
);
|
||||
let runnable_test = RunnableDocTest {
|
||||
full_test_code,
|
||||
full_test_code: wrapped.to_string(),
|
||||
full_test_line_offset,
|
||||
test_opts,
|
||||
global_opts,
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@
|
|||
//! This module contains the logic to extract doctests and output a JSON containing this
|
||||
//! information.
|
||||
|
||||
use rustc_span::edition::Edition;
|
||||
use serde::Serialize;
|
||||
|
||||
use super::make::DocTestWrapResult;
|
||||
use super::{BuildDocTestBuilder, ScrapedDocTest};
|
||||
use crate::config::Options as RustdocOptions;
|
||||
use crate::html::markdown;
|
||||
|
|
@ -14,7 +16,7 @@ use crate::html::markdown;
|
|||
/// This integer is incremented with every breaking change to the API,
|
||||
/// and is returned along with the JSON blob into the `format_version` root field.
|
||||
/// Consuming code should assert that this value matches the format version(s) that it supports.
|
||||
const FORMAT_VERSION: u32 = 1;
|
||||
const FORMAT_VERSION: u32 = 2;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub(crate) struct ExtractedDocTests {
|
||||
|
|
@ -34,7 +36,16 @@ impl ExtractedDocTests {
|
|||
options: &RustdocOptions,
|
||||
) {
|
||||
let edition = scraped_test.edition(options);
|
||||
self.add_test_with_edition(scraped_test, opts, edition)
|
||||
}
|
||||
|
||||
/// This method is used by unit tests to not have to provide a `RustdocOptions`.
|
||||
pub(crate) fn add_test_with_edition(
|
||||
&mut self,
|
||||
scraped_test: ScrapedDocTest,
|
||||
opts: &super::GlobalTestOptions,
|
||||
edition: Edition,
|
||||
) {
|
||||
let ScrapedDocTest { filename, line, langstr, text, name, global_crate_attrs, .. } =
|
||||
scraped_test;
|
||||
|
||||
|
|
@ -44,8 +55,7 @@ impl ExtractedDocTests {
|
|||
.edition(edition)
|
||||
.lang_str(&langstr)
|
||||
.build(None);
|
||||
|
||||
let (full_test_code, size) = doctest.generate_unique_doctest(
|
||||
let (wrapped, _size) = doctest.generate_unique_doctest(
|
||||
&text,
|
||||
langstr.test_harness,
|
||||
opts,
|
||||
|
|
@ -55,11 +65,46 @@ impl ExtractedDocTests {
|
|||
file: filename.prefer_remapped_unconditionaly().to_string(),
|
||||
line,
|
||||
doctest_attributes: langstr.into(),
|
||||
doctest_code: if size != 0 { Some(full_test_code) } else { None },
|
||||
doctest_code: match wrapped {
|
||||
DocTestWrapResult::Valid { crate_level_code, wrapper, code } => Some(DocTest {
|
||||
crate_level: crate_level_code,
|
||||
code,
|
||||
wrapper: wrapper.map(
|
||||
|super::make::WrapperInfo { before, after, returns_result, .. }| {
|
||||
WrapperInfo { before, after, returns_result }
|
||||
},
|
||||
),
|
||||
}),
|
||||
DocTestWrapResult::SyntaxError { .. } => None,
|
||||
},
|
||||
original_code: text,
|
||||
name,
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn doctests(&self) -> &[ExtractedDocTest] {
|
||||
&self.doctests
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub(crate) struct WrapperInfo {
|
||||
before: String,
|
||||
after: String,
|
||||
returns_result: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub(crate) struct DocTest {
|
||||
crate_level: String,
|
||||
code: String,
|
||||
/// This field can be `None` if one of the following conditions is true:
|
||||
///
|
||||
/// * The doctest's codeblock has the `test_harness` attribute.
|
||||
/// * The doctest has a `main` function.
|
||||
/// * The doctest has the `![no_std]` attribute.
|
||||
pub(crate) wrapper: Option<WrapperInfo>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
|
@ -69,7 +114,7 @@ pub(crate) struct ExtractedDocTest {
|
|||
doctest_attributes: LangString,
|
||||
original_code: String,
|
||||
/// `None` if the code syntax is invalid.
|
||||
doctest_code: Option<String>,
|
||||
pub(crate) doctest_code: Option<DocTest>,
|
||||
name: String,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -196,6 +196,80 @@ pub(crate) struct DocTestBuilder {
|
|||
pub(crate) can_be_merged: bool,
|
||||
}
|
||||
|
||||
/// Contains needed information for doctest to be correctly generated with expected "wrapping".
|
||||
pub(crate) struct WrapperInfo {
|
||||
pub(crate) before: String,
|
||||
pub(crate) after: String,
|
||||
pub(crate) returns_result: bool,
|
||||
insert_indent_space: bool,
|
||||
}
|
||||
|
||||
impl WrapperInfo {
|
||||
fn len(&self) -> usize {
|
||||
self.before.len() + self.after.len()
|
||||
}
|
||||
}
|
||||
|
||||
/// Contains a doctest information. Can be converted into code with the `to_string()` method.
|
||||
pub(crate) enum DocTestWrapResult {
|
||||
Valid {
|
||||
crate_level_code: String,
|
||||
/// This field can be `None` if one of the following conditions is true:
|
||||
///
|
||||
/// * The doctest's codeblock has the `test_harness` attribute.
|
||||
/// * The doctest has a `main` function.
|
||||
/// * The doctest has the `![no_std]` attribute.
|
||||
wrapper: Option<WrapperInfo>,
|
||||
/// Contains the doctest processed code without the wrappers (which are stored in the
|
||||
/// `wrapper` field).
|
||||
code: String,
|
||||
},
|
||||
/// Contains the original source code.
|
||||
SyntaxError(String),
|
||||
}
|
||||
|
||||
impl std::string::ToString for DocTestWrapResult {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Self::SyntaxError(s) => s.clone(),
|
||||
Self::Valid { crate_level_code, wrapper, code } => {
|
||||
let mut prog_len = code.len() + crate_level_code.len();
|
||||
if let Some(wrapper) = wrapper {
|
||||
prog_len += wrapper.len();
|
||||
if wrapper.insert_indent_space {
|
||||
prog_len += code.lines().count() * 4;
|
||||
}
|
||||
}
|
||||
let mut prog = String::with_capacity(prog_len);
|
||||
|
||||
prog.push_str(crate_level_code);
|
||||
if let Some(wrapper) = wrapper {
|
||||
prog.push_str(&wrapper.before);
|
||||
|
||||
// add extra 4 spaces for each line to offset the code block
|
||||
if wrapper.insert_indent_space {
|
||||
write!(
|
||||
prog,
|
||||
"{}",
|
||||
fmt::from_fn(|f| code
|
||||
.lines()
|
||||
.map(|line| fmt::from_fn(move |f| write!(f, " {line}")))
|
||||
.joined("\n", f))
|
||||
)
|
||||
.unwrap();
|
||||
} else {
|
||||
prog.push_str(code);
|
||||
}
|
||||
prog.push_str(&wrapper.after);
|
||||
} else {
|
||||
prog.push_str(code);
|
||||
}
|
||||
prog
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DocTestBuilder {
|
||||
fn invalid(
|
||||
global_crate_attrs: Vec<String>,
|
||||
|
|
@ -228,50 +302,49 @@ impl DocTestBuilder {
|
|||
dont_insert_main: bool,
|
||||
opts: &GlobalTestOptions,
|
||||
crate_name: Option<&str>,
|
||||
) -> (String, usize) {
|
||||
) -> (DocTestWrapResult, usize) {
|
||||
if self.invalid_ast {
|
||||
// If the AST failed to compile, no need to go generate a complete doctest, the error
|
||||
// will be better this way.
|
||||
debug!("invalid AST:\n{test_code}");
|
||||
return (test_code.to_string(), 0);
|
||||
return (DocTestWrapResult::SyntaxError(test_code.to_string()), 0);
|
||||
}
|
||||
let mut line_offset = 0;
|
||||
let mut prog = String::new();
|
||||
let everything_else = self.everything_else.trim();
|
||||
|
||||
let mut crate_level_code = String::new();
|
||||
let processed_code = self.everything_else.trim();
|
||||
if self.global_crate_attrs.is_empty() {
|
||||
// If there aren't any attributes supplied by #![doc(test(attr(...)))], then allow some
|
||||
// lints that are commonly triggered in doctests. The crate-level test attributes are
|
||||
// commonly used to make tests fail in case they trigger warnings, so having this there in
|
||||
// that case may cause some tests to pass when they shouldn't have.
|
||||
prog.push_str("#![allow(unused)]\n");
|
||||
crate_level_code.push_str("#![allow(unused)]\n");
|
||||
line_offset += 1;
|
||||
}
|
||||
|
||||
// Next, any attributes that came from #![doc(test(attr(...)))].
|
||||
for attr in &self.global_crate_attrs {
|
||||
prog.push_str(&format!("#![{attr}]\n"));
|
||||
crate_level_code.push_str(&format!("#![{attr}]\n"));
|
||||
line_offset += 1;
|
||||
}
|
||||
|
||||
// Now push any outer attributes from the example, assuming they
|
||||
// are intended to be crate attributes.
|
||||
if !self.crate_attrs.is_empty() {
|
||||
prog.push_str(&self.crate_attrs);
|
||||
crate_level_code.push_str(&self.crate_attrs);
|
||||
if !self.crate_attrs.ends_with('\n') {
|
||||
prog.push('\n');
|
||||
crate_level_code.push('\n');
|
||||
}
|
||||
}
|
||||
if !self.maybe_crate_attrs.is_empty() {
|
||||
prog.push_str(&self.maybe_crate_attrs);
|
||||
crate_level_code.push_str(&self.maybe_crate_attrs);
|
||||
if !self.maybe_crate_attrs.ends_with('\n') {
|
||||
prog.push('\n');
|
||||
crate_level_code.push('\n');
|
||||
}
|
||||
}
|
||||
if !self.crates.is_empty() {
|
||||
prog.push_str(&self.crates);
|
||||
crate_level_code.push_str(&self.crates);
|
||||
if !self.crates.ends_with('\n') {
|
||||
prog.push('\n');
|
||||
crate_level_code.push('\n');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -289,17 +362,20 @@ impl DocTestBuilder {
|
|||
{
|
||||
// rustdoc implicitly inserts an `extern crate` item for the own crate
|
||||
// which may be unused, so we need to allow the lint.
|
||||
prog.push_str("#[allow(unused_extern_crates)]\n");
|
||||
crate_level_code.push_str("#[allow(unused_extern_crates)]\n");
|
||||
|
||||
prog.push_str(&format!("extern crate r#{crate_name};\n"));
|
||||
crate_level_code.push_str(&format!("extern crate r#{crate_name};\n"));
|
||||
line_offset += 1;
|
||||
}
|
||||
|
||||
// FIXME: This code cannot yet handle no_std test cases yet
|
||||
if dont_insert_main || self.has_main_fn || prog.contains("![no_std]") {
|
||||
prog.push_str(everything_else);
|
||||
let wrapper = if dont_insert_main
|
||||
|| self.has_main_fn
|
||||
|| crate_level_code.contains("![no_std]")
|
||||
{
|
||||
None
|
||||
} else {
|
||||
let returns_result = everything_else.ends_with("(())");
|
||||
let returns_result = processed_code.ends_with("(())");
|
||||
// Give each doctest main function a unique name.
|
||||
// This is for example needed for the tooling around `-C instrument-coverage`.
|
||||
let inner_fn_name = if let Some(ref test_id) = self.test_id {
|
||||
|
|
@ -333,28 +409,22 @@ impl DocTestBuilder {
|
|||
// /// ``` <- end of the inner main
|
||||
line_offset += 1;
|
||||
|
||||
prog.push_str(&main_pre);
|
||||
Some(WrapperInfo {
|
||||
before: main_pre,
|
||||
after: main_post,
|
||||
returns_result,
|
||||
insert_indent_space: opts.insert_indent_space,
|
||||
})
|
||||
};
|
||||
|
||||
// add extra 4 spaces for each line to offset the code block
|
||||
if opts.insert_indent_space {
|
||||
write!(
|
||||
prog,
|
||||
"{}",
|
||||
fmt::from_fn(|f| everything_else
|
||||
.lines()
|
||||
.map(|line| fmt::from_fn(move |f| write!(f, " {line}")))
|
||||
.joined("\n", f))
|
||||
)
|
||||
.unwrap();
|
||||
} else {
|
||||
prog.push_str(everything_else);
|
||||
};
|
||||
prog.push_str(&main_post);
|
||||
}
|
||||
|
||||
debug!("final doctest:\n{prog}");
|
||||
|
||||
(prog, line_offset)
|
||||
(
|
||||
DocTestWrapResult::Valid {
|
||||
code: processed_code.to_string(),
|
||||
wrapper,
|
||||
crate_level_code,
|
||||
},
|
||||
line_offset,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use super::{BuildDocTestBuilder, GlobalTestOptions};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{DUMMY_SP, FileName};
|
||||
|
||||
use super::extracted::ExtractedDocTests;
|
||||
use super::{BuildDocTestBuilder, GlobalTestOptions, ScrapedDocTest};
|
||||
use crate::html::markdown::LangString;
|
||||
|
||||
fn make_test(
|
||||
test_code: &str,
|
||||
|
|
@ -19,9 +24,9 @@ fn make_test(
|
|||
builder = builder.test_id(test_id.to_string());
|
||||
}
|
||||
let doctest = builder.build(None);
|
||||
let (code, line_offset) =
|
||||
let (wrapped, line_offset) =
|
||||
doctest.generate_unique_doctest(test_code, dont_insert_main, opts, crate_name);
|
||||
(code, line_offset)
|
||||
(wrapped.to_string(), line_offset)
|
||||
}
|
||||
|
||||
/// Default [`GlobalTestOptions`] for these unit tests.
|
||||
|
|
@ -461,3 +466,51 @@ pub mod outer_module {
|
|||
let (output, len) = make_test(input, None, false, &opts, Vec::new(), None);
|
||||
assert_eq!((output, len), (expected, 2));
|
||||
}
|
||||
|
||||
fn get_extracted_doctests(code: &str) -> ExtractedDocTests {
|
||||
let opts = default_global_opts("");
|
||||
let mut extractor = ExtractedDocTests::new();
|
||||
extractor.add_test_with_edition(
|
||||
ScrapedDocTest::new(
|
||||
FileName::Custom(String::new()),
|
||||
0,
|
||||
Vec::new(),
|
||||
LangString::default(),
|
||||
code.to_string(),
|
||||
DUMMY_SP,
|
||||
Vec::new(),
|
||||
),
|
||||
&opts,
|
||||
Edition::Edition2018,
|
||||
);
|
||||
extractor
|
||||
}
|
||||
|
||||
// Test that `extracted::DocTest::wrapper` is `None` if the doctest has a `main` function.
|
||||
#[test]
|
||||
fn test_extracted_doctest_wrapper_field() {
|
||||
let extractor = get_extracted_doctests("fn main() {}");
|
||||
|
||||
assert_eq!(extractor.doctests().len(), 1);
|
||||
let doctest_code = extractor.doctests()[0].doctest_code.as_ref().unwrap();
|
||||
assert!(doctest_code.wrapper.is_none());
|
||||
}
|
||||
|
||||
// Test that `ExtractedDocTest::doctest_code` is `None` if the doctest has syntax error.
|
||||
#[test]
|
||||
fn test_extracted_doctest_doctest_code_field() {
|
||||
let extractor = get_extracted_doctests("let x +=");
|
||||
|
||||
assert_eq!(extractor.doctests().len(), 1);
|
||||
assert!(extractor.doctests()[0].doctest_code.is_none());
|
||||
}
|
||||
|
||||
// Test that `extracted::DocTest::wrapper` is `Some` if the doctest needs wrapping.
|
||||
#[test]
|
||||
fn test_extracted_doctest_wrapper_field_with_info() {
|
||||
let extractor = get_extracted_doctests("let x = 12;");
|
||||
|
||||
assert_eq!(extractor.doctests().len(), 1);
|
||||
let doctest_code = extractor.doctests()[0].doctest_code.as_ref().unwrap();
|
||||
assert!(doctest_code.wrapper.is_some());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -307,7 +307,8 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
|
|||
builder = builder.crate_name(krate);
|
||||
}
|
||||
let doctest = builder.build(None);
|
||||
let (test, _) = doctest.generate_unique_doctest(&test, false, &opts, krate);
|
||||
let (wrapped, _) = doctest.generate_unique_doctest(&test, false, &opts, krate);
|
||||
let test = wrapped.to_string();
|
||||
let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" };
|
||||
|
||||
let test_escaped = small_url_encode(test);
|
||||
|
|
|
|||
11
tests/rustdoc-ui/extract-doctests-result.rs
Normal file
11
tests/rustdoc-ui/extract-doctests-result.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// Test to ensure that it generates expected output for `--output-format=doctest` command-line
|
||||
// flag.
|
||||
|
||||
//@ compile-flags:-Z unstable-options --output-format=doctest
|
||||
//@ normalize-stdout: "tests/rustdoc-ui" -> "$$DIR"
|
||||
//@ check-pass
|
||||
|
||||
//! ```
|
||||
//! let x = 12;
|
||||
//! Ok(())
|
||||
//! ```
|
||||
1
tests/rustdoc-ui/extract-doctests-result.stdout
Normal file
1
tests/rustdoc-ui/extract-doctests-result.stdout
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"format_version":2,"doctests":[{"file":"$DIR/extract-doctests-result.rs","line":8,"doctest_attributes":{"original":"","should_panic":false,"no_run":false,"ignore":"None","rust":true,"test_harness":false,"compile_fail":false,"standalone_crate":false,"error_codes":[],"edition":null,"added_css_classes":[],"unknown":[]},"original_code":"let x = 12;\nOk(())","doctest_code":{"crate_level":"#![allow(unused)]\n","code":"let x = 12;\nOk(())","wrapper":{"before":"fn main() { fn _inner() -> core::result::Result<(), impl core::fmt::Debug> {\n","after":"\n} _inner().unwrap() }","returns_result":true}},"name":"$DIR/extract-doctests-result.rs - (line 8)"}]}
|
||||
|
|
@ -1 +1 @@
|
|||
{"format_version":1,"doctests":[{"file":"$DIR/extract-doctests.rs","line":8,"doctest_attributes":{"original":"ignore (checking attributes)","should_panic":false,"no_run":false,"ignore":"All","rust":true,"test_harness":false,"compile_fail":false,"standalone_crate":false,"error_codes":[],"edition":null,"added_css_classes":[],"unknown":[]},"original_code":"let x = 12;\nlet y = 14;","doctest_code":"#![allow(unused)]\nfn main() {\nlet x = 12;\nlet y = 14;\n}","name":"$DIR/extract-doctests.rs - (line 8)"},{"file":"$DIR/extract-doctests.rs","line":13,"doctest_attributes":{"original":"edition2018,compile_fail","should_panic":false,"no_run":true,"ignore":"None","rust":true,"test_harness":false,"compile_fail":true,"standalone_crate":false,"error_codes":[],"edition":"2018","added_css_classes":[],"unknown":[]},"original_code":"let","doctest_code":null,"name":"$DIR/extract-doctests.rs - (line 13)"}]}
|
||||
{"format_version":2,"doctests":[{"file":"$DIR/extract-doctests.rs","line":8,"doctest_attributes":{"original":"ignore (checking attributes)","should_panic":false,"no_run":false,"ignore":"All","rust":true,"test_harness":false,"compile_fail":false,"standalone_crate":false,"error_codes":[],"edition":null,"added_css_classes":[],"unknown":[]},"original_code":"let x = 12;\nlet y = 14;","doctest_code":{"crate_level":"#![allow(unused)]\n","code":"let x = 12;\nlet y = 14;","wrapper":{"before":"fn main() {\n","after":"\n}","returns_result":false}},"name":"$DIR/extract-doctests.rs - (line 8)"},{"file":"$DIR/extract-doctests.rs","line":13,"doctest_attributes":{"original":"edition2018,compile_fail","should_panic":false,"no_run":true,"ignore":"None","rust":true,"test_harness":false,"compile_fail":true,"standalone_crate":false,"error_codes":[],"edition":"2018","added_css_classes":[],"unknown":[]},"original_code":"let","doctest_code":null,"name":"$DIR/extract-doctests.rs - (line 13)"}]}
|
||||
Loading…
Add table
Add a link
Reference in a new issue