2 # include <simgear_config.h>
6 // Always enable DEBUG mode in test application, otherwise "assert" test
7 // statements have no effect and don't actually test anything (catch 17 ;-) ).
11 #include <simgear/compiler.h>
18 #include "StateMachine.hxx"
20 #include <simgear/structure/SGBinding.hxx>
21 #include <simgear/structure/exception.hxx>
22 #include <simgear/props/condition.hxx>
23 #include <simgear/props/props.hxx>
24 #include <simgear/props/props_io.hxx>
25 #include <simgear/structure/commands.hxx>
32 // SGCondition subclass we can trivially manipulate from test code.
33 class DummyCondition : public SGCondition
36 DummyCondition(): _state(false) { }
38 virtual bool test() const
46 static int dummy_cmd_state = 0;
48 bool dummyCommand(const SGPropertyNode* arg)
54 #define COMPARE(a, b) \
56 cerr << "failed:" << #a << " != " << #b << endl; \
57 cerr << "\tgot:'" << a << "'" << endl; \
63 cerr << "failed:" << #a << endl; \
67 using namespace simgear;
69 #define BUILD_MACHINE_1() \
70 StateMachine_ptr sm(new StateMachine); \
71 StateMachine::State_ptr stateA = sm->createState("a"); \
72 StateMachine::State_ptr stateB = sm->createState("b"); \
73 StateMachine::State_ptr stateC = sm->createState("c"); \
75 DummyCondition* trigger1 = new DummyCondition; \
76 StateMachine::Transition_ptr t1 = sm->createTransition(">b", stateB); \
77 t1->addSourceState(stateA); \
78 t1->setTriggerCondition(trigger1); \
80 DummyCondition* trigger2 = new DummyCondition; \
81 StateMachine::Transition_ptr t2 = sm->createTransition(">c", stateC); \
82 t2->addSourceState(stateB); \
83 t2->setTriggerCondition(trigger2); \
85 DummyCondition* trigger3 = new DummyCondition; \
86 StateMachine::Transition_ptr t3 = sm->createTransition(">a", stateA); \
87 t3->addSourceState(stateC); \
88 t3->addSourceState(stateB); \
89 t3->setTriggerCondition(trigger3); \
95 ////////////////////////////////////////////
96 COMPARE(sm->state()->name(), "a");
98 COMPARE(sm->indexOfState(stateA), 0);
99 COMPARE(sm->findStateByName("c"), stateC);
101 sm->changeToState(stateC);
102 COMPARE(sm->state(), stateC);
104 trigger3->_state = true;
106 COMPARE(sm->state()->name(), "a");
107 trigger3->_state = false;
109 trigger1->_state = true;
111 trigger1->_state = false;
112 COMPARE(sm->state()->name(), "b");
114 trigger3->_state = true;
116 COMPARE(sm->state()->name(), "a");
117 trigger3->_state = false;
119 trigger1->_state = true;
121 trigger1->_state = false;
122 COMPARE(sm->state()->name(), "b");
124 trigger2->_state = true;
126 trigger2->_state = false;
127 COMPARE(sm->state()->name(), "c");
129 //////////////////////////////////////////
130 COMPARE(sm->root()->getIntValue("current-index"), 2);
131 COMPARE(sm->root()->getStringValue("current-name"), string("c"));
133 sm->root()->setStringValue("current-name", "b");
134 COMPARE(sm->state()->name(), "b");
136 ////////////////////////////////////////
137 COMPARE(sm->findStateByName("foo"), NULL);
138 COMPARE(sm->indexOfState(StateMachine::State_ptr()), -1);
140 COMPARE(sm->stateByIndex(1), stateB);
143 sm->stateByIndex(44);
144 VERIFY(false && "should have raised an exception");
145 } catch (sg_exception& e){
152 SGCommandMgr* cmdMgr = SGCommandMgr::instance();
153 cmdMgr->addCommand("dummy", dummyCommand);
156 t2->addBinding(new SGBinding("dummy"));
158 stateA->addEntryBinding(new SGBinding("dummy"));
159 stateA->addExitBinding(new SGBinding("dummy"));
160 stateC->addEntryBinding(new SGBinding("dummy"));
162 ////////////////////////
163 COMPARE(sm->state()->name(), "a");
164 trigger1->_state = true;
166 trigger1->_state = false;
167 COMPARE(sm->state()->name(), "b");
168 COMPARE(dummy_cmd_state, 1); // exit state A
170 trigger2->_state = true;
172 trigger2->_state = false;
173 COMPARE(dummy_cmd_state, 3); // fire transition 2, enter state C
176 sm->changeToState(stateA);
177 COMPARE(dummy_cmd_state, 1); // enter state A
178 trigger1->_state = true;
180 trigger1->_state = false;
181 COMPARE(dummy_cmd_state, 2); // exit state A
183 ////////////////////////
184 t3->addBinding(new SGBinding("dummy"));
185 t3->addBinding(new SGBinding("dummy"));
186 t3->addBinding(new SGBinding("dummy"));
188 sm->changeToStateName("b");
190 trigger3->_state = true;
192 trigger3->_state = false;
193 COMPARE(dummy_cmd_state, 4); // three transition bindings, enter A
198 const char* xml = "<?xml version=\"1.0\"?>"
208 SGPropertyNode* desc = new SGPropertyNode;
209 readProperties(xml, strlen(xml), desc);
211 SGPropertyNode_ptr root(new SGPropertyNode);
212 StateMachine_ptr sm = StateMachine::createFromPlist(desc, root);
214 VERIFY(sm->findStateByName("one") != NULL);
215 VERIFY(sm->findStateByName("two") != NULL);
218 int main(int argc, char* argv[])
223 cout << __FILE__ << ": All tests passed" << endl;