/**
  * Sets up the finite state machine.
  */
 private function setupFiniteStateMachine()
 {
     $this->fsm = new xfFiniteStateMachine();
     $this->fsm->addStates(array(self::ST_QUERY, self::ST_RANGE_START, self::ST_RANGE_END, self::ST_RANGE_END_INDICATOR, self::ST_RANGE_SEPARATOR, self::ST_ERROR));
     $this->fsm->setInitialState(self::ST_QUERY);
     $this->fsm->addTransitions(array(array(self::ST_QUERY, xfLexemeLucene::WORD, self::ST_QUERY), array(self::ST_QUERY, xfLexemeLucene::SYNTAX, self::ST_QUERY), array(self::ST_QUERY, xfLexemeLucene::PHRASE, self::ST_QUERY), array(self::ST_QUERY, xfLexemeLucene::NUMBER, self::ST_QUERY), array(self::ST_QUERY, xfLexemeLucene::FIELD, self::ST_QUERY), array(self::ST_QUERY, xfLexemeLucene::WILDCARD, self::ST_QUERY)));
     $this->fsm->addTransitions(array(array(self::ST_QUERY, xfLexemeLucene::RANGE_START_INCLUSIVE, self::ST_RANGE_START), array(self::ST_QUERY, xfLexemeLucene::RANGE_START_EXCLUSIVE, self::ST_RANGE_START), array(self::ST_RANGE_START, xfLexemeLucene::WORD, self::ST_RANGE_SEPARATOR), array(self::ST_RANGE_SEPARATOR, xfLexemeLucene::RANGE_SEPARATOR, self::ST_RANGE_END), array(self::ST_RANGE_END, xfLexemeLucene::WORD, self::ST_RANGE_END_INDICATOR), array(self::ST_RANGE_END_INDICATOR, xfLexemeLucene::RANGE_END_INCLUSIVE, self::ST_QUERY), array(self::ST_RANGE_END_INDICATOR, xfLexemeLucene::RANGE_END_EXCLUSIVE, self::ST_QUERY)));
     $addTerm = new xfCriterionBuilderAddTerm($this->builder);
     $addPhrase = new xfCriterionBuilderAddPhrase($this->builder, $this->phraseSlop);
     $addWildcard = new xfCriterionBuilderAddWildcard($this->builder);
     $addField = new xfCriterionBuilderSetField($this->builder);
     $handleSyntax = new xfCriterionBuilderLuceneHandleSyntax($this->builder);
     $handleRange = new xfCriterionBuilderLuceneHandleRange($this->builder);
     $this->fsm->addInputAction(self::ST_QUERY, xfLexemeLucene::WORD, $addTerm);
     $this->fsm->addInputAction(self::ST_QUERY, xfLexemeLucene::PHRASE, $addPhrase);
     $this->fsm->addInputAction(self::ST_QUERY, xfLexemeLucene::WILDCARD, $addWildcard);
     $this->fsm->addInputAction(self::ST_QUERY, xfLexemeLucene::FIELD, $addField);
     $this->fsm->addInputAction(self::ST_QUERY, xfLexemeLucene::SYNTAX, $handleSyntax);
     $this->fsm->addExitAction(self::ST_RANGE_END_INDICATOR, $handleRange);
 }
try {
    $msg = '->process() fails when there is no transition defined for an input';
    $fsm->process('twist');
    $t->fail($msg);
} catch (Exception $e) {
    $t->pass($msg);
}
$fsm->setDefaultTransition('broken');
$t->is($fsm->process('twist')->getState(), 'broken', '->process() uses the default transition if possible');
$fsm->setDefaultTransition(null);
$fsm->reset();
$t->is($fsm->getState(), 'off', '->reset() resets the state');
$t->diag('exit actions');
$fsm->reset();
$exit = new CounterAction();
$fsm->addExitAction('off', $exit);
$fsm->process('push');
$t->is($exit->counter, 1, '->process() calls an exit action when leaving a state');
$fsm->process('push');
$t->is($exit->counter, 1, '->process() does not call an exit action when not leaving the state');
$fsm->process('wait');
$t->is($exit->counter, 1, '->process() does not call an exit action when the state does not change');
$t->diag('entry actions');
$fsm->reset();
$enter = new CounterAction();
$fsm->addEntryAction('broken', $enter);
$fsm->process('smash');
$t->is($enter->counter, 1, '->process() calls an entry action when entering the state');
$fsm->process('wait');
$t->is($enter->counter, 1, '->process() does not call an entry action when the state does not change');
$fsm->process('replace');