from pathlib import Path from lupa import LuaRuntime source=(Path(__file__).resolve().parents[1]/'ale/azerothai_training.lua').read_text() setup=''' now=1000;os.time=function()return now end;calls={};moves=0;learned=0;team=2;callbacks={} function AuthDBExecute()end function AuthDBQuery(s) if s:find("state='active'",1,true) then return {GetUInt32=function(_,i)return i==0 and 1 or 11 end,GetString=function()return 'A' end,NextRow=function()return false end} end if s:find('SELECT flags',1,true) then return {GetString=function()return 'new rpg,quest' end}end end function WorldDBQuery()return {GetUInt32=function(_,i)return ({[0]=8,[1]=100,[2]=0,[7]=team})[i]end,GetFloat=function(_,i)return ({[3]=10,[4]=20,[5]=30})[i]end,GetString=function()return 'Trainer' end,NextRow=function()return false end}end function CreateLuaEvent(f)tick=f end;function PrintError(s)error(s)end p={ai={},money=100,level=4,distance=0,pending=2} function p:GetGUIDLow()return 1 end;function p:GetAccountId()return 11 end;function p:GetName()return 'A' end function p:GetLevel()return self.level end;function p:GetClass()return 8 end;function p:GetTeam()return 0 end;function p:GetMapId()return 0 end function p:GetX()return 10 end;function p:GetY()return 20 end;function p:IsPlayerbot()return true end;function p:GetBotAI()return self.ai end function p.ai:HasGameClientMaster()return p.human end;function p:IsDead()return p.dead end;function p:IsInCombat()return p.combat end function p:IsCasting()return false end;function p:HasUnitState(state)assert(state==0x00000100);return self.taxi end;function p:GetGroup()return p.group end;function p:GetCoinage()return self.money end function p.ai:GetClassTrainerStatus()return p.pending,10,20 end function p.ai:TrainAtClassTrainer()assert(p.distance<=5);local n=p.pending;learned=learned+n;p.pending=0;p.money=p.money-20;return n end function p.ai:HasStrategy()return true end;function p.ai:ChangeStrategy(s)table.insert(calls,s)end function p:GetNearestCreature()return {} end;function p:GetDistance()return self.distance end;function p:MoveStop()end;function p:MoveTo()moves=moves+1 end function GetPlayersInWorld()return {p}end function AzerothAISurvivalOverride()return p.recovering end ''' def new(extra=''): l=LuaRuntime();l.execute(setup+extra);l.execute(source);return l l=new();l.execute("tick();assert(learned==2 and p.money==80);assert(AzerothAITrainingSnapshot(p).trainingStatus=='no new trainable spells');now=1010;p.level=5;p.pending=1;tick();assert(learned==3,'New level is checked without waiting a minute')") for flag in ['human','dead','combat','recovering','taxi']: l=new();l.execute(f'p.{flag}=true;tick();assert(learned==0 and moves==0)') l=new();l.execute("p.money=0;tick();assert(learned==0 and moves==0 and AzerothAITrainingSnapshot(p).trainingStatus=='saving for training')") l=new();l.execute("p.distance=20;tick();assert(learned==0 and moves==1 and AzerothAITrainingOverride(p));now=1060;tick();assert(not AzerothAITrainingOverride(p),'Stalled visit releases held work')") l=new('team=4');l.execute("tick();assert(learned==0 and moves==0,'Opposing faction trainer excluded')") l=new();l.execute("p.distance=20;tick();assert(AzerothAITrainingOverride(p));p.human=true;now=1010;tick();assert(not AzerothAITrainingOverride(p) and moves==1,'Human takeover releases our lease without continuing travel')") l=new();l.execute("p.group={IsRaidGroup=function()return false end,GetMembersCount=function()return 2 end,GetMembers=function()return {p}end};tick();assert(learned==0 and moves==0)") print('Trainer checks: every level, verified learning, money, interaction distance, stalled-path release and human/combat/death/group/faction guards passed')