package com.greghaskins.spectrum;

import java.util.ArrayList;
import java.util.List;

import org.junit.runner.Description;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;

import com.greghaskins.spectrum.Spectrum.Block;

class TestPlan {

    static class Test {
        public Block block;
        public Description description;
    }

    private final List<Test> tests;
    private Description currentDescription;

    private final Description suiteDescription;

    public TestPlan(final Description rootDescription) {
        suiteDescription = rootDescription;
        tests = new ArrayList<Test>();
    }

    public void addContext(final String context, final Block block) {
        currentDescription = Description.createSuiteDescription(context);
        suiteDescription.addChild(currentDescription);
        try {
            block.run();
        } catch (final Throwable exceptionFromDescribeBlock) {
            final Test failingTest = new Test();
            failingTest.description = Description.createTestDescription(context, "encountered an error");
            failingTest.block = new Block() {

                @Override
                public void run() throws Throwable {
                    throw exceptionFromDescribeBlock;
                }

            };
            tests.add(failingTest);
            currentDescription.addChild(failingTest.description);
        }
    }

    public void addTest(final String behavior, final Block block) {
        final Test test = new Test();
        test.block = block;
        test.description = Description.createTestDescription(currentDescription.getClassName(), behavior);
        tests.add(test);
        currentDescription.addChild(test.description);
    }

    public void execute(final RunNotifier notifier) {
        for (final Test test : tests) {
            notifier.fireTestStarted(test.description);
            try {
                test.block.run();
            } catch (final Throwable e) {
                notifier.fireTestFailure(new Failure(test.description, e));
            }
            notifier.fireTestFinished(test.description);
        }
    }


}

@@ -285,16 +285,24 @@
  %7B%0A%0A    
+private 
 static c
@@ -313,16 +313,16 @@
  Test %7B%0A
-
         
@@ -384,24 +384,403 @@
 ion;%0A    %7D%0A%0A
+    private static class FailingBlock implements Block %7B%0A        private final Throwable exceptionFromDescribeBlock;%0A%0A        private FailingBlock(final Throwable exceptionToThrow) %7B%0A            exceptionFromDescribeBlock = exceptionToThrow;%0A        %7D%0A%0A        @Override%0A        public void run() throws Throwable %7B%0A            throw exceptionFromDescribeBlock;%0A        %7D%0A    %7D%0A%0A
     private 
@@ -1320,505 +1320,75 @@
 le e
-xceptionFromDescribeBlock) %7B%0A            final Test failingTest = new Test();%0A            failingTest.description = Description.createTestDescription(context, %22encountered an error%22);%0A            failingTest.block = new Block() %7B%0A%0A                @Override%0A                public void run() throws Throwable %7B%0A                    throw exceptionFromDescribeBlock;%0A                %7D%0A%0A            %7D;%0A            tests.add(failingTest);%0A            currentDescription.addChild(failingTest.description
+) %7B%0A            addTest(%22encountered an error%22, new FailingBlock(e)
 );%0A 
@@ -2136,14 +2136,13 @@
   %7D%0A
+
     %7D%0A%0A
-%0A
 %7D%0A

remove duplication in TestPlan