#[cfg(test)]
#[derive(Debug)]
pub struct PatternTestCase {
pub input: &'static str,
pub expected: bool,
pub description: &'static str,
}
#[cfg(test)]
#[derive(Debug)]
pub struct PositionTestCase {
pub content: &'static str,
pub test_positions: Vec<(&'static str, bool)>, pub description: &'static str,
}
#[cfg(test)]
#[derive(Debug)]
pub struct IndentTestCase {
pub input: &'static str,
pub expected: Option<usize>,
pub description: &'static str,
}
#[cfg(test)]
pub fn run_pattern_tests<F>(test_fn: F, cases: &[PatternTestCase])
where
F: Fn(&str) -> bool,
{
for case in cases {
assert_eq!(
test_fn(case.input),
case.expected,
"Failed: {} - Input: {:?}",
case.description,
case.input
);
}
}
#[cfg(test)]
pub fn run_position_tests<F>(test_fn: F, cases: &[PositionTestCase])
where
F: Fn(&str, usize) -> bool,
{
for case in cases {
for (substring, expected) in &case.test_positions {
let pos = case.content.find(substring).unwrap_or_else(|| {
panic!(
"Substring '{}' not found in content for test: {}",
substring, case.description
)
});
assert_eq!(
test_fn(case.content, pos),
*expected,
"Failed: {} - Position test for substring '{}' at position {}",
case.description,
substring,
pos
);
}
}
}
#[cfg(test)]
pub fn run_indent_tests<F>(test_fn: F, cases: &[IndentTestCase])
where
F: Fn(&str) -> Option<usize>,
{
for case in cases {
assert_eq!(
test_fn(case.input),
case.expected,
"Failed: {} - Input: {:?}",
case.description,
case.input
);
}
}
#[cfg(test)]
pub fn create_mkdocs_test_document() -> String {
r#"# Test Document
Regular paragraph text.
!!! note "Test Note"
This is an admonition with content.
Multiple lines of content.
[^1]: This is a footnote definition
with multiple lines
of content.
=== "Tab 1"
Content in tab 1.
More content.
=== "Tab 2"
Content in tab 2.
::: mymodule.MyClass
handler: python
options:
show_source: true
--8<-- "included.md"
Regular text with [^1] footnote reference.
<!-- --8<-- [start:section] -->
Section content
<!-- --8<-- [end:section] -->
Final paragraph."#
.to_string()
}
#[cfg(test)]
pub fn assert_positions<F>(content: &str, test_fn: F, positions: &[(&str, bool)])
where
F: Fn(&str, usize) -> bool,
{
for (substring, expected) in positions {
if let Some(pos) = content.find(substring) {
let actual = test_fn(content, pos);
assert_eq!(
actual, *expected,
"Position test failed for '{substring}' at position {pos}. Expected: {expected}, Got: {actual}"
);
} else {
panic!("Substring '{substring}' not found in content");
}
}
}
#[cfg(test)]
pub struct TestContentBuilder {
lines: Vec<String>,
}
#[cfg(test)]
impl TestContentBuilder {
pub fn new() -> Self {
Self { lines: Vec::new() }
}
pub fn add_line(mut self, line: &str) -> Self {
self.lines.push(line.to_string());
self
}
pub fn add_empty_line(mut self) -> Self {
self.lines.push(String::new());
self
}
pub fn add_indented(mut self, indent: usize, content: &str) -> Self {
self.lines.push(format!("{}{}", " ".repeat(indent), content));
self
}
pub fn add_admonition(mut self, admon_type: &str, title: Option<&str>) -> Self {
let line = if let Some(t) = title {
format!("!!! {admon_type} \"{t}\"")
} else {
format!("!!! {admon_type}")
};
self.lines.push(line);
self
}
pub fn add_footnote_def(mut self, ref_name: &str, content: &str) -> Self {
self.lines.push(format!("[^{ref_name}]: {content}"));
self
}
pub fn add_tab(mut self, label: &str) -> Self {
self.lines.push(format!("=== \"{label}\""));
self
}
pub fn add_snippet(mut self, file: &str) -> Self {
self.lines.push(format!("--8<-- \"{file}\""));
self
}
pub fn build(self) -> String {
self.lines.join("\n")
}
}
#[cfg(test)]
impl Default for TestContentBuilder {
fn default() -> Self {
Self::new()
}
}