Skip to content

Commit 9ce3510

Browse files
committed
callback
1 parent 8c58416 commit 9ce3510

2 files changed

Lines changed: 38 additions & 28 deletions

File tree

crates/mdtest/src/parser.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,16 @@ use serde::Deserialize;
2121
pub trait MdtestConfig: Clone + Default + for<'de> Deserialize<'de> {}
2222

2323
/// Parse the Markdown `source` as a test suite with given `title`.
24+
///
25+
/// `validate_config` is invoked once for every literally-declared `toml` config block
26+
/// (after deserialization, before it replaces the section's inherited config) so callers
27+
/// can enforce invariants that mdtest itself shouldn't know about.
2428
pub fn parse<'s, C: MdtestConfig>(
2529
title: &'s str,
2630
source: &'s str,
31+
validate_config: impl FnMut(&C) -> anyhow::Result<()>,
2732
) -> anyhow::Result<MarkdownTestSuite<'s, C>> {
28-
let parser = Parser::new(title, source);
33+
let parser = Parser::new(title, source, validate_config);
2934
parser.parse()
3035
}
3136

@@ -480,8 +485,7 @@ impl SectionStack {
480485
}
481486

482487
/// Parse the source of a Markdown file into a [`MarkdownTestSuite`].
483-
#[derive(Debug)]
484-
struct Parser<'s, C> {
488+
struct Parser<'s, C, F> {
485489
/// [`Section`]s of the final [`MarkdownTestSuite`].
486490
sections: IndexVec<SectionId, Section<'s, C>>,
487491

@@ -507,10 +511,13 @@ struct Parser<'s, C> {
507511

508512
/// Whether or not the current section has a config block.
509513
current_section_has_config: bool,
514+
515+
/// Callback to validate config blocks
516+
validate_config: F,
510517
}
511518

512-
impl<'s, C: MdtestConfig> Parser<'s, C> {
513-
fn new(title: &'s str, source: &'s str) -> Self {
519+
impl<'s, C: MdtestConfig, F: FnMut(&C) -> anyhow::Result<()>> Parser<'s, C, F> {
520+
fn new(title: &'s str, source: &'s str, validate_config: F) -> Self {
514521
let mut sections = IndexVec::default();
515522
let root_section_id = sections.push(Section {
516523
title,
@@ -529,6 +536,7 @@ impl<'s, C: MdtestConfig> Parser<'s, C> {
529536
stack: SectionStack::new(root_section_id),
530537
current_section_files: IndexMap::default(),
531538
current_section_has_config: false,
539+
validate_config,
532540
}
533541
}
534542

@@ -912,6 +920,8 @@ impl<'s, C: MdtestConfig> Parser<'s, C> {
912920

913921
let config: C = toml::from_str(code).context("Error while parsing Markdown TOML config")?;
914922

923+
(self.validate_config)(&config)?;
924+
915925
let current_section = &mut self.sections[self.stack.top()];
916926
current_section.config = config;
917927

@@ -1107,7 +1117,7 @@ mod tests {
11071117
title: &'s str,
11081118
source: &'s str,
11091119
) -> anyhow::Result<super::MarkdownTestSuite<'s, TestConfig>> {
1110-
super::parse::<TestConfig>(title, source)
1120+
super::parse::<TestConfig>(title, source, |_| Ok(()))
11111121
}
11121122

11131123
#[test]

crates/ty_test/src/lib.rs

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -49,23 +49,8 @@ pub fn run(
4949
) -> anyhow::Result<()> {
5050
let output_format = output_format();
5151

52-
let suite = parser::parse::<MarkdownTestConfig>(short_title, source)
53-
.map_err(|err| anyhow!("Failed to parse fixture: {err}"))?;
54-
55-
// Whether or not any section in the file has external dependencies.
56-
// Only one section per file is allowed to have dependencies (for lockfile support).
57-
let mut file_has_dependencies = false;
58-
for test in suite.tests() {
59-
if test.configuration().dependencies().is_some() {
60-
if file_has_dependencies {
61-
bail!(
62-
"Multiple sections with `[project]` dependencies in the same file are not allowed. \
63-
External dependencies must be specified in a single top-level configuration block."
64-
);
65-
}
66-
file_has_dependencies = true;
67-
}
68-
}
52+
let suite =
53+
parse(short_title, source).map_err(|err| anyhow!("Failed to parse fixture: {err}"))?;
6954

7055
let mut db = Db::setup();
7156
let mut markdown_edits = vec![];
@@ -792,13 +777,29 @@ impl AttemptTestError<'_> {
792777
}
793778
}
794779

780+
fn parse<'s>(
781+
short_title: &'s str,
782+
source: &'s str,
783+
) -> anyhow::Result<parser::MarkdownTestSuite<'s, MarkdownTestConfig>> {
784+
let mut file_has_dependencies = false;
785+
parser::parse::<MarkdownTestConfig>(short_title, source, |config| {
786+
if config.dependencies().is_some() {
787+
if file_has_dependencies {
788+
bail!(
789+
"Multiple sections with `[project]` dependencies in the same file are not allowed. \
790+
External dependencies must be specified in a single top-level configuration block."
791+
);
792+
}
793+
file_has_dependencies = true;
794+
}
795+
Ok(())
796+
})
797+
}
798+
795799
#[cfg(test)]
796800
mod tests {
797-
use mdtest::parser::parse;
798801
use ruff_python_trivia::textwrap::dedent;
799802

800-
use crate::config::MarkdownTestConfig;
801-
802803
#[test]
803804
fn multiple_sections_with_dependencies_not_allowed() {
804805
let source = dedent(
@@ -826,8 +827,7 @@ mod tests {
826827
```
827828
"#,
828829
);
829-
let err =
830-
parse::<MarkdownTestConfig>("file.md", &source).expect_err("Should fail to parse");
830+
let err = super::parse("file.md", &source).expect_err("Should fail to parse");
831831
assert_eq!(
832832
err.to_string(),
833833
"Multiple sections with `[project]` dependencies in the same file are not allowed. \

0 commit comments

Comments
 (0)