Files
EscapistsReintroduced/tests/test_start_stock_overflow.py
2026-10-28 14:43:43 +01:00

57 lines
4.6 KiB
Python

"""Execute the real stock-preparation loop with native inventory boundaries stubbed."""
from policy_harness import ROOT, body, run
p=ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_SiteService.c'
s=body(p,'protected ERR_PrepareResult PrepareStock(')
for a,b in [('protected ',''),('int pending, accepted;', 'int pending=0, accepted=0;'),('ERR_PrepareResult.', 'Result::'),('foreach (ERR_StockPlacement placement :', 'for (Placement* placement :'),('array<IEntity> items = {};','Array<IEntity> items;'),('placement.', 'placement->'),('.GetPrefabData()', '->GetPrefabData()'),('.GetPrefabName()', '->GetPrefabName()'),('.GetItems(', '->GetItems('),('.CanInsertItem(', '->CanInsertItem('),('.TryInsertItem(', '->TryInsertItem('),('GetGame().GetWorld().GetWorldTime()', 'now'),('LogLevel.WARNING','0'),('string.Format(', 'string::Format(')]:s=s.replace(a,b)
run(r'''
#include <cassert>
#include <string>
#include <vector>
#include <algorithm>
struct string:std::string{using std::string::string;bool IsEmpty(){return empty();}static string Format(string,int,int,string){return "timeout";}};
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;bool Contains(T x){return std::find(this->begin(),this->end(),x)!=this->end();}};
struct Item{string name="item";Item* GetPrefabData(){return this;}string GetPrefabName(){return name;}};using IEntity=Item*;
struct Inventory{Array<IEntity> contents;bool fits=true,accept=true;int requests=0;
void GetItems(Array<IEntity>& out){out=contents;}bool CanInsertItem(IEntity){return fits;}bool TryInsertItem(IEntity){requests++;return accept;}};
struct Placement{IEntity Item=nullptr;struct Inventory* Inventory=nullptr;bool Skipped=false,Accepted=false,Optional=false,OnGround=false;};
namespace Result{enum{FAILED=-1,PENDING,READY};}using ERR_PrepareResult=int;
int now=0;void Print(string,int){}
struct Service{Array<Placement*> m_Placements;int m_Deadline=100,failed=0,dropped=0;Array<IEntity> loose;
void Fail(string){failed++;}void LeaveStartingItem(Placement* p){dropped++;loose.push_back(p->Item);p->Skipped=true;}
'''+s+r'''
};
int main(){
Item floor;Inventory room;Placement explicitGround{&floor,&room,false,false,true,true};
Service direct;direct.m_Placements={&explicitGround};
assert(direct.PrepareStock()==Result::READY&&direct.dropped==1&&room.requests==0);
assert(direct.loose[0]==&floor);assert(direct.PrepareStock()==Result::READY&&direct.dropped==1);
Item map,rifle,pistol;Inventory bag;bag.fits=false;
Placement big{&rifle,&bag,false,false,true};Service s;s.m_Placements={&big};
assert(s.PrepareStock()==Result::READY&&s.dropped==1&&s.loose[0]==&rifle&&bag.requests==0);
assert(s.PrepareStock()==Result::READY&&s.dropped==1); // same item is not repeatedly dropped/spawned
Inventory good;Placement required{&map,&good},small{&pistol,&good,false,false,true};
Service mixed;mixed.m_Placements={&required,&small,&big};
assert(mixed.PrepareStock()==Result::PENDING&&good.requests==2);
assert(mixed.PrepareStock()==Result::PENDING&&good.requests==2); // async accepted requests are not repeated
good.contents={&map,&pistol};assert(mixed.PrepareStock()==Result::READY&&mixed.dropped==0);
Inventory delayed;delayed.fits=false;Placement moving{&rifle,&delayed,false,true,true};
Service wait;wait.m_Placements={&moving};assert(wait.PrepareStock()==Result::PENDING&&wait.dropped==0);
delayed.contents={&rifle};assert(wait.PrepareStock()==Result::READY&&wait.dropped==0);
Placement gone{nullptr,&bag,false,false,true};Service missing;missing.m_Placements={&gone};
assert(missing.PrepareStock()==Result::READY&&missing.failed==0&&gone.Skipped);
Placement lostMap{nullptr,&bag};Service broken;broken.m_Placements={&lostMap};
assert(broken.PrepareStock()==Result::FAILED&&broken.failed==1);
Inventory refusing;refusing.fits=false;refusing.accept=false;Placement noMap{&map,&refusing};
Service requiredFailure;requiredFailure.m_Placements={&noMap};
assert(requiredFailure.PrepareStock()==Result::PENDING);now=101;
assert(requiredFailure.PrepareStock()==Result::FAILED&&requiredFailure.failed==1);
Inventory stalled;Placement timeout{&rifle,&stalled,false,true,true};Service optionalTimeout;optionalTimeout.m_Placements={&timeout};
assert(optionalTimeout.PrepareStock()==Result::READY&&optionalTimeout.dropped==1&&optionalTimeout.failed==0);
}
''')
leave=body(p,'protected void LeaveStartingItem(')
assert '!item.GetParentSlot()' in leave and 'DryGround(point)' in leave
assert 'BackpackClearance(point)' in leave and 'TraceMove(access, null)' in leave
assert 'DeleteSpawned' not in leave and 'Spawn(' not in leave
print('PASS: native-rejected custom items remain available without startup delay; required map and async insertion safeguards retained')