102 lines
4.4 KiB
Luau
102 lines
4.4 KiB
Luau
-- Click fuzzer for the demo: records every visible item rect (by wrapping ImGui.ItemAdd) and clicks/drags/scrolls/types on random ones.
|
|
-- Usage: python3 tools/test/run.py --main tools/test/scripts/t_click_fuzz.luau --frames 3000 --quiet
|
|
-- Change SEED to explore other paths.
|
|
local SEED = tonumber(_G.FUZZ_SEED) or 1
|
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
|
local RunService = game:GetService("RunService")
|
|
local G = require(ReplicatedStorage:WaitForChild("ImGui"))
|
|
local ImGui, ImVec2 = G.ImGui, G.ImVec2
|
|
ImGui.CreateContext()
|
|
local io = ImGui.GetIO()
|
|
io.ConfigFlags = bit32.bor(io.ConfigFlags, G.ImGuiConfigFlags.NavEnableKeyboard, G.ImGuiConfigFlags.DockingEnable)
|
|
G.ImGui_ImplRoblox.Init()
|
|
math.randomseed(SEED)
|
|
|
|
local items, prev_items = {}, {}
|
|
local orig_ItemAdd = ImGui.ItemAdd
|
|
ImGui.ItemAdd = function(bb, id, nav_bb, extra)
|
|
local r = orig_ItemAdd(bb, id, nav_bb, extra)
|
|
if r and id ~= 0 then
|
|
local g = ImGui.GetCurrentContext()
|
|
local w = g.CurrentWindow
|
|
local c = w.ClipRect
|
|
local x1, y1 = math.max(bb.Min.x, c.Min.x), math.max(bb.Min.y, c.Min.y)
|
|
local x2, y2 = math.min(bb.Max.x, c.Max.x), math.min(bb.Max.y, c.Max.y)
|
|
if x2 - x1 >= 2 and y2 - y1 >= 2 then
|
|
items[#items + 1] = { x1, y1, x2, y2, w.Name }
|
|
end
|
|
end
|
|
return r
|
|
end
|
|
|
|
local log = {}
|
|
local function note(s) log[#log + 1] = s; if #log > 12 then table.remove(log, 1) end end
|
|
|
|
-- action queue: list of {x, y, down, key, char, wheel}
|
|
local queue = {}
|
|
local mx, my, down = 500, 500, false
|
|
local function plan()
|
|
local list = prev_items
|
|
if #list == 0 then queue = { { 500, 500, false } }; return end
|
|
local it = list[math.random(#list)]
|
|
local x = it[1] + math.random() * (it[3] - it[1])
|
|
local y = it[2] + math.random() * (it[4] - it[2])
|
|
local r = math.random()
|
|
if r < 0.65 then
|
|
note(string.format("click %.0f,%.0f in %s", x, y, it[5]))
|
|
queue = { { x, y, false }, { x, y, true }, { x, y, false }, { x, y, false } }
|
|
elseif r < 0.8 then
|
|
local dx, dy = math.random(-150, 150), math.random(-80, 80)
|
|
note(string.format("drag %.0f,%.0f by %d,%d in %s", x, y, dx, dy, it[5]))
|
|
queue = { { x, y, false }, { x, y, true } }
|
|
for i = 1, 6 do queue[#queue + 1] = { x + dx * i / 6, y + dy * i / 6, true } end
|
|
queue[#queue + 1] = { x + dx, y + dy, false }
|
|
elseif r < 0.9 then
|
|
note(string.format("wheel %.0f,%.0f in %s", x, y, it[5]))
|
|
queue = { { x, y, false, wheel = (math.random() < 0.5) and -3 or 3 } }
|
|
elseif r < 0.95 then
|
|
note(string.format("dblclick %.0f,%.0f in %s", x, y, it[5]))
|
|
queue = { { x, y, false }, { x, y, true }, { x, y, false }, { x, y, true }, { x, y, false }, { x, y, false } }
|
|
else
|
|
local keys = { G.ImGuiKey.Enter, G.ImGuiKey.Escape, G.ImGuiKey.Tab, G.ImGuiKey.UpArrow, G.ImGuiKey.DownArrow, G.ImGuiKey.Backspace }
|
|
local k = keys[math.random(#keys)]
|
|
note("key " .. tostring(k) .. " + text")
|
|
queue = { { mx, my, down, key = k }, { mx, my, down, char = "a1" } }
|
|
end
|
|
end
|
|
|
|
local frame = 0
|
|
RunService.Stepped:Connect(function()
|
|
frame += 1
|
|
local ok, err = xpcall(function()
|
|
G.ImGui_ImplRoblox.NewFrame()
|
|
if #queue == 0 then plan() end
|
|
local a = table.remove(queue, 1)
|
|
mx, my = a[1], a[2]
|
|
io:AddMousePosEvent(mx, my)
|
|
if a[3] ~= down then down = a[3]; io:AddMouseButtonEvent(0, down) end
|
|
if a.wheel then io:AddMouseWheelEvent(0, a.wheel) end
|
|
if a.key then io:AddKeyEvent(a.key, true); io:AddKeyEvent(a.key, false) end
|
|
if a.char then for i = 1, #a.char do io:AddInputCharacter(string.byte(a.char, i)) end end
|
|
|
|
prev_items = items
|
|
items = {}
|
|
ImGui.NewFrame()
|
|
ImGui.DockSpaceOverViewport(0, nil, G.ImGuiDockNodeFlags.PassthruCentralNode)
|
|
if frame % 400 == 1 then
|
|
ImGui.SetNextWindowCollapsed(false)
|
|
ImGui.SetNextWindowPos(ImVec2(650, 20))
|
|
ImGui.SetNextWindowSize(ImVec2(700, 1000))
|
|
end
|
|
ImGui.ShowDemoWindow()
|
|
ImGui.Render()
|
|
G.ImGui_ImplRoblox.RenderDrawData(ImGui.GetDrawData())
|
|
end, debug.traceback)
|
|
if not ok then
|
|
print("FUZZ FAIL at frame " .. frame .. " seed " .. SEED)
|
|
for _, l in ipairs(log) do print(" " .. l) end
|
|
error(err, 0)
|
|
end
|
|
if frame % 500 == 0 then print("frame", frame, "items", #prev_items) end
|
|
end)
|