Fix tabheader parsing and use busted for tests
This commit is contained in:
parent
68712195f3
commit
c7629b718d
|
@ -4,8 +4,17 @@ jobs:
|
|||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- uses: actions/checkout@v3
|
||||
- name: lint
|
||||
uses: Roang-zero1/factorio-mod-luacheck@master
|
||||
with:
|
||||
luacheckrc_url: ""
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Run unit tests
|
||||
uses: lunarmodules/busted@v2.1.2
|
||||
with:
|
||||
args: --verbose test.lua
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
__pycache__/
|
||||
test.lua
|
||||
|
|
|
@ -48,6 +48,10 @@ all attributes are lowercase.
|
|||
While I try to reduce backwards incompatibilities, sometimes they are necessary
|
||||
to either fix bugs in formspec_ast or for implementing new formspec features.
|
||||
|
||||
#### April 2023
|
||||
|
||||
- The `current_tab` value of dropdowns is now parsed as a number.
|
||||
|
||||
#### February 2022
|
||||
|
||||
- The value of scrollbars is now a number instead of a string.
|
||||
|
|
|
@ -54,7 +54,7 @@ a[47] = {{{"listelems", "string"}, "..."}}
|
|||
a[48] = {"selected_idx", "number"}
|
||||
a[49] = {"transparent", "boolean"}
|
||||
a[50] = {{{"captions", "string"}, "..."}}
|
||||
a[51] = {"current_tab", "string"}
|
||||
a[51] = {"current_tab", "number"}
|
||||
a[52] = {"draw_border", "boolean"}
|
||||
a[53] = {{{"items", "string"}, "..."}}
|
||||
a[54] = {"index_event", "boolean"}
|
||||
|
@ -64,4 +64,4 @@ a[57] = {{a[56]}}
|
|||
a[58] = {{"props", "table"}, "..."}
|
||||
a[59] = {a[26]}
|
||||
a[60] = {{{{{"selectors", "string"}, "..."}}, a[58]}, {a[59], a[58]}}
|
||||
return {["formspec_version"] = {{{"version", "number"}}}, ["size"] = {{a[3]}, {{a[1], a[2], {"fixed_size", "boolean"}}}}, ["position"] = a[5], ["anchor"] = a[5], ["padding"] = a[5], ["no_prepend"] = a[7], ["real_coordinates"] = {{{"bool", "boolean"}}}, ["container"] = a[5], ["container_end"] = a[7], ["scroll_container"] = {{a[4], a[3], a[8], a[9], {"scroll_factor", "number"}}, {a[4], a[3], a[8], a[9]}}, ["scroll_container_end"] = a[7], ["list"] = {{a[10], a[11], a[4], a[3], {"starting_item_index", "number"}}, {a[10], a[11], a[4], a[3]}}, ["listring"] = {{a[10], a[11]}, a[6]}, ["listcolors"] = {{a[12], a[13], a[14], {"tooltip_bgcolor", "string"}, {"tooltip_fontcolor", "string"}}, {a[12], a[13], a[14]}, {a[12], a[13]}}, ["tooltip"] = {{a[4], a[3], a[15], a[16], a[17]}, {a[4], a[3], a[15], a[16]}, {a[18], a[15], a[16], a[17]}, {a[4], a[3], a[15]}, {a[18], a[15], a[16]}, {a[18], a[15]}}, ["image"] = {{a[4], a[3], a[19], a[22]}, {a[4], a[3], a[19], a[23]}, {a[4], a[3], a[19], a[24]}, a[25]}, ["animated_image"] = {{a[4], a[3], a[26], a[19], a[27], a[28], a[29], a[22]}, {a[4], a[3], a[26], a[19], a[27], a[28], a[29], a[23]}, {a[4], a[3], a[26], a[19], a[27], a[28], a[29], a[24]}, {a[4], a[3], a[26], a[19], a[27], a[28], a[29]}, {a[4], a[3], a[26], a[19], a[27], a[28]}}, ["model"] = {{a[4], a[3], a[26], a[30], a[31], a[32], a[33], a[34], a[35], {"animation_speed", "number"}}, {a[4], a[3], a[26], a[30], a[31], a[32], a[33], a[34], a[35]}, {a[4], a[3], a[26], a[30], a[31], a[32], a[33], a[34]}, {a[4], a[3], a[26], a[30], a[31], a[32], a[33]}, {a[4], a[3], a[26], a[30], a[31], a[32]}, {a[4], a[3], a[26], a[30], a[31]}}, ["item_image"] = {{a[4], a[3], a[36]}}, ["bgcolor"] = {{a[16], a[37], {"fbgcolor", "string"}}, {a[16], a[37]}, {a[16]}}, ["background"] = {{a[4], a[3], a[19], a[38]}, a[25]}, ["background9"] = {{a[4], a[3], a[19], a[38], a[22]}, {a[4], a[3], a[19], a[38], a[23]}, {a[4], a[3], a[19], a[38], a[24]}}, ["pwdfield"] = a[40], ["field"] = {a[42], {a[26], a[39], a[41]}}, ["field_close_on_enter"] = {{a[26], {"close_on_enter", "boolean"}}}, ["textarea"] = {a[42]}, ["label"] = a[43], ["hypertext"] = {{a[4], a[3], a[26], {"text", "string"}}}, ["vertlabel"] = a[43], ["button"] = a[40], ["image_button"] = a[46], ["item_image_button"] = {{a[4], a[3], a[36], a[26], a[39]}}, ["button_exit"] = a[40], ["image_button_exit"] = a[46], ["textlist"] = {{a[4], a[3], a[26], a[47], a[48], a[49]}, {a[4], a[3], a[26], a[47], a[48]}, {a[4], a[3], a[26], a[47]}}, ["tabheader"] = {{a[4], a[2], a[26], a[50], a[51], a[49], a[52]}, {a[4], a[3], a[26], a[50], a[51], a[49], a[52]}, {a[4], a[26], a[50], a[51], a[49], a[52]}, {a[4], a[2], a[26], a[50], a[51], a[49]}, {a[4], a[3], a[26], a[50], a[51], a[49]}, {a[4], a[26], a[50], a[51], a[49]}, {a[4], a[2], a[26], a[50], a[51]}, {a[4], a[3], a[26], a[50], a[51]}, {a[4], a[26], a[50], a[51]}}, ["box"] = {{a[4], a[3], {"color", "string"}}}, ["dropdown"] = {{a[4], a[3], a[26], a[53], a[48], a[54]}, {a[4], a[1], a[26], a[53], a[48], a[54]}, {a[4], a[3], a[26], a[53], a[48]}, {a[4], a[1], a[26], a[53], a[48]}}, ["checkbox"] = {{a[4], a[26], a[39], {"selected", "boolean"}}, {a[4], a[26], a[39]}}, ["scrollbar"] = {{a[4], a[3], a[9], a[26], a[55], {{"scrollbar_bg", "string"}, {"slider", "string"}, {"arrow_up", "string"}, {"arrow_down", "string"}}}, {a[4], a[3], a[9], a[26], a[55]}}, ["scrollbaroptions"] = a[57], ["table"] = {{a[4], a[3], a[26], {{{"cells", "string"}, "..."}}, a[48]}}, ["tableoptions"] = a[57], ["tablecolumns"] = {{{{{"type", "string"}, a[56]}, "..."}}}, ["style"] = a[60], ["style_type"] = a[60], ["set_focus"] = {{a[26], {"force", "boolean"}}, a[59]}}
|
||||
return {["formspec_version"] = {{{"version", "number"}}}, ["size"] = {{a[3]}, {{a[1], a[2], {"fixed_size", "boolean"}}}}, ["position"] = a[5], ["anchor"] = a[5], ["padding"] = a[5], ["no_prepend"] = a[7], ["real_coordinates"] = {{{"bool", "boolean"}}}, ["container"] = a[5], ["container_end"] = a[7], ["scroll_container"] = {{a[4], a[3], a[8], a[9], {"scroll_factor", "number"}}, {a[4], a[3], a[8], a[9]}}, ["scroll_container_end"] = a[7], ["list"] = {{a[10], a[11], a[4], a[3], {"starting_item_index", "number"}}, {a[10], a[11], a[4], a[3]}}, ["listring"] = {{a[10], a[11]}, a[6]}, ["listcolors"] = {{a[12], a[13], a[14], {"tooltip_bgcolor", "string"}, {"tooltip_fontcolor", "string"}}, {a[12], a[13], a[14]}, {a[12], a[13]}}, ["tooltip"] = {{a[4], a[3], a[15], a[16], a[17]}, {a[4], a[3], a[15], a[16]}, {a[18], a[15], a[16], a[17]}, {a[4], a[3], a[15]}, {a[18], a[15], a[16]}, {a[18], a[15]}}, ["image"] = {{a[4], a[3], a[19], a[22]}, {a[4], a[3], a[19], a[23]}, {a[4], a[3], a[19], a[24]}, a[25]}, ["animated_image"] = {{a[4], a[3], a[26], a[19], a[27], a[28], a[29], a[22]}, {a[4], a[3], a[26], a[19], a[27], a[28], a[29], a[23]}, {a[4], a[3], a[26], a[19], a[27], a[28], a[29], a[24]}, {a[4], a[3], a[26], a[19], a[27], a[28], a[29]}, {a[4], a[3], a[26], a[19], a[27], a[28]}}, ["model"] = {{a[4], a[3], a[26], a[30], a[31], a[32], a[33], a[34], a[35], {"animation_speed", "number"}}, {a[4], a[3], a[26], a[30], a[31], a[32], a[33], a[34], a[35]}, {a[4], a[3], a[26], a[30], a[31], a[32], a[33], a[34]}, {a[4], a[3], a[26], a[30], a[31], a[32], a[33]}, {a[4], a[3], a[26], a[30], a[31], a[32]}, {a[4], a[3], a[26], a[30], a[31]}}, ["item_image"] = {{a[4], a[3], a[36]}}, ["bgcolor"] = {{a[16], a[37], {"fbgcolor", "string"}}, {a[16], a[37]}, {a[16]}}, ["background"] = {{a[4], a[3], a[19], a[38]}, a[25]}, ["background9"] = {{a[4], a[3], a[19], a[38], a[22]}, {a[4], a[3], a[19], a[38], a[23]}, {a[4], a[3], a[19], a[38], a[24]}}, ["pwdfield"] = a[40], ["field"] = {a[42], {a[26], a[39], a[41]}}, ["field_close_on_enter"] = {{a[26], {"close_on_enter", "boolean"}}}, ["textarea"] = {a[42]}, ["label"] = a[43], ["hypertext"] = {{a[4], a[3], a[26], {"text", "string"}}}, ["vertlabel"] = a[43], ["button"] = a[40], ["image_button"] = a[46], ["item_image_button"] = {{a[4], a[3], a[36], a[26], a[39]}}, ["button_exit"] = a[40], ["image_button_exit"] = a[46], ["textlist"] = {{a[4], a[3], a[26], a[47], a[48], a[49]}, {a[4], a[3], a[26], a[47], a[48]}, {a[4], a[3], a[26], a[47]}}, ["tabheader"] = {{a[4], a[2], a[26], a[50], a[51], a[49], a[52]}, {a[4], a[3], a[26], a[50], a[51], a[49], a[52]}, {a[4], a[26], a[50], a[51], a[49], a[52]}, {a[4], a[26], a[50], a[51]}}, ["box"] = {{a[4], a[3], {"color", "string"}}}, ["dropdown"] = {{a[4], a[3], a[26], a[53], a[48], a[54]}, {a[4], a[1], a[26], a[53], a[48], a[54]}, {a[4], a[3], a[26], a[53], a[48]}, {a[4], a[1], a[26], a[53], a[48]}}, ["checkbox"] = {{a[4], a[26], a[39], {"selected", "boolean"}}, {a[4], a[26], a[39]}}, ["scrollbar"] = {{a[4], a[3], a[9], a[26], a[55], {{"scrollbar_bg", "string"}, {"slider", "string"}, {"arrow_up", "string"}, {"arrow_down", "string"}}}, {a[4], a[3], a[9], a[26], a[55]}}, ["scrollbaroptions"] = a[57], ["table"] = {{a[4], a[3], a[26], {{{"cells", "string"}, "..."}}, a[48]}}, ["tableoptions"] = a[57], ["tablecolumns"] = {{{{{"type", "string"}, a[56]}, "..."}}}, ["style"] = a[60], ["style_type"] = a[60], ["set_focus"] = {{a[26], {"force", "boolean"}}, a[59]}}
|
||||
|
|
|
@ -483,7 +483,7 @@ tabheader:
|
|||
- [name, string]
|
||||
- - - [captions, string]
|
||||
- '...'
|
||||
- [current_tab, string]
|
||||
- [current_tab, number]
|
||||
- [transparent, boolean]
|
||||
- [draw_border, boolean]
|
||||
- - - [x, number]
|
||||
|
@ -493,7 +493,7 @@ tabheader:
|
|||
- [name, string]
|
||||
- - - [captions, string]
|
||||
- '...'
|
||||
- [current_tab, string]
|
||||
- [current_tab, number]
|
||||
- [transparent, boolean]
|
||||
- [draw_border, boolean]
|
||||
- - - [x, number]
|
||||
|
@ -501,54 +501,15 @@ tabheader:
|
|||
- [name, string]
|
||||
- - - [captions, string]
|
||||
- '...'
|
||||
- [current_tab, string]
|
||||
- [current_tab, number]
|
||||
- [transparent, boolean]
|
||||
- [draw_border, boolean]
|
||||
- - - [x, number]
|
||||
- [y, number]
|
||||
- [h, number]
|
||||
- [name, string]
|
||||
- - - [captions, string]
|
||||
- '...'
|
||||
- [current_tab, string]
|
||||
- [transparent, boolean]
|
||||
- - - [x, number]
|
||||
- [y, number]
|
||||
- - [w, number]
|
||||
- [h, number]
|
||||
- [name, string]
|
||||
- - - [captions, string]
|
||||
- '...'
|
||||
- [current_tab, string]
|
||||
- [transparent, boolean]
|
||||
- - - [x, number]
|
||||
- [y, number]
|
||||
- [name, string]
|
||||
- - - [captions, string]
|
||||
- '...'
|
||||
- [current_tab, string]
|
||||
- [transparent, boolean]
|
||||
- - - [x, number]
|
||||
- [y, number]
|
||||
- [h, number]
|
||||
- [name, string]
|
||||
- - - [captions, string]
|
||||
- '...'
|
||||
- [current_tab, string]
|
||||
- - - [x, number]
|
||||
- [y, number]
|
||||
- - [w, number]
|
||||
- [h, number]
|
||||
- [name, string]
|
||||
- - - [captions, string]
|
||||
- '...'
|
||||
- [current_tab, string]
|
||||
- - - [x, number]
|
||||
- [y, number]
|
||||
- [name, string]
|
||||
- - - [captions, string]
|
||||
- '...'
|
||||
- [current_tab, string]
|
||||
- [current_tab, number]
|
||||
table:
|
||||
- - - [x, number]
|
||||
- [y, number]
|
||||
|
|
|
@ -14,7 +14,7 @@ def _make_known(**kwargs):
|
|||
return known
|
||||
|
||||
_known = _make_known(
|
||||
number=('x', 'y', 'w', 'h', 'selected_idx', 'version',
|
||||
number=('x', 'y', 'w', 'h', 'selected_idx', 'version', 'current_tab',
|
||||
'starting_item_index', 'scroll_factor', 'frame_count',
|
||||
'frame_duration', 'frame_start', 'animation_speed', 'value'),
|
||||
boolean=('auto_clip', 'fixed_size', 'transparent', 'draw_border', 'bool',
|
||||
|
@ -193,6 +193,19 @@ def _image_button_hook(params):
|
|||
params.append(('pressed_texture_name', 'string'))
|
||||
yield params
|
||||
|
||||
|
||||
# Work around tabheader's documentation
|
||||
@hook('tabheader')
|
||||
def _tabheader_hook(params):
|
||||
yield params
|
||||
if len(params) == 6:
|
||||
assert params[4:] == [
|
||||
('transparent', 'boolean'),
|
||||
('draw_border', 'boolean'),
|
||||
]
|
||||
yield params[:4]
|
||||
|
||||
|
||||
# Support MultiCraft's non-standard scrollbar styling
|
||||
# WARNING: This may be removed or broken without notice
|
||||
@hook('scrollbar')
|
||||
|
@ -283,7 +296,7 @@ def parse(data):
|
|||
|
||||
return res
|
||||
|
||||
URL = 'https://github.com/minetest/minetest/raw/master/doc/lua_api.txt'
|
||||
URL = 'https://github.com/minetest/minetest/raw/master/doc/lua_api.md'
|
||||
def fetch_and_parse(*, url=URL):
|
||||
with urllib.request.urlopen(url) as f:
|
||||
raw = f.read()
|
||||
|
|
|
@ -0,0 +1,619 @@
|
|||
dofile('init.lua')
|
||||
|
||||
local function test_parse(fs, expected_tree)
|
||||
-- Make single elements lists and add formspec_version
|
||||
if expected_tree.type then
|
||||
expected_tree = {expected_tree}
|
||||
end
|
||||
if not expected_tree.formspec_version then
|
||||
expected_tree.formspec_version = 1
|
||||
end
|
||||
|
||||
local tree = assert(formspec_ast.parse(fs))
|
||||
assert.same(tree, expected_tree)
|
||||
end
|
||||
|
||||
local function test_parse_unparse(fs, expected_tree)
|
||||
test_parse(fs, expected_tree)
|
||||
local unparsed_fs = assert(formspec_ast.unparse(expected_tree))
|
||||
assert.equals(fs, unparsed_fs)
|
||||
end
|
||||
|
||||
it("can parse complex escapes", function()
|
||||
test_parse_unparse([=[label[123,456;yay abc def\, ghi\; jkl mno \]\\]]=], {
|
||||
formspec_version = 1,
|
||||
{
|
||||
type = 'label',
|
||||
x = 123,
|
||||
y = 456,
|
||||
label = 'yay abc def, ghi; jkl mno ]\\'
|
||||
}
|
||||
})
|
||||
end)
|
||||
|
||||
it("can round-trip most elements", function()
|
||||
local fs = [[
|
||||
formspec_version[2]
|
||||
size[5,2]
|
||||
padding[1,2]
|
||||
no_prepend[]
|
||||
container[1,1]
|
||||
label[0,0;Containers are fun\]\\]
|
||||
container[-1,-1]
|
||||
button[0.5,0;4,1;name;Label]
|
||||
container_end[]
|
||||
label[0,1;Nested containers work too.]
|
||||
scroll_container[0,2;1,1;scrollbar;vertical]
|
||||
button[0.5,0;4,1;name;Label]
|
||||
scroll_container_end[]
|
||||
container_end[]
|
||||
image[0,1;1,1;air.png]
|
||||
set_focus[name;true]
|
||||
dropdown[0,0;1;test;abc,def,ghi,jkl;2]
|
||||
dropdown[0,0;1;test;abc,def,ghi,jkl;2;true]
|
||||
field_close_on_enter[my-field;false]
|
||||
bgcolor[blue]
|
||||
bgcolor[blue;true]
|
||||
bgcolor[blue;both;green]
|
||||
tooltip[1,2;3,4;text]
|
||||
tooltip[elem;text;bgcolor]
|
||||
background9[1,2;3,4;bg.png;false;5]
|
||||
background9[1,2;3,4;bg.png;false;5,6]
|
||||
background9[1,2;3,4;bg.png;false;5,6,7,8]
|
||||
tablecolumns[text;image;color,option=value;tree]
|
||||
list[test;test2;1,2;3,4;5]
|
||||
list[test6;test7;8,9;10,11]
|
||||
image_button[1,2;3,4;img.png;name;label]
|
||||
image_button[1,2;3,4;img.png;name;label;false;true]
|
||||
image_button[1,2;3,4;img.png;name;label;true;false;img2.png]
|
||||
image_button_exit[1,2;3,4;img.png;name;label]
|
||||
image_button_exit[1,2;3,4;img.png;name;label;false;true]
|
||||
image_button_exit[1,2;3,4;img.png;name;label;true;false;img2.png]
|
||||
image[1,2;3,4;air.png;5]
|
||||
image[1,2;3,4;air.png;5,6]
|
||||
image[1,2;3,4;air.png;5,6,7,8]
|
||||
]]
|
||||
fs = ('\n' .. fs):gsub('\n[ \n]*', '')
|
||||
|
||||
test_parse_unparse(fs, {
|
||||
formspec_version = 2,
|
||||
{
|
||||
type = "size",
|
||||
w = 5,
|
||||
h = 2,
|
||||
},
|
||||
{
|
||||
type = "padding",
|
||||
x = 1,
|
||||
y = 2,
|
||||
},
|
||||
{
|
||||
type = "no_prepend"
|
||||
},
|
||||
{
|
||||
type = "container",
|
||||
x = 1,
|
||||
y = 1,
|
||||
{
|
||||
type = "label",
|
||||
x = 0,
|
||||
y = 0,
|
||||
label = "Containers are fun]\\",
|
||||
},
|
||||
{
|
||||
type = "container",
|
||||
x = -1,
|
||||
y = -1,
|
||||
{
|
||||
type = "button",
|
||||
x = 0.5,
|
||||
y = 0,
|
||||
w = 4,
|
||||
h = 1,
|
||||
name = "name",
|
||||
label = "Label",
|
||||
},
|
||||
},
|
||||
{
|
||||
type = "label",
|
||||
x = 0,
|
||||
y = 1,
|
||||
label = "Nested containers work too.",
|
||||
},
|
||||
{
|
||||
type = "scroll_container",
|
||||
x = 0,
|
||||
y = 2,
|
||||
w = 1,
|
||||
h = 1,
|
||||
scrollbar_name = "scrollbar",
|
||||
orientation = "vertical",
|
||||
-- scroll_factor = nil,
|
||||
{
|
||||
h = 1,
|
||||
y = 0,
|
||||
label = "Label",
|
||||
w = 4,
|
||||
name = "name",
|
||||
x = 0.5,
|
||||
type = "button"
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type = "image",
|
||||
x = 0,
|
||||
y = 1,
|
||||
w = 1,
|
||||
h = 1,
|
||||
texture_name = "air.png",
|
||||
},
|
||||
{
|
||||
type = "set_focus",
|
||||
name = "name",
|
||||
force = true,
|
||||
},
|
||||
{
|
||||
type = "dropdown",
|
||||
x = 0,
|
||||
y = 0,
|
||||
w = 1,
|
||||
name = "test",
|
||||
items = {"abc", "def", "ghi", "jkl"},
|
||||
selected_idx = 2,
|
||||
},
|
||||
{
|
||||
type = "dropdown",
|
||||
x = 0,
|
||||
y = 0,
|
||||
w = 1,
|
||||
name = "test",
|
||||
items = {"abc", "def", "ghi", "jkl"},
|
||||
selected_idx = 2,
|
||||
index_event = true,
|
||||
},
|
||||
{
|
||||
type = "field_close_on_enter",
|
||||
name = "my-field",
|
||||
close_on_enter = false,
|
||||
},
|
||||
{
|
||||
type = "bgcolor",
|
||||
bgcolor = "blue",
|
||||
},
|
||||
{
|
||||
type = "bgcolor",
|
||||
bgcolor = "blue",
|
||||
fullscreen = true,
|
||||
},
|
||||
{
|
||||
type = "bgcolor",
|
||||
bgcolor = "blue",
|
||||
fullscreen = "both",
|
||||
fbgcolor = "green",
|
||||
},
|
||||
{
|
||||
type = "tooltip",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
tooltip_text = "text",
|
||||
},
|
||||
{
|
||||
type = "tooltip",
|
||||
gui_element_name = "elem",
|
||||
tooltip_text = "text",
|
||||
bgcolor = "bgcolor",
|
||||
},
|
||||
{
|
||||
type = "background9",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "bg.png",
|
||||
auto_clip = false,
|
||||
middle_x = 5,
|
||||
},
|
||||
{
|
||||
type = "background9",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "bg.png",
|
||||
auto_clip = false,
|
||||
middle_x = 5,
|
||||
middle_y = 6,
|
||||
},
|
||||
{
|
||||
type = "background9",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "bg.png",
|
||||
auto_clip = false,
|
||||
middle_x = 5,
|
||||
middle_y = 6,
|
||||
middle_x2 = 7,
|
||||
middle_y2 = 8,
|
||||
},
|
||||
{
|
||||
type = "tablecolumns",
|
||||
tablecolumns = {
|
||||
{type = "text", opts = {}},
|
||||
{type = "image", opts = {}},
|
||||
{type = "color", opts = {option = "value"}},
|
||||
{type = "tree", opts = {}},
|
||||
},
|
||||
},
|
||||
{
|
||||
type = "list",
|
||||
inventory_location = "test",
|
||||
list_name = "test2",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
starting_item_index = 5,
|
||||
},
|
||||
{
|
||||
type = "list",
|
||||
inventory_location = "test6",
|
||||
list_name = "test7",
|
||||
x = 8,
|
||||
y = 9,
|
||||
w = 10,
|
||||
h = 11,
|
||||
},
|
||||
{
|
||||
type = "image_button",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "img.png",
|
||||
name = "name",
|
||||
label = "label",
|
||||
},
|
||||
{
|
||||
type = "image_button",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "img.png",
|
||||
name = "name",
|
||||
label = "label",
|
||||
noclip = false,
|
||||
drawborder = true,
|
||||
},
|
||||
{
|
||||
type = "image_button",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "img.png",
|
||||
name = "name",
|
||||
label = "label",
|
||||
noclip = true,
|
||||
drawborder = false,
|
||||
pressed_texture_name = "img2.png",
|
||||
},
|
||||
{
|
||||
type = "image_button_exit",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "img.png",
|
||||
name = "name",
|
||||
label = "label",
|
||||
},
|
||||
{
|
||||
type = "image_button_exit",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "img.png",
|
||||
name = "name",
|
||||
label = "label",
|
||||
noclip = false,
|
||||
drawborder = true,
|
||||
},
|
||||
{
|
||||
type = "image_button_exit",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "img.png",
|
||||
name = "name",
|
||||
label = "label",
|
||||
noclip = true,
|
||||
drawborder = false,
|
||||
pressed_texture_name = "img2.png",
|
||||
},
|
||||
{
|
||||
type = "image",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "air.png",
|
||||
middle_x = 5,
|
||||
},
|
||||
{
|
||||
type = "image",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "air.png",
|
||||
middle_x = 5,
|
||||
middle_y = 6,
|
||||
},
|
||||
{
|
||||
type = "image",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "air.png",
|
||||
middle_x = 5,
|
||||
middle_y = 6,
|
||||
middle_x2 = 7,
|
||||
middle_y2 = 8,
|
||||
},
|
||||
})
|
||||
end)
|
||||
|
||||
local function remove_trailing_params(elem_s, elem, ...)
|
||||
local res = {}
|
||||
local strings = {}
|
||||
local optional_params = {...}
|
||||
for i = #optional_params, 1, -1 do
|
||||
local p = optional_params[i]
|
||||
local no_copy = {}
|
||||
if type(p) == "table" then
|
||||
for _, param in ipairs(p) do
|
||||
no_copy[param] = true
|
||||
end
|
||||
else
|
||||
no_copy[p] = true
|
||||
end
|
||||
|
||||
res[i] = elem
|
||||
strings[i] = elem_s
|
||||
elem_s = elem_s:gsub(";[^;]+%]$", "]")
|
||||
local old_elem = elem
|
||||
elem = {}
|
||||
for k, v in pairs(old_elem) do
|
||||
if not no_copy[k] then
|
||||
elem[k] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
return table.concat(strings, ""), res
|
||||
end
|
||||
|
||||
it("can parse model[]", function()
|
||||
test_parse_unparse(remove_trailing_params(
|
||||
"model[1,2;3,4;abc;def;ghi,jkl;5,6;true;false;7,8;9]",
|
||||
{
|
||||
type = "model",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
name = "abc",
|
||||
mesh = "def",
|
||||
textures = {"ghi", "jkl"},
|
||||
rotation_x = 5,
|
||||
rotation_y = 6,
|
||||
continuous = true,
|
||||
mouse_control = false,
|
||||
frame_loop_begin = 7,
|
||||
frame_loop_end = 8,
|
||||
animation_speed = 9
|
||||
},
|
||||
{"rotation_x", "rotation_y"}, "continuous", "mouse_control",
|
||||
{"frame_loop_begin", "frame_loop_end"}, "animation_speed"
|
||||
))
|
||||
end)
|
||||
|
||||
it("can round-trip style[]", function()
|
||||
local s = 'style[test1,test2;def=ghi]style_type[test;abc=def]'
|
||||
assert.equals(s, assert(formspec_ast.interpret(s)))
|
||||
test_parse('style[name,name2;bgcolor=blue;textcolor=yellow]', {
|
||||
type = "style",
|
||||
selectors = {
|
||||
"name",
|
||||
"name2",
|
||||
},
|
||||
props = {
|
||||
bgcolor = "blue",
|
||||
textcolor = "yellow",
|
||||
},
|
||||
})
|
||||
end)
|
||||
|
||||
-- Test item/items compatibility
|
||||
it("can parse dropdown[]", function()
|
||||
local expected = 'dropdown[0,0;1,2;test;abc,def,ghi,jkl;2;true]'
|
||||
assert.equals(
|
||||
expected,
|
||||
assert(formspec_ast.unparse({
|
||||
{
|
||||
type = "dropdown",
|
||||
x = 0,
|
||||
y = 0,
|
||||
w = 1,
|
||||
h = 2,
|
||||
name = "test",
|
||||
items = {"abc", "def", "ghi", "jkl"},
|
||||
selected_idx = 2,
|
||||
index_event = true,
|
||||
},
|
||||
}))
|
||||
)
|
||||
assert.equals(
|
||||
expected,
|
||||
assert(formspec_ast.unparse({
|
||||
{
|
||||
type = "dropdown",
|
||||
x = 0,
|
||||
y = 0,
|
||||
w = 1,
|
||||
h = 2,
|
||||
name = "test",
|
||||
item = {"abc", "def", "ghi", "jkl"},
|
||||
selected_idx = 2,
|
||||
index_event = true,
|
||||
},
|
||||
}))
|
||||
)
|
||||
end)
|
||||
|
||||
-- Ensure the style[] unparse compatibility works correctly
|
||||
it("can unparse style with name", function()
|
||||
local expected = 'style_type[test;abc=def]'
|
||||
assert.equals(
|
||||
expected,
|
||||
assert(formspec_ast.unparse({
|
||||
{
|
||||
type = 'style_type',
|
||||
name = 'test',
|
||||
props = {
|
||||
abc = 'def',
|
||||
},
|
||||
}
|
||||
}))
|
||||
)
|
||||
assert.equals(
|
||||
expected,
|
||||
assert(formspec_ast.unparse({
|
||||
{
|
||||
type = 'style_type',
|
||||
selectors = {
|
||||
'test',
|
||||
},
|
||||
props = {
|
||||
abc = 'def',
|
||||
},
|
||||
}
|
||||
}))
|
||||
)
|
||||
end)
|
||||
|
||||
-- Ensure flatten works correctly
|
||||
it("flattens formspecs correctly", function()
|
||||
assert.equals(
|
||||
'label[0,0;abc]label[2,2;def]scroll_container[1,1;2,2;test;vertical]' ..
|
||||
'image[1,1;1,1;def]scroll_container_end[]',
|
||||
formspec_ast.unparse(formspec_ast.flatten(assert(formspec_ast.parse([[
|
||||
label[0,0;abc]
|
||||
container[3,2]
|
||||
container[-1,0]
|
||||
label[0,0;def]
|
||||
container_end[]
|
||||
container_end[]
|
||||
scroll_container[1,1;2,2;test;vertical]
|
||||
image[1,1;1,1;def]
|
||||
scroll_container_end[]
|
||||
]]))))
|
||||
)
|
||||
end)
|
||||
|
||||
it("interprets invsize[] and escapes correctly", function()
|
||||
assert.equals(assert(formspec_ast.interpret('invsize[12,34]')), 'size[12,34]')
|
||||
|
||||
assert.equals(assert(formspec_ast.interpret('label[1,2;abc\\')),
|
||||
'label[1,2;abc]')
|
||||
assert.equals(assert(formspec_ast.interpret('label[1,2;abc\\\\')),
|
||||
'label[1,2;abc\\\\]')
|
||||
|
||||
assert.equals(formspec_ast.formspec_escape('label[1,2;abc\\def]'),
|
||||
'label\\[1\\,2\\;abc\\\\def\\]')
|
||||
end)
|
||||
|
||||
it("safe_interpret", function()
|
||||
assert.equals(
|
||||
formspec_ast.safe_interpret([[
|
||||
formspec_version[5.1]
|
||||
size[3,3]
|
||||
label[0,0;Hi]
|
||||
image[1,2;3,4;a^b\[c]
|
||||
formspec_ast:crash[]
|
||||
textlist[1,2;3,4;test;a,b,c]
|
||||
]]),
|
||||
'formspec_version[5]size[3,3]label[0,0;Hi]image[1,2;3,4;a^b]' ..
|
||||
'textlist[1,2;3,4;test;a,b,c]'
|
||||
)
|
||||
end)
|
||||
|
||||
it("can parse tabheader", function()
|
||||
local fs =
|
||||
"tabheader[1,2;name;a,b,c;1]" ..
|
||||
"tabheader[1,2;name;a,b,c;1;false;true]" ..
|
||||
|
||||
-- Width and height can only be specified if transparent and drawborder
|
||||
-- are specified
|
||||
"tabheader[1,2;3,4;name;a,b,c;1;false;true]" ..
|
||||
"tabheader[1,2;3;name;a,b,c;1;false;true]" ..
|
||||
"tabheader[1,2;3;name;a,b,c;1;;]"
|
||||
|
||||
test_parse_unparse(fs, {
|
||||
{
|
||||
type = "tabheader",
|
||||
x = 1, y = 2,
|
||||
name = "name",
|
||||
captions = {"a", "b", "c"},
|
||||
current_tab = 1
|
||||
},
|
||||
{
|
||||
type = "tabheader",
|
||||
x = 1, y = 2,
|
||||
name = "name",
|
||||
captions = {"a", "b", "c"},
|
||||
current_tab = 1,
|
||||
transparent = false,
|
||||
draw_border = true
|
||||
},
|
||||
{
|
||||
type = "tabheader",
|
||||
x = 1, y = 2, w = 3, h = 4,
|
||||
name = "name",
|
||||
captions = {"a", "b", "c"},
|
||||
current_tab = 1,
|
||||
transparent = false,
|
||||
draw_border = true
|
||||
},
|
||||
{
|
||||
type = "tabheader",
|
||||
x = 1, y = 2, h = 3,
|
||||
name = "name",
|
||||
captions = {"a", "b", "c"},
|
||||
current_tab = 1,
|
||||
transparent = false,
|
||||
draw_border = true
|
||||
},
|
||||
{
|
||||
type = "tabheader",
|
||||
x = 1, y = 2, h = 3,
|
||||
name = "name",
|
||||
captions = {"a", "b", "c"},
|
||||
current_tab = 1,
|
||||
},
|
||||
})
|
||||
end)
|
||||
|
||||
it("does not parse invalid tabheader elements", function()
|
||||
assert.is_nil(formspec_ast.parse("tabheader[1,2;name;a,b,c]"))
|
||||
assert.is_nil(formspec_ast.parse("tabheader[1,2;name;a,b,c;1;false]"))
|
||||
assert.is_nil(formspec_ast.parse("tabheader[1,2;3,4;name;a,b,c;1]"))
|
||||
end)
|
581
tests.lua
581
tests.lua
|
@ -1,581 +0,0 @@
|
|||
dofile('init.lua')
|
||||
|
||||
local function dump(obj)
|
||||
if type(obj) == 'string' then
|
||||
return ('%q'):format(obj)
|
||||
elseif type(obj) == 'table' then
|
||||
local entries = {}
|
||||
for k, v in pairs(obj) do
|
||||
if type(k) == 'string' and k:match('^[a-zA-Z_][a-zA-Z0-9_]*$') then
|
||||
entries[#entries + 1] = k .. ' = ' .. dump(v)
|
||||
else
|
||||
entries[#entries + 1] = '[' .. dump(k) .. '] = ' .. dump(v)
|
||||
end
|
||||
end
|
||||
table.sort(entries)
|
||||
return '{' .. table.concat(entries, ', ') .. '}'
|
||||
end
|
||||
return tostring(obj)
|
||||
end
|
||||
|
||||
local function equal(t1, t2)
|
||||
if type(t1) ~= 'table' or type(t2) ~= 'table' then
|
||||
return t1 == t2
|
||||
end
|
||||
for k, v in pairs(t1) do
|
||||
if not equal(v, t2[k]) then
|
||||
print(k, v, dump(t1), dump(t2))
|
||||
return false
|
||||
end
|
||||
end
|
||||
for k in pairs(t2) do
|
||||
if t1[k] == nil then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function assert_equal(obj1, ...)
|
||||
for i = 1, select('#', ...) do
|
||||
local objn = select(i, ...)
|
||||
if not equal(obj1, objn) then
|
||||
error(('%s ~= %s'):format(obj1, objn))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function test_parse(fs, expected_tree)
|
||||
-- Make single elements lists and add formspec_version
|
||||
if expected_tree.type then
|
||||
expected_tree = {expected_tree}
|
||||
end
|
||||
if not expected_tree.formspec_version then
|
||||
expected_tree.formspec_version = 1
|
||||
end
|
||||
|
||||
local tree = assert(formspec_ast.parse(fs))
|
||||
assert_equal(tree, expected_tree)
|
||||
end
|
||||
|
||||
local function test_parse_unparse(fs, expected_tree)
|
||||
test_parse(fs, expected_tree)
|
||||
local unparsed_fs = assert(formspec_ast.unparse(expected_tree))
|
||||
assert_equal(fs, unparsed_fs)
|
||||
end
|
||||
|
||||
test_parse_unparse([=[label[123,456;yay abc def\, ghi\; jkl mno \]\\]]=], {
|
||||
formspec_version = 1,
|
||||
{
|
||||
type = 'label',
|
||||
x = 123,
|
||||
y = 456,
|
||||
label = 'yay abc def, ghi; jkl mno ]\\'
|
||||
}
|
||||
})
|
||||
|
||||
local fs = [[
|
||||
formspec_version[2]
|
||||
size[5,2]
|
||||
padding[1,2]
|
||||
no_prepend[]
|
||||
container[1,1]
|
||||
label[0,0;Containers are fun\]\\]
|
||||
container[-1,-1]
|
||||
button[0.5,0;4,1;name;Label]
|
||||
container_end[]
|
||||
label[0,1;Nested containers work too.]
|
||||
scroll_container[0,2;1,1;scrollbar;vertical]
|
||||
button[0.5,0;4,1;name;Label]
|
||||
scroll_container_end[]
|
||||
container_end[]
|
||||
image[0,1;1,1;air.png]
|
||||
set_focus[name;true]
|
||||
dropdown[0,0;1;test;abc,def,ghi,jkl;2]
|
||||
dropdown[0,0;1;test;abc,def,ghi,jkl;2;true]
|
||||
field_close_on_enter[my-field;false]
|
||||
bgcolor[blue]
|
||||
bgcolor[blue;true]
|
||||
bgcolor[blue;both;green]
|
||||
tooltip[1,2;3,4;text]
|
||||
tooltip[elem;text;bgcolor]
|
||||
background9[1,2;3,4;bg.png;false;5]
|
||||
background9[1,2;3,4;bg.png;false;5,6]
|
||||
background9[1,2;3,4;bg.png;false;5,6,7,8]
|
||||
tablecolumns[text;image;color,option=value;tree]
|
||||
list[test;test2;1,2;3,4;5]
|
||||
list[test6;test7;8,9;10,11]
|
||||
image_button[1,2;3,4;img.png;name;label]
|
||||
image_button[1,2;3,4;img.png;name;label;false;true]
|
||||
image_button[1,2;3,4;img.png;name;label;true;false;img2.png]
|
||||
image_button_exit[1,2;3,4;img.png;name;label]
|
||||
image_button_exit[1,2;3,4;img.png;name;label;false;true]
|
||||
image_button_exit[1,2;3,4;img.png;name;label;true;false;img2.png]
|
||||
image[1,2;3,4;air.png;5]
|
||||
image[1,2;3,4;air.png;5,6]
|
||||
image[1,2;3,4;air.png;5,6,7,8]
|
||||
]]
|
||||
fs = ('\n' .. fs):gsub('\n[ \n]*', '')
|
||||
|
||||
test_parse_unparse(fs, {
|
||||
formspec_version = 2,
|
||||
{
|
||||
type = "size",
|
||||
w = 5,
|
||||
h = 2,
|
||||
},
|
||||
{
|
||||
type = "padding",
|
||||
x = 1,
|
||||
y = 2,
|
||||
},
|
||||
{
|
||||
type = "no_prepend"
|
||||
},
|
||||
{
|
||||
type = "container",
|
||||
x = 1,
|
||||
y = 1,
|
||||
{
|
||||
type = "label",
|
||||
x = 0,
|
||||
y = 0,
|
||||
label = "Containers are fun]\\",
|
||||
},
|
||||
{
|
||||
type = "container",
|
||||
x = -1,
|
||||
y = -1,
|
||||
{
|
||||
type = "button",
|
||||
x = 0.5,
|
||||
y = 0,
|
||||
w = 4,
|
||||
h = 1,
|
||||
name = "name",
|
||||
label = "Label",
|
||||
},
|
||||
},
|
||||
{
|
||||
type = "label",
|
||||
x = 0,
|
||||
y = 1,
|
||||
label = "Nested containers work too.",
|
||||
},
|
||||
{
|
||||
type = "scroll_container",
|
||||
x = 0,
|
||||
y = 2,
|
||||
w = 1,
|
||||
h = 1,
|
||||
scrollbar_name = "scrollbar",
|
||||
orientation = "vertical",
|
||||
-- scroll_factor = nil,
|
||||
{
|
||||
h = 1,
|
||||
y = 0,
|
||||
label = "Label",
|
||||
w = 4,
|
||||
name = "name",
|
||||
x = 0.5,
|
||||
type = "button"
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type = "image",
|
||||
x = 0,
|
||||
y = 1,
|
||||
w = 1,
|
||||
h = 1,
|
||||
texture_name = "air.png",
|
||||
},
|
||||
{
|
||||
type = "set_focus",
|
||||
name = "name",
|
||||
force = true,
|
||||
},
|
||||
{
|
||||
type = "dropdown",
|
||||
x = 0,
|
||||
y = 0,
|
||||
w = 1,
|
||||
name = "test",
|
||||
items = {"abc", "def", "ghi", "jkl"},
|
||||
selected_idx = 2,
|
||||
},
|
||||
{
|
||||
type = "dropdown",
|
||||
x = 0,
|
||||
y = 0,
|
||||
w = 1,
|
||||
name = "test",
|
||||
items = {"abc", "def", "ghi", "jkl"},
|
||||
selected_idx = 2,
|
||||
index_event = true,
|
||||
},
|
||||
{
|
||||
type = "field_close_on_enter",
|
||||
name = "my-field",
|
||||
close_on_enter = false,
|
||||
},
|
||||
{
|
||||
type = "bgcolor",
|
||||
bgcolor = "blue",
|
||||
},
|
||||
{
|
||||
type = "bgcolor",
|
||||
bgcolor = "blue",
|
||||
fullscreen = true,
|
||||
},
|
||||
{
|
||||
type = "bgcolor",
|
||||
bgcolor = "blue",
|
||||
fullscreen = "both",
|
||||
fbgcolor = "green",
|
||||
},
|
||||
{
|
||||
type = "tooltip",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
tooltip_text = "text",
|
||||
},
|
||||
{
|
||||
type = "tooltip",
|
||||
gui_element_name = "elem",
|
||||
tooltip_text = "text",
|
||||
bgcolor = "bgcolor",
|
||||
},
|
||||
{
|
||||
type = "background9",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "bg.png",
|
||||
auto_clip = false,
|
||||
middle_x = 5,
|
||||
},
|
||||
{
|
||||
type = "background9",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "bg.png",
|
||||
auto_clip = false,
|
||||
middle_x = 5,
|
||||
middle_y = 6,
|
||||
},
|
||||
{
|
||||
type = "background9",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "bg.png",
|
||||
auto_clip = false,
|
||||
middle_x = 5,
|
||||
middle_y = 6,
|
||||
middle_x2 = 7,
|
||||
middle_y2 = 8,
|
||||
},
|
||||
{
|
||||
type = "tablecolumns",
|
||||
tablecolumns = {
|
||||
{type = "text", opts = {}},
|
||||
{type = "image", opts = {}},
|
||||
{type = "color", opts = {option = "value"}},
|
||||
{type = "tree", opts = {}},
|
||||
},
|
||||
},
|
||||
{
|
||||
type = "list",
|
||||
inventory_location = "test",
|
||||
list_name = "test2",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
starting_item_index = 5,
|
||||
},
|
||||
{
|
||||
type = "list",
|
||||
inventory_location = "test6",
|
||||
list_name = "test7",
|
||||
x = 8,
|
||||
y = 9,
|
||||
w = 10,
|
||||
h = 11,
|
||||
},
|
||||
{
|
||||
type = "image_button",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "img.png",
|
||||
name = "name",
|
||||
label = "label",
|
||||
},
|
||||
{
|
||||
type = "image_button",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "img.png",
|
||||
name = "name",
|
||||
label = "label",
|
||||
noclip = false,
|
||||
drawborder = true,
|
||||
},
|
||||
{
|
||||
type = "image_button",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "img.png",
|
||||
name = "name",
|
||||
label = "label",
|
||||
noclip = true,
|
||||
drawborder = false,
|
||||
pressed_texture_name = "img2.png",
|
||||
},
|
||||
{
|
||||
type = "image_button_exit",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "img.png",
|
||||
name = "name",
|
||||
label = "label",
|
||||
},
|
||||
{
|
||||
type = "image_button_exit",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "img.png",
|
||||
name = "name",
|
||||
label = "label",
|
||||
noclip = false,
|
||||
drawborder = true,
|
||||
},
|
||||
{
|
||||
type = "image_button_exit",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "img.png",
|
||||
name = "name",
|
||||
label = "label",
|
||||
noclip = true,
|
||||
drawborder = false,
|
||||
pressed_texture_name = "img2.png",
|
||||
},
|
||||
{
|
||||
type = "image",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "air.png",
|
||||
middle_x = 5,
|
||||
},
|
||||
{
|
||||
type = "image",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "air.png",
|
||||
middle_x = 5,
|
||||
middle_y = 6,
|
||||
},
|
||||
{
|
||||
type = "image",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
texture_name = "air.png",
|
||||
middle_x = 5,
|
||||
middle_y = 6,
|
||||
middle_x2 = 7,
|
||||
middle_y2 = 8,
|
||||
},
|
||||
})
|
||||
|
||||
local function remove_trailing_params(elem_s, elem, ...)
|
||||
local res = {}
|
||||
local strings = {}
|
||||
local optional_params = {...}
|
||||
for i = #optional_params, 1, -1 do
|
||||
local p = optional_params[i]
|
||||
local no_copy = {}
|
||||
if type(p) == "table" then
|
||||
for _, param in ipairs(p) do
|
||||
no_copy[param] = true
|
||||
end
|
||||
else
|
||||
no_copy[p] = true
|
||||
end
|
||||
|
||||
res[i] = elem
|
||||
strings[i] = elem_s
|
||||
elem_s = elem_s:gsub(";[^;]+%]$", "]")
|
||||
local old_elem = elem
|
||||
elem = {}
|
||||
for k, v in pairs(old_elem) do
|
||||
if not no_copy[k] then
|
||||
elem[k] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
return table.concat(strings, ""), res
|
||||
end
|
||||
|
||||
test_parse_unparse(remove_trailing_params(
|
||||
"model[1,2;3,4;abc;def;ghi,jkl;5,6;true;false;7,8;9]",
|
||||
{
|
||||
type = "model",
|
||||
x = 1,
|
||||
y = 2,
|
||||
w = 3,
|
||||
h = 4,
|
||||
name = "abc",
|
||||
mesh = "def",
|
||||
textures = {"ghi", "jkl"},
|
||||
rotation_x = 5,
|
||||
rotation_y = 6,
|
||||
continuous = true,
|
||||
mouse_control = false,
|
||||
frame_loop_begin = 7,
|
||||
frame_loop_end = 8,
|
||||
animation_speed = 9
|
||||
},
|
||||
{"rotation_x", "rotation_y"}, "continuous", "mouse_control",
|
||||
{"frame_loop_begin", "frame_loop_end"}, "animation_speed"
|
||||
))
|
||||
|
||||
|
||||
-- Make sure style[] (un)parses correctly
|
||||
local s = 'style[test1,test2;def=ghi]style_type[test;abc=def]'
|
||||
assert_equal(s, assert(formspec_ast.interpret(s)))
|
||||
test_parse('style[name,name2;bgcolor=blue;textcolor=yellow]', {
|
||||
type = "style",
|
||||
selectors = {
|
||||
"name",
|
||||
"name2",
|
||||
},
|
||||
props = {
|
||||
bgcolor = "blue",
|
||||
textcolor = "yellow",
|
||||
},
|
||||
})
|
||||
|
||||
-- Test item/items compatibility
|
||||
assert_equal(
|
||||
'dropdown[0,0;1,2;test;abc,def,ghi,jkl;2;true]',
|
||||
assert(formspec_ast.unparse({
|
||||
{
|
||||
type = "dropdown",
|
||||
x = 0,
|
||||
y = 0,
|
||||
w = 1,
|
||||
h = 2,
|
||||
name = "test",
|
||||
items = {"abc", "def", "ghi", "jkl"},
|
||||
selected_idx = 2,
|
||||
index_event = true,
|
||||
},
|
||||
})),
|
||||
assert(formspec_ast.unparse({
|
||||
{
|
||||
type = "dropdown",
|
||||
x = 0,
|
||||
y = 0,
|
||||
w = 1,
|
||||
h = 2,
|
||||
name = "test",
|
||||
item = {"abc", "def", "ghi", "jkl"},
|
||||
selected_idx = 2,
|
||||
index_event = true,
|
||||
},
|
||||
}))
|
||||
)
|
||||
|
||||
-- Ensure the style[] unparse compatibility works correctly
|
||||
assert_equal(
|
||||
'style_type[test;abc=def]',
|
||||
assert(formspec_ast.unparse({
|
||||
{
|
||||
type = 'style_type',
|
||||
name = 'test',
|
||||
props = {
|
||||
abc = 'def',
|
||||
},
|
||||
}
|
||||
})),
|
||||
assert(formspec_ast.unparse({
|
||||
{
|
||||
type = 'style_type',
|
||||
selectors = {
|
||||
'test',
|
||||
},
|
||||
props = {
|
||||
abc = 'def',
|
||||
},
|
||||
}
|
||||
}))
|
||||
)
|
||||
|
||||
-- Ensure flatten works correctly
|
||||
assert_equal(
|
||||
'label[0,0;abc]label[2,2;def]scroll_container[1,1;2,2;test;vertical]' ..
|
||||
'image[1,1;1,1;def]scroll_container_end[]',
|
||||
formspec_ast.unparse(formspec_ast.flatten(assert(formspec_ast.parse([[
|
||||
label[0,0;abc]
|
||||
container[3,2]
|
||||
container[-1,0]
|
||||
label[0,0;def]
|
||||
container_end[]
|
||||
container_end[]
|
||||
scroll_container[1,1;2,2;test;vertical]
|
||||
image[1,1;1,1;def]
|
||||
scroll_container_end[]
|
||||
]]))))
|
||||
)
|
||||
|
||||
-- Ensure invsize[] is converted to size[]
|
||||
assert_equal(assert(formspec_ast.interpret('invsize[12,34]')), 'size[12,34]')
|
||||
|
||||
assert_equal(assert(formspec_ast.interpret('label[1,2;abc\\')),
|
||||
'label[1,2;abc]')
|
||||
assert_equal(assert(formspec_ast.interpret('label[1,2;abc\\\\')),
|
||||
'label[1,2;abc\\\\]')
|
||||
|
||||
assert_equal(formspec_ast.formspec_escape('label[1,2;abc\\def]'),
|
||||
'label\\[1\\,2\\;abc\\\\def\\]')
|
||||
|
||||
assert_equal(
|
||||
formspec_ast.safe_interpret([[
|
||||
formspec_version[5.1]
|
||||
size[3,3]
|
||||
label[0,0;Hi]
|
||||
image[1,2;3,4;a^b\[c]
|
||||
formspec_ast:crash[]
|
||||
textlist[1,2;3,4;test;a,b,c]
|
||||
]]),
|
||||
'formspec_version[5]size[3,3]label[0,0;Hi]image[1,2;3,4;a^b]' ..
|
||||
'textlist[1,2;3,4;test;a,b,c]'
|
||||
)
|
||||
|
||||
print('Tests pass')
|
Loading…
Reference in New Issue