Files
EscapistsReintroduced/tests/test_casualty_feedback.py
T

146 lines
12 KiB
Python

"""Execute production feedback control flow; no native UI or network claim."""
from policy_harness import ROOT, body, run
service = ROOT/'addons/core/Scripts/Game/ERR/ERR_CasualtyLoadingService.c'
action = ROOT/'addons/core/Scripts/Game/ERR/ERR_LoadCasualtyAction.c'
feedback = ROOT/'addons/core/Scripts/Game/ERR/ERR_CasualtyLoadingFeedback.c'
def convert(s):
s=s.replace('protected ', '').replace('override ', '').replace('string.Empty','string{}').replace('.IsEmpty()', '.empty()')
for ns in ['Replication','System','ERR_CasualtyFeedback','ERR_Phase','ERR_CasualtyLoadingRules']:
s=s.replace(ns+'.',ns+'::')
s=s.replace('ERR_GameMode.Get()', 'Mode::Get()').replace('ERR_GameMode mode', 'Mode* mode').replace('ERR_GameMode.Cast','Mode::Cast')
s=s.replace('ERR_PlayerLife life','Life* life').replace('SCR_PlayerController controller = SCR_PlayerController.Cast(GetGame().GetPlayerManager().GetPlayerController(life.ConnectionId));','Controller* controller = GetGame()->GetPlayerManager()->GetPlayerController(life->ConnectionId);')
s=s.replace('ERR_CasualtyLoadTicket ticket','Ticket* ticket')
for v in ['mode','m_Mode','ticket','life','controller']:
s=s.replace(v+'.',v+'->')
s=s.replace('mode->CasualtyLoading().','mode->CasualtyLoading()->').replace('null','nullptr')
return s
methods='\n'.join(convert(body(service, sig)) for sig in ['string RejectionReason(', 'protected void NotifyCaller(', 'void Request(', 'protected void NotifyResolution('])
permission=convert(body(action,'override bool CanBePerformedScript('))
run(r'''
#include <cassert>
#include <string>
#include <vector>
using string=std::string;
struct Actor{int identity=1;};using IEntity=Actor*;
namespace Replication{bool server=true;bool IsServer(){return server;}}
namespace System{int GetTickCount(){return 10000;}}
namespace ERR_Phase{enum{EXTRACTION=4};}
struct Mode;struct Service;
struct Life{int ConnectionId=1;};
struct Controller{IEntity actor=nullptr;int messages=0;string last;IEntity GetControlledEntity(){return actor;}void ERR_CasualtyFeedback(Mode*,IEntity a,string s){assert(a==actor);messages++;last=s;}};
struct Manager{Controller* current=nullptr;Controller* GetPlayerController(int){return current;}};
struct Game{Manager manager;Manager* GetPlayerManager(){return &manager;}} game;Game* GetGame(){return &game;}
struct Mode{bool active=true;int phase=4;Service* service=nullptr;static Mode* current;static Mode* Get(){return current;}bool Active(){return active;}int Phase(){return phase;}Service* CasualtyLoading(){return service;}int ExtractionVehicle(){return 1;}};Mode* Mode::current=nullptr;
namespace ERR_CasualtyFeedback{string physical;string PhysicalReason(Mode*,IEntity,IEntity){return physical;}}
struct Ticket{bool FeedbackSubmitted=false;IEntity Caller=nullptr;int CallerAccount=1,CallerConnection=1;};
struct Service{
Mode* m_Mode;bool m_Stopped=false,settled=true,pending=false,seat=true,beginOK=true,same=true;int begins=0;Life life;IEntity admittedCaller=nullptr,admittedCasualty=nullptr;
Life* CurrentLife(IEntity a){return a&&(a==admittedCaller||a==admittedCasualty)?&life:nullptr;}
bool Settled(IEntity,int){return settled;}bool PendingActor(IEntity,IEntity){return pending;}bool AvailableSeat(IEntity,int){return seat;}
bool Begin(IEntity,IEntity){begins++;return beginOK;}bool SameLife(IEntity a,int account,int connection){return same&&CurrentLife(a)&&account==1&&connection==1;}
''' + methods + r'''
};
struct Action{string reason="old";IEntity target=nullptr;IEntity GetOwner(){return target;}void SetCannotPerformReason(string s){reason=s;}
''' + permission + r'''
};
int main(){
Mode mode;Service svc{&mode};mode.service=&svc;Mode::current=&mode;Actor caller,patient,stranger;svc.admittedCaller=&caller;svc.admittedCasualty=&patient;Controller controller;controller.actor=&caller;game.manager.current=&controller;Action action;action.target=&patient;
assert(action.CanBePerformedScript(&caller)&&action.reason.empty());
ERR_CasualtyFeedback::physical="No accessible transport seat is available";
assert(!action.CanBePerformedScript(&caller)&&action.reason==ERR_CasualtyFeedback::physical);
svc.Request(&caller,&patient);assert(svc.begins==0&&controller.messages==1);
ERR_CasualtyFeedback::physical.clear();assert(action.CanBePerformedScript(&caller)&&action.reason.empty());
svc.settled=false;assert(!action.CanBePerformedScript(&caller)&&action.reason.find("five seconds")!=string::npos);svc.settled=true;
svc.pending=true;assert(svc.RejectionReason(&caller,&patient).find("already")!=string::npos);svc.pending=false;
svc.seat=false;assert(svc.RejectionReason(&caller,&patient).find("seat")!=string::npos);svc.seat=true;
assert(svc.RejectionReason(&stranger,&patient).find("connected")!=string::npos);
int before=controller.messages;svc.Request(&stranger,&patient);assert(controller.messages==before&&svc.begins==0);
svc.beginOK=false;svc.Request(&caller,&patient);assert(svc.begins==1&&controller.messages==before+1&&controller.last.find("could not start")!=string::npos);
svc.beginOK=true;before=controller.messages;svc.Request(&caller,&patient);assert(svc.begins==2&&controller.messages==before);
Ticket ticket;ticket.Caller=&caller;
svc.NotifyResolution(&ticket,false);assert(controller.messages==before); // failed reservation before submission: Request gives exactly one failure
ticket.FeedbackSubmitted=true;svc.NotifyResolution(&ticket,true);assert(controller.messages==before);
svc.NotifyResolution(&ticket,false);assert(controller.messages==before+1&&controller.last.find("could not be confirmed")!=string::npos);
before=controller.messages;
svc.same=false;svc.NotifyResolution(&ticket,false);assert(controller.messages==before);svc.same=true;
ticket.CallerAccount=2;svc.NotifyResolution(&ticket,false);assert(controller.messages==before);ticket.CallerAccount=1;
ticket.CallerConnection=2;svc.NotifyResolution(&ticket,false);assert(controller.messages==before);ticket.CallerConnection=1;
controller.actor=&stranger;svc.NotifyResolution(&ticket,false);assert(controller.messages==before);controller.actor=&caller;
svc.m_Stopped=true;svc.NotifyResolution(&ticket,false);assert(controller.messages==before);svc.m_Stopped=false;
mode.active=false;svc.NotifyResolution(&ticket,false);assert(controller.messages==before);mode.active=true;
mode.phase=5;svc.NotifyResolution(&ticket,false);assert(controller.messages==before);mode.phase=4;
Replication::server=false;svc.Request(&caller,&patient);assert(svc.begins==2&&controller.messages==before);
// Client presentation never evaluates authoritative roster/settling: physical facts only.
svc.settled=false;assert(action.CanBePerformedScript(&caller)&&action.reason.empty());
ERR_CasualtyFeedback::physical="The helicopter must be upright, grounded and stationary";assert(!action.CanBePerformedScript(&caller));
}
''')
# Guard the unchanged transfer path and exact recipient channel around the tested logic.
owner=feedback.read_text()
assert '[RplRpc(RplChannel.Reliable, RplRcver.Owner)]' in owner
assert 'RplRcver.Broadcast' not in owner and 'RplRcver.Server' not in owner
send=body(feedback,'void ERR_CasualtyFeedback(')
for guard in ['!Replication.IsServer()', 'mode != ERR_GameMode.Get()', '!mode.Players().CurrentActor(actor)', 'GetPlayerController(GetPlayerId()) != this']:
assert guard in send
receive=body(feedback,'protected void ERR_CasualtyFeedbackOwner(')
for guard in ['this != GetGame().GetPlayerController()', 'EntityId(mode) != modeId', 'EntityId(GetControlledEntity()) != actorId', 'mode.Phase() != ERR_Phase.EXTRACTION']:
assert guard in receive
assert receive.index('EntityId(GetControlledEntity()) != actorId') < receive.index('ShowCustom(')
resolve=body(service,'protected void Resolve(')
assert resolve.index('m_Pending.Remove(index)') < resolve.index('NotifyResolution(ticket, success)') < resolve.index('m_OnResolved.Invoke')
begin=body(service,'bool Begin(')
assert begin.index('IsReservedBy(casualty)') < begin.index('ticket.FeedbackSubmitted = true') < begin.index('ERR_PrepareCasualtyLoad(')
print('PASS: actual action denial/clearing, server request failure, single submitted-result feedback, current rescuer identity and terminal/stop suppression; native UI/RPC pending')
physical=convert(body(feedback,'static string PhysicalReason(')).replace('static ','')
physical=physical.replace('Vehicle aircraft','Actor* aircraft').replace('aircraft.FindComponent(BaseCompartmentManagerComponent)','0')
physical=physical.replace('BaseCompartmentManagerComponent manager = BaseCompartmentManagerComponent.Cast(0);','Manager* manager = aircraft->manager;')
physical=physical.replace('array<BaseCompartmentSlot> seats = {}','std::vector<Seat*> seats').replace('foreach (BaseCompartmentSlot seat : seats)','for (Seat* seat : seats)')
for var in ['caller','casualty','aircraft','manager','seat']:
physical=physical.replace(var+'.',var+'->')
physical=physical.replace('vector.Distance','Distance').replace('ERR_Actors.','ERR_Actors::').replace('CompartmentAccessComponent.','CompartmentAccessComponent::')
run(r'''
#include <cassert>
#include <string>
#include <vector>
using string=std::string;
struct Actor;using IEntity=Actor*;
struct Seat{bool transport=true,occupied=false,reserved=false,accessible=true,locked=false;bool GetOccupant(){return occupied;}bool IsReserved(){return reserved;}bool IsCompartmentAccessible(){return accessible;}bool IsGetInLockedFor(IEntity){return locked;}};
struct Manager{std::vector<Seat*> seats;void GetCompartments(std::vector<Seat*>& out){out=seats;}};
struct Actor{bool conscious=true,aboard=false,settled=true,ready=true;Manager* manager=nullptr;int GetOrigin(){return 0;}};
struct Mode{bool active=true;int phase=4;Actor* aircraft=nullptr;bool Active(){return active;}int Phase(){return phase;}Actor* CasualtyLoadingAircraft(){return aircraft;}};
namespace ERR_Phase{enum{EXTRACTION=4};}
namespace ERR_Actors{bool CanFight(IEntity a){return a&&a->conscious;}}
namespace CompartmentAccessComponent{bool GetVehicleIn(IEntity a){return a->aboard;}}
float Distance(int,int){return 0;}
namespace ERR_CasualtyLoadingRules{
bool ranges=true,nearby=true;
bool GroundSettled(IEntity a){return a&&a->settled;}
bool Ranges(float,float,float){return ranges;}
bool AircraftReady(IEntity a){return a&&a->ready;}
bool Nearby(Mode*,IEntity,IEntity){return nearby;}
bool TransportBench(Seat* s,IEntity){return s&&s->transport;}
}
''' + physical + r'''
int main(){
Actor caller,patient,aircraft;Mode mode;mode.aircraft=&aircraft;Manager manager;aircraft.manager=&manager;Seat seat;manager.seats={nullptr,&seat};
assert(PhysicalReason(&mode,&caller,&patient).empty());
for(int mask=1;mask<16;mask++){
seat.occupied=mask&1;seat.reserved=mask&2;seat.accessible=!(mask&4);seat.locked=mask&8;
assert(PhysicalReason(&mode,&caller,&patient).find("seat")!=string::npos);
}
seat=Seat{};seat.transport=false;assert(PhysicalReason(&mode,&caller,&patient).find("seat")!=string::npos);seat.transport=true;
aircraft.manager=nullptr;assert(PhysicalReason(&mode,&caller,&patient).find("seat")!=string::npos);aircraft.manager=&manager;
mode.active=false;assert(PhysicalReason(&mode,&caller,&patient).find("Wait")!=string::npos);mode.active=true;
mode.phase=3;assert(!PhysicalReason(&mode,&caller,&patient).empty());mode.phase=4;
assert(!PhysicalReason(nullptr,&caller,&patient).empty());assert(!PhysicalReason(&mode,nullptr,&patient).empty());assert(!PhysicalReason(&mode,&patient,&patient).empty());
caller.conscious=false;assert(PhysicalReason(&mode,&caller,&patient).find("conscious rescuer")!=string::npos);caller.conscious=true;
caller.aboard=true;assert(PhysicalReason(&mode,&caller,&patient).find("Leave")!=string::npos);caller.aboard=false;
patient.settled=false;assert(PhysicalReason(&mode,&caller,&patient).find("stable ground")!=string::npos);patient.settled=true;
ERR_CasualtyLoadingRules::ranges=false;assert(PhysicalReason(&mode,&caller,&patient).find("twelve metres")!=string::npos);ERR_CasualtyLoadingRules::ranges=true;
aircraft.ready=false;assert(PhysicalReason(&mode,&caller,&patient).find("stationary")!=string::npos);aircraft.ready=true;
ERR_CasualtyLoadingRules::nearby=false;assert(PhysicalReason(&mode,&caller,&patient).find("clear access")!=string::npos);ERR_CasualtyLoadingRules::nearby=true;
assert(PhysicalReason(&mode,&caller,&patient).empty());
}
''')
print('PASS: actual physical denial precedence and transport-seat occupancy/reservation/access/lock checks')