90 lines
6.5 KiB
Python
90 lines
6.5 KiB
Python
"""Execute actual resolver/context/latch bodies with opaque native handles.
|
|
UUID generation/nullness and native session/controller APIs are substituted;
|
|
this is not authentication, native GenV4 or multiplayer evidence.
|
|
"""
|
|
from policy_harness import ROOT, body, run
|
|
import re
|
|
source=ROOT/'addons/core/Scripts/Game/ERR/ERR_LocalAdmission.c'
|
|
s=source.read_text().split('\nmodded class ERR_GameMode')[0]
|
|
s=s[s.index('class ERR_LocalAdmissionRules'):]
|
|
s=s.replace('class ERR_LocalAdmissionRules','struct ERR_LocalAdmissionRules').replace('class ERR_LocalAdmission\n','struct ERR_LocalAdmission\n')
|
|
s=s.replace('\n}\n','\n};\n').replace('protected ','')
|
|
s=s.replace('void ERR_LocalAdmission(', 'ERR_LocalAdmission(')
|
|
s=s.replace('ERR_GameMode', 'Mode').replace('SCR_PlayerController', 'Controller').replace('PlayerManager', 'Manager')
|
|
s=re.sub(r'\b(Mode|Controller|Manager) (mode|controller|manager|m_Mode|m_Controller)\b',r'\1* \2',s)
|
|
s=s.replace('Mode.Get()', 'Mode::Get()').replace('RplMode.None','0')
|
|
s=s.replace('Replication.IsServer()', 'isServer').replace('RplSession.Mode()', 'sessionMode')
|
|
s=s.replace('GetGame().', 'GetGame()->').replace('manager.', 'manager->').replace('controller.', 'controller->')
|
|
s=s.replace('System.GetCLIParam', 'System::GetCLIParam').replace('string project;', 'std::string project;')
|
|
s=s.replace('bool connected, sameManager;', 'bool connected=false, sameManager=false;').replace('int controllerId;', 'int controllerId=0;')
|
|
s=s.replace('ERR_LocalAdmissionRules.', 'ERR_LocalAdmissionRules::')
|
|
s=s.replace('UUID.NULL_UUID','UUID::NULL_UUID').replace('UUID.GenV4()', 'UUID::GenV4()').replace('null','nullptr')
|
|
# Enforce initializes managed fields; retain that contract in this C++ model.
|
|
s=s.replace('Mode* m_Mode;', 'Mode* m_Mode=nullptr;').replace('Controller* m_Controller;', 'Controller* m_Controller=nullptr;')
|
|
s=re.sub(r'\b(bool|int) (m_\w+);',r'\1 \2=0;',s)
|
|
run('''#include <cassert>
|
|
#include <string>
|
|
int generated=0;bool isServer=true;int sessionMode=0;
|
|
struct UUID {int value=0;bool IsNull(){return value<=0;}bool operator==(UUID other){return value==other.value;}static UUID NULL_UUID;static UUID GenV4(){return UUID{++generated+100};}};
|
|
UUID UUID::NULL_UUID{0};
|
|
struct Controller {int id=1;int GetPlayerId(){return id;}};
|
|
struct Manager {int count=1;bool connected=true;Controller* controller=nullptr;int GetPlayerCount(){return count;}bool IsPlayerConnected(int id){return connected;}Controller* GetPlayerController(int id){return controller;}};
|
|
struct Mode {static Mode* current;static Mode* Get(){return current;}};Mode* Mode::current=nullptr;
|
|
struct Game {Manager* manager=nullptr;Controller* local=nullptr;Manager* GetManager(){return manager;}Controller* GetPlayerController(){return local;}};
|
|
Game* game=nullptr;Game* GetGame(){return game;}void Print(const char*){}
|
|
namespace System {bool GetCLIParam(const char*,std::string&){return false;}}
|
|
template<class... Args> void PrintFormat(Args... args) {}
|
|
'''+s+'''
|
|
int main(){
|
|
// Exact None only; every context condition independently matters.
|
|
for(int mode=-1;mode<5;++mode)for(int count=0;count<3;++count)for(int flags=0;flags<16;++flags)
|
|
assert(ERR_LocalAdmissionRules::Context(flags&1,mode,count,flags&2,flags&4,flags&8,1,1)==(mode==0&&count==1&&flags==15));
|
|
assert(!ERR_LocalAdmissionRules::Context(true,0,1,true,true,true,0,0));
|
|
assert(!ERR_LocalAdmissionRules::Context(true,0,1,true,true,true,1,2));
|
|
Mode round,nextRound;Mode::current=&round;Controller owner,replacement;Manager manager;manager.controller=&owner;Game world{&manager,&owner};game=&world;
|
|
ERR_LocalAdmission admission(&round);
|
|
UUID selected=admission.Resolve(&round,1,&owner,UUID{0});assert(!selected.IsNull()&&admission.LocalKey()&&generated==1);
|
|
assert(admission.Resolve(&round,1,&owner,UUID{0})==selected&&generated==1);
|
|
assert(admission.Resolve(&round,1,&owner,UUID{55})==selected&&generated==1); // late BI arrival cannot make fresh life
|
|
assert(admission.Validate());
|
|
assert(!admission.Disconnected(2));assert(admission.Validate());
|
|
assert(admission.Disconnected(1));assert(!admission.Validate());
|
|
assert(admission.Resolve(&round,1,&owner,UUID{55}).IsNull()); // irreversible within this mode
|
|
ERR_LocalAdmission native(&round);assert(native.Resolve(&round,1,&owner,UUID{55})==UUID{55});
|
|
assert(!native.LocalKey()&&native.Resolve(&round,1,&owner,UUID{0})==UUID{55}&&generated==1);
|
|
native.Stop();assert(native.Resolve(&round,1,&owner,UUID{0}).IsNull());assert(!native.Validate());
|
|
// Replacement, mode switch, manager/local mismatch and additional connections latch.
|
|
for(int fault=0;fault<6;++fault){
|
|
sessionMode=0;Mode::current=&round;manager.controller=&owner;world.local=&owner;manager.count=1;manager.connected=true;
|
|
ERR_LocalAdmission a(&round);assert(!a.Resolve(&round,1,&owner,UUID{0}).IsNull());
|
|
if(fault==0)sessionMode=1;
|
|
if(fault==1)manager.controller=&replacement;
|
|
if(fault==2)world.local=&replacement;
|
|
if(fault==3)manager.count=2;
|
|
if(fault==4)manager.connected=false;
|
|
if(fault==5)Mode::current=&nextRound;
|
|
assert(!a.Validate());
|
|
sessionMode=0;Mode::current=&round;manager.controller=&owner;world.local=&owner;manager.count=1;manager.connected=true;
|
|
assert(!a.Validate());assert(a.Resolve(&round,1,&owner,UUID{88}).IsNull());
|
|
}
|
|
// A newly created round owns a fresh key. Old resolver cannot be reused.
|
|
Mode::current=&nextRound;ERR_LocalAdmission next(&nextRound);UUID nextKey=next.Resolve(&nextRound,1,&owner,UUID{0});assert(!(nextKey==selected));
|
|
assert(admission.Resolve(&nextRound,1,&owner,UUID{0}).IsNull());
|
|
// Fresh network modes remain native even on an absent controller/local world,
|
|
// after Stop, on null backend data, and with changing native identities.
|
|
for(int mode: {1,2,3}){
|
|
sessionMode=mode;int before=generated;ERR_LocalAdmission network(&nextRound);game=nullptr;
|
|
assert(network.Resolve(&nextRound,9,nullptr,UUID{41})==UUID{41});
|
|
assert(network.Resolve(&nextRound,9,nullptr,UUID{0}).IsNull());
|
|
network.Stop();assert(network.Validate());
|
|
assert(network.Resolve(&nextRound,9,nullptr,UUID{42})==UUID{42});
|
|
assert(!network.Selected()&&!network.LocalKey()&&generated==before);game=&world;
|
|
}
|
|
// Incomplete local context cannot generate a key and cannot later self-repair.
|
|
sessionMode=0;manager.count=0;int before=generated;ERR_LocalAdmission invalid(&nextRound);
|
|
assert(invalid.Resolve(&nextRound,1,&owner,UUID{0}).IsNull()&&generated==before);
|
|
manager.count=1;assert(invalid.Resolve(&nextRound,1,&owner,UUID{0}).IsNull());
|
|
}
|
|
''')
|
|
print('PASS: actual local admission context/selection/latch, same-round late identity, replacement/mode failure, fresh round and untouched network path')
|