Files
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

74 lines
6.3 KiB
Python

"""Actual Stinger feedback and parsing, against a failure-injectable settings boundary."""
from pathlib import Path
import os
from policy_harness import ROOT,body,run
P=Path(os.environ.get('ERR_HQ_ADMIN_SOURCE',str(ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_HQAdminProvider.c')))
S=ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_Settings.c'
valid=body(S,'static bool Valid(').replace('string key','std::string key')
integer=body(ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_AdminService.c','static bool Integer(')
integer=(integer.replace('string text','std::string text').replace('out int value','int& value').replace('text.IsEmpty()','text.empty()').replace('text.Length()','int(text.size())').replace('text.Substring(','text.substr(').replace('"0123456789".IndexOf(', 'std::string("0123456789").find(').replace('< 0) return false;','== std::string::npos) return false;').replace('text.ToInt()','std::stoi(text)'))
selection=body(ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_AdminService.c','static bool Selection(')
selection=selection.replace('out int ', 'int& ').replace('ERR_Settings.', '').replace('ERR_TimeService.', '').replace('ERR_EnvironmentService.', '')
selection_rules='\n'.join(body(S,sig) for sig in ('static bool Randomizable(', 'static bool ValidSelection(', 'static string SelectionText(')).replace('value.ToString()', 'std::to_string(value)')
method=body(P,'protected void StingerSetting(')
method=(method.replace('protected ','').replace('ERR_GameMode mode','ERR_GameMode* mode').replace('array<string>','Array<string>&').replace('mode.Settings().','mode->Settings()->').replace('ERR_CommandArguments.Integer','Integer').replace('ERR_CommandArguments.Selection','Selection').replace('ERR_Settings.SelectionText','SelectionText').replace('mode->Settings()->Get(key).ToString()','std::to_string(mode->Settings()->Get(key))').replace('value.ToString()','std::to_string(value)').replace('int value;','int value=0;'))
run(r'''
#include <cassert>
#include <string>
#include <vector>
using string=std::string;
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;int Count(){return this->size();}void Insert(T x){this->push_back(x);}};
'''+valid+integer+selection_rules+r'''
bool ParseClock(string,int&){return false;}bool ParseDate(string,int&){return false;}bool ParseProfile(string,int&){return false;}
'''+selection+r'''
struct Settings{int chance=7,writes=0;bool fail=false;
int Get(string key){assert(key=="antiAirChancePercent");return chance;}
bool Set(string key,int value){writes++;if(fail||!ValidSelection(key,value))return false;chance=value;return true;}};
struct ERR_GameMode{struct Settings settings;struct Settings* Settings(){return &settings;}};
struct Provider{
'''+method+r'''
};
void Effect(const Array<string>& r){assert(r.back().find("have not rolled yet")!=string::npos&&r.back().find("no reroll, removal or replenishment")!=string::npos);}
int main(){
int parsed=0;assert(Selection("antiAirChancePercent","random",parsed)&&parsed==-1);
assert(SelectionText(parsed)=="Random");
ERR_GameMode mode;Provider p;Array<string> replies;
Array<string> show{"hq","stinger","show"};p.StingerSetting(&mode,show,replies);
assert(mode.settings.writes==0&&replies.back().find("antiAirChancePercent=7")!=string::npos);Effect(replies);
Array<string> help{"hq","stinger","help"};p.StingerSetting(&mode,help,replies);
assert(mode.settings.writes==0&&replies.back().find("0..100 percent")!=string::npos);Effect(replies);
Array<string> setting{"hq","stinger","set","0"};
for(int n:{0,1,2,15,100}){
setting[3]=std::to_string(n);p.StingerSetting(&mode,setting,replies);
assert(mode.settings.chance==n&&replies.back().find(" saved.")!=string::npos);Effect(replies);
}
for(string invalid:{"-1","1.0","1junk","10000000","101","1e1","+1"}){
setting[3]=invalid;p.StingerSetting(&mode,setting,replies);
assert(mode.settings.chance==100&&replies.back().find("previous setting retained")!=string::npos&&replies.back().find(" saved.")==string::npos);Effect(replies);
}
setting[3]="0";mode.settings.fail=true;p.StingerSetting(&mode,setting,replies);
assert(mode.settings.chance==100&&replies.back().find("previous setting retained")!=string::npos);Effect(replies);
int writes=mode.settings.writes;
for(Array<string> malformed: {Array<string>{"hq","stinger"},Array<string>{"hq","stinger","set"},Array<string>{"hq","stinger","show","extra"}}){
p.StingerSetting(&mode,malformed,replies);assert(mode.settings.writes==writes&&replies.back().find("previous setting retained")!=string::npos);
}
// Same antiAirChancePercent selection as the menu and `hq aa` alias.
mode.settings.fail=false;setting[3]="random";p.StingerSetting(&mode,setting,replies);
assert(mode.settings.chance==-1&&replies.back().find("antiAirChancePercent=Random saved.")!=string::npos);Effect(replies);
p.StingerSetting(&mode,show,replies);assert(replies.back().find("antiAirChancePercent=Random.")!=string::npos);Effect(replies);
// Invalid raw sentinel and unsupported modes remain rejected; no reroll calls.
for(string bad:{"-1","random-day","random day","101"}){setting[3]=bad;p.StingerSetting(&mode,setting,replies);assert(mode.settings.chance==-1&&replies.back().find("previous setting retained")!=string::npos);}
mode.settings.fail=true;setting[3]="0";p.StingerSetting(&mode,setting,replies);assert(mode.settings.chance==-1);
mode.settings.fail=false;setting[3]="0";p.StingerSetting(&mode,setting,replies);assert(mode.settings.chance==0);
mode.settings.fail=true;setting[3]="random";p.StingerSetting(&mode,setting,replies);assert(mode.settings.chance==0&&replies.back().find("previous setting retained")!=string::npos);
}
''')
execute=body(P,'override bool Execute(')
assert execute.index('arguments.IndexOf("hq stinger ") == 0')<execute.index('if (arguments != "status"')
assert 'StingerSetting(mode, parts, replies); return true;' in execute
admin=body(ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_AdminService.c','void Execute(')
assert admin.index('if (!authorized)')<admin.index('Extension(mode, arguments, replies)')
for forbidden in ('Check(', 'RandomInt(', 'Spawn', 'ConvoyAllowance', 'SetAISkill', 'entry.'):
assert forbidden not in body(P,'protected void StingerSetting(')
print('PASS: actual Stinger show/set/help state precise actor-roll effects; read-only help, bounded values, malformed syntax and failed-save preservation; no rerolls/gameplay edits and no native persistence claim')