tinymux/testcases/lua_fn.mux
2026-07-29 15:31:00 -06:00

1589 lines
37 KiB
Text
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#
# lua_fn.mux - Test Cases for lua() function and Lua module.
#
@create test_lua_fn
-
@set test_lua_fn=INHERIT QUIET
-
#
# Beginning of Test Cases
#
&tr.tc000 test_lua_fn=
@log smoke=Beginning lua() test cases.
-
#
# Test 1: Basic arithmetic — return an integer sum.
#
&LUA_ADD test_lua_fn=return mux.args[1] + mux.args[2]
-
&tr.tc001 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_ADD,2,3)),
5)=
{
@log smoke=TC001: lua basic arithmetic. Succeeded.
},
{
@log smoke=TC001: lua basic arithmetic. Failed (%q0).
}
-
#
# Test 2: String return — return a literal string.
#
&LUA_HELLO test_lua_fn=return "hello world"
-
&tr.tc002 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_HELLO)),
hello world)=
{
@log smoke=TC002: lua string return. Succeeded.
},
{
@log smoke=TC002: lua string return. Failed (%q0).
}
-
#
# Test 3: String concatenation with args.
#
&LUA_CAT test_lua_fn=return mux.args[1] .. " " .. mux.args[2]
-
&tr.tc003 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_CAT,foo,bar)),
foo bar)=
{
@log smoke=TC003: lua string concat. Succeeded.
},
{
@log smoke=TC003: lua string concat. Failed (%q0).
}
-
#
# Test 4: Nil return produces empty string.
#
&LUA_NIL test_lua_fn=return nil
-
&tr.tc004 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_NIL)),
)=
{
@log smoke=TC004: lua nil return is empty. Succeeded.
},
{
@log smoke=TC004: lua nil return is empty. Failed (%q0).
}
-
#
# Test 5: Boolean return — true becomes "1", false becomes "0".
#
&LUA_BOOL test_lua_fn=return true
-
&tr.tc005 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_BOOL)),
1)=
{
@log smoke=TC005: lua boolean return. Succeeded.
},
{
@log smoke=TC005: lua boolean return. Failed (%q0).
}
-
#
# Test 6: Sandbox — os.execute is blocked.
#
&LUA_OS test_lua_fn=return os.execute("echo pwned")
-
# #1751 Phase 0 interim: os is nil and GETGLOBAL loud-fails post-entry.
# Phase 1 (total GETGLOBAL) restores the LUA ERROR leg; tighten then.
&tr.tc006 test_lua_fn=
@if or(
strmatch(setr(0,lua(me/LUA_OS)),#-1 LUA ERROR:*),
strmatch(%q0,#-1 LUA JIT POST-ENTRY DECLINE*))=
{
@log smoke=TC006: lua sandbox blocks os. Succeeded.
},
{
@log smoke=TC006: lua sandbox blocks os. Failed (%q0).
}
-
#
# Test 7: Sandbox — io.open is blocked.
#
&LUA_IO test_lua_fn=return io.open("/etc/passwd")
-
# #1751 Phase 0 interim; see TC006.
&tr.tc007 test_lua_fn=
@if or(
strmatch(setr(0,lua(me/LUA_IO)),#-1 LUA ERROR:*),
strmatch(%q0,#-1 LUA JIT POST-ENTRY DECLINE*))=
{
@log smoke=TC007: lua sandbox blocks io. Succeeded.
},
{
@log smoke=TC007: lua sandbox blocks io. Failed (%q0).
}
-
#
# Test 8: Sandbox — load() is blocked.
#
&LUA_LOAD test_lua_fn=return load("return 42")()
-
&tr.tc008 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_LOAD)),
#-1 LUA ERROR:*)=
{
@log smoke=TC008: lua sandbox blocks load. Succeeded.
},
{
@log smoke=TC008: lua sandbox blocks load. Failed (%q0).
}
-
#
# Test 9: Instruction limit — infinite loop triggers error.
#
&LUA_LOOP test_lua_fn=while true do end
-
# #1751 Phase 0 interim: budget exhaustion is a loud POST-ENTRY DECLINE
# (ECALL_LUA_LIMITED), not the interpreter re-run's limit error. Phase 3
# converges the text; tighten back to the single pattern then.
&tr.tc009 test_lua_fn=
@if or(
strmatch(setr(0,lua(me/LUA_LOOP)),#-1 LUA ERROR:*instruction limit*),
strmatch(%q0,#-1 LUA JIT POST-ENTRY DECLINE (ECALL_LUA_LIMITED)*))=
{
@log smoke=TC009: lua instruction limit. Succeeded.
},
{
@log smoke=TC009: lua instruction limit. Failed (%q0).
}
-
#
# Test 10: math library works.
#
&LUA_MATH test_lua_fn=return math.floor(math.sqrt(144))
-
&tr.tc010 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_MATH)),
12)=
{
@log smoke=TC010: lua math library. Succeeded.
},
{
@log smoke=TC010: lua math library. Failed (%q0).
}
-
#
# Test 11: string library works.
#
&LUA_STR test_lua_fn=return string.upper("hello")
-
&tr.tc011 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_STR)),
HELLO)=
{
@log smoke=TC011: lua string library. Succeeded.
},
{
@log smoke=TC011: lua string library. Failed (%q0).
}
-
#
# Test 12: table library works.
#
&LUA_TBL test_lua_fn=local t = {3,1,2} table.sort(t) return t[1]..t[2]..t[3]
-
&tr.tc012 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_TBL)),
123)=
{
@log smoke=TC012: lua table library. Succeeded.
},
{
@log smoke=TC012: lua table library. Failed (%q0).
}
-
#
# Test 13: mux.name() bridge — read object name.
#
&LUA_NAME test_lua_fn=return mux.name(1)
-
&tr.tc013 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_NAME)),
Wizard)=
{
@log smoke=TC013: lua mux.name bridge. Succeeded.
},
{
@log smoke=TC013: lua mux.name bridge. Failed (%q0).
}
-
#
# Test 14: mux.eval() bridge — evaluate softcode.
#
&LUA_EVAL test_lua_fn=return mux.eval("add(10,20)")
-
&tr.tc014 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_EVAL)),
30)=
{
@log smoke=TC014: lua mux.eval bridge. Succeeded.
},
{
@log smoke=TC014: lua mux.eval bridge. Failed (%q0).
}
-
#
# Test 15: Compile error — bad syntax returns error.
#
&LUA_BAD test_lua_fn=this is not valid lua!!!!
-
&tr.tc015 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_BAD)),
#-1 LUA ERROR:*)=
{
@log smoke=TC015: lua compile error. Succeeded.
},
{
@log smoke=TC015: lua compile error. Failed (%q0).
}
-
#
# Test 16: Empty attribute returns empty string.
#
&LUA_EMPTY test_lua_fn=
-
&tr.tc016 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_EMPTY)),
)=
{
@log smoke=TC016: lua empty attr. Succeeded.
},
{
@log smoke=TC016: lua empty attr. Failed (%q0).
}
-
#
# Test 17: Missing attribute returns error.
#
&tr.tc017 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_NOEXIST)),
#-1 LUA ERROR:*)=
{
@log smoke=TC017: lua missing attr error. Succeeded.
},
{
@log smoke=TC017: lua missing attr error. Failed (%q0).
}
-
#
# Test 18: No slash in argument returns error.
#
&tr.tc018 test_lua_fn=
@if strmatch(
setr(0,lua(me)),
#-1 NO ATTRIBUTE SPECIFIED)=
{
@log smoke=TC018: lua no-slash error. Succeeded.
},
{
@log smoke=TC018: lua no-slash error. Failed (%q0).
}
-
#
# Test 19: Numeric for loop works (exercises Lua VM).
#
&LUA_FORLOOP test_lua_fn=local s=0 for i=1,100 do s=s+i end return s
-
&tr.tc019 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_FORLOOP)),
5050)=
{
@log smoke=TC019: lua for loop. Succeeded.
},
{
@log smoke=TC019: lua for loop. Failed (%q0).
}
-
#
# Test 20: Multiple arguments in mux.args.
#
&LUA_NARGS test_lua_fn=return #mux.args
-
&tr.tc020 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_NARGS,a,b,c,d,e)),
5)=
{
@log smoke=TC020: lua arg count. Succeeded.
},
{
@log smoke=TC020: lua arg count. Failed (%q0).
}
-
#
# Test 21: Pure integer subtraction (JIT-eligible: LOADI+SUB+RETURN1).
#
&LUA_SUB test_lua_fn=return 100 - 37
-
&tr.tc021 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_SUB)),
63)=
{
@log smoke=TC021: lua integer subtract. Succeeded.
},
{
@log smoke=TC021: lua integer subtract. Failed (%q0).
}
-
#
# Test 22: Multiplication chain (JIT-eligible: multiple arithmetic ops).
#
&LUA_MULCHAIN test_lua_fn=return 3 * 4 * 5
-
&tr.tc022 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_MULCHAIN)),
60)=
{
@log smoke=TC022: lua multiply chain. Succeeded.
},
{
@log smoke=TC022: lua multiply chain. Failed (%q0).
}
-
#
# Test 23: Integer division and modulo (JIT-eligible: IDIV+MOD).
#
&LUA_DIVMOD test_lua_fn=return (17 // 5) * 10 + (17 % 5)
-
&tr.tc023 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_DIVMOD)),
32)=
{
@log smoke=TC023: lua idiv and mod. Succeeded.
},
{
@log smoke=TC023: lua idiv and mod. Failed (%q0).
}
-
#
# Test 24: Unary minus (JIT-eligible: UNM).
#
&LUA_NEGATE test_lua_fn=return -(42)
-
&tr.tc024 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_NEGATE)),
-42)=
{
@log smoke=TC024: lua unary minus. Succeeded.
},
{
@log smoke=TC024: lua unary minus. Failed (%q0).
}
-
#
# Test 25: Arithmetic with mux.args (JIT-eligible: args + ADD).
#
&LUA_ARITH_ARGS test_lua_fn=return mux.args[1] * mux.args[2] + mux.args[3]
-
&tr.tc025 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_ARITH_ARGS,6,7,8)),
50)=
{
@log smoke=TC025: lua args arithmetic. Succeeded.
},
{
@log smoke=TC025: lua args arithmetic. Failed (%q0).
}
-
#
# Test 26: Numeric for loop — sum 1..100 = 5050.
# Same as TC019 but exercises the STORE_Q/LOAD_Q PHI path.
# Repeated here to verify JIT for-loop parity.
#
&LUA_SUM100 test_lua_fn=local s=0 for i=1,100 do s=s+i end return s
-
&tr.tc026 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_SUM100)),
5050)=
{
@log smoke=TC026: lua for-loop sum 1..100. Succeeded.
},
{
@log smoke=TC026: lua for-loop sum 1..100. Failed (%q0).
}
-
#
# Test 27: Numeric for loop with step — sum of odds 1..99.
# for i=1,99,2 do s=s+i end → 2500
#
&LUA_ODDS test_lua_fn=local s=0 for i=1,99,2 do s=s+i end return s
-
&tr.tc027 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_ODDS)),
2500)=
{
@log smoke=TC027: lua for-loop step=2 (odds). Succeeded.
},
{
@log smoke=TC027: lua for-loop step=2 (odds). Failed (%q0).
}
-
#
# Test 28: Nested arithmetic — Fibonacci-style computation.
# a=1, b=1, for i=1,10 do c=a+b, a=b, b=c end, return b → 144
#
&LUA_FIB test_lua_fn=local a,b=1,1 for i=1,10 do local c=a+b a=b b=c end return b
-
&tr.tc028 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_FIB)),
144)=
{
@log smoke=TC028: lua fibonacci loop. Succeeded.
},
{
@log smoke=TC028: lua fibonacci loop. Failed (%q0).
}
-
#
# Test 29: Conditional — if/else returns different values.
# This exercises TEST/JMP multi-block paths.
#
&LUA_COND test_lua_fn=if mux.args[1] + 0 > 10 then return "big" else return "small" end
-
&tr.tc029 test_lua_fn=
@if cand(
strmatch(setr(0,lua(me/LUA_COND,20)),big),
strmatch(setr(1,lua(me/LUA_COND,5)),small))=
{
@log smoke=TC029: lua if/else conditional. Succeeded.
},
{
@log smoke=TC029: lua if/else conditional. Failed (%q0 %q1).
}
-
#
# Test 30: String-heavy script falls back to VM gracefully.
# String concat uses OP_CONCAT which is not JIT-eligible.
# Should produce the correct result via Lua VM fallback.
#
&LUA_STRFALL test_lua_fn=return string.rep("ab", 3)
-
&tr.tc030 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_STRFALL)),
ababab)=
{
@log smoke=TC030: lua VM fallback for strings. Succeeded.
},
{
@log smoke=TC030: lua VM fallback for strings. Failed (%q0).
}
-
#
# Test 31: Table operations fall back to VM gracefully.
#
&LUA_TBLFALL test_lua_fn=local t={10,20,30} return t[1]+t[2]+t[3]
-
&tr.tc031 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_TBLFALL)),
60)=
{
@log smoke=TC031: lua VM fallback for tables. Succeeded.
},
{
@log smoke=TC031: lua VM fallback for tables. Failed (%q0).
}
-
#
# Test 32: Large loop — sum 1..10000 = 50005000.
# Verifies JIT handles larger iteration counts.
#
&LUA_BIGLOOP test_lua_fn=local s=0 for i=1,10000 do s=s+i end return s
-
&tr.tc032 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_BIGLOOP)),
50005000)=
{
@log smoke=TC032: lua large for-loop. Succeeded.
},
{
@log smoke=TC032: lua large for-loop. Failed (%q0).
}
-
#
# Test 33: Float division — Lua `/` always produces float.
#
&LUA_FDIV test_lua_fn=return 10 / 3
-
&tr.tc033 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_FDIV)),
3.333333*)=
{
@log smoke=TC033: lua float division. Succeeded.
},
{
@log smoke=TC033: lua float division. Failed (%q0).
}
-
#
# Test 34: Float constant arithmetic.
#
&LUA_FCONST test_lua_fn=return 1.5 + 2.5
-
&tr.tc034 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_FCONST)),
4*)=
{
@log smoke=TC034: lua float constant add. Succeeded.
},
{
@log smoke=TC034: lua float constant add. Failed (%q0).
}
-
#
# Test 35: Mixed int/float arithmetic — promotion.
#
&LUA_MIXED test_lua_fn=return 3 + 1.5
-
&tr.tc035 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_MIXED)),
4.5)=
{
@log smoke=TC035: lua mixed int+float. Succeeded.
},
{
@log smoke=TC035: lua mixed int+float. Failed (%q0).
}
-
#
# Test 36: Float negation.
#
&LUA_FNEG test_lua_fn=return -(3.14)
-
&tr.tc036 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_FNEG)),
-3.14)=
{
@log smoke=TC036: lua float negation. Succeeded.
},
{
@log smoke=TC036: lua float negation. Failed (%q0).
}
-
#
# Test 37: String concatenation via .. operator.
#
&LUA_CONCAT test_lua_fn=return "hello" .. " " .. "world"
-
&tr.tc037 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_CONCAT)),
hello world)=
{
@log smoke=TC037: lua string concat op. Succeeded.
},
{
@log smoke=TC037: lua string concat op. Failed (%q0).
}
-
#
# Test 38: Concat with integer coercion.
#
&LUA_CONCATI test_lua_fn=return "count: " .. 42
-
&tr.tc038 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_CONCATI)),
count: 42)=
{
@log smoke=TC038: lua concat int coercion. Succeeded.
},
{
@log smoke=TC038: lua concat int coercion. Failed (%q0).
}
-
#
# Test 39: String length via # operator.
#
&LUA_SLEN test_lua_fn=return #"hello"
-
&tr.tc039 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_SLEN)),
5)=
{
@log smoke=TC039: lua string length. Succeeded.
},
{
@log smoke=TC039: lua string length. Failed (%q0).
}
-
#
# Test 40: Logical NOT operator.
#
&LUA_NOT test_lua_fn=if not false then return "yes" else return "no" end
-
&tr.tc040 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_NOT)),
yes)=
{
@log smoke=TC040: lua logical not. Succeeded.
},
{
@log smoke=TC040: lua logical not. Failed (%q0).
}
-
#
# Test 41: Table construction and integer access.
# {10,20,30} → NEWTABLE + SETLIST, t[1] → GETTABI.
#
&LUA_TBLSUM test_lua_fn=local t={10,20,30} return t[1]+t[2]+t[3]
-
&tr.tc041 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_TBLSUM)),
60)=
{
@log smoke=TC041: lua table construct+access. Succeeded.
},
{
@log smoke=TC041: lua table construct+access. Failed (%q0).
}
-
#
# Test 42: Table with string values and concatenation.
#
&LUA_TBLSTR test_lua_fn=local t={"hello","world"} return t[1] .. " " .. t[2]
-
&tr.tc042 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_TBLSTR)),
hello world)=
{
@log smoke=TC042: lua table string concat. Succeeded.
},
{
@log smoke=TC042: lua table string concat. Failed (%q0).
}
-
#
# Test 43: math.floor via generic global+field+call.
#
&LUA_MATHFLOOR test_lua_fn=return math.floor(3.7)
-
&tr.tc043 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_MATHFLOOR)),
3)=
{
@log smoke=TC043: lua math.floor. Succeeded.
},
{
@log smoke=TC043: lua math.floor. Failed (%q0).
}
-
#
# Test 44: string.upper via generic call.
#
&LUA_STRUPPER test_lua_fn=return string.upper("hello")
-
&tr.tc044 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_STRUPPER)),
HELLO)=
{
@log smoke=TC044: lua string.upper. Succeeded.
},
{
@log smoke=TC044: lua string.upper. Failed (%q0).
}
-
#
# Test 45: tostring() via generic global call.
#
&LUA_TOSTR test_lua_fn=return tostring(42)
-
&tr.tc045 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_TOSTR)),
42)=
{
@log smoke=TC045: lua tostring. Succeeded.
},
{
@log smoke=TC045: lua tostring. Failed (%q0).
}
-
#
# Test 46: math.sqrt via generic call with float.
#
&LUA_MATHSQRT test_lua_fn=return math.sqrt(144)
-
# sqrt claims TY_FLOAT (#1751 Phase 2 revision): no CALL_FLT marshalling
# exists, so the call is ineligible at lowering and the interpreter
# answers 12.0 on both routes.
&tr.tc046 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_MATHSQRT)),
12*)=
{
@log smoke=TC046: lua math.sqrt. Succeeded.
},
{
@log smoke=TC046: lua math.sqrt. Failed (%q0).
}
-
#
# Test 47: string-arg subtraction (runtime type guard: ATOI on mux.args).
#
&LUA_SUB_ARGS test_lua_fn=return mux.args[1] - mux.args[2]
-
&tr.tc047 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_SUB_ARGS,10,3)),
7)=
{
@log smoke=TC047: lua string-arg subtraction. Succeeded.
},
{
@log smoke=TC047: lua string-arg subtraction. Failed (%q0).
}
-
#
# Test 48: string-arg + immediate (ADDI path).
#
&LUA_ADD_IMM test_lua_fn=return mux.args[1] + 10
-
&tr.tc048 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_ADD_IMM,5)),
15)=
{
@log smoke=TC048: lua string-arg add immediate. Succeeded.
},
{
@log smoke=TC048: lua string-arg add immediate. Failed (%q0).
}
-
#
# Test 49: string-arg negation (UNM path).
#
&LUA_NEG_ARG test_lua_fn=return -mux.args[1]
-
&tr.tc049 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_NEG_ARG,42)),
-42)=
{
@log smoke=TC049: lua string-arg negation. Succeeded.
},
{
@log smoke=TC049: lua string-arg negation. Failed (%q0).
}
-
#
# Test 50: string-arg comparison (CMP_RR path).
#
&LUA_CMP_ARGS test_lua_fn= \
if mux.args[1] + 0 > mux.args[2] + 0 then \
return "yes" \
else \
return "no" \
end
-
&tr.tc050 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_CMP_ARGS,20,5)),
yes)=
{
@log smoke=TC050: lua string-arg comparison. Succeeded.
},
{
@log smoke=TC050: lua string-arg comparison. Failed (%q0).
}
-
#
# Test 51: string-arg integer division (IDIV path).
#
&LUA_IDIV_ARGS test_lua_fn=return mux.args[1] // mux.args[2]
-
&tr.tc051 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_IDIV_ARGS,17,5)),
3)=
{
@log smoke=TC051: lua string-arg integer division. Succeeded.
},
{
@log smoke=TC051: lua string-arg integer division. Failed (%q0).
}
-
#
# Test 52: string-arg modulo (MOD path).
#
&LUA_MOD_ARGS test_lua_fn=return mux.args[1] % mux.args[2]
-
&tr.tc052 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_MOD_ARGS,17,5)),
2)=
{
@log smoke=TC052: lua string-arg modulo. Succeeded.
},
{
@log smoke=TC052: lua string-arg modulo. Failed (%q0).
}
-
#
# Test 53: string equality (native strcmp path).
#
&LUA_STREQ test_lua_fn= \
if mux.args[1] == "hello" then \
return "yes" \
else \
return "no" \
end
-
&tr.tc053 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_STREQ,hello)),
yes)=
{
@log smoke=TC053: lua string equality match. Succeeded.
},
{
@log smoke=TC053: lua string equality match. Failed (%q0).
}
-
#
# Test 54: string inequality (strcmp returns nonzero).
#
&tr.tc054 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_STREQ,world)),
no)=
{
@log smoke=TC054: lua string inequality. Succeeded.
},
{
@log smoke=TC054: lua string inequality. Failed (%q0).
}
-
#
# Test 55: string equality with numeric-looking string.
#
&LUA_STREQ_NUM test_lua_fn= \
if mux.args[1] == "5" then \
return "str" \
else \
return "other" \
end
-
&tr.tc055 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_STREQ_NUM,5)),
str)=
{
@log smoke=TC055: lua string equality numeric. Succeeded.
},
{
@log smoke=TC055: lua string equality numeric. Failed (%q0).
}
-
#
# Test 56: integer table access via HIR_LUA_GETI (no string marshal).
#
&LUA_TBLINT test_lua_fn= \
local t = {10, 20, 30} \
return t[1] + t[2] + t[3]
-
&tr.tc056 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_TBLINT)),
60)=
{
@log smoke=TC056: lua integer table sum. Succeeded.
},
{
@log smoke=TC056: lua integer table sum. Failed (%q0).
}
-
#
# Test 57: for-loop over integer table.
#
&LUA_TBLLOOP test_lua_fn= \
local t = {10, 20, 30, 40, 50} \
local s = 0 \
for i = 1, 5 do \
s = s + t[i] \
end \
return s
-
&tr.tc057 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_TBLLOOP)),
150)=
{
@log smoke=TC057: lua for-loop table sum. Succeeded.
},
{
@log smoke=TC057: lua for-loop table sum. Failed (%q0).
}
-
#
# Test 58: for-loop with index arithmetic on table.
#
&LUA_TBLIDX test_lua_fn= \
local t = {1, 2, 3, 4, 5} \
local s = 0 \
for i = 1, 5 do \
s = s + t[i] * i \
end \
return s
-
&tr.tc058 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_TBLIDX)),
55)=
{
@log smoke=TC058: lua for-loop table index arithmetic. Succeeded.
},
{
@log smoke=TC058: lua for-loop table index arithmetic. Failed (%q0).
}
-
#
# Test 59: runtime HIR_NEG of INT64_MIN via args (#1258).
# Forces the non-constant UNM path (no ICONST fold). Two's-complement
# wrap: -INT64_MIN stays INT64_MIN, matching RV64 SUB dest,x0,rs.
#
&tr.tc059 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_NEG_ARG,-9223372036854775808)),
-9223372036854775808)=
{
@log smoke=TC059: lua runtime NEG of INT64_MIN wraps. Succeeded.
},
{
@log smoke=TC059: lua runtime NEG of INT64_MIN wraps. Failed (%q0).
}
-
#
# Test 60: const-fold HIR_NEG of math.mininteger (#1258).
# Fold must not evaluate -INT64_MIN as C++ UB; keep INT64_MIN.
#
&LUA_NEG_MININT test_lua_fn=return -math.mininteger
-
&tr.tc060 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_NEG_MININT)),
-9223372036854775808)=
{
@log smoke=TC060: lua fold NEG of mininteger. Succeeded.
},
{
@log smoke=TC060: lua fold NEG of mininteger. Failed (%q0).
}
-
#
# ---- Softcode ↔ Lua seam (#1751 follow-up corpus) ----
# Softcode drives lua(); Lua reaches back via mux.* into softcode/attrs.
# These pin the seam, not just pure Lua arithmetic.
#
# Test 61: softcode → lua() → mux.eval softcode → answer back to softcode.
#
&LUA_SEAM_EVAL test_lua_fn=return mux.eval("mul(6,7)")
-
&tr.tc061 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_SEAM_EVAL)),
42)=
{
@log smoke=TC061: seam softcode→lua→mux.eval. Succeeded.
},
{
@log smoke=TC061: seam softcode→lua→mux.eval. Failed (%q0).
}
-
#
# Test 62: softcode writes an attr; lua mux.get reads it (object seam).
#
&SEAM_PAYLOAD test_lua_fn=payload-from-softcode
-
# Softcode may pass dbref as "2" or "#2"; bridge_get wants an integer.
&LUA_SEAM_GET test_lua_fn= \
local s = tostring(mux.args[1]) \
if s:sub(1,1) == "#" then s = s:sub(2) end \
return mux.get(tonumber(s), "SEAM_PAYLOAD")
-
&tr.tc062 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_SEAM_GET,num(me))),
payload-from-softcode)=
{
@log smoke=TC062: seam softcode attr→lua mux.get. Succeeded.
},
{
@log smoke=TC062: seam softcode attr→lua mux.get. Failed (%q0).
}
-
#
# Test 63: lua mux.set writes; softcode get() reads it back.
# set is effectful; both routes share the bridge (compiled path allowed
# after #1751 Phase 4 removed re-run, so effects are exactly-once).
#
&LUA_SEAM_SET test_lua_fn= \
local s = tostring(mux.args[1]) \
if s:sub(1,1) == "#" then s = s:sub(2) end \
mux.set(tonumber(s), "SEAM_FROM_LUA", mux.args[2]) \
return "ok"
-
&tr.tc063 test_lua_fn=
@switch \
and( \
strmatch(setr(0,lua(me/LUA_SEAM_SET,num(me),hello-from-lua)),ok), \
strmatch(setr(1,get(me/SEAM_FROM_LUA)),hello-from-lua))=1,
{
@log smoke=TC063: seam lua mux.set→softcode get. Succeeded.
},
{
@log smoke=TC063: seam lua mux.set→softcode get. Failed (lua=%q0 get=%q1).
}
-
#
# Test 64: softcode nests [lua(...)] inside softcode (eval seam).
#
&LUA_SEAM_NEST test_lua_fn=return mux.args[1] + mux.args[2]
-
&tr.tc064 test_lua_fn=
@if strmatch(
setr(0,add(lua(me/LUA_SEAM_NEST,10,5),1)),
16)=
{
@log smoke=TC064: seam softcode nest [lua]+add. Succeeded.
},
{
@log smoke=TC064: seam softcode nest [lua]+add. Failed (%q0).
}
-
#
# Test 65: string.find multi-value first result through CALL_STR marshal.
#
&LUA_SEAM_FIND test_lua_fn=return string.find("ab","b")
-
&tr.tc065 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_SEAM_FIND)),
2)=
{
@log smoke=TC065: seam string.find first result. Succeeded.
},
{
@log smoke=TC065: seam string.find first result. Failed (%q0).
}
-
#
# Test 66: softcode truthiness at the boundary (softcode ≠ Lua).
# Lua "0" is truthy in Lua; softcode t("0") is false. Document intentional.
#
&LUA_SEAM_ZEROSTR test_lua_fn=return "0"
&LUA_SEAM_HELLO test_lua_fn=return "hello"
-
&tr.tc066 test_lua_fn=
@switch \
and( \
not(t(setr(0,lua(me/LUA_SEAM_ZEROSTR)))), \
t(setr(1,lua(me/LUA_SEAM_HELLO))))=1,
{
@log smoke=TC066: seam softcode t() on lua "0"/hello. Succeeded.
},
{
@log smoke=TC066: seam softcode t() on lua "0"/hello. Failed (zero=%q0 hello=%q1).
}
-
#
# Test 67: softcode arithmetic on a lua numeric return (marshal as decimal).
#
&LUA_SEAM_FORTYONE test_lua_fn=return 41
-
&tr.tc067 test_lua_fn=
@if strmatch(
setr(0,add(lua(me/LUA_SEAM_FORTYONE),1)),
42)=
{
@log smoke=TC067: seam softcode add(lua number,1). Succeeded.
},
{
@log smoke=TC067: seam softcode add(lua number,1). Failed (%q0).
}
-
#
# Test 68: lua mux.owner → softcode; pin integer-as-text across the seam.
# Use object #1 (same fixed target as TC013) so both sides are stable
# under the smoke suite enactor — nested num(owner(me)) as a strmatch
# pattern is flaky here (empty soft side under suite dispatch).
#
&LUA_SEAM_OWNER test_lua_fn=return mux.owner(1)
-
&tr.tc068 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_SEAM_OWNER)),
1)=
{
@log smoke=TC068: seam lua mux.owner→softcode. Succeeded.
},
{
@log smoke=TC068: seam lua mux.owner→softcode. Failed (%q0).
}
-
#
# Test 69: softcode ifelse driven by a lua numeric compare (nest + branch).
#
&LUA_SEAM_SCORE test_lua_fn=return tonumber(mux.args[1])
-
&tr.tc069 test_lua_fn=
@switch \
and( \
strmatch(setr(0,ifelse(gt(lua(me/LUA_SEAM_SCORE,20),10),big,small)),big), \
strmatch(setr(1,ifelse(gt(lua(me/LUA_SEAM_SCORE,3),10),big,small)),small))=1,
{
@log smoke=TC069: seam ifelse(gt(lua)). Succeeded.
},
{
@log smoke=TC069: seam ifelse(gt(lua)). Failed (big=%q0 small=%q1).
}
-
#
# Test 70: Lua error surfaces through softcode as #-1 LUA ERROR:…
# Use `return error(...)` so the call is value-producing (CALL_STR); bare
# `error(...)` is CALL_VOID and must totalize the same way (see engine).
#
&LUA_SEAM_ERR test_lua_fn=return error("seam-boom")
-
&tr.tc070 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_SEAM_ERR)),
#-1 LUA ERROR:*seam-boom*)=
{
@log smoke=TC070: seam lua error text. Succeeded.
},
{
@log smoke=TC070: seam lua error text. Failed (%q0).
}
-
#
# ---- Seam corpus expansion (residual after #1751 / TC061065) ----
# Complementary to in-flight TC066070 (softcode t()/add/owner/ifelse/error).
# These pin nest integrity, softcode consumers of marshaled text, and
# more mux.* bridge returns through the softcode boundary.
#
# Test 71: nested lua via mux.eval must not stomp outer mux.args.
# Residual "anytime item 3" in plan-lua-post-entry-contract.md: nested
# mux.args / executor stomp. Outer args must still be visible after
# the inner lua() returns.
#
&LUA_SEAM_INNER test_lua_fn=return mux.args[1]
-
&LUA_SEAM_ARGS_NEST test_lua_fn= \
local id = tostring(mux.args[1]) \
if id:sub(1,1) ~= "#" then id = "#" .. id end \
local outer = tostring(mux.args[2]) \
local mid = mux.eval("lua(" .. id .. "/LUA_SEAM_INNER,inner-token)") \
return outer .. ":" .. tostring(mid) .. ":" .. tostring(mux.args[2])
-
&tr.tc071 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_SEAM_ARGS_NEST,num(me),outer-token)),
outer-token:inner-token:outer-token)=
{
@log smoke=TC071: seam nested mux.args survive mux.eval. Succeeded.
},
{
@log smoke=TC071: seam nested mux.args survive mux.eval. Failed (%q0).
}
-
#
# Test 72: softcode string consumers on a lua string return (strlen/mid).
#
&LUA_SEAM_STR test_lua_fn=return "abcdef"
-
&tr.tc072 test_lua_fn=
@switch \
and( \
strmatch(setr(0,strlen(lua(me/LUA_SEAM_STR))),6), \
strmatch(setr(1,mid(lua(me/LUA_SEAM_STR),2,3)),cde))=1,
{
@log smoke=TC072: seam softcode strlen/mid on lua string. Succeeded.
},
{
@log smoke=TC072: seam softcode strlen/mid on lua string. Failed (len=%q0 mid=%q1).
}
-
#
# Test 73: softcode list extract on a multi-word lua return.
#
&LUA_SEAM_WORDS test_lua_fn=return "alpha beta gamma"
-
&tr.tc073 test_lua_fn=
@switch \
and( \
strmatch(setr(0,words(lua(me/LUA_SEAM_WORDS))),3), \
strmatch(setr(1,extract(lua(me/LUA_SEAM_WORDS),2,1)),beta))=1,
{
@log smoke=TC073: seam softcode words/extract on lua list. Succeeded.
},
{
@log smoke=TC073: seam softcode words/extract on lua list. Failed (n=%q0 w=%q1).
}
-
#
# Test 74: lua false marshals as "0"; softcode and() treats it as false.
#
&LUA_SEAM_FALSE test_lua_fn=return false
-
&LUA_SEAM_TRUE test_lua_fn=return true
-
&tr.tc074 test_lua_fn=
@switch \
and( \
strmatch(setr(0,lua(me/LUA_SEAM_FALSE)),0), \
strmatch(setr(1,lua(me/LUA_SEAM_TRUE)),1), \
strmatch(setr(2,and(lua(me/LUA_SEAM_FALSE),1)),0), \
strmatch(setr(3,and(lua(me/LUA_SEAM_TRUE),1)),1))=1,
{
@log smoke=TC074: seam lua bool → softcode and(). Succeeded.
},
{
@log smoke=TC074: seam lua bool → softcode and(). Failed (f=%q0 t=%q1 af=%q2 at=%q3).
}
-
#
# Test 75: mux.location / pennies integer returns through softcode (with
# owner-style compare). Location of a room's content is the room.
#
&LUA_SEAM_LOC test_lua_fn= \
local s = tostring(mux.args[1]) \
if s:sub(1,1) == "#" then s = s:sub(2) end \
return mux.location(tonumber(s))
-
&tr.tc075 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_SEAM_LOC,num(me))),
mid(loc(me),1,99))=
{
@log smoke=TC075: seam lua mux.location→softcode loc(). Succeeded.
},
{
@log smoke=TC075: seam lua mux.location→softcode loc(). Failed (lua=%q0 soft=mid(loc)=[mid(loc(me),1,99)]).
}
-
#
# Test 76: softcode → lua → mux.eval → nested [lua(...)] (double hop).
# Outer softcode never sees the inner chunk; the hop is entirely in Lua.
#
&LUA_SEAM_HOP_INNER test_lua_fn=return mux.args[1] * 3
-
&LUA_SEAM_HOP test_lua_fn= \
local id = tostring(mux.args[1]) \
if id:sub(1,1) ~= "#" then id = "#" .. id end \
return mux.eval("lua(" .. id .. "/LUA_SEAM_HOP_INNER,7)")
-
&tr.tc076 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_SEAM_HOP,num(me))),
21)=
{
@log smoke=TC076: seam lua→mux.eval→lua double hop. Succeeded.
},
{
@log smoke=TC076: seam lua→mux.eval→lua double hop. Failed (%q0).
}
-
#
# Test 77: softcode cat() of two lua returns (marshal + softcode concat).
#
&LUA_SEAM_A test_lua_fn=return "left"
-
&LUA_SEAM_B test_lua_fn=return "right"
-
&tr.tc077 test_lua_fn=
@if strmatch(
setr(0,cat(lua(me/LUA_SEAM_A),lua(me/LUA_SEAM_B))),
left right)=
{
@log smoke=TC077: seam softcode cat of two lua returns. Succeeded.
},
{
@log smoke=TC077: seam softcode cat of two lua returns. Failed (%q0).
}
-
#
# Test 78: empty string return is not an error; softcode strlen is 0.
# Distinct from nil (TC004) which also marshals empty — pin strlen.
#
&LUA_SEAM_EMPTY test_lua_fn=return ""
-
&tr.tc078 test_lua_fn=
@switch \
and( \
strmatch(setr(0,lua(me/LUA_SEAM_EMPTY)),), \
strmatch(setr(1,strlen(lua(me/LUA_SEAM_EMPTY))),0))=1,
{
@log smoke=TC078: seam empty string marshal + strlen. Succeeded.
},
{
@log smoke=TC078: seam empty string marshal + strlen. Failed (s=%q0 len=%q1).
}
-
#
# ---- Seam corpus (TC079+) — production nest, softcode host state, ----
# ---- multi-entry softcode→lua, float/nil/bool edges. Residual after
# ---- #1751 / softcode post-entry contract (#1791). Concern ends at
# ---- the softcode↔Lua RV64 seam (ECALL/DMA), not deep DBT.
#
# Test 79: softcode u() of an attribute that embeds [lua(...)] —
# classic softcode-JIT → fun_lua nest under default brackets.
#
&SOFT_U_SEAM test_lua_fn=[add(lua(me/LUA_ADD,6,1),3)]
-
&tr.tc079 test_lua_fn=
@if strmatch(
setr(0,u(me/SOFT_U_SEAM)),
10)=
{
@log smoke=TC079: seam softcode u() embeds lua(). Succeeded.
},
{
@log smoke=TC079: seam softcode u() embeds lua(). Failed (%q0).
}
-
#
# Test 80: softcode setq survives a nested lua() host ECALL.
# Softcode #1791 host_ecalls path: SETQ then lua must not stomp %qregs.
# setq() returns empty; pin via %qN after the lua nest (not setq's return).
#
&tr.tc080 test_lua_fn=
@switch \
and( \
strmatch(setr(0,[setq(8,q-keep)][lua(me/LUA_ADD,4,5)]),9), \
strmatch(%q8,q-keep))=1,
{
@log smoke=TC080: seam softcode setq survives lua(). Succeeded.
},
{
@log smoke=TC080: seam softcode setq survives lua(). Failed (lua=%q0 q8=%q8).
}
-
#
# Test 81: object attr written by softcode still readable after lua().
# Host softcode work + nested lua + softcode read (no double-write).
#
&tr.tc081 test_lua_fn=
@switch \
and( \
strmatch(setr(0,attrib_set(me/SEAM_PRE,before-lua)),), \
strmatch(setr(1,lua(me/LUA_ADD,2,2)),4), \
strmatch(setr(2,get(me/SEAM_PRE)),before-lua))=1,
{
@log smoke=TC081: seam softcode attr survives lua(). Succeeded.
},
{
@log smoke=TC081: seam softcode attr survives lua(). Failed (set=%q0 lua=%q1 get=%q2).
}
-
#
# Test 82: Lua nil marshals empty; softcode t() is false (≠ Lua truthiness).
#
&LUA_SEAM_NIL test_lua_fn=return nil
-
&tr.tc082 test_lua_fn=
@switch \
and( \
strmatch(setr(0,lua(me/LUA_SEAM_NIL)),), \
not(t(%q0)), \
not(t(lua(me/LUA_SEAM_NIL))))=1,
{
@log smoke=TC082: seam nil → softcode empty + t() false. Succeeded.
},
{
@log smoke=TC082: seam nil → softcode empty + t() false. Failed (s=%q0).
}
-
#
# Test 83: float return through softcode mul (decimal marshal).
# Pin the marshaled text first; then softcode arithmetic on that text.
# Softcode has mul/fdiv, not fmul — mul handles decimals (see nested_float_fn).
#
&LUA_SEAM_HALF test_lua_fn=return 2.5
-
&tr.tc083 test_lua_fn=
@switch \
and( \
strmatch(setr(0,lua(me/LUA_SEAM_HALF)),2.5*), \
strmatch(setr(1,mul(lua(me/LUA_SEAM_HALF),2)),5*))=1,
{
@log smoke=TC083: seam float → softcode mul. Succeeded.
},
{
@log smoke=TC083: seam float → softcode mul. Failed (lua=%q0 mul=%q1).
}
-
#
# Test 84: three softcode args into lua (CARGS multi-slot nest).
#
&LUA_SEAM_3 test_lua_fn=return mux.args[1] + mux.args[2] + mux.args[3]
-
&tr.tc084 test_lua_fn=
@if strmatch(
setr(0,lua(me/LUA_SEAM_3,1,2,3)),
6)=
{
@log smoke=TC084: seam three softcode args → lua. Succeeded.
},
{
@log smoke=TC084: seam three softcode args → lua. Failed (%q0).
}
-
#
# Test 85: two separate lua() entries in one softcode expression.
# Softcode JIT issues two fun_lua ECALLs; each may compile+run.
#
&tr.tc085 test_lua_fn=
@if strmatch(
setr(0,add(lua(me/LUA_ADD,1,2),lua(me/LUA_ADD,3,4))),
10)=
{
@log smoke=TC085: seam softcode add of two lua(). Succeeded.
},
{
@log smoke=TC085: seam softcode add of two lua(). Failed (%q0).
}
-
#
# Test 86: softcode first/rest on a multi-word lua return.
#
&LUA_SEAM_PAIR test_lua_fn=return "left right"
-
&tr.tc086 test_lua_fn=
@switch \
and( \
strmatch(setr(0,first(lua(me/LUA_SEAM_PAIR))),left), \
strmatch(setr(1,rest(lua(me/LUA_SEAM_PAIR))),right))=1,
{
@log smoke=TC086: seam softcode first/rest on lua. Succeeded.
},
{
@log smoke=TC086: seam softcode first/rest on lua. Failed (f=%q0 r=%q1).
}
-
#
# Test 87: softcode after a lua error still sees prior setq (no host stomp).
# setq() returns empty; embed as a side-effect prefix like TC080.
#
&tr.tc087 test_lua_fn=
@switch \
and( \
strmatch(setr(0,[setq(7,still-here)][lua(me/LUA_SEAM_ERR)]),#-1 LUA ERROR:*seam-boom*), \
strmatch(%q7,still-here))=1,
{
@log smoke=TC087: seam setq survives lua error. Succeeded.
},
{
@log smoke=TC087: seam setq survives lua error. Failed (err=%q0 q7=%q7).
}
-
#
# Test 88: softcode → lua → mux.eval(set via softcode) → softcode get.
# Keep the eval argument constant: runtime string call arguments and SELF
# (`s:sub`) are deliberately ineligible, which would make this result-only
# smoke pass through the interpreter while claiming compiled coverage.
# NESTED and STATE e4 below pin execution and exactly-once effect separately.
#
&LUA_SEAM_EVAL_WRITE test_lua_fn= \
local x = mux.eval("strcat(attrib_set(me/SEAM_EVAL_WROTE,via-mux-eval),ok)") \
return x
-
&tr.tc088 test_lua_fn=
@switch \
and( \
strmatch(setr(0,lua(me/LUA_SEAM_EVAL_WRITE)),ok), \
strmatch(setr(1,get(me/SEAM_EVAL_WROTE)),via-mux-eval))=1,
{
@log smoke=TC088: seam lua→mux.eval→attrib_set→softcode get. Succeeded.
},
{
@log smoke=TC088: seam lua→mux.eval→attrib_set→softcode get. Failed (lua=%q0 get=%q1).
}
-
#
# Test 89: softcode match() pattern consumer of a lua string.
#
&LUA_SEAM_TOKEN test_lua_fn=return "abc-def-ghi"
-
&tr.tc089 test_lua_fn=
@if strmatch(
setr(0,match(lua(me/LUA_SEAM_TOKEN),*-def-*)),
1)=
{
@log smoke=TC089: seam softcode match on lua string. Succeeded.
},
{
@log smoke=TC089: seam softcode match on lua string. Failed (%q0).
}
-
#
# Test 90: softcode switch/case on a lua integer (branch after nest).
#
&LUA_SEAM_CODE test_lua_fn=return tonumber(mux.args[1])
-
&tr.tc090 test_lua_fn=
@switch \
and( \
strmatch(setr(0,switch(lua(me/LUA_SEAM_CODE,2),1,one,2,two,other)),two), \
strmatch(setr(1,switch(lua(me/LUA_SEAM_CODE,9),1,one,2,two,other)),other))=1,
{
@log smoke=TC090: seam softcode switch on lua int. Succeeded.;
@trig me/tr.done
},
{
@log smoke=TC090: seam softcode switch on lua int. Failed (t=%q0 o=%q1).;
@trig me/tr.done
}
-
&tr.done test_lua_fn=
@log smoke=End lua() test cases.;
@notify smoke
-
drop test_lua_fn
-
#
# End of Test Cases
#