From 502d3f7e81254e77079ae6569a076a57022e9812 Mon Sep 17 00:00:00 2001 From: squid-protocol Date: Wed, 7 Oct 2026 16:52:20 -0400 Subject: [PATCH 1/2] equivalence: CICS input channels and output containers compared (#4270) - A scenario's "channel" (name + containers, text or hex, BIT unless CHAR) is the channel the task starts with: the stub's GGCCHIN (channel.cfg) and CicsTask.withChannel / Channel.with make it the first program's current channel (oracle_assumptions.md X24). - At the task's end the containers on that channel are compared, byte for byte, as a last CONTAINERS event (the stub's containers.out from GGCEND; the Java test reads task.currentChannel()); dropped on an abend and for a task judged up to a refusal (X6, X23). - RUN TRANSID CHILD is compared on the COBOL side as CicsTask records it (TRANSID, RESP); the child is not run. A case's "transactions" writes the stub's transactions.cfg and the Java side's Programs.transaction. - The java-facade side runs a channel program (handleLink(XChannelIn), no task facade yet, #4343) through runTask, and its entries say so. - Cases: asynccc-crdtchk, -getaddr, -getname, -csstatus (LINKs GETPOL / GETSPND), -csstats2 (RUN TRANSID GETP / SPND), each with its '0001' and other-account branches and a no-channel task. Co-Authored-By: Claude Opus 5.5 --- docs/language_status/oracle_assumptions.md | 29 +++ .../cobol_to_java_transaction_forge.py | 7 + .../cobol_mainframe/test_equivalence_cics.py | 123 +++++++++++ tests/equivalence/asynccc-crdtchk/LICENSE | 201 ++++++++++++++++++ tests/equivalence/asynccc-crdtchk/NOTICE | 9 + tests/equivalence/asynccc-crdtchk/case.json | 47 ++++ tests/equivalence/asynccc-csstats2/LICENSE | 201 ++++++++++++++++++ tests/equivalence/asynccc-csstats2/NOTICE | 9 + tests/equivalence/asynccc-csstats2/case.json | 58 +++++ tests/equivalence/asynccc-csstatus/LICENSE | 201 ++++++++++++++++++ tests/equivalence/asynccc-csstatus/NOTICE | 9 + tests/equivalence/asynccc-csstatus/case.json | 57 +++++ tests/equivalence/asynccc-getaddr/LICENSE | 201 ++++++++++++++++++ tests/equivalence/asynccc-getaddr/NOTICE | 9 + tests/equivalence/asynccc-getaddr/case.json | 47 ++++ tests/equivalence/asynccc-getname/LICENSE | 201 ++++++++++++++++++ tests/equivalence/asynccc-getname/NOTICE | 9 + tests/equivalence/asynccc-getname/case.json | 47 ++++ tests/equivalence/cics/ggcics.c | 71 ++++++- tests/equivalence/det_sweep_coverage.json | 89 +++++++- tests/tools/equivalence_cics.py | 128 ++++++++++- 21 files changed, 1746 insertions(+), 7 deletions(-) create mode 100644 tests/equivalence/asynccc-crdtchk/LICENSE create mode 100644 tests/equivalence/asynccc-crdtchk/NOTICE create mode 100644 tests/equivalence/asynccc-crdtchk/case.json create mode 100644 tests/equivalence/asynccc-csstats2/LICENSE create mode 100644 tests/equivalence/asynccc-csstats2/NOTICE create mode 100644 tests/equivalence/asynccc-csstats2/case.json create mode 100644 tests/equivalence/asynccc-csstatus/LICENSE create mode 100644 tests/equivalence/asynccc-csstatus/NOTICE create mode 100644 tests/equivalence/asynccc-csstatus/case.json create mode 100644 tests/equivalence/asynccc-getaddr/LICENSE create mode 100644 tests/equivalence/asynccc-getaddr/NOTICE create mode 100644 tests/equivalence/asynccc-getaddr/case.json create mode 100644 tests/equivalence/asynccc-getname/LICENSE create mode 100644 tests/equivalence/asynccc-getname/NOTICE create mode 100644 tests/equivalence/asynccc-getname/case.json diff --git a/docs/language_status/oracle_assumptions.md b/docs/language_status/oracle_assumptions.md index d580b604f..2933a07f1 100644 --- a/docs/language_status/oracle_assumptions.md +++ b/docs/language_status/oracle_assumptions.md @@ -101,6 +101,7 @@ verdict, but it limits what the proof says about inputs outside the scenarios. | X21 | CICS | EIBTASKN: the task's number is a stated fact of the run (`$GGCICS_TASKN` / `CicsTask.withTaskNumber`, a case's or scenario's `"taskn"`, default 0), not the number CICS assigns; a value outside 0 to 9,999,999 refused | DIFFERS (the value) / MATCHED (both sides) | yes (every CICS task; read by CBSA's Db2 programs, GenApp LGICDB01) | | X22 | CICS | READ GTEQ / GENERIC on a KSDS: the first record whose key (or its first KEYLENGTH bytes) equals RIDFLD's or, with GTEQ, is greater, in the browse's key order (D1); NOTFND RESP2 80; READ UPDATE holds the record found; RIDFLD not updated; a GENERIC KEYLENGTH not shorter than the key or not above zero, a non-constant KEYLENGTH and a RIDFLD shorter than the key searched refused | ASSUMED (REFUSED where IBM is silent or the layout decides) | yes (GenApp LGICVS01 genapp-lgicvs01) | | X23 | CICS | A COMMAREA of a stated length (a scenario's `commarea_length`, EIBCALEN shorter than the record): the program is given exactly those bytes; a reference past EIBCALEN refused on both sides, the task judged up to it | ASSUMED (REFUSED past EIBCALEN) | yes (GenApp LGACDB01, LGACDB02, LGDPDB01, LGIPDB01) | +| X24 | CICS | A task started with a channel (a scenario's `channel`: what a RUN TRANSID CHANNEL parent or a LINK CHANNEL caller passed), made its first program's current channel; the containers left on that channel compared at the task's end (dropped on an abend), byte for byte; RUN TRANSID children not run | ASSUMED | yes (async credit-card CRDTCHK, CSSTATS2, CSSTATUS, GETADDR, GETNAME) | | X25 | COBOL layout | SYNCHRONIZED slack bytes in the layout model (GalaxyIR `record_layout`, `_storage_spans`): IBM Enterprise COBOL boundaries (halfword up to 4 digits, fullword above, the 8-byte binary S9(10)-S9(18) included; COMP-1 / INDEX / pointers fullword; COMP-2 doubleword) counted from the record, the table slack of IBM's rule; GnuCOBOL / Micro Focus may align an 8-byte binary on a doubleword | ASSUMED (IBM's fullword; z/OS is the target) | no (no committed case reaches an 8-byte SYNC binary) | | L1 | LE | CEEDAYS: documented pictures only | MATCHED / REFUSED | yes | | L2 | LE | CEE3ABD abend codes | MATCHED | yes | @@ -943,6 +944,34 @@ The length READQ TS returns on ITEMERR or QIDERR is not documented, so it is not - **Reach today.** No committed case reaches it: no committed oracle case or answer-key layout holds an 8-byte binary with SYNC after an off-boundary item. Status: ASSUMED. +### X24. A task started with a channel; the containers it leaves compared — ASSUMED (#4270) +- **What IBM documents** (CICS TS 6.x, "Scope of a channel"; RUN TRANSID CHANNEL: "the name of the channel that is + to be passed to the child task"; FETCH CHILD CHANNEL: "the channel returned by the child task"; LINK CHANNEL: the + called program's current channel, "what it puts there, the caller sees"). A service started by RUN TRANSID CHANNEL, + or LINKed with CHANNEL, finds its input in containers on its current channel and leaves its result there for the + parent to FETCH, or for the caller. +- **The harness's model.** A scenario states `"channel": {"name", "containers": {NAME: {"text" | "hex", + "datatype"}}}`: the channel the caller passed (text in the case's data page; BIT unless CHAR, as PUT CONTAINER's + default). Both sides build it before the program runs and make it the first program's current channel, the only + one in its scope: the stub's `GGCCHIN` (channel.cfg), and the Java side's `CicsTask.withChannel` (with the new + `Channel.with`). Unstated, the task has no current channel, as before (GET CONTAINER INVREQ RESP2 4). +- **What is compared.** At the task's end, the containers on that channel -- every one, by name, byte for byte, and + the channel's name -- as a last CONTAINERS event (the stub's `containers.out`, written by GGCEND; the Java test reads + `task.currentChannel()`), what the parent or caller sees. Dropped when the task abended (as a LINKed program's + COMMAREA is) and for a task judged up to a refusal (X6, X23). The data type is not compared: no conversion is + modelled (X17), so a parent sees the same bytes either way. Other channels the task made die with it and are not + compared. +- **RUN TRANSID children.** The equivalence harness runs one task: a RUN TRANSID CHILD is compared as the command + (TRANSID, RESP; `"transactions"` states the region's transaction definitions, else every one is defined), and the + child is not run. Sound for a parent that never FETCHes it (CSSTATS2): nothing the child does can reach the parent. + A FETCH CHILD / FETCH ANY is refused by the translator and the stub (X18). +- **A channel program's facade.** The generator gives a channel program `handleLink(XChannelIn)`, which no task + facade carries yet (#4343): the java-facade side runs such a program through runTask, and its `entries` say so. +- **Reached.** The async credit-card services CRDTCHK, GETADDR, GETNAME, CSSTATUS (which LINKs GETPOL and GETSPND) + and CSSTATS2 (RUN TRANSID GETP / SPND): their '0001' and other-account branches, and the containers they PUT. + Pinned by `tests/cobol_mainframe/test_equivalence_cics.py` (the stub's channel in and containers out, the + comparison, the drop on abend). + ## Language Environment ### L1. CEEDAYS — MATCHED where documented, REFUSED otherwise diff --git a/gitgalaxy/tools/cobol_to_java/cobol_to_java_transaction_forge.py b/gitgalaxy/tools/cobol_to_java/cobol_to_java_transaction_forge.py index 62a527b42..f988b6c8c 100644 --- a/gitgalaxy/tools/cobol_to_java/cobol_to_java_transaction_forge.py +++ b/gitgalaxy/tools/cobol_to_java/cobol_to_java_transaction_forge.py @@ -1085,6 +1085,13 @@ def commarea_alternative_todos(commarea: dict) -> list[str]: return name; } + /** #4270 (X24): a container this channel holds before any program runs -- what the parent of a RUN TRANSID + * CHANNEL, or a LINK CHANNEL caller outside the region, put there (BIT or CHAR, as its PUT gave it). */ + public Channel with(String container, byte[] data, boolean bit) { + containers.put(channelName(container, "container"), new Container(data.clone(), bit)); + return this; + } + /** The containers, by name (a copy). */ public Map containers() { Map out = new LinkedHashMap<>(); diff --git a/tests/cobol_mainframe/test_equivalence_cics.py b/tests/cobol_mainframe/test_equivalence_cics.py index df3e9be41..7e031834c 100644 --- a/tests/cobol_mainframe/test_equivalence_cics.py +++ b/tests/cobol_mainframe/test_equivalence_cics.py @@ -1070,3 +1070,126 @@ def run(*args: str) -> tuple[int, str]: (d / "commarea.exact").write_text("60\n", encoding="ascii") assert run("60", "59") == (0, "moved=1 first=x\nwrote\n") assert run("60", "60") == (98, "moved=1 first=x\nCOMMAREA past EIBCALEN: not modelled\n") + + +# ---- #4270: a task started with a channel; the containers it leaves compared (X24); a case's transactions ---------- +def _channel_case(): + return {"name": "x", "program": "CRDTCHK", "transid": "ICCK", "scenarios": [], "datasets": {}} + + +def test_a_scenario_states_the_channel_its_task_starts_with(): + """#4270 (X24): `"channel"` -- a name and containers (text in the case's data page, or hex; BIT unless CHAR, as + PUT CONTAINER's default) -- is what a RUN TRANSID CHANNEL parent passed. Names are CICS's: 1-16, no blank.""" + sc = {"name": "s", "channel": {"name": "MYCHANNEL", "containers": { + "INPUTCONTAINER": {"text": "0001"}, "RAW": {"hex": "00ff", "datatype": "CHAR"}}}} # fmt: skip + got = ec.scenario_channel(_channel_case(), sc) + assert got == {"name": "MYCHANNEL", "containers": [{"name": "INPUTCONTAINER", "data": b"0001", "bit": True}, + {"name": "RAW", "data": b"\x00\xff", "bit": False}]} # fmt: skip + assert ec.scenario_channel(_channel_case(), {"name": "s"}) is None + assert ec._channel_json(_channel_case(), sc)["containers"][1] == {"name": "RAW", "hex": "00FF", "bit": False} + for bad in ( + {"name": "MY CHANNEL"}, + {"name": "X" * 17}, + {"name": "C", "containers": {"K": {"text": "a", "hex": "61"}}}, + {"name": "C", "containers": {"K": {}}}, + {"name": "C", "containers": {"K": {"hex": "61", "datatype": "X"}}}, + ): + with pytest.raises(ec.Unsupported): + ec.scenario_channel(_channel_case(), {"name": "s", "channel": bad}) + + +def test_the_containers_a_task_leaves_are_compared_at_its_end_unless_it_abends(tmp_path): + """#4270 (X24): the stub's containers.out -> a last CONTAINERS event (before a LINKed program's COMMAREA, as + CicsTask's test writes them); RUN TRANSID CHILD is compared as CicsTask records it; an abend drops the + containers, as it drops the COMMAREA; every container's bytes, both ways, are compared.""" + out = tmp_path / "out" + out.mkdir() + (out / "events.txt").write_text("001 RUN pgm=CSSTATS2 transid=GETP resp=0 resp2=0\n" + "002 RUN pgm=CSSTATS2 transid=NONE resp=28 resp2=1\n" + "003 RETURN pgm=CSSTATS2 level=1 transid= len=0\n", encoding="ascii") # fmt: skip + (out / "containers.out").write_text("CHANNEL MYCHANNEL\nINPUTCONTAINER 30303031\nGETVIPSTATUS 56455259\n", + encoding="ascii") # fmt: skip + got = ec.cobol_events(ec.outputs(out, {"name": "x"}, tmp_path, [])) + assert got == [{"event": "RUN", "transid": "GETP", "resp": "NORMAL"}, + {"event": "RUN", "transid": "NONE", "resp": "TRANSIDERR"}, + {"event": "RETURN", "transid": None, "commarea": None}, + {"event": "CONTAINERS", "channel": "MYCHANNEL", + "containers": {"INPUTCONTAINER": "30303031", "GETVIPSTATUS": "56455259"}}] # fmt: skip + java = [*got[:3], {"event": "CONTAINERS", "channel": "MYCHANNEL", + "containers": {"GETVIPSTATUS": "56455259", "INPUTCONTAINER": "30303031"}}] # fmt: skip + assert ec.compare_events(got, java)["equal"] == 4 # order of containers does not matter + java[3] = {**java[3], "containers": {"INPUTCONTAINER": "30303031", "GETVIPSTATUS": "52454755"}} + assert [f["field"] for f in ec.compare_events(got, java)["diffs"][0]["fields"]] == ["containers.GETVIPSTATUS"] + abended = [{"event": "ABEND", "abcode": "X"}, got[3]] + assert ec.linked_result({}, abended) == abended[:1] and ec.linked_result({}, got) == got + _, _, _ = ec.x6_judged({"name": "s"}, tmp_path, got, got) # (no refusal: unchanged) + cev, _, _ = ec.x6_judged({"name": "s", "prefix_x6": "WRITEQ TD LENGTH > FROM: not modelled"}, tmp_path, got, got) + assert cev == got[:3] # a task judged up to a refusal: its end state (containers too) is not compared + + +def test_the_driver_gives_the_task_its_channel_and_a_case_states_its_transactions(tmp_path): + assert "CALL 'GGCCHIN' USING GG-CICS" in ec.cics_driver("PROG", False) + assert ec.case_transactions({"transactions": ["SPND", "GETP"]}) == ["GETP", "SPND"] + with pytest.raises(ec.Unsupported, match="transaction ids"): + ec.case_transactions({"transactions": ["TOOLONG"]}) + import equivalence_java as ej + + (tmp_path / "service").mkdir() + (tmp_path / "service" / f"{ej._service_class('PROG')}.java").write_text("public void handleLink() {}") + case = {**_facade_case(), "clock": "2026/10/01 10:30:15.00", "screens": {}, "commarea": None, + "transactions": ["GETP", "SPND"]} # fmt: skip + java = ec.cics_equivalence_test(case, tmp_path, []) + assert ( + 'public boolean transaction(String transid) { return java.util.Set.of("GETP", "SPND").contains(transid); }' + in java + ) + assert "task.withChannel(channel);" in java and 'left.put("event", "CONTAINERS");' in java + + +_CHANNEL_MAIN = r""" +#include "GGCICS" +int main(void) { + gg_cics c; + char into[8] = "...."; + memset(&c, 0, sizeof c); + GGCCHIN(&c); + memset(c.qname, ' ', 16); + memcpy(c.qname, "INPUTCONTAINER", 14); + memset(c.flags, ' ', 40); + c.len = 4; + GGCGETC(&c, into); + printf("get resp=%d len=%d into=%.4s\n", c.resp, c.len, into); + memset(c.qname, ' ', 16); + memcpy(c.qname, "OUT", 3); + c.len = 3; + GGCPUTC(&c, "998"); + printf("put resp=%d\n", c.resp); + GGCEND(&c); + return 0; +} +""" + + +@pytest.mark.skipif(not __import__("shutil").which("gcc"), reason="needs gcc") +def test_the_stub_starts_the_task_with_its_channel_and_writes_what_it_leaves(tmp_path): + """#4270 (X24): GGCCHIN makes channel.cfg's channel the first program's current channel (GET CONTAINER finds the + stated data, PUT CONTAINER adds to it); GGCEND writes its containers to containers.out. No channel.cfg: no + current channel (GET CONTAINER INVREQ RESP2 4) and no containers.out, as before.""" + import subprocess + + (tmp_path / "main.c").write_text(_CHANNEL_MAIN.replace("GGCICS", str(ec.STUB / "ggcics.c")), encoding="ascii") + exe = tmp_path / "chan" + built = subprocess.run(["gcc", "-o", str(exe), str(tmp_path / "main.c")], capture_output=True, text=True, # noqa: S603,S607 + check=False) # fmt: skip + assert built.returncode == 0, built.stderr + d, o = tmp_path / "d", tmp_path / "o" + d.mkdir() + o.mkdir() + env = {"GGCICS_DIR": str(d), "GGCICS_OUT": str(o)} + run = subprocess.run([str(exe)], capture_output=True, text=True, env=env, check=False) # noqa: S603 + assert run.stdout.splitlines() == ["get resp=16 len=4 into=....", "put resp=16"] # INVREQ: no current channel + assert not (o / "containers.out").exists() + (d / "channel.cfg").write_text("MYCHANNEL\nINPUTCONTAINER BIT 30303031\n", encoding="ascii") + run = subprocess.run([str(exe)], capture_output=True, text=True, env=env, check=False) # noqa: S603 + assert run.stdout.splitlines()[:2] == ["get resp=0 len=4 into=0001", "put resp=0"] + assert (o / "containers.out").read_text() == "CHANNEL MYCHANNEL\nINPUTCONTAINER 30303031\nOUT 393938\n" diff --git a/tests/equivalence/asynccc-crdtchk/LICENSE b/tests/equivalence/asynccc-crdtchk/LICENSE new file mode 100644 index 000000000..cff851c9c --- /dev/null +++ b/tests/equivalence/asynccc-crdtchk/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016 IBM Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/tests/equivalence/asynccc-crdtchk/NOTICE b/tests/equivalence/asynccc-crdtchk/NOTICE new file mode 100644 index 000000000..5bc981aa9 --- /dev/null +++ b/tests/equivalence/asynccc-crdtchk/NOTICE @@ -0,0 +1,9 @@ +CICS asynchronous API credit-card application example +https://github.com/cicsdev/cics-async-api-credit-card-application-example +Copyright IBM Corp. 2016 + +Licensed under the Apache License, Version 2.0 (see LICENSE, the corpus's own +licence file). The program under test, src/CRDTCHK.cbl, is the corpus's, used +unmodified from the corpus. +case.json (the scenarios, their input channel data and notes) was written for +this equivalence case; it contains no code or data from the corpus. diff --git a/tests/equivalence/asynccc-crdtchk/case.json b/tests/equivalence/asynccc-crdtchk/case.json new file mode 100644 index 000000000..4c3841a6e --- /dev/null +++ b/tests/equivalence/asynccc-crdtchk/case.json @@ -0,0 +1,47 @@ +{ + "kind": "cics", + "corpus": "cics-async-api-credit-card-application-example", + "program": "CRDTCHK", + "program_source": "src/CRDTCHK.cbl", + "copy_dirs": [], + "transid": "ICCK", + "clock": "2026/10/01 10:30:15.00", + "datasets": {}, + "commarea": null, + "linked": true, + "screens": {}, + "notes": "IBM's CICS asynchronous API credit-card example: CRDTCHK (the credit check, transaction ICCK). GET CONTAINER(INPUTCONTAINER) INTO the account number; '0001' scores '998', any other '537'; DELAY FOR SECONDS(5); PUT CONTAINER(CREDITCHECKCONT) the 3-byte score; RETURN. Its LINKAGE SECTION is empty: no COMMAREA (\"commarea\": null). The task starts with the channel its caller passes (#4270, oracle_assumptions.md X24): MYCHANNEL holding INPUTCONTAINER, the 4-byte account number ASYNCPNT / SEQPNT PUT there (no DATATYPE: BIT). The containers the task leaves on MYCHANNEL are compared at its end, as the caller sees them after FETCH CHILD / its LINK. Derived from github.com/cicsdev/cics-async-api-credit-card-application-example (Apache-2.0; Copyright IBM Corp. 2016): LICENSE here is the corpus's own, NOTICE names the source and what was derived.", + "scenarios": [ + { + "name": "account-0001", + "commarea": null, + "channel": { + "name": "MYCHANNEL", + "containers": { + "INPUTCONTAINER": { + "text": "0001" + } + } + }, + "why": "'0001': CREDIT-CHECK-RESULT '998', PUT into CREDITCHECKCONT; MYCHANNEL left with INPUTCONTAINER and CREDITCHECKCONT '998'" + }, + { + "name": "other-account", + "commarea": null, + "channel": { + "name": "MYCHANNEL", + "containers": { + "INPUTCONTAINER": { + "text": "0002" + } + } + }, + "why": "'0002': the ELSE branch, '537' into CREDITCHECKCONT" + }, + { + "name": "no-channel", + "commarea": null, + "why": "no channel: GET CONTAINER without CHANNEL has no current channel -- INVREQ RESP2 4 (caught by RESP), ACCOUNT-NUMBER-IN keeps its initial value (no VALUE clause: oracle_assumptions.md L3) so the ELSE branch runs; PUT CONTAINER is INVREQ RESP2 4 too, then RETURN; there is no channel, so nothing more to compare" + } + ] +} diff --git a/tests/equivalence/asynccc-csstats2/LICENSE b/tests/equivalence/asynccc-csstats2/LICENSE new file mode 100644 index 000000000..cff851c9c --- /dev/null +++ b/tests/equivalence/asynccc-csstats2/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016 IBM Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/tests/equivalence/asynccc-csstats2/NOTICE b/tests/equivalence/asynccc-csstats2/NOTICE new file mode 100644 index 000000000..a4fe63169 --- /dev/null +++ b/tests/equivalence/asynccc-csstats2/NOTICE @@ -0,0 +1,9 @@ +CICS asynchronous API credit-card application example +https://github.com/cicsdev/cics-async-api-credit-card-application-example +Copyright IBM Corp. 2016 + +Licensed under the Apache License, Version 2.0 (see LICENSE, the corpus's own +licence file). The program under test, src/CSSTATS2.cbl, is the corpus's, used +unmodified from the corpus. +case.json (the scenarios, their input channel data and notes) was written for +this equivalence case; it contains no code or data from the corpus. diff --git a/tests/equivalence/asynccc-csstats2/case.json b/tests/equivalence/asynccc-csstats2/case.json new file mode 100644 index 000000000..d8a720056 --- /dev/null +++ b/tests/equivalence/asynccc-csstats2/case.json @@ -0,0 +1,58 @@ +{ + "kind": "cics", + "corpus": "cics-async-api-credit-card-application-example", + "program": "CSSTATS2", + "program_source": "src/CSSTATS2.cbl", + "copy_dirs": [], + "transid": "STUS", + "clock": "2026/10/01 10:30:15.00", + "datasets": {}, + "commarea": null, + "linked": true, + "screens": {}, + "transactions": [ + "ACCA", + "GETA", + "GETN", + "GETP", + "ICCK", + "SCCA", + "SPND", + "STUS", + "UPDB" + ], + "notes": "IBM's CICS asynchronous API credit-card example: CSSTATS2 (the customer-status service ASYNCPNT starts in parallel, transaction STUS). GET CONTAINER(INPUTCONTAINER); RUN TRANSID(GETP) CHILD and RUN TRANSID(SPND) CHILD (no CHANNEL; it never FETCHes them, so their outcome cannot reach this task -- the children are not run here, the RUN commands are compared); '0001' is 'VERY VIP', any other 'REGULAR '; PUT CONTAINER(GETVIPSTATUS); RETURN. The region's transactions are the bundle's (\"transactions\": etc/CICS_bundles/cics-async-creditcardapplication-resources/*.transaction: the bundle's nine TRANSACTION definitions (GETP runs GETPOL, SPND runs GETSPND)). Its LINKAGE SECTION is empty: no COMMAREA (\"commarea\": null). The task starts with the channel its caller passes (#4270, oracle_assumptions.md X24): MYCHANNEL holding INPUTCONTAINER, the 4-byte account number ASYNCPNT / SEQPNT PUT there (no DATATYPE: BIT). The containers the task leaves on MYCHANNEL are compared at its end, as the caller sees them after FETCH CHILD / its LINK. Derived from github.com/cicsdev/cics-async-api-credit-card-application-example (Apache-2.0; Copyright IBM Corp. 2016): LICENSE here is the corpus's own, NOTICE names the source and what was derived.", + "scenarios": [ + { + "name": "account-0001", + "commarea": null, + "channel": { + "name": "MYCHANNEL", + "containers": { + "INPUTCONTAINER": { + "text": "0001" + } + } + }, + "why": "'0001': RUN GETP and RUN SPND NORMAL (both defined), 'VERY VIP' into GETVIPSTATUS" + }, + { + "name": "other-account", + "commarea": null, + "channel": { + "name": "MYCHANNEL", + "containers": { + "INPUTCONTAINER": { + "text": "0002" + } + } + }, + "why": "'0002': the same RUNs, 'REGULAR ' into GETVIPSTATUS" + }, + { + "name": "no-channel", + "commarea": null, + "why": "no channel: GET CONTAINER without CHANNEL has no current channel -- INVREQ RESP2 4 (caught by RESP), ACCOUNT-NUMBER-IN keeps its initial value (no VALUE clause: oracle_assumptions.md L3) so the ELSE branch runs; PUT CONTAINER is INVREQ RESP2 4 too, then RETURN; there is no channel, so nothing more to compare" + } + ] +} diff --git a/tests/equivalence/asynccc-csstatus/LICENSE b/tests/equivalence/asynccc-csstatus/LICENSE new file mode 100644 index 000000000..cff851c9c --- /dev/null +++ b/tests/equivalence/asynccc-csstatus/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016 IBM Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/tests/equivalence/asynccc-csstatus/NOTICE b/tests/equivalence/asynccc-csstatus/NOTICE new file mode 100644 index 000000000..99bafc785 --- /dev/null +++ b/tests/equivalence/asynccc-csstatus/NOTICE @@ -0,0 +1,9 @@ +CICS asynchronous API credit-card application example +https://github.com/cicsdev/cics-async-api-credit-card-application-example +Copyright IBM Corp. 2016 + +Licensed under the Apache License, Version 2.0 (see LICENSE, the corpus's own +licence file). The program under test, src/CSSTATUS.cbl, is the corpus's, used +unmodified from the corpus, and so are the programs it LINKs to (src/GETPOL.cbl, src/GETSPND.cbl). +case.json (the scenarios, their input channel data and notes) was written for +this equivalence case; it contains no code or data from the corpus. diff --git a/tests/equivalence/asynccc-csstatus/case.json b/tests/equivalence/asynccc-csstatus/case.json new file mode 100644 index 000000000..7b72d61f5 --- /dev/null +++ b/tests/equivalence/asynccc-csstatus/case.json @@ -0,0 +1,57 @@ +{ + "kind": "cics", + "corpus": "cics-async-api-credit-card-application-example", + "program": "CSSTATUS", + "program_source": "src/CSSTATUS.cbl", + "copy_dirs": [], + "transid": "SCCA", + "clock": "2026/10/01 10:30:15.00", + "datasets": {}, + "commarea": null, + "linked": true, + "screens": {}, + "programs": [ + { + "program": "GETPOL", + "program_source": "src/GETPOL.cbl" + }, + { + "program": "GETSPND", + "program_source": "src/GETSPND.cbl" + } + ], + "notes": "IBM's CICS asynchronous API credit-card example: CSSTATUS (the customer-status service SEQPNT LINKs to, transaction SCCA). GET CONTAINER(INPUTCONTAINER); LINK GETPOL and LINK GETSPND (no COMMAREA, no channel: each DELAYs and RETURNs, run in the same task -- \"programs\"); '0001' is 'VERY VIP', any other 'REGULAR '; PUT CONTAINER(GETVIPSTATUS); RETURN. Its LINKAGE SECTION is empty: no COMMAREA (\"commarea\": null). The task starts with the channel its caller passes (#4270, oracle_assumptions.md X24): MYCHANNEL holding INPUTCONTAINER, the 4-byte account number ASYNCPNT / SEQPNT PUT there (no DATATYPE: BIT). The containers the task leaves on MYCHANNEL are compared at its end, as the caller sees them after FETCH CHILD / its LINK. Derived from github.com/cicsdev/cics-async-api-credit-card-application-example (Apache-2.0; Copyright IBM Corp. 2016): LICENSE here is the corpus's own, NOTICE names the source and what was derived.", + "scenarios": [ + { + "name": "account-0001", + "commarea": null, + "channel": { + "name": "MYCHANNEL", + "containers": { + "INPUTCONTAINER": { + "text": "0001" + } + } + }, + "why": "'0001': LINK GETPOL, LINK GETSPND (each RETURNs), 'VERY VIP' into GETVIPSTATUS" + }, + { + "name": "other-account", + "commarea": null, + "channel": { + "name": "MYCHANNEL", + "containers": { + "INPUTCONTAINER": { + "text": "0002" + } + } + }, + "why": "'0002': the same LINKs, 'REGULAR ' into GETVIPSTATUS" + }, + { + "name": "no-channel", + "commarea": null, + "why": "no channel: GET CONTAINER without CHANNEL has no current channel -- INVREQ RESP2 4 (caught by RESP), ACCOUNT-NUMBER-IN keeps its initial value (no VALUE clause: oracle_assumptions.md L3) so the ELSE branch runs; PUT CONTAINER is INVREQ RESP2 4 too, then RETURN; there is no channel, so nothing more to compare" + } + ] +} diff --git a/tests/equivalence/asynccc-getaddr/LICENSE b/tests/equivalence/asynccc-getaddr/LICENSE new file mode 100644 index 000000000..cff851c9c --- /dev/null +++ b/tests/equivalence/asynccc-getaddr/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016 IBM Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/tests/equivalence/asynccc-getaddr/NOTICE b/tests/equivalence/asynccc-getaddr/NOTICE new file mode 100644 index 000000000..1969f1e6f --- /dev/null +++ b/tests/equivalence/asynccc-getaddr/NOTICE @@ -0,0 +1,9 @@ +CICS asynchronous API credit-card application example +https://github.com/cicsdev/cics-async-api-credit-card-application-example +Copyright IBM Corp. 2016 + +Licensed under the Apache License, Version 2.0 (see LICENSE, the corpus's own +licence file). The program under test, src/GETADDR.cbl, is the corpus's, used +unmodified from the corpus. +case.json (the scenarios, their input channel data and notes) was written for +this equivalence case; it contains no code or data from the corpus. diff --git a/tests/equivalence/asynccc-getaddr/case.json b/tests/equivalence/asynccc-getaddr/case.json new file mode 100644 index 000000000..6a8102784 --- /dev/null +++ b/tests/equivalence/asynccc-getaddr/case.json @@ -0,0 +1,47 @@ +{ + "kind": "cics", + "corpus": "cics-async-api-credit-card-application-example", + "program": "GETADDR", + "program_source": "src/GETADDR.cbl", + "copy_dirs": [], + "transid": "GETA", + "clock": "2026/10/01 10:30:15.00", + "datasets": {}, + "commarea": null, + "linked": true, + "screens": {}, + "notes": "IBM's CICS asynchronous API credit-card example: GETADDR (the address lookup, transaction GETA). GET CONTAINER(INPUTCONTAINER); '0001' is 1 HURSLEY PARK, WINCHESTER, UK / SO21 2JN, any other 123 HIGH STREET, LONDON, UK / S14 4WG; DELAY FOR SECONDS(5); PUT CONTAINER(GETADDRCONTAINER) the 80-byte address and PUT CONTAINER(GETPOSTCODE) the 8-byte postcode; RETURN. Its LINKAGE SECTION is empty: no COMMAREA (\"commarea\": null). The task starts with the channel its caller passes (#4270, oracle_assumptions.md X24): MYCHANNEL holding INPUTCONTAINER, the 4-byte account number ASYNCPNT / SEQPNT PUT there (no DATATYPE: BIT). The containers the task leaves on MYCHANNEL are compared at its end, as the caller sees them after FETCH CHILD / its LINK. Derived from github.com/cicsdev/cics-async-api-credit-card-application-example (Apache-2.0; Copyright IBM Corp. 2016): LICENSE here is the corpus's own, NOTICE names the source and what was derived.", + "scenarios": [ + { + "name": "account-0001", + "commarea": null, + "channel": { + "name": "MYCHANNEL", + "containers": { + "INPUTCONTAINER": { + "text": "0001" + } + } + }, + "why": "'0001': the Hursley address and SO21 2JN into GETADDRCONTAINER / GETPOSTCODE" + }, + { + "name": "other-account", + "commarea": null, + "channel": { + "name": "MYCHANNEL", + "containers": { + "INPUTCONTAINER": { + "text": "9999" + } + } + }, + "why": "'9999': the ELSE branch, the London address and S14 4WG" + }, + { + "name": "no-channel", + "commarea": null, + "why": "no channel: GET CONTAINER without CHANNEL has no current channel -- INVREQ RESP2 4 (caught by RESP), ACCOUNT-NUMBER-IN keeps its initial value (no VALUE clause: oracle_assumptions.md L3) so the ELSE branch runs; PUT CONTAINER is INVREQ RESP2 4 too, then RETURN; there is no channel, so nothing more to compare" + } + ] +} diff --git a/tests/equivalence/asynccc-getname/LICENSE b/tests/equivalence/asynccc-getname/LICENSE new file mode 100644 index 000000000..cff851c9c --- /dev/null +++ b/tests/equivalence/asynccc-getname/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016 IBM Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/tests/equivalence/asynccc-getname/NOTICE b/tests/equivalence/asynccc-getname/NOTICE new file mode 100644 index 000000000..e94e64800 --- /dev/null +++ b/tests/equivalence/asynccc-getname/NOTICE @@ -0,0 +1,9 @@ +CICS asynchronous API credit-card application example +https://github.com/cicsdev/cics-async-api-credit-card-application-example +Copyright IBM Corp. 2016 + +Licensed under the Apache License, Version 2.0 (see LICENSE, the corpus's own +licence file). The program under test, src/GETNAME.cbl, is the corpus's, used +unmodified from the corpus. +case.json (the scenarios, their input channel data and notes) was written for +this equivalence case; it contains no code or data from the corpus. diff --git a/tests/equivalence/asynccc-getname/case.json b/tests/equivalence/asynccc-getname/case.json new file mode 100644 index 000000000..fa07d160c --- /dev/null +++ b/tests/equivalence/asynccc-getname/case.json @@ -0,0 +1,47 @@ +{ + "kind": "cics", + "corpus": "cics-async-api-credit-card-application-example", + "program": "GETNAME", + "program_source": "src/GETNAME.cbl", + "copy_dirs": [], + "transid": "GETN", + "clock": "2026/10/01 10:30:15.00", + "datasets": {}, + "commarea": null, + "linked": true, + "screens": {}, + "notes": "IBM's CICS asynchronous API credit-card example: GETNAME (the customer-name lookup, transaction GETN). GET CONTAINER(INPUTCONTAINER); '0001' is PRADEEP GOHIL, any other JOE BLOGS; PUT CONTAINER(GETNAMECONTAINER) the 80-byte name; RETURN. Its LINKAGE SECTION is empty: no COMMAREA (\"commarea\": null). The task starts with the channel its caller passes (#4270, oracle_assumptions.md X24): MYCHANNEL holding INPUTCONTAINER, the 4-byte account number ASYNCPNT / SEQPNT PUT there (no DATATYPE: BIT). The containers the task leaves on MYCHANNEL are compared at its end, as the caller sees them after FETCH CHILD / its LINK. Derived from github.com/cicsdev/cics-async-api-credit-card-application-example (Apache-2.0; Copyright IBM Corp. 2016): LICENSE here is the corpus's own, NOTICE names the source and what was derived.", + "scenarios": [ + { + "name": "account-0001", + "commarea": null, + "channel": { + "name": "MYCHANNEL", + "containers": { + "INPUTCONTAINER": { + "text": "0001" + } + } + }, + "why": "'0001': PRADEEP GOHIL into GETNAMECONTAINER" + }, + { + "name": "other-account", + "commarea": null, + "channel": { + "name": "MYCHANNEL", + "containers": { + "INPUTCONTAINER": { + "text": "0002" + } + } + }, + "why": "'0002': the ELSE branch, JOE BLOGS" + }, + { + "name": "no-channel", + "commarea": null, + "why": "no channel: GET CONTAINER without CHANNEL has no current channel -- INVREQ RESP2 4 (caught by RESP), ACCOUNT-NUMBER-IN keeps its initial value (no VALUE clause: oracle_assumptions.md L3) so the ELSE branch runs; PUT CONTAINER is INVREQ RESP2 4 too, then RETURN; there is no channel, so nothing more to compare" + } + ] +} diff --git a/tests/equivalence/cics/ggcics.c b/tests/equivalence/cics/ggcics.c index 15242a11a..46a1a9764 100644 --- a/tests/equivalence/cics/ggcics.c +++ b/tests/equivalence/cics/ggcics.c @@ -5,6 +5,9 @@ * * Inputs come from $GGCICS_DIR: * commarea.in the COMMAREA the task starts with (its length is EIBCALEN) + * channel.cfg #4270 (X24): the channel the task starts with (GGCCHIN): its name, then + * `NAME BIT|CHAR HEX` per container ('-' for no bytes); GGCEND writes the + * current channel's containers at task end to $GGCICS_OUT/containers.out * commarea.exact #4270 (X23): the COMMAREA is exactly that long (a scenario's stated * length, shorter than the record): GGCAREA puts it before a guard page * receive_.bin what RECEIVE MAP() returns; absent means MAPFAIL @@ -1775,7 +1778,8 @@ int GGCLRET(gg_cics *c) { * INTOCCSID and INTOCODEPAGE are not specified, the value for conversion defaults to the CCSID * of the region") -- the translator refuses the CCSID options. A channel is in the scope of the * level that made it and of a level it is passed to (LINK CHANNEL: "the called program"; XCTL - * CHANNEL: the target). Containers are not events: a program shows what it got by what it does. */ + * CHANNEL: the target). Containers are not events: a program shows what it got by what it does -- and + * (#4270, X24) the containers a task leaves on its first program's current channel are compared at its end. */ #define MAX_CHANNELS 64 #define MAX_CONTAINERS 64 typedef struct { char name[17]; int bit; char *data; int len; int used; } gg_container; @@ -1948,6 +1952,70 @@ int GGCASCH(gg_cics *c) { return 0; } +/* #4270 (oracle_assumptions.md X24): the channel a task starts with ($GGCICS_DIR/channel.cfg) -- what a RUN TRANSID + * CHANNEL parent or a LINK CHANNEL caller passed -- made the first program's current channel, the only one in its + * scope. No file: no current channel, as before. */ +static int hexval(int ch) { + if (ch >= '0' && ch <= '9') return ch - '0'; + if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10; + if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10; + refuse("channel.cfg: a container's data is not hex"); + return 0; +} + +static int channel_in; /* a channel.cfg was read: the task's containers are written at its end */ + +int GGCCHIN(gg_cics *c) { + char path[4096], name[17], word[32], type[8]; + size_t size = 1 << 20; + (void)c; + snprintf(path, sizeof path, "%s/channel.cfg", dir_in()); + FILE *f = fopen(path, "r"); + if (!f) return 0; + char *line = malloc(size); + if (!line) refuse("out of memory"); + if (!fgets(line, (int)size, f) || sscanf(line, "%16s", name) != 1) refuse("channel.cfg: no channel name"); + int ch = channel_named(name, 1); + levels[0].cur = ch; + channel_in = 1; + while (fgets(line, (int)size, f)) { + char *hex = malloc(size); + if (!hex) refuse("out of memory"); + if (sscanf(line, "%31s %7s %s", word, type, hex) != 3 || strlen(word) > 16) refuse("channel.cfg: a container line"); + gg_container *k = container_named(&chans[ch - 1], word, 1); + k->bit = strcmp(type, "CHAR") != 0; + size_t n = strcmp(hex, "-") == 0 ? 0 : strlen(hex) / 2; + k->data = malloc(n + 1); + if (!k->data) refuse("out of memory"); + for (size_t i = 0; i < n; i++) k->data[i] = (char)(hexval(hex[2 * i]) * 16 + hexval(hex[2 * i + 1])); + k->len = (int)n; + free(hex); + } + free(line); + fclose(f); + return 0; +} + +/* #4270 (X24): the first program's current channel at task end, every container's bytes in hex -- only for a task + * started with a channel (channel.cfg), whose first program keeps it as its current channel to the end. */ +static void containers_out(void) { + char path[3000]; + if (!channel_in) return; + if (!levels[0].cur) refuse("the task's current channel gone at its end"); + gg_channel *ch = &chans[levels[0].cur - 1]; + snprintf(path, sizeof path, "%s/containers.out", dir_out()); + FILE *f = fopen(path, "w"); + if (!f) return; + fprintf(f, "CHANNEL %s\n", ch->name); + for (int i = 0; i < MAX_CONTAINERS; i++) { + if (!ch->c[i].used) continue; + fprintf(f, "%s ", ch->c[i].name); + for (int j = 0; j < ch->c[i].len; j++) fprintf(f, "%02X", (unsigned char)ch->c[i].data[j]); + fprintf(f, "\n"); + } + fclose(f); +} + /* ---- interval control (#4006) ---------------------------------------------------------- * * The virtual clock is $GGCICS_NOW; a task takes no time (SPEC 4). START records its request * as an event (with its expiry); the runner's scheduler keeps the requests and dispatches @@ -2351,5 +2419,6 @@ int GGCEND(gg_cics *c) { /* the task's program GOBACKed with no RETURN / XCTL / ABEND: at the highest level that GOBACK is the * RETURN (no TRANSID, no COMMAREA), as GGCPEND has it for a task run through GGCRUN */ if (!ended) return_event("", NULL, 0); + containers_out(); return 0; } diff --git a/tests/equivalence/det_sweep_coverage.json b/tests/equivalence/det_sweep_coverage.json index 8c8262870..ff8cf4459 100644 --- a/tests/equivalence/det_sweep_coverage.json +++ b/tests/equivalence/det_sweep_coverage.json @@ -2,6 +2,91 @@ "format": "det-sweep-coverage/1", "about": "#4270: the paragraph / branch coverage of each det-proven case, as `proof_sweep.py --det-only` reported it; written only by `tests/tools/det_coverage_ledger.py update SWEEP_DIR...`, checked by CI's det-sweep. An entry is trusted only while its input fingerprints match the tree (proof_blockers.py); stale or missing stays unknown.", "cases": { + "asynccc-crdtchk": { + "scenarios": 3, + "paragraphs": { + "covered": 1, + "live": 1 + }, + "branches": { + "covered": 2, + "total": 2 + }, + "inputs": { + "case": "91757418376cfc30e9db683b2ada855ac31d6afa3c9943afa40231330d981904", + "corpus": "a98b9cfe46b5f45db9305f0a997047218e09c7c36422ec0849f6af7af5dd5353", + "harness": "8ab54ed9dfcead1b10af65ca035b9312e3eaa2c216f0598a7c38e002e476e661", + "oracle": "3242708f13ca2c63a9276df4896d082df55c1b30c1042de17b970d9ad7eebdc3" + } + }, + "asynccc-csstats2": { + "scenarios": 3, + "paragraphs": { + "covered": 1, + "live": 1 + }, + "branches": { + "covered": 2, + "total": 2 + }, + "inputs": { + "case": "2ae5f7216cdf6b58f3594aef91fce8f9de1290c1a5427ba6806b0089191ee188", + "corpus": "a98b9cfe46b5f45db9305f0a997047218e09c7c36422ec0849f6af7af5dd5353", + "harness": "8ab54ed9dfcead1b10af65ca035b9312e3eaa2c216f0598a7c38e002e476e661", + "oracle": "3242708f13ca2c63a9276df4896d082df55c1b30c1042de17b970d9ad7eebdc3" + } + }, + "asynccc-csstatus": { + "scenarios": 3, + "paragraphs": { + "covered": 1, + "live": 1 + }, + "branches": { + "covered": 2, + "total": 2 + }, + "inputs": { + "case": "3080576e0121cd5ea20ea47dff4371dc63e2609c9517ea2c267c6e289d17a26e", + "corpus": "a98b9cfe46b5f45db9305f0a997047218e09c7c36422ec0849f6af7af5dd5353", + "harness": "8ab54ed9dfcead1b10af65ca035b9312e3eaa2c216f0598a7c38e002e476e661", + "oracle": "3242708f13ca2c63a9276df4896d082df55c1b30c1042de17b970d9ad7eebdc3" + } + }, + "asynccc-getaddr": { + "scenarios": 3, + "paragraphs": { + "covered": 1, + "live": 1 + }, + "branches": { + "covered": 2, + "total": 2 + }, + "inputs": { + "case": "daaa802061c35c541cc4904b8bdb26ad4102e4590fd07d7488e894b6f4bd2dbc", + "corpus": "a98b9cfe46b5f45db9305f0a997047218e09c7c36422ec0849f6af7af5dd5353", + "harness": "8ab54ed9dfcead1b10af65ca035b9312e3eaa2c216f0598a7c38e002e476e661", + "oracle": "3242708f13ca2c63a9276df4896d082df55c1b30c1042de17b970d9ad7eebdc3" + } + }, + "asynccc-getname": { + "scenarios": 3, + "paragraphs": { + "covered": 1, + "live": 1 + }, + "branches": { + "covered": 2, + "total": 2 + }, + "inputs": { + "case": "f6ca718be0ee1b2d7819adce6f3bfbc7a96ec371aed930ded05416e3a4fe5cc8", + "corpus": "a98b9cfe46b5f45db9305f0a997047218e09c7c36422ec0849f6af7af5dd5353", + "harness": "8ab54ed9dfcead1b10af65ca035b9312e3eaa2c216f0598a7c38e002e476e661", + "oracle": "3242708f13ca2c63a9276df4896d082df55c1b30c1042de17b970d9ad7eebdc3" + } + }, "asynccc-getpol": { "scenarios": 1, "paragraphs": { @@ -15,8 +100,8 @@ "inputs": { "case": "8715eb31cb1fe3d43aec7c2ce9de9d3b6e643b65113edc51fb979c8d39d43e21", "corpus": "a98b9cfe46b5f45db9305f0a997047218e09c7c36422ec0849f6af7af5dd5353", - "harness": "ff4e514ed862e7cc55a43ed599df0bb631c85b63de2e5e96f4b2093068ff15df", - "oracle": "812e95beccb670c5b2c432f18ec0c4656c1857c4c69d13aa88b1224635c58ab9" + "harness": "8ab54ed9dfcead1b10af65ca035b9312e3eaa2c216f0598a7c38e002e476e661", + "oracle": "3242708f13ca2c63a9276df4896d082df55c1b30c1042de17b970d9ad7eebdc3" } }, "asynccc-getspnd": { diff --git a/tests/tools/equivalence_cics.py b/tests/tools/equivalence_cics.py index b1ffa1986..9e7f8c6b0 100644 --- a/tests/tools/equivalence_cics.py +++ b/tests/tools/equivalence_cics.py @@ -973,6 +973,7 @@ def cics_driver(program: str, has_commarea: bool) -> str: lines += [" END-EVALUATE", " MOVE LOW-VALUES TO WS-CA", " CALL 'GGCLOAD' USING WS-CA BY VALUE LENGTH OF WS-CA", " RETURNING WS-LEN", " MOVE WS-LEN TO EIBCALEN", + " CALL 'GGCCHIN' USING GG-CICS", " SET WS-PTR TO ADDRESS OF WS-CA", " CALL 'GGCAREA' USING WS-PTR BY VALUE WS-LEN", " SET ADDRESS OF LK-CA TO WS-PTR", @@ -1323,6 +1324,64 @@ def commarea_length(sc: dict[str, Any], ca_fields: list[dict[str, Any]]) -> int return n +_CICS_NAME = re.compile(r"[^ ]{1,16}") + + +def scenario_channel(case: dict[str, Any], sc: dict[str, Any]) -> dict[str, Any] | None: + """#4270 (oracle_assumptions.md X24): the channel a scenario's task starts with -- `"channel": {"name": N, + "containers": {C: {"text": T | "hex": H, "datatype": "BIT" | "CHAR"}}}`, what a RUN TRANSID CHANNEL parent or a + LINK CHANNEL caller passed (the async credit-card services' MYCHANNEL / INPUTCONTAINER). Both sides make it the + first program's current channel. Text is in the case's data page; the data type defaults to BIT, as PUT + CONTAINER's does. {"name", "containers": [{"name", "data": bytes, "bit"}]}, None when not stated.""" + ch = sc.get("channel") + if ch is None: + return None + where = f"scenario {sc['name']}: channel" + if not isinstance(ch, dict) or not _CICS_NAME.fullmatch(str(ch.get("name", ""))): + raise Unsupported(f"{where}: a name of 1 to 16 characters with no blank", ["CHANNEL"]) + out = [] + for name, spec in (ch.get("containers") or {}).items(): + if not _CICS_NAME.fullmatch(name) or not isinstance(spec, dict) or ("text" in spec) == ("hex" in spec): + raise Unsupported(f"{where} container {name!r}: a name of 1 to 16 characters and one of text / hex", + ["CHANNEL"]) # fmt: skip + if spec.get("datatype", "BIT") not in ("BIT", "CHAR"): + raise Unsupported(f"{where} container {name}: datatype BIT or CHAR", ["CHANNEL"]) + data = spec["text"].encode(common.data_encoding(case)) if "text" in spec else bytes.fromhex(spec["hex"]) + out.append({"name": name, "data": data, "bit": spec.get("datatype", "BIT") == "BIT"}) + return {"name": ch["name"], "containers": out} + + +def _channel_json(case: dict[str, Any], sc: dict[str, Any]) -> dict[str, Any] | None: + """The scenario's channel (scenario_channel) as the generated Java test reads it: each container's bytes in hex.""" + chan = scenario_channel(case, sc) + if chan is None: + return None + return {"name": chan["name"], "containers": [{"name": k["name"], "hex": k["data"].hex().upper(), "bit": k["bit"]} + for k in chan["containers"]]} # fmt: skip + + +def case_transactions(case: dict[str, Any]) -> list[str]: + """#4270: the transactions the case's region defines (`"transactions": [...]`, a deployment fact the case states: + RUN TRANSID / START of any other is TRANSIDERR); absent, every transaction is defined, as before.""" + tx = case.get("transactions") + if not isinstance(tx, list) or not all(isinstance(t, str) and re.fullmatch(r"[A-Z0-9@#$]{1,4}", t) for t in tx): + raise Unsupported('"transactions": a list of 1- to 4-character transaction ids', ["TRANSACTIONS"]) + return sorted(set(tx)) + + +def task_containers(path: Path) -> dict[str, Any] | None: + """#4270 (X24): the stub's containers.out (GGCEND: the first program's current channel at task end, `CHANNEL N` + then `NAME HEX` per container) as the CONTAINERS event compares it; None when the task had no current channel.""" + if not path.is_file(): + return None + lines = path.read_text(encoding="ascii").splitlines() + containers = {} + for ln in lines[1:]: + name, _, data = ln.partition(" ") + containers[name] = data.strip().upper() + return {"channel": lines[0].split(" ", 1)[1].strip(), "containers": containers} + + def screen_fields(corpus: Path, case: dict[str, Any], map_name: str, side: str) -> list[dict[str, Any]]: scr = case["screens"][map_name] return common.layout_fields(corpus, str(common.case_path(corpus, scr["copybook"])), scr[side]) @@ -1525,6 +1584,13 @@ def run_cobol_cics(case: dict[str, Any], corpus: Path, work: Path, files: list[d area = area[:calen] (d / "commarea.exact").write_text(f"{calen}\n", encoding="ascii") (d / "commarea.in").write_bytes(area) + chan = scenario_channel(case, sc) + if chan is not None: # #4270 (X24): the channel the task starts with (GGCCHIN) + (d / "channel.cfg").write_text(f"{chan['name']}\n" + "".join( + f"{k['name']} {'BIT' if k['bit'] else 'CHAR'} {k['data'].hex().upper() or '-'}\n" + for k in chan["containers"]), encoding="ascii") # fmt: skip + if case.get("transactions") is not None: # #4270: the CSD's transactions (RUN TRANSID / START's TRANSIDERR) + (d / "transactions.cfg").write_text("".join(f"{t}\n" for t in case_transactions(case)), encoding="ascii") if task_facts(case, sc)[1] is not None: # #4270: what the operator typed (an unformatted RECEIVE) (d / "terminal.in").write_bytes(task_facts(case, sc)[1].encode(enc)) for q, items in ts_seed(case, sc).items(): # #4270: the TS queues the task starts with @@ -1845,6 +1911,7 @@ def outputs(out: Path, case: dict[str, Any], corpus: Path, ca_fields: list[dict[ res.setdefault("ts", []).append(_cobol_ts(kv, data, enc)) elif verb in ("READQ-TS", "RECEIVE"): # #4270 (GenApp LGICVS01): as CicsTask records them res.setdefault("reads", []).append(_cobol_read(verb, kv, data, enc)) + res["containers"] = task_containers(out / "containers.out") # #4270 (X24): the current channel's, at task end left = out / "commarea.out" # a LINKed program's result: the COMMAREA it left (ggcics GGCAOUT) res["linked_commarea"] = ( decode_record(left.read_bytes(), ca_fields, enc) if left.is_file() and left.stat().st_size else None @@ -2172,6 +2239,17 @@ def commarea_class(case: dict[str, Any], src: Path, svc_file: Path) -> str | Non runTask(service); return; } + if (commarea == null && m.getParameterCount() == 1 + && m.getParameterTypes()[0].getSimpleName().endsWith("ChannelIn")) { + // #4270: a channel program's handleLink takes its channel as a DTO, not a task: no task facade + // (#4343) can carry the scenario's task, so it runs through runTask, and `entries` says so + entry(program, "runTask (a channel program: handleLink(" + m.getParameterTypes()[0].getSimpleName() + + ") is no task facade, #4343)"); + started = true; + call(method(service, "runTask", 1), service, scenario); + ended = true; + return; + } if (commarea != null && !m.getParameterTypes()[0].isInstance(commarea)) { throw new FacadeRefused("handleLink of " + program + " takes a " + m.getParameterTypes()[0].getName() + ", the scenario's COMMAREA is a " + commarea.getClass().getName()); @@ -2367,11 +2445,17 @@ def cics_equivalence_test(case: dict[str, Any], src: Path, files: list[dict[str, f"else {{ {_svc_var(p)}.runTask(t); }} return; }}\n" for p in extras ) # the case's other programs (a LINK's target), each through its service (#4449: java-facade: its handleLink) - if programs is not None or extras: # the CSD's programs: an XCTL / LINK / INQUIRE of any other is PGMIDERR + transactions = case_transactions(case) if case.get("transactions") is not None else None + if programs is not None or extras or transactions is not None: # the CSD's programs: an XCTL / LINK / INQUIRE + # of any other is PGMIDERR; #4270: its transactions (a RUN TRANSID / START of any other is TRANSIDERR) defined = (f"java.util.Set.of({', '.join(f'{chr(34)}{p}{chr(34)}' for p in programs)}).contains(program)" if programs is not None else "true") # fmt: skip + tx_java = ("" if transactions is None else " public boolean transaction(String transid) { " + f"return java.util.Set.of({', '.join(f'{chr(34)}{t}{chr(34)}' for t in transactions)})" + ".contains(transid); }\n") # fmt: skip csd_java += (f" task.withPrograms(new CicsTask.Programs() {{\n" f" public boolean defined(String program) {{ return {defined}; }}\n" + f"{tx_java}" f" public void run(String program, CicsTask t) {{\n" f"{runs}" f' throw new NotRun(program); // #4173: the task ends here (NOPROGRAM)\n' @@ -2511,6 +2595,14 @@ class EquivalenceRunTest {{ if (calen != null) {{ task.withExactCommarea(); }} + if (sc.hasNonNull("channel")) {{ // #4270 (X24): the channel the task starts with, its current channel + CicsTask.Channel channel = new CicsTask.Channel(sc.get("channel").get("name").asText()); + for (JsonNode k : sc.get("channel").get("containers")) {{ + channel.with(k.get("name").asText(), java.util.HexFormat.of().parseHex(k.get("hex").asText()), + k.get("bit").asBoolean()); + }} + task.withChannel(channel); + }} FacadeRegion region = new FacadeRegion(task, commarea, "{case["program"]}", {"true" if case.get("linked") else "false"}); {csd_java} List faults = new ArrayList<>(); // #4023 follow-up: the scenario's injected conditions @@ -2572,6 +2664,15 @@ class EquivalenceRunTest {{ Map copy = new LinkedHashMap<>(e); {screen_copy} events.add(copy); }} + if (task.currentChannel() != null) {{ // #4270 (X24): the containers left on the task's current channel + Map left = new LinkedHashMap<>(); + left.put("event", "CONTAINERS"); + left.put("channel", task.currentChannel().name()); + Map data = new LinkedHashMap<>(); + task.currentChannel().containers().forEach((k, v) -> data.put(k, java.util.HexFormat.of().withUpperCase().formatHex(v))); + left.put("containers", data); + events.add(left); + }} if (commarea != null) {{ // a LINKed program's result: the COMMAREA it leaves (equivalence_cics.linked_result) Map left = new LinkedHashMap<>(); left.put("event", "COMMAREA"); @@ -2722,6 +2823,7 @@ def run_java_cics(case: dict[str, Any], corpus: Path, work: Path, cobol_work: Pa "commarea": ca, "receive": receive, "faults": fault_lines(sc), "sql_faults": sc.get("sql_plan", []), "sql_unjudged": sql_unjudged(sc.get("sql_plan", []), seams), "derived": bool(sc.get("derived")), "commarea_length": commarea_length(sc, ca_fields), + "channel": _channel_json(case, sc), "counters": _counters(case, sc), "taskn": task_number(case, sc), "startcode": task_facts(case, sc)[0], "terminal": task_facts(case, sc)[1], "ts": ts_seed(case, sc)}) # fmt: skip @@ -2967,6 +3069,12 @@ def cobol_events(res: dict[str, Any]) -> list[dict[str, Any]]: elif verb == "ABEND": m = re.search(r"\babcode=(\S*)", args) out.append({"event": "ABEND", "abcode": m.group(1) if m else ""}) + elif verb == "RUN": # #4270: RUN TRANSID CHILD, as CicsTask.runTransid records it (the child is not run here) + kv = dict(a.split("=", 1) for a in args.split() if "=" in a) + resp = RESP_NAMES.get(int(kv.get("resp", "0")), kv.get("resp", "")) + out.append({"event": "RUN", "transid": kv.get("transid", ""), "resp": resp}) + if res.get("containers") is not None: # #4270 (X24): the containers the task leaves on its current channel + out.append({"event": "CONTAINERS", **res["containers"]}) if res.get("linked_commarea") is not None: out.append({"event": "COMMAREA", "commarea": res["linked_commarea"]}) return out @@ -2983,8 +3091,12 @@ def linked_result(case: dict[str, Any], events: list[dict[str, Any]]) -> list[di """A LINKed program's events (`"linked": true` in the case): its result is the COMMAREA it leaves in its caller's storage, compared as a last COMMAREA event -- unless the task abended (no caller sees it then). Any other program's final COMMAREA storage is not observable (a terminal task's RETURN COMMAREA is), so it is dropped.""" - keep = case.get("linked") and not any(e.get("event") == "ABEND" for e in events) - return [_link_as_compared(e) for e in events if e.get("event") != "COMMAREA" or keep] + abended = any(e.get("event") == "ABEND" for e in events) + keep = case.get("linked") and not abended + # #4270 (X24): the containers left on the task's current channel are its result to whoever passed the channel + # (a LINK CHANNEL caller, a FETCH CHILD parent) -- unless the task abended, as the COMMAREA + return [_link_as_compared(e) for e in events + if (e.get("event") != "COMMAREA" or keep) and (e.get("event") != "CONTAINERS" or not abended)] # fmt: skip def _same(a: Any, b: Any) -> bool: @@ -3010,6 +3122,13 @@ def compare_events(cobol: list[dict[str, Any]], java: list[dict[str, Any]]) -> d for key in ("map", "transid", "program", "text", "abcode", "queue", "data", "resp", "item"): if key in c and not _same(c[key], j.get(key)): bad.append({"field": key, "cobol": c[key], "java": j.get(key)}) + if c["event"] == "CONTAINERS": # #4270 (X24): the channel's name and every container's bytes, both ways + if c.get("channel") != j.get("channel"): + bad.append({"field": "channel", "cobol": c.get("channel"), "java": j.get("channel")}) + cc, jc = c.get("containers") or {}, j.get("containers") or {} + for name in sorted(set(cc) | set(jc)): + if cc.get(name) != jc.get(name): + bad.append({"field": f"containers.{name}", "cobol": cc.get(name), "java": jc.get(name)}) for part in ("screen", "commarea"): cv, jv = c.get(part) or {}, j.get(part) or {} for name in cv: @@ -3211,7 +3330,8 @@ def x6_judged(sc: dict[str, Any], java_out: Path, cev: list[dict[str, Any]], java = f.read_text(encoding="utf-8").strip() if f.is_file() else None if not sc.get("prefix_x6") and java is None: return cev, jev, None - left = [e for e in cev if e.get("event") != "COMMAREA"], [e for e in jev if e.get("event") != "COMMAREA"] + end = ("COMMAREA", "CONTAINERS") # the end state, not compared for a task judged up to a refusal + left = [e for e in cev if e.get("event") not in end], [e for e in jev if e.get("event") not in end] cobol = sc.get("prefix_x6") def kind(said: str | None) -> str | None: # #4270: which refusal -- both sides must have stopped at the same one From 71ccf76786f2492c20d17e76074a8cad8772ca2b Mon Sep 17 00:00:00 2001 From: squid-protocol Date: Wed, 7 Oct 2026 17:59:07 -0400 Subject: [PATCH 2/2] docs: X24 before X25 in oracle_assumptions (after rebase) Co-Authored-By: Claude Opus 5.5 --- docs/language_status/oracle_assumptions.md | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/language_status/oracle_assumptions.md b/docs/language_status/oracle_assumptions.md index 2933a07f1..eefb96b73 100644 --- a/docs/language_status/oracle_assumptions.md +++ b/docs/language_status/oracle_assumptions.md @@ -926,24 +926,6 @@ The length READQ TS returns on ITEMERR or QIDERR is not documented, so it is not CA-ERROR-MSG and is judged up to X6. Pinned by `tests/cobol_mainframe/test_equivalence_cics.py` (the guard page, the driver, the length's checks) and `tests/cobol_mainframe/test_det_translate.py` (the det port's cut storage). -### X25. SYNCHRONIZED slack bytes -- 8-byte binary alignment ASSUMED to be IBM's fullword (#4266) - -- **The rule the layout model follows.** IBM Enterprise COBOL aligns a SYNCHRONIZED binary item of up to 4 digits on a - halfword and one of 5 to 18 digits (the 8-byte S9(10)-S9(18) included) on a fullword, COMP-1 / INDEX / pointers on a - fullword and COMP-2 on a doubleword, counted from the start of the record, which is doubleword-aligned - (). The slack bytes count toward the - group that holds the item. -- **Between the occurrences of a table** (an OCCURS group that holds SYNC items): the group's size, with the slack inside it, - is divided by the largest boundary any elementary item in it needs; when the remainder r is not zero, the compiler adds - m - r slack bytes at the end of each occurrence - (). `record_layout` and - `_storage_spans` do this. The rule is read from IBM's text; it was not run on z/OS. -- **The assumption.** The 8-byte binary stays on IBM's fullword because z/OS is the target. GnuCOBOL and Micro Focus may - align an 8-byte binary on a doubleword. If the GnuCOBOL oracle ever compares slack bytes (offsets after such an item, - or a record's length), the two can differ. -- **Reach today.** No committed case reaches it: no committed oracle case or answer-key layout holds an 8-byte binary - with SYNC after an off-boundary item. Status: ASSUMED. - ### X24. A task started with a channel; the containers it leaves compared — ASSUMED (#4270) - **What IBM documents** (CICS TS 6.x, "Scope of a channel"; RUN TRANSID CHANNEL: "the name of the channel that is to be passed to the child task"; FETCH CHILD CHANNEL: "the channel returned by the child task"; LINK CHANNEL: the @@ -972,6 +954,24 @@ The length READQ TS returns on ITEMERR or QIDERR is not documented, so it is not Pinned by `tests/cobol_mainframe/test_equivalence_cics.py` (the stub's channel in and containers out, the comparison, the drop on abend). +### X25. SYNCHRONIZED slack bytes -- 8-byte binary alignment ASSUMED to be IBM's fullword (#4266) + +- **The rule the layout model follows.** IBM Enterprise COBOL aligns a SYNCHRONIZED binary item of up to 4 digits on a + halfword and one of 5 to 18 digits (the 8-byte S9(10)-S9(18) included) on a fullword, COMP-1 / INDEX / pointers on a + fullword and COMP-2 on a doubleword, counted from the start of the record, which is doubleword-aligned + (). The slack bytes count toward the + group that holds the item. +- **Between the occurrences of a table** (an OCCURS group that holds SYNC items): the group's size, with the slack inside it, + is divided by the largest boundary any elementary item in it needs; when the remainder r is not zero, the compiler adds + m - r slack bytes at the end of each occurrence + (). `record_layout` and + `_storage_spans` do this. The rule is read from IBM's text; it was not run on z/OS. +- **The assumption.** The 8-byte binary stays on IBM's fullword because z/OS is the target. GnuCOBOL and Micro Focus may + align an 8-byte binary on a doubleword. If the GnuCOBOL oracle ever compares slack bytes (offsets after such an item, + or a record's length), the two can differ. +- **Reach today.** No committed case reaches it: no committed oracle case or answer-key layout holds an 8-byte binary + with SYNC after an off-boundary item. Status: ASSUMED. + ## Language Environment ### L1. CEEDAYS — MATCHED where documented, REFUSED otherwise