From b3a2ddb4dac7da97e82d1cfdebe7876f74f7a70c Mon Sep 17 00:00:00 2001 From: GeraldineGalindoG <42702922+GeraldineGalindo@users.noreply.github.com> Date: Thu, 20 Apr 2023 15:45:43 -0400 Subject: [PATCH 1/5] feat(heuristics-implementation) --- .../main/java/org/evosuite/Properties.java | 9 + .../evosuite/testcase/TestCodeVisitor.java | 177 +++++++++++++++--- .../statements/ConstructorStatement.java | 31 +++ .../testcase/statements/MethodStatement.java | 19 ++ .../testcase/utils/HeuristicsUtil.java | 39 ++++ 5 files changed, 254 insertions(+), 21 deletions(-) create mode 100644 client/src/main/java/org/evosuite/testcase/utils/HeuristicsUtil.java diff --git a/client/src/main/java/org/evosuite/Properties.java b/client/src/main/java/org/evosuite/Properties.java index a372f7c03c..27d2b81255 100755 --- a/client/src/main/java/org/evosuite/Properties.java +++ b/client/src/main/java/org/evosuite/Properties.java @@ -1234,6 +1234,8 @@ public enum OutputGranularity { @Parameter(key = "max_coverage_depth", group = "Output", description = "Maximum depth in the calltree to count a branch as covered") public static int MAX_COVERAGE_DEPTH = -1; + // --------------------------------------------------------------- + // Naming public enum TestNamingStrategy { NUMBERED, COVERAGE } @@ -1241,6 +1243,13 @@ public enum TestNamingStrategy { @Parameter(key = "test_naming_strategy", group = "Output", description = "What strategy to use to derive names for tests") public static TestNamingStrategy TEST_NAMING_STRATEGY = TestNamingStrategy.NUMBERED; + public enum VariableNamingStrategy { + TYPE_BASED, HEURISTICS_BASED, INFO_COLLECTOR + } + + @Parameter(key = "variable_naming_strategy", group = "Output", description = "What strategy to use to name variables for tests") + public static VariableNamingStrategy VARIABLE_NAMING_STRATEGY = VariableNamingStrategy.HEURISTICS_BASED; + // --------------------------------------------------------------- // Sandbox @Parameter(key = "sandbox", group = "Sandbox", description = "Execute tests in a sandbox environment") diff --git a/client/src/main/java/org/evosuite/testcase/TestCodeVisitor.java b/client/src/main/java/org/evosuite/testcase/TestCodeVisitor.java index d1b8149b49..b72be17526 100755 --- a/client/src/main/java/org/evosuite/testcase/TestCodeVisitor.java +++ b/client/src/main/java/org/evosuite/testcase/TestCodeVisitor.java @@ -25,6 +25,7 @@ import org.apache.commons.lang3.CharUtils; import org.apache.commons.lang3.ClassUtils; import org.apache.commons.lang3.StringEscapeUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.reflect.TypeUtils; import org.evosuite.PackageInfo; import org.evosuite.Properties; @@ -37,6 +38,7 @@ import org.evosuite.testcase.fm.MethodDescriptor; import org.evosuite.testcase.statements.*; import org.evosuite.testcase.statements.environment.EnvironmentDataStatement; +import org.evosuite.testcase.utils.HeuristicsUtil; import org.evosuite.testcase.variable.*; import org.evosuite.utils.NumberFormatter; import org.evosuite.utils.StringUtil; @@ -71,6 +73,12 @@ public class TestCodeVisitor extends TestVisitor { protected final Map nextIndices = new HashMap<>(); + /** + * Dictionaries for naming information + */ + protected Map methodNames = new HashMap<>(); + protected Map argumentNames = new HashMap<>(); + /** *

* getCode @@ -389,15 +397,15 @@ public String getVariableName(VariableReference var) { + className.substring(1) + "Array"; variableName = variableName.replace('.', '_').replace("[]", ""); if (!variableNames.containsKey(var)) { - if (!nextIndices.containsKey(variableName)) { - nextIndices.put(variableName, 0); - } - - int index = nextIndices.get(variableName); - nextIndices.put(variableName, index + 1); - - variableName += index; - +// if (!nextIndices.containsKey(variableName)) { +// nextIndices.put(variableName, 0); +// } +// +// int index = nextIndices.get(variableName); +// nextIndices.put(variableName, index + 1); +// +// variableName += index; + variableName = getNameByStrategy(var, variableName); variableNames.put(var, variableName); } @@ -422,21 +430,124 @@ public String getVariableName(VariableReference var) { if (CharUtils.isAsciiNumeric(variableName.charAt(variableName.length() - 1))) variableName += "_"; - if (!nextIndices.containsKey(variableName)) { - nextIndices.put(variableName, 0); - } - - int index = nextIndices.get(variableName); - nextIndices.put(variableName, index + 1); - - variableName += index; +// if (!nextIndices.containsKey(variableName)) { +// nextIndices.put(variableName, 0); +// } +// +// int index = nextIndices.get(variableName); +// nextIndices.put(variableName, index + 1); +// +// variableName += index; // } - + variableName = getNameByStrategy(var, variableName); variableNames.put(var, variableName); } return variableNames.get(var); } + /** + * Returns the suggested name for a variable according to Properties configuration + * + * 1. TYPE_BASED --> Using type names + index as suggested name (this is the traditional naming in EvoSuite) + * 2. HEURISTICS_BASED --> Using information about arguments + methods + types for proposing a name + index if name is repeated more than once + * 3. INFO_COLLECTOR --> Mode for controlling all the information about the test retrieved via reflection, only for debugging purposes + * + * @return String + */ + private String getNameByStrategy(final VariableReference var, final String originalVariableName) { + String variableName = ""; + if (Properties.VARIABLE_NAMING_STRATEGY == Properties.VariableNamingStrategy.TYPE_BASED) { + variableName = originalVariableName; + variableName = getIndexIncludingFirstAppearance(variableName); + } + if (Properties.VARIABLE_NAMING_STRATEGY == Properties.VariableNamingStrategy.HEURISTICS_BASED) { + variableName = this.getPrioritizedName(var, originalVariableName); + variableName = getVariableWithIndexExcludingFirstAppearance(variableName); + } + return variableName; + } + + /** + * Returns the variable name + the corresponding index if and only if there is more than one repetition of the name, + * otherwise, it returns the name without an index at last. + * + * Mainly used for Heuristic Renaming Strategy. + * + * @return String + */ + private String getVariableWithIndexExcludingFirstAppearance(String variableName) { + if (!this.nextIndices.containsKey(variableName)) { + this.nextIndices.put(variableName, 0); + } + else { + final int index = this.nextIndices.get(variableName); + this.nextIndices.put(variableName, index + 1); + variableName += this.nextIndices.get(variableName); + } + return variableName; + } + + /** + * Returns the variable name + the number of repetitions counting from 0. + * i.e. If the variable appears only once in the test, it is named as variable0. + * + * Mainly used for Type-Based Renaming Strategy (traditional naming in EvoSuite). + * + * @return String + */ + private String getIndexIncludingFirstAppearance(String variableName) { + if (!nextIndices.containsKey(variableName)) { + nextIndices.put(variableName, 0); + } + int index = nextIndices.get(variableName); + nextIndices.put(variableName, index + 1); + return variableName += index; + } + /** + * Retrieve a suggested name based on method, argument and type information. + * + * The followed order for prioritizing is: + * 1. Use argument suggestion, if not possible + * 2. Use method suggestion + reductions, if not possible + * 3. Use type suggestion, traditional naming. + * + * @return String + */ + private String getPrioritizedName(final VariableReference var, String variableName) { + final String methodCode = this.methodNames.get(var); + final String arguments = this.argumentNames.get(var); + if (arguments != null) { + variableName = arguments; + } + else if (methodCode != null) { + variableName = analyzeMethodName(methodCode); + } + if(variableName.equals(var.getSimpleClassName())){ + variableName = "_" + variableName; + } + return variableName; + } + + /** + * Returns the suggested method name controlling camel case and excluding some particles + * of the method names. + * + * @return String + */ + private String analyzeMethodName(String methodCode) { + String name = ""; + ArrayList methodName = HeuristicsUtil.separateByCamelCase(methodCode); + if(methodCode.length() > 0){ + if(HeuristicsUtil.containsAvoidableParticle(methodName.get(0)) && methodName.size() > 1){ + name = StringUtils.join(methodName.subList(1,methodName.size()), ""); + final char[] auxCharArray = name.toCharArray(); + auxCharArray[0] = Character.toLowerCase(auxCharArray[0]); + return new String(auxCharArray); + } + } + return methodCode; + } + /** * Retrieve the names of all known variables * @@ -1380,17 +1491,18 @@ public void visitMethodStatement(MethodStatement statement) { Throwable exception = getException(statement); List parameters = statement.getParameterReferences(); boolean isGenericMethod = method.hasTypeParameters(); - if (exception != null && !statement.isDeclaredException(exception)) { result += "// Undeclared exception!" + NEWLINE; } - boolean lastStatement = statement.getPosition() == statement.getTestCase().size() - 1; boolean unused = !Properties.ASSERTIONS ? exception != null : test != null && !test.hasReferences(retval); if (!retval.isVoid() && retval.getAdditionalVariableReference() == null && !unused) { + if (!this.methodNames.containsKey(retval)) { + this.methodNames.put(retval, method.getName()); + } if (exception != null) { if (!lastStatement || statement.hasAssertions()) result += getClassName(retval) + " " + getVariableName(retval) @@ -1403,7 +1515,22 @@ public void visitMethodStatement(MethodStatement statement) { result += "try { " + NEWLINE + " "; } - + if (!this.argumentNames.containsKey(retval)) { + final List parameterNames = (List)statement.obtainParameterNameListInOrder(); + int idx = 0; + for (final VariableReference param : parameters) { + this.argumentNames.put(param, parameterNames.get(idx)); + ++idx; + } + } + if (retval.isVoid()) { + final List parameterNames = (List)statement.obtainParameterNameListInOrder(); + int idx = 0; + for (final VariableReference param : parameters) { + this.argumentNames.put(param, parameterNames.get(idx)); + ++idx; + } + } String parameter_string = getParameterString(method.getParameterTypes(), parameters, isGenericMethod, method.isOverloaded(parameters), 0); @@ -1632,6 +1759,14 @@ public void visitConstructorStatement(ConstructorStatement statement) { && !Modifier.isStatic(constructor.getConstructor().getDeclaringClass().getModifiers()); List parameters = statement.getParameterReferences(); + if (!this.argumentNames.containsKey(retval)) { + final List parameterNames = (List)statement.obtainParameterNameListInOrder(); + int idx = 0; + for (final VariableReference param : parameters) { + this.argumentNames.put(param, parameterNames.get(idx)); + ++idx; + } + } int startPos = 0; if (isNonStaticMemberClass) { startPos = 1; diff --git a/client/src/main/java/org/evosuite/testcase/statements/ConstructorStatement.java b/client/src/main/java/org/evosuite/testcase/statements/ConstructorStatement.java index 93eddcaae0..2049c43f57 100755 --- a/client/src/main/java/org/evosuite/testcase/statements/ConstructorStatement.java +++ b/client/src/main/java/org/evosuite/testcase/statements/ConstructorStatement.java @@ -38,6 +38,7 @@ import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; +import java.lang.reflect.Parameter; import java.util.*; /** @@ -478,4 +479,34 @@ public String getDeclaringClassName() { public String getMethodName() { return ""; } + + /** + * Returns a list of the parameter names of a method using reflection. The list is in order of + * declaration in the method. + * + * @return List + */ + public List obtainParameterNameListInOrder() { + final Parameter[] parameters = this.constructor.getParameters(); + final List names = new ArrayList(); + for (final Parameter p : parameters) { + names.add(p.getName()); + } + return names; + } + + /** + * Returns a string concatenation of the parameter names of a method using reflection. + * The string contains the parameter names separated by low bars, and in order of declaration + * + * @return String + */ + public String obtainParameterNamesInOrder() { + final Parameter[] parameters = this.constructor.getParameters(); + String names = ""; + for (final Parameter p : parameters) { + names = names + p.getName() + "_"; + } + return names; + } } diff --git a/client/src/main/java/org/evosuite/testcase/statements/MethodStatement.java b/client/src/main/java/org/evosuite/testcase/statements/MethodStatement.java index 7b45edd43b..b5903d088a 100755 --- a/client/src/main/java/org/evosuite/testcase/statements/MethodStatement.java +++ b/client/src/main/java/org/evosuite/testcase/statements/MethodStatement.java @@ -36,6 +36,7 @@ import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Parameter; import java.util.*; import java.util.stream.Collectors; @@ -650,4 +651,22 @@ public String getDeclaringClassName() { public String getMethodName() { return method.getName(); } + + public List obtainParameterNameListInOrder() { + final Parameter[] parameters = this.method.getParameters(); + final List names = new ArrayList(); + for (final Parameter p : parameters) { + names.add(p.getName()); + } + return names; + } + + public String obtainParameterNamesInOrder() { + final Parameter[] parameters = this.method.getParameters(); + String names = ""; + for (final Parameter p : parameters) { + names = names + p.getName() + "_"; + } + return names; + } } diff --git a/client/src/main/java/org/evosuite/testcase/utils/HeuristicsUtil.java b/client/src/main/java/org/evosuite/testcase/utils/HeuristicsUtil.java new file mode 100644 index 0000000000..306102aeb3 --- /dev/null +++ b/client/src/main/java/org/evosuite/testcase/utils/HeuristicsUtil.java @@ -0,0 +1,39 @@ +package org.evosuite.testcase.utils; +import java.util.ArrayList; + +public class HeuristicsUtil { + /** + * List of particles of a method name that can be excluded or avoided when syggesting names + */ + private static ArrayList avoidableParticles = new ArrayList(){ + { + add("get"); + add("to"); + add("has"); + add("is"); + add("are"); + } + }; + + /** + * Returns a boolean value that indicates if the first word of a method can be avoided/excluded + * on method name suggestion + * @return boolean + */ + + public static boolean containsAvoidableParticle(String firstWord){ + return avoidableParticles.contains(firstWord); + } + /** + * Separates camelcase strings and retrieves the parts in a list + * @return ArrayList + */ + public static ArrayList separateByCamelCase(String name){ + ArrayList separatedName = new ArrayList<>(); + for (String word : name.split("(? Date: Fri, 21 Apr 2023 10:01:04 -0400 Subject: [PATCH 2/5] feat(added-method-naming-tests) --- .../main/java/org/evosuite/Properties.java | 2 +- .../testcase/TestCodeVisitorTest.java | 94 +++++++++++++++++++ .../org/evosuite/utils/generic/Person.java | 26 +++++ 3 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 client/src/test/java/org/evosuite/utils/generic/Person.java diff --git a/client/src/main/java/org/evosuite/Properties.java b/client/src/main/java/org/evosuite/Properties.java index 27d2b81255..360123b188 100755 --- a/client/src/main/java/org/evosuite/Properties.java +++ b/client/src/main/java/org/evosuite/Properties.java @@ -1248,7 +1248,7 @@ public enum VariableNamingStrategy { } @Parameter(key = "variable_naming_strategy", group = "Output", description = "What strategy to use to name variables for tests") - public static VariableNamingStrategy VARIABLE_NAMING_STRATEGY = VariableNamingStrategy.HEURISTICS_BASED; + public static VariableNamingStrategy VARIABLE_NAMING_STRATEGY = VariableNamingStrategy.TYPE_BASED; // --------------------------------------------------------------- // Sandbox diff --git a/client/src/test/java/org/evosuite/testcase/TestCodeVisitorTest.java b/client/src/test/java/org/evosuite/testcase/TestCodeVisitorTest.java index 16b2bd4a84..61ca54c285 100644 --- a/client/src/test/java/org/evosuite/testcase/TestCodeVisitorTest.java +++ b/client/src/test/java/org/evosuite/testcase/TestCodeVisitorTest.java @@ -23,6 +23,7 @@ import com.examples.with.different.packagename.AbstractEnumUser; import com.examples.with.different.packagename.EnumInInnerClass; import com.examples.with.different.packagename.EnumUser; +import org.evosuite.Properties; import org.evosuite.ga.ConstructionFailedException; import org.evosuite.testcase.statements.ArrayStatement; import org.evosuite.testcase.statements.AssignmentStatement; @@ -32,6 +33,7 @@ import org.evosuite.testcase.variable.VariableReference; import org.evosuite.utils.generic.GenericConstructor; import org.evosuite.utils.generic.GenericMethod; +import org.evosuite.utils.generic.Person; import org.evosuite.utils.generic.WildcardTypeImpl; import org.junit.Assert; import org.junit.Test; @@ -322,4 +324,96 @@ public void testInnerClassAbstractEnum() throws NoSuchMethodException, Construct assertFalse(code.contains("= AbstractEnumInInnerClass.AnEnum.1.FOO")); assertTrue(code.contains("= AbstractEnumInInnerClass.AnEnum.FOO")); } + + @Test + public void testMethodRenamingWithHeuristics() throws Exception{ + + Properties.getInstance().setValue("variable_naming_strategy", Properties.VariableNamingStrategy.HEURISTICS_BASED); + TestCase tc = new DefaultTestCase(); + // new Person() + VariableReference person = TestFactory.getInstance().addConstructor(tc, + new GenericConstructor(Person.class.getDeclaredConstructor(), Person.class), 0, 0); + //getFixedId() + Method m0 = Person.class.getDeclaredMethod("getFixedId"); + GenericMethod gm0 = new GenericMethod(m0, Person.class); + MethodStatement ms0 = new MethodStatement(tc, gm0, person, Arrays.asList()); + VariableReference var0 = tc.addStatement(ms0); + //setAge(); + Method m1 = Person.class.getDeclaredMethod("setAge", int.class); + GenericMethod gm1 = new GenericMethod(m1, Person.class); + MethodStatement ms1 = new MethodStatement(tc, gm1, person, Arrays.asList(var0)); + tc.addStatement(ms1); + //getAge(); + Method m2 = Person.class.getDeclaredMethod("getAge"); + GenericMethod gm2 = new GenericMethod(m2, Person.class); + VariableReference var1 = TestFactory.getInstance().addMethod(tc, gm2,3,0); + AssignmentStatement as0 = new AssignmentStatement(tc, var0, var1); + tc.addStatement(as0); + //isAdult(); + Method m3 = Person.class.getDeclaredMethod("isAdult"); + GenericMethod gm3 = new GenericMethod(m3, Person.class); + VariableReference var2 = TestFactory.getInstance().addMethod(tc, gm3,4,0); + AssignmentStatement as1 = new AssignmentStatement(tc, var2, var2); + tc.addStatement(as1); + + + //Finally, visit the test + TestCodeVisitor visitor = new TestCodeVisitor(); + tc.accept(visitor); //should not throw exception + String code = visitor.getCode(); + System.out.println(code); + + assertTrue(code.contains("int age = person.getAge()")); + assertFalse(code.contains("int int1 = person0.getAge()")); + assertTrue(code.contains("int fixedId = person.getFixedId()")); + assertFalse(code.contains("int int0 = person0.getFixedId()")); + assertTrue(code.contains("boolean adult = person.isAdult()")); + assertFalse(code.contains("boolean boolean0 = person0.isAdult()")); + } + + @Test + public void testMethodRenamingWithTypes() throws Exception{ + + Properties.getInstance().setValue("variable_naming_strategy", Properties.VariableNamingStrategy.TYPE_BASED); + TestCase tc = new DefaultTestCase(); + // new Person() + VariableReference person = TestFactory.getInstance().addConstructor(tc, + new GenericConstructor(Person.class.getDeclaredConstructor(), Person.class), 0, 0); + //getFixedId() + Method m0 = Person.class.getDeclaredMethod("getFixedId"); + GenericMethod gm0 = new GenericMethod(m0, Person.class); + MethodStatement ms0 = new MethodStatement(tc, gm0, person, Arrays.asList()); + VariableReference var0 = tc.addStatement(ms0); + //setAge(); + Method m1 = Person.class.getDeclaredMethod("setAge", int.class); + GenericMethod gm1 = new GenericMethod(m1, Person.class); + MethodStatement ms1 = new MethodStatement(tc, gm1, person, Arrays.asList(var0)); + tc.addStatement(ms1); + //getAge(); + Method m2 = Person.class.getDeclaredMethod("getAge"); + GenericMethod gm2 = new GenericMethod(m2, Person.class); + VariableReference var1 = TestFactory.getInstance().addMethod(tc, gm2,3,0); + AssignmentStatement as0 = new AssignmentStatement(tc, var0, var1); + tc.addStatement(as0); + //isAdult(); + Method m3 = Person.class.getDeclaredMethod("isAdult"); + GenericMethod gm3 = new GenericMethod(m3, Person.class); + VariableReference var2 = TestFactory.getInstance().addMethod(tc, gm3,4,0); + AssignmentStatement as1 = new AssignmentStatement(tc, var2, var2); + tc.addStatement(as1); + + + //Finally, visit the test + TestCodeVisitor visitor = new TestCodeVisitor(); + tc.accept(visitor); //should not throw exception + String code = visitor.getCode(); + System.out.println(code); + + assertFalse(code.contains("int age = person.getAge()")); + assertTrue(code.contains("int int1 = person0.getAge()")); + assertFalse(code.contains("int fixedId = person.getFixedId()")); + assertTrue(code.contains("int int0 = person0.getFixedId()")); + assertFalse(code.contains("boolean adult = person.isAdult()")); + assertTrue(code.contains("boolean boolean0 = person0.isAdult()")); + } } diff --git a/client/src/test/java/org/evosuite/utils/generic/Person.java b/client/src/test/java/org/evosuite/utils/generic/Person.java new file mode 100644 index 0000000000..797f816410 --- /dev/null +++ b/client/src/test/java/org/evosuite/utils/generic/Person.java @@ -0,0 +1,26 @@ +package org.evosuite.utils.generic; +/** + * Simple test class of simple setters and getters. + * Used for testing variable name generation + */ +public class Person { + String name; + Long id; + int age; + Person () { + } + Person (String name, Long id) { + this.name = name; + this.id = id; + } + public void setId(long id) {this.id = id;} + public void setName(String name) {this.name = name;} + public void setAge(int actualAge) {this.age = actualAge;} + public String getName() { return name; } + public Long getId() { return id; } + public int getAge() { return age; } + + public boolean isAdult() { return age>=18; } + public int getFixedId() {return 18;} +} + From 44fe28ec581e7a061cc253995ea039d05924fef0 Mon Sep 17 00:00:00 2001 From: GeraldineGalindoG <42702922+GeraldineGalindo@users.noreply.github.com> Date: Mon, 24 Apr 2023 08:35:56 -0400 Subject: [PATCH 3/5] fix(minor-delete) --- client/src/main/java/org/evosuite/Properties.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/main/java/org/evosuite/Properties.java b/client/src/main/java/org/evosuite/Properties.java index 360123b188..cbda3d4f52 100755 --- a/client/src/main/java/org/evosuite/Properties.java +++ b/client/src/main/java/org/evosuite/Properties.java @@ -1244,7 +1244,7 @@ public enum TestNamingStrategy { public static TestNamingStrategy TEST_NAMING_STRATEGY = TestNamingStrategy.NUMBERED; public enum VariableNamingStrategy { - TYPE_BASED, HEURISTICS_BASED, INFO_COLLECTOR + TYPE_BASED, HEURISTICS_BASED } @Parameter(key = "variable_naming_strategy", group = "Output", description = "What strategy to use to name variables for tests") From c8a404711532cd83346aca1110205c648c260056 Mon Sep 17 00:00:00 2001 From: GeraldineGalindoG <42702922+GeraldineGalindo@users.noreply.github.com> Date: Fri, 7 Jul 2023 13:32:58 -0400 Subject: [PATCH 4/5] Adapted heuristics implementation for strategy structure --- .../main/java/org/evosuite/Properties.java | 4 +- .../evosuite/testcase/TestCodeVisitor.java | 122 +++--------------- .../statements/ConstructorStatement.java | 15 --- .../testcase/statements/MethodStatement.java | 9 -- .../name/HeuristicsVariableNameStrategy.java | 97 ++++++++++++++ .../name/TypeBasedVariableNameStrategy.java | 66 +++++----- .../variable/name/VariableNameStrategy.java | 7 + .../name/VariableNameStrategyFactory.java | 13 +- 8 files changed, 163 insertions(+), 170 deletions(-) create mode 100644 client/src/main/java/org/evosuite/testcase/variable/name/HeuristicsVariableNameStrategy.java diff --git a/client/src/main/java/org/evosuite/Properties.java b/client/src/main/java/org/evosuite/Properties.java index 5fdb0257eb..d55647b8f5 100644 --- a/client/src/main/java/org/evosuite/Properties.java +++ b/client/src/main/java/org/evosuite/Properties.java @@ -1244,11 +1244,11 @@ public enum TestNamingStrategy { public static TestNamingStrategy TEST_NAMING_STRATEGY = TestNamingStrategy.NUMBERED; public enum VariableNamingStrategy { - TYPE_BASED + TYPE_BASED, HEURISTICS_BASED } @Parameter(key = "variable_naming_strategy", group = "Output", description = "What strategy to use to derive names for variables") - public static VariableNamingStrategy VARIABLE_NAMING_STRATEGY = VariableNamingStrategy.TYPE_BASED; + public static VariableNamingStrategy VARIABLE_NAMING_STRATEGY = VariableNamingStrategy.HEURISTICS_BASED; // --------------------------------------------------------------- // Sandbox diff --git a/client/src/main/java/org/evosuite/testcase/TestCodeVisitor.java b/client/src/main/java/org/evosuite/testcase/TestCodeVisitor.java index a8f88dfb12..be1a9759e7 100644 --- a/client/src/main/java/org/evosuite/testcase/TestCodeVisitor.java +++ b/client/src/main/java/org/evosuite/testcase/TestCodeVisitor.java @@ -74,12 +74,17 @@ public class TestCodeVisitor extends TestVisitor { protected VariableNameStrategy variableNameStrategy = VariableNameStrategyFactory.get(); + /** + * Dictionaries for naming information + */ /** * Dictionaries for naming information */ protected Map methodNames = new HashMap<>(); protected Map argumentNames = new HashMap<>(); + private Map> information = new HashMap<>(); + /** *

* getCode @@ -387,112 +392,15 @@ public String getVariableName(VariableReference var) { } return result; } else { + if(VariableNameStrategyFactory.gatherInformation()){ + information.put("MethodNames", methodNames); + information.put("ArgumentNames", argumentNames); + variableNameStrategy.addVariableInformation(information); + } return variableNameStrategy.getNameForVariable(var); } } - /** - * Returns the suggested name for a variable according to Properties configuration - * - * 1. TYPE_BASED --> Using type names + index as suggested name (this is the traditional naming in EvoSuite) - * 2. HEURISTICS_BASED --> Using information about arguments + methods + types for proposing a name + index if name is repeated more than once - * 3. INFO_COLLECTOR --> Mode for controlling all the information about the test retrieved via reflection, only for debugging purposes - * - * @return String - */ - private String getNameByStrategy(final VariableReference var, final String originalVariableName) { - String variableName = ""; - if (Properties.VARIABLE_NAMING_STRATEGY == Properties.VariableNamingStrategy.TYPE_BASED) { - variableName = originalVariableName; - variableName = getIndexIncludingFirstAppearance(variableName); - } - if (Properties.VARIABLE_NAMING_STRATEGY == Properties.VariableNamingStrategy.HEURISTICS_BASED) { - variableName = this.getPrioritizedName(var, originalVariableName); - variableName = getVariableWithIndexExcludingFirstAppearance(variableName); - } - return variableName; - } - - /** - * Returns the variable name + the corresponding index if and only if there is more than one repetition of the name, - * otherwise, it returns the name without an index at last. - * - * Mainly used for Heuristic Renaming Strategy. - * - * @return String - */ - private String getVariableWithIndexExcludingFirstAppearance(String variableName) { - if (!this.nextIndices.containsKey(variableName)) { - this.nextIndices.put(variableName, 0); - } - else { - final int index = this.nextIndices.get(variableName); - this.nextIndices.put(variableName, index + 1); - variableName += this.nextIndices.get(variableName); - } - return variableName; - } - - /** - * Returns the variable name + the number of repetitions counting from 0. - * i.e. If the variable appears only once in the test, it is named as variable0. - * - * Mainly used for Type-Based Renaming Strategy (traditional naming in EvoSuite). - * - * @return String - */ - private String getIndexIncludingFirstAppearance(String variableName) { - if (!nextIndices.containsKey(variableName)) { - nextIndices.put(variableName, 0); - } - int index = nextIndices.get(variableName); - nextIndices.put(variableName, index + 1); - return variableName += index; - } - /** - * Retrieve a suggested name based on method, argument and type information. - * - * The followed order for prioritizing is: - * 1. Use argument suggestion, if not possible - * 2. Use method suggestion + reductions, if not possible - * 3. Use type suggestion, traditional naming. - * - * @return String - */ - private String getPrioritizedName(final VariableReference var, String variableName) { - final String methodCode = this.methodNames.get(var); - final String arguments = this.argumentNames.get(var); - if (arguments != null) { - variableName = arguments; - } - else if (methodCode != null) { - variableName = analyzeMethodName(methodCode); - } - if(variableName.equals(var.getSimpleClassName())){ - variableName = "_" + variableName; - } - return variableName; - } - - /** - * Returns the suggested method name controlling camel case and excluding some particles - * of the method names. - * - * @return String - */ - private String analyzeMethodName(String methodCode) { - String name = ""; - ArrayList methodName = HeuristicsUtil.separateByCamelCase(methodCode); - if(methodCode.length() > 0){ - if(HeuristicsUtil.containsAvoidableParticle(methodName.get(0)) && methodName.size() > 1){ - name = StringUtils.join(methodName.subList(1,methodName.size()), ""); - final char[] auxCharArray = name.toCharArray(); - auxCharArray[0] = Character.toLowerCase(auxCharArray[0]); - return new String(auxCharArray); - } - } - return methodCode; - } /** * Retrieve the names of all known variables @@ -1445,7 +1353,7 @@ public void visitMethodStatement(MethodStatement statement) { if (!retval.isVoid() && retval.getAdditionalVariableReference() == null && !unused) { - if (!this.methodNames.containsKey(retval)) { + if (!this.methodNames.containsKey(retval) && VariableNameStrategyFactory.gatherInformation()) { this.methodNames.put(retval, method.getName()); } if (exception != null) { @@ -1460,7 +1368,7 @@ public void visitMethodStatement(MethodStatement statement) { result += "try { " + NEWLINE + " "; } - if (!this.argumentNames.containsKey(retval)) { + if (!this.argumentNames.containsKey(retval) && VariableNameStrategyFactory.gatherInformation()) { final List parameterNames = (List)statement.obtainParameterNameListInOrder(); int idx = 0; for (final VariableReference param : parameters) { @@ -1468,7 +1376,7 @@ public void visitMethodStatement(MethodStatement statement) { ++idx; } } - if (retval.isVoid()) { + if (retval.isVoid() && VariableNameStrategyFactory.gatherInformation()) { final List parameterNames = (List)statement.obtainParameterNameListInOrder(); int idx = 0; for (final VariableReference param : parameters) { @@ -1704,8 +1612,8 @@ public void visitConstructorStatement(ConstructorStatement statement) { && !Modifier.isStatic(constructor.getConstructor().getDeclaringClass().getModifiers()); List parameters = statement.getParameterReferences(); - if (!this.argumentNames.containsKey(retval)) { - final List parameterNames = (List)statement.obtainParameterNameListInOrder(); + if (!this.argumentNames.containsKey(retval) && VariableNameStrategyFactory.gatherInformation()) { + final List parameterNames = statement.obtainParameterNameListInOrder(); int idx = 0; for (final VariableReference param : parameters) { this.argumentNames.put(param, parameterNames.get(idx)); diff --git a/client/src/main/java/org/evosuite/testcase/statements/ConstructorStatement.java b/client/src/main/java/org/evosuite/testcase/statements/ConstructorStatement.java index 2049c43f57..b433144a60 100755 --- a/client/src/main/java/org/evosuite/testcase/statements/ConstructorStatement.java +++ b/client/src/main/java/org/evosuite/testcase/statements/ConstructorStatement.java @@ -494,19 +494,4 @@ public List obtainParameterNameListInOrder() { } return names; } - - /** - * Returns a string concatenation of the parameter names of a method using reflection. - * The string contains the parameter names separated by low bars, and in order of declaration - * - * @return String - */ - public String obtainParameterNamesInOrder() { - final Parameter[] parameters = this.constructor.getParameters(); - String names = ""; - for (final Parameter p : parameters) { - names = names + p.getName() + "_"; - } - return names; - } } diff --git a/client/src/main/java/org/evosuite/testcase/statements/MethodStatement.java b/client/src/main/java/org/evosuite/testcase/statements/MethodStatement.java index b5903d088a..87a0741b57 100755 --- a/client/src/main/java/org/evosuite/testcase/statements/MethodStatement.java +++ b/client/src/main/java/org/evosuite/testcase/statements/MethodStatement.java @@ -660,13 +660,4 @@ public List obtainParameterNameListInOrder() { } return names; } - - public String obtainParameterNamesInOrder() { - final Parameter[] parameters = this.method.getParameters(); - String names = ""; - for (final Parameter p : parameters) { - names = names + p.getName() + "_"; - } - return names; - } } diff --git a/client/src/main/java/org/evosuite/testcase/variable/name/HeuristicsVariableNameStrategy.java b/client/src/main/java/org/evosuite/testcase/variable/name/HeuristicsVariableNameStrategy.java new file mode 100644 index 0000000000..7520c00e89 --- /dev/null +++ b/client/src/main/java/org/evosuite/testcase/variable/name/HeuristicsVariableNameStrategy.java @@ -0,0 +1,97 @@ +package org.evosuite.testcase.variable.name; + +import org.apache.commons.lang3.StringUtils; +import org.evosuite.testcase.utils.HeuristicsUtil; +import org.evosuite.testcase.variable.VariableReference; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class HeuristicsVariableNameStrategy extends AbstractVariableNameStrategy{ + + protected final Map nextIndices = new ConcurrentHashMap<>(); + /** + * Dictionaries for naming information + */ + protected Map methodNames = new HashMap<>(); + protected Map argumentNames = new HashMap<>(); + + private TypeBasedVariableNameStrategy typeBasedVariableNameStrategy = new TypeBasedVariableNameStrategy(); + @Override + public String createNameForVariable(VariableReference variable) { + String typeBasedName = typeBasedVariableNameStrategy.getPlainNameForVariable(variable); + return getPrioritizedName(variable, typeBasedName); + } + + /** + * Returns the variable name + the corresponding index if and only if there is more than one repetition of the name, + * otherwise, it returns the name without an index at last. + * + * Mainly used for Heuristic Renaming Strategy. + * + * @return String + */ + private String getVariableWithIndexExcludingFirstAppearance(String variableName) { + if (!this.nextIndices.containsKey(variableName)) { + this.nextIndices.put(variableName, 0); + } + else { + final int index = this.nextIndices.get(variableName); + this.nextIndices.put(variableName, index + 1); + variableName += this.nextIndices.get(variableName); + } + return variableName; + } + /** + * Retrieve a suggested name based on method, argument and type information. + * + * The followed order for prioritizing is: + * 1. Use argument suggestion, if not possible + * 2. Use method suggestion + reductions, if not possible + * 3. Use type suggestion, traditional naming. + * + * @return String + */ + private String getPrioritizedName(final VariableReference var, String variableName) { + final String methodCode = this.methodNames.get(var); + final String arguments = this.argumentNames.get(var); + if (arguments != null) { + variableName = arguments; + } + else if (methodCode != null) { + variableName = analyzeMethodName(methodCode); + } + if(variableName.equals(var.getSimpleClassName())){ + variableName = "_" + variableName; + } + return variableName; + } + + /** + * Returns the suggested method name controlling camel case and excluding some particles + * of the method names. + * + * @return String + */ + private String analyzeMethodName(String methodCode) { + String name = ""; + ArrayList methodName = HeuristicsUtil.separateByCamelCase(methodCode); + if(methodCode.length() > 0){ + if(HeuristicsUtil.containsAvoidableParticle(methodName.get(0)) && methodName.size() > 1){ + name = StringUtils.join(methodName.subList(1,methodName.size()), ""); + final char[] auxCharArray = name.toCharArray(); + auxCharArray[0] = Character.toLowerCase(auxCharArray[0]); + return new String(auxCharArray); + } + } + return methodCode; + } + + public void addVariableInformation(Map> information){ + methodNames = information.get("MethodNames"); + argumentNames = information.get("ArgumentNames"); + } + +} diff --git a/client/src/main/java/org/evosuite/testcase/variable/name/TypeBasedVariableNameStrategy.java b/client/src/main/java/org/evosuite/testcase/variable/name/TypeBasedVariableNameStrategy.java index c3ccbd4aa4..ef121266a4 100644 --- a/client/src/main/java/org/evosuite/testcase/variable/name/TypeBasedVariableNameStrategy.java +++ b/client/src/main/java/org/evosuite/testcase/variable/name/TypeBasedVariableNameStrategy.java @@ -19,36 +19,19 @@ public class TypeBasedVariableNameStrategy extends AbstractVariableNameStrategy @Override public String createNameForVariable(VariableReference var) { + String variableName = getPlainNameForVariable(var); + return getIndexIncludingFirstAppearance(variableName); + } + + public String getPlainNameForVariable(VariableReference var){ + String className = var.getSimpleClassName(); + String variableName; if (var instanceof ArrayReference) { - String className = var.getSimpleClassName(); - // int num = 0; - // for (VariableReference otherVar : variableNames.keySet()) { - // if (!otherVar.equals(var) - // && otherVar.getVariableClass().equals(var.getVariableClass())) - // num++; - // } - String variableName = className.substring(0, 1).toLowerCase() + variableName = className.substring(0, 1).toLowerCase() + className.substring(1) + "Array"; variableName = variableName.replace('.', '_').replace("[]", ""); - - if (!nextIndices.containsKey(variableName)) { - nextIndices.put(variableName, 0); - } - - int index = nextIndices.get(variableName); - nextIndices.put(variableName, index + 1); - - variableName += index; - - return variableName; } else { - String className = var.getSimpleClassName(); - // int num = 0; - // for (VariableReference otherVar : variableNames.keySet()) { - // if (otherVar.getVariableClass().equals(var.getVariableClass())) - // num++; - // } - String variableName = className.substring(0, 1).toLowerCase() + variableName = className.substring(0, 1).toLowerCase() + className.substring(1); if (variableName.contains("[]")) { variableName = variableName.replace("[]", "Array"); @@ -61,19 +44,30 @@ public String createNameForVariable(VariableReference var) { // if (numObjectsOfType > 1 || className.equals(variableName)) { if (CharUtils.isAsciiNumeric(variableName.charAt(variableName.length() - 1))) variableName += "_"; - - if (!nextIndices.containsKey(variableName)) { - nextIndices.put(variableName, 0); - } - - int index = nextIndices.get(variableName); - nextIndices.put(variableName, index + 1); - - variableName += index; // } - return variableName; } + return variableName; + } + + /** + * Returns the variable name + the number of repetitions counting from 0. + * i.e. If the variable appears only once in the test, it is named as variable0. + * + * Mainly used for Type-Based Renaming Strategy (traditional naming in EvoSuite). + * + * @return String + */ + private String getIndexIncludingFirstAppearance(String variableName) { + if (!nextIndices.containsKey(variableName)) { + nextIndices.put(variableName, 0); + } + int index = nextIndices.get(variableName); + nextIndices.put(variableName, index + 1); + return variableName += index; + } + public void addVariableInformation(Map> information){ + //If needed any information about types } } diff --git a/client/src/main/java/org/evosuite/testcase/variable/name/VariableNameStrategy.java b/client/src/main/java/org/evosuite/testcase/variable/name/VariableNameStrategy.java index 29969c0225..447fd0be27 100644 --- a/client/src/main/java/org/evosuite/testcase/variable/name/VariableNameStrategy.java +++ b/client/src/main/java/org/evosuite/testcase/variable/name/VariableNameStrategy.java @@ -3,6 +3,7 @@ import org.evosuite.testcase.variable.VariableReference; import java.util.Collection; +import java.util.Map; import java.util.Optional; /** @@ -39,4 +40,10 @@ public interface VariableNameStrategy { */ Collection getVariableNames(); + /** + * Allows to add information on dictionaries for variable naming + */ + void addVariableInformation(Map> information); + + } diff --git a/client/src/main/java/org/evosuite/testcase/variable/name/VariableNameStrategyFactory.java b/client/src/main/java/org/evosuite/testcase/variable/name/VariableNameStrategyFactory.java index 03951498a4..89071b60a8 100644 --- a/client/src/main/java/org/evosuite/testcase/variable/name/VariableNameStrategyFactory.java +++ b/client/src/main/java/org/evosuite/testcase/variable/name/VariableNameStrategyFactory.java @@ -24,7 +24,11 @@ public class VariableNameStrategyFactory { public static VariableNameStrategy get(Properties.VariableNamingStrategy identifierNamingStrategy) { if (Properties.VariableNamingStrategy.TYPE_BASED.equals(identifierNamingStrategy)) { return new TypeBasedVariableNameStrategy(); - } else { + } + if (Properties.VariableNamingStrategy.HEURISTICS_BASED.equals(identifierNamingStrategy)) { + return new HeuristicsVariableNameStrategy(); + } + else { throw new IllegalArgumentException(String.format("Unknown variable naming strategy: %s", identifierNamingStrategy)); } } @@ -44,4 +48,11 @@ private VariableNameStrategyFactory() { // Nothing to do here } + public static boolean gatherInformation(){ + if (Properties.VariableNamingStrategy.HEURISTICS_BASED.equals(Properties.VARIABLE_NAMING_STRATEGY)) { + return true; + } + return false; + } + } From 7236daaa262629bb921b3306a746016ad1bda3c5 Mon Sep 17 00:00:00 2001 From: GeraldineGalindo <42702922+GeraldineGalindo@users.noreply.github.com> Date: Sat, 8 Jul 2023 07:33:47 -0400 Subject: [PATCH 5/5] Update Properties.java to use type-based naming strategy --- client/src/main/java/org/evosuite/Properties.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/main/java/org/evosuite/Properties.java b/client/src/main/java/org/evosuite/Properties.java index d55647b8f5..48758f5180 100644 --- a/client/src/main/java/org/evosuite/Properties.java +++ b/client/src/main/java/org/evosuite/Properties.java @@ -1248,7 +1248,7 @@ public enum VariableNamingStrategy { } @Parameter(key = "variable_naming_strategy", group = "Output", description = "What strategy to use to derive names for variables") - public static VariableNamingStrategy VARIABLE_NAMING_STRATEGY = VariableNamingStrategy.HEURISTICS_BASED; + public static VariableNamingStrategy VARIABLE_NAMING_STRATEGY = VariableNamingStrategy.TYPE_BASED; // --------------------------------------------------------------- // Sandbox