Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 40 additions & 33 deletions test/cli/commands/test_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -536,43 +548,39 @@ 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")
os.makedirs(step_dir, exist_ok=True)
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")
os.makedirs(step_dir, exist_ok=True)
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:
Expand Down Expand Up @@ -958,23 +966,22 @@ 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")
os.makedirs(step_dir, exist_ok=True)
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
17 changes: 8 additions & 9 deletions test/cli/rendering/test_log_view.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import os

from chipcompiler.cli.inspection.log_view import (
LineKind,
annotate_log_lines,
Expand Down Expand Up @@ -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:
Expand Down
Loading