112 lines
4.9 KiB
Python
112 lines
4.9 KiB
Python
# coding: utf-8
|
|
"""Catalog coverage plus Lua 5.0 menu/permission/warp integration checks.
|
|
Usage: python3 test_ring.py SERVER_LIBLUA_DIRECTORY [LIVE_MAP_INDEX] [COMPILED_OBJECT_ROOT]
|
|
"""
|
|
import importlib.util
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
spec = importlib.util.spec_from_file_location('ring_generate', ROOT / 'generate.py')
|
|
generator = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(generator)
|
|
quest = generator.generate()
|
|
assert quest == (ROOT / 'ring_warp.quest').read_text(encoding='utf-8'), 'regenerate quest'
|
|
catalog = json.loads((ROOT / 'maps.json').read_text(encoding='utf-8'))
|
|
maps = [m for c in catalog['categories'] for m in c['maps']]
|
|
byid = {m['id']:m for m in maps}
|
|
assert len(maps) == len(byid) == 65
|
|
if len(sys.argv) > 2:
|
|
live = dict((int(line.split()[0]),line.split()[1]) for line in Path(sys.argv[2]).read_text().splitlines() if line.strip() and not line.lstrip().startswith('#'))
|
|
assert {m['id']:m['directory'] for m in maps} == live
|
|
for m in maps:
|
|
assert m['mode'] in ('direct', 'entrance', 'gm', 'event')
|
|
target = byid[m['target'][0]]
|
|
for j in range(2):
|
|
assert target['base'][j] <= m['target'][j+1] < target['base'][j] + target['size'][j] * 25600, m
|
|
assert {m['id'] for m in maps if m['mode']=='entrance'} == {66,71,72,73,208,216,217,351}
|
|
assert byid[217]['target'][0] == 104 and byid[208]['target'][0] == 64
|
|
assert 'remove_item' not in quest and 'socket' not in quest and 'setqf' not in quest
|
|
# Run the actual generated functions/event body under the server's Lua 5.0.
|
|
helper = quest.split(' function destinations()',1)[1].split(' when 10031.sig_use begin',1)[0]
|
|
body = quest.split(' when 10031.sig_use begin',1)[1].rsplit(' end',1)[0]
|
|
script = 'ring_warp = {}\nfunction ring_warp.destinations()' + helper + '\nfunction use_ring()\n' + body + '\nend\n'
|
|
if len(sys.argv) > 3:
|
|
objects = Path(sys.argv[3])
|
|
state = (objects/'state/ring_warp').read_bytes().decode('gbk')
|
|
event = (objects/'10031/sig_use/ring_warp.start').read_bytes().decode('gbk')
|
|
script = state + '\nfunction use_ring()\n' + event + '\nend\n'
|
|
script += '''
|
|
local categories = ring_warp.destinations()
|
|
local queue = {}
|
|
local cursor = 0
|
|
local gm = false
|
|
local can_warp = true
|
|
local warps = {}
|
|
pc = {
|
|
is_gm = function() return gm end,
|
|
can_warp = function() return can_warp end,
|
|
warp = function(x,y) table.insert(warps,{x,y}) end,
|
|
}
|
|
say_title = function(text) end
|
|
say = function(text) end
|
|
wait = function() end
|
|
select_table = function(options)
|
|
assert(table.getn(options) <= 8, "menu too tall")
|
|
cursor = cursor + 1
|
|
local choice = queue[cursor]
|
|
assert(choice and choice >= 1 and choice <= table.getn(options), "bad selection")
|
|
return choice
|
|
end
|
|
select = function(...) return select_table(arg) end
|
|
local runs = 0
|
|
function run(answers, is_gm, allowed)
|
|
queue = answers; cursor = 0; gm = is_gm; can_warp = allowed; warps = {}
|
|
use_ring()
|
|
assert(cursor == table.getn(queue), "unexpected navigation")
|
|
runs = runs + 1
|
|
end
|
|
for category = 1, table.getn(categories) do
|
|
local maps = categories[category].maps
|
|
for index = 1, table.getn(maps) do
|
|
local page = math.floor((index-1)/5)+1
|
|
local answer = {}
|
|
table.insert(answer, category)
|
|
for p = 1,page-1 do table.insert(answer, p==1 and 6 or 7) end
|
|
table.insert(answer, math.mod(index-1,5)+1)
|
|
local m = maps[index]
|
|
local blocked = m.mode == "gm" or m.mode == "event"
|
|
if blocked then
|
|
local count = math.min(5,table.getn(maps)-(page-1)*5)
|
|
local buttons = count + 1
|
|
if page > 1 then buttons = buttons + 1 end
|
|
if page*5 < table.getn(maps) then buttons = buttons + 1 end
|
|
table.insert(answer,buttons); table.insert(answer,7)
|
|
else table.insert(answer,1) end
|
|
run(answer,false,true)
|
|
assert(table.getn(warps) == (blocked and 0 or 1))
|
|
if not blocked then assert(warps[1][1]==m.x and warps[1][2]==m.y) end
|
|
end
|
|
end
|
|
run({7},false,true) -- close
|
|
run({1,6,2,7,7},false,true) -- next, previous, return list/category, close
|
|
run({1,1,1},false,false) -- blocked by active trade etc.
|
|
assert(table.getn(warps)==0)
|
|
run({6,1,1},true,true) -- GM test-map access
|
|
assert(table.getn(warps)==1 and warps[1][1]==categories[6].maps[1].x)
|
|
print("PASS: 65 map selections, paging, back/cancel, warp guard and GM access; " .. runs .. " runs")
|
|
'''
|
|
lua = Path(sys.argv[1])
|
|
with tempfile.TemporaryDirectory(prefix='ring-warp-test-') as d:
|
|
d = Path(d)
|
|
sources = [p for p in sorted((lua/'src').glob('*.c')) if p.name != 'ltests.c']
|
|
sources += [lua/'src/lib'/name for name in ('lauxlib.c','lbaselib.c','ltablib.c','lstrlib.c','lmathlib.c')]
|
|
command = ['cc','-w','-I'+str(lua/'include'),'-I'+str(lua/'src'),str(ROOT/'tests/lua_runner.c'),*[str(p) for p in sources],'-lm','-o',str(d/'lua')]
|
|
subprocess.run(command,check=True)
|
|
(d/'test.lua').write_bytes(script.encode('gbk'))
|
|
subprocess.run([str(d/'lua'),str(d/'test.lua')],check=True)
|
|
print('PASS: catalog matches server index, coordinates in bounds, GBK source safe')
|