diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f7da9da0..f245c9607 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,6 +104,8 @@ if(BUILD_TESTING) set_tests_properties(pad_input PROPERTIES TIMEOUT 20) add_test(NAME trace_digest COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_trace_digest.py) + add_test(NAME conventions_body_bom COMMAND ${Python3_EXECUTABLE} + ${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_body_bom.py) endif() endif() diff --git a/tools/check_conventions.py b/tools/check_conventions.py index de46dd4d9..0d493fd47 100644 --- a/tools/check_conventions.py +++ b/tools/check_conventions.py @@ -397,5 +397,5 @@ if __name__ == "__main__": if pr: check.pull_request(pr["title"], pr["body"]) elif args.title is not None or args.body: - check.pull_request(args.title or "", open(args.body, encoding="utf-8").read() if args.body else "") + check.pull_request(args.title or "", open(args.body, encoding="utf-8-sig").read() if args.body else "") raise SystemExit(output(check, os.environ.get("GITHUB_REPOSITORY", "boykopovar/AnyPS5"))) diff --git a/tools/tests/test_check_conventions_body_bom.py b/tools/tests/test_check_conventions_body_bom.py new file mode 100644 index 000000000..2bc30ad43 --- /dev/null +++ b/tools/tests/test_check_conventions_body_bom.py @@ -0,0 +1,51 @@ +import os +import subprocess +import sys +import tempfile +import unittest +from pathlib import Path + +BODY = ( + "### What\nFix x.\n\n### Tested\nNot tested.\n\n### Checklist\n" + "- [x] Depends on: none\n- [x] AI-assisted: no\n" +) + + +class BodyBomTests(unittest.TestCase): + def run_checker(self, body): + checker = Path(__file__).resolve().parents[1] / "check_conventions.py" + with tempfile.TemporaryDirectory() as directory: + root = Path(directory) + + def git(*args): + return subprocess.run( + ["git", "-c", "user.name=Conventions Test", "-c", "user.email=test@example.com", + "-c", "commit.gpgsign=false", *args], + cwd=root, capture_output=True, text=True, check=True, + ) + + git("init", "-q") + (root / "README.md").write_text("# Example\n", encoding="utf-8") + git("add", ".") + git("commit", "-qm", "docs: add readme") + (root / "body.md").write_bytes(body) + return subprocess.run( + [sys.executable, "-I", str(checker), "--base", "HEAD", "--head", "HEAD", + "--title", "fix: x", "--body", "body.md"], + cwd=root, capture_output=True, text=True, encoding="utf-8", + env={key: value for key, value in os.environ.items() + if key not in ("GITHUB_EVENT_PATH", "GITHUB_STEP_SUMMARY", "GITHUB_ACTIONS")}, + ) + + def test_body_with_utf8_bom_keeps_its_first_section(self): + result = self.run_checker(b"\xef\xbb\xbf" + BODY.encode("utf-8")) + self.assertNotIn("section 'What' is missing", result.stdout) + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + + def test_body_without_bom_passes(self): + result = self.run_checker(BODY.encode("utf-8")) + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + + +if __name__ == "__main__": + unittest.main()