From 05a4c293443ff2f104e4fc6899d8980eea9862ee Mon Sep 17 00:00:00 2001 From: Eric Mark Martin Date: Fri, 7 Mar 2025 03:04:52 -0500 Subject: [PATCH] print MDTEST_TEST_FILTER value in single-quotes (and escaped) (#16548) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary If an mdtest fails, the error output will include an example command that can be run to re-run just the failing test, e.g ``` To rerun this specific test, set the environment variable: MDTEST_TEST_FILTER="sync.md - With statements - Context manager with non-callable `__exit__` attribute" MDTEST_TEST_FILTER="sync.md - With statements - Context manager with non-callable `__exit__` attribute" cargo test -p red_knot_python_semantic --test mdtest -- mdtest__with_sync ``` This is very helpful, but because we're printing the envvar value surrounded in double-quotes, the bits between backticks in this example get interpreted as a shell interpolation. When running this in zsh, for example, I see ```console ❯ MDTEST_TEST_FILTER="sync.md - With statements - Context manager with non-callable `__exit__` attribute" cargo test -p red_knot_python_semantic --test mdtest -- mdtest__with_sync zsh: command not found: __exit__ Compiling red_knot_python_semantic v0.0.0 (/home/ericmarkmartin/Development/ruff/crates/red_knot_python_semantic) Compiling red_knot_test v0.0.0 (/home/ericmarkmartin/Development/ruff/crates/red_knot_test) Finished `test` profile [unoptimized + debuginfo] target(s) in 6.09s Running tests/mdtest.rs (target/debug/deps/mdtest-149b8f9d937e36bc) running 1 test test mdtest__with_sync ... ok ``` [^1] This is a minor annoyance which we can solve by using single-quotes instead of double-quotes for this string. To do so safely, we also escape single-quotes possibly contained within the string. There is a [shell-quote](https://github.com/allenap/shell-quote) crate, which seems to handle all this escaping stuff for you but fixing this issue perfectly isn't a big deal (if there are more things to escape we can deal with it then), so adding a new dependency (even a dev one) seemed overkill. [^1]: The filter does still work---it turns out that the filter `MDTEST_TEST_FILTER="sync.md - With statements - Context manager with non-callable attribute"` (what you get after the failed interpolation) is still good enough ## Test Plan I broke the ``## Context manager with non-callable `__exit__` attribute`` test by deleting the error assertion, then successfully ran the new command it printed out. --- crates/red_knot_test/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/red_knot_test/src/lib.rs b/crates/red_knot_test/src/lib.rs index e649626056..528506157a 100644 --- a/crates/red_knot_test/src/lib.rs +++ b/crates/red_knot_test/src/lib.rs @@ -79,13 +79,13 @@ pub fn run( } } + let escaped_test_name = test.name().replace('\'', "\\'"); + println!( - "\nTo rerun this specific test, set the environment variable: {MDTEST_TEST_FILTER}=\"{}\"", - test.name() + "\nTo rerun this specific test, set the environment variable: {MDTEST_TEST_FILTER}='{escaped_test_name}'", ); println!( - "{MDTEST_TEST_FILTER}=\"{}\" cargo test -p red_knot_python_semantic --test mdtest -- {test_name}", - test.name() + "{MDTEST_TEST_FILTER}='{escaped_test_name}' cargo test -p red_knot_python_semantic --test mdtest -- {test_name}", ); } }