1use rustc_span::edition::Edition;
7use serde::Serialize;
8
9use super::make::DocTestWrapResult;
10use super::{BuildDocTestBuilder, ScrapedDocTest};
11use crate::config::Options as RustdocOptions;
12use crate::html::markdown;
13
14const FORMAT_VERSION: u32 = 2;
20
21#[derive(Serialize)]
22pub(crate) struct ExtractedDocTests {
23 format_version: u32,
24 doctests: Vec<ExtractedDocTest>,
25}
26
27impl ExtractedDocTests {
28 pub(crate) fn new() -> Self {
29 Self { format_version: FORMAT_VERSION, doctests: Vec::new() }
30 }
31
32 pub(crate) fn add_test(
33 &mut self,
34 scraped_test: ScrapedDocTest,
35 opts: &super::GlobalTestOptions,
36 options: &RustdocOptions,
37 ) {
38 let edition = scraped_test.edition(options);
39 self.add_test_with_edition(scraped_test, opts, edition)
40 }
41
42 pub(crate) fn add_test_with_edition(
44 &mut self,
45 scraped_test: ScrapedDocTest,
46 opts: &super::GlobalTestOptions,
47 edition: Edition,
48 ) {
49 let ScrapedDocTest { filename, line, langstr, text, name, global_crate_attrs, .. } =
50 scraped_test;
51
52 let doctest = BuildDocTestBuilder::new(&text)
53 .crate_name(&opts.crate_name)
54 .global_crate_attrs(global_crate_attrs)
55 .edition(edition)
56 .lang_str(&langstr)
57 .build(None);
58 let (wrapped, _size) = doctest.generate_unique_doctest(
59 &text,
60 langstr.test_harness,
61 opts,
62 Some(&opts.crate_name),
63 );
64 self.doctests.push(ExtractedDocTest {
65 file: filename.prefer_remapped_unconditionaly().to_string(),
66 line,
67 doctest_attributes: langstr.into(),
68 doctest_code: match wrapped {
69 DocTestWrapResult::Valid { crate_level_code, wrapper, code } => Some(DocTest {
70 crate_level: crate_level_code,
71 code,
72 wrapper: wrapper.map(
73 |super::make::WrapperInfo { before, after, returns_result, .. }| {
74 WrapperInfo { before, after, returns_result }
75 },
76 ),
77 }),
78 DocTestWrapResult::SyntaxError { .. } => None,
79 },
80 original_code: text,
81 name,
82 });
83 }
84
85 #[cfg(test)]
86 pub(crate) fn doctests(&self) -> &[ExtractedDocTest] {
87 &self.doctests
88 }
89}
90
91#[derive(Serialize)]
92pub(crate) struct WrapperInfo {
93 before: String,
94 after: String,
95 returns_result: bool,
96}
97
98#[derive(Serialize)]
99pub(crate) struct DocTest {
100 crate_level: String,
101 code: String,
102 pub(crate) wrapper: Option<WrapperInfo>,
108}
109
110#[derive(Serialize)]
111pub(crate) struct ExtractedDocTest {
112 file: String,
113 line: usize,
114 doctest_attributes: LangString,
115 original_code: String,
116 pub(crate) doctest_code: Option<DocTest>,
118 name: String,
119}
120
121#[derive(Serialize)]
122pub(crate) enum Ignore {
123 All,
124 None,
125 Some(Vec<String>),
126}
127
128impl From<markdown::Ignore> for Ignore {
129 fn from(original: markdown::Ignore) -> Self {
130 match original {
131 markdown::Ignore::All => Self::All,
132 markdown::Ignore::None => Self::None,
133 markdown::Ignore::Some(values) => Self::Some(values),
134 }
135 }
136}
137
138#[derive(Serialize)]
139struct LangString {
140 pub(crate) original: String,
141 pub(crate) should_panic: bool,
142 pub(crate) no_run: bool,
143 pub(crate) ignore: Ignore,
144 pub(crate) rust: bool,
145 pub(crate) test_harness: bool,
146 pub(crate) compile_fail: bool,
147 pub(crate) standalone_crate: bool,
148 pub(crate) error_codes: Vec<String>,
149 pub(crate) edition: Option<String>,
150 pub(crate) added_css_classes: Vec<String>,
151 pub(crate) unknown: Vec<String>,
152}
153
154impl From<markdown::LangString> for LangString {
155 fn from(original: markdown::LangString) -> Self {
156 let markdown::LangString {
157 original,
158 should_panic,
159 no_run,
160 ignore,
161 rust,
162 test_harness,
163 compile_fail,
164 standalone_crate,
165 error_codes,
166 edition,
167 added_classes,
168 unknown,
169 } = original;
170
171 Self {
172 original,
173 should_panic,
174 no_run,
175 ignore: ignore.into(),
176 rust,
177 test_harness,
178 compile_fail,
179 standalone_crate,
180 error_codes,
181 edition: edition.map(|edition| edition.to_string()),
182 added_css_classes: added_classes,
183 unknown,
184 }
185 }
186}