mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2026-09-03 05:10:16 +03:00
# Description of Changes Change tool APIs to use structured definitions for input/output/type info because we need that info to be able to validate whether policies can actually successfully work based on whether one tool accepts the output of another. There were various bugs in the previous string definitions because of either misspellings or just incorrect definitions, so I've gone through and fixed all that I can find. <img width="729" height="271" alt="image" src="https://github.com/user-attachments/assets/08357e96-6fbb-4b9c-ba4d-8995420c7b86" /> <img width="749" height="264" alt="image" src="https://github.com/user-attachments/assets/76f46284-1866-4b64-b1ed-2480e01866e9" /> <img width="402" height="636" alt="image" src="https://github.com/user-attachments/assets/8f7a36ca-2845-4f14-a2df-ec9c772e66f6" /> <img width="393" height="317" alt="image" src="https://github.com/user-attachments/assets/46d8b891-9820-4ce3-8109-a8b782277037" /> --------- Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
60 lines
2.2 KiB
Python
60 lines
2.2 KiB
Python
"""The shared cases in ``testing/tool-io-cases.json``, which all three implementations run."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import pytest
|
|
|
|
from stirling.models.tool_io import ToolFormat, ToolIOSpec
|
|
from stirling.models.tool_models import ToolEndpoint
|
|
from stirling.services.tool_io_compat import (
|
|
ToolChainStep,
|
|
ToolDiagnostic,
|
|
validate_tool_chain,
|
|
)
|
|
|
|
|
|
def _cases_file() -> Path:
|
|
"""Shared with the backend and frontend, so it lives at the repo root."""
|
|
for parent in Path(__file__).resolve().parents:
|
|
candidate = parent / "testing" / "tool-io-cases.json"
|
|
if candidate.exists():
|
|
return candidate
|
|
raise RuntimeError("testing/tool-io-cases.json not found above the test directory")
|
|
|
|
|
|
_DATA: dict[str, Any] = json.loads(_cases_file().read_text())
|
|
_SPECS: dict[str, ToolIOSpec] = {name: ToolIOSpec.model_validate(spec) for name, spec in _DATA["specs"].items()}
|
|
_ENDPOINTS: list[ToolEndpoint] = list(ToolEndpoint)
|
|
|
|
|
|
def _summarise(diagnostics: list[ToolDiagnostic]) -> list[str]:
|
|
"""Messages are free text, so compare only the contractual parts."""
|
|
return [f"{d.step_index}:{d.severity}:{d.code}" for d in diagnostics]
|
|
|
|
|
|
@pytest.mark.parametrize("case", _DATA["cases"], ids=lambda c: c["name"])
|
|
def test_shared_cases(case: dict[str, Any]) -> None:
|
|
table: dict[ToolEndpoint, ToolIOSpec] = {}
|
|
steps: list[ToolChainStep] = []
|
|
for index, step in enumerate(case["steps"]):
|
|
# Distinct endpoints so the same spec can appear twice in a chain. Which ones is
|
|
# irrelevant: the case supplies its own table, these are just keys.
|
|
operation = _ENDPOINTS[index]
|
|
if step.get("spec") is not None:
|
|
table[operation] = _SPECS[step["spec"]]
|
|
steps.append(ToolChainStep(operation=operation, parameters=step.get("parameters") or {}))
|
|
|
|
source = case.get("sourceFormat")
|
|
actual = validate_tool_chain(
|
|
steps,
|
|
source_format=ToolFormat(source) if source else None,
|
|
tool_io=table,
|
|
)
|
|
|
|
expected = [f"{e['stepIndex']}:{e['severity']}:{e['code']}" for e in case["expected"]]
|
|
assert _summarise(actual) == expected, [d.message for d in actual]
|