Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
193 lines
19 KiB
Python
193 lines
19 KiB
Python
"""Actual admission seed and one-time issuance methods; native boundaries are controlled doubles."""
|
|
import os,re
|
|
from pathlib import Path
|
|
from policy_harness import ROOT,body,run
|
|
R=Path(os.environ.get('ERR_MOUNTED_STOCK_ROOT',ROOT));D=R/'addons/core/Scripts/Game/ERR/10_AI'
|
|
seed=(D/'ERR_MountedMagazineSeed.c').read_text()
|
|
assert 'GetDefaultMagazineOrProjectileName' not in seed and 'IsUsed(' not in seed
|
|
for forbidden in ('TrySpawn','SetAmmoCount','DeleteEntity','GetChildren','GetSibling'):assert forbidden not in seed
|
|
s=re.sub(r'//[^\n]*','',seed).replace('protected ','').replace('ref ','').replace('class ERR_MountedMagazineSeed : ERR_HQMountedAmmoSampler','struct ERR_MountedMagazineSeed : ERR_HQMountedAmmoSampler')
|
|
for old,new in {
|
|
'InventoryItemComponent.Cast(gun.FindComponent(InventoryItemComponent))':'gun->item',
|
|
'InventoryItemComponent.Cast(loaded.FindComponent(InventoryItemComponent))':'loaded->item',
|
|
'InventoryItemComponent.Cast(weapon.GetOwner().FindComponent(InventoryItemComponent))':'weapon->GetOwner()->item',
|
|
'WeaponSlotComponent.Cast(weaponSlot.GetParentContainer())':'dynamic_cast<Mount*>(weaponSlot->GetParentContainer())',
|
|
}.items():s=s.replace(old,new)
|
|
s=s.replace('array<ERR_MountedMagazineSeed> seeds','Array<ERR_MountedMagazineSeed*>& seeds').replace('array<','Array<').replace('foreach (','for (')
|
|
s=re.sub(r'\bERR_MountedMagazineSeed (seed)\b',r'ERR_MountedMagazineSeed* \1',s)
|
|
s=s.replace('ERR_HQMountedAmmoSnapshot shape','ERR_HQMountedAmmoSnapshot* shape').replace('ERR_ConvoyRules.','ERR_ConvoyRules::').replace('EMuzzleType.','EMuzzleType::')
|
|
for obj in ['m_Weapon','m_Mount','m_WeaponSlot','m_Muzzle','m_Magazine','m_MagazineSlot','gun','loaded','gunItem','magazineItem','storage','shape','weapon','weaponSlot','mount','muzzle','magazine','item','seed']:
|
|
s=re.sub(r'\b'+obj+r'\.',obj+'->',s)
|
|
for call in ['GetPrefabData()','GetMagazineWell()','GetOwner()']:s=s.replace(call+'.',call+'->')
|
|
s=s.replace('!seeds || ','') # native array parameter reference is non-null in C++ fixture
|
|
s=re.sub(r'\b(IEntity|BaseWeaponComponent|WeaponSlotComponent|InventoryStorageSlot|BaseMuzzleComponent|BaseMagazineComponent|int) (\w+);',r'\1 \2{};',s).replace('\n}\n','\n};\n')
|
|
common=r'''
|
|
#include <cassert>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
struct string:std::string{using std::string::string;string(std::string s):std::string(s){}bool IsEmpty(){return empty();}};using ResourceName=string;
|
|
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;int Count(){return this->size();}void Insert(T t){this->push_back(t);}bool Contains(T t){return std::find(this->begin(),this->end(),t)!=this->end();}};
|
|
struct Entity;struct Weapon;struct Muzzle;struct Magazine;struct Slot;
|
|
using IEntity=Entity*;using BaseWeaponComponent=Weapon*;using BaseMuzzleComponent=Muzzle*;using BaseMagazineComponent=Magazine*;
|
|
struct Well{int type=1;int Type(){return type;}bool IsInherited(int other){return type==other;}};
|
|
struct Prefab{string name="AP-box";string GetPrefabName(){return name;}};
|
|
struct Item{Slot* slot=nullptr;Slot* GetParentSlot(){return slot;}};using InventoryItemComponent=Item*;
|
|
struct Entity{Entity* parent=nullptr;Item* item=nullptr;Prefab* prefab=nullptr;Array<IEntity>allowed;Array<Weapon*> weapons;bool complete=true;Prefab* GetPrefabData(){return prefab;}};
|
|
struct Container{IEntity owner=nullptr;virtual ~Container(){}IEntity GetOwner(){return owner;}};
|
|
struct Storage:Container{};using BaseInventoryStorageComponent=Storage*;
|
|
struct Slot{Container* parent=nullptr;Storage* storage=nullptr;IEntity attached=nullptr;Container* GetParentContainer(){return parent;}IEntity GetAttachedEntity(){return attached;}Storage* GetStorage(){return storage;}};using InventoryStorageSlot=Slot*;
|
|
struct Magazine:Container{Well* well=nullptr;int capacity=100,rounds=99;Well* GetMagazineWell(){return well;}int GetMaxAmmoCount(){return capacity;}int GetAmmoCount(){return rounds;}};
|
|
struct Muzzle:Container{Magazine* magazine=nullptr;Well* well=nullptr;int kind=0;Magazine* GetMagazine(){return magazine;}Well* GetMagazineWell(){return well;}int GetMuzzleType(){return kind;}};
|
|
struct Weapon:Container{Array<Muzzle*> muzzles;void GetMuzzlesList(Array<Muzzle*>& out){out=muzzles;}};
|
|
struct Mount:Container{Slot* slot=nullptr;IEntity gun=nullptr;Slot* GetSlotInfo(){return slot;}IEntity GetWeaponEntity(){return gun;}};using WeaponSlotComponent=Mount*;
|
|
struct EMuzzleType{static const int MT_BaseMuzzle=0;};
|
|
struct ERR_ConvoyRules{static bool PartOf(IEntity a,IEntity root){for(int n=0;a&&n<32;n++,a=a->parent)if(a==root)return true;return false;}};
|
|
struct ERR_HQMountedAmmoSnapshot{bool Complete=false;};
|
|
struct ERR_HQMountedAmmoSampler{static void Collect(IEntity root,ERR_HQMountedAmmoSnapshot* result,Array<IEntity>& allowed,Array<Weapon*>& weapons){result->Complete=root->complete;allowed=root->allowed;weapons=root->weapons;}};
|
|
'''
|
|
run(common+s+r'''
|
|
struct Rig{Entity root,gun,loaded;Item gunItem,magItem;Prefab prefab;Slot gunSlot,magSlot;Mount mount;Storage storage;Weapon weapon;Muzzle muzzle;Magazine magazine;Well well;
|
|
Rig(){gun.parent=&root;loaded.parent=&gun;gun.item=&gunItem;loaded.item=&magItem;loaded.prefab=&prefab;
|
|
gunItem.slot=&gunSlot;magItem.slot=&magSlot;gunSlot.parent=&mount;gunSlot.attached=&gun;magSlot.parent=&muzzle;magSlot.attached=&loaded;magSlot.storage=&storage;storage.owner=&gun;
|
|
mount.owner=&root;mount.slot=&gunSlot;mount.gun=&gun;weapon.owner=&gun;weapon.muzzles={&muzzle,&muzzle};muzzle.owner=&gun;muzzle.magazine=&magazine;muzzle.well=&well;
|
|
magazine.owner=&loaded;magazine.well=&well;root.allowed={&root,&gun,&loaded};root.weapons={&weapon,&weapon};}
|
|
};
|
|
int main(){
|
|
{Rig r;Array<ERR_MountedMagazineSeed*> seeds;ERR_MountedMagazineSeed::Capture(&r.root,0,seeds);assert(seeds.Count()==1&&seeds[0]->Current()&&seeds[0]->Prefab=="AP-box");
|
|
assert(seeds[0]->Root==&r.root&&seeds[0]->VehicleIndex==0);r.magazine.rounds=0;assert(seeds[0]->Current());
|
|
Magazine replacement=r.magazine;r.muzzle.magazine=&replacement;assert(!seeds[0]->Current());r.muzzle.magazine=&r.magazine;
|
|
r.prefab.name="replacement-box";assert(!seeds[0]->Current());}
|
|
for(int fault=0;fault<16;fault++){Rig r;Entity other;Slot replacement;Well wrong;wrong.type=2;
|
|
if(fault==0)r.root.complete=false;
|
|
if(fault==1)r.root.allowed={&r.root,&r.gun};
|
|
if(fault==2)r.muzzle.magazine=nullptr;
|
|
if(fault==3)r.loaded.prefab=nullptr;
|
|
if(fault==4)r.prefab.name="";
|
|
if(fault==5)r.muzzle.kind=1;
|
|
if(fault==6)r.magazine.well=nullptr;
|
|
if(fault==7)r.magazine.well=&wrong;
|
|
if(fault==8)r.magazine.capacity=0;
|
|
if(fault==9)r.magazine.rounds=101;
|
|
if(fault==10)r.storage.owner=&other;
|
|
if(fault==11)r.magItem.slot=&replacement;
|
|
if(fault==12)r.mount.gun=&other;
|
|
if(fault==13)r.gunSlot.attached=&other;
|
|
if(fault==14)r.weapon.muzzles.resize(9,&r.muzzle);
|
|
if(fault==15)r.magazine.rounds=-1;
|
|
Array<ERR_MountedMagazineSeed*> seeds;ERR_MountedMagazineSeed::Capture(&r.root,0,seeds);assert(seeds.Count()==0);}
|
|
{Rig r;Array<ERR_MountedMagazineSeed*> seeds;ERR_MountedMagazineSeed::Capture(&r.root,6,seeds);assert(seeds.Count()==0);seeds.resize(48,nullptr);ERR_MountedMagazineSeed::Capture(&r.root,0,seeds);assert(seeds.Count()==48);}
|
|
{Rig a,b;Array<ERR_MountedMagazineSeed*> seeds;ERR_MountedMagazineSeed::Capture(&a.root,0,seeds);ERR_MountedMagazineSeed::Capture(&b.root,3,seeds);assert(seeds.Count()==2);}
|
|
}
|
|
''')
|
|
print('PASS: actual admission seeds use exact installed loaded prefab, reject replacement/foreign/projectile paths and preserve bounded immutable identity')
|
|
service=D/'ERR_SupplyConvoyService.c'
|
|
raw=service.read_text()
|
|
assert raw.index('CaptureMountedStock(supply)') < raw.index('for (int i = 0; i < 8; i++)')
|
|
assert raw.index('task.MagazinesIssued = true;',raw.index('protected void IssueMagazines')) < raw.index('IssueMountedStock(task, inventory, issued,')
|
|
assert 'ref array<ref ERR_MountedMagazineSeed> MountedStock' in (D/'ERR_SupplyConvoyTactics.c').read_text()
|
|
code='\n'.join(body(service,x) for x in ['protected bool MountedStockOwner(', 'protected void CaptureMountedStock(', 'protected int IssueMountedStock(', 'protected void IssueMagazines('])
|
|
code=re.sub(r'//[^\n]*','',code).replace('protected ','').replace('null','nullptr').replace('foreach (','for (').replace('array<','Array<')
|
|
for old,new in {
|
|
'ERR_HQ.Cast(m_Mode.Command())':'m_Mode->Command()',
|
|
'InventoryStorageManagerComponent.Cast(task.Vehicles[1].Entity.FindComponent(InventoryStorageManagerComponent))':'task->Vehicles[1]->Entity->inventory',
|
|
'BaseWeaponComponent.Cast(item.FindComponent(BaseWeaponComponent))':'item->weapon',
|
|
'existing.FindComponent(BaseMagazineComponent)':'existing->magazine',
|
|
}.items():code=code.replace(old,new)
|
|
for typ in ['ERR_SupplyConvoyTask','ERR_HQ','ERR_ConvoyVehicle','ERR_ForceRecord','InventoryStorageManagerComponent','ERR_MountedMagazineSeed','ERR_ConvoyCargoCallback','BaseWeaponComponent','BaseMuzzleComponent']:
|
|
code=re.sub(r'\b'+typ+r' (?=\w)',typ+'* ',code)
|
|
code=code.replace('Array<BaseMuzzleComponent>', 'Array<BaseMuzzleComponent*>')
|
|
for name in ['m_Mode','task','vehicle','hq','record','inventory','seed','load','operation','item','weaponOperation','weapon','muzzle']:
|
|
code=re.sub(r'\b'+name+r'\.',name+'->',code)
|
|
for call in ['Forces()','GetPrefabData()']:code=code.replace(call+'.',call+'->')
|
|
code=code.replace('->Receipt.','->Receipt->').replace('Vehicles[index].','Vehicles[index]->').replace('Vehicles[1].','Vehicles[1]->').replace('Vehicles[seed->VehicleIndex].','Vehicles[seed->VehicleIndex]->')
|
|
for ns in ['ERR_MountedMagazineSeed','ERR_Inventory','EStoragePurpose','ERR_HQ','string']:code=code.replace(ns+'.',ns+'::')
|
|
code=code.replace('int existingMagazines;', 'int existingMagazines=0;').replace('int issued;', 'int issued=0;')
|
|
run(r'''
|
|
#include <cassert>
|
|
#include <algorithm>
|
|
#include <vector>
|
|
#include <string>
|
|
struct string:std::string{using std::string::string;string(std::string s):std::string(s){}bool IsEmpty(){return empty();}template<class...T>static string Format(T...){return "event";}};using ResourceName=string;
|
|
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;int Count(){return this->size();}void Insert(T t){this->push_back(t);}void Clear(){this->clear();}bool Contains(T t){return std::find(this->begin(),this->end(),t)!=this->end();}int Find(T t){auto f=std::find(this->begin(),this->end(),t);return f==this->end()?-1:f-this->begin();}void Remove(int i){this->erase(this->begin()+i);}};
|
|
struct Entity;using IEntity=Entity*;struct InventoryStorageManagerComponent;struct BaseWeaponComponent;
|
|
struct Prefab{string name;string GetPrefabName(){return name;}};
|
|
struct Entity{InventoryStorageManagerComponent* inventory=nullptr;BaseWeaponComponent* weapon=nullptr;bool magazine=false;Prefab prefab;Prefab* GetPrefabData(){return &prefab;}};
|
|
struct BaseMuzzleComponent{string resource="rifle-mag";string GetDefaultMagazineOrProjectileName(){return resource;}};
|
|
struct BaseWeaponComponent{Array<BaseMuzzleComponent*> muzzles;void GetMuzzlesList(Array<BaseMuzzleComponent*>& out){out=muzzles;}};
|
|
struct Group{int id=0;IEntity bound=nullptr;bool valid=true;};
|
|
struct ERR_ForceRecord{int Id=0;};struct Ledger{Array<ERR_ForceRecord>records;ERR_ForceRecord* FindGroup(Group* g){return g&&g->id<records.Count()?&records[g->id]:nullptr;}};
|
|
struct ERR_HQ{static void Event(string,string){}bool ValidateBoundVehicle(Group* g,IEntity e){return g&&g->valid&&g->bound==e;}};
|
|
struct Mode{Ledger ledger;ERR_HQ hq;Ledger* Forces(){return &ledger;}ERR_HQ* Command(){return &hq;}};
|
|
struct ERR_ConvoyVehicle{int Index=0;bool Registered=true,Released=false,crew=true;IEntity Entity=nullptr;struct Group* Group=nullptr;bool CrewValid(Mode*){return crew;}};
|
|
struct Receipt{bool Consumed=true;Array<int>Records={0,1,2,3,4,5};string SourceId="convoy";};
|
|
struct ERR_ConvoyCargoCallback{string Prefab;bool Finished=true,Succeeded=true;};
|
|
struct ERR_MountedMagazineSeed{IEntity Root=nullptr;int VehicleIndex=0;string Prefab="PKM-box";bool valid=true;bool Current(){return valid;}static inline int captures=0;static void Capture(IEntity,int,Array<ERR_MountedMagazineSeed*>&){captures++;}};
|
|
struct ERR_SupplyConvoyTask{bool Ready=true,Stopped=false,MagazinesIssued=false,CargoIssued=true;float Deadline=100;struct Receipt receipt;struct Receipt* Receipt=&receipt;Array<ERR_ConvoyVehicle*>Vehicles;Array<ERR_ConvoyCargoCallback*>Cargo;Array<ERR_MountedMagazineSeed*>MountedStock;Array<IEntity>CargoBefore;};
|
|
struct EStoragePurpose{static const int PURPOSE_DEPOSIT=1;};
|
|
struct InventoryStorageManagerComponent{IEntity owner=nullptr;Array<IEntity>items;Array<string>requests;bool accept=true,inlineDone=false;Entity spawned;IEntity GetOwner(){return owner;}
|
|
bool TrySpawnPrefabToStorage(string p,void*,int,int,ERR_ConvoyCargoCallback* cb){requests.Insert(p);cb->Finished=inlineDone;if(inlineDone){spawned.magazine=true;items.Insert(&spawned);}return accept;}};
|
|
struct ERR_Inventory{static void Items(InventoryStorageManagerComponent* i,Array<IEntity>& items){items=i->items;}};
|
|
struct Service{Mode* m_Mode;
|
|
'''+code+r'''
|
|
};
|
|
struct Fixture{Mode mode;Service service{&mode};ERR_SupplyConvoyTask task;InventoryStorageManagerComponent inventory;Array<Entity>roots{6},cargo{8},extra{129};Array<Group>groups{6};Array<ERR_ConvoyVehicle>vehicles{6};Array<BaseWeaponComponent>weapons{8};BaseMuzzleComponent muzzle;Array<ERR_ConvoyCargoCallback>callbacks{8};Array<ERR_MountedMagazineSeed>seeds{9};
|
|
Fixture(){mode.ledger.records.resize(6);for(int i=0;i<6;i++){groups[i].id=i;groups[i].bound=&roots[i];vehicles[i].Index=i;vehicles[i].Entity=&roots[i];vehicles[i].Group=&groups[i];task.Vehicles.Insert(&vehicles[i]);mode.ledger.records[i].Id=i;}
|
|
roots[1].inventory=&inventory;inventory.owner=&roots[1];
|
|
for(int i=0;i<8;i++){cargo[i].prefab.name="weapon"+std::to_string(i);cargo[i].weapon=&weapons[i];weapons[i].muzzles={&muzzle};callbacks[i].Prefab=cargo[i].prefab.name;task.Cargo.Insert(&callbacks[i]);inventory.items.Insert(&cargo[i]);}
|
|
for(int i=0;i<9;i++){seeds[i].Root=&roots[0];seeds[i].Prefab="box"+std::to_string(i);task.MountedStock.Insert(&seeds[i]);}}
|
|
};
|
|
int main(){
|
|
{Fixture f;f.service.IssueMagazines(&f.task,0);assert(f.task.MagazinesIssued&&f.inventory.requests.Count()==64&&f.task.Cargo.Count()==72&&f.task.MountedStock.Count()==0);
|
|
for(int i=0;i<48;i++)assert(f.inventory.requests[i]=="rifle-mag");for(int i=48;i<64;i++)assert(f.inventory.requests[i]=="box"+std::to_string((i-48)/2));
|
|
f.service.IssueMagazines(&f.task,99999);assert(f.inventory.requests.Count()==64);}
|
|
{Fixture f;f.callbacks[0].Finished=false;f.service.IssueMagazines(&f.task,0);assert(!f.task.MagazinesIssued&&f.inventory.requests.Count()==0);f.callbacks[0].Finished=true;f.service.IssueMagazines(&f.task,1);assert(f.inventory.requests.Count()==64);}
|
|
for(int missing=0;missing<2;missing++){Fixture f;
|
|
if(missing==0)f.callbacks[0].Finished=false;else f.task.Cargo[0]=nullptr;
|
|
f.service.IssueMagazines(&f.task,30100);
|
|
assert(f.task.MagazinesIssued&&f.inventory.requests.Count()==42&&f.task.MountedStock.Count()==0);
|
|
for(auto request:f.inventory.requests){assert(request=="rifle-mag");}
|
|
f.callbacks[0].Finished=true;f.task.Cargo[0]=&f.callbacks[0];
|
|
f.service.IssueMagazines(&f.task,99999);assert(f.inventory.requests.Count()==42);}
|
|
{Fixture f;f.inventory.accept=false;f.service.IssueMagazines(&f.task,0);assert(f.inventory.requests.Count()==64);for(auto cb:f.task.Cargo){assert(cb->Finished);}f.service.IssueMagazines(&f.task,99999);assert(f.inventory.requests.Count()==64);}
|
|
{Fixture f;f.inventory.inlineDone=true;f.service.IssueMagazines(&f.task,0);assert(f.inventory.requests.Count()==64);}
|
|
{Fixture f;f.service.IssueMountedStock(&f.task,&f.inventory,80,8,20);assert(f.inventory.requests.Count()==8);} //96 existing+attempts
|
|
{Fixture f;int total=f.service.IssueMountedStock(&f.task,&f.inventory,48,0,79);assert(total==49&&f.inventory.requests.Count()==1);} //128allitems
|
|
{Fixture f;f.task.Cargo.resize(127,&f.callbacks[0]);assert(f.service.IssueMountedStock(&f.task,&f.inventory,48,0,8)==49&&f.task.Cargo.Count()==128);}
|
|
{Fixture f;for(auto& seed:f.seeds){seed.Prefab="same";}assert(f.service.IssueMountedStock(&f.task,&f.inventory,48,0,8)==50);}
|
|
for(int bad=0;bad<8;bad++){Fixture f;
|
|
if(bad==0)f.vehicles[1].crew=false;if(bad==1)f.groups[1].valid=false;if(bad==2)f.mode.ledger.records[1].Id=9;
|
|
if(bad==3)f.task.Ready=false;if(bad==4)f.task.Receipt->Consumed=false;
|
|
if(bad==5)for(auto& seed:f.seeds)seed.valid=false;
|
|
if(bad==6)f.task.Vehicles[0]=&f.vehicles[3];if(bad==7)f.groups[0].valid=false;
|
|
assert(f.service.IssueMountedStock(&f.task,&f.inventory,48,0,8)==48&&f.inventory.requests.Count()==0);}
|
|
{Fixture f;f.inventory.items.clear();for(auto& e:f.extra){f.inventory.items.Insert(&e);}f.service.IssueMagazines(&f.task,0);
|
|
assert(f.task.MagazinesIssued&&f.inventory.requests.Count()==0&&f.task.MountedStock.Count()==0&&f.task.CargoBefore.Count()==0);}
|
|
{Fixture f;f.service.CaptureMountedStock(&f.task);assert(ERR_MountedMagazineSeed::captures==6);f.groups[1].valid=false;f.service.CaptureMountedStock(&f.task);assert(ERR_MountedMagazineSeed::captures==6);}
|
|
}
|
|
'''.replace(';if(', ';\n if(').replace(';for(', ';\n for('))
|
|
print('PASS: actual primary-before-mounted one-shot batch, shared96/128 caps, physical snapshot headroom, original ownership, callback refusal and admission pinning')
|
|
lookup=body(D/'ERR_HQ.c','bool ValidateBoundVehicle(SCR_AIGroup group, IEntity vehicle)')
|
|
lookup=lookup.replace('Replication.','Replication::').replace('null','nullptr')
|
|
for typ in ['SCR_AIGroup','IEntity','ERR_HQUnit']:lookup=re.sub(r'\b'+typ+r' (?=\w)',typ+'* ',lookup)
|
|
lookup=lookup.replace('unit.','unit->').replace('StatusSampler.','StatusSampler->')
|
|
run(r'''
|
|
#include <cassert>
|
|
#include <vector>
|
|
struct Replication{static inline bool server=true;static bool IsServer(){return server;}};
|
|
struct SCR_AIGroup{};struct IEntity{};
|
|
struct Sampler{SCR_AIGroup* group;IEntity* root;bool valid=true;int calls=0;bool OwnsRoster(SCR_AIGroup* g){return g==group;}bool ValidateBoundVehicle(IEntity* r){calls++;return valid&&root==r;}};
|
|
struct ERR_HQUnit{SCR_AIGroup* Group;Sampler* StatusSampler;};
|
|
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;int Count(){return this->size();}};
|
|
struct HQ{bool m_Mode=true;Array<ERR_HQUnit*>m_Units;
|
|
'''+lookup+r'''
|
|
};
|
|
int main(){SCR_AIGroup group,other;IEntity root,replacement;Sampler sampler{&group,&root};ERR_HQUnit unit{&group,&sampler};HQ h;h.m_Units={nullptr,&unit};
|
|
assert(h.ValidateBoundVehicle(&group,&root)&&!h.ValidateBoundVehicle(&group,&replacement)&&sampler.root==&root);
|
|
assert(!h.ValidateBoundVehicle(&other,&root));sampler.valid=false;assert(!h.ValidateBoundVehicle(&group,&root));sampler.valid=true;
|
|
int calls=sampler.calls;Replication::server=false;assert(!h.ValidateBoundVehicle(&group,&root)&&sampler.calls==calls);Replication::server=true;
|
|
h.m_Units.assign(256,nullptr);h.m_Units.push_back(&unit);assert(!h.ValidateBoundVehicle(&group,&root)&&sampler.calls==calls);
|
|
}
|
|
''')
|
|
print('PASS: actual bounded HQ query validates only existing original binding without admission or replacement lookup')
|