diff --git a/tests.lua b/tests.lua index 963d202..566ee24 100644 --- a/tests.lua +++ b/tests.lua @@ -13,6 +13,7 @@ local Prometheus = require("src.prometheus") local noColors = false; -- Wether Colors in the Console output should be enabled local isWindows = true; -- Wether the Test are Performed on a Windows or Linux System local ciMode = false; -- Wether the Test error are ignored or not +local iterationCount = 20; -- How often each test should be executed for _, currArg in pairs(arg) do if currArg == "--Linux" then @@ -21,6 +22,10 @@ for _, currArg in pairs(arg) do if currArg == "--CI" then ciMode = true end + local iterationValue = currArg:match("^%-%-iterations=(%d+)$") + if iterationValue then + iterationCount = math.max(tonumber(iterationValue), 1) + end end -- Enable/Disable Console Colors - this may be needed because cmd.exe and powershell.exe do not support ANSI Color Escape Sequences. The Windows Terminal Application is needed @@ -38,7 +43,15 @@ local pipeline = Prometheus.Pipeline:new({ -- "Number" for names like this : _1, _2, _3, ... - Not recomended pipeline:setNameGenerator("MangledShuffled"); -print("Performing Prometheus Tests ...") +local function describePlatform() + return isWindows and "Windows" or "Linux" +end + +print(string.format( + "Performing Prometheus Tests (iterations=%d per file/preset, platform=%s)...", + iterationCount, + describePlatform() +)) local function scandir(directory) local i, t, popen = 0, {}, io.popen local pfile = popen(isWindows and 'dir "'..directory..'" /b' or 'ls -a "'..directory..'"') @@ -112,25 +125,27 @@ for i, filename in ipairs(scandir(testdir)) do table.remove(preset.Steps, i); end end - pipeline = Prometheus.Pipeline:fromConfig(preset); - local obfuscated = pipeline:apply(code); - - local funca = loadstring(code); - local funcb = loadstring(obfuscated); - - if funcb == nil then - print(Prometheus.colors("[FAILED] ", "red") .. "(" .. filename .. "): " .. name .. ", Invalid Lua!"); - print("[SOURCE]", obfuscated); - fc = fc + 1; - else - local validated, outa, outb = validate(funca, funcb); - - if not validated then - print(Prometheus.colors("[FAILED] ", "red") .. "(" .. filename .. "): " .. name); - print("[OUTA] ", outa); - print("[OUTB] ", outb); + for iteration = 1, iterationCount do + pipeline = Prometheus.Pipeline:fromConfig(preset); + local obfuscated = pipeline:apply(code); + + local funca = loadstring(code); + local funcb = loadstring(obfuscated); + + if funcb == nil then + print(Prometheus.colors("[FAILED] ", "red") .. "(" .. filename .. "): " .. name .. ", Invalid Lua!"); print("[SOURCE]", obfuscated); fc = fc + 1; + else + local validated, outa, outb = validate(funca, funcb); + + if not validated then + print(Prometheus.colors("[FAILED] ", "red") .. "(" .. filename .. "): " .. name); + print("[OUTA] ", outa); + print("[OUTB] ", outb); + print("[SOURCE]", obfuscated); + fc = fc + 1; + end end end end @@ -146,4 +161,4 @@ else error("Test Failed!") end return -1; -end \ No newline at end of file +end diff --git a/tests/coroutines.lua b/tests/coroutines.lua new file mode 100644 index 0000000..a1f5961 --- /dev/null +++ b/tests/coroutines.lua @@ -0,0 +1,20 @@ +-- Deterministic coroutine driven sequence generator +local function squares(limit) + return coroutine.create(function() + for i = 1, limit do + coroutine.yield(i * i) + end + end) +end + +local co = squares(6) +while true do + local ok, value = coroutine.resume(co) + if not ok then + error(value) + end + if value == nil then + break + end + print(value) +end diff --git a/tests/iterator.lua b/tests/iterator.lua new file mode 100644 index 0000000..7bfe2b9 --- /dev/null +++ b/tests/iterator.lua @@ -0,0 +1,15 @@ +-- Custom iterator that creates a predictable countdown +local function countdown(startValue, step) + local value = startValue + step + return function() + value = value - step + if value <= 0 then + return nil + end + return value + end +end + +for num in countdown(12, 3) do + print(num) +end diff --git a/tests/matrix.lua b/tests/matrix.lua new file mode 100644 index 0000000..eb1bcb5 --- /dev/null +++ b/tests/matrix.lua @@ -0,0 +1,23 @@ +-- Deterministic 2x2 matrix multiplication example +local function multiply(a, b) + local result = { + { a[1][1] * b[1][1] + a[1][2] * b[2][1], a[1][1] * b[1][2] + a[1][2] * b[2][2] }, + { a[2][1] * b[1][1] + a[2][2] * b[2][1], a[2][1] * b[1][2] + a[2][2] * b[2][2] } + } + return result +end + +local A = { + {1, 2}, + {3, 4} +} + +local B = { + {5, 6}, + {7, 8} +} + +local C = multiply(A, B) +for row = 1, 2 do + print(string.format("%d,%d", C[row][1], C[row][2])) +end diff --git a/tests/metatables.lua b/tests/metatables.lua new file mode 100644 index 0000000..419a7d4 --- /dev/null +++ b/tests/metatables.lua @@ -0,0 +1,27 @@ +-- Example showcasing metamethod driven vector arithmetic +local Vector = {} +Vector.__index = Vector + +function Vector:new(x, y) + return setmetatable({ x = x, y = y }, self) +end + +function Vector.__add(a, b) + return Vector:new(a.x + b.x, a.y + b.y) +end + +function Vector:describe() + return string.format("(%d,%d)", self.x, self.y) +end + +local path = { + Vector:new(2, 3), + Vector:new(-1, 4), + Vector:new(0, -2) +} + +local position = Vector:new(0, 0) +for idx, delta in ipairs(path) do + position = position + delta + print(string.format("step%d:%s", idx, position:describe())) +end diff --git a/tests/state-machine.lua b/tests/state-machine.lua new file mode 100644 index 0000000..c99e18b --- /dev/null +++ b/tests/state-machine.lua @@ -0,0 +1,23 @@ +-- Simple deterministic finite-state machine demonstration +local transitions = { + idle = { start = "running" }, + running = { pause = "paused", stop = "stopped" }, + paused = { resume = "running", stop = "stopped" } +} + +local steps = { + { event = "start", expect = "running" }, + { event = "pause", expect = "paused" }, + { event = "resume", expect = "running" }, + { event = "stop", expect = "stopped" } +} + +local state = "idle" +for idx, step in ipairs(steps) do + local rule = transitions[state] + state = rule and rule[step.event] + assert(state == step.expect, string.format("bad transition at %d", idx)) + print(string.format("%d:%s->%s", idx, step.event, state)) +end + +print("final:" .. state) diff --git a/tests/strings.lua b/tests/strings.lua new file mode 100644 index 0000000..1adf0da --- /dev/null +++ b/tests/strings.lua @@ -0,0 +1,12 @@ +-- Deterministic text statistics for repeated words +local passage = "lorem ipsum dolor sit amet ipsum lorem" +local counts = {} + +for word in passage:gmatch("%w+") do + counts[word] = (counts[word] or 0) + 1 +end + +local order = {"lorem", "ipsum", "dolor", "sit", "amet"} +for _, word in ipairs(order) do + print(string.format("%s:%d", word, counts[word] or 0)) +end diff --git a/tests/table-merge.lua b/tests/table-merge.lua new file mode 100644 index 0000000..c1fe033 --- /dev/null +++ b/tests/table-merge.lua @@ -0,0 +1,20 @@ +-- Demonstrate deterministic table merging and traversal +local breakfast = { eggs = 4, bacon = 3 } +local lunch = { bacon = 1, toast = 5 } + +local function mergeQuantities(a, b) + local totals = {} + for k, v in pairs(a) do + totals[k] = v + end + for k, v in pairs(b) do + totals[k] = (totals[k] or 0) + v + end + return totals +end + +local merged = mergeQuantities(breakfast, lunch) +local order = {"eggs", "bacon", "toast"} +for _, item in ipairs(order) do + print(string.format("%s:%d", item, merged[item] or 0)) +end diff --git a/tests/upvalues.lua b/tests/upvalues.lua new file mode 100644 index 0000000..81162af --- /dev/null +++ b/tests/upvalues.lua @@ -0,0 +1,58 @@ +-- Deterministic tests covering closure upvalues in nested functions and loops +local function emitList(label, list) + print(label .. ":" .. table.concat(list, ",")) +end + +local function makeSeries(tag) + local total = 0 + local function step(delta) + total = total + delta + return string.format("%s-%d", tag, total) + end + local function runSeries(values) + local out = {} + for _, delta in ipairs(values) do + out[#out + 1] = step(delta) + end + return out + end + return runSeries +end + +local alphaSeries = makeSeries("alpha") +emitList("series", alphaSeries({ 1, 2, 1, 3 })) + +-- Verify each for-loop iteration captures its own upvalue +local watchers = {} +for i = 1, 4 do + watchers[i] = function(mult) + return i * mult + end +end + +for idx, fn in ipairs(watchers) do + print(string.format("watch%d:%d", idx, fn(idx + 1))) +end + +-- Nested functions sharing a master accumulator through for-loops +local function buildAccumulators() + local master = 0 + local store = {} + for group = 1, 3 do + local localTotal = group + store[group] = function(iterations) + for step = 1, iterations do + localTotal = localTotal + group + step + master = master + group + end + return localTotal, master + end + end + return store +end + +local runners = buildAccumulators() +for idx, fn in ipairs(runners) do + local value, master = fn(idx) + print(string.format("acc%d:%d|%d", idx, value, master)) +end