Files
EscapistsReintroduced/tests/test_engineer_mine_posts.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

54 lines
6.0 KiB
Python

"""Actual finite post ledger; engine identity/vector boundaries are doubles."""
import os,re
from pathlib import Path
from policy_harness import ROOT,run
P=Path(os.environ.get('ERR_ENGINEER_MINE_POSTS_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_EngineerMinePosts.c'))
BOUNDARY=r'''
#include <cassert>
#include <cmath>
#include <string>
#include <vector>
#include <algorithm>
struct string:std::string{using std::string::string;using std::string::operator=;string(std::string s):std::string(s){} bool IsEmpty(){return empty();}};
struct vector{float x=0,y=0,z=0;static float DistanceXZ(vector a,vector b){return std::hypot(a.x-b.x,a.z-b.z);}};
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;int Count(){return this->size();}void Insert(T p){this->push_back(p);}void Clear(){this->clear();}};
struct SCR_AIGroup{vector position;vector GetOrigin(){return position;}};
struct ERR_ForceRecord{SCR_AIGroup* Group=nullptr;bool Physical=true,Eliminated=false;string SourceId="s";int InitialStrength=2;};
struct ERR_HQTask{bool RoadIntercept=true,ReleaseOnly=false,investigation=false;string SecuritySite;int BeliefId=1,BeliefRevision=1;vector Destination;float QueuedAt=10,ExpiresAt=100000;bool Investigation(){return investigation;}};
struct ERR_HQReport{int MessageId=1;float ObservedAt=5;vector Position;};
namespace ERR_ForceRules{bool Finite(float f){return std::isfinite(f);}bool FiniteVector(vector p){return Finite(p.x)&&Finite(p.y)&&Finite(p.z);}}
struct ERR_EngineerMineSite{static inline bool valid=true;static inline int calls=0;static bool InBand(vector a,vector b){float d=vector::DistanceXZ(a,b);return d>=25&&d<=60;}static bool Select(vector post,vector&site){calls++;site={post.x+30,post.y,post.z};return valid;}};
'''
def ledger_cpp(path=P):
s=path.read_text().replace('class ','struct ').replace('protected ','').replace('ref ','').replace('out array<vector> sites','Array<vector>& sites').replace('array<','Array<').replace(' = {};',';')
for typ in ['ERR_EngineerMinePost','ERR_ForceRecord','SCR_AIGroup','ERR_HQTask','ERR_HQReport']:
s=re.sub(r'\b'+typ+r'(?=\s+\w)',typ+'*',s);s=s.replace('Array<'+typ+'>','Array<'+typ+'*>')
for ns in ['ERR_ForceRules','vector','ERR_EngineerMineSite']:s=s.replace(ns+'.',ns+'::')
for obj in ['record','task','assignment','previous','entry']:s=re.sub(r'\b'+obj+r'\.',obj+'->',s)
s=s.replace('foreach (','for (').replace('int used;','int used=0;')
# Enforce initializes scalar fields to zero; C++ aggregate members must match.
s=re.sub(r'^( (?:bool|int|float|ERR_ForceRecord\*|SCR_AIGroup\*|ERR_HQTask\*|ERR_HQReport\*) \w+);$',r'\1{};',s,flags=re.M)
s=s.replace('\n}\n','\n};\n')
return s
TEST=r'''
struct Fixture{SCR_AIGroup group;ERR_ForceRecord record;ERR_HQTask tasks[40];ERR_HQReport reports[40];ERR_EngineerMinePosts posts;
Fixture(){record.Group=&group;for(int i=0;i<40;i++){tasks[i].Destination={float(i*200),0,0};tasks[i].QueuedAt=10+i*10;tasks[i].BeliefRevision=1+i;reports[i].ObservedAt=5+i*10;reports[i].MessageId=i+1;}}
int Take(int i){return posts.Consume(&record,"s",&tasks[i],&reports[i],1000);}};
int main(){
{Fixture f;assert(f.Take(0)==0);assert(f.Take(1)==1);assert(f.Take(2)==2);assert(f.Take(3)==3);assert(f.Take(4)==-1&&f.posts.Count()==4);}
{Fixture f;assert(f.Take(0)==0);assert(f.Take(0)==-1);f.tasks[0].Destination={900,0,0};f.tasks[0].QueuedAt=900;f.reports[0].ObservedAt=800;f.reports[0].MessageId=999;f.tasks[0].BeliefRevision=999;
assert(f.Take(1)==1);assert(f.posts.RecordSite(0,{30,0,0}));assert(!f.posts.RecordSite(0,{31,0,0}));Array<vector> sites;f.posts.PriorSites(sites);assert(sites.size()==1&&sites[0].x==30);sites[0].x=900;f.posts.PriorSites(sites);assert(sites[0].x==30);}
for(int fault=0;fault<8;fault++){Fixture f;f.Take(0);if(fault==0)f.tasks[1].Destination={160,0,0};if(fault==1)f.tasks[1].QueuedAt=10;if(fault==2)f.reports[1].ObservedAt=5;if(fault==3)f.reports[1].MessageId=1;if(fault==4)f.tasks[1].BeliefRevision=1;if(fault==5)f.tasks[1].BeliefRevision=0;if(fault==6)f.tasks[1].ExpiresAt=1000;if(fault==7)f.tasks[1].Destination.x=NAN;assert(f.Take(1)==-1&&f.posts.Count()==1);}
{Fixture f;f.Take(0);f.tasks[1].Destination.x=160.001f;assert(f.Take(1)==1);}
{Fixture f;f.Take(0);f.tasks[1].BeliefId=2;f.tasks[1].BeliefRevision=1;assert(f.Take(1)==1);}
{Fixture f;f.Take(0);ERR_ForceRecord alias=f.record;assert(f.posts.Consume(&alias,"s",&f.tasks[1],&f.reports[1],1000)==-1);alias.SourceId="alias";assert(f.posts.Consume(&alias,"alias",&f.tasks[1],&f.reports[1],1000)==-1);f.record.SourceId="changed";assert(f.posts.Consume(&f.record,"changed",&f.tasks[1],&f.reports[1],1000)==-1);}
{Fixture f;f.Take(0);SCR_AIGroup replacement;f.record.Group=&replacement;assert(f.Take(1)==-1);f.record.Group=&f.group;f.record.InitialStrength=3;assert(f.Take(1)==-1);}
{Fixture f;assert(!f.posts.RecordSite(-1,{30,0,0}));assert(f.Take(0)==0);assert(!f.posts.RecordSite(0,{24,0,0}));assert(!f.posts.RecordSite(0,{61,0,0}));assert(!f.posts.RecordSite(0,{30,NAN,0}));Array<vector> empty;f.posts.PriorSites(empty);assert(empty.empty());assert(f.posts.RecordSite(0,{25,0,0}));}
{Fixture f;ERR_ForceRecord records[33];SCR_AIGroup groups[33];for(int i=0;i<33;i++){records[i].Group=&groups[i];records[i].SourceId=std::to_string(i);int result=f.posts.Consume(&records[i],records[i].SourceId,&f.tasks[i],&f.reports[i],1000);assert(result==(i<32?i:-1));}assert(f.posts.Count()==32);}
for(int fault=0;fault<10;fault++){Fixture f;if(fault==0)f.record.Physical=false;if(fault==1)f.record.Eliminated=true;if(fault==2)f.record.InitialStrength=33;if(fault==3)f.record.Group=nullptr;if(fault==4)f.tasks[0].ReleaseOnly=true;if(fault==5)f.tasks[0].investigation=true;if(fault==6)f.tasks[0].SecuritySite="site";if(fault==7)f.tasks[0].QueuedAt=1001;if(fault==8)f.reports[0].ObservedAt=11;if(fault==9)f.reports[0].Position.x=NAN;assert(f.Take(0)==-1&&f.posts.Count()==0);}
}
'''
if __name__=='__main__':
run(BOUNDARY+ledger_cpp()+TEST)
print('PASS: actual mine post ledger immutable history, strict chronology/evidence, aliases, >160m separation, detached sites and finite4/32 consumed attempts')