From 89690a1ad893f54016ca02fb3dc0737c7a02a813 Mon Sep 17 00:00:00 2001 From: Emin Date: Wed, 24 Jun 2026 15:47:17 +0800 Subject: [PATCH] test: avoid chmod for unreadable log tests --- test/cli/commands/test_log.py | 73 ++++++++++++++++------------- test/cli/rendering/test_log_view.py | 17 ++++--- 2 files changed, 48 insertions(+), 42 deletions(-) diff --git a/test/cli/commands/test_log.py b/test/cli/commands/test_log.py index eda44862..e835a126 100644 --- a/test/cli/commands/test_log.py +++ b/test/cli/commands/test_log.py @@ -4,6 +4,18 @@ from chipcompiler.cli import main as cli_main +def _make_path_unreadable(monkeypatch, unreadable_path): + real_open = open + unreadable_path = os.fspath(unreadable_path) + + def open_unless_target(path, *args, **kwargs): + if os.fspath(path) == unreadable_path: + raise PermissionError("cannot read") + return real_open(path, *args, **kwargs) + + monkeypatch.setattr("builtins.open", open_unless_target) + + class TestLog: def test_log_step_errors(self, tmp_path, capsys, create_cli_project): project_dir = create_cli_project() @@ -536,7 +548,9 @@ def test_artifacts_log_disclosure_no_errors( class TestLogUnreadableFile: """AC-9: Unreadable log files return non-zero with OS error.""" - def test_unreadable_log_returns_nonzero(self, tmp_path, capsys, create_cli_project): + def test_unreadable_log_returns_nonzero( + self, tmp_path, monkeypatch, capsys, create_cli_project + ): project_dir = create_cli_project() run_dir = os.path.join(project_dir, "runs", "default") step_dir = os.path.join(run_dir, "Synthesis_yosys", "log") @@ -544,17 +558,14 @@ def test_unreadable_log_returns_nonzero(self, tmp_path, capsys, create_cli_proje log_path = os.path.join(step_dir, "synthesis.log") with open(log_path, "w") as f: f.write("content\n") - os.chmod(log_path, 0o000) + _make_path_unreadable(monkeypatch, log_path) - try: - rc = cli_main.run(["log", "synthesis", "--project", project_dir]) - assert rc == 1 - out = capsys.readouterr().out - assert "unreadable" in out - finally: - os.chmod(log_path, 0o644) + rc = cli_main.run(["log", "synthesis", "--project", project_dir]) + assert rc == 1 + out = capsys.readouterr().out + assert "unreadable" in out - def test_unreadable_log_jsonl(self, tmp_path, capsys, create_cli_project): + def test_unreadable_log_jsonl(self, tmp_path, monkeypatch, capsys, create_cli_project): project_dir = create_cli_project() run_dir = os.path.join(project_dir, "runs", "default") step_dir = os.path.join(run_dir, "Synthesis_yosys", "log") @@ -562,17 +573,14 @@ def test_unreadable_log_jsonl(self, tmp_path, capsys, create_cli_project): log_path = os.path.join(step_dir, "synthesis.log") with open(log_path, "w") as f: f.write("content\n") - os.chmod(log_path, 0o000) + _make_path_unreadable(monkeypatch, log_path) - try: - rc = cli_main.run(["log", "synthesis", "--jsonl", "--project", project_dir]) - assert rc == 1 - record = json.loads(capsys.readouterr().out.strip()) - assert record["log_status"] == "unreadable" - assert "source" in record - assert "error" in record - finally: - os.chmod(log_path, 0o644) + rc = cli_main.run(["log", "synthesis", "--jsonl", "--project", project_dir]) + assert rc == 1 + record = json.loads(capsys.readouterr().out.strip()) + assert record["log_status"] == "unreadable" + assert "source" in record + assert "error" in record class TestLogMultiSource: @@ -958,7 +966,9 @@ def test_step_jsonl_unchanged(self, tmp_path, capsys, create_cli_project): class TestLogListingUnreadable: """Unreadable logs in listing mode must omit tail, keep path+inspect, no traceback.""" - def test_unreadable_step_log_in_listing(self, tmp_path, capsys, create_cli_project): + def test_unreadable_step_log_in_listing( + self, tmp_path, monkeypatch, capsys, create_cli_project + ): project_dir = create_cli_project() run_dir = os.path.join(project_dir, "runs", "default") step_dir = os.path.join(run_dir, "Synthesis_yosys", "log") @@ -966,15 +976,12 @@ def test_unreadable_step_log_in_listing(self, tmp_path, capsys, create_cli_proje log_path = os.path.join(step_dir, "synthesis.log") with open(log_path, "w") as f: f.write("content\n") - os.chmod(log_path, 0o000) - - try: - rc = cli_main.run(["log", "--project", project_dir]) - assert rc == 0 - out = capsys.readouterr().out - assert "tail:" not in out - assert "Synthesis_yosys" in out - assert "inspect:" in out - assert "Traceback" not in out - finally: - os.chmod(log_path, 0o644) + _make_path_unreadable(monkeypatch, log_path) + + rc = cli_main.run(["log", "--project", project_dir]) + assert rc == 0 + out = capsys.readouterr().out + assert "tail:" not in out + assert "Synthesis_yosys" in out + assert "inspect:" in out + assert "Traceback" not in out diff --git a/test/cli/rendering/test_log_view.py b/test/cli/rendering/test_log_view.py index aa64f087..18e8c49b 100644 --- a/test/cli/rendering/test_log_view.py +++ b/test/cli/rendering/test_log_view.py @@ -1,5 +1,3 @@ -import os - from chipcompiler.cli.inspection.log_view import ( LineKind, annotate_log_lines, @@ -852,17 +850,18 @@ def test_bel_and_backspace_stripped(self, tmp_path): result = tail_lines_for_log(str(log_file)) assert result == ["abc", "done"] - def test_unreadable_file_returns_empty(self, tmp_path): + def test_unreadable_file_returns_empty(self, monkeypatch, tmp_path): from chipcompiler.cli.inspection.log_view import tail_lines_for_log log_file = tmp_path / "test.log" log_file.write_text("content\n") - os.chmod(str(log_file), 0o000) - try: - result = tail_lines_for_log(str(log_file)) - assert result == [] - finally: - os.chmod(str(log_file), 0o644) + + def raise_permission_error(*args, **kwargs): + raise PermissionError("cannot read") + + monkeypatch.setattr("builtins.open", raise_permission_error) + result = tail_lines_for_log(str(log_file)) + assert result == [] class TestListingTailRendering: