Skip to content

Commit 602d7f2

Browse files
committed
extend conformance matrix with read_file cases
1 parent fb19116 commit 602d7f2

5 files changed

Lines changed: 154 additions & 2 deletions

File tree

tests/protocol_fixtures/PROTOCOL_FIXTURES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ Phase-1 scope:
1111
- No runtime behavior changes.
1212
- Python-only execution through `tests/test_protocol_conformance.py`.
1313
- Fixture format is language-neutral to enable future cross-binding runners.
14+
- Baseline now includes `read_file` runtime-behavior checks in addition to parser/API targets.
1415

1516
Phase-2 scope (mapping only):
1617

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

2325
Java conformance execution in CI:

tests/protocol_fixtures/cross_runtime_matrix.phase2.json

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,78 @@
237237
"note": "May require binding-specific interpretation."
238238
}
239239
}
240+
},
241+
{
242+
"id": "read_file/missing_file_returns_default_and_false",
243+
"target": "read_file",
244+
"runtime_results": {
245+
"python": {
246+
"status": "observed_pass",
247+
"classification": "required",
248+
"note": "Phase-1 baseline execution."
249+
},
250+
"cpp": {
251+
"status": "not_audited",
252+
"classification": "required",
253+
"note": "Audit planned in phase 2."
254+
},
255+
"java": {
256+
"status": "observed_pass",
257+
"classification": "required",
258+
"note": "Validated by TestConcoredockerApi.java."
259+
},
260+
"matlab": {
261+
"status": "not_audited",
262+
"classification": "required",
263+
"note": "Audit planned in phase 2."
264+
},
265+
"octave": {
266+
"status": "not_audited",
267+
"classification": "required",
268+
"note": "Audit planned in phase 2."
269+
},
270+
"verilog": {
271+
"status": "not_audited",
272+
"classification": "implementation_defined",
273+
"note": "May require binding-specific interpretation."
274+
}
275+
}
276+
},
277+
{
278+
"id": "read_file/older_timestamp_does_not_decrease_simtime",
279+
"target": "read_file",
280+
"runtime_results": {
281+
"python": {
282+
"status": "observed_pass",
283+
"classification": "required",
284+
"note": "Phase-1 baseline execution."
285+
},
286+
"cpp": {
287+
"status": "not_audited",
288+
"classification": "required",
289+
"note": "Audit planned in phase 2."
290+
},
291+
"java": {
292+
"status": "observed_pass",
293+
"classification": "required",
294+
"note": "Validated by TestConcoredockerApi.java simtime progression checks."
295+
},
296+
"matlab": {
297+
"status": "not_audited",
298+
"classification": "required",
299+
"note": "Audit planned in phase 2."
300+
},
301+
"octave": {
302+
"status": "not_audited",
303+
"classification": "required",
304+
"note": "Audit planned in phase 2."
305+
},
306+
"verilog": {
307+
"status": "not_audited",
308+
"classification": "implementation_defined",
309+
"note": "May require binding-specific interpretation."
310+
}
311+
}
240312
}
241313
]
242314
}

tests/protocol_fixtures/python_phase1_cases.json

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,43 @@
100100
"sent_payload": "ok",
101101
"simtime_after": 10
102102
}
103+
},
104+
{
105+
"id": "read_file/missing_file_returns_default_and_false",
106+
"target": "read_file",
107+
"description": "read() returns init default with ok=False when file is missing.",
108+
"input": {
109+
"initial_simtime": 4,
110+
"port": 1,
111+
"name": "missing",
112+
"initstr_val": "[0.0, 5.0]"
113+
},
114+
"expected": {
115+
"result": [
116+
5.0
117+
],
118+
"ok": false,
119+
"simtime_after": 4
120+
}
121+
},
122+
{
123+
"id": "read_file/older_timestamp_does_not_decrease_simtime",
124+
"target": "read_file",
125+
"description": "read() keeps simtime monotonic when incoming file timestamp is older.",
126+
"input": {
127+
"initial_simtime": 10,
128+
"port": 1,
129+
"name": "ym",
130+
"file_content": "[7.0, 3.14]",
131+
"initstr_val": "[0.0, 0.0]"
132+
},
133+
"expected": {
134+
"result": [
135+
3.14
136+
],
137+
"ok": true,
138+
"simtime_after": 10
139+
}
103140
}
104141
]
105142
}

tests/protocol_fixtures/schema.phase1.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
"enum": [
4242
"parse_params",
4343
"initval",
44-
"write_zmq"
44+
"write_zmq",
45+
"read_file"
4546
]
4647
},
4748
"description": {

tests/test_protocol_conformance.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import json
2+
import os
23
from pathlib import Path
4+
import tempfile
35

46
import pytest
57

@@ -9,7 +11,7 @@
911
FIXTURE_DIR = Path(__file__).parent / "protocol_fixtures"
1012
SCHEMA_PATH = FIXTURE_DIR / "schema.phase1.json"
1113
CASES_PATH = FIXTURE_DIR / "python_phase1_cases.json"
12-
SUPPORTED_TARGETS = {"parse_params", "initval", "write_zmq"}
14+
SUPPORTED_TARGETS = {"parse_params", "initval", "write_zmq", "read_file"}
1315

1416

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

9597

98+
def _run_read_file_case(case):
99+
old_simtime = concore.simtime
100+
old_inpath = concore.inpath
101+
old_delay = concore.delay
102+
try:
103+
with tempfile.TemporaryDirectory() as temp_dir:
104+
concore.simtime = case["input"]["initial_simtime"]
105+
concore.inpath = os.path.join(temp_dir, "in")
106+
concore.delay = 0
107+
108+
port_dir = os.path.join(temp_dir, f"in{case['input']['port']}")
109+
os.makedirs(port_dir, exist_ok=True)
110+
111+
if "file_content" in case["input"]:
112+
with open(
113+
os.path.join(port_dir, case["input"]["name"]),
114+
"w",
115+
encoding="utf-8",
116+
) as f:
117+
f.write(case["input"]["file_content"])
118+
119+
result, ok = concore.read(
120+
case["input"]["port"],
121+
case["input"]["name"],
122+
case["input"]["initstr_val"],
123+
)
124+
125+
assert result == case["expected"]["result"]
126+
assert ok == case["expected"]["ok"]
127+
assert concore.simtime == case["expected"]["simtime_after"]
128+
finally:
129+
concore.simtime = old_simtime
130+
concore.inpath = old_inpath
131+
concore.delay = old_delay
132+
133+
96134
def _run_case(case):
97135
if case["target"] == "parse_params":
98136
_run_parse_params_case(case)
99137
elif case["target"] == "initval":
100138
_run_initval_case(case)
101139
elif case["target"] == "write_zmq":
102140
_run_write_zmq_case(case)
141+
elif case["target"] == "read_file":
142+
_run_read_file_case(case)
103143
else:
104144
raise AssertionError(f"Unsupported target: {case['target']}")
105145

0 commit comments

Comments
 (0)