-------------------------------------------------------------------------------- --- Various utilities for managing lua tables - used in tests -- @module test.test-lib.table -- This file is a part of lua-nucleo library -- @copyright lua-nucleo authors (see file `COPYRIGHT` for the license) -------------------------------------------------------------------------------- local function gen_random_dataset(num, nesting, visited, random) random = random or math.random nesting = nesting or 1 visited = visited or {} num = num or random(0, 10) local gen_str = function() local len = random(1, 64) local t = {} for i = 1, len do t[i] = string.char(random(0, 255)) end return table.concat(t) end local gen_bool = function() return random() >= 0.5 end local gen_udata = function() return newproxy() end local gen_func = function() return function() end end local gen_thread = function() return coroutine.create(function() end) end local gen_nil = function() return nil end local gen_visited_link = function() if #visited > 1 then return visited[random(1, #visited)] else return gen_str() end end local generators = { gen_bool; gen_bool; gen_bool; function() return random(-10, 10) end; gen_str; gen_str; gen_str; --[[ gen_thread; gen_thread; gen_func; gen_func; gen_udata; gen_udata;--]] gen_visited_link; function() if nesting >= 10 then return nil end local t = {} visited[#visited + 1] = t local n = random(0, 10 - nesting) for i = 1, n do local k = gen_random_dataset(1, nesting + 1, visited, random) if k == nil then k = "(nil)" end t[ k ] = gen_random_dataset(1, nesting + 1, visited, random) end return t end } local t = {} visited[#visited + 1] = t for i = 1, num do local n = random(1, #generators) t[i] = generators[n]() end return unpack(t, 1, num) end local mutate do local impl impl = function(t, visited, vis) local mutated = false visited = visited or {} vis = vis or {} if type(t) == table then if not vis[t] then visited[#visited + 1] = t vis[t] = true end local n = math.random(0, 2) if n == 0 then for k, v in pairs(t) do t[k] = nil local v_1 = impl(v, visited, vis) local k_1 = impl(k, visited, vis) if k_1 ~= k or v_1 ~= v then mutated = true end k = k_1 v = v_1 end elseif n == 1 then local n = math.random(1, #visited) local t1 = visited[n] if t1 ~= t then mutated = true end else local t1 = gen_random_dataset() if t1 ~= t then mutated = true end t = t1 end else local t1 = gen_random_dataset() if t1 ~= t then mutated = true end t = t1 end return t, mutated end mutate = function(t) local r, mutated = impl(t) return mutated, r end end return { gen_random_dataset = gen_random_dataset; mutate = mutate; }