mirror of
https://github.com/brazilofmux/tinymux
synced 2026-08-13 00:23:11 -04:00
1589 lines
37 KiB
Text
1589 lines
37 KiB
Text
#
|
||
# 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 / TC061–065) ----
|
||
# Complementary to in-flight TC066–070 (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
|
||
#
|