@Test
  public void doesNothingWhenTaskHasNoActions() {
    context.checking(
        new Expectations() {
          {
            allowing(task).getTaskActions();
            will(returnValue(emptyList()));

            one(listener).beforeActions(task);
            inSequence(sequence);

            one(state).setExecuting(true);
            inSequence(sequence);

            one(state).executed(null);
            inSequence(sequence);

            one(state).setExecuting(false);
            inSequence(sequence);

            one(listener).afterActions(task);
            inSequence(sequence);
          }
        });

    executer.execute(task, state, executionContext);
  }
  @Test
  public void stopsAtFirstActionWhichThrowsException() {
    final Throwable failure = new RuntimeException("failure");
    final Collector<Throwable> wrappedFailure = collector();
    context.checking(
        new Expectations() {
          {
            allowing(task).getTaskActions();
            will(returnValue(toList(action1, action2)));

            one(listener).beforeActions(task);
            inSequence(sequence);

            one(state).setExecuting(true);
            inSequence(sequence);

            one(state).setDidWork(true);
            inSequence(sequence);

            one(standardOutputCapture).start();
            inSequence(sequence);

            one(action1).contextualise(executionContext);
            inSequence(sequence);

            one(action1).execute(task);
            will(throwException(failure));
            inSequence(sequence);

            one(action1).contextualise(null);
            inSequence(sequence);

            one(standardOutputCapture).stop();
            inSequence(sequence);

            one(state).executed(with(notNullValue(Throwable.class)));
            will(collectTo(wrappedFailure));
            inSequence(sequence);

            one(state).setExecuting(false);
            inSequence(sequence);

            one(listener).afterActions(task);
            inSequence(sequence);
          }
        });

    executer.execute(task, state, executionContext);

    assertThat(wrappedFailure.get(), instanceOf(TaskExecutionException.class));
    TaskExecutionException exception = (TaskExecutionException) wrappedFailure.get();
    assertThat(exception.getTask(), equalTo((Task) task));
    assertThat(exception.getMessage(), equalTo("Execution failed for <task>."));
    assertThat(exception.getCause(), sameInstance(failure));
  }
  @Test
  public void executeDoesOperateOnNewActionListInstance() {
    context.checking(
        new Expectations() {
          {
            allowing(task).getActions();
            will(returnValue(toList(action1)));

            allowing(task).getTaskActions();
            will(returnValue(toList(action1)));

            one(listener).beforeActions(task);
            inSequence(sequence);

            one(state).setExecuting(true);
            inSequence(sequence);

            one(state).setDidWork(true);
            inSequence(sequence);

            one(standardOutputCapture).start();
            inSequence(sequence);

            one(action1).contextualise(executionContext);
            inSequence(sequence);

            one(action1).execute(task);
            will(
                new CustomAction("Add action to actions list") {
                  public Object invoke(Invocation invocation) throws Throwable {
                    task.getActions().add(action2);
                    return null;
                  }
                });

            inSequence(sequence);

            one(action1).contextualise(null);
            inSequence(sequence);

            one(standardOutputCapture).stop();
            one(state).executed(null);
            inSequence(sequence);

            one(state).setExecuting(false);
            inSequence(sequence);

            one(listener).afterActions(task);
            inSequence(sequence);
          }
        });
    executer.execute(task, state, executionContext);
  }
  @Test
  public void stopsAtFirstActionWhichThrowsStopExecutionException() {
    context.checking(
        new Expectations() {
          {
            allowing(task).getTaskActions();
            will(returnValue(toList(action1, action2)));

            one(listener).beforeActions(task);
            inSequence(sequence);

            one(state).setExecuting(true);
            inSequence(sequence);

            one(state).setDidWork(true);
            inSequence(sequence);

            one(standardOutputCapture).start();
            inSequence(sequence);

            one(action1).contextualise(executionContext);
            inSequence(sequence);

            one(action1).execute(task);
            will(throwException(new StopExecutionException("stop")));
            inSequence(sequence);

            one(action1).contextualise(null);
            inSequence(sequence);

            one(standardOutputCapture).stop();
            inSequence(sequence);

            one(state).executed(null);
            inSequence(sequence);

            one(state).setExecuting(false);
            inSequence(sequence);

            one(listener).afterActions(task);
            inSequence(sequence);
          }
        });

    executer.execute(task, state, executionContext);
  }
  @Test
  public void executesEachActionInOrder() {
    context.checking(
        new Expectations() {
          {
            allowing(task).getTaskActions();
            will(returnValue(toList(action1, action2)));

            one(listener).beforeActions(task);
            inSequence(sequence);

            one(state).setExecuting(true);
            inSequence(sequence);

            one(state).setDidWork(true);
            inSequence(sequence);

            one(standardOutputCapture).start();
            inSequence(sequence);

            one(action1).contextualise(executionContext);
            inSequence(sequence);

            one(action1).execute(task);
            inSequence(sequence);

            one(action1).contextualise(null);
            inSequence(sequence);

            one(standardOutputCapture).stop();
            inSequence(sequence);

            one(state).setDidWork(true);
            inSequence(sequence);

            one(standardOutputCapture).start();
            inSequence(sequence);

            one(action2).contextualise(executionContext);
            inSequence(sequence);

            one(action2).execute(task);
            inSequence(sequence);

            one(action2).contextualise(null);
            inSequence(sequence);

            one(standardOutputCapture).stop();
            inSequence(sequence);

            one(state).executed(null);
            inSequence(sequence);

            one(state).setExecuting(false);
            inSequence(sequence);

            one(listener).afterActions(task);
            inSequence(sequence);
          }
        });

    executer.execute(task, state, executionContext);
  }