Files
EscapistsReintroduced/tests/test_admin_providers.py
T
2026-10-21 16:36:22 +02:00

75 lines
5.6 KiB
Python

"""Exercise actual registration/dispatch bodies without requiring optional addons.
Native script compilation and authenticated RPC tests remain separate checks.
"""
from policy_harness import ROOT, body, run
core = ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_AdminService.c'
hq = ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_HQAdminProvider.c'
intel = ROOT/'addons/core/Scripts/Game/ERR/20_Intel/ERR_IntelAdminProvider.c'
source=core.read_text()
assert 'ERR_HQ' not in source and 'ERR_IntelService' not in source
assert 'modded class' not in (ROOT/'addons/core/Scripts/Game/ERR/40_Chat/ERR_AdminCommands.c').read_text()
assert 'Admin().Register(new ERR_HQAdminProvider(hq))' in (ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_HQ.c').read_text()
assert 'Admin().Register(new ERR_IntelAdminProvider())' in (ROOT/'addons/core/Scripts/Game/ERR/20_Intel/ERR_IntelService.c').read_text()
execute=body(core,'void Execute(')
assert execute.index('if (!Replication.IsServer()') < execute.index('if (!authorized)') < execute.index('Extension(mode, arguments, replies)')
assert 'arguments = "mission " + arguments' in execute
def translate(s):
return (s.replace('protected ', '').replace('override ', '')
.replace('array<string>', 'Array<string>&').replace('out int ', 'int& ')
.replace('ERR_AdminProvider provider', 'Provider* provider').replace('ERR_GameMode mode','Mode* mode')
.replace('foreach (Provider* provider : m_Providers)', 'for (Provider* provider : m_Providers)')
.replace('ERR_CommandArguments.CoreSetting(', 'CoreSetting(')
.replace('provider.', 'provider->').replace('m_Providers[i].', 'm_Providers[i]->')
.replace('.IsEmpty()', '.empty()').replace('bool handled;', 'bool handled = false;'))
methods='\n'.join(translate(body(core,sig)) for sig in ('void Register(', 'void Capabilities(', 'int JournalSequence(', 'bool ReadJournal(', 'protected string Setting(', 'protected bool Extension('))
aliases='struct HQAliases{'+translate(body(hq,'override string Setting('))+'};\nstruct IntelAliases{'+translate(body(intel,'override string Setting('))+'};'
help_bodies='struct HQHelp{'+translate(body(hq,'override bool Help('))+'};\nstruct IntelHelp{'+translate(body(intel,'override bool Help('))+'};'
run(r'''
#include <cassert>
#include <string>
#include <vector>
#include <algorithm>
using string=std::string;
template<class T> struct Array:std::vector<T>{void Insert(T v){this->push_back(v);}void Clear(){this->clear();}int Count(){return this->size();}};
struct Mode{};
string CoreSetting(string section,string option){if(section=="intel"&&option=="reveal")return "intelRevealChancePercent";return "";}
struct Provider{
string id;int sequence=-1;int calls=0;bool accepts=false;int reads=0;
string Id(){return id;}void Capabilities(Array<string>& values){values.Insert("supports="+id);}
int JournalSequence(){return sequence;}
bool ReadJournal(int after,Array<string>& lines,int& cursor,int limit=8){if(sequence<0)return false;reads++;cursor=std::min(sequence,after+limit);lines.Insert(id);return true;}
string Setting(string section,string){return section==id?id+"Setting":"";}
bool Execute(Mode*,string,Array<string>& replies){calls++;if(accepts)replies.Insert(id);return accepts;}
};
struct Admin{Array<Provider*>m_Providers;
'''+methods+'};\n'+aliases+help_bodies+r'''
int main(){
Admin admin;Mode mode;Array<string> lines;int cursor=0;
assert(admin.JournalSequence()==-1&&!admin.ReadJournal(0,lines,cursor));
assert(admin.Setting("intel","reveal")=="intelRevealChancePercent"&&admin.Setting("hq","squads").empty());
admin.Register(nullptr);Provider empty;admin.Register(&empty);assert(admin.m_Providers.empty());
Provider hq;hq.id="hq";hq.sequence=12;hq.accepts=true;
Provider intel;intel.id="intel";intel.accepts=true;
admin.Register(&hq);admin.Register(&hq);admin.Register(&intel);assert(admin.m_Providers.size()==2);
admin.Capabilities(lines);assert(lines.size()==2&&lines[0]=="supports=hq"&&lines[1]=="supports=intel");
assert(admin.JournalSequence()==12);assert(admin.ReadJournal(2,lines,cursor,4)&&cursor==6&&lines.size()==1&&lines[0]=="hq");
assert(hq.reads==1&&intel.reads==0);
lines.clear();assert(admin.Extension(&mode,"status",lines)&&lines.size()==2&&hq.calls==1&&intel.calls==1);
lines.clear();assert(admin.Extension(&mode,"hq show",lines)&&lines.size()==1&&hq.calls==2&&intel.calls==1);
hq.accepts=false;intel.accepts=false;lines.clear();assert(!admin.Extension(&mode,"unknown",lines)&&lines.empty());
Provider replacement;replacement.id="hq";replacement.sequence=20;
admin.Register(&replacement);assert(admin.m_Providers.size()==2&&admin.JournalSequence()==20);
HQAliases ha;IntelAliases ia;
assert(ha.Setting("hq","equipment")=="automaticEquipmentChancePercent");
assert(ha.Setting("hq","interval")=="reportIntervalSeconds"&&ha.Setting("hq","squads")=="supportSquadLimit"&&ha.Setting("hq","radius")=="responseRadiusMetres");
assert(ha.Setting("hq","aa")=="antiAirChancePercent"&&ha.Setting("hq","mines")=="antiPersonnelMineChancePercent");
assert(ha.Setting("intel","carrying").empty()&&ha.Setting("hq","stinger")=="antiAirChancePercent");
assert(ia.Setting("intel","chance")=="aiIntelChancePercent"&&ia.Setting("intel","carrying")=="aiIntelChancePercent");
assert(ia.Setting("hq","chance").empty()&&ia.Setting("intel","spawn").empty());
HQHelp hh;IntelHelp ih;lines.clear();assert(hh.Help("hq",lines)&&lines.size()<=5);lines.clear();assert(ih.Help("intel",lines)&&lines.size()<=5&&lines[0].find("radiosites")!=string::npos);
lines.clear();assert(!hh.Help("unknown",lines)&&!ih.Help("unknown",lines)&&lines.empty());
}
''')
print('PASS: mission provider registration is idempotent, optional dispatch is ordered, status aggregates, journals preserve cursors, aliases stay with their addons and topic help is bounded')