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

org.evosuite.setup.ConcreteClassAnalyzer Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) 2010-2018 Gordon Fraser, Andrea Arcuri and EvoSuite
 * contributors
 *
 * This file is part of EvoSuite.
 *
 * EvoSuite is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3.0 of the License, or
 * (at your option) any later version.
 *
 * EvoSuite is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with EvoSuite. If not, see .
 */
package org.evosuite.setup;


import org.evosuite.Properties;
import org.evosuite.TestGenerationContext;
import org.evosuite.runtime.mock.MockList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Modifier;
import java.util.*;

public class ConcreteClassAnalyzer {

    private static Logger logger = LoggerFactory.getLogger(ConcreteClassAnalyzer.class);

    private static ConcreteClassAnalyzer instance;

    private ConcreteClassAnalyzer() {

    }

    public static ConcreteClassAnalyzer getInstance() {
        if(instance == null)
            instance = new ConcreteClassAnalyzer();

        return instance;
    }


    private Map, Set>> cache = new LinkedHashMap<>();

    public void clear() {
        cache.clear();
    }

    public Set> getConcreteClasses(Class clazz,
                                            InheritanceTree inheritanceTree) {
        if(cache.containsKey(clazz))
            return cache.get(clazz);

        Set> classes = getConcreteClassesImpl(clazz, inheritanceTree);
        cache.put(clazz, classes);
        return classes;
    }

    private Set> getConcreteClassesImpl(Class clazz,
                                                   InheritanceTree inheritanceTree) {

        // Some special cases
        if (clazz.equals(java.util.Map.class))
            return getConcreteClassesMap();
        else if (clazz.equals(java.util.List.class))
            return getConcreteClassesList();
        else if (clazz.equals(Set.class))
            return getConcreteClassesSet();
        else if (clazz.equals(java.util.Collection.class))
            return getConcreteClassesList();
        else if (clazz.equals(java.util.Iterator.class))
            // We don't want to explicitly create iterators
            // This would only pull in java.util.Scanner, the only
            // concrete subclass
            return new LinkedHashSet>();
        else if (clazz.equals(java.util.ListIterator.class))
            // We don't want to explicitly create iterators
            return new LinkedHashSet>();
        else if (clazz.equals(java.io.Serializable.class))
            return new LinkedHashSet>();
        else if (clazz.equals(Comparable.class))
            return getConcreteClassesComparable();
        else if (clazz.equals(java.util.Comparator.class))
            return new LinkedHashSet>();
        else if (clazz.equals(java.io.Reader.class))
            return getConcreteClassesReader();
        else if (clazz.equals(java.io.Writer.class))
            return getConcreteClassesWriter();

        Set> actualClasses = new LinkedHashSet>();
        if (Modifier.isAbstract(clazz.getModifiers())
                || Modifier.isInterface(clazz.getModifiers()) || clazz.equals(Enum.class)) {
            // We have to use getName here and not getCanonicalName
            // because getCanonicalname uses . rather than $ for inner classes
            // but the InheritanceTree uses $
            String className = clazz.getName();
            if(MockList.isAMockClass(className))
                className = clazz.getSuperclass().getName();
            Set subClasses = inheritanceTree.getSubclasses(className);
            logger.debug("Subclasses of " + clazz.getName() + ": " + subClasses);
            Map classDistance = new HashMap();
            int maxDistance = -1;
            String name = clazz.getName();
            if (clazz.equals(Enum.class)) {
                name = Properties.TARGET_CLASS;
            }
            for (String subClass : subClasses) {
                int distance = TestClusterUtils.getPackageDistance(subClass, name);
                classDistance.put(subClass, distance);
                maxDistance = Math.max(distance, maxDistance);
            }
            int distance = 0;
            while (actualClasses.isEmpty() && distance <= maxDistance) {
                logger.debug(" Current distance: " + distance);
                for (String subClass : subClasses) {
                    if (TestClusterUtils.isAnonymousClass(subClass)) {
                        continue;
                    }

                    if (classDistance.get(subClass) == distance) {
                        try {
                            TestGenerationContext.getInstance().goingToExecuteSUTCode();
                            Class subClazz = Class.forName(subClass,
                                                              false,
                                                              TestGenerationContext.getInstance().getClassLoaderForSUT());
                            if (!TestUsageChecker.canUse(subClazz))
                                continue;
                            if (subClazz.isInterface())
                                continue;
                            if (Modifier.isAbstract(subClazz.getModifiers())) {
                                if(!TestClusterUtils.hasStaticGenerator(subClazz))
                                    continue;
                            }
                            Class mock = MockList.getMockClass(subClazz.getCanonicalName());
                            if (mock != null) {
                                /*
                                 * If we are mocking this class, then such class should not be used
                                 * in the generated JUnit test cases, but rather its mock.
                                 */
                                logger.debug("Adding mock " + mock + " instead of "
                                        + clazz);
                                subClazz = mock;
                            } else {

                                if (!TestClusterUtils.checkIfCanUse(subClazz.getCanonicalName())) {
                                    continue;
                                }
                            }

                            actualClasses.add(subClazz);

                        } catch (ClassNotFoundException | IncompatibleClassChangeError | NoClassDefFoundError e) {
                            logger.error("Problem for " + Properties.TARGET_CLASS
                                    + ". Class not found: " + subClass, e);
                            logger.error("Removing class from inheritance tree");
                            inheritanceTree.removeClass(subClass);
                        } finally {
                            TestGenerationContext.getInstance().doneWithExecutingSUTCode();
                        }
                    }
                }
                distance++;
            }
            if(TestClusterUtils.hasStaticGenerator(clazz)) {
                actualClasses.add(clazz);
            }
            if (actualClasses.isEmpty()) {
                logger.info("Don't know how to instantiate abstract class {}", clazz.getName());
            }
        } else {
            actualClasses.add(clazz);
        }

        logger.debug("Subclasses of " + clazz.getName() + ": " + actualClasses);
        return actualClasses;
    }

    private Set> getConcreteClassesMap() {
        Set> mapClasses = new LinkedHashSet<>();
        Class mapClazz;
        try {
            mapClazz = Class.forName("java.util.HashMap",
                                     false,
                                     TestGenerationContext.getInstance().getClassLoaderForSUT());
            mapClasses.add(mapClazz);
        } catch (ClassNotFoundException e) {
            logger.error(e.getMessage());
        }
        return mapClasses;
    }

    private Set> getConcreteClassesList() {
        Set> mapClasses = new LinkedHashSet>();
        Class mapClazz;
        try {
            mapClazz = Class.forName("java.util.LinkedList",
                                     false,
                                     TestGenerationContext.getInstance().getClassLoaderForSUT());
            mapClasses.add(mapClazz);
        } catch (ClassNotFoundException e) {
            logger.error(e.getMessage());
        }
        return mapClasses;
    }

    private Set> getConcreteClassesSet() {
        Set> mapClasses = new LinkedHashSet>();
        Class setClazz;
        try {
            setClazz = Class.forName("java.util.LinkedHashSet",
                                     false,
                                     TestGenerationContext.getInstance().getClassLoaderForSUT());
            mapClasses.add(setClazz);
        } catch (ClassNotFoundException e) {
            logger.error(e.getMessage());
        }
        return mapClasses;
    }

    private Set> getConcreteClassesReader() {
        Set> mapClasses = new LinkedHashSet>();
        Class setClazz;
        try {
            setClazz = Class.forName("java.io.StringReader",
                    false,
                    TestGenerationContext.getInstance().getClassLoaderForSUT());
            mapClasses.add(setClazz);
        } catch (ClassNotFoundException e) {
            logger.error(e.getMessage());
        }
        return mapClasses;
    }

    private Set> getConcreteClassesWriter() {
        Set> mapClasses = new LinkedHashSet>();
        Class setClazz;
        try {
            setClazz = Class.forName("java.io.StringWriter",
                    false,
                    TestGenerationContext.getInstance().getClassLoaderForSUT());
            mapClasses.add(setClazz);
        } catch (ClassNotFoundException e) {
            logger.error(e.getMessage());
        }
        return mapClasses;
    }

    private Set> getConcreteClassesComparable() {
        Set> comparableClasses = new LinkedHashSet>();
        Class comparableClazz;
        try {
            comparableClazz = Class.forName("java.lang.Integer",
                                            false,
                                            TestGenerationContext.getInstance().getClassLoaderForSUT());
            comparableClasses.add(comparableClazz);
        } catch (ClassNotFoundException e) {
            logger.error(e.getMessage());
        }
        return comparableClasses;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy