mirror of
https://github.com/magnus919/agent-skills.git
synced 2026-09-20 16:16:25 +03:00
* feat(fpga-development): add design and verification methodology * feat(fpga-development): integrate electronics verification routing
91 lines
4.2 KiB
Python
Executable File
91 lines
4.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import importlib.util
|
|
import json
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
RUNNER = Path(__file__).with_name("fpga_fixture.py")
|
|
|
|
spec = importlib.util.spec_from_file_location("fpga_fixture", RUNNER)
|
|
fixture = importlib.util.module_from_spec(spec)
|
|
assert spec.loader
|
|
spec.loader.exec_module(fixture)
|
|
|
|
def test_runner_help():
|
|
assert subprocess.run([sys.executable, str(RUNNER), "--help"], capture_output=True, text=True).returncode == 0
|
|
|
|
def test_runner_simulation_and_synthesis():
|
|
if not (shutil.which("iverilog") and shutil.which("vvp") and shutil.which("yosys")):
|
|
pytest.skip("integration tools unavailable")
|
|
with tempfile.TemporaryDirectory() as d:
|
|
p = subprocess.run([sys.executable, str(RUNNER), "--json", "--output", d], capture_output=True, text=True)
|
|
data = json.loads(p.stdout)
|
|
assert p.returncode == 0
|
|
assert data["status"] == "passed"
|
|
assert {x["width"] for x in data["simulation"]} == {1, 8}
|
|
assert all(x["status"] == "passed" for x in data["simulation"])
|
|
assert all(x["status"] == "passed" for x in data["synthesis"])
|
|
|
|
def test_checker_rejects_data_loss_mutation():
|
|
if not (shutil.which("iverilog") and shutil.which("vvp")):
|
|
pytest.skip("simulation tools unavailable")
|
|
asset = RUNNER.parents[1] / "assets" / "rv_buffer.sv"
|
|
original = asset.read_text()
|
|
mutated = original.replace("full <= 1'b1; data_reg <= in_data;", "full <= 1'b1; data_reg <= data_reg;")
|
|
assert mutated != original
|
|
with tempfile.TemporaryDirectory() as d:
|
|
root = Path(d)
|
|
(root / "rv_buffer.sv").write_text(mutated)
|
|
(root / "tb_rv_buffer.sv").write_text((asset.parent / "tb_rv_buffer.sv").read_text())
|
|
p = subprocess.run(["iverilog", "-g2012", "-s", "tb_rv_buffer", "-o", str(root / "a.vvp"), "-Ptb_rv_buffer.DATA_WIDTH=8", str(root / "rv_buffer.sv"), str(root / "tb_rv_buffer.sv")], capture_output=True, text=True)
|
|
assert p.returncode == 0
|
|
q = subprocess.run(["vvp", str(root / "a.vvp"), "+SEED=20260914"], capture_output=True, text=True)
|
|
assert q.returncode != 0
|
|
assert "FAIL" in q.stdout
|
|
|
|
def test_missing_tools_are_reported_separately(monkeypatch, tmp_path, capsys):
|
|
monkeypatch.setattr(fixture.shutil, "which", lambda _: None)
|
|
monkeypatch.setattr(sys, "argv", [str(RUNNER), "--json", "--output", str(tmp_path / "missing")])
|
|
assert fixture.main() == 1
|
|
data = json.loads(capsys.readouterr().out)
|
|
assert data["status"] == "incomplete"
|
|
assert all(x["status"] == "skipped" for x in data["simulation"] + data["synthesis"])
|
|
|
|
def test_timeout_bytes_are_json_safe(monkeypatch, tmp_path):
|
|
def timed_out(*args, **kwargs):
|
|
raise subprocess.TimeoutExpired(args[0], 30, output=b"partial output", stderr=b"partial error")
|
|
monkeypatch.setattr(fixture.subprocess, "run", timed_out)
|
|
result = fixture.run(["example-tool"], tmp_path)
|
|
assert result["status"] == "timeout"
|
|
assert result["stdout"] == "partial output"
|
|
assert result["stderr"] == "partial error"
|
|
json.dumps(result)
|
|
|
|
def test_existing_output_is_preserved(tmp_path):
|
|
output = tmp_path / "keep.txt"
|
|
output.write_text("preserve me")
|
|
p = subprocess.run([sys.executable, str(RUNNER), "--output", str(output)], capture_output=True, text=True)
|
|
assert p.returncode == 2
|
|
assert output.read_text() == "preserve me"
|
|
|
|
def test_relative_output_from_other_cwd(tmp_path):
|
|
if not all(shutil.which(t) for t in ("iverilog", "vvp", "yosys")):
|
|
pytest.skip("integration tools unavailable")
|
|
p = subprocess.run([sys.executable, str(RUNNER), "--json", "--output", "results with spaces"], cwd=tmp_path, capture_output=True, text=True)
|
|
assert p.returncode == 0, p.stderr
|
|
data = json.loads(p.stdout)
|
|
assert data["status"] == "passed"
|
|
assert Path(data["output"]) == tmp_path / "results with spaces"
|
|
assert (Path(data["output"]) / "result.json").is_file()
|
|
|
|
def test_timeout_is_json_safe():
|
|
with tempfile.TemporaryDirectory() as d:
|
|
result = fixture.run([sys.executable, "-c", "import time; print('before'); time.sleep(1)"], Path(d), timeout=0.01)
|
|
assert result["status"] == "timeout"
|
|
json.dumps(result)
|