Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
73 lines
5.7 KiB
Python
73 lines
5.7 KiB
Python
"""Production rule/preset operations; native fixture separately covers disk IO."""
|
|
from policy_harness import ROOT, body, run
|
|
import re
|
|
p=ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_ItemPreferences.c'
|
|
methods='\n'.join(body(p,n) for n in ('static bool Name(', 'static bool Guid(', 'static bool WeightKey(', 'static bool WeightValue(', 'static bool Valid(', 'protected void Rebuild(', 'bool Enabled(', 'bool Allows(', 'bool Set(', 'int WeightSetting(', 'int Weight(', 'bool SetWeight(', 'bool Preset('))
|
|
methods=methods.replace('weight.ToString()', 'string(std::to_string(weight))').replace('Math.Max', 'std::max').replace('ERR_CommandArguments.Integer', 'Integer')
|
|
methods=methods.replace('protected ', '').replace('array<string>', 'Array<string>').replace('set<string> keys = new set<string>();','Array<string> keys;')
|
|
methods=methods.replace('foreach (', 'for (').replace('ResourceName','string').replace('ERR_TerrainCatalog.Key(prefab)', 'prefab').replace('SCR_AddonTool.GetResourceAddons(prefab)', 'sources')
|
|
methods=methods.replace('Array<string> sources = sources;', 'Array<string> resourceSources = sources;').replace('project : sources','project : resourceSources')
|
|
methods=methods.replace('"0123456789abcdef".IndexOf','string("0123456789abcdef").IndexOf').replace('!records || ', '')
|
|
run(r'''
|
|
#include <cassert>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include <map>
|
|
struct string;
|
|
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;using std::vector<T>::operator=;int Count(){return this->size();}void Insert(T x){this->push_back(x);}bool Contains(T x){return std::find(this->begin(),this->end(),x)!=this->end();}void Clear(){this->clear();}};
|
|
struct string:std::string{using std::string::string;string(std::string x):std::string(x){}bool IsEmpty(){return empty();}int Length(){return size();}int IndexOf(string s){auto i=find(s);return i==npos?-1:int(i);}string Substring(int a,int n){return substr(a,n);}int ToInt(){return std::stoi(*this);}void Split(string delim,Array<string>& out,bool){size_t a=0;while(true){auto b=find(delim,a);out.Insert(substr(a,b==npos?b:b-a));if(b==npos)break;a=b+delim.size();}}};
|
|
template<class T>struct Map{std::map<string,T> data;bool Contains(string k){return data.count(k);}T Get(string k){return data[k];}void Set(string k,T v){data[k]=v;}void Clear(){data.clear();}};
|
|
bool Integer(string s,int& n){try{size_t end;n=std::stoi(s,&end);return end==s.size();}catch(...){return false;}}
|
|
struct Prefs{Array<string> m_Records={"active"},sources={"base-project","mod-project"};Map<int> m_Rules;Map<string> m_Loaded;int m_Revision=0;bool fail=false;
|
|
bool Save(Array<string> rows){if(fail||!Valid(rows))return false;m_Records=rows;Rebuild();return true;}
|
|
'''+methods+r'''
|
|
};
|
|
int main(){
|
|
string a="1111111111111111",b="2222222222222222",i="aaaaaaaaaaaaaaaa",j="bbbbbbbbbbbbbbbb";
|
|
Prefs p;p.m_Loaded.Set("base-project",a);p.m_Loaded.Set("mod-project",b);
|
|
assert(p.Allows(i));assert(p.Set(a,"*",false)&&!p.Allows(i));
|
|
assert(p.Set(a,i,true)&&p.Allows(i)&&!p.Allows(j));
|
|
assert(p.Set(b,i,false)&&!p.Allows(i)); // Shared source disable wins.
|
|
assert(p.Preset("save","custom"));
|
|
assert(p.Set(a,"*",true)&&p.Set(b,"*",true)&&p.Allows(i)&&p.Allows(j));
|
|
assert(p.Preset("load","custom")&&!p.Allows(i)&&!p.Allows(j));
|
|
p.m_Loaded.Clear();assert(p.Allows(i)&&p.Allows(j)); // Missing sources are dormant.
|
|
p.m_Loaded.Set("mod-project",b);assert(!p.Allows(i)); // Returns when source is loaded again.
|
|
// Weight records coexist with booleans and travel with named presets.
|
|
p.m_Loaded.Set("base-project",a);
|
|
assert(p.Weight(i)==1);assert(p.SetWeight(b,"*",100)&&p.Weight(i)==100);
|
|
assert(p.SetWeight(b,i,10)&&p.Weight(i)==1000&&p.Weight(j)==100);
|
|
assert(p.Set(a,"*",true)&&p.Set(b,"*",true)&&p.Weight(i)==1000);
|
|
assert(p.Preset("save","weighted"));
|
|
assert(p.SetWeight(b,"*",1)&&p.Weight(i)==10);
|
|
assert(p.SetWeight(b,i,0)&&p.Weight(i)==0&&p.Weight(j)==1);
|
|
assert(p.Preset("load","weighted")&&p.Weight(i)==1000);
|
|
assert(p.SetWeight(a,"*",0)&&p.Weight(i)==0); // Shared source exclusion wins.
|
|
assert(p.SetWeight(a,"*",1)&&p.Weight(i)==1000);
|
|
assert(!p.SetWeight(a,i,-1)&&!p.SetWeight(a,i,101));
|
|
for(string bad:{"100junk","-1","101","1.5",""})assert(!p.WeightValue(bad));
|
|
assert(p.WeightValue("0")&&p.WeightValue("100"));
|
|
assert(!p.Valid({"active","active|1111111111111111|w*|101"}));
|
|
p.m_Loaded.Clear();assert(p.Weight(i)==1); // Absent mod has no effect.
|
|
p.m_Loaded.Set("mod-project",b);assert(p.Weight(i)==1000);
|
|
assert(p.Preset("delete","weighted"));
|
|
auto old=p.m_Records;int revision=p.m_Revision;p.fail=true;
|
|
assert(!p.Set(b,"*",true)&&p.m_Records==old&&p.m_Revision==revision);
|
|
assert(!p.Preset("save","failed")&&p.m_Records==old);
|
|
assert(!p.Preset("delete","custom")&&p.m_Records==old);
|
|
p.fail=false;
|
|
assert(p.Preset("save","custom")&&p.Preset("delete","custom")&&!p.Preset("load","custom"));
|
|
for(string name:{"", "active", "../bad", "two words", "abcdefghijklmnopqrstuvwxy"})assert(!p.Preset("save",name));
|
|
assert(!p.Preset("delete","missing")&&!p.Preset("load","missing")&&!p.Preset("evil","x"));
|
|
for(int n=0;n<16;n++)assert(p.Preset("save",string("preset_")+std::to_string(n)));
|
|
assert(!p.Preset("save","overflow"));assert(p.Preset("save","preset_0"));
|
|
assert(p.Preset("delete","preset_0")&&p.Preset("save","replacement"));
|
|
assert(!p.Valid({"active","active|1111111111111111|*|2"}));
|
|
assert(!p.Valid({"active","active|1111111111111111|*|0","active|1111111111111111|*|1"}));
|
|
assert(!p.Valid({"active","missing|1111111111111111|*|0"}));
|
|
assert(!p.Set("../x",i,true)&&!p.Set(a,"unknown",true));
|
|
}
|
|
''')
|
|
print('PASS: actual item rules, shared-source conflicts, missing/returning mods, bulk reset, independent named presets, bounds, malformed data and failed-save state preservation')
|