mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 02:12:22 +00:00
Use insta::glob
instead of fixture
macro (#5364)
This commit is contained in:
parent
dce6a046b0
commit
8879927b9a
82 changed files with 285 additions and 765 deletions
|
@ -6,7 +6,7 @@ exclude: |
|
||||||
crates/ruff/src/rules/.*/snapshots/.*|
|
crates/ruff/src/rules/.*/snapshots/.*|
|
||||||
crates/ruff_cli/resources/.*|
|
crates/ruff_cli/resources/.*|
|
||||||
crates/ruff_python_formatter/resources/.*|
|
crates/ruff_python_formatter/resources/.*|
|
||||||
crates/ruff_python_formatter/src/snapshots/.*
|
crates/ruff_python_formatter/tests/snapshots/.*
|
||||||
)$
|
)$
|
||||||
|
|
||||||
repos:
|
repos:
|
||||||
|
|
13
Cargo.lock
generated
13
Cargo.lock
generated
|
@ -988,9 +988,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28491f7753051e5704d4d0ae7860d45fae3238d7d235bc4289dcd45c48d3cec3"
|
checksum = "28491f7753051e5704d4d0ae7860d45fae3238d7d235bc4289dcd45c48d3cec3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console",
|
"console",
|
||||||
|
"globset",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"linked-hash-map",
|
"linked-hash-map",
|
||||||
"similar",
|
"similar",
|
||||||
|
"walkdir",
|
||||||
"yaml-rust",
|
"yaml-rust",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2060,7 +2062,6 @@ dependencies = [
|
||||||
"ruff_formatter",
|
"ruff_formatter",
|
||||||
"ruff_python_ast",
|
"ruff_python_ast",
|
||||||
"ruff_python_whitespace",
|
"ruff_python_whitespace",
|
||||||
"ruff_testing_macros",
|
|
||||||
"ruff_text_size",
|
"ruff_text_size",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"rustpython-parser",
|
"rustpython-parser",
|
||||||
|
@ -2105,16 +2106,6 @@ dependencies = [
|
||||||
"rustpython-parser",
|
"rustpython-parser",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ruff_testing_macros"
|
|
||||||
version = "0.0.0"
|
|
||||||
dependencies = [
|
|
||||||
"glob",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.22",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff_text_size"
|
name = "ruff_text_size"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
|
|
@ -21,7 +21,7 @@ filetime = { version = "0.2.20" }
|
||||||
glob = { version = "0.3.1" }
|
glob = { version = "0.3.1" }
|
||||||
globset = { version = "0.4.10" }
|
globset = { version = "0.4.10" }
|
||||||
ignore = { version = "0.4.20" }
|
ignore = { version = "0.4.20" }
|
||||||
insta = { version = "1.28.0" }
|
insta = { version = "1.30.0" }
|
||||||
is-macro = { version = "0.2.2" }
|
is-macro = { version = "0.2.2" }
|
||||||
itertools = { version = "0.10.5" }
|
itertools = { version = "0.10.5" }
|
||||||
log = { version = "0.4.17" }
|
log = { version = "0.4.17" }
|
||||||
|
|
|
@ -27,8 +27,6 @@ rustc-hash = { workspace = true }
|
||||||
rustpython-parser = { workspace = true }
|
rustpython-parser = { workspace = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
ruff_testing_macros = { path = "../ruff_testing_macros" }
|
insta = { workspace = true, features = ["glob"] }
|
||||||
|
|
||||||
insta = { workspace = true, features = [] }
|
|
||||||
test-case = { workspace = true }
|
test-case = { workspace = true }
|
||||||
similar = { workspace = true }
|
similar = { workspace = true }
|
||||||
|
|
|
@ -263,18 +263,12 @@ impl TryFrom<char> for QuoteStyle {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::{format_module, format_node};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use insta::assert_snapshot;
|
use insta::assert_snapshot;
|
||||||
use ruff_python_ast::source_code::CommentRangesBuilder;
|
use ruff_python_ast::source_code::CommentRangesBuilder;
|
||||||
use ruff_testing_macros::fixture;
|
|
||||||
use rustpython_parser::lexer::lex;
|
use rustpython_parser::lexer::lex;
|
||||||
use rustpython_parser::{parse_tokens, Mode};
|
use rustpython_parser::{parse_tokens, Mode};
|
||||||
use similar::TextDiff;
|
|
||||||
use std::fmt::{Formatter, Write};
|
|
||||||
use std::fs;
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use crate::{format_module, format_node};
|
|
||||||
|
|
||||||
/// Very basic test intentionally kept very similar to the CLI
|
/// Very basic test intentionally kept very similar to the CLI
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -295,138 +289,6 @@ if True:
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixture(pattern = "resources/test/fixtures/black/**/*.py")]
|
|
||||||
#[test]
|
|
||||||
fn black_test(input_path: &Path) -> Result<()> {
|
|
||||||
let content = fs::read_to_string(input_path)?;
|
|
||||||
|
|
||||||
let printed = format_module(&content)?;
|
|
||||||
|
|
||||||
let expected_path = input_path.with_extension("py.expect");
|
|
||||||
let expected_output = fs::read_to_string(&expected_path)
|
|
||||||
.unwrap_or_else(|_| panic!("Expected Black output file '{expected_path:?}' to exist"));
|
|
||||||
|
|
||||||
let formatted_code = printed.as_code();
|
|
||||||
|
|
||||||
ensure_stability_when_formatting_twice(formatted_code);
|
|
||||||
|
|
||||||
if formatted_code == expected_output {
|
|
||||||
// Black and Ruff formatting matches. Delete any existing snapshot files because the Black output
|
|
||||||
// already perfectly captures the expected output.
|
|
||||||
// The following code mimics insta's logic generating the snapshot name for a test.
|
|
||||||
let workspace_path = std::env::var("CARGO_MANIFEST_DIR").unwrap();
|
|
||||||
let snapshot_name = insta::_function_name!()
|
|
||||||
.strip_prefix(&format!("{}::", module_path!()))
|
|
||||||
.unwrap();
|
|
||||||
let module_path = module_path!().replace("::", "__");
|
|
||||||
|
|
||||||
let snapshot_path = Path::new(&workspace_path)
|
|
||||||
.join("src/snapshots")
|
|
||||||
.join(format!(
|
|
||||||
"{module_path}__{}.snap",
|
|
||||||
snapshot_name.replace(&['/', '\\'][..], "__")
|
|
||||||
));
|
|
||||||
|
|
||||||
if snapshot_path.exists() && snapshot_path.is_file() {
|
|
||||||
// SAFETY: This is a convenience feature. That's why we don't want to abort
|
|
||||||
// when deleting a no longer needed snapshot fails.
|
|
||||||
fs::remove_file(&snapshot_path).ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_snapshot_path = snapshot_path.with_extension("snap.new");
|
|
||||||
if new_snapshot_path.exists() && new_snapshot_path.is_file() {
|
|
||||||
// SAFETY: This is a convenience feature. That's why we don't want to abort
|
|
||||||
// when deleting a no longer needed snapshot fails.
|
|
||||||
fs::remove_file(&new_snapshot_path).ok();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Black and Ruff have different formatting. Write out a snapshot that covers the differences
|
|
||||||
// today.
|
|
||||||
let mut snapshot = String::new();
|
|
||||||
write!(snapshot, "{}", Header::new("Input"))?;
|
|
||||||
write!(snapshot, "{}", CodeFrame::new("py", &content))?;
|
|
||||||
|
|
||||||
write!(snapshot, "{}", Header::new("Black Differences"))?;
|
|
||||||
|
|
||||||
let diff = TextDiff::from_lines(expected_output.as_str(), formatted_code)
|
|
||||||
.unified_diff()
|
|
||||||
.header("Black", "Ruff")
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
write!(snapshot, "{}", CodeFrame::new("diff", &diff))?;
|
|
||||||
|
|
||||||
write!(snapshot, "{}", Header::new("Ruff Output"))?;
|
|
||||||
write!(snapshot, "{}", CodeFrame::new("py", formatted_code))?;
|
|
||||||
|
|
||||||
write!(snapshot, "{}", Header::new("Black Output"))?;
|
|
||||||
write!(snapshot, "{}", CodeFrame::new("py", &expected_output))?;
|
|
||||||
|
|
||||||
insta::with_settings!({ omit_expression => false, input_file => input_path }, {
|
|
||||||
insta::assert_snapshot!(snapshot);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[fixture(pattern = "resources/test/fixtures/ruff/**/*.py")]
|
|
||||||
#[test]
|
|
||||||
fn ruff_test(input_path: &Path) -> Result<()> {
|
|
||||||
let content = fs::read_to_string(input_path)?;
|
|
||||||
|
|
||||||
let printed = format_module(&content)?;
|
|
||||||
let formatted_code = printed.as_code();
|
|
||||||
|
|
||||||
ensure_stability_when_formatting_twice(formatted_code);
|
|
||||||
|
|
||||||
let snapshot = format!(
|
|
||||||
r#"## Input
|
|
||||||
{}
|
|
||||||
|
|
||||||
## Output
|
|
||||||
{}"#,
|
|
||||||
CodeFrame::new("py", &content),
|
|
||||||
CodeFrame::new("py", formatted_code)
|
|
||||||
);
|
|
||||||
assert_snapshot!(snapshot);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Format another time and make sure that there are no changes anymore
|
|
||||||
fn ensure_stability_when_formatting_twice(formatted_code: &str) {
|
|
||||||
let reformatted = match format_module(formatted_code) {
|
|
||||||
Ok(reformatted) => reformatted,
|
|
||||||
Err(err) => {
|
|
||||||
panic!(
|
|
||||||
"Expected formatted code to be valid syntax: {err}:\
|
|
||||||
\n---\n{formatted_code}---\n",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if reformatted.as_code() != formatted_code {
|
|
||||||
let diff = TextDiff::from_lines(formatted_code, reformatted.as_code())
|
|
||||||
.unified_diff()
|
|
||||||
.header("Formatted once", "Formatted twice")
|
|
||||||
.to_string();
|
|
||||||
panic!(
|
|
||||||
r#"Reformatting the formatted code a second time resulted in formatting changes.
|
|
||||||
---
|
|
||||||
{diff}---
|
|
||||||
|
|
||||||
Formatted once:
|
|
||||||
---
|
|
||||||
{formatted_code}---
|
|
||||||
|
|
||||||
Formatted twice:
|
|
||||||
---
|
|
||||||
{}---"#,
|
|
||||||
reformatted.as_code()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Use this test to debug the formatting of some snipped
|
/// Use this test to debug the formatting of some snipped
|
||||||
#[ignore]
|
#[ignore]
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -549,41 +411,4 @@ if [
|
||||||
|
|
||||||
assert_snapshot!(output.print().expect("Printing to succeed").as_code());
|
assert_snapshot!(output.print().expect("Printing to succeed").as_code());
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Header<'a> {
|
|
||||||
title: &'a str,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Header<'a> {
|
|
||||||
fn new(title: &'a str) -> Self {
|
|
||||||
Self { title }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Header<'_> {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
writeln!(f, "## {}", self.title)?;
|
|
||||||
writeln!(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CodeFrame<'a> {
|
|
||||||
language: &'a str,
|
|
||||||
code: &'a str,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CodeFrame<'a> {
|
|
||||||
fn new(language: &'a str, code: &'a str) -> Self {
|
|
||||||
Self { language, code }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for CodeFrame<'_> {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
writeln!(f, "```{}", self.language)?;
|
|
||||||
write!(f, "{}", self.code)?;
|
|
||||||
writeln!(f, "```")?;
|
|
||||||
writeln!(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
187
crates/ruff_python_formatter/tests/fixtures.rs
Normal file
187
crates/ruff_python_formatter/tests/fixtures.rs
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
use ruff_python_formatter::format_module;
|
||||||
|
use similar::TextDiff;
|
||||||
|
use std::fmt::{Formatter, Write};
|
||||||
|
use std::fs;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn black_compatibility() {
|
||||||
|
let test_file = |input_path: &Path| {
|
||||||
|
let content = fs::read_to_string(input_path).unwrap();
|
||||||
|
|
||||||
|
let printed = format_module(&content).expect("Formatting to succeed");
|
||||||
|
|
||||||
|
let expected_path = input_path.with_extension("py.expect");
|
||||||
|
let expected_output = fs::read_to_string(&expected_path)
|
||||||
|
.unwrap_or_else(|_| panic!("Expected Black output file '{expected_path:?}' to exist"));
|
||||||
|
|
||||||
|
let formatted_code = printed.as_code();
|
||||||
|
|
||||||
|
ensure_stability_when_formatting_twice(formatted_code);
|
||||||
|
|
||||||
|
if formatted_code == expected_output {
|
||||||
|
// Black and Ruff formatting matches. Delete any existing snapshot files because the Black output
|
||||||
|
// already perfectly captures the expected output.
|
||||||
|
// The following code mimics insta's logic generating the snapshot name for a test.
|
||||||
|
let workspace_path = std::env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||||
|
let snapshot_name = insta::_function_name!()
|
||||||
|
.strip_prefix(&format!("{}::", module_path!()))
|
||||||
|
.unwrap();
|
||||||
|
let module_path = module_path!().replace("::", "__");
|
||||||
|
|
||||||
|
let snapshot_path = Path::new(&workspace_path)
|
||||||
|
.join("src/snapshots")
|
||||||
|
.join(format!(
|
||||||
|
"{module_path}__{}.snap",
|
||||||
|
snapshot_name.replace(&['/', '\\'][..], "__")
|
||||||
|
));
|
||||||
|
|
||||||
|
if snapshot_path.exists() && snapshot_path.is_file() {
|
||||||
|
// SAFETY: This is a convenience feature. That's why we don't want to abort
|
||||||
|
// when deleting a no longer needed snapshot fails.
|
||||||
|
fs::remove_file(&snapshot_path).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_snapshot_path = snapshot_path.with_extension("snap.new");
|
||||||
|
if new_snapshot_path.exists() && new_snapshot_path.is_file() {
|
||||||
|
// SAFETY: This is a convenience feature. That's why we don't want to abort
|
||||||
|
// when deleting a no longer needed snapshot fails.
|
||||||
|
fs::remove_file(&new_snapshot_path).ok();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Black and Ruff have different formatting. Write out a snapshot that covers the differences
|
||||||
|
// today.
|
||||||
|
let mut snapshot = String::new();
|
||||||
|
write!(snapshot, "{}", Header::new("Input")).unwrap();
|
||||||
|
write!(snapshot, "{}", CodeFrame::new("py", &content)).unwrap();
|
||||||
|
|
||||||
|
write!(snapshot, "{}", Header::new("Black Differences")).unwrap();
|
||||||
|
|
||||||
|
let diff = TextDiff::from_lines(expected_output.as_str(), formatted_code)
|
||||||
|
.unified_diff()
|
||||||
|
.header("Black", "Ruff")
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
write!(snapshot, "{}", CodeFrame::new("diff", &diff)).unwrap();
|
||||||
|
|
||||||
|
write!(snapshot, "{}", Header::new("Ruff Output")).unwrap();
|
||||||
|
write!(snapshot, "{}", CodeFrame::new("py", formatted_code)).unwrap();
|
||||||
|
|
||||||
|
write!(snapshot, "{}", Header::new("Black Output")).unwrap();
|
||||||
|
write!(snapshot, "{}", CodeFrame::new("py", &expected_output)).unwrap();
|
||||||
|
|
||||||
|
insta::with_settings!({
|
||||||
|
omit_expression => true,
|
||||||
|
input_file => input_path,
|
||||||
|
prepend_module_to_snapshot => false,
|
||||||
|
}, {
|
||||||
|
insta::assert_snapshot!(snapshot);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
insta::glob!("../resources", "test/fixtures/black/**/*.py", test_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn format() {
|
||||||
|
let test_file = |input_path: &Path| {
|
||||||
|
let content = fs::read_to_string(input_path).unwrap();
|
||||||
|
|
||||||
|
let printed = format_module(&content).expect("Formatting to succeed");
|
||||||
|
let formatted_code = printed.as_code();
|
||||||
|
|
||||||
|
ensure_stability_when_formatting_twice(formatted_code);
|
||||||
|
|
||||||
|
let snapshot = format!(
|
||||||
|
r#"## Input
|
||||||
|
{}
|
||||||
|
|
||||||
|
## Output
|
||||||
|
{}"#,
|
||||||
|
CodeFrame::new("py", &content),
|
||||||
|
CodeFrame::new("py", formatted_code)
|
||||||
|
);
|
||||||
|
|
||||||
|
insta::with_settings!({
|
||||||
|
omit_expression => true,
|
||||||
|
input_file => input_path,
|
||||||
|
prepend_module_to_snapshot => false,
|
||||||
|
}, {
|
||||||
|
insta::assert_snapshot!(snapshot);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
insta::glob!("../resources", "test/fixtures/ruff/**/*.py", test_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Format another time and make sure that there are no changes anymore
|
||||||
|
fn ensure_stability_when_formatting_twice(formatted_code: &str) {
|
||||||
|
let reformatted = match format_module(formatted_code) {
|
||||||
|
Ok(reformatted) => reformatted,
|
||||||
|
Err(err) => {
|
||||||
|
panic!(
|
||||||
|
"Expected formatted code to be valid syntax: {err}:\
|
||||||
|
\n---\n{formatted_code}---\n",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if reformatted.as_code() != formatted_code {
|
||||||
|
let diff = TextDiff::from_lines(formatted_code, reformatted.as_code())
|
||||||
|
.unified_diff()
|
||||||
|
.header("Formatted once", "Formatted twice")
|
||||||
|
.to_string();
|
||||||
|
panic!(
|
||||||
|
r#"Reformatting the formatted code a second time resulted in formatting changes.
|
||||||
|
---
|
||||||
|
{diff}---
|
||||||
|
|
||||||
|
Formatted once:
|
||||||
|
---
|
||||||
|
{formatted_code}---
|
||||||
|
|
||||||
|
Formatted twice:
|
||||||
|
---
|
||||||
|
{}---"#,
|
||||||
|
reformatted.as_code()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Header<'a> {
|
||||||
|
title: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Header<'a> {
|
||||||
|
fn new(title: &'a str) -> Self {
|
||||||
|
Self { title }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Header<'_> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
writeln!(f, "## {}", self.title)?;
|
||||||
|
writeln!(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CodeFrame<'a> {
|
||||||
|
language: &'a str,
|
||||||
|
code: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CodeFrame<'a> {
|
||||||
|
fn new(language: &'a str, code: &'a str) -> Self {
|
||||||
|
Self { language, code }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for CodeFrame<'_> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
writeln!(f, "```{}", self.language)?;
|
||||||
|
write!(f, "{}", self.code)?;
|
||||||
|
writeln!(f, "```")?;
|
||||||
|
writeln!(f)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/attribute_access_on_number_literals.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/attribute_access_on_number_literals.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/beginning_backslash.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/beginning_backslash.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/bracketmatch.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/bracketmatch.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/class_methods_new_line.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/class_methods_new_line.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/collections.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/collections.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comment_after_escaped_newline.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comment_after_escaped_newline.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments2.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments2.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments3.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments3.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments4.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments4.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments5.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments5.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments6.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments6.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments9.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments9.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments_non_breaking_space.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments_non_breaking_space.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/composition.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/composition.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/composition_no_trailing_comma.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/composition_no_trailing_comma.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring_preview.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring_preview.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/empty_lines.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/empty_lines.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/expression.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/expression.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff2.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff2.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff3.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff3.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff4.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff4.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff5.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff5.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip2.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip2.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip3.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip3.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip4.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip4.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip5.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip5.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip6.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip6.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip7.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip7.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip8.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip8.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fstring.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fstring.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function2.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function2.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function_trailing_comma.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function_trailing_comma.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/import_spacing.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/import_spacing.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/one_element_subscript.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/one_element_subscript.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/power_op_spacing.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/power_op_spacing.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/prefer_rhs_split_reformatted.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/prefer_rhs_split_reformatted.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_await_parens.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_await_parens.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_except_parens.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_except_parens.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_for_brackets.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_for_brackets.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_newline_after_code_block_open.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_newline_after_code_block_open.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_parens.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_parens.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/return_annotation_brackets.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/return_annotation_brackets.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/skip_magic_trailing_comma.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/skip_magic_trailing_comma.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/slices.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/slices.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/string_prefixes.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/string_prefixes.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/torture.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/torture.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_comma_optional_parens1.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_comma_optional_parens1.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_comma_optional_parens2.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_comma_optional_parens2.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_comma_optional_parens3.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_comma_optional_parens3.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_commas_in_leading_parts.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_commas_in_leading_parts.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/tupleassign.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/tupleassign.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/attribute.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
||||||
```py
|
```py
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/binary.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
||||||
```py
|
```py
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/boolean_operation.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
||||||
```py
|
```py
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/compare.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
||||||
```py
|
```py
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/dict.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
||||||
```py
|
```py
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/list.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
||||||
```py
|
```py
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/slice.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
||||||
```py
|
```py
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/string.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
||||||
```py
|
```py
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/tuple.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
||||||
```py
|
```py
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/unary.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
||||||
```py
|
```py
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/assign.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
||||||
```py
|
```py
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/break.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
||||||
```py
|
```py
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/class_definition.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
||||||
```py
|
```py
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/for.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
||||||
```py
|
```py
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/function.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
||||||
```py
|
```py
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/if.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
||||||
```py
|
```py
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/while.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
||||||
```py
|
```py
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/src/lib.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
expression: snapshot
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/trivia.py
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
||||||
```py
|
```py
|
|
@ -1,22 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "ruff_testing_macros"
|
|
||||||
version = "0.0.0"
|
|
||||||
publish = false
|
|
||||||
authors = { workspace = true }
|
|
||||||
edition = { workspace = true }
|
|
||||||
rust-version = { workspace = true }
|
|
||||||
homepage = { workspace = true }
|
|
||||||
documentation = { workspace = true }
|
|
||||||
repository = { workspace = true }
|
|
||||||
license = { workspace = true }
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
proc-macro = true
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
glob = { workspace = true }
|
|
||||||
proc-macro2 = { workspace = true }
|
|
||||||
quote = { workspace = true }
|
|
||||||
syn = { workspace = true, features = ["extra-traits", "full"] }
|
|
|
@ -1,403 +0,0 @@
|
||||||
use proc_macro::TokenStream;
|
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use std::env;
|
|
||||||
use std::path::{Component, PathBuf};
|
|
||||||
|
|
||||||
use glob::{glob, Pattern};
|
|
||||||
use proc_macro2::Span;
|
|
||||||
use quote::{format_ident, quote};
|
|
||||||
use syn::parse::{Parse, ParseStream};
|
|
||||||
use syn::punctuated::Punctuated;
|
|
||||||
use syn::spanned::Spanned;
|
|
||||||
use syn::{bracketed, parse_macro_input, parse_quote, Error, FnArg, ItemFn, LitStr, Pat, Token};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct FixtureConfiguration {
|
|
||||||
pattern: Pattern,
|
|
||||||
pattern_span: Span,
|
|
||||||
exclude: Vec<Pattern>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Arg {
|
|
||||||
name: syn::Ident,
|
|
||||||
value: ArgValue,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for Arg {
|
|
||||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
|
||||||
let name = input.parse()?;
|
|
||||||
let _equal_token: Token![=] = input.parse()?;
|
|
||||||
let value = input.parse()?;
|
|
||||||
|
|
||||||
Ok(Self { name, value })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ArgValue {
|
|
||||||
LitStr(LitStr),
|
|
||||||
List(Punctuated<LitStr, Token![,]>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for ArgValue {
|
|
||||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
|
||||||
let value = if input.peek(syn::token::Bracket) {
|
|
||||||
let inner;
|
|
||||||
_ = bracketed!(inner in input);
|
|
||||||
|
|
||||||
let values = inner.parse_terminated(
|
|
||||||
|parser| {
|
|
||||||
let value: LitStr = parser.parse()?;
|
|
||||||
Ok(value)
|
|
||||||
},
|
|
||||||
Token![,],
|
|
||||||
)?;
|
|
||||||
ArgValue::List(values)
|
|
||||||
} else {
|
|
||||||
ArgValue::LitStr(input.parse()?)
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for FixtureConfiguration {
|
|
||||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
|
||||||
let args: Punctuated<_, Token![,]> = input.parse_terminated(Arg::parse, Token![,])?;
|
|
||||||
|
|
||||||
let mut pattern = None;
|
|
||||||
let mut exclude = None;
|
|
||||||
|
|
||||||
for arg in args {
|
|
||||||
match arg.name.to_string().as_str() {
|
|
||||||
"pattern" => match arg.value {
|
|
||||||
ArgValue::LitStr(value) => {
|
|
||||||
pattern = Some(try_parse_pattern(&value)?);
|
|
||||||
}
|
|
||||||
ArgValue::List(list) => {
|
|
||||||
return Err(Error::new(
|
|
||||||
list.span(),
|
|
||||||
"The pattern must be a string literal",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"exclude" => {
|
|
||||||
match arg.value {
|
|
||||||
ArgValue::LitStr(lit) => return Err(Error::new(
|
|
||||||
lit.span(),
|
|
||||||
"The exclude argument must be an array of globs: 'exclude=[\"a.py\"]",
|
|
||||||
)),
|
|
||||||
ArgValue::List(list) => {
|
|
||||||
let mut exclude_patterns = Vec::with_capacity(list.len());
|
|
||||||
|
|
||||||
for pattern in list {
|
|
||||||
let (pattern, _) = try_parse_pattern(&pattern)?;
|
|
||||||
exclude_patterns.push(pattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
exclude = Some(exclude_patterns);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {
|
|
||||||
return Err(Error::new(
|
|
||||||
arg.name.span(),
|
|
||||||
format!("Unknown argument {}.", arg.name),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let exclude = exclude.unwrap_or_default();
|
|
||||||
|
|
||||||
match pattern {
|
|
||||||
None => Err(Error::new(
|
|
||||||
input.span(),
|
|
||||||
"'fixture' macro must have a pattern attribute",
|
|
||||||
)),
|
|
||||||
Some((pattern, pattern_span)) => Ok(Self {
|
|
||||||
pattern,
|
|
||||||
pattern_span,
|
|
||||||
exclude,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_parse_pattern(pattern_lit: &LitStr) -> syn::Result<(Pattern, Span)> {
|
|
||||||
let raw_pattern = pattern_lit.value();
|
|
||||||
match Pattern::new(&raw_pattern) {
|
|
||||||
Ok(pattern) => Ok((pattern, pattern_lit.span())),
|
|
||||||
Err(err) => Err(Error::new(
|
|
||||||
pattern_lit.span(),
|
|
||||||
format!("'{raw_pattern}' is not a valid glob pattern: '{}'", err.msg),
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generates a test for each file that matches the specified pattern.
|
|
||||||
///
|
|
||||||
/// The attributed function must have exactly one argument of the type `&Path`.
|
|
||||||
/// The `#[test]` attribute must come after the `#[fixture]` argument or `test` will complain
|
|
||||||
/// that your function can not have any arguments.
|
|
||||||
///
|
|
||||||
/// ## Examples
|
|
||||||
///
|
|
||||||
/// Creates a test for every python file file in the `fixtures` directory.
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// #[fixture(pattern="fixtures/*.py")]
|
|
||||||
/// #[test]
|
|
||||||
/// fn my_test(path: &Path) -> std::io::Result<()> {
|
|
||||||
/// // ... implement the test
|
|
||||||
/// Ok(())
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ### Excluding Files
|
|
||||||
///
|
|
||||||
/// You can exclude files by specifying optional `exclude` patterns.
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// #[fixture(pattern="fixtures/*.py", exclude=["a_*.py"])]
|
|
||||||
/// #[test]
|
|
||||||
/// fn my_test(path: &Path) -> std::io::Result<()> {
|
|
||||||
/// // ... implement the test
|
|
||||||
/// Ok(())
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Creates tests for each python file in the `fixtures` directory except for files matching the `a_*.py` pattern.
|
|
||||||
#[proc_macro_attribute]
|
|
||||||
pub fn fixture(attribute: TokenStream, item: TokenStream) -> TokenStream {
|
|
||||||
let test_fn = parse_macro_input!(item as ItemFn);
|
|
||||||
let configuration = parse_macro_input!(attribute as FixtureConfiguration);
|
|
||||||
|
|
||||||
let result = generate_fixtures(test_fn, &configuration);
|
|
||||||
|
|
||||||
let stream = match result {
|
|
||||||
Ok(output) => output,
|
|
||||||
Err(err) => err.to_compile_error(),
|
|
||||||
};
|
|
||||||
|
|
||||||
TokenStream::from(stream)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_fixtures(
|
|
||||||
mut test_fn: ItemFn,
|
|
||||||
configuration: &FixtureConfiguration,
|
|
||||||
) -> syn::Result<proc_macro2::TokenStream> {
|
|
||||||
// Remove the fixtures attribute
|
|
||||||
test_fn
|
|
||||||
.attrs
|
|
||||||
.retain(|attr| !attr.path().is_ident("fixtures"));
|
|
||||||
|
|
||||||
// Extract the name of the only argument of the test function.
|
|
||||||
let last_arg = test_fn.sig.inputs.last();
|
|
||||||
let path_ident = match (test_fn.sig.inputs.len(), last_arg) {
|
|
||||||
(1, Some(last_arg)) => match last_arg {
|
|
||||||
FnArg::Typed(typed) => match typed.pat.as_ref() {
|
|
||||||
Pat::Ident(ident) => ident.ident.clone(),
|
|
||||||
pat => {
|
|
||||||
return Err(Error::new(
|
|
||||||
pat.span(),
|
|
||||||
"#[fixture] function argument name must be an identifier",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
FnArg::Receiver(receiver) => {
|
|
||||||
return Err(Error::new(
|
|
||||||
receiver.span(),
|
|
||||||
"#[fixture] function argument name must be an identifier",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
return Err(Error::new(
|
|
||||||
test_fn.sig.inputs.span(),
|
|
||||||
"#[fixture] function must have exactly one argument with the type '&Path'",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Remove all arguments
|
|
||||||
test_fn.sig.inputs.clear();
|
|
||||||
|
|
||||||
let crate_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect(
|
|
||||||
"#[fixture] requires CARGO_MANIFEST_DIR to be set during the build to resolve the relative paths to the test files.",
|
|
||||||
));
|
|
||||||
|
|
||||||
let pattern = if configuration.pattern.as_str().starts_with('/') {
|
|
||||||
Cow::from(configuration.pattern.as_str())
|
|
||||||
} else {
|
|
||||||
Cow::from(format!(
|
|
||||||
"{}/{}",
|
|
||||||
crate_dir
|
|
||||||
.to_str()
|
|
||||||
.expect("CARGO_MANIFEST_DIR must point to a directory with a UTF8 path"),
|
|
||||||
configuration.pattern.as_str()
|
|
||||||
))
|
|
||||||
};
|
|
||||||
|
|
||||||
let files = glob(&pattern).expect("Pattern to be valid").flatten();
|
|
||||||
let mut modules = Modules::default();
|
|
||||||
|
|
||||||
for file in files {
|
|
||||||
if configuration
|
|
||||||
.exclude
|
|
||||||
.iter()
|
|
||||||
.any(|exclude| exclude.matches_path(&file))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut test_fn = test_fn.clone();
|
|
||||||
|
|
||||||
let test_name = file
|
|
||||||
.file_name()
|
|
||||||
// SAFETY: Glob only matches on file names.
|
|
||||||
.unwrap()
|
|
||||||
.to_str()
|
|
||||||
.expect("Expected path to be valid UTF8")
|
|
||||||
.replace('.', "_");
|
|
||||||
|
|
||||||
test_fn.sig.ident = format_ident!("{test_name}");
|
|
||||||
|
|
||||||
let path = file.as_os_str().to_str().unwrap();
|
|
||||||
|
|
||||||
test_fn.block.stmts.insert(
|
|
||||||
0,
|
|
||||||
parse_quote!(let #path_ident = std::path::Path::new(#path);),
|
|
||||||
);
|
|
||||||
|
|
||||||
modules.push_test(Test {
|
|
||||||
path: file,
|
|
||||||
test_fn,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if modules.is_empty() {
|
|
||||||
return Err(Error::new(
|
|
||||||
configuration.pattern_span,
|
|
||||||
"No file matches the specified glob pattern",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let root = find_highest_common_ancestor_module(&modules.root);
|
|
||||||
|
|
||||||
root.generate(&test_fn.sig.ident.to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_highest_common_ancestor_module(module: &Module) -> &Module {
|
|
||||||
let children = &module.children;
|
|
||||||
|
|
||||||
if children.len() == 1 {
|
|
||||||
let (_, child) = children.iter().next().unwrap();
|
|
||||||
|
|
||||||
match child {
|
|
||||||
Child::Module(common_child) => find_highest_common_ancestor_module(common_child),
|
|
||||||
Child::Test(_) => module,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
module
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Test {
|
|
||||||
path: PathBuf,
|
|
||||||
test_fn: ItemFn,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Test {
|
|
||||||
fn generate(&self, _: &str) -> proc_macro2::TokenStream {
|
|
||||||
let test_fn = &self.test_fn;
|
|
||||||
quote!(#test_fn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
struct Module {
|
|
||||||
children: BTreeMap<String, Child>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Module {
|
|
||||||
fn generate(&self, name: &str) -> syn::Result<proc_macro2::TokenStream> {
|
|
||||||
let mut inner = Vec::with_capacity(self.children.len());
|
|
||||||
|
|
||||||
for (name, child) in &self.children {
|
|
||||||
inner.push(child.generate(name)?);
|
|
||||||
}
|
|
||||||
|
|
||||||
let module_ident = format_ident!("{name}");
|
|
||||||
|
|
||||||
Ok(quote!(
|
|
||||||
mod #module_ident {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#(#inner)*
|
|
||||||
}
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum Child {
|
|
||||||
Module(Module),
|
|
||||||
Test(Test),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Child {
|
|
||||||
fn generate(&self, name: &str) -> syn::Result<proc_macro2::TokenStream> {
|
|
||||||
match self {
|
|
||||||
Child::Module(module) => module.generate(name),
|
|
||||||
Child::Test(test) => Ok(test.generate(name)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
struct Modules {
|
|
||||||
root: Module,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Modules {
|
|
||||||
fn push_test(&mut self, test: Test) {
|
|
||||||
let mut components = test
|
|
||||||
.path
|
|
||||||
.as_path()
|
|
||||||
.components()
|
|
||||||
.skip_while(|c| matches!(c, Component::RootDir))
|
|
||||||
.peekable();
|
|
||||||
|
|
||||||
let mut current = &mut self.root;
|
|
||||||
while let Some(component) = components.next() {
|
|
||||||
let name = component.as_os_str().to_str().unwrap();
|
|
||||||
// A directory
|
|
||||||
if components.peek().is_some() {
|
|
||||||
let name = component.as_os_str().to_str().unwrap();
|
|
||||||
let entry = current.children.entry(name.to_owned());
|
|
||||||
|
|
||||||
match entry.or_insert_with(|| Child::Module(Module::default())) {
|
|
||||||
Child::Module(module) => {
|
|
||||||
current = module;
|
|
||||||
}
|
|
||||||
Child::Test(_) => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// We reached the final component, insert the test
|
|
||||||
drop(components);
|
|
||||||
current.children.insert(name.to_owned(), Child::Test(test));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_empty(&self) -> bool {
|
|
||||||
self.root.children.is_empty()
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue