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

org.evosuite.regression.ObjectFields Maven / Gradle / Ivy

/**
 * 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.regression;

import org.apache.commons.lang3.ClassUtils;
import org.evosuite.testcase.execution.Scope;
import org.evosuite.testcase.variable.VariableReference;
import org.evosuite.utils.generic.GenericClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.management.RuntimeErrorException;

/**
 * Implementation of object distance following
 * "Object distance and its application to adaptive random testing of object-oriented programs"
 * by Ilinca Ciupa, Andreas Leitner, Manuel Oriol, Bertrand Meyer (http://se.ethz.ch/~meyer/publications/testing/object_distance.pdf).
 *
 * We implemented the following changes:
 * 
    *
  • In the paper if a reference field does not match (i.e., is different * because the types are different) then R = 10 is used as difference. This does * not make sense for several reasons: *
      *
    • The difference is already taken into account in the type distance.
    • *
    • If one type adds a field but the other does not, so what? R/2?
    • *
    * Therefore we decided to apply the value R as factor in the type difference to * the non-shared fields.
  • *
  • In the paper a factor of 1/2 is applied to the recursive distance. We * treat the recursive distance simply as any other field distance, thus it is * normalized by the number of fields and not by a static factor.
  • *
  • There is no distance given for two characters. We defined that to be C = * 10.
  • *
*/ public class ObjectFields { private static final double B = 10; private static final double R = 10; private static final double V = 10; private static final double C = 10; private static int MAX_RECURSION = 1; /* * public static double getObjectDistance(Object p, Object q) { double * distance = new ObjectVariables().getObjectDistanceImpl(p, q); assert * distance >= 0.0 : "Result was " + distance; assert * !Double.isNaN(distance); assert !Double.isInfinite(distance); return * distance; } */ private Scope scope; public ObjectFields(Scope s) { scope = s; // getObjectVariables(); } /* * public static Object getObjectVariables(Object p) { Object distance = new * ObjectVariables().getObjectValue(p); // assert distance >= 0.0 : * "Result was " + distance; // assert !Double.isNaN(distance); // assert * !Double.isInfinite(distance); return distance; } */ public List>> getObjectVariables(Object p, Class c) { List>> vars = getFieldValues(c, p); // logger.warn("getObjectVariables: " + vars); return vars; } private static Collection getAllFields(Class commonAncestor) { Collection result = new ArrayList(); Class ancestor = commonAncestor; while (!ancestor.equals(Object.class)) { for (Field f : ancestor.getDeclaredFields()) { if (Modifier.isFinal(f.getModifiers())) continue; if (Modifier.isStatic(f.getModifiers())) continue; result.add(f); } // result.addAll(Arrays.asList(ancestor.getDeclaredFields())); ancestor = ancestor.getSuperclass(); } return result; } /* * private static Class getCommonAncestor(Object p) { double pInheritCnt * = getTypeDistance(Object.class, p); * * Class pClass = p.getClass(); * * while (!pClass.equals(qClass)) { if (pInheritCnt > qInheritCnt) { pClass * = pClass.getSuperclass(); pInheritCnt--; } else { qClass = * qClass.getSuperclass(); qInheritCnt--; } } return pClass; } */ private static boolean getElementaryValue(Boolean p) { return p.booleanValue(); } private static char getElementaryValue(Character p) { return p.charValue(); } private static double getElementaryValue(Number p) { return p.doubleValue(); } private static double getElementaryValue(Enum p) { return p.ordinal(); } private static String getElementaryValue(String p) { return p; } private static Object getFieldValue(Field field, Object p) { try { /*Class objClass = p.getClass(); if(p instanceof java.lang.String){ ((String) p).hashCode(); }*/ Class fieldType = field.getType(); field.setAccessible(true); if (fieldType.isPrimitive()) { if (fieldType.equals(Boolean.TYPE)) { return field.getBoolean(p); } if (fieldType.equals(Integer.TYPE)) { return field.getInt(p); } if (fieldType.equals(Byte.TYPE)) { return field.getByte(p); } if (fieldType.equals(Short.TYPE)) { return field.getShort(p); } if (fieldType.equals(Long.TYPE)) { return field.getLong(p); } if (fieldType.equals(Double.TYPE)) { return field.getDouble(p); } if (fieldType.equals(Float.TYPE)) { return field.getFloat(p); } if (fieldType.equals(Character.TYPE)) { return field.getChar(p); } throw new UnsupportedOperationException("Primitive type " + fieldType + " not implemented!"); } return field.get(p); } catch (IllegalAccessException exc) { throw new RuntimeException(exc); } catch (OutOfMemoryError e) { e.printStackTrace(); if (MAX_RECURSION != 0) MAX_RECURSION = 0; else throw new RuntimeErrorException(e); return getFieldValue(field, p); } } /* * private static Integer getHasCode(Object p) { return ((p == null) ? 0 : * p.hashCode()) ; } */ private static Collection getNonSharedFields( Class commonAncestor, Object p) { Collection result = new ArrayList(); Class ancestor = p.getClass(); while (!ancestor.equals(commonAncestor)) { result.addAll(Arrays.asList(ancestor.getDeclaredFields())); ancestor = ancestor.getSuperclass(); } return result; } private static double getTypeDistance(Class commonAncestor, Object p) { double result = 0.0; Class ancestor = p.getClass(); while (!ancestor.equals(commonAncestor)) { ancestor = ancestor.getSuperclass(); result++; } return result; } private static double getTypeDistance(Class commonAncestor, Object p, Object q) { double result = getTypeDistance(commonAncestor, p) + getTypeDistance(commonAncestor, q); result += getNonSharedFields(commonAncestor, p).size() * R; result += getNonSharedFields(commonAncestor, q).size() * R; return result; } private final Map hashRecursionCntMap = new LinkedHashMap(); private final Map resultCache = new LinkedHashMap(); /* * private boolean breakRecursion(Object p) { Integer hashCode = * getHasCode(p); Integer recursionCnt = hashRecursionCntMap.get(hashCode); * if (recursionCnt == null) { recursionCnt = 0; } if (recursionCnt >= * MAX_RECURSION) { return true; } recursionCnt++; * hashRecursionCntMap.put(hashCode, recursionCnt); return false; } */ /* * private double getCompositeObjectValue(Object p) { Double cachedDistance * = resultCache.get(getHasCode(p)); if (cachedDistance != null) { return * cachedDistance; } if (breakRecursion(p)) { return 0.0; } Class * commonAncestor = getCommonAncestor(p); double distance = * getTypeDistance(commonAncestor, p); //distance += * getFieldDistance(commonAncestor, p); resultCache.put(getHasCode(p), * distance); return distance; } */ public Map>> getObjectVariables() { //List>> ov = new ArrayList>>(); //Map> variable_field = new HashMap>(); Map>> variable_ref_field = new HashMap>>(); //Map field_value = new HashMap(); // Collection fields = getAllFields(c); //List values = new ArrayList(); /* * for (Field field : fields) { if (p.getClass().isPrimitive()) * values.add(getObjectValue(getFieldValue(field, p))); else * values.addAll(getObjectValues(getFieldValue(field, p))); * * } */ for (VariableReference vref : scope.getVariables()) { Object scope_object = scope.getObject(vref); if (scope_object == null) continue; String vref_class = vref.getClassName(); // logger.warn(x); int vref_string = vref.getStPosition(); Map objectMap = getObjectMap(scope_object); Map> vrefObjectMap = new HashMap>(); vrefObjectMap.put(vref_class, objectMap); // variable_field.put(vref_string, objectMap); variable_ref_field.put(vref_string, vrefObjectMap); /* * * Class so_class = scope_object.getClass(); * * int vref_string = vref.getStPosition(); * * if (ClassUtils.isPrimitiveOrWrapper(scope_object.getClass())) { * Map all_vars = new HashMap(); * variable_field.put(vref_string, (Map) (all_vars * .put("fake_var", scope_object))); } else { Map * all_vars = getAllVars(scope_object, 0,""); * variable_field.put(vref_string, all_vars); } */ // boolean is_prim = ClassUtils.isPrimitiveOrWrapper(so_class); // assert is_prim != false : so_class.toString(); /* * logger.warn("scope_ob: " + scope_object.toString() + ", so_class" * + so_class.toString() + ", vref:" + vref_string + * ",primitve? "+is_prim); */ } return variable_ref_field; } public Map> getObjectVariables( Collection vrefs) { List>> ov = new ArrayList>>(); Map> variable_field = new HashMap>(); Map>> variable_ref_field = new HashMap>>(); Map field_value = new HashMap(); // Collection fields = getAllFields(c); List values = new ArrayList(); /* * for (Field field : fields) { if (p.getClass().isPrimitive()) * values.add(getObjectValue(getFieldValue(field, p))); else * values.addAll(getObjectValues(getFieldValue(field, p))); * * } */ for (VariableReference vref : vrefs) { Object scope_object = scope.getObject(vref); if (scope_object == null) continue; String vref_class = vref.getClassName(); // logger.warn(x); int vref_string = vref.getStPosition(); Map objectMap = getObjectMap(scope_object); // Map> vrefObjectMap = new // HashMap>(); // vrefObjectMap.put(vref_class, objectMap); variable_field.put(vref_string, objectMap); // variable_ref_field.put(vref_string, vrefObjectMap); /* * * Class so_class = scope_object.getClass(); * * int vref_string = vref.getStPosition(); * * if (ClassUtils.isPrimitiveOrWrapper(scope_object.getClass())) { * Map all_vars = new HashMap(); * variable_field.put(vref_string, (Map) (all_vars * .put("fake_var", scope_object))); } else { Map * all_vars = getAllVars(scope_object, 0,""); * variable_field.put(vref_string, all_vars); } */ // boolean is_prim = ClassUtils.isPrimitiveOrWrapper(so_class); // assert is_prim != false : so_class.toString(); /* * logger.warn("scope_ob: " + scope_object.toString() + ", so_class" * + so_class.toString() + ", vref:" + vref_string + * ",primitve? "+is_prim); */ } return variable_field; } public static Map getObjectMap(Object o) { if (ClassUtils.isPrimitiveOrWrapper(o.getClass()) || (o instanceof String)) { Map objectMap = new HashMap(); objectMap.put("fake_var_" + o.getClass().getName().replace('.', '_'), o); return objectMap; } else { return getAllVars(o, 0, ""); } } public static int getDim(Object array) { int dim = 0; Class cls = array.getClass(); while (cls.isArray()) { dim++; cls = cls.getComponentType(); } return dim; } private static Map getAllVars(Object p, int counter, String prefix) { // TODO Auto-generated method stub // logger.warn("getting: " + ((p instanceof Field)?((Field) // p).getType():p.getClass()) + ", count:" + counter); Map values = new HashMap(); // if(((p instanceof Field)?((Field) p).getType():p.getClass()) == null) // return values; if (p == null) return values; Collection fields = getAllFields(p.getClass()); for (Field field : fields) { // String what_happened = ""; GenericClass gc = new GenericClass(field.getType()); if (ClassUtils.isPrimitiveOrWrapper(field.getType()) || gc.isString()) { // what_happened += ", " + field.getType() + " is primitive,"; if (field.getName().equals("serialVersionUID")) continue; values.put(prefix + field.getName(), getObjectValue(getFieldValue(field, p))); } else if (field.getType().equals(Object.class) || counter >= MAX_RECURSION) { values.put(prefix + field.getName(), (getObjectValue(getFieldValue(field, p)) != null)); // what_happened += ", " + field.getType() + ",reached end,"; } else if (field.getType().isArray()) { /* * values.put(prefix + field.getName(), Array * .getLength(getObjectValue(getFieldValue(field, p)))); */ // Object[] arr = (Object[]) getFieldValue(field, p); /* * for(Object o: arr){ values.putAll(getAllVars(o, counter + * 1,prefix + ((prefix.equals(""))?"":".")+field.getName())); } */ Object arr = getFieldValue(field, p); if (arr == null) return values; for (int n = 0; n < Array.getLength(arr); n++) { // values.putAll(getAllVars(Array.get(arr,n), counter + // 1,prefix + ((prefix.isEmpty())?"":".")+field.getName())); values.put( prefix + field.getName(), getAllVars(Array.get(arr, n), counter + 1, prefix + ((prefix.isEmpty()) ? "" : ".") + field.getName())); } } else { try { field.setAccessible(true); // values.putAll(getAllVars(field.get(p), counter + 1,prefix // + ((prefix.isEmpty())?"":".")+field.getName())); values.put( prefix + field.getName(), getAllVars(field.get(p), counter + 1, prefix + ((prefix.isEmpty()) ? "" : ".") + field.getName())); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block return values; } catch (IllegalAccessException e) { // TODO Auto-generated catch block return values; } // what_happened += ", " + field.getType() + ",recursed,"; } // logger.warn(prefix + field.getName() + what_happened); } /* * if (ClassUtils.isPrimitiveOrWrapper(p.getClass())){ * * return null; } else { * * } */ return values; } private static final Logger logger = LoggerFactory .getLogger(ObjectFields.class); private Collection getObjectValues(Object fieldValue) { int i = 0; List values = new ArrayList(); while (!fieldValue.getClass().isPrimitive() && i < 10) { Collection fields = getAllFields(fieldValue.getClass()); for (Field field : fields) { if (fieldValue.getClass().isPrimitive()) values.add(getObjectValue(getFieldValue(field, fieldValue))); else fieldValue = field; } i++; } return values; } private Collection getAllObjectValues(Object p, int counter) { if (!p.getClass().isPrimitive()) return null;// getObjectValues(p,(counter+1)); else { } return null; } private List>> getFieldValues( Class commonAncestor, Object p) { Collection fields = getAllFields(commonAncestor); List values = new ArrayList(); for (Field field : fields) { values.add(getObjectValue(getFieldValue(field, p))); int counter = 0; if (!p.getClass().isPrimitive()) { } // field. } /* * List>>; var.getStPosition() -> * Map Object> * * @Test public void test() { Foo var0 = new Foo(); Bar var1 = foo.b; } * * [ { 0 -> { "x" -> 0; "b.y" -> 0; } }, { 0 -> { "x" -> 0; "b.y" -> 0; * }, 1 -> { "y" -> 0 }} ] * * * class Bar { int y; } class Foo { int x; Bar b; } * * "x" -> 1; "b.y" -> 2; */ return null; // return values; } private static Object getObjectValue(Object p) { if ((p == null)) { return V; } // What if one is a primitive and the other not? // if (!value.getClass().equals(value2.getClass())) ? if (p instanceof Number) { return getElementaryValue((Number) p); } if (p instanceof Enum) { return getElementaryValue((Enum) p); } if (p instanceof Boolean) { return getElementaryValue((Boolean) p); } if (p instanceof String) { return getElementaryValue((String) p); } if (p instanceof Character) { return getElementaryValue((Character) p); } return p;// getCompositeObjectValue(p); } }