Repository: pre-commit/pre-commit-hooks

Issue:
`file-contents-sorter` Not working same way everytime
I get strange issue that file-contents-sorter hook does not work same way everytime. I made little test case which trickers the issue. If i run this 10 times it will sometimes pass and sometimes not. I did not have time to look what problem might be.

Add this to `file_contents_sorter_test.py`
```
(
    b'pre\nPre\n',
    ['--unique', '--ignore-case'],
    PASS,
    b'pre\nPre\n',
),
```

And run it with
`for run in {1..10}; do pytest tests/file_contents_sorter_test.py; done`
This gives me that about 30% pass and 70% fails


Discussion:

Patch:
diff --git a/pre_commit_hooks/file_contents_sorter.py b/pre_commit_hooks/file_contents_sorter.py
index bfbeb25..4435d6a 100644
--- a/pre_commit_hooks/file_contents_sorter.py
+++ b/pre_commit_hooks/file_contents_sorter.py
@@ -54,18 +54,21 @@ def sort_file_contents(
 def main(argv: Sequence[str] | None = None) -> int:
     parser = argparse.ArgumentParser()
     parser.add_argument('filenames', nargs='+', help='Files to sort')
-    parser.add_argument(
+
+    mutex = parser.add_mutually_exclusive_group(required=False)
+    mutex.add_argument(
         '--ignore-case',
         action='store_const',
         const=bytes.lower,
         default=None,
         help='fold lower case to upper case characters',
     )
-    parser.add_argument(
+    mutex.add_argument(
         '--unique',
         action='store_true',
         help='ensure each line is unique',
     )
+
     args = parser.parse_args(argv)
 
     retv = PASS


Test patch:
diff --git a/tests/file_contents_sorter_test.py b/tests/file_contents_sorter_test.py
index 49b3b79..f178ae6 100644
--- a/tests/file_contents_sorter_test.py
+++ b/tests/file_contents_sorter_test.py
@@ -67,25 +67,34 @@ from pre_commit_hooks.file_contents_sorter import PASS
             FAIL,
             b'Fie\nFoe\nfee\nfum\n',
         ),
+    ),
+)
+def test_integration(input_s, argv, expected_retval, output, tmpdir):
+    path = tmpdir.join('file.txt')
+    path.write_binary(input_s)
+
+    output_retval = main([str(path)] + argv)
+
+    assert path.read_binary() == output
+    assert output_retval == expected_retval
+
+
+@pytest.mark.parametrize(
+    ('input_s', 'argv'),
+    (
         (
             b'fee\nFie\nFoe\nfum\n',
             ['--unique', '--ignore-case'],
-            PASS,
-            b'fee\nFie\nFoe\nfum\n',
         ),
         (
             b'fee\nfee\nFie\nFoe\nfum\n',
             ['--unique', '--ignore-case'],
-            FAIL,
-            b'fee\nFie\nFoe\nfum\n',
         ),
     ),
 )
-def test_integration(input_s, argv, expected_retval, output, tmpdir):
+def test_integration_invalid_args(input_s, argv, tmpdir):
     path = tmpdir.join('file.txt')
     path.write_binary(input_s)
 
-    output_retval = main([str(path)] + argv)
-
-    assert path.read_binary() == output
-    assert output_retval == expected_retval
+    with pytest.raises(SystemExit):
+        main([str(path)] + argv)