package net.avh4.test.junit;

import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.ParentRunner;
import org.junit.runners.model.InitializationError;

import java.util.Arrays;
import java.util.List;

public class Nested extends Runner {
    private final BlockJUnit4ClassRunner outerClassRunner;
    private final ParentRunner<Class<?>> innerClassesRunner;
    private final Class<?> testClass;

    public Nested(final Class<?> testClass) throws InitializationError {
        BlockJUnit4ClassRunner outerClassRunner;
        try {
            outerClassRunner = new BlockJUnit4ClassRunner(testClass);
        } catch (Exception e) {
            outerClassRunner = null;
        }
        this.outerClassRunner = outerClassRunner;
        innerClassesRunner = new InnerClassesRunner(testClass);
        this.testClass = testClass;
    }

    @Override
    public Description getDescription() {
        Description suiteDescription;
        if (outerClassRunner != null) {
            suiteDescription = outerClassRunner.getDescription();
        } else {
            suiteDescription = Description.createSuiteDescription(testClass);
        }
        for (Description childDescription : innerClassesRunner.getDescription()
                .getChildren()) {
            suiteDescription.addChild(childDescription);
        }
        return suiteDescription;
    }

    @Override
    public void run(RunNotifier notifier) {
        if (outerClassRunner != null) {
            outerClassRunner.run(notifier);
        }
        innerClassesRunner.run(notifier);
    }

    private static class InnerClassesRunner extends ParentRunner<Class<?>> {
        private final Class<?> testClass;

        public InnerClassesRunner(Class<?> testClass)
                throws InitializationError {
            super(testClass);
            this.testClass = testClass;
        }

        @Override
        protected List<Class<?>> getChildren() {
            return Arrays.asList(testClass.getDeclaredClasses());
        }

        @Override
        protected Description describeChild(Class<?> child) {
            return createRunnerForChild(child).getDescription();
        }

        @Override
        protected void runChild(Class<?> child, RunNotifier notifier) {
            createRunnerForChild(child).run(notifier);
        }

        private InnerSpecMethodRunner createRunnerForChild(Class<?> child) {
            try {
                return new InnerSpecMethodRunner(child);
            } catch (InitializationError initializationError) {
                throw new RuntimeException(initializationError);
            }
        }
    }
}

@@ -308,16 +308,42 @@
 Arrays;%0A
+import java.util.HashMap;%0A
 import j
@@ -1822,34 +1822,150 @@
 e final 
-Class%3C?%3E testClass
+HashMap%3CClass%3C?%3E, InnerSpecMethodRunner%3E runners =%0A                new HashMap%3C%3E();%0A        private final List%3CClass%3C?%3E%3E classChildren
 ;%0A%0A     
@@ -2080,32 +2080,33 @@
 per(testClass);%0A
+%0A
             this
@@ -2105,35 +2105,208 @@
     
-this.testClass = testClass;
+classChildren = Arrays.asList(testClass.getDeclaredClasses());%0A            for (Class%3C?%3E aClass : classChildren) %7B%0A                runners.put(aClass, new InnerSpecMethodRunner(aClass));%0A            %7D
 %0A   
@@ -2403,53 +2403,21 @@
 urn 
-Arrays.asList(testClass.getDeclaredClasses())
+classChildren
 ;%0A  
@@ -2524,36 +2524,27 @@
  return 
-createRunnerForChild
+runners.get
 (child).
@@ -2678,356 +2678,41 @@
     
-createRunnerForChild(child).run(notifier);%0A        %7D%0A%0A        private InnerSpecMethodRunner createRunnerForChild(Class%3C?%3E child) %7B%0A            try %7B%0A                return new InnerSpecMethodRunner(child);%0A            %7D catch (InitializationError initializationError) %7B%0A                throw new RuntimeException(initializationError);%0A            %7D
+runners.get(child).run(notifier);
 %0A   

Simplify Nested.InnerClassesRunner