2021-05-12 18:30:16 +02:00
|
|
|
-- ensure modlib API isn't leaking into global environment
|
|
|
|
assert(modlib.bluon.assert ~= assert)
|
|
|
|
|
2021-03-24 23:46:17 +01:00
|
|
|
local random, huge = math.random, math.huge
|
|
|
|
local parent_env = getfenv(1)
|
|
|
|
setfenv(1, setmetatable({}, {
|
2021-03-27 20:10:49 +01:00
|
|
|
__index = function(_, key)
|
|
|
|
local value = modlib[key]
|
|
|
|
if value ~= nil then
|
|
|
|
return value
|
|
|
|
end
|
|
|
|
return parent_env[key]
|
|
|
|
end,
|
|
|
|
__newindex = function(_, key, value)
|
|
|
|
error(dump{key = key, value = value})
|
|
|
|
end
|
2021-03-24 23:46:17 +01:00
|
|
|
}))
|
2021-03-24 20:27:02 +01:00
|
|
|
|
2021-07-03 11:55:36 +02:00
|
|
|
-- func
|
|
|
|
do
|
|
|
|
local tab = {a = 1, b = 2}
|
|
|
|
func.iterate(function(key, value)
|
|
|
|
assert(tab[key] == value)
|
|
|
|
tab[key] = nil
|
|
|
|
end, pairs, tab)
|
|
|
|
assert(next(tab) == nil)
|
|
|
|
assert(func.aggregate(func.add, 1, 2, 3) == 6)
|
|
|
|
end
|
|
|
|
|
2021-01-19 13:24:10 +01:00
|
|
|
-- string
|
2021-03-24 23:46:17 +01:00
|
|
|
assert(string.escape_magic_chars"%" == "%%")
|
2021-01-19 13:24:10 +01:00
|
|
|
|
2021-01-19 13:18:25 +01:00
|
|
|
-- table
|
2021-01-19 13:24:10 +01:00
|
|
|
do
|
2021-03-27 20:10:49 +01:00
|
|
|
local tab = {}
|
|
|
|
tab[tab] = tab
|
|
|
|
local table_copy = table.deepcopy(tab)
|
|
|
|
assert(table_copy[table_copy] == table_copy)
|
|
|
|
assert(table.is_circular(tab))
|
|
|
|
assert(not table.is_circular{a = 1})
|
|
|
|
assert(table.equals_noncircular({[{}]={}}, {[{}]={}}))
|
|
|
|
assert(table.equals_content(tab, table_copy))
|
|
|
|
local equals_references = table.equals_references
|
|
|
|
assert(equals_references(tab, table_copy))
|
|
|
|
assert(equals_references({}, {}))
|
|
|
|
assert(not equals_references({a = 1, b = 2}, {a = 1, b = 3}))
|
|
|
|
tab = {}
|
|
|
|
tab.a, tab.b = tab, tab
|
|
|
|
table_copy = table.deepcopy(tab)
|
|
|
|
assert(equals_references(tab, table_copy))
|
|
|
|
local x, y = {}, {}
|
|
|
|
assert(not equals_references({[x] = x, [y] = y}, {[x] = y, [y] = x}))
|
|
|
|
assert(equals_references({[x] = x, [y] = y}, {[x] = x, [y] = y}))
|
|
|
|
local nilget = table.nilget
|
|
|
|
assert(nilget({a = {b = {c = 42}}}, "a", "b", "c") == 42)
|
|
|
|
assert(nilget({a = {}}, "a", "b", "c") == nil)
|
|
|
|
assert(nilget(nil, "a", "b", "c") == nil)
|
|
|
|
assert(nilget(nil, "a", nil, "c") == nil)
|
|
|
|
local rope = table.rope{}
|
|
|
|
rope:write"hello"
|
|
|
|
rope:write" "
|
|
|
|
rope:write"world"
|
|
|
|
assert(rope:to_text() == "hello world", rope:to_text())
|
2021-07-03 12:19:44 +02:00
|
|
|
tab = {a = 1, b = {2}}
|
|
|
|
tab[3] = tab
|
|
|
|
local contents = {
|
|
|
|
a = 1,
|
|
|
|
[1] = 1,
|
|
|
|
b = 1,
|
|
|
|
[tab.b] = 1,
|
|
|
|
[2] = 1,
|
|
|
|
[tab] = 1,
|
|
|
|
[3] = 1
|
|
|
|
}
|
|
|
|
table.deep_foreach_any(tab, function(content)
|
|
|
|
assert(contents[content], content)
|
|
|
|
contents[content] = 2
|
|
|
|
end)
|
|
|
|
for _, value in pairs(contents) do
|
|
|
|
assert(value == 2)
|
|
|
|
end
|
2021-01-19 13:24:10 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
-- heap
|
|
|
|
do
|
2021-03-27 20:10:49 +01:00
|
|
|
local n = 100
|
|
|
|
local list = {}
|
|
|
|
for index = 1, n do
|
|
|
|
list[index] = index
|
|
|
|
end
|
|
|
|
table.shuffle(list)
|
|
|
|
local heap = heap.new()
|
|
|
|
for index = 1, #list do
|
|
|
|
heap:push(list[index])
|
|
|
|
end
|
|
|
|
for index = 1, #list do
|
|
|
|
local popped = heap:pop()
|
|
|
|
assert(popped == index)
|
|
|
|
end
|
2021-01-19 13:24:10 +01:00
|
|
|
end
|
|
|
|
|
2021-07-11 16:52:41 +02:00
|
|
|
-- hashlist
|
|
|
|
do
|
|
|
|
local n = 100
|
|
|
|
local list = hashlist.new{}
|
|
|
|
for i = 1, n do
|
|
|
|
list:push_tail(i)
|
|
|
|
end
|
|
|
|
for i = 1, n do
|
|
|
|
local head = list:get_head()
|
|
|
|
assert(head == list:pop_head(i) and head == i)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-01-25 21:18:56 +01:00
|
|
|
-- ranked set
|
|
|
|
do
|
2021-03-27 20:10:49 +01:00
|
|
|
local n = 100
|
|
|
|
local ranked_set = ranked_set.new()
|
|
|
|
local list = {}
|
|
|
|
for i = 1, n do
|
|
|
|
ranked_set:insert(i)
|
|
|
|
list[i] = i
|
|
|
|
end
|
2021-01-25 21:18:56 +01:00
|
|
|
|
2021-03-27 20:10:49 +01:00
|
|
|
assert(table.equals(ranked_set:to_table(), list))
|
2021-01-25 21:18:56 +01:00
|
|
|
|
2021-03-27 20:10:49 +01:00
|
|
|
local i = 0
|
|
|
|
for rank, key in ranked_set:ipairs() do
|
|
|
|
i = i + 1
|
|
|
|
assert(i == key and i == rank)
|
|
|
|
assert(ranked_set:get_by_rank(rank) == key)
|
|
|
|
local rank, key = ranked_set:get(i)
|
|
|
|
assert(key == i and i == rank)
|
|
|
|
end
|
|
|
|
assert(i == n)
|
2021-01-25 21:18:56 +01:00
|
|
|
|
2021-03-27 20:10:49 +01:00
|
|
|
for i = 1, n do
|
|
|
|
local _, v = ranked_set:delete(i)
|
|
|
|
assert(v == i, i)
|
|
|
|
end
|
|
|
|
assert(not next(ranked_set:to_table()))
|
2021-01-25 21:18:56 +01:00
|
|
|
|
2021-03-27 20:10:49 +01:00
|
|
|
local ranked_set = ranked_set.new()
|
|
|
|
for i = 1, n do
|
|
|
|
ranked_set:insert(i)
|
|
|
|
end
|
2021-01-25 21:18:56 +01:00
|
|
|
|
2021-03-27 20:10:49 +01:00
|
|
|
for rank, key in ranked_set:ipairs(10, 20) do
|
|
|
|
assert(rank == key and key >= 10 and key <= 20)
|
|
|
|
end
|
2021-01-25 21:18:56 +01:00
|
|
|
|
2021-03-27 20:10:49 +01:00
|
|
|
for i = n, 1, -1 do
|
|
|
|
local j = ranked_set:delete_by_rank(i)
|
|
|
|
assert(j == i)
|
|
|
|
end
|
2021-01-25 21:18:56 +01:00
|
|
|
end
|
|
|
|
|
2021-02-07 14:00:48 +01:00
|
|
|
-- k-d-tree
|
|
|
|
local vectors = {}
|
|
|
|
for _ = 1, 1000 do
|
2021-03-27 20:10:49 +01:00
|
|
|
_G.table.insert(vectors, {random(), random(), random()})
|
2021-02-07 14:00:48 +01:00
|
|
|
end
|
2021-03-24 23:46:17 +01:00
|
|
|
local kdtree = kdtree.new(vectors)
|
|
|
|
for _, v in ipairs(vectors) do
|
2021-03-27 20:10:49 +01:00
|
|
|
local neighbor, distance = kdtree:get_nearest_neighbor(v)
|
|
|
|
assert(vector.equals(v, neighbor), distance == 0)
|
2021-02-07 14:00:48 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
for _ = 1, 1000 do
|
2021-03-27 20:10:49 +01:00
|
|
|
local v = {random(), random(), random()}
|
|
|
|
local _, distance = kdtree:get_nearest_neighbor(v)
|
|
|
|
local min_distance = huge
|
|
|
|
for _, w in ipairs(vectors) do
|
|
|
|
local other_distance = vector.distance(v, w)
|
|
|
|
if other_distance < min_distance then
|
|
|
|
min_distance = other_distance
|
|
|
|
end
|
|
|
|
end
|
|
|
|
assert(distance == min_distance)
|
2021-02-07 14:00:48 +01:00
|
|
|
end
|
|
|
|
|
2021-07-07 12:31:40 +02:00
|
|
|
local function serializer_test(assert_preserves)
|
|
|
|
-- TODO nan
|
|
|
|
for _, constant in pairs{true, false, huge, -huge} do
|
|
|
|
assert_preserves(constant)
|
|
|
|
end
|
|
|
|
-- Strings
|
|
|
|
for i = 1, 1000 do
|
|
|
|
assert_preserves(_G.table.concat(table.repetition(_G.string.char(i % 256), i)))
|
|
|
|
end
|
|
|
|
-- Numbers
|
|
|
|
for _ = 1, 1000 do
|
|
|
|
local int = random(-2^50, 2^50)
|
|
|
|
assert(int % 1 == 0)
|
|
|
|
assert_preserves(int)
|
|
|
|
assert_preserves((random() - 0.5) * 2^random(-20, 20))
|
|
|
|
end
|
|
|
|
-- Simple tables
|
|
|
|
assert_preserves{hello = "world", welt = "hallo"}
|
|
|
|
assert_preserves{"hello", "hello", "hello"}
|
|
|
|
local circular = {}
|
|
|
|
circular[circular] = circular
|
|
|
|
circular[1] = circular
|
|
|
|
assert_preserves(circular)
|
|
|
|
local mixed = {1, 2, 3}
|
|
|
|
mixed[mixed] = mixed
|
|
|
|
mixed.vec = {x = 1, y = 2, z = 3}
|
|
|
|
mixed.vec2 = modlib.table.copy(mixed.vec)
|
|
|
|
mixed.blah = "blah"
|
|
|
|
assert_preserves(mixed)
|
2021-07-07 19:14:56 +02:00
|
|
|
local a, b, c = {}, {}, {}
|
|
|
|
a[a] = a; a[b] = b; a[c] = c;
|
|
|
|
b[a] = a; b[b] = b; b[c] = c;
|
|
|
|
c[a] = a; c[b] = b; c[c] = c;
|
|
|
|
a.a = {"a", a = a}
|
|
|
|
assert_preserves(a)
|
2021-07-07 12:31:40 +02:00
|
|
|
end
|
|
|
|
|
2021-03-05 15:07:34 +01:00
|
|
|
-- bluon
|
|
|
|
do
|
2021-03-27 20:10:49 +01:00
|
|
|
local bluon = bluon
|
2021-07-07 12:31:40 +02:00
|
|
|
serializer_test(function(object)
|
2021-03-27 20:10:49 +01:00
|
|
|
local rope = table.rope{}
|
|
|
|
local written, read, input
|
|
|
|
local _, err = pcall(function()
|
|
|
|
bluon:write(object, rope)
|
|
|
|
written = rope:to_text()
|
|
|
|
input = text.inputstream(written)
|
|
|
|
read = bluon:read(input)
|
|
|
|
local remaining = input:read(1000)
|
|
|
|
assert(not remaining)
|
|
|
|
end)
|
|
|
|
assertdump(table.equals_references(object, read) and not err, {
|
|
|
|
object = object,
|
|
|
|
read = read,
|
|
|
|
written = written and text.hexdump(written),
|
|
|
|
err = err
|
|
|
|
})
|
2021-07-07 12:31:40 +02:00
|
|
|
end)
|
2021-03-05 15:07:34 +01:00
|
|
|
end
|
|
|
|
|
2021-07-06 21:56:20 +02:00
|
|
|
-- luon
|
|
|
|
do
|
2021-07-07 12:31:40 +02:00
|
|
|
serializer_test(function(object)
|
2021-07-08 13:28:11 +02:00
|
|
|
local serialized = luon:write_string(object)
|
|
|
|
assert(table.equals_references(object, luon:read_string(serialized)), serialized)
|
2021-07-07 12:31:40 +02:00
|
|
|
end)
|
2021-07-08 13:28:11 +02:00
|
|
|
local nan = luon:read_string(luon:write_string(0/0))
|
2021-07-07 12:31:40 +02:00
|
|
|
assert(nan ~= nan)
|
2021-07-06 21:56:20 +02:00
|
|
|
end
|
|
|
|
|
2021-03-30 18:06:41 +02:00
|
|
|
if not _G.minetest then return end
|
|
|
|
|
2021-07-11 16:07:54 +02:00
|
|
|
assert(minetest.luon:read_string(minetest.luon:write_string(ItemStack"")))
|
|
|
|
|
2021-03-30 18:06:41 +02:00
|
|
|
-- colorspec
|
|
|
|
local colorspec = minetest.colorspec
|
|
|
|
local function test_from_string(string, number)
|
|
|
|
local spec = colorspec.from_string(string)
|
|
|
|
local expected = colorspec.from_number(number)
|
|
|
|
assertdump(table.equals(spec, expected), {expected = expected, actual = spec})
|
|
|
|
end
|
|
|
|
local spec = colorspec.from_number(0xDDCCBBAA)
|
|
|
|
assertdump(table.equals(spec, {a = 0xAA, b = 0xBB, g = 0xCC, r = 0xDD}), spec)
|
|
|
|
test_from_string("aliceblue", 0xf0f8ffff)
|
|
|
|
test_from_string("aliceblue#42", 0xf0f8ff42)
|
|
|
|
test_from_string("#333", 0x333333FF)
|
|
|
|
test_from_string("#694269", 0x694269FF)
|
|
|
|
test_from_string("#11223344", 0x11223344)
|
2021-07-12 16:15:37 +02:00
|
|
|
assert(colorspec.from_string"#694269":to_string() == "694269")
|
2021-03-30 18:06:41 +02:00
|
|
|
|
2021-07-03 19:35:02 +02:00
|
|
|
local function test_logfile(reference_strings)
|
|
|
|
local logfile = persistence.lua_log_file.new(mod.get_resource"logfile.test.lua", {}, reference_strings)
|
|
|
|
logfile:init()
|
|
|
|
logfile.root = {a_longer_string = "test"}
|
|
|
|
logfile:rewrite()
|
|
|
|
logfile:set_root({a = 1}, {b = 2, c = 3, d = _G.math.huge, e = -_G.math.huge})
|
2021-07-06 09:24:25 +02:00
|
|
|
local circular = {}
|
|
|
|
circular[circular] = circular
|
|
|
|
logfile:set_root(circular, circular)
|
2021-07-03 19:35:02 +02:00
|
|
|
logfile:close()
|
|
|
|
logfile:init()
|
2021-07-06 09:24:25 +02:00
|
|
|
assert(table.equals_references(logfile.root, {
|
|
|
|
a_longer_string = "test",
|
|
|
|
[{a = 1}] = {b = 2, c = 3, d = _G.math.huge, e = -_G.math.huge},
|
|
|
|
[circular] = circular,
|
|
|
|
}))
|
2021-07-03 19:35:02 +02:00
|
|
|
if not reference_strings then
|
|
|
|
for key in pairs(logfile.references) do
|
|
|
|
assert(type(key) ~= "string")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
test_logfile(true)
|
|
|
|
test_logfile(false)
|
2021-04-21 21:11:00 +02:00
|
|
|
|
2021-02-01 16:27:21 +01:00
|
|
|
-- in-game tests & b3d testing
|
2020-12-21 20:26:06 +01:00
|
|
|
local tests = {
|
2021-03-27 20:10:49 +01:00
|
|
|
-- depends on player_api
|
|
|
|
b3d = false,
|
|
|
|
liquid_dir = false,
|
|
|
|
liquid_raycast = false
|
2020-12-21 20:26:06 +01:00
|
|
|
}
|
2021-02-01 16:27:21 +01:00
|
|
|
if tests.b3d then
|
2021-03-27 20:10:49 +01:00
|
|
|
local stream = io.open(mod.get_resource("player_api", "models", "character.b3d"), "r")
|
|
|
|
assert(stream)
|
|
|
|
local b3d = b3d.read(stream)
|
|
|
|
--! dirty helper method to create truncate tables with 10+ number keys
|
|
|
|
local function _b3d_truncate(table)
|
|
|
|
local count = 1
|
|
|
|
for key, value in pairs(table) do
|
|
|
|
if type(key) == "table" then
|
|
|
|
_b3d_truncate(key)
|
|
|
|
end
|
|
|
|
if type(value) == "table" then
|
|
|
|
_b3d_truncate(value)
|
|
|
|
end
|
|
|
|
count = count + 1
|
|
|
|
if type(key) == "number" and count >= 9 and next(table, key) then
|
|
|
|
if count == 9 then
|
|
|
|
table[key] = "TRUNCATED"
|
|
|
|
else
|
|
|
|
table[key] = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return table
|
|
|
|
end
|
|
|
|
file.write(mod.get_resource"character.b3d.lua", "return " .. dump(_b3d_truncate(table.copy(b3d))))
|
|
|
|
stream:close()
|
2021-02-01 16:27:21 +01:00
|
|
|
end
|
2021-03-24 23:46:17 +01:00
|
|
|
local vector, minetest, ml_mt = _G.vector, _G.minetest, minetest
|
2020-12-21 20:26:06 +01:00
|
|
|
if tests.liquid_dir then
|
2021-03-27 20:10:49 +01:00
|
|
|
minetest.register_abm{
|
|
|
|
label = "get_liquid_corner_levels & get_liquid_direction test",
|
|
|
|
nodenames = {"group:liquid"},
|
|
|
|
interval = 1,
|
|
|
|
chance = 1,
|
|
|
|
action = function(pos, node)
|
|
|
|
assert(type(node) == "table")
|
|
|
|
for _, corner_level in pairs(ml_mt.get_liquid_corner_levels(pos, node)) do
|
|
|
|
minetest.add_particle{
|
|
|
|
pos = vector.add(pos, corner_level),
|
|
|
|
size = 2,
|
|
|
|
texture = "logo.png"
|
|
|
|
}
|
|
|
|
end
|
|
|
|
local direction = ml_mt.get_liquid_flow_direction(pos, node)
|
|
|
|
local start_pos = pos
|
|
|
|
start_pos.y = start_pos.y + 1
|
|
|
|
for i = 0, 5 do
|
|
|
|
minetest.add_particle{
|
|
|
|
pos = vector.add(start_pos, vector.multiply(direction, i/5)),
|
|
|
|
size = i/2.5,
|
|
|
|
texture = "logo.png"
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
}
|
2020-12-21 20:26:06 +01:00
|
|
|
end
|
|
|
|
if tests.liquid_raycast then
|
2021-03-27 20:10:49 +01:00
|
|
|
minetest.register_globalstep(function()
|
|
|
|
for _, player in pairs(minetest.get_connected_players()) do
|
|
|
|
local eye_pos = vector.offset(player:get_pos(), 0, player:get_properties().eye_height, 0)
|
|
|
|
local raycast = ml_mt.raycast(eye_pos, vector.add(eye_pos, vector.multiply(player:get_look_dir(), 3)), false, true)
|
|
|
|
for pointed_thing in raycast do
|
|
|
|
if pointed_thing.type == "node" and minetest.registered_nodes[minetest.get_node(pointed_thing.under).name].liquidtype == "flowing" then
|
|
|
|
minetest.add_particle{
|
|
|
|
pos = vector.add(pointed_thing.intersection_point, vector.multiply(pointed_thing.intersection_normal, 0.1)),
|
|
|
|
size = 0.5,
|
|
|
|
texture = "object_marker_red.png",
|
|
|
|
expirationtime = 3
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end)
|
2020-12-21 20:26:06 +01:00
|
|
|
end
|