123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- core.register_mapgen_script(core.get_modpath(core.get_current_modname()) ..
- DIR_DELIM .. "inside_mapgen_env.lua")
- local function test_pseudo_random()
- -- We have comprehensive unit tests in C++, this is just to make sure the API code isn't messing up
- local gen1 = PseudoRandom(13)
- assert(gen1:next() == 22290)
- assert(gen1:next() == 13854)
- local gen2 = PseudoRandom(gen1:get_state())
- for n = 0, 16 do
- assert(gen1:next() == gen2:next())
- end
- local pr3 = PseudoRandom(-101)
- assert(pr3:next(0, 100) == 35)
- -- unusual case that is normally disallowed:
- assert(pr3:next(10000, 42767) == 12485)
- end
- unittests.register("test_pseudo_random", test_pseudo_random)
- local function test_pcg_random()
- -- We have comprehensive unit tests in C++, this is just to make sure the API code isn't messing up
- local gen1 = PcgRandom(55)
- for n = 0, 16 do
- gen1:next()
- end
- local gen2 = PcgRandom(26)
- gen2:set_state(gen1:get_state())
- for n = 16, 32 do
- assert(gen1:next() == gen2:next())
- end
- end
- unittests.register("test_pcg_random", test_pcg_random)
- local function test_dynamic_media(cb, player)
- if core.get_player_information(player:get_player_name()).protocol_version < 40 then
- core.log("warning", "test_dynamic_media: Client too old, skipping test.")
- return cb()
- end
- -- Check that the client acknowledges media transfers
- local path = core.get_worldpath() .. "/test_media.obj"
- local f = io.open(path, "w")
- f:write("# contents don't matter\n")
- f:close()
- local call_ok = false
- local ok = core.dynamic_add_media({
- filepath = path,
- to_player = player:get_player_name(),
- }, function(name)
- if not call_ok then
- return cb("impossible condition")
- end
- cb()
- end)
- if not ok then
- return cb("dynamic_add_media() returned error")
- end
- call_ok = true
- -- if the callback isn't called this test will just hang :shrug:
- end
- unittests.register("test_dynamic_media", test_dynamic_media, {async=true, player=true})
- local function test_v3f_metatable(player)
- assert(vector.check(player:get_pos()))
- end
- unittests.register("test_v3f_metatable", test_v3f_metatable, {player=true})
- local function test_v3s16_metatable(player, pos)
- local node = core.get_node(pos)
- local found_pos = core.find_node_near(pos, 0, node.name, true)
- assert(vector.check(found_pos))
- end
- unittests.register("test_v3s16_metatable", test_v3s16_metatable, {map=true})
- local function test_clear_meta(_, pos)
- local ref = core.get_meta(pos)
- for way = 1, 3 do
- ref:set_string("foo", "bar")
- assert(ref:contains("foo"))
- if way == 1 then
- ref:from_table({})
- elseif way == 2 then
- ref:from_table(nil)
- else
- ref:set_string("foo", "")
- end
- assert(#core.find_nodes_with_meta(pos, pos) == 0, "clearing failed " .. way)
- end
- end
- unittests.register("test_clear_meta", test_clear_meta, {map=true})
- local on_punch_called, on_place_called
- core.register_on_placenode(function()
- on_place_called = true
- end)
- core.register_on_punchnode(function()
- on_punch_called = true
- end)
- local function test_node_callbacks(_, pos)
- on_place_called = false
- on_punch_called = false
- core.place_node(pos, {name="basenodes:dirt"})
- assert(on_place_called, "on_place not called")
- core.punch_node(pos)
- assert(on_punch_called, "on_punch not called")
- core.remove_node(pos)
- end
- unittests.register("test_node_callbacks", test_node_callbacks, {map=true})
- local function test_hashing()
- local input = "hello\000world"
- assert(core.sha1(input) == "f85b420f1e43ebf88649dfcab302b898d889606c")
- assert(core.sha256(input) == "b206899bc103669c8e7b36de29d73f95b46795b508aa87d612b2ce84bfb29df2")
- end
- unittests.register("test_hashing", test_hashing)
- local function test_compress()
- -- This text should be compressible, to make sure the results are... normal
- local text = "The\000 icey canoe couldn't move very well on the\128 lake. The\000 ice was too stiff and the icey canoe's paddles simply wouldn't punch through."
- local methods = {
- "deflate",
- "zstd",
- -- "noodle", -- for warning alarm test
- }
- local zstd_magic = string.char(0x28, 0xB5, 0x2F, 0xFD)
- for _, method in ipairs(methods) do
- local compressed = core.compress(text, method)
- assert(core.decompress(compressed, method) == text, "input/output mismatch for compression method " .. method)
- local has_zstd_magic = compressed:sub(1, 4) == zstd_magic
- if method == "zstd" then
- assert(has_zstd_magic, "zstd magic number not in zstd method")
- else
- assert(not has_zstd_magic, "zstd magic number in method " .. method .. " (which is not zstd)")
- end
- end
- end
- unittests.register("test_compress", test_compress)
- local function test_urlencode()
- -- checks that API code handles null bytes
- assert(core.urlencode("foo\000bar!") == "foo%00bar%21")
- end
- unittests.register("test_urlencode", test_urlencode)
- local function test_parse_json()
- local raw = "{\"how\\u0000weird\":\n\"yes\\u0000really\",\"n\":-1234567891011,\"z\":null}"
- do
- local data = core.parse_json(raw)
- assert(data["how\000weird"] == "yes\000really")
- assert(data.n == -1234567891011)
- assert(data.z == nil)
- end
- do
- local null = {}
- local data = core.parse_json(raw, null)
- assert(data.z == null)
- end
- do
- local data, err = core.parse_json('"ceci n\'est pas un json', nil, true)
- assert(data == nil)
- assert(type(err) == "string")
- end
- end
- unittests.register("test_parse_json", test_parse_json)
- local function test_write_json()
- -- deeply nested structures should be preserved
- local leaf = 42
- local data = leaf
- for i = 1, 1000 do
- data = {data}
- end
- local roundtripped = core.parse_json(core.write_json(data))
- for i = 1, 1000 do
- roundtripped = roundtripped[1]
- end
- assert(roundtripped == 42)
- end
- unittests.register("test_write_json", test_write_json)
- local function test_game_info()
- local info = core.get_game_info()
- local game_conf = Settings(info.path .. "/game.conf")
- assert(info.id == "devtest")
- assert(info.title == game_conf:get("title"))
- end
- unittests.register("test_game_info", test_game_info)
- local function test_mapgen_edges(cb)
- -- Test that the map can extend to the expected edges and no further.
- local min_edge, max_edge = core.get_mapgen_edges()
- local min_finished = {}
- local max_finished = {}
- local function finish()
- if #min_finished ~= 1 then
- return cb("Expected 1 block to emerge around mapgen minimum edge")
- end
- if min_finished[1] ~= (min_edge / core.MAP_BLOCKSIZE):floor() then
- return cb("Expected block within minimum edge to emerge")
- end
- if #max_finished ~= 1 then
- return cb("Expected 1 block to emerge around mapgen maximum edge")
- end
- if max_finished[1] ~= (max_edge / core.MAP_BLOCKSIZE):floor() then
- return cb("Expected block within maximum edge to emerge")
- end
- return cb()
- end
- local emerges_left = 2
- local function emerge_block(blockpos, action, blocks_left, finished)
- if action ~= core.EMERGE_CANCELLED then
- table.insert(finished, blockpos)
- end
- if blocks_left == 0 then
- emerges_left = emerges_left - 1
- if emerges_left == 0 then
- return finish()
- end
- end
- end
- core.emerge_area(min_edge:subtract(1), min_edge, emerge_block, min_finished)
- core.emerge_area(max_edge, max_edge:add(1), emerge_block, max_finished)
- end
- unittests.register("test_mapgen_edges", test_mapgen_edges, {map=true, async=true})
- local finish_test_on_mapblocks_changed
- core.register_on_mapblocks_changed(function(modified_blocks, modified_block_count)
- if finish_test_on_mapblocks_changed then
- finish_test_on_mapblocks_changed(modified_blocks, modified_block_count)
- finish_test_on_mapblocks_changed = nil
- end
- end)
- local function test_on_mapblocks_changed(cb, player, pos)
- local bp1 = (pos / core.MAP_BLOCKSIZE):floor()
- local bp2 = bp1:add(1)
- for _, bp in ipairs({bp1, bp2}) do
- -- Make a modification in the block.
- local p = bp * core.MAP_BLOCKSIZE
- core.load_area(p)
- local meta = core.get_meta(p)
- meta:set_int("test_on_mapblocks_changed", meta:get_int("test_on_mapblocks_changed") + 1)
- end
- finish_test_on_mapblocks_changed = function(modified_blocks, modified_block_count)
- if modified_block_count < 2 then
- return cb("Expected at least two mapblocks to be recorded as modified")
- end
- if not modified_blocks[core.hash_node_position(bp1)] or
- not modified_blocks[core.hash_node_position(bp2)] then
- return cb("The expected mapblocks were not recorded as modified")
- end
- cb()
- end
- end
- unittests.register("test_on_mapblocks_changed", test_on_mapblocks_changed, {map=true, async=true})
- local function test_gennotify_api()
- local DECO_ID = 123
- local UD_ID = "unittests:dummy"
- -- the engine doesn't check if the id is actually valid, maybe it should
- core.set_gen_notify({decoration=true}, {DECO_ID})
- core.set_gen_notify({custom=true}, nil, {UD_ID})
- local flags, deco, custom = core.get_gen_notify()
- local function ff(flag)
- return (" " .. flags .. " "):match("[ ,]" .. flag .. "[ ,]") ~= nil
- end
- assert(ff("decoration"), "'decoration' flag missing")
- assert(ff("custom"), "'custom' flag missing")
- assert(table.indexof(deco, DECO_ID) > 0)
- assert(table.indexof(custom, UD_ID) > 0)
- core.set_gen_notify({decoration=false, custom=false})
- flags, deco, custom = core.get_gen_notify()
- assert(not ff("decoration") and not ff("custom"))
- assert(#deco == 0, "deco ids not empty")
- assert(#custom == 0, "custom ids not empty")
- end
- unittests.register("test_gennotify_api", test_gennotify_api)
- -- <=> inside_mapgen_env.lua
- local function test_mapgen_env(cb)
- -- emerge threads start delayed so this can take a second
- local res = core.ipc_get("unittests:mg")
- if res == nil then
- return core.after(0, test_mapgen_env, cb)
- end
- -- handle error status
- if res[1] then
- cb()
- else
- cb(res[2])
- end
- end
- unittests.register("test_mapgen_env", test_mapgen_env, {async=true})
- local function test_ipc_vector_preserve(cb)
- -- the IPC also uses register_portable_metatable
- core.ipc_set("unittests:v", vector.new(4, 0, 4))
- local v = core.ipc_get("unittests:v")
- assert(type(v) == "table")
- assert(vector.check(v))
- end
- unittests.register("test_ipc_vector_preserve", test_ipc_vector_preserve)
- local function test_ipc_poll(cb)
- core.ipc_set("unittests:flag", nil)
- assert(core.ipc_poll("unittests:flag", 1) == false)
- -- Note that unlike the async result callback - which has to wait for the
- -- next server step - the IPC is instant
- local t0 = core.get_us_time()
- core.handle_async(function()
- core.ipc_set("unittests:flag", true)
- end, function() end)
- assert(core.ipc_poll("unittests:flag", 1000) == true, "Wait failed (or slow machine?)")
- print("delta: " .. (core.get_us_time() - t0) .. "us")
- end
- unittests.register("test_ipc_poll", test_ipc_poll)
|