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

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

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

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import org.testng.ITestNGMethod;
import org.testng.collections.Lists;
import org.testng.collections.Maps;

public class MethodInheritance {

  /**
   * A Custom comparator that helps in {@link ITestNGMethod} ordering keeping in mind the class hierarchy.
   * Here's how the comparator works: 
* Lets say we have two method objects o1 and o2.
* o1 is associated with MyClass and o2 is associated with * AnotherClass. *
    *
  • -1 is returned if MyClass is the parent of AnotherClass
  • *
  • 1 is returned if AnotherClass is the parent of MyClass
  • *
  • 0 is returned otherwise if MyClass and AnotherClass are the same i.e., both methods belong to the same * class.
  • * *
* * Working of isAssignableFrom
* Lets say we have :
*
    *
  1. interface Oven
  2. *
  3. Microwave implements Oven
  4. *
* *
    *
  1. microwave instanceof Oven : returns true
  2. *
  3. Oven.class.isAssignableFrom(microwave.getClass()) : returns true
  4. *
* */ private static final Comparator COMPARATOR = new Comparator() { @Override public int compare(ITestNGMethod o1, ITestNGMethod o2) { int result = -2; Class thisClass = o1.getRealClass(); Class otherClass = o2.getRealClass(); if (thisClass.isAssignableFrom(otherClass)) { result = -1; } else if (otherClass.isAssignableFrom(thisClass)) { result = 1; } else if (o1.equals(o2)) { result = 0; } return result; } }; /** * Look in map for a class that is a superclass of methodClass */ private static List findMethodListSuperClass(Map> map, Class< ? extends ITestNGMethod> methodClass) { for (Map.Entry> entry : map.entrySet()) { if (entry.getKey().isAssignableFrom(methodClass)) { return entry.getValue(); } } return null; } /** * Look in map for a class that is a subclass of methodClass */ private static Class findSubClass(Map> map, Class< ? extends ITestNGMethod> methodClass) { for (Class cls : map.keySet()) { if (methodClass.isAssignableFrom(cls)) { return cls; } } return null; } /** * Fix the methodsDependedUpon to make sure that @Configuration methods * respect inheritance (before methods are invoked in the order Base first * and after methods are invoked in the order Child first) * * @param methods the list of methods * @param before true if we are handling a before method (meaning, the methods * need to be sorted base class first and subclass last). false otherwise (subclass * methods first, base classes last). */ public static void fixMethodInheritance(ITestNGMethod[] methods, boolean before) { // Map of classes -> List of methods that belong to this class or same hierarchy Map> map = Maps.newHashMap(); // // Put the list of methods in their hierarchy buckets // for (ITestNGMethod method : methods) { Class< ? extends ITestNGMethod> methodClass = method.getRealClass(); List l = findMethodListSuperClass(map, methodClass); if (null != l) { l.add(method); } else { Class subClass = findSubClass(map, methodClass); if (null != subClass) { l = map.get(subClass); l.add(method); map.remove(subClass); map.put(methodClass, l); } else { l = Lists.newArrayList(); l.add(method); map.put(methodClass, l); } } } // // Each bucket that has a list bigger than one element gets sorted // for (List l : map.values()) { if (l.size() > 1) { // Sort them sortMethodsByInheritance(l, before); /* * Set methodDependedUpon accordingly * E.g. Base class can have multiple @BeforeClass methods. Need to ensure * that @BeforeClass methods in derived class depend on all @BeforeClass methods * of base class. Vice versa for @AfterXXX methods */ for (int i = 0; i < l.size() - 1; i++) { ITestNGMethod m1 = l.get(i); for (int j = i + 1; j < l.size(); j++) { ITestNGMethod m2 = l.get(j); if (!equalsEffectiveClass(m1, m2) && !dependencyExists(m1, m2, methods)) { Utils.log("MethodInheritance", 4, m2 + " DEPENDS ON " + m1); m2.addMethodDependedUpon(MethodHelper.calculateMethodCanonicalName(m1)); } } } } } } private static boolean dependencyExists(ITestNGMethod m1, ITestNGMethod m2, ITestNGMethod[] methods) { return internalDependencyExists(m1, m2, methods) || internalDependencyExists(m2, m1, methods); } private static boolean internalDependencyExists(ITestNGMethod m1, ITestNGMethod m2, ITestNGMethod[] methods) { ITestNGMethod[] methodsNamed = MethodHelper.findDependedUponMethods(m1, methods); for (ITestNGMethod method : methodsNamed) { if (method.equals(m2)) { return true; } } for (String group : m1.getGroupsDependedUpon()) { ITestNGMethod[] methodsThatBelongToGroup = MethodGroupsHelper.findMethodsThatBelongToGroup(m1, methods, group); for (ITestNGMethod method : methodsThatBelongToGroup) { if (method.equals(m2)) { return true; } } } return false; } private static boolean equalsEffectiveClass(ITestNGMethod m1, ITestNGMethod m2) { try { Class c1 = m1.getRealClass(); Class c2 = m2.getRealClass(); return c1 == null ? c2 == null : c1.equals(c2); } catch(Exception ex) { return false; } } /** * Given a list of methods belonging to the same class hierarchy, orders them * from the base class to the child (if true) or from child to base class (if false) * @param methods */ private static void sortMethodsByInheritance(List methods, boolean baseClassToChild) { Collections.sort(methods, COMPARATOR); if (! baseClassToChild) { Collections.reverse(methods); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy