1
0

async_env.lua 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. -- helper
  2. core.register_async_dofile(core.get_modpath(core.get_current_modname()) ..
  3. DIR_DELIM .. "inside_async_env.lua")
  4. local function deepequal(a, b)
  5. if type(a) == "function" then
  6. return type(b) == "function"
  7. elseif type(a) ~= "table" then
  8. return a == b
  9. elseif type(b) ~= "table" then
  10. return false
  11. end
  12. for k, v in pairs(a) do
  13. if not deepequal(v, b[k]) then
  14. return false
  15. end
  16. end
  17. for k, v in pairs(b) do
  18. if not deepequal(a[k], v) then
  19. return false
  20. end
  21. end
  22. return true
  23. end
  24. -- Object Passing / Serialization
  25. local test_object = {
  26. name = "stairs:stair_glass",
  27. type = "node",
  28. groups = {oddly_breakable_by_hand = 3, cracky = 3, stair = 1},
  29. description = "Glass Stair",
  30. sounds = {
  31. dig = {name = "default_glass_footstep", gain = 0.5},
  32. footstep = {name = "default_glass_footstep", gain = 0.3},
  33. dug = {name = "default_break_glass", gain = 1}
  34. },
  35. node_box = {
  36. fixed = {
  37. {-0.5, -0.5, -0.5, 0.5, 0, 0.5},
  38. {-0.5, 0, 0, 0.5, 0.5, 0.5}
  39. },
  40. type = "fixed"
  41. },
  42. tiles = {
  43. {name = "stairs_glass_split.png", backface_culling = true},
  44. {name = "default_glass.png", backface_culling = true},
  45. {name = "stairs_glass_stairside.png^[transformFX", backface_culling = true}
  46. },
  47. on_place = function(itemstack, placer)
  48. return core.is_player(placer)
  49. end,
  50. sunlight_propagates = true,
  51. is_ground_content = false,
  52. pos = vector.new(-1, -2, -3),
  53. }
  54. local function test_object_passing()
  55. local tmp = core.serialize_roundtrip(test_object)
  56. assert(deepequal(test_object, tmp))
  57. local circular_key = {"foo", "bar"}
  58. circular_key[circular_key] = true
  59. tmp = core.serialize_roundtrip(circular_key)
  60. assert(tmp[1] == "foo")
  61. assert(tmp[2] == "bar")
  62. assert(tmp[tmp] == true)
  63. local circular_value = {"foo"}
  64. circular_value[2] = circular_value
  65. tmp = core.serialize_roundtrip(circular_value)
  66. assert(tmp[1] == "foo")
  67. assert(tmp[2] == tmp)
  68. -- Two-segment cycle
  69. local cycle_seg_1, cycle_seg_2 = {}, {}
  70. cycle_seg_1[1] = cycle_seg_2
  71. cycle_seg_2[1] = cycle_seg_1
  72. tmp = core.serialize_roundtrip(cycle_seg_1)
  73. assert(tmp[1][1] == tmp)
  74. -- Duplicated value without a cycle
  75. local acyclic_dup_holder = {}
  76. tmp = ItemStack("")
  77. acyclic_dup_holder[tmp] = tmp
  78. tmp = core.serialize_roundtrip(acyclic_dup_holder)
  79. for k, v in pairs(tmp) do
  80. assert(rawequal(k, v))
  81. end
  82. end
  83. unittests.register("test_object_passing", test_object_passing)
  84. local function test_userdata_passing(_, pos)
  85. -- basic userdata passing
  86. local obj = table.copy(test_object.tiles[1])
  87. obj.test = ItemStack("default:cobble 99")
  88. local tmp = core.serialize_roundtrip(obj)
  89. assert(type(tmp.test) == "userdata")
  90. assert(obj.test:to_string() == tmp.test:to_string())
  91. -- object can't be passed, should error
  92. obj = core.raycast(pos, pos)
  93. assert(not pcall(core.serialize_roundtrip, obj))
  94. -- VManip
  95. local vm = core.get_voxel_manip(pos, pos)
  96. local expect = vm:get_node_at(pos)
  97. local vm2 = core.serialize_roundtrip(vm)
  98. assert(deepequal(vm2:get_node_at(pos), expect))
  99. end
  100. unittests.register("test_userdata_passing", test_userdata_passing, {map=true})
  101. -- Asynchronous jobs
  102. local function test_handle_async(cb)
  103. -- Basic test including mod name tracking and unittests.async_test()
  104. -- which is defined inside_async_env.lua
  105. local func = function(x)
  106. return core.get_last_run_mod(), _VERSION, unittests[x]()
  107. end
  108. local expect = {core.get_last_run_mod(), _VERSION, true}
  109. core.handle_async(func, function(...)
  110. if not deepequal(expect, {...}) then
  111. return cb("Values did not equal")
  112. end
  113. if core.get_last_run_mod() ~= expect[1] then
  114. return cb("Mod name not tracked correctly")
  115. end
  116. -- Test passing of nil arguments and return values
  117. core.handle_async(function(a, b)
  118. return a, b
  119. end, function(a, b)
  120. if b ~= 123 then
  121. return cb("Argument went missing")
  122. end
  123. cb()
  124. end, nil, 123)
  125. end, "async_test")
  126. end
  127. unittests.register("test_handle_async", test_handle_async, {async=true})
  128. local function test_userdata_passing2(cb, _, pos)
  129. -- VManip: check transfer into other env
  130. local vm = core.get_voxel_manip(pos, pos)
  131. local expect = vm:get_node_at(pos)
  132. core.handle_async(function(vm_, pos_)
  133. return vm_:get_node_at(pos_)
  134. end, function(ret)
  135. if not deepequal(expect, ret) then
  136. return cb("Node data mismatch (one-way)")
  137. end
  138. -- VManip: test a roundtrip
  139. core.handle_async(function(vm_)
  140. return vm_
  141. end, function(vm2)
  142. if not deepequal(expect, vm2:get_node_at(pos)) then
  143. return cb("Node data mismatch (roundtrip)")
  144. end
  145. cb()
  146. end, vm)
  147. end, vm, pos)
  148. end
  149. unittests.register("test_userdata_passing2", test_userdata_passing2, {map=true, async=true})
  150. local function test_portable_metatable_override()
  151. assert(pcall(core.register_portable_metatable, "__builtin:vector", vector.metatable),
  152. "Metatable name aliasing throws an error when it should be allowed")
  153. assert(not pcall(core.register_portable_metatable, "__builtin:vector", {}),
  154. "Illegal metatable overriding allowed")
  155. end
  156. unittests.register("test_portable_metatable_override", test_portable_metatable_override)
  157. local function test_portable_metatable_registration(cb)
  158. local custom_metatable = {}
  159. core.register_portable_metatable("unittests:custom_metatable", custom_metatable)
  160. core.handle_async(function(x)
  161. -- unittests.custom_metatable is registered in inside_async_env.lua
  162. return getmetatable(x) == unittests.custom_metatable, x
  163. end, function(metatable_preserved_async, table_after_roundtrip)
  164. if not metatable_preserved_async then
  165. return cb("Custom metatable not preserved (main -> async)")
  166. end
  167. if getmetatable(table_after_roundtrip) ~= custom_metatable then
  168. return cb("Custom metable not preserved (after roundtrip)")
  169. end
  170. cb()
  171. end, setmetatable({}, custom_metatable))
  172. end
  173. unittests.register("test_portable_metatable_registration", test_portable_metatable_registration, {async=true})
  174. local function test_vector_preserve(cb)
  175. local vec = vector.new(1, 2, 3)
  176. core.handle_async(function(x)
  177. return x[1]
  178. end, function(ret)
  179. if ret ~= vec then -- fails if metatable was not preserved
  180. return cb("Vector value mismatch")
  181. end
  182. cb()
  183. end, {vec})
  184. end
  185. unittests.register("test_async_vector", test_vector_preserve, {async=true})