<commit_before>package org.testng.internal;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.testng.IClass;
import org.testng.IInstanceInfo;
import org.testng.ITestContext;
import org.testng.ITestObjectFactory;
import org.testng.TestNGException;
import org.testng.annotations.IAnnotation;
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.xml.XmlClass;
import org.testng.xml.XmlTest;

import static org.testng.internal.ClassHelper.getAvailableMethods;

/**
 * This class creates an ITestClass from a test class.
 *
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public class TestNGClassFinder extends BaseClassFinder {
  private ITestContext m_testContext = null;
  private Map<Class, List<Object>> m_instanceMap = Maps.newHashMap();

  public TestNGClassFinder(ClassInfoMap cim,
                           Map<Class, List<Object>> instanceMap,
                           XmlTest xmlTest,
                           IConfiguration configuration,
                           ITestContext testContext)
  {
    m_testContext = testContext;

    if(null == instanceMap) {
      instanceMap= Maps.newHashMap();
    }

    IAnnotationFinder annotationFinder = configuration.getAnnotationFinder();
    ITestObjectFactory objectFactory = configuration.getObjectFactory();

    //
    // Find all the new classes and their corresponding instances
    //
    Set<Class<?>> allClasses= cim.getClasses();

    //very first pass is to find ObjectFactory, can't create anything else until then
    if(objectFactory == null) {
      objectFactory = new ObjectFactoryImpl();
      outer:
      for (Class cls : allClasses) {
        try {
          if (null != cls) {
            Method[] ms;
            try {
              ms = cls.getMethods();
            } catch (NoClassDefFoundError e) {
              // https://github.com/cbeust/testng/issues/602
              ppp("Warning: Can't link and determine methods of " + cls);
              ms = new Method[0];
            }
            for (Method m : ms) {
              IAnnotation a = annotationFinder.findAnnotation(m,
                  org.testng.annotations.IObjectFactoryAnnotation.class);
              if (null != a) {
                if (!ITestObjectFactory.class.isAssignableFrom(m.getReturnType())) {
                  throw new TestNGException("Return type of " + m + " is not IObjectFactory");
                }
                try {
                  Object instance = cls.newInstance();
                  if (m.getParameterTypes().length > 0 && m.getParameterTypes()[0].equals(ITestContext.class)) {
                    objectFactory = (ITestObjectFactory) m.invoke(instance, testContext);
                  } else {
                    objectFactory = (ITestObjectFactory) m.invoke(instance);
                  }
                  break outer;
                }
                catch (Exception ex) {
                  throw new TestNGException("Error creating object factory: " + cls,
                      ex);
                }
              }
            }
          }
        } catch (NoClassDefFoundError e) {
          Utils.log("[TestNGClassFinder]", 1, "Unable to read methods on class " + cls.getName()
              + " - unable to resolve class reference " + e.getMessage());

          for (XmlClass xmlClass : xmlTest.getXmlClasses()) {
            if (xmlClass.loadClasses() && xmlClass.getName().equals(cls.getName())) {
              throw e;
            }
          }

        }
      }
    }

    for(Class cls : allClasses) {
      if((null == cls)) {
        ppp("FOUND NULL CLASS IN FOLLOWING ARRAY:");
        int i= 0;
        for(Class c : allClasses) {
          ppp("  " + i + ": " + c);
        }

        continue;
      }

      if(isTestNGClass(cls, annotationFinder)) {
        List allInstances= instanceMap.get(cls);
        Object thisInstance= (null != allInstances) ? allInstances.get(0) : null;

        // If annotation class and instances are abstract, skip them
        if ((null == thisInstance) && Modifier.isAbstract(cls.getModifiers())) {
          Utils.log("", 5, "[WARN] Found an abstract class with no valid instance attached: " + cls);
          continue;
        }

        IClass ic= findOrCreateIClass(m_testContext, cls, cim.getXmlClass(cls), thisInstance,
            xmlTest, annotationFinder, objectFactory);
        if(null != ic) {
          Object[] theseInstances = ic.getInstances(false);
          if (theseInstances.length == 0) {
            theseInstances = ic.getInstances(true);
          }
          Object instance= theseInstances[0];
          putIClass(cls, ic);

          ConstructorOrMethod factoryMethod =
            ClassHelper.findDeclaredFactoryMethod(cls, annotationFinder);
          if (factoryMethod != null && factoryMethod.getEnabled()) {
            FactoryMethod fm = new FactoryMethod( /* cls, */
              factoryMethod,
              instance,
              xmlTest,
              annotationFinder,
              m_testContext);
            ClassInfoMap moreClasses = new ClassInfoMap();

            {
//            ppp("INVOKING FACTORY " + fm + " " + this.hashCode());
              Object[] instances= fm.invoke();

              //
              // If the factory returned IInstanceInfo, get the class from it,
              // otherwise, just call getClass() on the returned instances
              //
              if (instances.length > 0) {
                if (instances[0] != null) {
                  Class elementClass = instances[0].getClass();
                  if(IInstanceInfo.class.isAssignableFrom(elementClass)) {
                    for(Object o : instances) {
                      IInstanceInfo ii = (IInstanceInfo) o;
                      addInstance(ii.getInstanceClass(), ii.getInstance());
                      moreClasses.addClass(ii.getInstanceClass());
                    }
                  }
                  else {
                    for (int i = 0; i < instances.length; i++) {
                      Object o = instances[i];
                      if (o == null) {
                        throw new TestNGException("The factory " + fm + " returned a null instance" +
                            "at index " + i);
                      } else {
                        addInstance(o.getClass(), o);
                        if(!classExists(o.getClass())) {
                          moreClasses.addClass(o.getClass());
                        }
                      }
                    }
                  }
                }
              }
            }

            if(moreClasses.getSize() > 0) {
              TestNGClassFinder finder=
                new TestNGClassFinder(moreClasses,
                    m_instanceMap,
                    xmlTest,
                    configuration,
                    m_testContext);<commit_msg>Rework usage of InstanceInfo in TestNGClassFinder<commit_after>package org.testng.internal;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.testng.IClass;
import org.testng.IInstanceInfo;
import org.testng.ITestContext;
import org.testng.ITestObjectFactory;
import org.testng.TestNGException;
import org.testng.annotations.IAnnotation;
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.xml.XmlClass;
import org.testng.xml.XmlTest;

import static org.testng.internal.ClassHelper.getAvailableMethods;

/**
 * This class creates an ITestClass from a test class.
 *
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public class TestNGClassFinder extends BaseClassFinder {
  private ITestContext m_testContext = null;
  private Map<Class, List<Object>> m_instanceMap = Maps.newHashMap();

  public TestNGClassFinder(ClassInfoMap cim,
                           Map<Class, List<Object>> instanceMap,
                           XmlTest xmlTest,
                           IConfiguration configuration,
                           ITestContext testContext)
  {
    m_testContext = testContext;

    if(null == instanceMap) {
      instanceMap= Maps.newHashMap();
    }

    IAnnotationFinder annotationFinder = configuration.getAnnotationFinder();
    ITestObjectFactory objectFactory = configuration.getObjectFactory();

    //
    // Find all the new classes and their corresponding instances
    //
    Set<Class<?>> allClasses= cim.getClasses();

    //very first pass is to find ObjectFactory, can't create anything else until then
    if(objectFactory == null) {
      objectFactory = new ObjectFactoryImpl();
      outer:
      for (Class cls : allClasses) {
        try {
          if (null != cls) {
            Method[] ms;
            try {
              ms = cls.getMethods();
            } catch (NoClassDefFoundError e) {
              // https://github.com/cbeust/testng/issues/602
              ppp("Warning: Can't link and determine methods of " + cls);
              ms = new Method[0];
            }
            for (Method m : ms) {
              IAnnotation a = annotationFinder.findAnnotation(m,
                  org.testng.annotations.IObjectFactoryAnnotation.class);
              if (null != a) {
                if (!ITestObjectFactory.class.isAssignableFrom(m.getReturnType())) {
                  throw new TestNGException("Return type of " + m + " is not IObjectFactory");
                }
                try {
                  Object instance = cls.newInstance();
                  if (m.getParameterTypes().length > 0 && m.getParameterTypes()[0].equals(ITestContext.class)) {
                    objectFactory = (ITestObjectFactory) m.invoke(instance, testContext);
                  } else {
                    objectFactory = (ITestObjectFactory) m.invoke(instance);
                  }
                  break outer;
                }
                catch (Exception ex) {
                  throw new TestNGException("Error creating object factory: " + cls,
                      ex);
                }
              }
            }
          }
        } catch (NoClassDefFoundError e) {
          Utils.log("[TestNGClassFinder]", 1, "Unable to read methods on class " + cls.getName()
              + " - unable to resolve class reference " + e.getMessage());

          for (XmlClass xmlClass : xmlTest.getXmlClasses()) {
            if (xmlClass.loadClasses() && xmlClass.getName().equals(cls.getName())) {
              throw e;
            }
          }

        }
      }
    }

    for(Class cls : allClasses) {
      if((null == cls)) {
        ppp("FOUND NULL CLASS IN FOLLOWING ARRAY:");
        int i= 0;
        for(Class c : allClasses) {
          ppp("  " + i + ": " + c);
        }

        continue;
      }

      if(isTestNGClass(cls, annotationFinder)) {
        List allInstances= instanceMap.get(cls);
        Object thisInstance= (null != allInstances) ? allInstances.get(0) : null;

        // If annotation class and instances are abstract, skip them
        if ((null == thisInstance) && Modifier.isAbstract(cls.getModifiers())) {
          Utils.log("", 5, "[WARN] Found an abstract class with no valid instance attached: " + cls);
          continue;
        }

        IClass ic= findOrCreateIClass(m_testContext, cls, cim.getXmlClass(cls), thisInstance,
            xmlTest, annotationFinder, objectFactory);
        if(null != ic) {
          Object[] theseInstances = ic.getInstances(false);
          if (theseInstances.length == 0) {
            theseInstances = ic.getInstances(true);
          }
          Object instance= theseInstances[0];
          putIClass(cls, ic);

          ConstructorOrMethod factoryMethod =
            ClassHelper.findDeclaredFactoryMethod(cls, annotationFinder);
          if (factoryMethod != null && factoryMethod.getEnabled()) {
            FactoryMethod fm = new FactoryMethod( /* cls, */
              factoryMethod,
              instance,
              xmlTest,
              annotationFinder,
              m_testContext);
            ClassInfoMap moreClasses = new ClassInfoMap();

            //
            // If the factory returned IInstanceInfo, get the class from it,
            // otherwise, just call getClass() on the returned instances
            //
            int i = 0;
            for (Object o : fm.invoke()) {
              if (o == null) {
                throw new TestNGException("The factory " + fm + " returned a null instance" +
                    "at index " + i);
              }
              Class<?> elementClass = o.getClass();
              if(IInstanceInfo.class.isAssignableFrom(elementClass)) {
                IInstanceInfo<?> ii = (IInstanceInfo) o;
                addInstance(ii.getInstanceClass(), ii.getInstance());
                moreClasses.addClass(ii.getInstanceClass());
              } else {
                addInstance(o.getClass(), o);
                if(!classExists(o.getClass())) {
                  moreClasses.addClass(o.getClass());
                }
              }
              i++;
            }

            if(moreClasses.getSize() > 0) {
              TestNGClassFinder finder=
                new TestNGClassFinder(moreClasses,
                    m_instanceMap,
                    xmlTest,
                    configuration,
                    m_testContext);
{'fraction_non_alphanumeric': 0.10189090909090909, 'fraction_numerical': 0.0022545454545454544, 'mean_word_length': 1.7629093831625477, 'pattern_counts': {'":': 2, '<': 26, '<?xml version=': 0, '>': 30, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 20}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7656911', 'n_tokens_mistral': 3608, 'n_tokens_neox': 3510, 'n_words': 823}