Files
Viano-Core/tests/clientless/test_adventure_rotation.py
T
Nico d3273c677e
clang PCH / build (push) Canceled after 0s
GCC PCH / build (push) Canceled after 0s
Implement AdventureBot profiles, daily planning and population management
2026-10-28 18:22:13 +01:00

63 lines
4.8 KiB
Python

"""Execute production rotation cleanup with failed ownership/save/delete phases."""
from pathlib import Path
import subprocess,tempfile
root=Path(__file__).resolve().parents[2]
s=(root/'src/server/game/World/AdventurePopulationMgr.cpp').read_text()
a=s.index('void AdventurePopulationMgr::DeleteRotated()');b=s.index('{',a);e=b+1;n=1
while n:n+=(s[e]=='{')-(s[e]=='}');e+=1
code=r'''
#include <cassert>
#include <functional>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
using uint32=unsigned;
#define TC_LOG_INFO(...) ((void)0)
namespace Trinity{template<class...A>std::string StringFormat(char const* f,A...args){char b[4096];std::snprintf(b,sizeof(b),f,args...);return b;}}
struct ObjectGuid{unsigned id;ObjectGuid(int,unsigned v):id(v){}};
namespace HighGuid{constexpr int Player=0;}
namespace ObjectAccessor{bool connected=false;bool FindConnectedPlayer(ObjectGuid){return connected;}}
enum class ClientlessPlayerState{Offline,Online};
struct World{ClientlessPlayerState state=ClientlessPlayerState::Offline;auto GetClientlessPlayerState(unsigned){return state;}}world;auto sWorld=&world;
struct Field{unsigned GetUInt32(){return 6;}};
struct Row{Field f;Field*Fetch(){return &f;}};using QueryResult=std::shared_ptr<Row>;
struct Callback{std::function<void()> invoke;};
struct Processor{std::vector<Callback>pending;void AddCallback(Callback c){pending.push_back(std::move(c));}void run(){auto batch=std::move(pending);pending.clear();for(auto&c:batch)c.invoke();}};
struct Query{QueryResult row;template<class F>Callback WithCallback(F f){return {[row=row,f]{f(row);}};}};
struct Tx{std::vector<std::string>sql;template<class...A>void PAppend(char const*f,A...a){sql.push_back(Trinity::StringFormat(f,a...));}};
struct Save{bool ok;std::function<void(bool)>done;template<class F>void AfterComplete(F f){done=f;}operator Callback(){return {[ok=ok,done=done]{done(ok);}};}};
struct DB{
bool world=false,owns=true,exists=true,ok=true;int queries=0;std::vector<std::string>committed;
Query AsyncQuery(char const*sql){++queries;bool present=std::string(sql).find("SELECT guid FROM characters")!=std::string::npos?exists:owns;return {present?std::make_shared<Row>():nullptr};}
auto BeginTransaction(){return std::make_shared<Tx>();}
Save AsyncCommitTransaction(std::shared_ptr<Tx>tx){if(ok)for(auto const&s:tx->sql)committed.push_back(s);return {ok,{}};}
}CharacterDatabase,WorldDatabase;
struct Player{static int deletes;static bool fail;static void DeleteFromDB(ObjectGuid,unsigned,bool,bool){++deletes;if(!fail)CharacterDatabase.exists=false;}};int Player::deletes=0;bool Player::fail=false;
struct AdventurePopulationMgr{
struct Rotation{unsigned Old=10,New=11,Account=6;bool Submitted=false;};std::vector<Rotation>_rotations{{}};
bool _busy=false;unsigned _refresh=99;Processor _queries,_saves;std::string error;
void Failed(std::string s){_busy=false;error=s;}void DeleteRotated();
void drain(){for(int i=0;i<15;++i){_queries.run();_saves.run();}}
};
'''+s[a:e]+r'''
int main(){
AdventurePopulationMgr mgr;world.state=ClientlessPlayerState::Online;mgr.DeleteRotated();assert(!mgr._busy && !CharacterDatabase.queries && !Player::deletes);
world.state=ClientlessPlayerState::Offline;ObjectAccessor::connected=true;mgr.DeleteRotated();assert(!CharacterDatabase.queries);ObjectAccessor::connected=false;
CharacterDatabase.owns=false;mgr.DeleteRotated();mgr.drain();assert(!mgr.error.empty() && !Player::deletes && mgr._rotations.size()==1);
mgr={};CharacterDatabase.owns=true;Player::fail=true;mgr.DeleteRotated();mgr.drain();assert(Player::deletes==1 && !mgr.error.empty() && mgr._rotations.size()==1 && WorldDatabase.committed.empty());
mgr={};Player::fail=false;WorldDatabase.ok=false;mgr.DeleteRotated();mgr.drain();assert(!CharacterDatabase.exists && mgr._rotations.size()==1 && !mgr.error.empty());
assert(CharacterDatabase.committed.size()==2); // native deletion barriers only; profile/journal retained
mgr={};WorldDatabase.ok=true;mgr.DeleteRotated();mgr.drain();assert(mgr._rotations.empty() && !mgr._busy && !mgr._refresh);
auto contains=[](auto const& list,char const*text){return std::any_of(list.begin(),list.end(),[&](auto const&s){return s.find(text)!=std::string::npos;});};
assert(contains(WorldDatabase.committed,"vcore_adventure_day"));
for(auto name:{"vcore_adventure_generated_bot","vcore_adventure_supply_state","vcore_adventure_instance_visit","vcore_adventure_rotation"})assert(contains(CharacterDatabase.committed,name));
}
'''
with tempfile.TemporaryDirectory() as d:
p=Path(d);(p/'test.cpp').write_text(code)
subprocess.run(['g++','-std=c++17',str(p/'test.cpp'),'-o',str(p/'test')],check=True)
subprocess.run([str(p/'test')],check=True)
print('Production rotation: connected/native-online protection, ownership refusal, native delete failure, world cleanup failure and journal-retained retry before successful profile/plan/state removal passed')