Files
EscapistsReintroduced/tests/test_native_convoy_mine_stock.py
T
jakub 6a667d8deb Capture current mission, AI, map and administration development
Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
2026-10-13 22:52:53 +02:00

85 lines
9.2 KiB
Python

"""Execute the opt-in fixture's exact callback/custody/snapshot/Candidate methods."""
import os,re
from pathlib import Path
from policy_harness import ROOT,body,run
P=Path(os.environ.get('ERR_NATIVE_MOUNTED_AMMO_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeMountedAmmoProbe.c'))
s=P.read_text()
assert s.startswith('#ifdef WORKBENCH') and s.rstrip().endswith('#endif')
for forbidden in ('TryMove','TrySwap','TrySpawn','SpawnEntity','SetOrigin','SetAmmoCount','.Dispatch(','.Ingest(','.Advance('):assert forbidden not in s
constructor=body(P,'void ERR_NativeMountedAmmoProbe(')
assert 'errMineStock' in constructor and 'now + 180000' in constructor
assert 'm_MineStock && (m_SwapEligibility' in constructor and 'errMountedCourier' in constructor
fleet=body(P,'protected bool Fleet(');tick=body(P,'int Tick(')
assert fleet.index('Mines(task, true)')<fleet.index('m_ProofTask = task')
assert tick.index('actual HQ Watch holds separate copy')<tick.index('Mines(m_ProofTask, false)')<tick.rindex('return 1')
assert 'fixed 180-second mine-stock and radio proof deadline' in tick
def cpp(x):
x=x.replace('protected ','').replace('null','nullptr').replace('foreach (','for (')
x=x.replace('array<IEntity> items = {};','Array<IEntity> items;').replace('array<IEntity> unique = {};','Array<IEntity> unique;').replace('array<IEntity> items','Array<IEntity> items')
for t in ('ERR_HQ','ERR_SupplyConvoyTask','ERR_ConvoyVehicle','ERR_ConvoyMineStock','ERR_ConvoyMineCargo','ERR_ConvoyCargoCallback','InventoryStorageManagerComponent','InventoryItemComponent','InventoryStorageSlot'):
x=re.sub(r'\b'+t+r' (?=\w)',t+'* ',x)
for n in ('InventoryStorageManagerComponent','InventoryItemComponent','ERR_InfantryAmmoTransfer','ERR_InfantryMineTransfer','ERR_Inventory','ERR_SupplyConvoyTask'):
x=x.replace(n+'.',n+'::')
x=x.replace('FindComponent(InventoryStorageManagerComponent)','Inventory()').replace('FindComponent(InventoryItemComponent)','Carried()').replace('FindComponent(DamageManagerComponent)','damage')
for n in ('m_Truck','m_Inventory','original','item','operation','carried','slot','task','truck','batch','inventory','hq','pending','vehicle','m_MineBatch'):
x=re.sub(r'\b'+n+r'\.',n+'->',x)
x=x.replace('truck->Entity.','truck->Entity->').replace('GetStorage().','GetStorage()->').replace('Convoys().','Convoys()->').replace('task->MineStock.','task->MineStock->')
x=re.sub(r'task->Cargo\[cargo\]\.',r'task->Cargo[cargo]->',x)
x=x.replace('bool ownsRoot;', 'bool ownsRoot=false;')
return x
callback=cpp(body(P,'bool ERR_FixtureMine('))
methods='\n'.join(cpp(body(P,k)) for k in ('protected bool MineCustody(', 'protected bool Mines(', 'protected ERR_SupplyConvoyTask Candidate('))
run(r'''
#include <cassert>
#include <vector>
#include <string>
#include <algorithm>
using string=std::string;
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;int Count(){return this->size();}bool Contains(T x){return std::find(this->begin(),this->end(),x)!=this->end();}void Insert(T x){this->push_back(x);}};
struct Entity;using IEntity=Entity*;struct InventoryStorageManagerComponent;struct InventoryItemComponent;struct InventoryStorageSlot;
struct Entity{bool ready=true,damage=true;IEntity under=nullptr;InventoryStorageManagerComponent*inventory=nullptr;InventoryItemComponent*carried=nullptr;InventoryStorageManagerComponent* Inventory(){return inventory;}InventoryItemComponent* Carried(){return carried;}};
struct Storage{InventoryStorageSlot*slot=nullptr;InventoryStorageSlot*GetSlot(int){return slot;}};
struct InventoryStorageSlot{IEntity item=nullptr;Storage*storage=nullptr;IEntity GetAttachedEntity(){return item;}Storage*GetStorage(){return storage;}int GetID(){return 0;}};
struct InventoryItemComponent{InventoryStorageSlot*slot=nullptr;InventoryStorageSlot*GetParentSlot(){return slot;}static auto Cast(InventoryItemComponent*x){return x;}};
struct InventoryStorageManagerComponent{IEntity owner=nullptr;Array<IEntity>items;IEntity GetOwner(){return owner;}static auto Cast(InventoryStorageManagerComponent*x){return x;}};
struct ERR_Inventory{static void Items(InventoryStorageManagerComponent*i,Array<IEntity>&items){items=i->items;}};
struct ERR_InfantryMineTransfer{static bool ReadyMine(IEntity i){return i&&i->ready;}};
struct ERR_InfantryAmmoTransfer{static bool StoredUnder(IEntity i,IEntity root){return i&&i->under==root;}};
struct ERR_ConvoyMineStock;
struct ERR_ConvoyVehicle{IEntity Entity=nullptr;bool Registered=true,Released=false;};
struct ERR_ConvoyCargoCallback{bool Finished=true;};
struct ERR_ConvoyMineCargo{bool Finished=true,Succeeded=true;IEntity Item=nullptr;};
struct ERR_SupplyConvoyTask{bool Stopped=false,Ready=true,MagazinesIssued=true;void*Receipt=this;Array<ERR_ConvoyVehicle*>Vehicles;Array<ERR_ConvoyCargoCallback*>Cargo;ERR_ConvoyMineStock*MineStock=nullptr;static auto Cast(ERR_SupplyConvoyTask*x){return x;}};
struct ERR_ConvoyMineStock{bool m_Closed=true;ERR_SupplyConvoyTask*m_Task=nullptr;ERR_ConvoyVehicle*m_Original=nullptr;IEntity m_Truck=nullptr;InventoryStorageManagerComponent*m_Inventory=nullptr;Array<IEntity>m_Items;Array<ERR_ConvoyMineCargo*>m_Cargo;
bool Complete(){return m_Closed;}int Count(){return m_Items.Count();}IEntity At(int i){return m_Items[i];}
'''+callback+r'''};
struct Pool{Array<ERR_SupplyConvoyTask*>tasks;int Count(){return tasks.Count();}ERR_SupplyConvoyTask*At(int i){return tasks[i];}};
struct ERR_HQ{Pool pool;Pool*Convoys(){return &pool;}};
template<class...T>void PrintFormat(T...){}
struct Probe{ERR_SupplyConvoyTask*m_ProofTask=nullptr;bool m_MineStock=true,m_Failed=false;ERR_ConvoyMineStock*m_MineBatch=nullptr;ERR_ConvoyVehicle*m_MineTruck=nullptr;InventoryStorageManagerComponent*m_MineInventory=nullptr;Array<IEntity>m_Mines;Array<ERR_ConvoyCargoCallback*>m_PrimaryCargo;void*m_Queued=nullptr;IEntity m_Root=nullptr;
bool Check(bool yes,string){if(!yes)m_Failed=true;return yes;}
'''+methods+r'''};
struct F{Probe p;ERR_HQ h;ERR_SupplyConvoyTask task;ERR_ConvoyVehicle vehicle;ERR_ConvoyMineStock batch;Entity truck,a,b;InventoryStorageManagerComponent inventory;Storage storageA,storageB;InventoryStorageSlot slotA,slotB;InventoryItemComponent itemA,itemB;ERR_ConvoyMineCargo callbackA,callbackB;ERR_ConvoyCargoCallback primary;
F(){vehicle.Entity=&truck;task.Vehicles={&vehicle,&vehicle,&vehicle,&vehicle,&vehicle,&vehicle};task.Cargo={&primary};task.MineStock=&batch;h.pool.tasks={&task};truck.inventory=&inventory;inventory.owner=&truck;inventory.items={&a,&b};
a.under=b.under=&truck;a.carried=&itemA;b.carried=&itemB;itemA.slot=&slotA;itemB.slot=&slotB;slotA.item=&a;slotB.item=&b;slotA.storage=&storageA;slotB.storage=&storageB;storageA.slot=&slotA;storageB.slot=&slotB;
callbackA.Item=&a;callbackB.Item=&b;batch.m_Task=&task;batch.m_Original=&vehicle;batch.m_Truck=&truck;batch.m_Inventory=&inventory;batch.m_Items={&a,&b};batch.m_Cargo={&callbackA,&callbackB};}
};
int main(){
{F f;assert(f.p.Candidate(&f.h)==&f.task&&f.p.Mines(&f.task,true));assert(f.p.m_Mines.Count()==2&&f.p.Mines(&f.task,false));}
{F f;f.batch.m_Items.pop_back();assert(f.p.Mines(&f.task,true)&&f.p.Mines(&f.task,false));}
{F f;f.batch.m_Closed=false;assert(!f.p.Candidate(&f.h));f.p.m_MineStock=false;assert(f.p.Candidate(&f.h)==&f.task);assert(f.p.Mines(nullptr,false));}
{F f;ERR_SupplyConvoyTask other=f.task;f.h.pool.tasks.push_back(&other);f.batch.m_Closed=false;assert(!f.p.Candidate(&f.h)&&f.p.m_ProofTask==&f.task);f.task.MineStock=nullptr;assert(!f.p.Candidate(&f.h)&&f.p.m_ProofTask==&f.task);f.task.MineStock=&f.batch;f.batch.m_Closed=true;assert(f.p.Candidate(&f.h)==&f.task);}
{F f;f.batch.m_Closed=false;assert(!f.p.Candidate(&f.h)&&f.p.m_MineBatch==&f.batch);ERR_ConvoyMineStock other=f.batch;other.m_Closed=true;f.task.MineStock=&other;assert(!f.p.Candidate(&f.h)&&f.p.m_Failed&&f.p.m_MineBatch==&f.batch);}
{F f;f.primary.Finished=false;assert(!f.p.Candidate(&f.h));f.primary.Finished=true;f.p.m_Queued=&f;Entity foreign;f.p.m_Root=&foreign;assert(!f.p.Candidate(&f.h));f.p.m_Root=&f.truck;assert(f.p.Candidate(&f.h)==&f.task);}
for(int bad=0;bad<14;bad++){F f;
if(bad==0){f.batch.m_Items.clear();}if(bad==1){f.batch.m_Items.push_back(&f.a);}if(bad==2){f.batch.m_Items[1]=&f.a;}if(bad==3){f.callbackA.Succeeded=false;}if(bad==4){f.callbackA.Finished=false;}if(bad==5){f.a.ready=false;}if(bad==6){f.a.damage=false;}if(bad==7){f.a.under=&f.b;}if(bad==8){f.inventory.items.erase(f.inventory.items.begin());}if(bad==9){f.slotA.item=&f.b;}if(bad==10){f.storageA.slot=&f.slotB;}if(bad==11){f.vehicle.Released=true;}if(bad==12){f.inventory.owner=&f.b;}if(bad==13){f.inventory.items.resize(129,&f.a);}
assert(!f.p.Mines(&f.task,true)&&f.p.m_Failed);}
for(int bad=0;bad<6;bad++){F f;assert(f.p.Mines(&f.task,true));ERR_ConvoyCargoCallback other;ERR_ConvoyMineStock replacement=f.batch;
if(bad==0){f.task.MineStock=&replacement;}if(bad==1){std::swap(f.batch.m_Items[0],f.batch.m_Items[1]);}if(bad==2){f.batch.m_Items.pop_back();}if(bad==3){f.task.Cargo[0]=&other;}if(bad==4){f.primary.Finished=false;}if(bad==5){f.inventory.items.clear();}
assert(!f.p.Mines(&f.task,false)&&f.p.m_Failed);}
{F f;f.batch.m_Truck=nullptr;assert(!f.batch.ERR_FixtureMine(&f.task,&f.vehicle,&f.a));}
}
''')
print('PASS: actual optional candidate barrier, exact callback/custody proof and unchanged mine/primary snapshots; no native transfer claim')