// ========================================================================== // SC.Statechart Unit Test // ========================================================================== /*globals SC */

var statechart, del, monitor, stateFoo, stateBar, stateA, stateB, stateC, stateX, stateY, TestState;

module(“SC.Statechart: Concurrent States - Trigger Routing on States Basic Tests”, {

setup: function() {

  del = SC.Object.create(SC.StatechartDelegate, {

    location: null,

    handlers: {},

    statechartUpdateLocationForState: function(statechart, location, state) {
      this.set('location', location);
    },

    statechartAcquireLocationForState: function(statechart, state) {
      return this.get('location');
    },

    statechartBindStateToRoute: function(statechart, state, route, handler) {
      this.handlers[route] = {
        statechart: statechart,
        state: state,
        handler: handler
      };
    }

  });

  TestState = SC.State.extend({

    enterState: function(context) {
      this.info = {};
      this.info.enterState = {
        state: this,
        context: context
      };
    }

  });

  statechart = SC.Statechart.create({

    monitorIsActive: YES,

    delegate: del,

    statesAreConcurrent: YES,

    foo: SC.State.design({

      initialSubstate: 'a',

      a: TestState.design({

        representRoute: 'dog'

      }),

      b: TestState.design({

        representRoute: 'cat'

      }),

      c: TestState.design({

        representRoute: ''

      })

    }),

    bar: SC.State.design({

      initialSubstate: 'x',

      x: TestState.design({

        representRoute: 'pig'

      }),

      y: TestState.design({

        representRoute: 'cow',

        enterStateByRoute: function(context) {
          this.info = {};
          this.info.enterStateByRoute = {
            context: context
          };
        }

      })

    })

  });

  statechart.initStatechart();

  monitor = statechart.get('monitor');
  stateFoo = statechart.getState('foo');
  stateBar = statechart.getState('bar');
  stateA = statechart.getState('a');
  stateB = statechart.getState('b');
  stateC = statechart.getState('c');
  stateX = statechart.getState('x');
  stateY = statechart.getState('y');
},

teardown: function() {
  statechart = del = monitor = TestState = stateFoo = stateBar = stateA = stateB = stateC = stateX = stateY = null;
}

});

test(“check statechart initialization”, function() {

equals(del.get('location'), null, "del.location should be null");

var handlers = del.handlers;

ok(handlers['dog'], "delegate should have a route 'dog'");
equals(handlers['dog'].statechart, statechart, "route 'dog' should be bound to statechart");
equals(handlers['dog'].state, stateA, "route 'dog' should be bound to state A");
equals(handlers['dog'].handler, stateA.routeTriggered, "route 'dog' should be bound to handler stateA.routeTriggered");

ok(handlers['cat'], "delegate should have a route 'cat'");
equals(handlers['cat'].statechart, statechart, "route 'cat' should be bound to statechart");
equals(handlers['cat'].state, stateB, "route 'cat' should be bound to state B");
equals(handlers['cat'].handler, stateB.routeTriggered, "route 'cat' should be bound to handler stateB.routeTriggered");

ok(handlers[''], "delegate should have a route ''");
equals(handlers[''].statechart, statechart, "route '' should be bound to statechart");
equals(handlers[''].state, stateC, "route '' should be bound to state C");
equals(handlers[''].handler, stateC.routeTriggered, "route '' should be bound to handler stateC.routeTriggered");

ok(handlers['pig'], "delegate should have a route 'pig'");
equals(handlers['pig'].statechart, statechart, "route 'pig' should be bound to statechart");
equals(handlers['pig'].state, stateX, "route 'pig' should be bound to state X");
equals(handlers['pig'].handler, stateX.routeTriggered, "route 'pig' should be bound to handler stateX.routeTriggered");

ok(handlers['cow'], "delegate should have a route 'cow'");
equals(handlers['cow'].statechart, statechart, "route 'cow' should be bound to statechart");
equals(handlers['cow'].state, stateY, "route 'cow' should be bound to state Y");
equals(handlers['cow'].handler, stateY.routeTriggered, "route 'cow' should be bound to handler stateY.routeTriggered");

});

