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
2 changes: 2 additions & 0 deletions tests/protocol_fixtures/PROTOCOL_FIXTURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ Phase-1 scope:
- No runtime behavior changes.
- Python-only execution through `tests/test_protocol_conformance.py`.
- Fixture format is language-neutral to enable future cross-binding runners.
- Baseline now includes `read_file` runtime-behavior checks in addition to parser/API targets.

Phase-2 scope (mapping only):

- No runtime behavior changes.
- Adds a cross-runtime matrix to track per-case audit status and classification.
- Java runtime entries are tracked with observed status from the Java regression suite (`TestLiteralEval.java`, `TestConcoredockerApi.java`).
- Current baseline records Java as `observed_pass` for the listed phase-2 cases.
- Phase-2 matrix includes `read_file` status rows for cross-runtime tracking.
- Keeps CI non-blocking for non-Python runtimes that are not yet audited by marking them as `not_audited`.

Java conformance execution in CI:
Expand Down
72 changes: 72 additions & 0 deletions tests/protocol_fixtures/cross_runtime_matrix.phase2.json
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,78 @@
"note": "May require binding-specific interpretation."
}
}
},
{
"id": "read_file/missing_file_returns_default_and_false",
"target": "read_file",
"runtime_results": {
"python": {
"status": "observed_pass",
"classification": "required",
"note": "Phase-1 baseline execution."
},
"cpp": {
"status": "not_audited",
"classification": "required",
"note": "Audit planned in phase 2."
},
"java": {
"status": "observed_pass",
"classification": "required",
"note": "Validated by TestConcoredockerApi.java."
},
"matlab": {
"status": "not_audited",
"classification": "required",
"note": "Audit planned in phase 2."
},
"octave": {
"status": "not_audited",
"classification": "required",
"note": "Audit planned in phase 2."
},
"verilog": {
"status": "not_audited",
"classification": "implementation_defined",
"note": "May require binding-specific interpretation."
}
}
},
{
"id": "read_file/older_timestamp_does_not_decrease_simtime",
"target": "read_file",
"runtime_results": {
"python": {
"status": "observed_pass",
"classification": "required",
"note": "Phase-1 baseline execution."
},
"cpp": {
"status": "not_audited",
"classification": "required",
"note": "Audit planned in phase 2."
},
"java": {
"status": "observed_pass",
"classification": "required",
"note": "Validated by TestConcoredockerApi.java simtime progression checks."
},
"matlab": {
"status": "not_audited",
"classification": "required",
"note": "Audit planned in phase 2."
},
"octave": {
"status": "not_audited",
"classification": "required",
"note": "Audit planned in phase 2."
},
"verilog": {
"status": "not_audited",
"classification": "implementation_defined",
"note": "May require binding-specific interpretation."
}
}
}
]
}
37 changes: 37 additions & 0 deletions tests/protocol_fixtures/python_phase1_cases.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,43 @@
"sent_payload": "ok",
"simtime_after": 10
}
},
{
"id": "read_file/missing_file_returns_default_and_false",
"target": "read_file",
"description": "read() returns init default with ok=False when file is missing.",
"input": {
"initial_simtime": 4,
"port": 1,
"name": "missing",
"initstr_val": "[0.0, 5.0]"
},
"expected": {
"result": [
5.0
],
"ok": false,
"simtime_after": 4
}
},
{
"id": "read_file/older_timestamp_does_not_decrease_simtime",
"target": "read_file",
"description": "read() keeps simtime monotonic when incoming file timestamp is older.",
"input": {
"initial_simtime": 10,
"port": 1,
"name": "ym",
"file_content": "[7.0, 3.14]",
"initstr_val": "[0.0, 0.0]"
},
"expected": {
"result": [
3.14
],
"ok": true,
"simtime_after": 10
}
}
]
}
3 changes: 2 additions & 1 deletion tests/protocol_fixtures/schema.phase1.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
"enum": [
"parse_params",
"initval",
"write_zmq"
"write_zmq",
"read_file"
]
},
"description": {
Expand Down
42 changes: 41 additions & 1 deletion tests/test_protocol_conformance.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import json
import os
from pathlib import Path
import tempfile

import pytest

Expand All @@ -9,7 +11,7 @@
FIXTURE_DIR = Path(__file__).parent / "protocol_fixtures"
SCHEMA_PATH = FIXTURE_DIR / "schema.phase1.json"
CASES_PATH = FIXTURE_DIR / "python_phase1_cases.json"
SUPPORTED_TARGETS = {"parse_params", "initval", "write_zmq"}
SUPPORTED_TARGETS = {"parse_params", "initval", "write_zmq", "read_file"}


def _load_json(path):
Expand Down Expand Up @@ -93,13 +95,51 @@ def send_json_with_retry(self, message):
concore.zmq_ports[port_name] = existing_port


def _run_read_file_case(case):
old_simtime = concore.simtime
old_inpath = concore.inpath
old_delay = concore.delay
try:
with tempfile.TemporaryDirectory() as temp_dir:
concore.simtime = case["input"]["initial_simtime"]
concore.inpath = os.path.join(temp_dir, "in")
concore.delay = 0

port_dir = os.path.join(temp_dir, f"in{case['input']['port']}")
os.makedirs(port_dir, exist_ok=True)

if "file_content" in case["input"]:
with open(
os.path.join(port_dir, case["input"]["name"]),
"w",
encoding="utf-8",
) as f:
f.write(case["input"]["file_content"])

result, ok = concore.read(
case["input"]["port"],
case["input"]["name"],
case["input"]["initstr_val"],
)

assert result == case["expected"]["result"]
assert ok == case["expected"]["ok"]
assert concore.simtime == case["expected"]["simtime_after"]
finally:
concore.simtime = old_simtime
concore.inpath = old_inpath
concore.delay = old_delay


def _run_case(case):
if case["target"] == "parse_params":
_run_parse_params_case(case)
elif case["target"] == "initval":
_run_initval_case(case)
elif case["target"] == "write_zmq":
_run_write_zmq_case(case)
elif case["target"] == "read_file":
_run_read_file_case(case)
else:
raise AssertionError(f"Unsupported target: {case['target']}")

Expand Down
Loading