All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.testng.internal.MethodGroupsHelper Maven / Gradle / Ivy

There is a newer version: 7.10.1
Show newest version
package org.testng.internal;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;

import org.testng.ITestClass;
import org.testng.ITestNGMethod;
import org.testng.annotations.IConfigurationAnnotation;
import org.testng.annotations.ITestOrConfiguration;
import org.testng.collections.Lists;
import org.testng.collections.Maps;
import org.testng.internal.annotations.AnnotationHelper;
import org.testng.internal.annotations.IAnnotationFinder;
import org.testng.internal.collections.Pair;

/**
 * Collections of helper methods to help deal with test methods
 *
 * @author Cedric Beust 
 * @author nullin 
 *
 */
public class MethodGroupsHelper {

  private static final Map PATTERN_CACHE = new ConcurrentHashMap<>();
  private static final Map, Boolean> MATCH_CACHE =
          new ConcurrentHashMap<>();

    /**
   * Collect all the methods that belong to the included groups and exclude all
   * the methods that belong to an excluded group.
   */
  static void collectMethodsByGroup(ITestNGMethod[] methods,
      boolean forTests,
      List outIncludedMethods,
      List outExcludedMethods,
      RunInfo runInfo,
      IAnnotationFinder finder, boolean unique)
  {
    for (ITestNGMethod tm : methods) {
      boolean in = false;
      Method m = tm.getConstructorOrMethod().getMethod();
      //
      // @Test method
      //
      if (forTests) {
        in = MethodGroupsHelper.includeMethod(AnnotationHelper.findTest(finder, m),
            runInfo, tm, forTests, unique, outIncludedMethods);
      }

      //
      // @Configuration method
      //
      else {
        IConfigurationAnnotation annotation = AnnotationHelper.findConfiguration(finder, m);
        if (annotation.getAlwaysRun()) {
        	if (!unique || !MethodGroupsHelper.isMethodAlreadyPresent(outIncludedMethods, tm)) {
        		in = true;
        	}
        }
        else {
          in = MethodGroupsHelper.includeMethod(AnnotationHelper.findTest(finder, tm),
              runInfo, tm, forTests, unique, outIncludedMethods);
        }
      }
      if (in) {
        outIncludedMethods.add(tm);
      }
      else {
        outExcludedMethods.add(tm);
      }
    }
  }

  private static boolean includeMethod(ITestOrConfiguration annotation,
      RunInfo runInfo, ITestNGMethod tm, boolean forTests, boolean unique, List outIncludedMethods)
  {
    boolean result = false;

    if (MethodHelper.isEnabled(annotation)) {
      if (runInfo.includeMethod(tm, forTests)) {
        if (unique) {
          if (!MethodGroupsHelper.isMethodAlreadyPresent(outIncludedMethods, tm)) {
            result = true;
          }
        }
        else {
          result = true;
        }
      }
    }

    return result;
  }

  /**
   * @param result
   * @param tm
   * @return true if a method by a similar name (and same hierarchy) already
   *         exists
   */
  private static boolean isMethodAlreadyPresent(List result,
      ITestNGMethod tm) {
    for (ITestNGMethod m : result) {
      ConstructorOrMethod jm1 = m.getConstructorOrMethod();
      ConstructorOrMethod jm2 = tm.getConstructorOrMethod();
      if (jm1.getName().equals(jm2.getName())) {
        // Same names, see if they are in the same hierarchy
        Class c1 = jm1.getDeclaringClass();
        Class c2 = jm2.getDeclaringClass();
        if (c1.isAssignableFrom(c2) || c2.isAssignableFrom(c1)) {
          return true;
        }
      }
    }

    return false;
  }

  /**
   * Extracts the map of groups and their corresponding methods from the classes.
   */
  public static Map> findGroupsMethods(Collection classes, boolean before) {
    Map> result = Maps.newHashMap();
    for (ITestClass cls : classes) {
      ITestNGMethod[] methods = before ? cls.getBeforeGroupsMethods() : cls.getAfterGroupsMethods();
      for (ITestNGMethod method : methods) {
        for (String group : before ? method.getBeforeGroups() : method.getAfterGroups()) {
          List methodList = result.get(group);
          if (methodList == null) {
            methodList = Lists.newArrayList();
            result.put(group, methodList);
          }
          // NOTE(cbeust, 2007/01/23)
          // BeforeGroups/AfterGroups methods should only be invoked once.
          // I should probably use a map instead of a list for a contains(), but
          // this list should usually be fairly short
          if (! methodList.contains(method)) {
            methodList.add(method);
          }
        }
      }
    }

    return result;
  }

