misc_helpers_spec.lua 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. _G.core = {}
  2. dofile("builtin/common/math.lua")
  3. dofile("builtin/common/vector.lua")
  4. dofile("builtin/common/misc_helpers.lua")
  5. describe("string", function()
  6. it("trim()", function()
  7. assert.equal("foo bar", string.trim("\n \t\tfoo bar\t "))
  8. end)
  9. describe("split()", function()
  10. it("removes empty", function()
  11. assert.same({ "hello" }, string.split("hello"))
  12. assert.same({ "hello", "world" }, string.split("hello,world"))
  13. assert.same({ "hello", "world" }, string.split("hello,world,,,"))
  14. assert.same({ "hello", "world" }, string.split(",,,hello,world"))
  15. assert.same({ "hello", "world", "2" }, string.split("hello,,,world,2"))
  16. assert.same({ "hello ", " world" }, string.split("hello :| world", ":|"))
  17. end)
  18. it("keeps empty", function()
  19. assert.same({ "hello" }, string.split("hello", ",", true))
  20. assert.same({ "hello", "world" }, string.split("hello,world", ",", true))
  21. assert.same({ "hello", "world", "" }, string.split("hello,world,", ",", true))
  22. assert.same({ "hello", "", "", "world", "2" }, string.split("hello,,,world,2", ",", true))
  23. assert.same({ "", "", "hello", "world", "2" }, string.split(",,hello,world,2", ",", true))
  24. assert.same({ "hello ", " world | :" }, string.split("hello :| world | :", ":|"))
  25. end)
  26. it("max_splits", function()
  27. assert.same({ "one" }, string.split("one", ",", true, 2))
  28. assert.same({ "one,two,three,four" }, string.split("one,two,three,four", ",", true, 0))
  29. assert.same({ "one", "two", "three,four" }, string.split("one,two,three,four", ",", true, 2))
  30. assert.same({ "one", "", "two,three,four" }, string.split("one,,two,three,four", ",", true, 2))
  31. assert.same({ "one", "two", "three,four" }, string.split("one,,,,,,two,three,four", ",", false, 2))
  32. end)
  33. it("pattern", function()
  34. assert.same({ "one", "two" }, string.split("one,two", ",", false, -1, true))
  35. assert.same({ "one", "two", "three" }, string.split("one2two3three", "%d", false, -1, true))
  36. end)
  37. it("rejects empty separator", function()
  38. assert.has.errors(function()
  39. string.split("", "")
  40. end)
  41. end)
  42. end)
  43. end)
  44. describe("privs", function()
  45. it("from string", function()
  46. assert.same({ a = true, b = true }, core.string_to_privs("a,b"))
  47. end)
  48. it("to string", function()
  49. assert.equal("one", core.privs_to_string({ one=true }))
  50. local ret = core.privs_to_string({ a=true, b=true })
  51. assert(ret == "a,b" or ret == "b,a")
  52. end)
  53. end)
  54. describe("pos", function()
  55. it("from string", function()
  56. assert.equal(vector.new(10, 5.1, -2), core.string_to_pos("10.0, 5.1, -2"))
  57. assert.equal(vector.new(10, 5.1, -2), core.string_to_pos("( 10.0, 5.1, -2)"))
  58. assert.is_nil(core.string_to_pos("asd, 5, -2)"))
  59. end)
  60. it("to string", function()
  61. assert.equal("(10.1,5.2,-2.3)", core.pos_to_string({ x = 10.1, y = 5.2, z = -2.3}))
  62. end)
  63. end)
  64. describe("area parsing", function()
  65. describe("valid inputs", function()
  66. it("accepts absolute numbers", function()
  67. local p1, p2 = core.string_to_area("(10.0, 5, -2) ( 30.2 4 -12.53)")
  68. assert(p1.x == 10 and p1.y == 5 and p1.z == -2)
  69. assert(p2.x == 30.2 and p2.y == 4 and p2.z == -12.53)
  70. end)
  71. it("accepts relative numbers", function()
  72. local p1, p2 = core.string_to_area("(1,2,3) (~5,~-5,~)", {x=10,y=10,z=10})
  73. assert(type(p1) == "table" and type(p2) == "table")
  74. assert(p1.x == 1 and p1.y == 2 and p1.z == 3)
  75. assert(p2.x == 15 and p2.y == 5 and p2.z == 10)
  76. p1, p2 = core.string_to_area("(1 2 3) (~5 ~-5 ~)", {x=10,y=10,z=10})
  77. assert(type(p1) == "table" and type(p2) == "table")
  78. assert(p1.x == 1 and p1.y == 2 and p1.z == 3)
  79. assert(p2.x == 15 and p2.y == 5 and p2.z == 10)
  80. end)
  81. end)
  82. describe("invalid inputs", function()
  83. it("rejects too few numbers", function()
  84. local p1, p2 = core.string_to_area("(1,1) (1,1,1,1)", {x=1,y=1,z=1})
  85. assert(p1 == nil and p2 == nil)
  86. end)
  87. it("rejects too many numbers", function()
  88. local p1, p2 = core.string_to_area("(1,1,1,1) (1,1,1,1)", {x=1,y=1,z=1})
  89. assert(p1 == nil and p2 == nil)
  90. end)
  91. it("rejects nan & inf", function()
  92. local p1, p2 = core.string_to_area("(1,1,1) (1,1,nan)", {x=1,y=1,z=1})
  93. assert(p1 == nil and p2 == nil)
  94. p1, p2 = core.string_to_area("(1,1,1) (1,1,~nan)", {x=1,y=1,z=1})
  95. assert(p1 == nil and p2 == nil)
  96. p1, p2 = core.string_to_area("(1,1,1) (1,~nan,1)", {x=1,y=1,z=1})
  97. assert(p1 == nil and p2 == nil)
  98. p1, p2 = core.string_to_area("(1,1,1) (1,1,inf)", {x=1,y=1,z=1})
  99. assert(p1 == nil and p2 == nil)
  100. p1, p2 = core.string_to_area("(1,1,1) (1,1,~inf)", {x=1,y=1,z=1})
  101. assert(p1 == nil and p2 == nil)
  102. p1, p2 = core.string_to_area("(1,1,1) (1,~inf,1)", {x=1,y=1,z=1})
  103. assert(p1 == nil and p2 == nil)
  104. p1, p2 = core.string_to_area("(nan,nan,nan) (nan,nan,nan)", {x=1,y=1,z=1})
  105. assert(p1 == nil and p2 == nil)
  106. p1, p2 = core.string_to_area("(nan,nan,nan) (nan,nan,nan)")
  107. assert(p1 == nil and p2 == nil)
  108. p1, p2 = core.string_to_area("(inf,inf,inf) (-inf,-inf,-inf)", {x=1,y=1,z=1})
  109. assert(p1 == nil and p2 == nil)
  110. p1, p2 = core.string_to_area("(inf,inf,inf) (-inf,-inf,-inf)")
  111. assert(p1 == nil and p2 == nil)
  112. end)
  113. it("rejects words", function()
  114. local p1, p2 = core.string_to_area("bananas", {x=1,y=1,z=1})
  115. assert(p1 == nil and p2 == nil)
  116. p1, p2 = core.string_to_area("bananas", "foobar")
  117. assert(p1 == nil and p2 == nil)
  118. p1, p2 = core.string_to_area("bananas")
  119. assert(p1 == nil and p2 == nil)
  120. p1, p2 = core.string_to_area("(bananas,bananas,bananas)")
  121. assert(p1 == nil and p2 == nil)
  122. p1, p2 = core.string_to_area("(bananas,bananas,bananas) (bananas,bananas,bananas)")
  123. assert(p1 == nil and p2 == nil)
  124. end)
  125. it("requires parenthesis & valid numbers", function()
  126. local p1, p2 = core.string_to_area("(10.0, 5, -2 30.2, 4, -12.53")
  127. assert(p1 == nil and p2 == nil)
  128. p1, p2 = core.string_to_area("(10.0, 5,) -2 fgdf2, 4, -12.53")
  129. assert(p1 == nil and p2 == nil)
  130. end)
  131. end)
  132. end)
  133. describe("table", function()
  134. it("indexof()", function()
  135. assert.equal(1, table.indexof({"foo", "bar"}, "foo"))
  136. assert.equal(-1, table.indexof({"foo", "bar"}, "baz"))
  137. assert.equal(-1, table.indexof({[2] = "foo", [3] = "bar"}, "foo"))
  138. assert.equal(-1, table.indexof({[1] = "foo", [3] = "bar"}, "bar"))
  139. end)
  140. it("keyof()", function()
  141. assert.equal("a", table.keyof({a = "foo", b = "bar"}, "foo"))
  142. assert.equal(nil, table.keyof({a = "foo", b = "bar"}, "baz"))
  143. assert.equal(1, table.keyof({"foo", "bar"}, "foo"))
  144. assert.equal(2, table.keyof({[2] = "foo", [3] = "bar"}, "foo"))
  145. assert.equal(3, table.keyof({[1] = "foo", [3] = "bar"}, "bar"))
  146. end)
  147. describe("copy()", function()
  148. it("strips metatables", function()
  149. local v = vector.new(1, 2, 3)
  150. local w = table.copy(v)
  151. assert.are_not.equal(v, w)
  152. assert.same(v, w)
  153. assert.equal(nil, getmetatable(w))
  154. end)
  155. it("preserves referential structure", function()
  156. local t = {{}, {}}
  157. t[1][1] = t[2]
  158. t[2][1] = t[1]
  159. local copy = table.copy(t)
  160. assert.same(t, copy)
  161. assert.equal(copy[1][1], copy[2])
  162. assert.equal(copy[2][1], copy[1])
  163. end)
  164. end)
  165. describe("copy_with_metatables()", function()
  166. it("preserves metatables", function()
  167. local v = vector.new(1, 2, 3)
  168. local w = table.copy_with_metatables(v)
  169. assert.equal(getmetatable(v), getmetatable(w))
  170. assert(vector.check(w))
  171. assert.equal(v, w) -- vector overrides ==
  172. end)
  173. end)
  174. end)
  175. describe("formspec_escape", function()
  176. it("escapes", function()
  177. assert.equal(nil, core.formspec_escape(nil))
  178. assert.equal("", core.formspec_escape(""))
  179. assert.equal("\\[Hello\\\\\\[", core.formspec_escape("[Hello\\["))
  180. end)
  181. end)
  182. describe("math", function()
  183. it("round()", function()
  184. assert.equal(0, math.round(0))
  185. assert.equal(10, math.round(10.3))
  186. assert.equal(11, math.round(10.5))
  187. assert.equal(11, math.round(10.7))
  188. assert.equal(-10, math.round(-10.3))
  189. assert.equal(-11, math.round(-10.5))
  190. assert.equal(-11, math.round(-10.7))
  191. assert.equal(0, math.round(0.49999999999999994))
  192. assert.equal(0, math.round(-0.49999999999999994))
  193. end)
  194. end)
  195. describe("dump", function()
  196. local function test_expression(expr)
  197. local chunk = assert(loadstring("return " .. expr))
  198. local refs = {}
  199. setfenv(chunk, {
  200. setref = function(id)
  201. refs[id] = {}
  202. return function(fields)
  203. for k, v in pairs(fields) do
  204. refs[id][k] = v
  205. end
  206. return refs[id]
  207. end
  208. end,
  209. getref = function(id)
  210. return assert(refs[id])
  211. end,
  212. })
  213. assert.equal(expr, dump(chunk()))
  214. end
  215. it("nil", function()
  216. test_expression("nil")
  217. end)
  218. it("booleans", function()
  219. test_expression("false")
  220. test_expression("true")
  221. end)
  222. describe("numbers", function()
  223. it("formats integers nicely", function()
  224. test_expression("42")
  225. end)
  226. it("avoids misleading rounding", function()
  227. test_expression("0.3")
  228. assert.equal("0.30000000000000004", dump(0.1 + 0.2))
  229. end)
  230. end)
  231. it("strings", function()
  232. test_expression('"hello world"')
  233. test_expression([["hello \"world\""]])
  234. end)
  235. describe("tables", function()
  236. it("empty", function()
  237. test_expression("{}")
  238. end)
  239. it("lists", function()
  240. test_expression([[
  241. {
  242. false,
  243. true,
  244. "foo",
  245. 1,
  246. 2,
  247. }]])
  248. end)
  249. it("number keys", function()
  250. test_expression([[
  251. {
  252. [0.5] = false,
  253. [1.5] = true,
  254. [2.5] = "foo",
  255. }]])
  256. end)
  257. it("dicts", function()
  258. test_expression([[{
  259. a = 1,
  260. b = 2,
  261. c = 3,
  262. }]])
  263. end)
  264. it("mixed", function()
  265. test_expression([[{
  266. a = 1,
  267. b = 2,
  268. c = 3,
  269. ["d e"] = true,
  270. "foo",
  271. "bar",
  272. }]])
  273. end)
  274. it("nested", function()
  275. test_expression([[{
  276. a = {
  277. 1,
  278. {},
  279. },
  280. b = "foo",
  281. c = {
  282. [0.5] = 0.1,
  283. [1.5] = 0.2,
  284. },
  285. }]])
  286. end)
  287. it("circular references", function()
  288. test_expression([[setref(1){
  289. child = {
  290. parent = getref(1),
  291. },
  292. other_child = {
  293. parent = getref(1),
  294. },
  295. }]])
  296. end)
  297. it("supports variable indent", function()
  298. assert.equal('{1,2,3,{foo = "bar",},}', dump({1, 2, 3, {foo = "bar"}}, ""))
  299. assert.equal('{\n "x",\n "y",\n}', dump({"x", "y"}, " "))
  300. end)
  301. end)
  302. end)