From bdf144226bf7da3a2238b26f88550108376a152b Mon Sep 17 00:00:00 2001 From: EMRG Evolution Date: Thu, 23 Jul 2026 23:07:14 +0800 Subject: [PATCH 1/2] emrg: add explicit encoding='utf-8' to all subprocess.run calls Three subprocess.run() calls used text=True without explicit encoding, relying on system locale defaults. This completes the encoding hardening series started in #167/#168 (read_text/write_text). Also adds 5 unit tests for _detect_git_remote URL parsing (SSH format, HTTPS format, no .git suffix, unknown format, git failure), bringing test count from 408 to 413. --- emrg/__main__.py | 2 ++ emrg/server/git_utils.py | 2 +- tests/test_git_utils.py | 58 +++++++++++++++++++++++++++++++++++----- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/emrg/__main__.py b/emrg/__main__.py index 715d5de7..2c74d9e2 100644 --- a/emrg/__main__.py +++ b/emrg/__main__.py @@ -322,6 +322,7 @@ def _run_update() -> None: cwd=source_dir, capture_output=True, text=True, + encoding="utf-8", timeout=10, ) if result.returncode != 0: @@ -338,6 +339,7 @@ def _run_update() -> None: cwd=source_dir, capture_output=True, text=True, + encoding="utf-8", ) if result.returncode != 0: print(f"reinstall failed:\n{result.stderr}", file=sys.stderr) diff --git a/emrg/server/git_utils.py b/emrg/server/git_utils.py index a5a73ba3..be73fa8a 100644 --- a/emrg/server/git_utils.py +++ b/emrg/server/git_utils.py @@ -13,7 +13,7 @@ def _detect_git_remote(cwd: str) -> str: try: result = subprocess.run( ["git", "remote", "get-url", "origin"], - cwd=cwd, capture_output=True, text=True, timeout=5, + cwd=cwd, capture_output=True, text=True, encoding="utf-8", timeout=5, ) if result.returncode == 0: url = result.stdout.strip() diff --git a/tests/test_git_utils.py b/tests/test_git_utils.py index f62b2cfe..d12ac7de 100644 --- a/tests/test_git_utils.py +++ b/tests/test_git_utils.py @@ -2,15 +2,61 @@ from __future__ import annotations +import subprocess +from unittest.mock import MagicMock, patch + from emrg.server.git_utils import _detect_git_remote -def test_detect_ssh_url(): - """Parses SSH-style git@github.com:owner/repo.git URLs.""" - # We can't actually run 'git remote get-url' in tests, but the URL parsing - # logic is self-contained. Test via a mock subprocess or just verify - # the non-git parts work. Since _detect_git_remote shells out to git, - # we test the string parsing via the current working directory's git remote. +# ── URL parsing (mocked subprocess) ────────────────────────────── + +def _make_mock_run(stdout: str, returncode: int = 0) -> MagicMock: + """Helper to create a mock subprocess.run result.""" + mock = MagicMock() + mock.returncode = returncode + mock.stdout = stdout + return mock + + +def test_parse_ssh_url(monkeypatch): + """Parses SSH-style git@github.com:owner/repo.git → owner/repo.""" + mock = _make_mock_run("git@github.com:argszero/emrg.git\n") + monkeypatch.setattr(subprocess, "run", lambda *a, **kw: mock) + assert _detect_git_remote("/fake") == "argszero/emrg" + + +def test_parse_https_url(monkeypatch): + """Parses HTTPS-style https://github.com/owner/repo.git → owner/repo.""" + mock = _make_mock_run("https://github.com/argszero/emrg.git\n") + monkeypatch.setattr(subprocess, "run", lambda *a, **kw: mock) + assert _detect_git_remote("/fake") == "argszero/emrg" + + +def test_parse_https_url_no_dot_git(monkeypatch): + """Parses HTTPS without .git suffix.""" + mock = _make_mock_run("https://github.com/argszero/emrg\n") + monkeypatch.setattr(subprocess, "run", lambda *a, **kw: mock) + assert _detect_git_remote("/fake") == "argszero/emrg" + + +def test_parse_unknown_format(monkeypatch): + """Returns empty string for unknown URL format.""" + mock = _make_mock_run("unknown-format-url\n") + monkeypatch.setattr(subprocess, "run", lambda *a, **kw: mock) + assert _detect_git_remote("/fake") == "" + + +def test_parse_git_failure(monkeypatch): + """Returns empty string when git remote fails.""" + mock = _make_mock_run("", returncode=128) + monkeypatch.setattr(subprocess, "run", lambda *a, **kw: mock) + assert _detect_git_remote("/fake") == "" + + +# ── Real repo tests ────────────────────────────────────────────── + +def test_detect_real_repo(): + """Verifies detection on the actual git repo (integration test).""" result = _detect_git_remote(".") # The current directory IS a git repo with an origin — result should be non-empty assert isinstance(result, str) From 7f646be862cf672573b322b88279fae104394df1 Mon Sep 17 00:00:00 2001 From: EMRG Evolution Date: Thu, 23 Jul 2026 23:15:24 +0800 Subject: [PATCH 2/2] emrg: remove unused patch import from test_git_utils.py --- tests/test_git_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_git_utils.py b/tests/test_git_utils.py index d12ac7de..994f3624 100644 --- a/tests/test_git_utils.py +++ b/tests/test_git_utils.py @@ -3,7 +3,7 @@ from __future__ import annotations import subprocess -from unittest.mock import MagicMock, patch +from unittest.mock import MagicMock from emrg.server.git_utils import _detect_git_remote