summaryrefslogtreecommitdiff
path: root/games/devtest/mods/unittests/async_env.lua
blob: b7edf941eb78048779a85d99cdae12ba82ed970e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
-- helper

core.register_async_dofile(core.get_modpath(core.get_current_modname()) ..
	DIR_DELIM .. "inside_async_env.lua")

local function deepequal(a, b)
	if type(a) == "function" then
		return type(b) == "function"
	elseif type(a) ~= "table" then
		return a == b
	elseif type(b) ~= "table" then
		return false
	end
	for k, v in pairs(a) do
		if not deepequal(v, b[k]) then
			return false
		end
	end
	for k, v in pairs(b) do
		if not deepequal(a[k], v) then
			return false
		end
	end
	return true
end

-- Object Passing / Serialization

local test_object = {
	name = "stairs:stair_glass",
	type = "node",
	groups = {oddly_breakable_by_hand = 3, cracky = 3, stair = 1},
	description = "Glass Stair",
	sounds = {
		dig = {name = "default_glass_footstep", gain = 0.5},
		footstep = {name = "default_glass_footstep", gain = 0.3},
		dug = {name = "default_break_glass", gain = 1}
	},
	node_box = {
		fixed = {
			{-0.5, -0.5, -0.5, 0.5, 0, 0.5},
			{-0.5, 0, 0, 0.5, 0.5, 0.5}
		},
		type = "fixed"
	},
	tiles = {
		{name = "stairs_glass_split.png", backface_culling = true},
		{name = "default_glass.png", backface_culling = true},
		{name = "stairs_glass_stairside.png^[transformFX", backface_culling = true}
	},
	on_place = function(itemstack, placer)
		return core.is_player(placer)
	end,
	sunlight_propagates = true,
	is_ground_content = false,
	light_source = 0,
}

local function test_object_passing()
	local tmp = core.serialize_roundtrip(test_object)
	assert(deepequal(test_object, tmp))

	local circular_key = {"foo", "bar"}
	circular_key[circular_key] = true
	tmp = core.serialize_roundtrip(circular_key)
	assert(tmp[1] == "foo")
	assert(tmp[2] == "bar")
	assert(tmp[tmp] == true)

	local circular_value = {"foo"}
	circular_value[2] = circular_value
	tmp = core.serialize_roundtrip(circular_value)
	assert(tmp[1] == "foo")
	assert(tmp[2] == tmp)

	-- Two-segment cycle
	local cycle_seg_1, cycle_seg_2 = {}, {}
	cycle_seg_1[1] = cycle_seg_2
	cycle_seg_2[1] = cycle_seg_1
	tmp = core.serialize_roundtrip(cycle_seg_1)
	assert(tmp[1][1] == tmp)

	-- Duplicated value without a cycle
	local acyclic_dup_holder = {}
	tmp = ItemStack("")
	acyclic_dup_holder[tmp] = tmp
	tmp = core.serialize_roundtrip(acyclic_dup_holder)
	for k, v in pairs(tmp) do
		assert(rawequal(k, v))
	end
end
unittests.register("test_object_passing", test_object_passing)

local function test_userdata_passing(_, pos)
	-- basic userdata passing
	local obj = table.copy(test_object.tiles[1])
	obj.test = ItemStack("default:cobble 99")
	local tmp = core.serialize_roundtrip(obj)
	assert(type(tmp.test) == "userdata")
	assert(obj.test:to_string() == tmp.test:to_string())

	-- object can't be passed, should error
	obj = core.raycast(pos, pos)
	assert(not pcall(core.serialize_roundtrip, obj))

	-- VManip
	local vm = core.get_voxel_manip(pos, pos)
	local expect = vm:get_node_at(pos)
	local vm2 = core.serialize_roundtrip(vm)
	assert(deepequal(vm2:get_node_at(pos), expect))
end
unittests.register("test_userdata_passing", test_userdata_passing, {map=true})

-- Asynchronous jobs

local function test_handle_async(cb)
	-- Basic test including mod name tracking and unittests.async_test()
	-- which is defined inside_async_env.lua
	local func = function(x)
		return core.get_last_run_mod(), _VERSION, unittests[x]()
	end
	local expect = {core.get_last_run_mod(), _VERSION, true}

	core.handle_async(func, function(...)
		if not deepequal(expect, {...}) then
			return cb("Values did not equal")
		end
		if core.get_last_run_mod() ~= expect[1] then
			return cb("Mod name not tracked correctly")
		end

		-- Test passing of nil arguments and return values
		core.handle_async(function(a, b)
			return a, b
		end, function(a, b)
			if b ~= 123 then
				return cb("Argument went missing")
			end
			cb()
		end, nil, 123)
	end, "async_test")
end
unittests.register("test_handle_async", test_handle_async, {async=true})

local function test_userdata_passing2(cb, _, pos)
	-- VManip: check transfer into other env
	local vm = core.get_voxel_manip(pos, pos)
	local expect = vm:get_node_at(pos)

	core.handle_async(function(vm_, pos_)
		return vm_:get_node_at(pos_)
	end, function(ret)
		if not deepequal(expect, ret) then
			return cb("Node data mismatch (one-way)")
		end

		-- VManip: test a roundtrip
		core.handle_async(function(vm_)
			return vm_
		end, function(vm2)
			if not deepequal(expect, vm2:get_node_at(pos)) then
				return cb("Node data mismatch (roundtrip)")
			end
			cb()
		end, vm)
	end, vm, pos)
end
unittests.register("test_userdata_passing2", test_userdata_passing2, {map=true, async=true})