]> git.madduck.net Git - etc/vim.git/commitdiff

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Use inline flags for test cases (#3931)
authorJelle Zijlstra <jelle.zijlstra@gmail.com>
Tue, 10 Oct 2023 01:43:47 +0000 (18:43 -0700)
committerGitHub <noreply@github.com>
Tue, 10 Oct 2023 01:43:47 +0000 (18:43 -0700)
Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
132 files changed:
docs/contributing/the_basics.md
tests/data/cases/attribute_access_on_number_literals.py [moved from tests/data/simple_cases/attribute_access_on_number_literals.py with 100% similarity]
tests/data/cases/beginning_backslash.py [moved from tests/data/simple_cases/beginning_backslash.py with 100% similarity]
tests/data/cases/bracketmatch.py [moved from tests/data/simple_cases/bracketmatch.py with 100% similarity]
tests/data/cases/class_blank_parentheses.py [moved from tests/data/simple_cases/class_blank_parentheses.py with 100% similarity]
tests/data/cases/class_methods_new_line.py [moved from tests/data/simple_cases/class_methods_new_line.py with 100% similarity]
tests/data/cases/collections.py [moved from tests/data/simple_cases/collections.py with 100% similarity]
tests/data/cases/comment_after_escaped_newline.py [moved from tests/data/simple_cases/comment_after_escaped_newline.py with 100% similarity]
tests/data/cases/comments.py [moved from tests/data/simple_cases/comments.py with 100% similarity]
tests/data/cases/comments2.py [moved from tests/data/simple_cases/comments2.py with 100% similarity]
tests/data/cases/comments3.py [moved from tests/data/simple_cases/comments3.py with 100% similarity]
tests/data/cases/comments4.py [moved from tests/data/simple_cases/comments4.py with 100% similarity]
tests/data/cases/comments5.py [moved from tests/data/simple_cases/comments5.py with 100% similarity]
tests/data/cases/comments6.py [moved from tests/data/simple_cases/comments6.py with 100% similarity]
tests/data/cases/comments8.py [moved from tests/data/simple_cases/comments8.py with 100% similarity]
tests/data/cases/comments9.py [moved from tests/data/simple_cases/comments9.py with 100% similarity]
tests/data/cases/comments_non_breaking_space.py [moved from tests/data/simple_cases/comments_non_breaking_space.py with 100% similarity]
tests/data/cases/composition.py [moved from tests/data/simple_cases/composition.py with 100% similarity]
tests/data/cases/composition_no_trailing_comma.py [moved from tests/data/simple_cases/composition_no_trailing_comma.py with 100% similarity]
tests/data/cases/docstring.py [moved from tests/data/simple_cases/docstring.py with 100% similarity]
tests/data/cases/docstring_no_extra_empty_line_before_eof.py [moved from tests/data/simple_cases/docstring_no_extra_empty_line_before_eof.py with 100% similarity]
tests/data/cases/docstring_no_string_normalization.py [moved from tests/data/miscellaneous/docstring_no_string_normalization.py with 98% similarity]
tests/data/cases/docstring_preview.py [moved from tests/data/simple_cases/docstring_preview.py with 100% similarity]
tests/data/cases/docstring_preview_no_string_normalization.py [moved from tests/data/miscellaneous/docstring_preview_no_string_normalization.py with 88% similarity]
tests/data/cases/empty_lines.py [moved from tests/data/simple_cases/empty_lines.py with 100% similarity]
tests/data/cases/expression.diff [moved from tests/data/simple_cases/expression.diff with 100% similarity]
tests/data/cases/expression.py [moved from tests/data/simple_cases/expression.py with 100% similarity]
tests/data/cases/fmtonoff.py [moved from tests/data/simple_cases/fmtonoff.py with 100% similarity]
tests/data/cases/fmtonoff2.py [moved from tests/data/simple_cases/fmtonoff2.py with 100% similarity]
tests/data/cases/fmtonoff3.py [moved from tests/data/simple_cases/fmtonoff3.py with 100% similarity]
tests/data/cases/fmtonoff4.py [moved from tests/data/simple_cases/fmtonoff4.py with 100% similarity]
tests/data/cases/fmtonoff5.py [moved from tests/data/simple_cases/fmtonoff5.py with 100% similarity]
tests/data/cases/fmtpass_imports.py [moved from tests/data/simple_cases/fmtpass_imports.py with 100% similarity]
tests/data/cases/fmtskip.py [moved from tests/data/simple_cases/fmtskip.py with 100% similarity]
tests/data/cases/fmtskip2.py [moved from tests/data/simple_cases/fmtskip2.py with 100% similarity]
tests/data/cases/fmtskip3.py [moved from tests/data/simple_cases/fmtskip3.py with 100% similarity]
tests/data/cases/fmtskip4.py [moved from tests/data/simple_cases/fmtskip4.py with 100% similarity]
tests/data/cases/fmtskip5.py [moved from tests/data/simple_cases/fmtskip5.py with 100% similarity]
tests/data/cases/fmtskip6.py [moved from tests/data/simple_cases/fmtskip6.py with 100% similarity]
tests/data/cases/fmtskip7.py [moved from tests/data/simple_cases/fmtskip7.py with 100% similarity]
tests/data/cases/fmtskip8.py [moved from tests/data/simple_cases/fmtskip8.py with 100% similarity]
tests/data/cases/fstring.py [moved from tests/data/simple_cases/fstring.py with 100% similarity]
tests/data/cases/funcdef_return_type_trailing_comma.py [moved from tests/data/preview_py_310/funcdef_return_type_trailing_comma.py with 99% similarity]
tests/data/cases/function.py [moved from tests/data/simple_cases/function.py with 100% similarity]
tests/data/cases/function2.py [moved from tests/data/simple_cases/function2.py with 100% similarity]
tests/data/cases/function_trailing_comma.py [moved from tests/data/simple_cases/function_trailing_comma.py with 100% similarity]
tests/data/cases/ignore_pyi.py [moved from tests/data/simple_cases/ignore_pyi.py with 97% similarity]
tests/data/cases/import_spacing.py [moved from tests/data/simple_cases/import_spacing.py with 100% similarity]
tests/data/cases/linelength6.py [moved from tests/data/miscellaneous/linelength6.py with 80% similarity]
tests/data/cases/long_strings_flag_disabled.py [moved from tests/data/miscellaneous/long_strings_flag_disabled.py with 100% similarity]
tests/data/cases/multiline_consecutive_open_parentheses_ignore.py [moved from tests/data/simple_cases/multiline_consecutive_open_parentheses_ignore.py with 100% similarity]
tests/data/cases/nested_stub.py [moved from tests/data/miscellaneous/nested_stub.pyi with 94% similarity]
tests/data/cases/numeric_literals.py [moved from tests/data/py_36/numeric_literals.py with 91% similarity]
tests/data/cases/numeric_literals_skip_underscores.py [moved from tests/data/py_36/numeric_literals_skip_underscores.py with 77% similarity]
tests/data/cases/one_element_subscript.py [moved from tests/data/simple_cases/one_element_subscript.py with 100% similarity]
tests/data/cases/parenthesized_context_managers.py [moved from tests/data/py_310/parenthesized_context_managers.py with 95% similarity]
tests/data/cases/pattern_matching_complex.py [moved from tests/data/py_310/pattern_matching_complex.py with 98% similarity]
tests/data/cases/pattern_matching_extras.py [moved from tests/data/py_310/pattern_matching_extras.py with 98% similarity]
tests/data/cases/pattern_matching_generic.py [moved from tests/data/py_310/pattern_matching_generic.py with 98% similarity]
tests/data/cases/pattern_matching_simple.py [moved from tests/data/py_310/pattern_matching_simple.py with 98% similarity]
tests/data/cases/pattern_matching_style.py [moved from tests/data/py_310/pattern_matching_style.py with 97% similarity]
tests/data/cases/pep604_union_types_line_breaks.py [moved from tests/data/preview_py_310/pep604_union_types_line_breaks.py with 99% similarity]
tests/data/cases/pep_570.py [moved from tests/data/py_38/pep_570.py with 95% similarity]
tests/data/cases/pep_572.py [moved from tests/data/py_38/pep_572.py with 96% similarity]
tests/data/cases/pep_572_do_not_remove_parens.py [moved from tests/data/fast/pep_572_do_not_remove_parens.py with 96% similarity]
tests/data/cases/pep_572_py310.py [moved from tests/data/py_310/pep_572_py310.py with 93% similarity]
tests/data/cases/pep_572_py39.py [moved from tests/data/py_39/pep_572_py39.py with 89% similarity]
tests/data/cases/pep_572_remove_parens.py [moved from tests/data/py_38/pep_572_remove_parens.py with 98% similarity]
tests/data/cases/pep_604.py [moved from tests/data/simple_cases/pep_604.py with 100% similarity]
tests/data/cases/pep_646.py [moved from tests/data/py_311/pep_646.py with 98% similarity]
tests/data/cases/pep_654.py [moved from tests/data/py_311/pep_654.py with 96% similarity]
tests/data/cases/pep_654_style.py [moved from tests/data/py_311/pep_654_style.py with 98% similarity]
tests/data/cases/power_op_newline.py [moved from tests/data/miscellaneous/power_op_newline.py with 73% similarity]
tests/data/cases/power_op_spacing.py [moved from tests/data/simple_cases/power_op_spacing.py with 100% similarity]
tests/data/cases/prefer_rhs_split_reformatted.py [moved from tests/data/simple_cases/prefer_rhs_split_reformatted.py with 100% similarity]
tests/data/cases/preview_async_stmts.py [moved from tests/data/preview/async_stmts.py with 93% similarity]
tests/data/cases/preview_cantfit.py [moved from tests/data/preview/cantfit.py with 99% similarity]
tests/data/cases/preview_comments7.py [moved from tests/data/preview/comments7.py with 99% similarity]
tests/data/cases/preview_context_managers_38.py [moved from tests/data/preview_context_managers/targeting_py38.py with 96% similarity]
tests/data/cases/preview_context_managers_39.py [moved from tests/data/preview_context_managers/targeting_py39.py with 98% similarity]
tests/data/cases/preview_context_managers_autodetect_310.py [moved from tests/data/preview_context_managers/auto_detect/features_3_10.py with 93% similarity]
tests/data/cases/preview_context_managers_autodetect_311.py [moved from tests/data/preview_context_managers/auto_detect/features_3_11.py with 92% similarity]
tests/data/cases/preview_context_managers_autodetect_38.py [moved from tests/data/preview_context_managers/auto_detect/features_3_8.py with 98% similarity]
tests/data/cases/preview_context_managers_autodetect_39.py [moved from tests/data/preview_context_managers/auto_detect/features_3_9.py with 93% similarity]
tests/data/cases/preview_dummy_implementations.py [moved from tests/data/preview/dummy_implementations.py with 98% similarity]
tests/data/cases/preview_format_unicode_escape_seq.py [moved from tests/data/preview/format_unicode_escape_seq.py with 96% similarity]
tests/data/cases/preview_long_dict_values.py [moved from tests/data/preview/long_dict_values.py with 99% similarity]
tests/data/cases/preview_long_strings.py [moved from tests/data/preview/long_strings.py with 99% similarity]
tests/data/cases/preview_long_strings__east_asian_width.py [moved from tests/data/preview/long_strings__east_asian_width.py with 96% similarity]
tests/data/cases/preview_long_strings__edge_case.py [moved from tests/data/preview/long_strings__edge_case.py with 99% similarity]
tests/data/cases/preview_long_strings__regression.py [moved from tests/data/preview/long_strings__regression.py with 99% similarity]
tests/data/cases/preview_long_strings__type_annotations.py [moved from tests/data/preview/long_strings__type_annotations.py with 98% similarity]
tests/data/cases/preview_multiline_strings.py [moved from tests/data/preview/multiline_strings.py with 99% similarity]
tests/data/cases/preview_no_blank_line_before_docstring.py [moved from tests/data/preview/no_blank_line_before_docstring.py with 97% similarity]
tests/data/cases/preview_pep_572.py [moved from tests/data/preview/pep_572.py with 75% similarity]
tests/data/cases/preview_percent_precedence.py [moved from tests/data/preview/percent_precedence.py with 96% similarity]
tests/data/cases/preview_prefer_rhs_split.py [moved from tests/data/preview/prefer_rhs_split.py with 99% similarity]
tests/data/cases/preview_return_annotation_brackets_string.py [moved from tests/data/preview/return_annotation_brackets_string.py with 97% similarity]
tests/data/cases/preview_trailing_comma.py [moved from tests/data/preview/trailing_comma.py with 97% similarity]
tests/data/cases/py310_pep572.py [moved from tests/data/preview_py_310/pep_572.py with 77% similarity]
tests/data/cases/python37.py [moved from tests/data/py_37/python37.py with 95% similarity]
tests/data/cases/python38.py [moved from tests/data/py_38/python38.py with 93% similarity]
tests/data/cases/python39.py [moved from tests/data/py_39/python39.py with 91% similarity]
tests/data/cases/remove_await_parens.py [moved from tests/data/simple_cases/remove_await_parens.py with 100% similarity]
tests/data/cases/remove_except_parens.py [moved from tests/data/simple_cases/remove_except_parens.py with 100% similarity]
tests/data/cases/remove_for_brackets.py [moved from tests/data/simple_cases/remove_for_brackets.py with 100% similarity]
tests/data/cases/remove_newline_after_code_block_open.py [moved from tests/data/simple_cases/remove_newline_after_code_block_open.py with 100% similarity]
tests/data/cases/remove_newline_after_match.py [moved from tests/data/py_310/remove_newline_after_match.py with 88% similarity]
tests/data/cases/remove_parens.py [moved from tests/data/simple_cases/remove_parens.py with 100% similarity]
tests/data/cases/remove_with_brackets.py [moved from tests/data/py_39/remove_with_brackets.py with 98% similarity]
tests/data/cases/return_annotation_brackets.py [moved from tests/data/simple_cases/return_annotation_brackets.py with 100% similarity]
tests/data/cases/skip_magic_trailing_comma.py [moved from tests/data/simple_cases/skip_magic_trailing_comma.py with 97% similarity]
tests/data/cases/slices.py [moved from tests/data/simple_cases/slices.py with 100% similarity]
tests/data/cases/starred_for_target.py [moved from tests/data/py_310/starred_for_target.py with 92% similarity]
tests/data/cases/string_prefixes.py [moved from tests/data/simple_cases/string_prefixes.py with 100% similarity]
tests/data/cases/stub.py [moved from tests/data/miscellaneous/stub.pyi with 99% similarity]
tests/data/cases/torture.py [moved from tests/data/simple_cases/torture.py with 100% similarity]
tests/data/cases/trailing_comma_optional_parens1.py [moved from tests/data/simple_cases/trailing_comma_optional_parens1.py with 100% similarity]
tests/data/cases/trailing_comma_optional_parens2.py [moved from tests/data/simple_cases/trailing_comma_optional_parens2.py with 100% similarity]
tests/data/cases/trailing_comma_optional_parens3.py [moved from tests/data/simple_cases/trailing_comma_optional_parens3.py with 100% similarity]
tests/data/cases/trailing_commas_in_leading_parts.py [moved from tests/data/simple_cases/trailing_commas_in_leading_parts.py with 100% similarity]
tests/data/cases/tricky_unicode_symbols.py [moved from tests/data/simple_cases/tricky_unicode_symbols.py with 100% similarity]
tests/data/cases/tupleassign.py [moved from tests/data/simple_cases/tupleassign.py with 100% similarity]
tests/data/cases/type_aliases.py [moved from tests/data/py_312/type_aliases.py with 81% similarity]
tests/data/cases/type_comment_syntax_error.py [moved from tests/data/type_comments/type_comment_syntax_error.py with 100% similarity]
tests/data/cases/type_params.py [moved from tests/data/py_312/type_params.py with 97% similarity]
tests/data/cases/whitespace.py [moved from tests/data/simple_cases/whitespace.py with 100% similarity]
tests/data/miscellaneous/force_pyi.py
tests/test_black.py
tests/test_blackd.py
tests/test_format.py
tests/util.py

index 864894b491fbe3cdaca802911d952cc2a5530c17..bc1680eecfd835e92fbffa3fd99cac39c9856ed0 100644 (file)
@@ -58,7 +58,26 @@ Further examples of invoking the tests
 (.venv)$ tox -e py -- --print-tree-diff=False
 ```
 
 (.venv)$ tox -e py -- --print-tree-diff=False
 ```
 
-`Black` has two pytest command-line options affecting test files in `tests/data/` that
+### Testing
+
+All aspects of the _Black_ style should be tested. Normally, tests should be created as
+files in the `tests/data/cases` directory. These files consist of up to three parts:
+
+- A line that starts with `# flags: ` followed by a set of command-line options. For
+  example, if the line is `# flags: --preview --skip-magic-trailing-comma`, the test
+  case will be run with preview mode on and the magic trailing comma off. The options
+  accepted are mostly a subset of those of _Black_ itself, except for the
+  `--minimum-version=` flag, which should be used when testing a grammar feature that
+  works only in newer versions of Python. This flag ensures that we don't try to
+  validate the AST on older versions and tests that we autodetect the Python version
+  correctly when the feature is used. For the exact flags accepted, see the function
+  `get_flags_parser` in `tests/util.py`. If this line is omitted, the default options
+  are used.
+- A block of Python code used as input for the formatter.
+- The line `# output`, followed by the output of _Black_ when run on the previous block.
+  If this is omitted, the test asserts that _Black_ will leave the input code unchanged.
+
+_Black_ has two pytest command-line options affecting test files in `tests/data/` that
 are split into an input part, and an output part, separated by a line with`# output`.
 These can be passed to `pytest` through `tox`, or directly into pytest if not using
 `tox`.
 are split into an input part, and an output part, separated by a line with`# output`.
 These can be passed to `pytest` through `tox`, or directly into pytest if not using
 `tox`.
similarity index 98%
rename from tests/data/miscellaneous/docstring_no_string_normalization.py
rename to tests/data/cases/docstring_no_string_normalization.py
index a90b578f09afb71ddff8e84e8ede8dcc5372fe1d..4ec6b8a01535a17d092a4ac0d255c43d8ec524d2 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --skip-string-normalization
 class ALonelyClass:
     '''
     A multiline class docstring.
 class ALonelyClass:
     '''
     A multiline class docstring.
similarity index 88%
rename from tests/data/miscellaneous/docstring_preview_no_string_normalization.py
rename to tests/data/cases/docstring_preview_no_string_normalization.py
index 338cc01d33e64d6959250eb1002d9155dbe50fd6..712c7364f51bd97d73b1c1b8f0bd82e6274ba913 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview --skip-string-normalization
 def do_not_touch_this_prefix():
     R"""There was a bug where docstring prefixes would be normalized even with -S."""
 
 def do_not_touch_this_prefix():
     R"""There was a bug where docstring prefixes would be normalized even with -S."""
 
similarity index 99%
rename from tests/data/preview_py_310/funcdef_return_type_trailing_comma.py
rename to tests/data/cases/funcdef_return_type_trailing_comma.py
index 15db772f01eb0719c6f60ced202309d95731f885..9b9b9c673de63917b1ec3ec7d137dce7ede97302 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview --minimum-version=3.10
 # normal, short, function definition
 def foo(a, b) -> tuple[int, float]: ...
 
 # normal, short, function definition
 def foo(a, b) -> tuple[int, float]: ...
 
similarity index 97%
rename from tests/data/simple_cases/ignore_pyi.py
rename to tests/data/cases/ignore_pyi.py
index 3ef61079bfecc78adc2f288dad32da250195af77..4fae7530eb98ab918766980229dc88320c83a8e0 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --pyi
 def f():  # type: ignore
     ...
 
 def f():  # type: ignore
     ...
 
similarity index 80%
rename from tests/data/miscellaneous/linelength6.py
rename to tests/data/cases/linelength6.py
index 4fb342726f57ac41a597ec7178c19d2c431b6ea4..158038bf960607aa048e6cde702c8a4ce6c0bb62 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --line-length=6
 # Regression test for #3427, which reproes only with line length <= 6
 def f():
     """
 # Regression test for #3427, which reproes only with line length <= 6
 def f():
     """
similarity index 94%
rename from tests/data/miscellaneous/nested_stub.pyi
rename to tests/data/cases/nested_stub.py
index 15e69d854db7fb05dbbc165358298d7e6ff78955..b81549ec115c9bec521cb606d5ec9d91dc2924f2 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --pyi --preview
 import sys
 
 class Outer:
 import sys
 
 class Outer:
similarity index 91%
rename from tests/data/py_36/numeric_literals.py
rename to tests/data/cases/numeric_literals.py
index 254da68d3308bf76cdf464dbf9aa5a5a74252828..996693287448580093d4be201fc770b6a985308c 100644 (file)
@@ -1,5 +1,3 @@
-#!/usr/bin/env python3.6
-
 x = 123456789
 x = 123456
 x = .1
 x = 123456789
 x = 123456
 x = .1
@@ -21,9 +19,6 @@ x = 133333
 
 # output
 
 
 # output
 
-
-#!/usr/bin/env python3.6
-
 x = 123456789
 x = 123456
 x = 0.1
 x = 123456789
 x = 123456
 x = 0.1
similarity index 77%
rename from tests/data/py_36/numeric_literals_skip_underscores.py
rename to tests/data/cases/numeric_literals_skip_underscores.py
index e345bb90276c709939125f2e366f45318e973486..6d60bdbb34d185dd63a79b1fcf579b8183ee78dc 100644 (file)
@@ -1,5 +1,3 @@
-#!/usr/bin/env python3.6
-
 x = 123456789
 x = 1_2_3_4_5_6_7
 x = 1E+1
 x = 123456789
 x = 1_2_3_4_5_6_7
 x = 1E+1
@@ -11,8 +9,6 @@ x = 1_2.
 
 # output
 
 
 # output
 
-#!/usr/bin/env python3.6
-
 x = 123456789
 x = 1_2_3_4_5_6_7
 x = 1e1
 x = 123456789
 x = 1_2_3_4_5_6_7
 x = 1e1
similarity index 95%
rename from tests/data/py_310/parenthesized_context_managers.py
rename to tests/data/cases/parenthesized_context_managers.py
index 1ef09a1bd3429f922f3d88c9404f9849bd1d190f..16645a18baa25b65deb728300c91e44ae92a5c55 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --minimum-version=3.10
 with (CtxManager() as example):
     ...
 
 with (CtxManager() as example):
     ...
 
similarity index 98%
rename from tests/data/py_310/pattern_matching_complex.py
rename to tests/data/cases/pattern_matching_complex.py
index 97ee194fd39e2d044b78d183c54759aa73dba0b7..b4355c7333a54021f41999637a7bed7adb1c0eeb 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --minimum-version=3.10
 # Cases sampled from Lib/test/test_patma.py
 
 # case black_test_patma_098
 # Cases sampled from Lib/test/test_patma.py
 
 # case black_test_patma_098
similarity index 98%
rename from tests/data/py_310/pattern_matching_extras.py
rename to tests/data/cases/pattern_matching_extras.py
index 0242d264e5b63143066cf37aa3e4a71a09f9637a..1e1481d7bbecda80bd9b037764cc086cc8bad4dd 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --minimum-version=3.10
 import match
 
 match something:
 import match
 
 match something:
similarity index 98%
rename from tests/data/py_310/pattern_matching_generic.py
rename to tests/data/cases/pattern_matching_generic.py
index 00a0e4a677dcf2d8d622cf5764a8dbf32f5531fc..4b4d45f0bffb5966e63225efb87a220bad9f8e0d 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --minimum-version=3.10
 re.match()
 match = a
 with match() as match:
 re.match()
 match = a
 with match() as match:
similarity index 98%
rename from tests/data/py_310/pattern_matching_simple.py
rename to tests/data/cases/pattern_matching_simple.py
index 5ed62415a4b5d1b72a3bf6e413960802a6b62b43..6fa2000f0dedc93db0837093443e98376ac78025 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --minimum-version=3.10
 # Cases sampled from PEP 636 examples
 
 match command.split():
 # Cases sampled from PEP 636 examples
 
 match command.split():
similarity index 97%
rename from tests/data/py_310/pattern_matching_style.py
rename to tests/data/cases/pattern_matching_style.py
index 8e18ce2ada6dda70dd8c82d2733034b807e44384..2ee6ea2b6e99b5d168227f9803386e92f64f6c9d 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --minimum-version=3.10
 match something:
     case b(): print(1+1)
     case c(
 match something:
     case b(): print(1+1)
     case c(
similarity index 99%
rename from tests/data/preview_py_310/pep604_union_types_line_breaks.py
rename to tests/data/cases/pep604_union_types_line_breaks.py
index 9c4ab870766e46c88f66092d01fb3af2505d1204..fee2b8404943cdbd0ba1592f0646695270d3581a 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview --minimum-version=3.10
 # This has always worked
 z= Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong
 
 # This has always worked
 z= Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong
 
similarity index 95%
rename from tests/data/py_38/pep_570.py
rename to tests/data/cases/pep_570.py
index ca8f7ab1d95d08f642db68a852f2821c09a9c720..2641c2b970edb77adb82a1fbeaad3fd48bbf3e63 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --minimum-version=3.8
 def positional_only_arg(a, /):
     pass
 
 def positional_only_arg(a, /):
     pass
 
similarity index 96%
rename from tests/data/py_38/pep_572.py
rename to tests/data/cases/pep_572.py
index d41805f1cb16d93eb0600ae30b69019973652522..742b6d5b7e41eed7d047cfa2c5ec5d221c59358c 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --minimum-version=3.8
 (a := 1)
 (a := a)
 if (match := pattern.search(data)) is None:
 (a := 1)
 (a := a)
 if (match := pattern.search(data)) is None:
similarity index 96%
rename from tests/data/fast/pep_572_do_not_remove_parens.py
rename to tests/data/cases/pep_572_do_not_remove_parens.py
index 05619ddcc2b0336560560d5adaac81d100a8d82a..08dba3ffdf9b3eacc1c4410452bd631f06085384 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --fast
 # Most of the following examples are really dumb, some of them aren't even accepted by Python,
 # we're fixing them only so fuzzers (which follow the grammar which actually allows these
 # examples matter of fact!) don't yell at us :p
 # Most of the following examples are really dumb, some of them aren't even accepted by Python,
 # we're fixing them only so fuzzers (which follow the grammar which actually allows these
 # examples matter of fact!) don't yell at us :p
similarity index 93%
rename from tests/data/py_310/pep_572_py310.py
rename to tests/data/cases/pep_572_py310.py
index cb82b2d23f8a49d54a615605105100c62942ebba..9f999deeb89effc38301cf682d19abedcce38f95 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --minimum-version=3.10
 # Unparenthesized walruses are now allowed in indices since Python 3.10.
 x[a:=0]
 x[a:=0, b:=1]
 # Unparenthesized walruses are now allowed in indices since Python 3.10.
 x[a:=0]
 x[a:=0, b:=1]
similarity index 89%
rename from tests/data/py_39/pep_572_py39.py
rename to tests/data/cases/pep_572_py39.py
index b8b081b8c4574d3638f6dcc9242cffcc096f6ea2..d1614624d99448a5e6ea7b6a02a518da65280755 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --minimum-version=3.9
 # Unparenthesized walruses are now allowed in set literals & set comprehensions
 # since Python 3.9
 {x := 1, 2, 3}
 # Unparenthesized walruses are now allowed in set literals & set comprehensions
 # since Python 3.9
 {x := 1, 2, 3}
similarity index 98%
rename from tests/data/py_38/pep_572_remove_parens.py
rename to tests/data/cases/pep_572_remove_parens.py
index b952b2940c502f87bf8dabfc7ba02d2e159a8e04..24f1ac29168f7069e8d3563080522bf80ffe1984 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --minimum-version=3.8
 if (foo := 0):
     pass
 
 if (foo := 0):
     pass
 
similarity index 98%
rename from tests/data/py_311/pep_646.py
rename to tests/data/cases/pep_646.py
index e843ecf39d89f40a09b91765b2d87cba743b62f1..92b568a379c4202aae7a45e5f0e46bc126eb408d 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --minimum-version=3.11
 A[*b]
 A[*b] = 1
 A
 A[*b]
 A[*b] = 1
 A
similarity index 96%
rename from tests/data/py_311/pep_654.py
rename to tests/data/cases/pep_654.py
index 387c0816f4b824e756189c8c29653523f833bd73..12e49180e415f8ea07e81fbc8d99e7eb16ce3e4a 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --minimum-version=3.11
 try:
     raise OSError("blah")
 except* ExceptionGroup as e:
 try:
     raise OSError("blah")
 except* ExceptionGroup as e:
similarity index 98%
rename from tests/data/py_311/pep_654_style.py
rename to tests/data/cases/pep_654_style.py
index 9fc7c0c84dbcdd6afae9765f612db58847b343aa..0d34650e0980fabfd2ed63cf52df37ce818219d9 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --minimum-version=3.11
 try:
     raise OSError("blah")
 except               * ExceptionGroup as e:
 try:
     raise OSError("blah")
 except               * ExceptionGroup as e:
similarity index 73%
rename from tests/data/miscellaneous/power_op_newline.py
rename to tests/data/cases/power_op_newline.py
index 85d434d63f6ea107e54f0075912507bfbd4de363..d9b31403c9d639d27cb5addaa7491624710a1301 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --line-length=0
 importA;()<<0**0#
 
 # output
 importA;()<<0**0#
 
 # output
similarity index 93%
rename from tests/data/preview/async_stmts.py
rename to tests/data/cases/preview_async_stmts.py
index fe9594b216492e983dad24561b563b5ff9466d3f..0a7671be5a6edb0b362123b1237211689bd02422 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview
 async def func() -> (int):
     return 0
 
 async def func() -> (int):
     return 0
 
similarity index 99%
rename from tests/data/preview/cantfit.py
rename to tests/data/cases/preview_cantfit.py
index 0849374f776ebbefc13f0332dd55aaeb0e690feb..d5da6654f0c2503acf74844f69e3e0b9b0c1bb26 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview
 # long variable name
 this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = 0
 this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = 1  # with a comment
 # long variable name
 this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = 0
 this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = 1  # with a comment
similarity index 99%
rename from tests/data/preview/comments7.py
rename to tests/data/cases/preview_comments7.py
index 0655de999ece6ef8783af25e051b1f620ef0a012..006d4f7266f8e872ba41cae9f5d6dbe95b315421 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview
 from .config import (
     Any,
     Bool,
 from .config import (
     Any,
     Bool,
similarity index 96%
rename from tests/data/preview_context_managers/targeting_py38.py
rename to tests/data/cases/preview_context_managers_38.py
index f125cdffb8af26e4d3cc78aa3b456809e7b6fb90..719d94fdcc541cb9416a332f32e7ab0c138ad370 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview --minimum-version=3.8
 with \
      make_context_manager1() as cm1, \
      make_context_manager2() as cm2, \
 with \
      make_context_manager1() as cm1, \
      make_context_manager2() as cm2, \
similarity index 98%
rename from tests/data/preview_context_managers/targeting_py39.py
rename to tests/data/cases/preview_context_managers_39.py
index c9fcf9c8ba2c9699382bfb45f57e75c0b344d98a..589e00ad187232bf4a1e0d9e089414350bfeb71f 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview --minimum-version=3.9
 with \
      make_context_manager1() as cm1, \
      make_context_manager2() as cm2, \
 with \
      make_context_manager1() as cm1, \
      make_context_manager2() as cm2, \
similarity index 93%
rename from tests/data/preview_context_managers/auto_detect/features_3_10.py
rename to tests/data/cases/preview_context_managers_autodetect_310.py
index 1458df1cb418195928e8ca51be3aafe92c338c71..a9e31076f03132958eec3879665f52f5f1b3530c 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview --minimum-version=3.10
 # This file uses pattern matching introduced in Python 3.10.
 
 
 # This file uses pattern matching introduced in Python 3.10.
 
 
similarity index 92%
rename from tests/data/preview_context_managers/auto_detect/features_3_11.py
rename to tests/data/cases/preview_context_managers_autodetect_311.py
index f83c5330ab3bde402b35afd3e36690ad368a15a7..af1e83fe74c4d0c05e5f3fabb7c31c20bad6e28b 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview --minimum-version=3.11
 # This file uses except* clause in Python 3.11.
 
 
 # This file uses except* clause in Python 3.11.
 
 
similarity index 98%
rename from tests/data/preview_context_managers/auto_detect/features_3_8.py
rename to tests/data/cases/preview_context_managers_autodetect_38.py
index 79e438b995e742fa7887d1a1555dff53aa22cfcb..25217a406042c864dc9fdc4adc8dc2558e72147d 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview
 # This file doesn't use any Python 3.9+ only grammars.
 
 
 # This file doesn't use any Python 3.9+ only grammars.
 
 
similarity index 93%
rename from tests/data/preview_context_managers/auto_detect/features_3_9.py
rename to tests/data/cases/preview_context_managers_autodetect_39.py
index 0d28f9931081ba153cf34d2b8fd7da57fda802dd..3f72e48db9d5d876224d8e2230cfffe5d150f26a 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview --minimum-version=3.9
 # This file uses parenthesized context managers introduced in Python 3.9.
 
 
 # This file uses parenthesized context managers introduced in Python 3.9.
 
 
similarity index 98%
rename from tests/data/preview/dummy_implementations.py
rename to tests/data/cases/preview_dummy_implementations.py
index e07c25ed129f1f70d6146e623a29f7957b8e33be..98b69bf87b230ed5886e19462848689f9d460960 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview
 from typing import NoReturn, Protocol, Union, overload
 
 
 from typing import NoReturn, Protocol, Union, overload
 
 
similarity index 96%
rename from tests/data/preview/format_unicode_escape_seq.py
rename to tests/data/cases/preview_format_unicode_escape_seq.py
index 3440696c3039191b1c4f74ad0c111b62b7882f8d..65c3d8d166edd5ce8f4f69a6745ad2a345e4acca 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview
 x = "\x1F"
 x = "\\x1B"
 x = "\\\x1B"
 x = "\x1F"
 x = "\\x1B"
 x = "\\\x1B"
similarity index 99%
rename from tests/data/preview/long_dict_values.py
rename to tests/data/cases/preview_long_dict_values.py
index 4c515180028f1300a52f51a9298e1d1f11fce172..fbbacd13d1d959c288d434e485fa5ee52d5a5cc1 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview
 my_dict = {
     "something_something":
         r"Lorem ipsum dolor sit amet, an sed convenire eloquentiam \t"
 my_dict = {
     "something_something":
         r"Lorem ipsum dolor sit amet, an sed convenire eloquentiam \t"
similarity index 99%
rename from tests/data/preview/long_strings.py
rename to tests/data/cases/preview_long_strings.py
index 059148729d57ed784eb3dc015426475a8882ad1b..5519f0987741967c27c60adc231c018f1b6cfbac 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview
 x = "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three."
 
 x += "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three."
 x = "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three."
 
 x += "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three."
similarity index 96%
rename from tests/data/preview/long_strings__east_asian_width.py
rename to tests/data/cases/preview_long_strings__east_asian_width.py
index fb66a78ed8b4ffb6a698ac410eec36ead203d9d8..d190f422a60bf3f119016d13fa1d0fc6d34333eb 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview\r
 # The following strings do not have not-so-many chars, but are long enough\r
 # when these are rendered in a monospace font (if the renderer respects\r
 # Unicode East Asian Width properties).\r
 # The following strings do not have not-so-many chars, but are long enough\r
 # when these are rendered in a monospace font (if the renderer respects\r
 # Unicode East Asian Width properties).\r
similarity index 99%
rename from tests/data/preview/long_strings__edge_case.py
rename to tests/data/cases/preview_long_strings__edge_case.py
index 2bc0b6ed32885a7bac4c816d6bcd3c3e4ce6fcca..a8e8971968cffff7a5e4d355bc2ef8135b92702e 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview
 some_variable = "This string is long but not so long that it needs to be split just yet"
 some_variable = 'This string is long but not so long that it needs to be split just yet'
 some_variable = "This string is long, just long enough that it needs to be split, u get?"
 some_variable = "This string is long but not so long that it needs to be split just yet"
 some_variable = 'This string is long but not so long that it needs to be split just yet'
 some_variable = "This string is long, just long enough that it needs to be split, u get?"
similarity index 99%
rename from tests/data/preview/long_strings__regression.py
rename to tests/data/cases/preview_long_strings__regression.py
index 5f0646e6029bcab434b9e51749c7f514c843cca3..40d5e745cc82bdaf091cfa71feded01c77724f41 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview
 class A:
     def foo():
         result = type(message)("")
 class A:
     def foo():
         result = type(message)("")
similarity index 98%
rename from tests/data/preview/long_strings__type_annotations.py
rename to tests/data/cases/preview_long_strings__type_annotations.py
index 45de882d02c079e9b8e84e424e25c9530a7e8f9f..8beb877bdd1e02bbc07e0ea723dcd351715d7955 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview
 def func(
     arg1,
     arg2,
 def func(
     arg1,
     arg2,
similarity index 99%
rename from tests/data/preview/multiline_strings.py
rename to tests/data/cases/preview_multiline_strings.py
index bb517d128e29e1141f873674b28f537d84f3ff16..dec4ef2e548d0095b275035a4e74d36abe36b0c2 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview
 """cow
 say""",
 call(3, "dogsay", textwrap.dedent("""dove
 """cow
 say""",
 call(3, "dogsay", textwrap.dedent("""dove
similarity index 97%
rename from tests/data/preview/no_blank_line_before_docstring.py
rename to tests/data/cases/preview_no_blank_line_before_docstring.py
index a37362de100df9805a33f6d9cca1850396bd9250..303035a7efbdad5275d8b84025484d7fc63f9fe5 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview
 def line_before_docstring():
 
     """Please move me up"""
 def line_before_docstring():
 
     """Please move me up"""
similarity index 75%
rename from tests/data/preview/pep_572.py
rename to tests/data/cases/preview_pep_572.py
index a50e130ad9c4e69c560d793689db455c8f2cc7d1..8e801ff6cdc3df0f6ac51582a2936a634ab8bc36 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview
 x[(a:=0):]
 x[:(a:=0)]
 
 x[(a:=0):]
 x[:(a:=0)]
 
similarity index 96%
rename from tests/data/preview/percent_precedence.py
rename to tests/data/cases/preview_percent_precedence.py
index b895443fb46bbf372727bef666a1c3e23deaa536..aeaf450ff5ea4b419654a9983bc196153fe5c6d7 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview
 ("" % a) ** 2
 ("" % a)[0]
 ("" % a)()
 ("" % a) ** 2
 ("" % a)[0]
 ("" % a)()
similarity index 99%
rename from tests/data/preview/prefer_rhs_split.py
rename to tests/data/cases/preview_prefer_rhs_split.py
index a809eacc773c7b1d9272820b8fa57cdd1f021b0c..c732c33b53a8f3d36ef0c71888d0acd1d94608fd 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview
 first_item, second_item = (
     some_looooooooong_module.some_looooooooooooooong_function_name(
         first_argument, second_argument, third_argument
 first_item, second_item = (
     some_looooooooong_module.some_looooooooooooooong_function_name(
         first_argument, second_argument, third_argument
similarity index 97%
rename from tests/data/preview/return_annotation_brackets_string.py
rename to tests/data/cases/preview_return_annotation_brackets_string.py
index 9148bd045bc8ade46c801f4b1316c82d29d9b12b..fea0ea6839a6574f2472a390ae876014d18d3da9 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview
 # Long string example
 def frobnicate() -> "ThisIsTrulyUnreasonablyExtremelyLongClassName | list[ThisIsTrulyUnreasonablyExtremelyLongClassName]":
     pass
 # Long string example
 def frobnicate() -> "ThisIsTrulyUnreasonablyExtremelyLongClassName | list[ThisIsTrulyUnreasonablyExtremelyLongClassName]":
     pass
similarity index 97%
rename from tests/data/preview/trailing_comma.py
rename to tests/data/cases/preview_trailing_comma.py
index 5b09c6646062998e81b428b891e5cf83f0ee2226..bba7e7ad16d29bc9a76e0be0ddc341bace1f2d79 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview
 e = {
     "a": fun(msg, "ts"),
     "longggggggggggggggid": ...,
 e = {
     "a": fun(msg, "ts"),
     "longggggggggggggggid": ...,
similarity index 77%
rename from tests/data/preview_py_310/pep_572.py
rename to tests/data/cases/py310_pep572.py
index 78d4e9e4506aa371b03ad2b68b7762a43305295c..172be3898d6612fb71f64bea6315c30a68497a8f 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --preview --minimum-version=3.10
 x[a:=0]
 x[a := 0]
 x[a := 0, b := 1]
 x[a:=0]
 x[a := 0]
 x[a := 0, b := 1]
similarity index 95%
rename from tests/data/py_37/python37.py
rename to tests/data/cases/python37.py
index dab8b404a739c57f5258694e28ebe65bd9714462..3f61106c45dc96a8731bac308b0cdb5676ffb8a4 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.7
+# flags: --minimum-version=3.7
 
 
 def f():
 
 
 def f():
@@ -33,9 +33,6 @@ def make_arange(n):
 # output
 
 
 # output
 
 
-#!/usr/bin/env python3.7
-
-
 def f():
     return (i * 2 async for i in arange(42))
 
 def f():
     return (i * 2 async for i in arange(42))
 
similarity index 93%
rename from tests/data/py_38/python38.py
rename to tests/data/cases/python38.py
index 63b0588bc27a1affe2d5a955537728ad8f95f5be..919ea6aeed475f0bc27ba47e90c8e1d94f0f314b 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.8
+# flags: --minimum-version=3.8
 
 
 def starred_return():
 
 
 def starred_return():
@@ -22,9 +22,6 @@ def t():
 # output
 
 
 # output
 
 
-#!/usr/bin/env python3.8
-
-
 def starred_return():
     my_list = ["value2", "value3"]
     return "value1", *my_list
 def starred_return():
     my_list = ["value2", "value3"]
     return "value1", *my_list
similarity index 91%
rename from tests/data/py_39/python39.py
rename to tests/data/cases/python39.py
index ae67c2257ebba5802cad6b259ca798574dd15515..1b9536c1529314c5ac26fd5ed3af1b8d98f658ea 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.9
+# flags: --minimum-version=3.9
 
 @relaxed_decorator[0]
 def f():
 
 @relaxed_decorator[0]
 def f():
@@ -14,10 +14,6 @@ def f():
 
 # output
 
 
 # output
 
-
-#!/usr/bin/env python3.9
-
-
 @relaxed_decorator[0]
 def f():
     ...
 @relaxed_decorator[0]
 def f():
     ...
similarity index 88%
rename from tests/data/py_310/remove_newline_after_match.py
rename to tests/data/cases/remove_newline_after_match.py
index f7bcfbf27a232a17f8c4fcd2f0b9c433ca7f5d8c..fe6592b664d84ae3fe51d6cbb6f83c405d7a8900 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --minimum-version=3.10
 def http_status(status):
 
     match status:
 def http_status(status):
 
     match status:
similarity index 98%
rename from tests/data/py_39/remove_with_brackets.py
rename to tests/data/cases/remove_with_brackets.py
index ea58ab93a16f602f8a048cf0acd981dc3885cb20..3ee64902a3028bf6d9f04a06de43ebf389e3eab7 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --minimum-version=3.9
 with (open("bla.txt")):
     pass
 
 with (open("bla.txt")):
     pass
 
similarity index 97%
rename from tests/data/simple_cases/skip_magic_trailing_comma.py
rename to tests/data/cases/skip_magic_trailing_comma.py
index c020db798649a7003df7660710be4ee6573c8573..4dda5df40f0f252cfa4937efc5caa5e1b1bb5547 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --skip-magic-trailing-comma
 # We should not remove the trailing comma in a single-element subscript.
 a: tuple[int,]
 b = tuple[int,]
 # We should not remove the trailing comma in a single-element subscript.
 a: tuple[int,]
 b = tuple[int,]
similarity index 92%
rename from tests/data/py_310/starred_for_target.py
rename to tests/data/cases/starred_for_target.py
index 8fc8e059ed37347198db1a5b37324aba3819b5a7..13e517816d65fd63401228b0832c47dac07e854b 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --minimum-version=3.10
 for x in *a, *b:
     print(x)
 
 for x in *a, *b:
     print(x)
 
similarity index 99%
rename from tests/data/miscellaneous/stub.pyi
rename to tests/data/cases/stub.py
index af2cd2c2c026e64e4f254954baf0cf7baad614e1..f3828d55ba2b302c4521ac238a1dbb96d897667b 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --pyi
 X: int
 
 def f(): ...
 X: int
 
 def f(): ...
similarity index 81%
rename from tests/data/py_312/type_aliases.py
rename to tests/data/cases/type_aliases.py
index 84e07e50fe2db8ec6eb0ad68f551b0d96c271942..a3c1931c9fc08d63ca438a770dee65b64ce94249 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --minimum-version=3.12
 type A=int
 type Gen[T]=list[T]
 
 type A=int
 type Gen[T]=list[T]
 
similarity index 97%
rename from tests/data/py_312/type_params.py
rename to tests/data/cases/type_params.py
index 5f8ec43267c31f91a86f334b74318eac3fee5b95..720a775ef31bd8ef633fbc47d1e524c63207fdca 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --minimum-version=3.12
 def func  [T ](): pass
 async def func [ T ] (): pass
 class C[ T ] : pass
 def func  [T ](): pass
 async def func [ T ] (): pass
 class C[ T ] : pass
index 07ed93c6879363f22cde9de9e3c3c393aa2d41a1..40caf30a9831ded54ce91b8d0d4932d07a9c517a 100644 (file)
@@ -1,3 +1,4 @@
+# flags: --pyi
 from typing import Union
 
 @bird
 from typing import Union
 
 @bird
index c665eee3a6c20644e72a9728309c4c0f95e2b24d..bb5cc1e08c75a3ddb677f920931ce0f93351a88a 100644 (file)
@@ -187,7 +187,9 @@ class BlackTestCase(BlackBaseTestCase):
         )
 
     def test_piping(self) -> None:
         )
 
     def test_piping(self) -> None:
-        source, expected = read_data_from_file(PROJECT_ROOT / "src/black/__init__.py")
+        _, source, expected = read_data_from_file(
+            PROJECT_ROOT / "src/black/__init__.py"
+        )
         result = BlackRunner().invoke(
             black.main,
             [
         result = BlackRunner().invoke(
             black.main,
             [
@@ -209,8 +211,8 @@ class BlackTestCase(BlackBaseTestCase):
             r"(STDIN|STDOUT)\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\.\d\d\d\d\d\d"
             r"\+\d\d:\d\d"
         )
             r"(STDIN|STDOUT)\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\.\d\d\d\d\d\d"
             r"\+\d\d:\d\d"
         )
-        source, _ = read_data("simple_cases", "expression.py")
-        expected, _ = read_data("simple_cases", "expression.diff")
+        source, _ = read_data("cases", "expression.py")
+        expected, _ = read_data("cases", "expression.diff")
         args = [
             "-",
             "--fast",
         args = [
             "-",
             "--fast",
@@ -227,7 +229,7 @@ class BlackTestCase(BlackBaseTestCase):
         self.assertEqual(expected, actual)
 
     def test_piping_diff_with_color(self) -> None:
         self.assertEqual(expected, actual)
 
     def test_piping_diff_with_color(self) -> None:
-        source, _ = read_data("simple_cases", "expression.py")
+        source, _ = read_data("cases", "expression.py")
         args = [
             "-",
             "--fast",
         args = [
             "-",
             "--fast",
@@ -263,7 +265,7 @@ class BlackTestCase(BlackBaseTestCase):
         black.assert_stable(source, actual, black.FileMode())
 
     def test_pep_572_version_detection(self) -> None:
         black.assert_stable(source, actual, black.FileMode())
 
     def test_pep_572_version_detection(self) -> None:
-        source, _ = read_data("py_38", "pep_572")
+        source, _ = read_data("cases", "pep_572")
         root = black.lib2to3_parse(source)
         features = black.get_features_used(root)
         self.assertIn(black.Feature.ASSIGNMENT_EXPRESSIONS, features)
         root = black.lib2to3_parse(source)
         features = black.get_features_used(root)
         self.assertIn(black.Feature.ASSIGNMENT_EXPRESSIONS, features)
@@ -272,7 +274,7 @@ class BlackTestCase(BlackBaseTestCase):
 
     def test_pep_695_version_detection(self) -> None:
         for file in ("type_aliases", "type_params"):
 
     def test_pep_695_version_detection(self) -> None:
         for file in ("type_aliases", "type_params"):
-            source, _ = read_data("py_312", file)
+            source, _ = read_data("cases", file)
             root = black.lib2to3_parse(source)
             features = black.get_features_used(root)
             self.assertIn(black.Feature.TYPE_PARAMS, features)
             root = black.lib2to3_parse(source)
             features = black.get_features_used(root)
             self.assertIn(black.Feature.TYPE_PARAMS, features)
@@ -280,7 +282,7 @@ class BlackTestCase(BlackBaseTestCase):
             self.assertIn(black.TargetVersion.PY312, versions)
 
     def test_expression_ff(self) -> None:
             self.assertIn(black.TargetVersion.PY312, versions)
 
     def test_expression_ff(self) -> None:
-        source, expected = read_data("simple_cases", "expression.py")
+        source, expected = read_data("cases", "expression.py")
         tmp_file = Path(black.dump_to_file(source))
         try:
             self.assertTrue(ff(tmp_file, write_back=black.WriteBack.YES))
         tmp_file = Path(black.dump_to_file(source))
         try:
             self.assertTrue(ff(tmp_file, write_back=black.WriteBack.YES))
@@ -293,8 +295,8 @@ class BlackTestCase(BlackBaseTestCase):
             black.assert_stable(source, actual, DEFAULT_MODE)
 
     def test_expression_diff(self) -> None:
             black.assert_stable(source, actual, DEFAULT_MODE)
 
     def test_expression_diff(self) -> None:
-        source, _ = read_data("simple_cases", "expression.py")
-        expected, _ = read_data("simple_cases", "expression.diff")
+        source, _ = read_data("cases", "expression.py")
+        expected, _ = read_data("cases", "expression.diff")
         tmp_file = Path(black.dump_to_file(source))
         diff_header = re.compile(
             rf"{re.escape(str(tmp_file))}\t\d\d\d\d-\d\d-\d\d "
         tmp_file = Path(black.dump_to_file(source))
         diff_header = re.compile(
             rf"{re.escape(str(tmp_file))}\t\d\d\d\d-\d\d-\d\d "
@@ -319,8 +321,8 @@ class BlackTestCase(BlackBaseTestCase):
             self.assertEqual(expected, actual, msg)
 
     def test_expression_diff_with_color(self) -> None:
             self.assertEqual(expected, actual, msg)
 
     def test_expression_diff_with_color(self) -> None:
-        source, _ = read_data("simple_cases", "expression.py")
-        expected, _ = read_data("simple_cases", "expression.diff")
+        source, _ = read_data("cases", "expression.py")
+        expected, _ = read_data("cases", "expression.diff")
         tmp_file = Path(black.dump_to_file(source))
         try:
             result = BlackRunner().invoke(
         tmp_file = Path(black.dump_to_file(source))
         try:
             result = BlackRunner().invoke(
@@ -339,7 +341,7 @@ class BlackTestCase(BlackBaseTestCase):
         self.assertIn("\033[0m", actual)
 
     def test_detect_pos_only_arguments(self) -> None:
         self.assertIn("\033[0m", actual)
 
     def test_detect_pos_only_arguments(self) -> None:
-        source, _ = read_data("py_38", "pep_570")
+        source, _ = read_data("cases", "pep_570")
         root = black.lib2to3_parse(source)
         features = black.get_features_used(root)
         self.assertIn(black.Feature.POS_ONLY_ARGUMENTS, features)
         root = black.lib2to3_parse(source)
         features = black.get_features_used(root)
         self.assertIn(black.Feature.POS_ONLY_ARGUMENTS, features)
@@ -401,7 +403,7 @@ class BlackTestCase(BlackBaseTestCase):
             self.assertEqual(test_file.read_bytes(), expected)
 
     def test_skip_magic_trailing_comma(self) -> None:
             self.assertEqual(test_file.read_bytes(), expected)
 
     def test_skip_magic_trailing_comma(self) -> None:
-        source, _ = read_data("simple_cases", "expression")
+        source, _ = read_data("cases", "expression")
         expected, _ = read_data(
             "miscellaneous", "expression_skip_magic_trailing_comma.diff"
         )
         expected, _ = read_data(
             "miscellaneous", "expression_skip_magic_trailing_comma.diff"
         )
@@ -433,7 +435,7 @@ class BlackTestCase(BlackBaseTestCase):
     @patch("black.dump_to_file", dump_to_stderr)
     def test_async_as_identifier(self) -> None:
         source_path = get_case_path("miscellaneous", "async_as_identifier")
     @patch("black.dump_to_file", dump_to_stderr)
     def test_async_as_identifier(self) -> None:
         source_path = get_case_path("miscellaneous", "async_as_identifier")
-        source, expected = read_data_from_file(source_path)
+        _, source, expected = read_data_from_file(source_path)
         actual = fs(source)
         self.assertFormatEqual(expected, actual)
         major, minor = sys.version_info[:2]
         actual = fs(source)
         self.assertFormatEqual(expected, actual)
         major, minor = sys.version_info[:2]
@@ -447,8 +449,8 @@ class BlackTestCase(BlackBaseTestCase):
 
     @patch("black.dump_to_file", dump_to_stderr)
     def test_python37(self) -> None:
 
     @patch("black.dump_to_file", dump_to_stderr)
     def test_python37(self) -> None:
-        source_path = get_case_path("py_37", "python37")
-        source, expected = read_data_from_file(source_path)
+        source_path = get_case_path("cases", "python37")
+        _, source, expected = read_data_from_file(source_path)
         actual = fs(source)
         self.assertFormatEqual(expected, actual)
         major, minor = sys.version_info[:2]
         actual = fs(source)
         self.assertFormatEqual(expected, actual)
         major, minor = sys.version_info[:2]
@@ -884,7 +886,7 @@ class BlackTestCase(BlackBaseTestCase):
         self.assertEqual(black.get_features_used(node), {Feature.NUMERIC_UNDERSCORES})
         node = black.lib2to3_parse("123456\n")
         self.assertEqual(black.get_features_used(node), set())
         self.assertEqual(black.get_features_used(node), {Feature.NUMERIC_UNDERSCORES})
         node = black.lib2to3_parse("123456\n")
         self.assertEqual(black.get_features_used(node), set())
-        source, expected = read_data("simple_cases", "function")
+        source, expected = read_data("cases", "function")
         node = black.lib2to3_parse(source)
         expected_features = {
             Feature.TRAILING_COMMA_IN_CALL,
         node = black.lib2to3_parse(source)
         expected_features = {
             Feature.TRAILING_COMMA_IN_CALL,
@@ -894,7 +896,7 @@ class BlackTestCase(BlackBaseTestCase):
         self.assertEqual(black.get_features_used(node), expected_features)
         node = black.lib2to3_parse(expected)
         self.assertEqual(black.get_features_used(node), expected_features)
         self.assertEqual(black.get_features_used(node), expected_features)
         node = black.lib2to3_parse(expected)
         self.assertEqual(black.get_features_used(node), expected_features)
-        source, expected = read_data("simple_cases", "expression")
+        source, expected = read_data("cases", "expression")
         node = black.lib2to3_parse(source)
         self.assertEqual(black.get_features_used(node), set())
         node = black.lib2to3_parse(expected)
         node = black.lib2to3_parse(source)
         self.assertEqual(black.get_features_used(node), set())
         node = black.lib2to3_parse(expected)
@@ -1109,7 +1111,7 @@ class BlackTestCase(BlackBaseTestCase):
             src1 = get_case_path("miscellaneous", "string_quotes")
             self.invokeBlack([str(src1), "--diff", "--check"], exit_code=1)
             # Files which will not be reformatted.
             src1 = get_case_path("miscellaneous", "string_quotes")
             self.invokeBlack([str(src1), "--diff", "--check"], exit_code=1)
             # Files which will not be reformatted.
-            src2 = get_case_path("simple_cases", "composition")
+            src2 = get_case_path("cases", "composition")
             self.invokeBlack([str(src2), "--diff", "--check"])
             # Multi file command.
             self.invokeBlack([str(src1), str(src2), "--diff", "--check"], exit_code=1)
             self.invokeBlack([str(src2), "--diff", "--check"])
             # Multi file command.
             self.invokeBlack([str(src1), str(src2), "--diff", "--check"], exit_code=1)
@@ -1330,7 +1332,7 @@ class BlackTestCase(BlackBaseTestCase):
             report = MagicMock()
             # Even with an existing file, since we are forcing stdin, black
             # should output to stdout and not modify the file inplace
             report = MagicMock()
             # Even with an existing file, since we are forcing stdin, black
             # should output to stdout and not modify the file inplace
-            p = THIS_DIR / "data" / "simple_cases" / "collections.py"
+            p = THIS_DIR / "data" / "cases" / "collections.py"
             # Make sure is_file actually returns True
             self.assertTrue(p.is_file())
             path = Path(f"__BLACK_STDIN_FILENAME__{p}")
             # Make sure is_file actually returns True
             self.assertTrue(p.is_file())
             path = Path(f"__BLACK_STDIN_FILENAME__{p}")
index dd2126e6bc24d97473c89153a3043af2f3f9a024..c0152de73e6a83e587cbe28001b27f438daaa041 100644 (file)
@@ -104,7 +104,7 @@ class BlackDTestCase(AioHTTPTestCase):  # type: ignore[misc]
 
     @unittest_run_loop
     async def test_blackd_pyi(self) -> None:
 
     @unittest_run_loop
     async def test_blackd_pyi(self) -> None:
-        source, expected = read_data("miscellaneous", "stub.pyi")
+        source, expected = read_data("cases", "stub.py")
         response = await self.client.post(
             "/", data=source, headers={blackd.PYTHON_VARIANT_HEADER: "pyi"}
         )
         response = await self.client.post(
             "/", data=source, headers={blackd.PYTHON_VARIANT_HEADER: "pyi"}
         )
index ff358d59c945c2502e33825d3cfe343e347882d3..4e863c6c54b4ddb843434c4d4586531a877645d5 100644 (file)
@@ -1,4 +1,3 @@
-import re
 from dataclasses import replace
 from typing import Any, Iterator
 from unittest.mock import patch
 from dataclasses import replace
 from typing import Any, Iterator
 from unittest.mock import patch
@@ -6,13 +5,13 @@ from unittest.mock import patch
 import pytest
 
 import black
 import pytest
 
 import black
+from black.mode import TargetVersion
 from tests.util import (
 from tests.util import (
-    DEFAULT_MODE,
-    PY36_VERSIONS,
     all_data_cases,
     assert_format,
     dump_to_stderr,
     read_data,
     all_data_cases,
     assert_format,
     dump_to_stderr,
     read_data,
+    read_data_with_mode,
 )
 
 
 )
 
 
@@ -22,61 +21,33 @@ def patch_dump_to_file(request: Any) -> Iterator[None]:
         yield
 
 
         yield
 
 
-def check_file(
-    subdir: str, filename: str, mode: black.Mode, *, data: bool = True
-) -> None:
-    source, expected = read_data(subdir, filename, data=data)
-    assert_format(source, expected, mode, fast=False)
+def check_file(subdir: str, filename: str, *, data: bool = True) -> None:
+    args, source, expected = read_data_with_mode(subdir, filename, data=data)
+    assert_format(
+        source,
+        expected,
+        args.mode,
+        fast=args.fast,
+        minimum_version=args.minimum_version,
+    )
+    if args.minimum_version is not None:
+        major, minor = args.minimum_version
+        target_version = TargetVersion[f"PY{major}{minor}"]
+        mode = replace(args.mode, target_versions={target_version})
+        assert_format(
+            source, expected, mode, fast=args.fast, minimum_version=args.minimum_version
+        )
 
 
 @pytest.mark.filterwarnings("ignore:invalid escape sequence.*:DeprecationWarning")
 
 
 @pytest.mark.filterwarnings("ignore:invalid escape sequence.*:DeprecationWarning")
-@pytest.mark.parametrize("filename", all_data_cases("simple_cases"))
+@pytest.mark.parametrize("filename", all_data_cases("cases"))
 def test_simple_format(filename: str) -> None:
 def test_simple_format(filename: str) -> None:
-    magic_trailing_comma = filename != "skip_magic_trailing_comma"
-    mode = black.Mode(
-        magic_trailing_comma=magic_trailing_comma, is_pyi=filename.endswith("_pyi")
-    )
-    check_file("simple_cases", filename, mode)
-
-
-@pytest.mark.parametrize("filename", all_data_cases("preview"))
-def test_preview_format(filename: str) -> None:
-    check_file("preview", filename, black.Mode(preview=True))
-
-
-def test_preview_context_managers_targeting_py38() -> None:
-    source, expected = read_data("preview_context_managers", "targeting_py38.py")
-    mode = black.Mode(preview=True, target_versions={black.TargetVersion.PY38})
-    assert_format(source, expected, mode, minimum_version=(3, 8))
-
-
-def test_preview_context_managers_targeting_py39() -> None:
-    source, expected = read_data("preview_context_managers", "targeting_py39.py")
-    mode = black.Mode(preview=True, target_versions={black.TargetVersion.PY39})
-    assert_format(source, expected, mode, minimum_version=(3, 9))
-
-
-@pytest.mark.parametrize("filename", all_data_cases("preview_py_310"))
-def test_preview_python_310(filename: str) -> None:
-    source, expected = read_data("preview_py_310", filename)
-    mode = black.Mode(target_versions={black.TargetVersion.PY310}, preview=True)
-    assert_format(source, expected, mode, minimum_version=(3, 10))
-
-
-@pytest.mark.parametrize(
-    "filename", all_data_cases("preview_context_managers/auto_detect")
-)
-def test_preview_context_managers_auto_detect(filename: str) -> None:
-    match = re.match(r"features_3_(\d+)", filename)
-    assert match is not None, "Unexpected filename format: %s" % filename
-    source, expected = read_data("preview_context_managers/auto_detect", filename)
-    mode = black.Mode(preview=True)
-    assert_format(source, expected, mode, minimum_version=(3, int(match.group(1))))
+    check_file("cases", filename)
 
 
 # =============== #
 
 
 # =============== #
-# Complex cases
-# ============= #
+# Unusual cases
+# =============== #
 
 
 def test_empty() -> None:
 
 
 def test_empty() -> None:
@@ -84,48 +55,6 @@ def test_empty() -> None:
     assert_format(source, expected)
 
 
     assert_format(source, expected)
 
 
-@pytest.mark.parametrize("filename", all_data_cases("py_36"))
-def test_python_36(filename: str) -> None:
-    source, expected = read_data("py_36", filename)
-    mode = black.Mode(target_versions=PY36_VERSIONS)
-    assert_format(source, expected, mode, minimum_version=(3, 6))
-
-
-@pytest.mark.parametrize("filename", all_data_cases("py_37"))
-def test_python_37(filename: str) -> None:
-    source, expected = read_data("py_37", filename)
-    mode = black.Mode(target_versions={black.TargetVersion.PY37})
-    assert_format(source, expected, mode, minimum_version=(3, 7))
-
-
-@pytest.mark.parametrize("filename", all_data_cases("py_38"))
-def test_python_38(filename: str) -> None:
-    source, expected = read_data("py_38", filename)
-    mode = black.Mode(target_versions={black.TargetVersion.PY38})
-    assert_format(source, expected, mode, minimum_version=(3, 8))
-
-
-@pytest.mark.parametrize("filename", all_data_cases("py_39"))
-def test_python_39(filename: str) -> None:
-    source, expected = read_data("py_39", filename)
-    mode = black.Mode(target_versions={black.TargetVersion.PY39})
-    assert_format(source, expected, mode, minimum_version=(3, 9))
-
-
-@pytest.mark.parametrize("filename", all_data_cases("py_310"))
-def test_python_310(filename: str) -> None:
-    source, expected = read_data("py_310", filename)
-    mode = black.Mode(target_versions={black.TargetVersion.PY310})
-    assert_format(source, expected, mode, minimum_version=(3, 10))
-
-
-@pytest.mark.parametrize("filename", all_data_cases("py_310"))
-def test_python_310_without_target_version(filename: str) -> None:
-    source, expected = read_data("py_310", filename)
-    mode = black.Mode()
-    assert_format(source, expected, mode, minimum_version=(3, 10))
-
-
 def test_patma_invalid() -> None:
     source, expected = read_data("miscellaneous", "pattern_matching_invalid")
     mode = black.Mode(target_versions={black.TargetVersion.PY310})
 def test_patma_invalid() -> None:
     source, expected = read_data("miscellaneous", "pattern_matching_invalid")
     mode = black.Mode(target_versions={black.TargetVersion.PY310})
@@ -133,82 +62,3 @@ def test_patma_invalid() -> None:
         assert_format(source, expected, mode, minimum_version=(3, 10))
 
     exc_info.match("Cannot parse: 10:11")
         assert_format(source, expected, mode, minimum_version=(3, 10))
 
     exc_info.match("Cannot parse: 10:11")
-
-
-@pytest.mark.parametrize("filename", all_data_cases("py_311"))
-def test_python_311(filename: str) -> None:
-    source, expected = read_data("py_311", filename)
-    mode = black.Mode(target_versions={black.TargetVersion.PY311})
-    assert_format(source, expected, mode, minimum_version=(3, 11))
-
-
-@pytest.mark.parametrize("filename", all_data_cases("py_312"))
-def test_python_312(filename: str) -> None:
-    source, expected = read_data("py_312", filename)
-    mode = black.Mode(target_versions={black.TargetVersion.PY312})
-    assert_format(source, expected, mode, minimum_version=(3, 12))
-
-
-@pytest.mark.parametrize("filename", all_data_cases("fast"))
-def test_fast_cases(filename: str) -> None:
-    source, expected = read_data("fast", filename)
-    assert_format(source, expected, fast=True)
-
-
-@pytest.mark.filterwarnings("ignore:invalid escape sequence.*:DeprecationWarning")
-def test_docstring_no_string_normalization() -> None:
-    """Like test_docstring but with string normalization off."""
-    source, expected = read_data("miscellaneous", "docstring_no_string_normalization")
-    mode = replace(DEFAULT_MODE, string_normalization=False)
-    assert_format(source, expected, mode)
-
-
-def test_docstring_line_length_6() -> None:
-    """Like test_docstring but with line length set to 6."""
-    source, expected = read_data("miscellaneous", "linelength6")
-    mode = black.Mode(line_length=6)
-    assert_format(source, expected, mode)
-
-
-def test_preview_docstring_no_string_normalization() -> None:
-    """
-    Like test_docstring but with string normalization off *and* the preview style
-    enabled.
-    """
-    source, expected = read_data(
-        "miscellaneous", "docstring_preview_no_string_normalization"
-    )
-    mode = replace(DEFAULT_MODE, string_normalization=False, preview=True)
-    assert_format(source, expected, mode)
-
-
-def test_long_strings_flag_disabled() -> None:
-    """Tests for turning off the string processing logic."""
-    source, expected = read_data("miscellaneous", "long_strings_flag_disabled")
-    mode = replace(DEFAULT_MODE, experimental_string_processing=False)
-    assert_format(source, expected, mode)
-
-
-def test_stub() -> None:
-    mode = replace(DEFAULT_MODE, is_pyi=True)
-    source, expected = read_data("miscellaneous", "stub.pyi")
-    assert_format(source, expected, mode)
-
-
-def test_nested_stub() -> None:
-    mode = replace(DEFAULT_MODE, is_pyi=True, preview=True)
-    source, expected = read_data("miscellaneous", "nested_stub.pyi")
-    assert_format(source, expected, mode)
-
-
-def test_power_op_newline() -> None:
-    # requires line_length=0
-    source, expected = read_data("miscellaneous", "power_op_newline")
-    assert_format(source, expected, mode=black.Mode(line_length=0))
-
-
-def test_type_comment_syntax_error() -> None:
-    """Test that black is able to format python code with type comment syntax errors."""
-    source, expected = read_data("type_comments", "type_comment_syntax_error")
-    assert_format(source, expected)
-    black.assert_equivalent(source, expected)
index 541d21da4dfd9dddb1168cfdd18b2ce10e8f023b..a31ae0992c2886936fdc0bdb52c9c9213203df7e 100644 (file)
@@ -1,13 +1,17 @@
+import argparse
+import functools
 import os
 import os
+import shlex
 import sys
 import unittest
 from contextlib import contextmanager
 import sys
 import unittest
 from contextlib import contextmanager
-from dataclasses import replace
+from dataclasses import dataclass, field, replace
 from functools import partial
 from pathlib import Path
 from typing import Any, Iterator, List, Optional, Tuple
 
 import black
 from functools import partial
 from pathlib import Path
 from typing import Any, Iterator, List, Optional, Tuple
 
 import black
+from black.const import DEFAULT_LINE_LENGTH
 from black.debug import DebugVisitor
 from black.mode import TargetVersion
 from black.output import diff, err, out
 from black.debug import DebugVisitor
 from black.mode import TargetVersion
 from black.output import diff, err, out
@@ -35,6 +39,13 @@ ff = partial(black.format_file_in_place, mode=DEFAULT_MODE, fast=True)
 fs = partial(black.format_str, mode=DEFAULT_MODE)
 
 
 fs = partial(black.format_str, mode=DEFAULT_MODE)
 
 
+@dataclass
+class TestCaseArgs:
+    mode: black.Mode = field(default_factory=black.Mode)
+    fast: bool = False
+    minimum_version: Optional[Tuple[int, int]] = None
+
+
 def _assert_format_equal(expected: str, actual: str) -> None:
     if actual != expected and (conftest.PRINT_FULL_TREE or conftest.PRINT_TREE_DIFF):
         bdv: DebugVisitor[Any]
 def _assert_format_equal(expected: str, actual: str) -> None:
     if actual != expected and (conftest.PRINT_FULL_TREE or conftest.PRINT_TREE_DIFF):
         bdv: DebugVisitor[Any]
@@ -178,18 +189,85 @@ def get_case_path(
     return case_path
 
 
     return case_path
 
 
+def read_data_with_mode(
+    subdir_name: str, name: str, data: bool = True
+) -> Tuple[TestCaseArgs, str, str]:
+    """read_data_with_mode('test_name') -> Mode(), 'input', 'output'"""
+    return read_data_from_file(get_case_path(subdir_name, name, data))
+
+
 def read_data(subdir_name: str, name: str, data: bool = True) -> Tuple[str, str]:
     """read_data('test_name') -> 'input', 'output'"""
 def read_data(subdir_name: str, name: str, data: bool = True) -> Tuple[str, str]:
     """read_data('test_name') -> 'input', 'output'"""
-    return read_data_from_file(get_case_path(subdir_name, name, data))
+    _, input, output = read_data_with_mode(subdir_name, name, data)
+    return input, output
+
+
+def _parse_minimum_version(version: str) -> Tuple[int, int]:
+    major, minor = version.split(".")
+    return int(major), int(minor)
 
 
 
 
-def read_data_from_file(file_name: Path) -> Tuple[str, str]:
+@functools.lru_cache()
+def get_flags_parser() -> argparse.ArgumentParser:
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+        "--target-version",
+        action="append",
+        type=lambda val: TargetVersion[val.upper()],
+        default=(),
+    )
+    parser.add_argument("--line-length", default=DEFAULT_LINE_LENGTH, type=int)
+    parser.add_argument(
+        "--skip-string-normalization", default=False, action="store_true"
+    )
+    parser.add_argument("--pyi", default=False, action="store_true")
+    parser.add_argument("--ipynb", default=False, action="store_true")
+    parser.add_argument(
+        "--skip-magic-trailing-comma", default=False, action="store_true"
+    )
+    parser.add_argument("--preview", default=False, action="store_true")
+    parser.add_argument("--fast", default=False, action="store_true")
+    parser.add_argument(
+        "--minimum-version",
+        type=_parse_minimum_version,
+        default=None,
+        help=(
+            "Minimum version of Python where this test case is parseable. If this is"
+            " set, the test case will be run twice: once with the specified"
+            " --target-version, and once with --target-version set to exactly the"
+            " specified version. This ensures that Black's autodetection of the target"
+            " version works correctly."
+        ),
+    )
+    return parser
+
+
+def parse_mode(flags_line: str) -> TestCaseArgs:
+    parser = get_flags_parser()
+    args = parser.parse_args(shlex.split(flags_line))
+    mode = black.Mode(
+        target_versions=set(args.target_version),
+        line_length=args.line_length,
+        string_normalization=not args.skip_string_normalization,
+        is_pyi=args.pyi,
+        is_ipynb=args.ipynb,
+        magic_trailing_comma=not args.skip_magic_trailing_comma,
+        preview=args.preview,
+    )
+    return TestCaseArgs(mode=mode, fast=args.fast, minimum_version=args.minimum_version)
+
+
+def read_data_from_file(file_name: Path) -> Tuple[TestCaseArgs, str, str]:
     with open(file_name, "r", encoding="utf8") as test:
         lines = test.readlines()
     _input: List[str] = []
     _output: List[str] = []
     result = _input
     with open(file_name, "r", encoding="utf8") as test:
         lines = test.readlines()
     _input: List[str] = []
     _output: List[str] = []
     result = _input
+    mode = TestCaseArgs()
     for line in lines:
     for line in lines:
+        if not _input and line.startswith("# flags: "):
+            mode = parse_mode(line[len("# flags: ") :])
+            continue
         line = line.replace(EMPTY_LINE, "")
         if line.rstrip() == "# output":
             result = _output
         line = line.replace(EMPTY_LINE, "")
         if line.rstrip() == "# output":
             result = _output
@@ -199,7 +277,7 @@ def read_data_from_file(file_name: Path) -> Tuple[str, str]:
     if _input and not _output:
         # If there's no output marker, treat the entire file as already pre-formatted.
         _output = _input[:]
     if _input and not _output:
         # If there's no output marker, treat the entire file as already pre-formatted.
         _output = _input[:]
-    return "".join(_input).strip() + "\n", "".join(_output).strip() + "\n"
+    return mode, "".join(_input).strip() + "\n", "".join(_output).strip() + "\n"
 
 
 def read_jupyter_notebook(subdir_name: str, name: str, data: bool = True) -> str:
 
 
 def read_jupyter_notebook(subdir_name: str, name: str, data: bool = True) -> str: