Package com.cueup.hegemon.testing

Source Code of com.cueup.hegemon.testing.HegemonRunner$RunScriptTest

/*
* Copyright 2012 the hegemon authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.cueup.hegemon.testing;

import com.cueup.hegemon.LoadError;
import com.cueup.hegemon.LoadPath;
import com.cueup.hegemon.Script;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.internal.runners.statements.InvokeMethod;
import org.junit.internal.runners.statements.RunAfters;
import org.junit.internal.runners.statements.RunBefores;
import org.junit.runner.Description;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.ParentRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;

/**
* Base class for Hegemon tests.
*/
public class HegemonRunner extends ParentRunner<String> {

  /**
   * The Script annotation specifies the scrpt to be run when a class
   * annotated with <code>@RunWith(HegemonRunner.class)</code> is run.
   */
  @Retention(RetentionPolicy.RUNTIME)
  @Target(ElementType.TYPE)
  @Inherited
  public @interface TestScript {
    // This compensates for a bug in checkstyle: http://jira.codehaus.org/browse/MCHECKSTYLE-161
    // lint: disable=JavadocMethodCheck next 3 lines
    /**
     * @return the script to be run
     */
    String filename();
  }


  /**
   * Runs script test as a JUnit statement.
   */
  private static class RunScriptTest extends Statement {

    private final Script script;

    private final Object instance;

    private final Object[] arguments;

    private final String name;


    public RunScriptTest(Script script, Object instance, Object[] arguments, String name) {
      this.script = script;
      this.instance = instance;
      this.arguments = arguments;
      this.name = name;
    }


    @Override
    public void evaluate() throws Exception { // lint: disable=IllegalThrowsCheck
      Script.enterContext();
      try {
        this.script.run("unittest.setTestInstance", this.instance);
        this.script.run(this.name, this.arguments);
      } catch (Throwable t) { //lint: disable=IllegalCatchCheck
        throw new RuntimeException(t);
      } finally {
        Script.exitContext();
      }
    }

  }


  private final Script testScript;

  private final Object instance;

  // TODO(kevinclark): Nullable annotation? Requires dependency.
  private final String method;


  /**
   * Creates a HegemonRunner to run the given class.
   * @param klass the class to run tests for.
   * @throws InitializationError if the test class is malformed.
   */
  public HegemonRunner(Class<?> klass) throws InitializationError {
    this(klass, null);
  }

  /**
   * Creates a HegemonRunner to run the given method in a class.
   * It uses the javascript/ toplevel resource directory as a load path.
   * @param klass the class to run tests for.
   * @param method the test method to run.
   * @throws InitializationError if the test class is malformed.
   */
  public HegemonRunner(Class<?> klass, String method) throws InitializationError {
    this(klass, method, LoadPath.defaultPath());
  }

  /**
   * Creates a HegemonRunner to run the given method of the class.
   * @param klass the class to run tests for.
   * @param method the method to run.
   * @param loadPath where to load javascript files from.
   * @throws InitializationError if the test class is malformed.
   */
  public HegemonRunner(Class<?> klass, String method, LoadPath loadPath) throws InitializationError {
    super(klass);

    this.method = method;

    try {
      this.instance = klass.newInstance();
    } catch (InstantiationException e) {
      throw new InitializationError(e);
    } catch (IllegalAccessException e) {
      throw new InitializationError(e);
    }

    TestScript scriptData = klass.getAnnotation(TestScript.class);
    if (scriptData == null) {
      this.testScript = null;
    } else {
      try {
        String source = loadPath.load(scriptData.filename() + ".js");
        this.testScript = new Script(scriptData.filename(), source, loadPath, "hegemon/unittest");
      } catch (LoadError e) {
        throw new InitializationError(e);
      }
    }
  }


  @Override
  protected List<String> getChildren() {
    if (this.method != null) {
      return ImmutableList.of(this.method);
    } else if (this.testScript == null) {
      List<String> testNames = Lists.newArrayList();
      for (Method method : this.instance.getClass().getMethods()) {
        if (method.isAnnotationPresent(Test.class)
            && (method.getModifiers() & Modifier.PUBLIC) != 0
            && method.getParameterTypes().length == 0) {
          testNames.add(method.getName());
        }
      }
      return testNames;
    } else {
      List<String> testNames = Lists.newArrayList();
      this.testScript.run("unittest.collectTests", this.testScript.getScope(), testNames);
      return testNames;
    }
  }


  @Override
  protected Description describeChild(String child) {
    return Description.createTestDescription(this.getTestClass().getJavaClass(), child);
  }


  @Override
  protected void runChild(String child, RunNotifier notifier) {
    Description d = describeChild(child);
    notifier.fireTestStarted(d);

    Statement statement;
    if (this.testScript == null) {
      try {
        statement = new InvokeMethod(new FrameworkMethod(this.instance.getClass().getMethod(child)), this.instance);
      } catch (NoSuchMethodException e) {
        notifier.fireTestFailure(new Failure(d, e));
        statement = null;
      }
    } else {
      Object[] arguments = null;
      try {
        arguments = (Object[]) this.getTestClass().getJavaClass().getMethod("getArguments").invoke(this.instance);
      } catch (IllegalAccessException e) {
        notifier.fireTestFailure(new Failure(d, e));
      } catch (InvocationTargetException e) {
        notifier.fireTestFailure(new Failure(d, e));
      } catch (NoSuchMethodException e) {
        arguments = new Object[0];
      }

      statement = arguments == null ? null : new RunScriptTest(this.testScript, this.instance, arguments, child);
    }

    if (statement != null) {
      List<FrameworkMethod> before = getTestClass().getAnnotatedMethods(Before.class);
      if (!before.isEmpty()) {
        statement = new RunBefores(statement, before, this.instance);
      }

      List<FrameworkMethod> after = getTestClass().getAnnotatedMethods(After.class);
      if (!after.isEmpty()) {
        statement = new RunAfters(statement, after, this.instance);
      }

      try {
        statement.evaluate();
      } catch (Throwable e) { // lint: disable=IllegalCatchCheck
        notifier.fireTestFailure(new Failure(d, e));
      }
    }

    notifier.fireTestFinished(d);
  }

}
TOP

Related Classes of com.cueup.hegemon.testing.HegemonRunner$RunScriptTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.