/**
   * A leaf state must have a enter sequence. This enter sequence consists of an entry action call
   * and a state enter step.
   */
  @SuppressWarnings("unused")
  @Test
  public void testLeafStateEnterSequence() {
    Statechart sc = _createStatechart("cs");
    Scope scope = _createInterfaceScope("interface", sc);
    VariableDefinition v1 = _createVariableDefinition("v1", TYPE_INTEGER, scope);
    Region r = _createRegion("r", sc);
    State s1 = _createState("s1", r);
    LocalReaction entryAction = _createEntryAction(s1);
    _createVariableAssignment(
        v1, AssignmentOperator.ASSIGN, _createValue(42), (ReactionEffect) entryAction.getEffect());

    Entry e = _createEntry(EntryKind.INITIAL, null, r);
    Transition t = _createTransition(e, s1);

    ExecutionFlow flow = sequencer.transform(sc);

    ExecutionState _s1 = flow.getStates().get(0);
    assertEquals(s1.getName(), _s1.getSimpleName());

    assertNotNull(_s1.getEntryAction());
    assertNotNull(_s1.getEnterSequences().get(0));
    assertEquals(2, _s1.getEnterSequences().get(0).getSteps().size());

    assertCall(_s1.getEnterSequences().get(0), 0, _s1.getEntryAction());

    assertClass(EnterState.class, _s1.getEnterSequences().get(0).getSteps().get(1));
  }
  /** The exit action must be part of the reaction effect sequence */
  @SuppressWarnings("unused")
  @Test
  public void testStateReaction_WithEntryAction() {
    SimpleFlatTSC tsc = new SimpleFlatTSC();

    VariableDefinition v1 = _createVariableDefinition("v1", TYPE_INTEGER, tsc.s_scope);
    LocalReaction entryAction = _createEntryAction(tsc.s2);
    AssignmentExpression assign =
        _createVariableAssignment(
            v1,
            AssignmentOperator.ASSIGN,
            _createValue(21),
            (ReactionEffect) entryAction.getEffect());

    ExecutionFlow flow = sequencer.transform(tsc.sc);

    // test state with one outgoing transition
    ExecutionState _s1 = flow.getStates().get(0);
    ExecutionState _s2 = flow.getStates().get(1);
    assertEquals(tsc.s1.getName(), _s1.getSimpleName());
    assertEquals(tsc.s2.getName(), _s2.getSimpleName());

    assertEquals(1, _s1.getReactions().size());
    Reaction reaction = _s1.getReactions().get(0);

    assertNotNull(reaction.getCheck());

    assertNotNull(reaction.getEffect());
    Sequence seq = (Sequence) reaction.getEffect();
    assertEquals(2, seq.getSteps().size());

    assertCall(seq, 0, _s1.getExitSequence());
    assertCall(seq, 1, _s2.getEnterSequences().get(0));
    assertCall(_s2.getEnterSequences().get(0), 0, _s2.getEntryAction());
  }
  /** The transition action must be part of the reaction effect sequence */
  @Test
  public void testStateReaction_WithTransitionAction() {
    SimpleFlatTSC tsc = new SimpleFlatTSC();
    VariableDefinition v1 = _createVariableDefinition("v1", TYPE_INTEGER, tsc.s_scope);
    ReactionEffect effect = _createReactionEffect(tsc.t1);
    AssignmentExpression assign =
        _createVariableAssignment(v1, AssignmentOperator.ASSIGN, _createValue(42), effect);

    ExecutionFlow flow = sequencer.transform(tsc.sc);

    // test state with one outgoing transition
    ExecutionState s1 = flow.getStates().get(0);
    ExecutionState s2 = flow.getStates().get(1);
    assertEquals(tsc.s1.getName(), s1.getSimpleName());
    assertEquals(tsc.s2.getName(), s2.getSimpleName());

    assertEquals(1, s1.getReactions().size());
    Reaction reaction = s1.getReactions().get(0);

    assertNotNull(reaction.getCheck());

    assertNotNull(reaction.getEffect());
    Sequence seq = (Sequence) reaction.getEffect();

    assertCall(seq, 0, s1.getExitSequence());

    assertClass(Sequence.class, seq.getSteps().get(1));
    Execution _exec = (Execution) ((Sequence) seq.getSteps().get(1)).getSteps().get(0);
    AssignmentExpression _assign = (AssignmentExpression) _exec.getStatement();
    assertNotSame(_assign, assign);
    assertNotSame(_assign.getVarRef(), assign.getVarRef());
    assertNotSame(_assign.getVarRef(), v1);

    assertCall(seq, 2, s2.getEnterSequences().get(0));
  }
  /**
   * A leaf state must have a enter sequence. This enter sequence consists of an entry action call
   * and a state enter step.
   */
  @SuppressWarnings("unused")
  @Test
  public void testFinalStateEnterSequence() {
    Statechart sc = _createStatechart("cs");
    Scope scope = _createInterfaceScope("interface", sc);
    VariableDefinition v1 = _createVariableDefinition("v1", TYPE_INTEGER, scope);
    Region r = _createRegion("r", sc);
    FinalState fs = _createFinalState(r);

    ExecutionFlow flow = sequencer.transform(sc);

    ExecutionState _fs = flow.getStates().get(0);
    assertEquals("_final_0", _fs.getSimpleName());
    assertSame(fs, _fs.getSourceElement());

    assertNull(_fs.getEntryAction());
    assertNotNull(_fs.getEnterSequences().get(0));

    assertEquals(1, _fs.getEnterSequences().get(0).getSteps().size());
    assertClass(EnterState.class, _fs.getEnterSequences().get(0).getSteps().get(0));
  }
  /**
   * A composite state must have a enter sequence. This enter sequence consists of an entry action
   * call and a enter sequence call for each sub region.
   */
  @Test
  public void testCompositeStateEnterSequence() {
    Statechart sc = _createStatechart("cs");
    {
      Scope scope = _createInterfaceScope("interface", sc);
      VariableDefinition v1 = _createVariableDefinition("v1", TYPE_INTEGER, scope);

      Region r = _createRegion("r", sc);
      {
        State s1 = _createState("s1", r);
        {
          _createEntryAssignment(v1, s1, 1);
          Region r1_s1 = _createRegion("r1", s1);
          {
            Entry e = _createEntry(EntryKind.INITIAL, null, r1_s1);
            State s2 = _createState("s2", r1_s1);
            _createTransition(e, s2);
          }
          Region r2_s1 = _createRegion("r2", s1);
          {
            Entry e = _createEntry(EntryKind.INITIAL, null, r2_s1);
            State s3 = _createState("s3", r2_s1);
            _createTransition(e, s3);
          }
        }

        Entry e = _createEntry(EntryKind.INITIAL, null, r);
        _createTransition(e, s1);
      }
    }

    ExecutionFlow flow = sequencer.transform(sc);

    ExecutionState _s1 = flow.getStates().get(0);
    assertEquals("s1", _s1.getSimpleName());

    ExecutionState _s2 = flow.getStates().get(1);
    assertEquals("s2", _s2.getSimpleName());

    ExecutionState _s3 = flow.getStates().get(2);
    assertEquals("s3", _s3.getSimpleName());

    assertNotNull(_s1.getEntryAction());
    assertNotNull(_s1.getEnterSequences().get(0));
    assertEquals(3, _s1.getEnterSequences().get(0).getSteps().size());

    assertCall(_s1.getEnterSequences().get(0), 0, _s1.getEntryAction());
    assertCall(_s1.getEnterSequences().get(0), 1, _s2.getSuperScope().getEnterSequences().get(0));
    Sequence r1EntryReactSequence = flow.getNodes().get(0).getReactSequence();
    assertCall(_s2.getSuperScope().getEnterSequences().get(0), 0, r1EntryReactSequence);
    assertCall(
        ((Sequence) r1EntryReactSequence.getSteps().get(0)), 0, _s2.getEnterSequences().get(0));

    assertCall(_s1.getEnterSequences().get(0), 2, _s3.getSuperScope().getEnterSequences().get(0));
    Sequence r2EntryReactSequence = flow.getNodes().get(1).getReactSequence();
    assertCall(_s3.getSuperScope().getEnterSequences().get(0), 0, r2EntryReactSequence);
    assertCall(
        ((Sequence) r2EntryReactSequence.getSteps().get(0)), 0, _s3.getEnterSequences().get(0));
  }
  /** The enter sequence must be called withnin incoming transitions. */
  @SuppressWarnings("unused")
  @Test
  public void testFinalStateEnterSequenceCall() {

    Statechart sc = _createStatechart("sc");
    {
      InterfaceScope s_scope = _createInterfaceScope("Interface", sc);
      VariableDefinition v1 = _createVariableDefinition("v1", TYPE_INTEGER, s_scope);
      EventDefinition e1 = _createEventDefinition("e1", s_scope);

      Region r = _createRegion("r", sc);
      {
        State s1 = _createState("s1", r);

        FinalState fs = _createFinalState(r);

        Transition t_s1_fs = _createTransition(s1, fs);
        _createReactionTrigger(t_s1_fs);
        _createRegularEventSpec(e1, (ReactionTrigger) t_s1_fs.getTrigger());
      }
    }

    ExecutionFlow flow = sequencer.transform(sc);

    ExecutionState _s1 = flow.getStates().get(0);
    assertEquals("sc.r.s1", _s1.getName());

    ExecutionState _fs = flow.getStates().get(1);
    assertEquals("sc.r._final_", _fs.getName());

    assertNull(_fs.getEntryAction());
    assertNull(_fs.getExitAction());

    // the transition s1 -> fs must includes the fs exit sequence call
    Sequence cycle = _s1.getReactSequence();
    If _if = (If) SCTTestUtil.flattenSequenceStepsAsList(cycle).get(0);
    assertCall(_if.getThenStep(), _s1.getReactions().get(0).getEffect());

    Sequence _seq = (Sequence) _s1.getReactions().get(0).getEffect();
    assertCall(_seq, 1, _fs.getEnterSequences().get(0));
  }
  @Test
  public void testStateReaction_SimpleFlatTSC() {
    SimpleFlatTSC tsc = new SimpleFlatTSC();

    ExecutionFlow flow = sequencer.transform(tsc.sc);

    // test state with one outgoing transition
    ExecutionState s1 = flow.getStates().get(0);
    ExecutionState s2 = flow.getStates().get(1);
    assertEquals(tsc.s1.getName(), s1.getSimpleName());
    assertEquals(tsc.s2.getName(), s2.getSimpleName());

    assertEquals(1, s1.getReactions().size());
    Reaction reaction = s1.getReactions().get(0);

    assertNotNull(reaction.getCheck());

    assertNotNull(reaction.getEffect());
    Sequence seq = (Sequence) reaction.getEffect();

    assertCall(seq, 0, s1.getExitSequence());
    assertCall(seq, 1, s2.getEnterSequences().get(0));
  }