73 lines
5.4 KiB
Python
73 lines
5.4 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/ERR_AdminService.c'
|
|
hq = ROOT/'addons/ai/Scripts/Game/ERR/ERR_HQAdminProvider.c'
|
|
intel = ROOT/'addons/intel/Scripts/Game/ERR/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/chat/Scripts/Game/ERR/ERR_AdminCommands.c').read_text()
|
|
assert 'Admin().Register(new ERR_HQAdminProvider(hq))' in (ROOT/'addons/ai/Scripts/Game/ERR/ERR_HQ.c').read_text()
|
|
assert 'Admin().Register(new ERR_IntelAdminProvider())' in (ROOT/'addons/intel/Scripts/Game/ERR/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","interval")=="reportIntervalSeconds"&&ha.Setting("hq","squads")=="supportSquadLimit"&&ha.Setting("hq","radius")=="responseRadiusMetres");
|
|
assert(ha.Setting("intel","carrying").empty()&&ha.Setting("hq","stinger")=="stingerChanceOneIn");
|
|
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()<=4);lines.clear();assert(ih.Help("intel",lines)&&lines.size()<=4);
|
|
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')
|