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){
150 void testNoSourcesTransition()
154 DummyCondition* trigger4 = new DummyCondition;
155 StateMachine::Transition_ptr t4 = sm->createTransition("alwaysToA", stateA); \
156 t4->setTriggerCondition(trigger4); \
159 COMPARE(sm->state()->name(), "a");
160 trigger1->_state = true;
162 trigger1->_state = false;
163 COMPARE(sm->state()->name(), "b");
165 trigger4->_state = true;
167 trigger4->_state = false;
168 COMPARE(sm->state()->name(), "a");
173 SGCommandMgr* cmdMgr = SGCommandMgr::instance();
174 cmdMgr->addCommand("dummy", dummyCommand);
177 t2->addBinding(new SGBinding("dummy"));
179 stateA->addEntryBinding(new SGBinding("dummy"));
180 stateA->addExitBinding(new SGBinding("dummy"));
181 stateC->addEntryBinding(new SGBinding("dummy"));
183 ////////////////////////
184 COMPARE(sm->state()->name(), "a");
185 trigger1->_state = true;
187 trigger1->_state = false;
188 COMPARE(sm->state()->name(), "b");
189 COMPARE(dummy_cmd_state, 1); // exit state A
191 trigger2->_state = true;
193 trigger2->_state = false;
194 COMPARE(dummy_cmd_state, 3); // fire transition 2, enter state C
197 sm->changeToState(stateA);
198 COMPARE(dummy_cmd_state, 1); // enter state A
199 trigger1->_state = true;
201 trigger1->_state = false;
202 COMPARE(dummy_cmd_state, 2); // exit state A
204 ////////////////////////
205 t3->addBinding(new SGBinding("dummy"));
206 t3->addBinding(new SGBinding("dummy"));
207 t3->addBinding(new SGBinding("dummy"));
209 sm->changeToStateName("b");
211 trigger3->_state = true;
213 trigger3->_state = false;
214 COMPARE(dummy_cmd_state, 4); // three transition bindings, enter A
219 const char* xml = "<?xml version=\"1.0\"?>"
229 SGPropertyNode* desc = new SGPropertyNode;
230 readProperties(xml, strlen(xml), desc);
232 SGPropertyNode_ptr root(new SGPropertyNode);
233 StateMachine_ptr sm = StateMachine::createFromPlist(desc, root);
235 VERIFY(sm->findStateByName("one") != NULL);
236 VERIFY(sm->findStateByName("two") != NULL);
239 int main(int argc, char* argv[])
244 testNoSourcesTransition();
246 cout << __FILE__ << ": All tests passed" << endl;