#include "robot_bt/core.hpp" #include #include #include #include using namespace robot_bt; struct Wire : GoalDriver { unsigned sends{0},cancels{0};std::vector events; bool ready(Skill)const override{return true;} void send(const GoalRequest&)override{++sends;} void cancel(const std::string&)override{++cancels;} std::vector drain_events()override{auto out=events;events.clear();return out;} }; int main(){ char directory[]="/tmp/bt_lifecycle_XXXXXX";assert(::mkdtemp(directory)); unsigned cases=0;std::set> transitions; // All sequences of length three over the ten documented event classes. // This is a finite bound, not an assertion about arbitrary-length schedules. for(unsigned word=0;word<1000;++word){ Wire wire;Budgets budgets{Milliseconds(2),Milliseconds(2),Milliseconds(2),Milliseconds(3),Milliseconds(2)}; ActiveGoalRegistry registry(wire,std::string(directory)+"/"+std::to_string(cases),budgets); GoalRequest q;q.robot_id="r";q.trace={"t","s","run",1,1,1,1}; const auto id=*registry.start(q,SteadyTime{});unsigned rest=word;bool terminal=false;SteadyTime now{}; for(unsigned step=0;step<3;++step){ const auto before=registry.find(id)->state;const unsigned kind=rest%10;rest/=10; GoalEvent e;e.goal_id=id;e.trace=q.trace; switch(kind){ case 0:e.kind=EventKind::ACCEPTED;break; case 1:e.kind=EventKind::REJECTED;break; case 2:e.kind=EventKind::FEEDBACK;e.sequence=step+1;break; case 3:e.kind=EventKind::FEEDBACK;e.sequence=0;break; case 4:e.kind=EventKind::CANCEL_ACK;break; case 5:e.kind=EventKind::RESULT;e.native_status=NativeStatus::SUCCEEDED;e.result.code=ResultCode::COMPLETED;e.result.stop=StopState::CONFIRMED;break; case 6:e.kind=EventKind::RESULT;e.native_status=NativeStatus::CANCELED;e.result.code=ResultCode::CANCELED;e.result.stop=StopState::UNKNOWN;break; case 7:e.kind=EventKind::RESULT;e.trace.run_id="stale";e.native_status=NativeStatus::SUCCEEDED;e.result.code=ResultCode::COMPLETED;e.result.stop=StopState::CONFIRMED;break; case 8:registry.request_cancel(id,now);break; case 9:now+=Milliseconds(5);break; } if(kind<8)wire.events.push_back(e); registry.pump(now);const auto* record=registry.find(id); transitions.emplace(static_cast(before),static_cast(record->state)); if(terminal)assert(record->state==GoalState::TERMINAL); terminal=record->state==GoalState::TERMINAL; if(terminal){assert(record->result);assert(record->result->stop==StopState::CONFIRMED);} if(!terminal)assert(registry.robot_locked("r")); if(kind==4&&!terminal)assert(registry.robot_locked("r")); if(kind==7)assert((before==GoalState::TERMINAL)==terminal); assert(!registry.start(q,now));assert(wire.sends==1); } ++cases; } // Full native-status x business-result x stop matrix, including mismatches. unsigned combinations=0; for(int n=0;n<5;++n)for(int b=0;b<5;++b)for(int stop=0;stop<2;++stop){ Wire wire;ActiveGoalRegistry registry(wire,std::string(directory)+"/"+std::to_string(cases++)); GoalRequest q;q.robot_id="r";q.trace={"t","s","run",1,1,1,1};const auto id=*registry.start(q,SteadyTime{}); GoalEvent e;e.goal_id=id;e.trace=q.trace;e.kind=EventKind::RESULT;e.native_status=static_cast(n);e.result.code=static_cast(b);e.result.stop=static_cast(stop);wire.events.push_back(e);registry.pump(SteadyTime{}); const bool matches=(n==0&&b==0)||(n==1&&(b==1||b==3||b==4))||(n==2&&b==2)||(n==3&&b==4); assert(registry.robot_locked("r")==!(matches&&stop==1));++combinations; } std::cout<<"{\"event_sequences\":1000,\"sequence_length\":3,\"event_alphabet\":10,\"result_combinations\":"<