test(“trigger state B's route”, function() {

var params = {};

monitor.reset();

ok(stateA.get('isCurrentState'), "state A should be a current state");
ok(!stateB.get('isCurrentState'), "state B should not be a current state");
ok(!stateC.get('isCurrentState'), "state C should not be a current state");
ok(stateX.get('isCurrentState'), "state X should be a current state");
ok(!stateY.get('isCurrentState'), "state Y should not be a current state");

del.set('location', 'cat');

stateB.routeTriggered(params);

var seq = monitor.matchSequence().begin().exited('a').entered('b').end();
ok(seq, 'sequence should be exited[a], entered[b]');

ok(!stateA.get('isCurrentState'), "state A should not be a current state");
ok(stateB.get('isCurrentState'), "state B should be a current state");
ok(!stateC.get('isCurrentState'), "state C should not be a current state");
ok(stateX.get('isCurrentState'), "state X should be a current state");
ok(!stateY.get('isCurrentState'), "state Y should not be a current state");

var info = stateB.info;

ok(info.enterState, "state B's enterState should have been invoked");

var context = info.enterState.context;

ok(SC.kindOf(context, SC.StateRouteHandlerContext), "state B's enterState method should have been provided a state route handler context object");
equals(context.get('state'), stateB);
equals(context.get('location'), 'cat');
equals(context.get('params'), params);
equals(context.get('handler'), stateB.routeTriggered);

});

test(“trigger state C's route”, function() {

var params = {};

monitor.reset();

ok(stateA.get('isCurrentState'), "state A should be a current state");
ok(!stateB.get('isCurrentState'), "state B should not be a current state");
ok(!stateC.get('isCurrentState'), "state C should not be a current state");
ok(stateX.get('isCurrentState'), "state X should be a current state");
ok(!stateY.get('isCurrentState'), "state Y should not be a current state");

del.set('location', '');

stateC.routeTriggered(params);

var seq = monitor.matchSequence().begin().exited('a').entered('c').end();
ok(seq, 'sequence should be exited[a], entered[c]');

ok(!stateA.get('isCurrentState'), "state A should not be a current state");
ok(!stateB.get('isCurrentState'), "state B should not be a current state");
ok(stateC.get('isCurrentState'), "state C should be a current state");
ok(stateX.get('isCurrentState'), "state X should be a current state");
ok(!stateY.get('isCurrentState'), "state Y should not be a current state");

var info = stateC.info;

ok(info.enterState, "state C's enterState should have been invoked");

var context = info.enterState.context;

ok(SC.kindOf(context, SC.StateRouteHandlerContext), "state C's enterState method should have been provided a state route handler context object");
equals(context.get('state'), stateC);
equals(context.get('location'), '');
equals(context.get('params'), params);
equals(context.get('handler'), stateC.routeTriggered);

});

test(“trigger state Y's route”, function() {

var params = {};

monitor.reset();

ok(stateA.get('isCurrentState'), "state A should be a current state");
ok(!stateB.get('isCurrentState'), "state B should not be a current state");
ok(!stateC.get('isCurrentState'), "state C should not be a current state");
ok(stateX.get('isCurrentState'), "state X should be a current state");
ok(!stateY.get('isCurrentState'), "state Y should not be a current state");

del.set('location', 'cow');

stateY.routeTriggered(params);

var seq = monitor.matchSequence().begin().exited('x').entered('y').end();
ok(seq, 'sequence should be exited[x], entered[y]');

ok(stateA.get('isCurrentState'), "state A should be a current state");
ok(!stateB.get('isCurrentState'), "state B should not be a current state");
ok(!stateC.get('isCurrentState'), "state C should not be a current state");
ok(!stateX.get('isCurrentState'), "state X should not be a current state");
ok(stateY.get('isCurrentState'), "state Y should be a current state");

var info = stateY.info;

ok(!info.enterState, "state Y's enterState should not have been invoked");
ok(info.enterStateByRoute, "state Y's enterStateByRoute should have been invoked");

var context = info.enterStateByRoute.context;

ok(SC.kindOf(context, SC.StateRouteHandlerContext), "state X's enterState method should have been provided a state route handler context object");
equals(context.get('state'), stateY);
equals(context.get('location'), 'cow');
equals(context.get('params'), params);
equals(context.get('handler'), stateX.routeTriggered);

});