Fix tabheader parsing and use busted for tests
This commit is contained in:
parent
68712195f3
commit
c7629b718d
|
@ -4,8 +4,17 @@ jobs:
|
||||||
lint:
|
lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@v3
|
||||||
- name: lint
|
- name: lint
|
||||||
uses: Roang-zero1/factorio-mod-luacheck@master
|
uses: Roang-zero1/factorio-mod-luacheck@master
|
||||||
with:
|
with:
|
||||||
luacheckrc_url: ""
|
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__/
|
__pycache__/
|
||||||
test.lua
|
|
||||||
|
|
|
@ -48,6 +48,10 @@ all attributes are lowercase.
|
||||||
While I try to reduce backwards incompatibilities, sometimes they are necessary
|
While I try to reduce backwards incompatibilities, sometimes they are necessary
|
||||||
to either fix bugs in formspec_ast or for implementing new formspec features.
|
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
|
#### February 2022
|
||||||
|
|
||||||
- The value of scrollbars is now a number instead of a string.
|
- 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[48] = {"selected_idx", "number"}
|
||||||
a[49] = {"transparent", "boolean"}
|
a[49] = {"transparent", "boolean"}
|
||||||
a[50] = {{{"captions", "string"}, "..."}}
|
a[50] = {{{"captions", "string"}, "..."}}
|
||||||
a[51] = {"current_tab", "string"}
|
a[51] = {"current_tab", "number"}
|
||||||
a[52] = {"draw_border", "boolean"}
|
a[52] = {"draw_border", "boolean"}
|
||||||
a[53] = {{{"items", "string"}, "..."}}
|
a[53] = {{{"items", "string"}, "..."}}
|
||||||
a[54] = {"index_event", "boolean"}
|
a[54] = {"index_event", "boolean"}
|
||||||
|
@ -64,4 +64,4 @@ a[57] = {{a[56]}}
|
||||||
a[58] = {{"props", "table"}, "..."}
|
a[58] = {{"props", "table"}, "..."}
|
||||||
a[59] = {a[26]}
|
a[59] = {a[26]}
|
||||||
a[60] = {{{{{"selectors", "string"}, "..."}}, a[58]}, {a[59], a[58]}}
|
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]
|
- [name, string]
|
||||||
- - - [captions, string]
|
- - - [captions, string]
|
||||||
- '...'
|
- '...'
|
||||||
- [current_tab, string]
|
- [current_tab, number]
|
||||||
- [transparent, boolean]
|
- [transparent, boolean]
|
||||||
- [draw_border, boolean]
|
- [draw_border, boolean]
|
||||||
- - - [x, number]
|
- - - [x, number]
|
||||||
|
@ -493,7 +493,7 @@ tabheader:
|
||||||
- [name, string]
|
- [name, string]
|
||||||
- - - [captions, string]
|
- - - [captions, string]
|
||||||
- '...'
|
- '...'
|
||||||
- [current_tab, string]
|
- [current_tab, number]
|
||||||
- [transparent, boolean]
|
- [transparent, boolean]
|
||||||
- [draw_border, boolean]
|
- [draw_border, boolean]
|
||||||
- - - [x, number]
|
- - - [x, number]
|
||||||
|
@ -501,54 +501,15 @@ tabheader:
|
||||||
- [name, string]
|
- [name, string]
|
||||||
- - - [captions, string]
|
- - - [captions, string]
|
||||||
- '...'
|
- '...'
|
||||||
- [current_tab, string]
|
- [current_tab, number]
|
||||||
- [transparent, boolean]
|
- [transparent, boolean]
|
||||||
- [draw_border, boolean]
|
- [draw_border, boolean]
|
||||||
- - - [x, number]
|
- - - [x, number]
|
||||||
- [y, number]
|
- [y, number]
|
||||||
- [h, number]
|
|
||||||
- [name, string]
|
- [name, string]
|
||||||
- - - [captions, string]
|
- - - [captions, string]
|
||||||
- '...'
|
- '...'
|
||||||
- [current_tab, string]
|
- [current_tab, number]
|
||||||
- [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]
|
|
||||||
table:
|
table:
|
||||||
- - - [x, number]
|
- - - [x, number]
|
||||||
- [y, number]
|
- [y, number]
|
||||||
|
|
|
@ -14,7 +14,7 @@ def _make_known(**kwargs):
|
||||||
return known
|
return known
|
||||||
|
|
||||||
_known = _make_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',
|
'starting_item_index', 'scroll_factor', 'frame_count',
|
||||||
'frame_duration', 'frame_start', 'animation_speed', 'value'),
|
'frame_duration', 'frame_start', 'animation_speed', 'value'),
|
||||||
boolean=('auto_clip', 'fixed_size', 'transparent', 'draw_border', 'bool',
|
boolean=('auto_clip', 'fixed_size', 'transparent', 'draw_border', 'bool',
|
||||||
|
@ -193,6 +193,19 @@ def _image_button_hook(params):
|
||||||
params.append(('pressed_texture_name', 'string'))
|
params.append(('pressed_texture_name', 'string'))
|
||||||
yield params
|
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
|
# Support MultiCraft's non-standard scrollbar styling
|
||||||
# WARNING: This may be removed or broken without notice
|
# WARNING: This may be removed or broken without notice
|
||||||
@hook('scrollbar')
|
@hook('scrollbar')
|
||||||
|
@ -283,7 +296,7 @@ def parse(data):
|
||||||
|
|
||||||
return res
|
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):
|
def fetch_and_parse(*, url=URL):
|
||||||
with urllib.request.urlopen(url) as f:
|
with urllib.request.urlopen(url) as f:
|
||||||
raw = f.read()
|
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