From 50186a23cd62fc6ce120f6114b428dc5c26b5a56 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Sat, 17 Oct 2026 09:23:04 +0000 Subject: test(multifile): cover imports, shared globals and exception propagation Allow fixtures to pass ordered source lists and require file-qualified negative diagnostics. Add native and runner cases for cross-unit calls, global mutation and shadowing, transitive imports, types, MAIN status, exception catches, runtime failures and destructor unwinding. Co-Authored-By: Claude Opus 5.5 --- tests/i/multifile-functions-globals/case.json | 6 +++++ tests/i/multifile-functions-globals/expected.txt | 6 +++++ tests/i/multifile-functions-globals/lib.cps | 27 ++++++++++++++++++++++ tests/i/multifile-functions-globals/notes.md | 5 ++++ tests/i/multifile-functions-globals/program.cps | 11 +++++++++ tests/i/multifile-main-exit/case.json | 7 ++++++ tests/i/multifile-main-exit/expected.txt | 1 + tests/i/multifile-main-exit/lib.cps | 9 ++++++++ tests/i/multifile-main-exit/notes.md | 5 ++++ tests/i/multifile-main-exit/program.cps | 6 +++++ tests/i/multifile-runtime-catch/case.json | 6 +++++ tests/i/multifile-runtime-catch/expected.txt | 3 +++ tests/i/multifile-runtime-catch/lib.cps | 3 +++ tests/i/multifile-runtime-catch/notes.md | 5 ++++ tests/i/multifile-runtime-catch/program.cps | 7 ++++++ tests/i/multifile-transitive-types/bridge.cps | 10 ++++++++ tests/i/multifile-transitive-types/case.json | 7 ++++++ tests/i/multifile-transitive-types/expected.txt | 2 ++ .../i/multifile-transitive-types/nested/values.cps | 6 +++++ tests/i/multifile-transitive-types/notes.md | 5 ++++ tests/i/multifile-transitive-types/program.cps | 8 +++++++ tests/i/multifile-try-catch/case.json | 7 ++++++ tests/i/multifile-try-catch/expected.txt | 7 ++++++ tests/i/multifile-try-catch/leaf.cps | 15 ++++++++++++ tests/i/multifile-try-catch/middle.cps | 13 +++++++++++ tests/i/multifile-try-catch/notes.md | 5 ++++ tests/i/multifile-try-catch/program.cps | 13 +++++++++++ tests/i/multifile-uncaught/case.json | 7 ++++++ tests/i/multifile-uncaught/expected.txt | 1 + tests/i/multifile-uncaught/lib.cps | 3 +++ tests/i/multifile-uncaught/notes.md | 5 ++++ tests/i/multifile-uncaught/program.cps | 5 ++++ 32 files changed, 226 insertions(+) create mode 100644 tests/i/multifile-functions-globals/case.json create mode 100644 tests/i/multifile-functions-globals/expected.txt create mode 100644 tests/i/multifile-functions-globals/lib.cps create mode 100644 tests/i/multifile-functions-globals/notes.md create mode 100644 tests/i/multifile-functions-globals/program.cps create mode 100644 tests/i/multifile-main-exit/case.json create mode 100644 tests/i/multifile-main-exit/expected.txt create mode 100644 tests/i/multifile-main-exit/lib.cps create mode 100644 tests/i/multifile-main-exit/notes.md create mode 100644 tests/i/multifile-main-exit/program.cps create mode 100644 tests/i/multifile-runtime-catch/case.json create mode 100644 tests/i/multifile-runtime-catch/expected.txt create mode 100644 tests/i/multifile-runtime-catch/lib.cps create mode 100644 tests/i/multifile-runtime-catch/notes.md create mode 100644 tests/i/multifile-runtime-catch/program.cps create mode 100644 tests/i/multifile-transitive-types/bridge.cps create mode 100644 tests/i/multifile-transitive-types/case.json create mode 100644 tests/i/multifile-transitive-types/expected.txt create mode 100644 tests/i/multifile-transitive-types/nested/values.cps create mode 100644 tests/i/multifile-transitive-types/notes.md create mode 100644 tests/i/multifile-transitive-types/program.cps create mode 100644 tests/i/multifile-try-catch/case.json create mode 100644 tests/i/multifile-try-catch/expected.txt create mode 100644 tests/i/multifile-try-catch/leaf.cps create mode 100644 tests/i/multifile-try-catch/middle.cps create mode 100644 tests/i/multifile-try-catch/notes.md create mode 100644 tests/i/multifile-try-catch/program.cps create mode 100644 tests/i/multifile-uncaught/case.json create mode 100644 tests/i/multifile-uncaught/expected.txt create mode 100644 tests/i/multifile-uncaught/lib.cps create mode 100644 tests/i/multifile-uncaught/notes.md create mode 100644 tests/i/multifile-uncaught/program.cps (limited to 'tests/i') diff --git a/tests/i/multifile-functions-globals/case.json b/tests/i/multifile-functions-globals/case.json new file mode 100644 index 0000000..032ec6a --- /dev/null +++ b/tests/i/multifile-functions-globals/case.json @@ -0,0 +1,6 @@ +{ + "sources": [ + "program.cps", + "lib.cps" + ] +} diff --git a/tests/i/multifile-functions-globals/expected.txt b/tests/i/multifile-functions-globals/expected.txt new file mode 100644 index 0000000..86906d2 --- /dev/null +++ b/tests/i/multifile-functions-globals/expected.txt @@ -0,0 +1,6 @@ +3 +3:shared:TRUE:Q:TRUE +5 +40 +5 +99:7 diff --git a/tests/i/multifile-functions-globals/lib.cps b/tests/i/multifile-functions-globals/lib.cps new file mode 100644 index 0000000..0d09ad5 --- /dev/null +++ b/tests/i/multifile-functions-globals/lib.cps @@ -0,0 +1,27 @@ +CONSTANT Offset = 2 +FUNCTION Add(a : INTEGER, b : INTEGER) RETURNS INTEGER + RETURN a + b +ENDFUNCTION +PROCEDURE Increment() + Counter <- Counter + Offset +ENDPROCEDURE +PROCEDURE Shadow() + DECLARE Counter : INTEGER + Counter <- 40 + OUTPUT Counter +ENDPROCEDURE +FUNCTION ReadCounter RETURNS INTEGER + RETURN Counter +ENDFUNCTION +GLOBAL + DECLARE Counter : INTEGER + Counter <- 3 + DECLARE Label : STRING + Label <- "shared" + DECLARE Enabled : BOOLEAN + Enabled <- TRUE + DECLARE Initial : CHAR + Initial <- 'Q' + DECLARE Ratio : REAL + Ratio <- -1.5 +ENDGLOBAL diff --git a/tests/i/multifile-functions-globals/notes.md b/tests/i/multifile-functions-globals/notes.md new file mode 100644 index 0000000..632c848 --- /dev/null +++ b/tests/i/multifile-functions-globals/notes.md @@ -0,0 +1,5 @@ +# Multi-file regression + +Human review: pending. Expected output was independently traced by AI. + +These are compiler extensions, not Cambridge guide requirements. Add returns 3. Globals start at 3/shared/TRUE/Q/-1.5. Increment adds the library constant 2. Shadow prints its local 40 without changing the global 5. The entry local 99 survives another library increment; ReadCounter returns the shared 7. Functions precede GLOBAL declarations to check pre-pass visibility. diff --git a/tests/i/multifile-functions-globals/program.cps b/tests/i/multifile-functions-globals/program.cps new file mode 100644 index 0000000..e5e6a6c --- /dev/null +++ b/tests/i/multifile-functions-globals/program.cps @@ -0,0 +1,11 @@ +INCLUDE "lib.cps" +OUTPUT Add(1, 2) +OUTPUT Counter, ":", Label, ":", Enabled, ":", Initial, ":", Ratio = -1.5 +CALL Increment() +OUTPUT Counter +CALL Shadow() +OUTPUT Counter +DECLARE Counter : INTEGER +Counter <- 99 +CALL Increment() +OUTPUT Counter, ":", ReadCounter() diff --git a/tests/i/multifile-main-exit/case.json b/tests/i/multifile-main-exit/case.json new file mode 100644 index 0000000..3cfd155 --- /dev/null +++ b/tests/i/multifile-main-exit/case.json @@ -0,0 +1,7 @@ +{ + "sources": [ + "lib.cps", + "program.cps" + ], + "exit_code": 3 +} diff --git a/tests/i/multifile-main-exit/expected.txt b/tests/i/multifile-main-exit/expected.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/i/multifile-main-exit/expected.txt @@ -0,0 +1 @@ +1 diff --git a/tests/i/multifile-main-exit/lib.cps b/tests/i/multifile-main-exit/lib.cps new file mode 100644 index 0000000..2bb4941 --- /dev/null +++ b/tests/i/multifile-main-exit/lib.cps @@ -0,0 +1,9 @@ +GLOBAL + DECLARE Counter : INTEGER +ENDGLOBAL +PROCEDURE Increment() + Counter <- Counter + 1 +ENDPROCEDURE +FUNCTION Status RETURNS INTEGER + RETURN 4294967298 + Counter +ENDFUNCTION diff --git a/tests/i/multifile-main-exit/notes.md b/tests/i/multifile-main-exit/notes.md new file mode 100644 index 0000000..486abab --- /dev/null +++ b/tests/i/multifile-main-exit/notes.md @@ -0,0 +1,5 @@ +# Multi-file regression + +Human review: pending. Expected output was independently traced by AI. + +These are compiler extensions, not Cambridge guide requirements. The entry is the second input and its name has mixed case. Increment changes the shared counter from 0 to 1. Status returns 4294967299, whose low 32 bits are 3; both native execution and the configured runner must return status 3. diff --git a/tests/i/multifile-main-exit/program.cps b/tests/i/multifile-main-exit/program.cps new file mode 100644 index 0000000..928d4df --- /dev/null +++ b/tests/i/multifile-main-exit/program.cps @@ -0,0 +1,6 @@ +INCLUDE "lib.cps" +FUNCTION mAiN RETURNS INTEGER + CALL Increment() + OUTPUT Counter + RETURN Status() +ENDFUNCTION diff --git a/tests/i/multifile-runtime-catch/case.json b/tests/i/multifile-runtime-catch/case.json new file mode 100644 index 0000000..032ec6a --- /dev/null +++ b/tests/i/multifile-runtime-catch/case.json @@ -0,0 +1,6 @@ +{ + "sources": [ + "program.cps", + "lib.cps" + ] +} diff --git a/tests/i/multifile-runtime-catch/expected.txt b/tests/i/multifile-runtime-catch/expected.txt new file mode 100644 index 0000000..731df7f --- /dev/null +++ b/tests/i/multifile-runtime-catch/expected.txt @@ -0,0 +1,3 @@ +[Fatal] line 2: Division by zero +runtime caught +5 diff --git a/tests/i/multifile-runtime-catch/lib.cps b/tests/i/multifile-runtime-catch/lib.cps new file mode 100644 index 0000000..694eaf6 --- /dev/null +++ b/tests/i/multifile-runtime-catch/lib.cps @@ -0,0 +1,3 @@ +FUNCTION Quotient(Divisor : INTEGER) RETURNS INTEGER + RETURN 10 DIV Divisor +ENDFUNCTION diff --git a/tests/i/multifile-runtime-catch/notes.md b/tests/i/multifile-runtime-catch/notes.md new file mode 100644 index 0000000..d3a118f --- /dev/null +++ b/tests/i/multifile-runtime-catch/notes.md @@ -0,0 +1,5 @@ +# Cross-file runtime-check regression + +Human review: pending. Expected output was independently traced by AI. + +TRY/CATCH and multi-file builds are compiler extensions. Quotient(0) fails at the division on library line 2, printing the exact runtime diagnostic before throwing. The entry catches it and continues. Quotient(2) then returns 5, proving the handler leaves execution usable. diff --git a/tests/i/multifile-runtime-catch/program.cps b/tests/i/multifile-runtime-catch/program.cps new file mode 100644 index 0000000..3d11099 --- /dev/null +++ b/tests/i/multifile-runtime-catch/program.cps @@ -0,0 +1,7 @@ +INCLUDE "lib.cps" +TRY + OUTPUT Quotient(0) +CATCH + OUTPUT "runtime caught" +ENDTRY +OUTPUT Quotient(2) diff --git a/tests/i/multifile-transitive-types/bridge.cps b/tests/i/multifile-transitive-types/bridge.cps new file mode 100644 index 0000000..cbdcae8 --- /dev/null +++ b/tests/i/multifile-transitive-types/bridge.cps @@ -0,0 +1,10 @@ +INCLUDE "nested/values.cps" +CLASS Container + Value : INTEGER + FUNCTION Read RETURNS INTEGER + RETURN Value + Base + ENDFUNCTION +ENDCLASS +TYPE Pair + DECLARE Value : INTEGER +ENDTYPE diff --git a/tests/i/multifile-transitive-types/case.json b/tests/i/multifile-transitive-types/case.json new file mode 100644 index 0000000..445f846 --- /dev/null +++ b/tests/i/multifile-transitive-types/case.json @@ -0,0 +1,7 @@ +{ + "sources": [ + "program.cps", + "bridge.cps", + "nested/values.cps" + ] +} diff --git a/tests/i/multifile-transitive-types/expected.txt b/tests/i/multifile-transitive-types/expected.txt new file mode 100644 index 0000000..a14bbdb --- /dev/null +++ b/tests/i/multifile-transitive-types/expected.txt @@ -0,0 +1,2 @@ +11:6:0 +11 diff --git a/tests/i/multifile-transitive-types/nested/values.cps b/tests/i/multifile-transitive-types/nested/values.cps new file mode 100644 index 0000000..713ffce --- /dev/null +++ b/tests/i/multifile-transitive-types/nested/values.cps @@ -0,0 +1,6 @@ +INCLUDE "../bridge.cps" +CONSTANT Base = 3 +TYPE Choice = (First, Second) +FUNCTION Twice(n : INTEGER) RETURNS INTEGER + RETURN n * 2 +ENDFUNCTION diff --git a/tests/i/multifile-transitive-types/notes.md b/tests/i/multifile-transitive-types/notes.md new file mode 100644 index 0000000..160c801 --- /dev/null +++ b/tests/i/multifile-transitive-types/notes.md @@ -0,0 +1,5 @@ +# Multi-file regression + +Human review: pending. Expected output was independently traced by AI. + +These are compiler extensions, not Cambridge guide requirements. The bridge imports nested values and the nested file imports the bridge, forming a cycle; repeated imports must not duplicate definitions. The entry sees Base=3, Twice and the enum through the bridge. Container.Read computes 8+3=11, Twice(3)=6, First has ordinal 0, and Pair stores 11. This covers imported methods, records, enums and constants, plus relative nested paths. diff --git a/tests/i/multifile-transitive-types/program.cps b/tests/i/multifile-transitive-types/program.cps new file mode 100644 index 0000000..9f4e6bd --- /dev/null +++ b/tests/i/multifile-transitive-types/program.cps @@ -0,0 +1,8 @@ +INCLUDE "bridge.cps" +INCLUDE "bridge.cps" +DECLARE Item : Container +Item.Value <- 8 +OUTPUT Item.Read(), ":", Twice(Base), ":", First +DECLARE Node : Pair +Node.Value <- Item.Read() +OUTPUT Node.Value diff --git a/tests/i/multifile-try-catch/case.json b/tests/i/multifile-try-catch/case.json new file mode 100644 index 0000000..edcaa8c --- /dev/null +++ b/tests/i/multifile-try-catch/case.json @@ -0,0 +1,7 @@ +{ + "sources": [ + "program.cps", + "middle.cps", + "leaf.cps" + ] +} diff --git a/tests/i/multifile-try-catch/expected.txt b/tests/i/multifile-try-catch/expected.txt new file mode 100644 index 0000000..3560fb1 --- /dev/null +++ b/tests/i/multifile-try-catch/expected.txt @@ -0,0 +1,7 @@ +destroy:2 +destroy:1 +caught:2 +continued +destroy:2 +library caught:3 +returned diff --git a/tests/i/multifile-try-catch/leaf.cps b/tests/i/multifile-try-catch/leaf.cps new file mode 100644 index 0000000..44b991a --- /dev/null +++ b/tests/i/multifile-try-catch/leaf.cps @@ -0,0 +1,15 @@ +GLOBAL + DECLARE Destroyed : INTEGER +ENDGLOBAL +CLASS Guard + Id : INTEGER + PROCEDURE DELETE() + OUTPUT "destroy:", Id + Destroyed <- Destroyed + 1 + ENDPROCEDURE +ENDCLASS +PROCEDURE Raise() + DECLARE GuardTwo : Guard + GuardTwo.Id <- 2 + THROW +ENDPROCEDURE diff --git a/tests/i/multifile-try-catch/middle.cps b/tests/i/multifile-try-catch/middle.cps new file mode 100644 index 0000000..11b8a85 --- /dev/null +++ b/tests/i/multifile-try-catch/middle.cps @@ -0,0 +1,13 @@ +INCLUDE "leaf.cps" +PROCEDURE Outer() + DECLARE GuardOne : Guard + GuardOne.Id <- 1 + CALL Raise() +ENDPROCEDURE +PROCEDURE CatchHere() + TRY + CALL Raise() + CATCH + OUTPUT "library caught:", Destroyed + ENDTRY +ENDPROCEDURE diff --git a/tests/i/multifile-try-catch/notes.md b/tests/i/multifile-try-catch/notes.md new file mode 100644 index 0000000..cf7f961 --- /dev/null +++ b/tests/i/multifile-try-catch/notes.md @@ -0,0 +1,5 @@ +# Multi-file regression + +Human review: pending. Expected output was independently traced by AI. + +These are compiler extensions, not Cambridge guide requirements. Raise destroys guard 2, then unwinding Outer destroys guard 1 before the entry catch reads Destroyed=2. Execution continues. CatchHere catches another Raise inside the middle file; only guard 2 is destroyed, yielding Destroyed=3, and the entry outer catch must not run. Every throw crosses a unit boundary and cleanup runs before catch output. diff --git a/tests/i/multifile-try-catch/program.cps b/tests/i/multifile-try-catch/program.cps new file mode 100644 index 0000000..ec3edca --- /dev/null +++ b/tests/i/multifile-try-catch/program.cps @@ -0,0 +1,13 @@ +INCLUDE "middle.cps" +TRY + CALL Outer() +CATCH + OUTPUT "caught:", Destroyed +ENDTRY +OUTPUT "continued" +TRY + CALL CatchHere() + OUTPUT "returned" +CATCH + OUTPUT "wrong handler" +ENDTRY diff --git a/tests/i/multifile-uncaught/case.json b/tests/i/multifile-uncaught/case.json new file mode 100644 index 0000000..bd1e132 --- /dev/null +++ b/tests/i/multifile-uncaught/case.json @@ -0,0 +1,7 @@ +{ + "sources": [ + "program.cps", + "lib.cps" + ], + "exit_code": 1 +} diff --git a/tests/i/multifile-uncaught/expected.txt b/tests/i/multifile-uncaught/expected.txt new file mode 100644 index 0000000..e9431ec --- /dev/null +++ b/tests/i/multifile-uncaught/expected.txt @@ -0,0 +1 @@ +Unhandled exception. Program terminated. diff --git a/tests/i/multifile-uncaught/lib.cps b/tests/i/multifile-uncaught/lib.cps new file mode 100644 index 0000000..c482a6d --- /dev/null +++ b/tests/i/multifile-uncaught/lib.cps @@ -0,0 +1,3 @@ +PROCEDURE Fail() + THROW +ENDPROCEDURE diff --git a/tests/i/multifile-uncaught/notes.md b/tests/i/multifile-uncaught/notes.md new file mode 100644 index 0000000..f89adf8 --- /dev/null +++ b/tests/i/multifile-uncaught/notes.md @@ -0,0 +1,5 @@ +# Multi-file regression + +Human review: pending. Expected output was independently traced by AI. + +These are compiler extensions, not Cambridge guide requirements. Fail throws in the library, unwinds the explicit MAIN function and reaches the generated wrapper handler. Exactly the generic message is printed and the process returns 1. diff --git a/tests/i/multifile-uncaught/program.cps b/tests/i/multifile-uncaught/program.cps new file mode 100644 index 0000000..d61ea3b --- /dev/null +++ b/tests/i/multifile-uncaught/program.cps @@ -0,0 +1,5 @@ +INCLUDE "lib.cps" +FUNCTION MAIN RETURNS INTEGER + CALL Fail() + RETURN 0 +ENDFUNCTION -- cgit v1.3.1-4-g156e