  protected static void findGroupTransitiveClosure(XmlMethodSelector xms,
      List includedMethods,
      List allMethods,
      String[] includedGroups,
      Set outGroups, Set outMethods)
  {
    Map runningMethods = Maps.newHashMap();
    for (ITestNGMethod m : includedMethods) {
      runningMethods.put(m, m);
    }

    Map runningGroups = Maps.newHashMap();
    for (String thisGroup : includedGroups) {
      runningGroups.put(thisGroup, thisGroup);
    }

    boolean keepGoing = true;

    Map newMethods = Maps.newHashMap();
    while (keepGoing) {
      for (ITestNGMethod m : includedMethods) {

        //
        // Depends on groups?
        // Adds all included methods to runningMethods
        //
        String[] ig = m.getGroupsDependedUpon();
        for (String g : ig) {
          if (! runningGroups.containsKey(g)) {
            // Found a new included group, add all the methods it contains to
            // our outMethod closure
            runningGroups.put(g, g);
            ITestNGMethod[] im =
              MethodGroupsHelper.findMethodsThatBelongToGroup(m,
                    allMethods.toArray(new ITestNGMethod[allMethods.size()]), g);
            for (ITestNGMethod thisMethod : im) {
              if (! runningMethods.containsKey(thisMethod)) {
                runningMethods.put(thisMethod, thisMethod);
                newMethods.put(thisMethod, thisMethod);
              }
            }
          }
        } // groups

        //
        // Depends on methods?
        // Adds all depended methods to runningMethods
        //
        String[] mdu = m.getMethodsDependedUpon();
        for (String tm : mdu) {
          ITestNGMethod thisMethod = MethodGroupsHelper.findMethodNamed(tm, allMethods);
          if (thisMethod != null && ! runningMethods.containsKey(thisMethod)) {
            runningMethods.put(thisMethod, thisMethod);
            newMethods.put(thisMethod, thisMethod);
          }
        }

      } // methods

      //
      // Only keep going if new methods have been added
      //
      keepGoing = newMethods.size() > 0;
      includedMethods = Lists.newArrayList();
      includedMethods.addAll(newMethods.keySet());
      newMethods = Maps.newHashMap();
    } // while keepGoing

    outMethods.addAll(runningMethods.keySet());
    outGroups.addAll(runningGroups.keySet());
  }

  private static ITestNGMethod findMethodNamed(String tm, List allMethods) {
    for (ITestNGMethod m : allMethods) {
      // TODO(cbeust):  account for package
      String methodName = m.getQualifiedName();
      if (methodName.equals(tm)) {
        return m;
      }
    }

    return null;
  }

  /**
   * Only used if a group is missing to flag an error on that method
   *
   * @param method if no group is found, group regex is set as this method's missing group
   * @param methods list of methods to search
   * @param groupRegexp regex representing the group
   *
   * @return all the methods that belong to the group specified by the regular
   * expression groupRegExp.  methods[] is the list of all the methods we
   * are choosing from and method is the method that owns the dependsOnGroups
   * statement (only used if a group is missing to flag an error on that method).
   */
  protected static ITestNGMethod[] findMethodsThatBelongToGroup(
      ITestNGMethod method,
      ITestNGMethod[] methods, String groupRegexp)
  {
    ITestNGMethod[] found = findMethodsThatBelongToGroup(methods, groupRegexp);

    if (found.length == 0) {
      method.setMissingGroup(groupRegexp);
    }

    return found;
  }

  /**
   * @param methods list of methods to search
   * @param groupRegexp regex representing the group
   *
   * @return all the methods that belong to the group specified by the regular
   * expression groupRegExp.  methods[] is the list of all the methods we
   * are choosing from.
   */
  protected static ITestNGMethod[] findMethodsThatBelongToGroup(ITestNGMethod[] methods, String groupRegexp)
  {
    List vResult = Lists.newArrayList();
    final Pattern pattern = getPattern(groupRegexp);
    for (ITestNGMethod tm : methods) {
      String[] groups = tm.getGroups();
      for (String group : groups) {
        Boolean match = isMatch(pattern, group);
        if (match) {
          vResult.add(tm);
        }
      }
    }

    return vResult.toArray(new ITestNGMethod[vResult.size()]);
  }

  private static Boolean isMatch(Pattern pattern, String group) {
    Pair cacheKey = Pair.create(pattern.pattern(), group);
    Boolean match = MATCH_CACHE.get(cacheKey);
    if (match == null) {
      match = pattern.matcher(group).matches();
      MATCH_CACHE.put(cacheKey, match);
    }
    return match;
  }

  private static Pattern getPattern(String groupRegexp) {
    Pattern groupPattern = PATTERN_CACHE.get(groupRegexp);
    if (groupPattern == null) {
      groupPattern = Pattern.compile(groupRegexp);
      PATTERN_CACHE.put(groupRegexp, groupPattern);
    }
    return groupPattern;
  }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy