Merge pull request #779 from pre-commit/test-conventions

name-test-tests: add --pytest-test-first convention
diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml
index c28c1c8..1a6056b 100644
--- a/.pre-commit-hooks.yaml
+++ b/.pre-commit-hooks.yaml
@@ -164,7 +164,7 @@
     types: [text]
 -   id: name-tests-test
     name: python tests naming
-    description: this verifies that test files are named correctly.
+    description: verifies that test files are named correctly.
     entry: name-tests-test
     language: python
     files: (^|/)tests/.+\.py$
diff --git a/README.md b/README.md
index 2c8cf4f..2819577 100644
--- a/README.md
+++ b/README.md
@@ -142,8 +142,10 @@
       - `no` - Checks if there is any mixed line ending without modifying any file.
 
 #### `name-tests-test`
-Assert that files in tests/ end in `_test.py`.
-  - Use `args: ['--django']` to match `test*.py` instead.
+verifies that test files are named correctly.
+- `--pytest` (the default): ensure tests match `.*_test\.py`
+- `--pytest-test-first`: ensure tests match `test_.*\.py`
+- `--django` / `--unittest`: ensure tests match `test.*\.py`
 
 #### `no-commit-to-branch`
 Protect specific branches from direct checkins.
diff --git a/pre_commit_hooks/tests_should_end_in_test.py b/pre_commit_hooks/tests_should_end_in_test.py
index e1ffe36..e7842af 100644
--- a/pre_commit_hooks/tests_should_end_in_test.py
+++ b/pre_commit_hooks/tests_should_end_in_test.py
@@ -9,23 +9,42 @@
 def main(argv: Sequence[str] | None = None) -> int:
     parser = argparse.ArgumentParser()
     parser.add_argument('filenames', nargs='*')
-    parser.add_argument(
-        '--django', default=False, action='store_true',
-        help='Use Django-style test naming pattern (test*.py)',
+    mutex = parser.add_mutually_exclusive_group()
+    mutex.add_argument(
+        '--pytest',
+        dest='pattern',
+        action='store_const',
+        const=r'.*_test\.py',
+        default=r'.*_test\.py',
+        help='(the default) ensure tests match %(const)s',
+    )
+    mutex.add_argument(
+        '--pytest-test-first',
+        dest='pattern',
+        action='store_const',
+        const=r'test_.*\.py',
+        help='ensure tests match %(const)s',
+    )
+    mutex.add_argument(
+        '--django', '--unittest',
+        dest='pattern',
+        action='store_const',
+        const=r'test.*\.py',
+        help='ensure tests match %(const)s',
     )
     args = parser.parse_args(argv)
 
     retcode = 0
-    test_name_pattern = r'test.*\.py' if args.django else r'.*_test\.py'
+    reg = re.compile(args.pattern)
     for filename in args.filenames:
         base = os.path.basename(filename)
         if (
-                not re.match(test_name_pattern, base) and
+                not reg.fullmatch(base) and
                 not base == '__init__.py' and
                 not base == 'conftest.py'
         ):
             retcode = 1
-            print(f'{filename} does not match pattern "{test_name_pattern}"')
+            print(f'{filename} does not match pattern "{args.pattern}"')
 
     return retcode
 
diff --git a/tests/tests_should_end_in_test_test.py b/tests/tests_should_end_in_test_test.py
index dc3744b..2b5a0de 100644
--- a/tests/tests_should_end_in_test_test.py
+++ b/tests/tests_should_end_in_test_test.py
@@ -43,3 +43,8 @@
 def test_main_django_fails():
     ret = main(['--django', 'foo_test.py', 'test_bar.py', 'test_baz.py'])
     assert ret == 1
+
+
+def test_main_pytest_test_first():
+    assert main(['--pytest-test-first', 'test_foo.py']) == 0
+    assert main(['--pytest-test-first', 'foo_test.py']) == 1