now builds test descriptions recursively
This commit is contained in:
parent
7ea8dc7ce4
commit
45d32509ef
|
@ -1,40 +1,24 @@
|
|||
package be.klak.junit.jasmine;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
import org.junit.runner.Description;
|
||||
|
||||
import be.klak.rhino.RhinoContext;
|
||||
|
||||
|
||||
class JasmineDescriptions {
|
||||
|
||||
private final Description rootDescription;
|
||||
private final Map<String, JasmineSpec> specsMap;
|
||||
private final RhinoContext rhinoContext;
|
||||
private final Description rootDescription;
|
||||
private final Collection<JasmineSpec> specs;
|
||||
|
||||
JasmineDescriptions(Description rootDescription, Map<String, JasmineSpec> specsMap, RhinoContext context) {
|
||||
this.rootDescription = rootDescription;
|
||||
this.specsMap = specsMap;
|
||||
this.rhinoContext = context;
|
||||
}
|
||||
public JasmineDescriptions(Description rootDescription, Collection<JasmineSpec> specs) {
|
||||
this.rootDescription = rootDescription;
|
||||
this.specs = specs;
|
||||
}
|
||||
|
||||
public Description getRootDescription() {
|
||||
return rootDescription;
|
||||
}
|
||||
|
||||
public Collection<JasmineSpec> getAllSpecs() {
|
||||
return specsMap.values();
|
||||
}
|
||||
|
||||
public void executeSpec(Description description) {
|
||||
getSpec(description).execute(rhinoContext);
|
||||
}
|
||||
|
||||
public JasmineSpec getSpec(Description description) {
|
||||
return specsMap.get(description.getDisplayName());
|
||||
}
|
||||
public Description getRootDescription() {
|
||||
return rootDescription;
|
||||
}
|
||||
|
||||
public Collection<JasmineSpec> getSpecs() {
|
||||
return specs;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
package be.klak.junit.jasmine;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.runner.Description;
|
||||
import org.mozilla.javascript.NativeArray;
|
||||
|
@ -11,49 +10,58 @@ import org.mozilla.javascript.NativeObject;
|
|||
|
||||
import be.klak.rhino.RhinoContext;
|
||||
|
||||
public class JasmineJSSuiteConverter {
|
||||
|
||||
class JasmineJSSuiteConverter {
|
||||
private final RhinoContext context;
|
||||
|
||||
private final NativeArray baseSuites;
|
||||
private final RhinoContext context;
|
||||
public JasmineJSSuiteConverter(RhinoContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
JasmineJSSuiteConverter(NativeArray baseSuites, RhinoContext context) {
|
||||
this.baseSuites = baseSuites;
|
||||
this.context = context;
|
||||
}
|
||||
public JasmineDescriptions convertToJunitDescriptions(Class<?> testClass, NativeArray baseSuites) {
|
||||
Description rootDescription = Description.createSuiteDescription(testClass);
|
||||
List<JasmineSpec> specs = convertSuiteArrayToDescriptions(baseSuites, rootDescription, new ArrayList<String>());
|
||||
return new JasmineDescriptions(rootDescription, specs);
|
||||
}
|
||||
|
||||
public JasmineDescriptions convertToJunitDescriptions(Class<?> testClass) {
|
||||
Description rootDescription = Description.createSuiteDescription(testClass);
|
||||
Map<String, JasmineSpec> specsMap = convertSuiteArrayToDescriptions(this.baseSuites, rootDescription);
|
||||
return new JasmineDescriptions(rootDescription, specsMap, context);
|
||||
}
|
||||
private List<JasmineSpec> convertSuiteArrayToDescriptions(NativeArray suiteArray, Description rootDescription,
|
||||
List<String> processed) {
|
||||
List<JasmineSpec> specs = new ArrayList<JasmineSpec>();
|
||||
for (Object idObj : suiteArray.getIds()) {
|
||||
NativeObject suite = (NativeObject) suiteArray.get((Integer) idObj, suiteArray);
|
||||
|
||||
private Map<String, JasmineSpec> convertSuiteArrayToDescriptions(NativeArray suiteArray, Description rootDescription) {
|
||||
Map<String, JasmineSpec> specsMap = new HashMap<String, JasmineSpec>();
|
||||
for (Object idObj : suiteArray.getIds()) {
|
||||
NativeObject suite = (NativeObject) suiteArray.get((Integer) idObj, suiteArray);
|
||||
String description = (String) suite.get("description", suite);
|
||||
if (!processed.contains(description)) {
|
||||
Description suiteDescription = addSuiteToDescription(rootDescription, processed, description);
|
||||
specs.addAll(convertToJunitDescription(suite, suiteDescription));
|
||||
|
||||
Description suiteDescription = Description
|
||||
.createSuiteDescription((String) suite.get("description", suite), (Annotation[]) null);
|
||||
rootDescription.addChild(suiteDescription);
|
||||
specsMap.putAll(convertToJunitDescription(suite, suiteDescription));
|
||||
}
|
||||
NativeArray subSuites = (NativeArray) context.executeFunction(suite, "suites");
|
||||
convertSuiteArrayToDescriptions(subSuites, suiteDescription, processed);
|
||||
}
|
||||
}
|
||||
|
||||
return specsMap;
|
||||
}
|
||||
return specs;
|
||||
}
|
||||
|
||||
private Map<String, JasmineSpec> convertToJunitDescription(NativeObject suite, Description description) {
|
||||
Map<String, JasmineSpec> specsMap = new HashMap<String, JasmineSpec>();
|
||||
NativeArray specsArray = (NativeArray) context.executeFunction(suite, "specs");
|
||||
for (Object idObj : specsArray.getIds()) {
|
||||
NativeObject spec = (NativeObject) specsArray.get((Integer) idObj, specsArray);
|
||||
private Description addSuiteToDescription(Description description, List<String> processed, String suiteName) {
|
||||
processed.add(suiteName);
|
||||
Description suiteDescription = Description.createSuiteDescription(suiteName, (Annotation[]) null);
|
||||
description.addChild(suiteDescription);
|
||||
return suiteDescription;
|
||||
}
|
||||
|
||||
JasmineSpec jasmineSpec = new JasmineSpec(spec);
|
||||
specsMap.put(jasmineSpec.toString(), jasmineSpec);
|
||||
description.addChild(jasmineSpec.getDescription());
|
||||
}
|
||||
private List<JasmineSpec> convertToJunitDescription(NativeObject suite, Description description) {
|
||||
List<JasmineSpec> specsMap = new ArrayList<JasmineSpec>();
|
||||
NativeArray specsArray = (NativeArray) context.executeFunction(suite, "specs");
|
||||
for (Object idObj : specsArray.getIds()) {
|
||||
NativeObject spec = (NativeObject) specsArray.get((Integer) idObj, specsArray);
|
||||
|
||||
return specsMap;
|
||||
}
|
||||
JasmineSpec jasmineSpec = new JasmineSpec(spec);
|
||||
specsMap.add(jasmineSpec);
|
||||
description.addChild(jasmineSpec.getDescription());
|
||||
}
|
||||
|
||||
return specsMap;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package be.klak.junit.jasmine;
|
|||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
@ -15,173 +14,172 @@ import org.mozilla.javascript.tools.debugger.Main;
|
|||
|
||||
import be.klak.rhino.RhinoContext;
|
||||
|
||||
|
||||
public class JasmineTestRunner extends Runner {
|
||||
|
||||
private static final int SLEEP_TIME_MILISECONDS = 50;
|
||||
private static final String JASMINE_LIB_DIR = "/lib/jasmine-1.0.2/";
|
||||
private static final int SLEEP_TIME_MILISECONDS = 50;
|
||||
private static final String JASMINE_LIB_DIR = "/lib/jasmine-1.0.2/";
|
||||
|
||||
private JasmineDescriptions jasmineSuite;
|
||||
private JasmineDescriptions jasmineSuite;
|
||||
|
||||
private final RhinoContext rhinoContext;
|
||||
private final JasmineSuite suiteAnnotation;
|
||||
private final Class<?> testClass;
|
||||
private final RhinoContext rhinoContext;
|
||||
private final JasmineSuite suiteAnnotation;
|
||||
private final Class<?> testClass;
|
||||
|
||||
@JasmineSuite
|
||||
private class DefaultSuite {
|
||||
}
|
||||
@JasmineSuite
|
||||
private class DefaultSuite {
|
||||
}
|
||||
|
||||
public JasmineTestRunner(Class<?> testClass) {
|
||||
this.testClass = testClass;
|
||||
this.suiteAnnotation = getJasmineSuiteAnnotationFromTestClass();
|
||||
public JasmineTestRunner(Class<?> testClass) {
|
||||
this.testClass = testClass;
|
||||
this.suiteAnnotation = getJasmineSuiteAnnotationFromTestClass();
|
||||
|
||||
Main debugger = null;
|
||||
if (this.suiteAnnotation.debug()) {
|
||||
debugger = this.rhinoContext.createDebugger();
|
||||
}
|
||||
Main debugger = null;
|
||||
if (this.suiteAnnotation.debug()) {
|
||||
debugger = this.rhinoContext.createDebugger();
|
||||
}
|
||||
|
||||
this.rhinoContext = setUpRhinoScope();
|
||||
this.rhinoContext = setUpRhinoScope();
|
||||
|
||||
if (this.suiteAnnotation.debug()) {
|
||||
debugger.doBreak();
|
||||
}
|
||||
}
|
||||
if (this.suiteAnnotation.debug()) {
|
||||
debugger.doBreak();
|
||||
}
|
||||
}
|
||||
|
||||
private RhinoContext setUpRhinoScope() {
|
||||
RhinoContext context = new RhinoContext();
|
||||
context.loadEnv(suiteAnnotation.jsRootDir());
|
||||
setUpJasmine(context);
|
||||
private RhinoContext setUpRhinoScope() {
|
||||
RhinoContext context = new RhinoContext();
|
||||
context.loadEnv(suiteAnnotation.jsRootDir());
|
||||
setUpJasmine(context);
|
||||
|
||||
context.load(suiteAnnotation.sourcesRootDir() + "/", suiteAnnotation.sources());
|
||||
context.load(suiteAnnotation.jsRootDir() + "/specs/", getJasmineSpecs(suiteAnnotation));
|
||||
return context;
|
||||
}
|
||||
context.load(suiteAnnotation.sourcesRootDir() + "/", suiteAnnotation.sources());
|
||||
context.load(suiteAnnotation.jsRootDir() + "/specs/", getJasmineSpecs(suiteAnnotation));
|
||||
return context;
|
||||
}
|
||||
|
||||
private void setUpJasmine(RhinoContext context) {
|
||||
context.load(getJsLibDir() + "jasmine.js");
|
||||
context.load(getJsLibDir() + "jasmine.delegator_reporter.js");
|
||||
private void setUpJasmine(RhinoContext context) {
|
||||
context.load(getJsLibDir() + "jasmine.js");
|
||||
context.load(getJsLibDir() + "jasmine.delegator_reporter.js");
|
||||
|
||||
context.evalJS("jasmine.getEnv().addReporter(new jasmine.DelegatorJUnitReporter());");
|
||||
}
|
||||
context.evalJS("jasmine.getEnv().addReporter(new jasmine.DelegatorJUnitReporter());");
|
||||
}
|
||||
|
||||
private JasmineSuite getJasmineSuiteAnnotationFromTestClass() {
|
||||
JasmineSuite suiteAnnotation = testClass.getAnnotation(JasmineSuite.class);
|
||||
if (suiteAnnotation == null) {
|
||||
suiteAnnotation = DefaultSuite.class.getAnnotation(JasmineSuite.class);
|
||||
}
|
||||
return suiteAnnotation;
|
||||
}
|
||||
private JasmineSuite getJasmineSuiteAnnotationFromTestClass() {
|
||||
JasmineSuite suiteAnnotation = testClass.getAnnotation(JasmineSuite.class);
|
||||
if (suiteAnnotation == null) {
|
||||
suiteAnnotation = DefaultSuite.class.getAnnotation(JasmineSuite.class);
|
||||
}
|
||||
return suiteAnnotation;
|
||||
}
|
||||
|
||||
private String[] getJasmineSpecs(JasmineSuite suiteAnnotation) {
|
||||
if (suiteAnnotation.specs().length == 0) {
|
||||
return new String[] { StringUtils.uncapitalize(testClass.getSimpleName()).replace("Test", "Spec") + ".js" };
|
||||
}
|
||||
return suiteAnnotation.specs();
|
||||
}
|
||||
private String[] getJasmineSpecs(JasmineSuite suiteAnnotation) {
|
||||
if (suiteAnnotation.specs().length == 0) {
|
||||
return new String[] { StringUtils.uncapitalize(testClass.getSimpleName()).replace("Test", "Spec") + ".js" };
|
||||
}
|
||||
return suiteAnnotation.specs();
|
||||
}
|
||||
|
||||
private void resetEnvjsWindowSpace() {
|
||||
this.rhinoContext.evalJS("window.location = '" + suiteAnnotation.jsRootDir() + "/lib/blank.html';");
|
||||
}
|
||||
private void resetEnvjsWindowSpace() {
|
||||
this.rhinoContext.evalJS("window.location = '" + suiteAnnotation.jsRootDir() + "/lib/blank.html';");
|
||||
}
|
||||
|
||||
private String getJsLibDir() {
|
||||
return suiteAnnotation.jsRootDir() + JASMINE_LIB_DIR;
|
||||
}
|
||||
private String getJsLibDir() {
|
||||
return suiteAnnotation.jsRootDir() + JASMINE_LIB_DIR;
|
||||
}
|
||||
|
||||
private JasmineDescriptions getJasmineDescriptions() {
|
||||
if (this.jasmineSuite == null) {
|
||||
NativeArray baseSuites = (NativeArray) rhinoContext.evalJS("jasmine.getEnv().currentRunner().suites()");
|
||||
this.jasmineSuite = new JasmineJSSuiteConverter(baseSuites, rhinoContext).convertToJunitDescriptions(testClass);
|
||||
}
|
||||
return this.jasmineSuite;
|
||||
}
|
||||
private JasmineDescriptions getJasmineDescriptions() {
|
||||
if (this.jasmineSuite == null) {
|
||||
NativeArray baseSuites = (NativeArray) rhinoContext.evalJS("jasmine.getEnv().currentRunner().suites()");
|
||||
this.jasmineSuite = new JasmineJSSuiteConverter(rhinoContext).convertToJunitDescriptions(testClass, baseSuites);
|
||||
}
|
||||
return this.jasmineSuite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Description getDescription() {
|
||||
return getJasmineDescriptions().getRootDescription();
|
||||
}
|
||||
@Override
|
||||
public Description getDescription() {
|
||||
return getJasmineDescriptions().getRootDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(RunNotifier notifier) {
|
||||
generateSpecRunnerIfNeeded();
|
||||
@Override
|
||||
public void run(RunNotifier notifier) {
|
||||
generateSpecRunnerIfNeeded();
|
||||
|
||||
for (JasmineSpec spec : getJasmineDescriptions().getAllSpecs()) {
|
||||
Object testClassInstance = createTestClassInstance();
|
||||
fireMethodsWithSpecifiedAnnotationIfAny(testClassInstance, Before.class);
|
||||
for (JasmineSpec spec : getJasmineDescriptions().getSpecs()) {
|
||||
Object testClassInstance = createTestClassInstance();
|
||||
fireMethodsWithSpecifiedAnnotationIfAny(testClassInstance, Before.class);
|
||||
|
||||
try {
|
||||
notifier.fireTestStarted(spec.getDescription());
|
||||
spec.execute(rhinoContext);
|
||||
while (!spec.isDone()) {
|
||||
waitALittle();
|
||||
}
|
||||
try {
|
||||
notifier.fireTestStarted(spec.getDescription());
|
||||
spec.execute(rhinoContext);
|
||||
while (!spec.isDone()) {
|
||||
waitALittle();
|
||||
}
|
||||
|
||||
reportSpecResultToNotifier(notifier, spec);
|
||||
resetEnvjsWindowSpace();
|
||||
} finally {
|
||||
fireMethodsWithSpecifiedAnnotationIfAny(testClassInstance, After.class);
|
||||
}
|
||||
}
|
||||
reportSpecResultToNotifier(notifier, spec);
|
||||
resetEnvjsWindowSpace();
|
||||
} finally {
|
||||
fireMethodsWithSpecifiedAnnotationIfAny(testClassInstance, After.class);
|
||||
}
|
||||
}
|
||||
|
||||
this.rhinoContext.exit();
|
||||
}
|
||||
this.rhinoContext.exit();
|
||||
}
|
||||
|
||||
private Object createTestClassInstance() {
|
||||
try {
|
||||
return testClass.newInstance();
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Unable to create a new instance of testClass " + testClass.getSimpleName()
|
||||
+ " using a no-arg constructor", ex);
|
||||
}
|
||||
}
|
||||
private Object createTestClassInstance() {
|
||||
try {
|
||||
return testClass.newInstance();
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Unable to create a new instance of testClass " + testClass.getSimpleName()
|
||||
+ " using a no-arg constructor", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void fireMethodsWithSpecifiedAnnotationIfAny(Object testClassInstance, Class<? extends Annotation> annotation) {
|
||||
for (Method method : testClass.getMethods()) {
|
||||
private void fireMethodsWithSpecifiedAnnotationIfAny(Object testClassInstance, Class<? extends Annotation> annotation) {
|
||||
for (Method method : testClass.getMethods()) {
|
||||
|
||||
try {
|
||||
if (method.getAnnotation(annotation) != null) {
|
||||
method.setAccessible(true);
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
if (parameterTypes.length == 0) {
|
||||
method.invoke(testClassInstance, (Object[]) null);
|
||||
} else if (parameterTypes.length == 1 && RhinoContext.class.isAssignableFrom(parameterTypes[0])) {
|
||||
method.invoke(testClassInstance, new Object[] { this.rhinoContext });
|
||||
} else {
|
||||
throw new IllegalStateException("Annotated method does not have zero or rhinoContext as parameterTypes");
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(
|
||||
"Exception while firing " + annotation.getSimpleName() + " method: " + method.getName(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (method.getAnnotation(annotation) != null) {
|
||||
method.setAccessible(true);
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
if (parameterTypes.length == 0) {
|
||||
method.invoke(testClassInstance, (Object[]) null);
|
||||
} else if (parameterTypes.length == 1 && RhinoContext.class.isAssignableFrom(parameterTypes[0])) {
|
||||
method.invoke(testClassInstance, new Object[] { this.rhinoContext });
|
||||
} else {
|
||||
throw new IllegalStateException("Annotated method does not have zero or rhinoContext as parameterTypes");
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(
|
||||
"Exception while firing " + annotation.getSimpleName() + " method: " + method.getName(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generateSpecRunnerIfNeeded() {
|
||||
if (suiteAnnotation.generateSpecRunner()) {
|
||||
String[] jasmineSpecs = getJasmineSpecs(suiteAnnotation);
|
||||
new JasmineSpecRunnerGenerator(jasmineSpecs, suiteAnnotation, suiteAnnotation.jsRootDir() + "/runners",
|
||||
testClass.getSimpleName()
|
||||
+ "Runner.html")
|
||||
.generate();
|
||||
}
|
||||
}
|
||||
private void generateSpecRunnerIfNeeded() {
|
||||
if (suiteAnnotation.generateSpecRunner()) {
|
||||
String[] jasmineSpecs = getJasmineSpecs(suiteAnnotation);
|
||||
new JasmineSpecRunnerGenerator(jasmineSpecs, suiteAnnotation, suiteAnnotation.jsRootDir() + "/runners",
|
||||
testClass.getSimpleName()
|
||||
+ "Runner.html")
|
||||
.generate();
|
||||
}
|
||||
}
|
||||
|
||||
private void reportSpecResultToNotifier(RunNotifier notifier, JasmineSpec spec) {
|
||||
if (spec.isPassed(rhinoContext)) {
|
||||
notifier.fireTestFinished(spec.getDescription());
|
||||
} else if (spec.isFailed(rhinoContext)) {
|
||||
notifier.fireTestFailure(spec.getJunitFailure(rhinoContext));
|
||||
} else {
|
||||
throw new IllegalStateException("Unexpected spec status received: " + spec);
|
||||
}
|
||||
}
|
||||
private void reportSpecResultToNotifier(RunNotifier notifier, JasmineSpec spec) {
|
||||
if (spec.isPassed(rhinoContext)) {
|
||||
notifier.fireTestFinished(spec.getDescription());
|
||||
} else if (spec.isFailed(rhinoContext)) {
|
||||
notifier.fireTestFailure(spec.getJunitFailure(rhinoContext));
|
||||
} else {
|
||||
throw new IllegalStateException("Unexpected spec status received: " + spec);
|
||||
}
|
||||
}
|
||||
|
||||
private void waitALittle() {
|
||||
try {
|
||||
Thread.sleep(SLEEP_TIME_MILISECONDS);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
private void waitALittle() {
|
||||
try {
|
||||
Thread.sleep(SLEEP_TIME_MILISECONDS);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Reference in New Issue