Files
metin2-client/tests/wiki/test_timers.py
T

68 lines
3.6 KiB
Python

"""Test the actual embedded UI timer methods with a deterministic clock (no rendering mocks)."""
import ast
from pathlib import Path
import types
import unittest
ROOT=Path(__file__).resolve().parents[2]
def window_class(filename,name,clock,messages):
text=(ROOT/'src/platform/ScriptLib'/filename).read_text().split('R"PY(',1)[1].rsplit(')PY";',1)[0]
tree=ast.parse(text)
tree.body=[n for n in tree.body if isinstance(n,(ast.ClassDef,ast.FunctionDef))]
ns=dict(ui=types.SimpleNamespace(Window=object),app=types.SimpleNamespace(GetTime=lambda:clock[0]),
chat=types.SimpleNamespace(CHAT_TYPE_INFO=1,AppendChat=lambda kind,text:messages.append(text)),
L=lambda text:text,NAMES={1:'moon',2:'sock'})
exec(compile(tree,filename,'exec'),ns)
return ns[name]
class TimerTests(unittest.TestCase):
def setUp(self):self.clock=[10.];self.messages=[]
def test_dungeon_reminder_only_confirmed_snapshot_and_extended_deadline(self):
cls=window_class('DungeonScript.inc','DungeonWindow',self.clock,self.messages)
w=cls.__new__(cls);w.reminder=(0,100);w.stale=True;w.values={'lair_end':100};w.serverTime=101;w.received=10.
w.CheckReminder();self.assertFalse(self.messages)
w.stale=False;w.values['lair_end']=200;w.CheckReminder()
self.assertEqual(w.reminder,(0,200));self.assertFalse(self.messages)
w.serverTime=200;w.CheckReminder();self.assertFalse(self.messages) # strict original deadline
w.serverTime=201;w.CheckReminder();w.CheckReminder()
self.assertEqual(len(self.messages),1);self.assertIsNone(w.reminder)
def test_dungeon_sleep_invalidates_display_and_requeries_before_notification(self):
cls=window_class('DungeonScript.inc','DungeonWindow',self.clock,self.messages)
w=cls.__new__(cls);w.lastTick=1.;w.stale=False;w.nextQuery=999;w.pending=False;w.values={};w.reminder=(0,5)
w.IsShow=lambda:False;calls=[];w.Query=lambda:calls.append('query')
w.Now=lambda:1000
w.OnUpdate()
self.assertTrue(w.stale);self.assertTrue(calls);self.assertFalse(self.messages)
def test_calendar_actual_scope_and_start_end_notifications_once(self):
cls=window_class('CalendarScript.inc','CalendarWindow',self.clock,self.messages)
w=cls.__new__(cls);w.offset=0;w.watch=dict(id=1,began=False,offset=0)
w.data=dict(time=100,rows=[[1,1,100,200,2,0,0]])
w.Notify();self.assertFalse(self.messages) # other channel cannot trigger start
w.data['rows'][0][-1]=1;w.Notify();w.Notify();self.assertEqual(len(self.messages),1)
w.data['time']=200;w.Notify();w.Notify();self.assertEqual(len(self.messages),2);self.assertIsNone(w.watch)
def test_short_screen_two_row_pages_do_not_skip_server_rows(self):
cls=window_class('CalendarScript.inc','CalendarWindow',self.clock,self.messages)
w=cls.__new__(cls);w.pending=False;w.offset=0;w.rowPage=0;w.pageSize=2;w.data=dict(total=10)
calls=[];w.Refresh=lambda:None;w.Query=lambda:calls.append(w.offset)
seen=[]
for i in range(5):
seen.append(w.offset+w.rowPage*w.pageSize)
w.Page(1)
if w.data is None:w.data=dict(total=10)
self.assertEqual(seen,[0,2,4,6,8]);self.assertEqual(calls,[8])
def test_calendar_removed_event_cancels_without_fake_end(self):
cls=window_class('CalendarScript.inc','CalendarWindow',self.clock,self.messages)
w=cls.__new__(cls);w.offset=0;w.watch=dict(id=1,began=True,offset=0);w.data=dict(time=500,rows=[])
w.Notify();self.assertIsNone(w.watch);self.assertFalse(self.messages)
if __name__=='__main__':unittest.main()