Java tutorial
/** * Copyright (C) 2010-2016 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 <http://www.gnu.org/licenses/>. */ package org.evosuite.junit.naming.variables; import org.apache.commons.lang3.CharUtils; import org.evosuite.Properties; import org.evosuite.assertion.ArrayEqualsAssertion; import org.evosuite.assertion.Assertion; import org.evosuite.assertion.CompareAssertion; import org.evosuite.assertion.EqualsAssertion; import org.evosuite.assertion.Inspector; import org.evosuite.assertion.InspectorAssertion; import org.evosuite.assertion.NullAssertion; import org.evosuite.assertion.PrimitiveAssertion; import org.evosuite.assertion.PrimitiveFieldAssertion; import org.evosuite.assertion.SameAssertion; import org.evosuite.coverage.mutation.Mutation; import org.evosuite.testcase.ImportsTestCodeVisitor; import org.evosuite.testcase.TestCase; import org.evosuite.testcase.TestVisitor; import org.evosuite.testcase.fm.MethodDescriptor; import org.evosuite.testcase.statements.ArrayStatement; import org.evosuite.testcase.statements.AssignmentStatement; import org.evosuite.testcase.statements.ClassPrimitiveStatement; import org.evosuite.testcase.statements.ConstructorStatement; import org.evosuite.testcase.statements.EnumPrimitiveStatement; import org.evosuite.testcase.statements.FieldStatement; import org.evosuite.testcase.statements.FunctionalMockStatement; import org.evosuite.testcase.statements.MethodStatement; import org.evosuite.testcase.statements.NullStatement; import org.evosuite.testcase.statements.PrimitiveExpression; import org.evosuite.testcase.statements.PrimitiveStatement; import org.evosuite.testcase.statements.Statement; import org.evosuite.testcase.statements.StringPrimitiveStatement; import org.evosuite.testcase.statements.environment.EnvironmentDataStatement; import org.evosuite.testcase.statements.environment.FileNamePrimitiveStatement; import org.evosuite.testcase.statements.environment.LocalAddressPrimitiveStatement; import org.evosuite.testcase.statements.environment.RemoteAddressPrimitiveStatement; import org.evosuite.testcase.statements.environment.UrlPrimitiveStatement; import org.evosuite.testcase.statements.numeric.NumericalPrimitiveStatement; import org.evosuite.testcase.variable.ConstantValue; import org.evosuite.testcase.variable.VariableReference; import org.evosuite.utils.generic.GenericClass; import org.evosuite.utils.generic.GenericConstructor; import org.evosuite.utils.generic.GenericField; import org.evosuite.utils.generic.GenericMethod; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; /** * The ExplanatoryNamingTestVisitor is a visitor that produces a mapping of variable * references to String names. * * @author Jose Miguel Rojas */ public class ExplanatoryNamingTestVisitor extends TestVisitor { // mapping from variable reference to *list* of candidate variable names protected final Map<VariableReference, SortedSet<CandidateName>> varNamesCandidates = new HashMap<>(); protected TestCase test = null; protected final ImportsTestCodeVisitor itv; protected final Map<String, Integer> indices = new HashMap<String, Integer>(); public ExplanatoryNamingTestVisitor(ImportsTestCodeVisitor itv) { this.itv = itv; } /* * (non-Javadoc) * * @see org.evosuite.testcase.TestVisitor#visitTestCase(org.evosuite.testcase.TestCase) */ /** {@inheritDoc} */ @Override public void visitTestCase(TestCase test) { this.test = test; this.varNamesCandidates.clear(); this.indices.clear(); } /** * <p> * visitPrimitiveAssertion * </p> * * @param assertion * a {@link org.evosuite.assertion.PrimitiveAssertion} object. */ protected void visitPrimitiveAssertion(PrimitiveAssertion assertion) { VariableReference source = assertion.getSource(); Object value = assertion.getValue(); if (value == null) { addCandidateName(source, CandidateSource.ASSERTION, "null" + getSimpleClassName(source)); } else if (source.getVariableClass().equals(boolean.class) || source.getVariableClass().equals(Boolean.class)) { String descriptor = getStringForPrimitiveValue(value); addCandidateName(source, CandidateSource.ASSERTION, "is" + descriptor); } } protected void visitArrayEqualsAssertion(ArrayEqualsAssertion assertion) { VariableReference source = assertion.getSource(); addCandidateName(source, CandidateSource.ASSERTION, "checkedArray"); } /** * <p> * visitPrimitiveFieldAssertion * </p> * * @param assertion * a {@link org.evosuite.assertion.PrimitiveFieldAssertion} * object. */ protected void visitPrimitiveFieldAssertion(PrimitiveFieldAssertion assertion) { VariableReference source = assertion.getSource(); Object value = assertion.getValue(); Field field = assertion.getField(); if (Modifier.isStatic(field.getModifiers())) return; String fn = capitalize(field.getName()); if (value == null) { addCandidateName(source, CandidateSource.ASSERTION, "hasNullField" + fn); } else { String descriptor = getStringForPrimitiveValue(value); addCandidateName(source, CandidateSource.ASSERTION, "hasField" + fn + "Equals" + descriptor); } } /** * <p> * visitInspectorAssertion * </p> * * @param assertion * a {@link org.evosuite.assertion.InspectorAssertion} object. */ protected void visitInspectorAssertion(InspectorAssertion assertion) { VariableReference source = assertion.getSource(); Object value = assertion.getValue(); Inspector inspector = assertion.getInspector(); String call = capitalize(inspector.getMethodCall()); if (value == null) { addCandidateName(source, CandidateSource.ASSERTION, "with" + call + "ReturningNull"); } else if ((value.getClass().equals(Long.class)) || (value.getClass().equals(Float.class)) || (value.getClass().equals(Double.class)) || (value.getClass().equals(Character.class)) || (value.getClass().equals(String.class)) || (value.getClass().isEnum() || value instanceof Enum) || (value.getClass().equals(boolean.class) || value.getClass().equals(Boolean.class))) { String descriptor = getStringForPrimitiveValue(value); addCandidateName(source, CandidateSource.ASSERTION, "with" + call + "Returning" + descriptor); } else addCandidateName(source, CandidateSource.ASSERTION, "with" + call + "ReturningNonNull"); } /** * <p> * visitNullAssertion * </p> * * @param assertion * a {@link org.evosuite.assertion.NullAssertion} object. */ protected void visitNullAssertion(NullAssertion assertion) { VariableReference source = assertion.getSource(); String prefix = ((Boolean) assertion.getValue()) ? "null" : "nonNull"; addCandidateName(source, CandidateSource.ASSERTION, prefix + getSimpleClassName(source)); } /** * <p> * visitCompareAssertion * </p> * * @param assertion * a {@link org.evosuite.assertion.CompareAssertion} object. */ protected void visitCompareAssertion(CompareAssertion assertion) { VariableReference source = assertion.getSource(); VariableReference dest = assertion.getDest(); addCandidateName(source, CandidateSource.ASSERTION, "usedInComparison"); addCandidateName(dest, CandidateSource.ASSERTION, "usedInComparison"); } /** * <p> * visitEqualsAssertion * </p> * * @param assertion * a {@link org.evosuite.assertion.EqualsAssertion} object. */ protected void visitEqualsAssertion(EqualsAssertion assertion) { VariableReference source = assertion.getSource(); VariableReference dest = assertion.getDest(); addCandidateName(source, CandidateSource.ASSERTION, "usedInEquals"); addCandidateName(dest, CandidateSource.ASSERTION, "usedInEquals"); } /** * <p> * visitSameAssertion * </p> * * @param assertion * a {@link org.evosuite.assertion.SameAssertion} object. */ protected void visitSameAssertion(SameAssertion assertion) { VariableReference source = assertion.getSource(); VariableReference dest = assertion.getDest(); addCandidateName(source, CandidateSource.ASSERTION, "usedInComparison"); addCandidateName(dest, CandidateSource.ASSERTION, "usedInComparison"); } protected void visitAssertion(Assertion assertion) { if (assertion instanceof PrimitiveAssertion) { visitPrimitiveAssertion((PrimitiveAssertion) assertion); } else if (assertion instanceof PrimitiveFieldAssertion) { visitPrimitiveFieldAssertion((PrimitiveFieldAssertion) assertion); } else if (assertion instanceof InspectorAssertion) { visitInspectorAssertion((InspectorAssertion) assertion); } else if (assertion instanceof NullAssertion) { visitNullAssertion((NullAssertion) assertion); } else if (assertion instanceof CompareAssertion) { visitCompareAssertion((CompareAssertion) assertion); } else if (assertion instanceof EqualsAssertion) { visitEqualsAssertion((EqualsAssertion) assertion); } else if (assertion instanceof SameAssertion) { visitSameAssertion((SameAssertion) assertion); } else if (assertion instanceof ArrayEqualsAssertion) { visitArrayEqualsAssertion((ArrayEqualsAssertion) assertion); } else { // do nothing } } private void visitAssertions(Statement statement) { if (getException(statement) != null) { // Assumption: The statement that throws an exception is the last statement of a test. VariableReference returnValue = statement.getReturnValue(); for (Assertion assertion : statement.getAssertions()) { if (assertion != null && !assertion.getReferencedVariables().contains(returnValue)) { visitAssertion(assertion); } } } else { for (Assertion assertion : statement.getAssertions()) { if (assertion != null) { visitAssertion(assertion); } } } } /* * (non-Javadoc) * * @see org.evosuite.testcase.TestVisitor#visitPrimitiveStatement(org.evosuite.testcase.PrimitiveStatement) */ /** {@inheritDoc} */ @Override public void visitPrimitiveStatement(PrimitiveStatement<?> statement) { VariableReference retval = statement.getReturnValue(); Object value = statement.getValue(); String strVal = ""; if (statement instanceof StringPrimitiveStatement) { // will be inlined if (value == null) strVal = "nullString"; else strVal = ((String) value).isEmpty() ? "emptyString" : "nonEmptyString"; } else if (statement instanceof EnvironmentDataStatement) { if (statement instanceof FileNamePrimitiveStatement) strVal = "fileName"; else if (statement instanceof LocalAddressPrimitiveStatement) strVal = "localAddress"; else if (statement instanceof RemoteAddressPrimitiveStatement) strVal = "remoteAddress"; else if (statement instanceof UrlPrimitiveStatement) strVal = "url"; else strVal = "envData"; } else if (statement instanceof ClassPrimitiveStatement) { strVal = "clazz"; } else if (statement instanceof NumericalPrimitiveStatement) { // will be inlined strVal = "const_" + String.valueOf(value); } else if (statement instanceof NullStatement) { String className = getSimpleClassName(retval); strVal = "null" + className; } else if (statement instanceof EnumPrimitiveStatement) { strVal = "const_" + String.valueOf(value); } addCandidateName(retval, CandidateSource.PRIMITIVE_STATEMENT, strVal, countKilledMutants(statement)); visitAssertions(statement); } /** {@inheritDoc} */ @Override public void visitPrimitiveExpression(PrimitiveExpression statement) { VariableReference retval = statement.getReturnValue(); addCandidateName(retval, CandidateSource.PRIMITIVE_EXPRESSION, "gets" + capitalize(statement.getOperator().name()), countKilledMutants(statement)); visitAssertions(statement); } /* * (non-Javadoc) * * @see org.evosuite.testcase.TestVisitor#visitFieldStatement(org.evosuite.testcase.FieldStatement) */ /** {@inheritDoc} */ @Override public void visitFieldStatement(FieldStatement statement) { Throwable exception = getException(statement); VariableReference retval = statement.getReturnValue(); GenericField field = statement.getField(); String fieldName = capitalize(field.getName()); String castStr = (retval.isAssignableFrom(field.getFieldType())) ? "" : "Cast"; String excStr = (exception == null) ? "" : "WithExc"; String statStr = (field.isStatic()) ? "Static" : ""; addCandidateName(retval, CandidateSource.FIELD_STATEMENT, "gets" + castStr + statStr + fieldName + excStr, countKilledMutants(statement)); visitAssertions(statement); } private void handleParameters(Type[] parameterTypes, List<VariableReference> parameters, int startPos, String suffix, int nKilledMutants) { for (int i = startPos; i < parameters.size(); i++) { Type declaredParamType = parameterTypes[i]; Type actualParamType = parameters.get(i).getType(); if (parameters.get(i) instanceof ConstantValue) continue; String prefix = "used"; if (!GenericClass.isAssignable(declaredParamType, actualParamType)) { prefix = "cast"; } addCandidateName(parameters.get(i), CandidateSource.PARAMETER, prefix + suffix, nKilledMutants); } } @Override public void visitFunctionalMockStatement(FunctionalMockStatement st) { VariableReference retval = st.getReturnValue(); addCandidateName(retval, CandidateSource.MOCK, "mock" + getSimpleClassName(retval)); for (MethodDescriptor md : st.getMockedMethods()) { if (md.shouldBeMocked()) { for (VariableReference paramVar : st.getParameters(md.getID())) { addCandidateName(paramVar, CandidateSource.MOCK, "usedToCallMock" + capitalize(md.getMethodName())); } } } } /* * (non-Javadoc) * * @see org.evosuite.testcase.TestVisitor#visitMethodStatement(org.evosuite.testcase.MethodStatement) */ /** {@inheritDoc} */ @Override public void visitMethodStatement(MethodStatement statement) { VariableReference retval = statement.getReturnValue(); GenericMethod method = statement.getMethod(); Throwable exception = getException(statement); List<VariableReference> parameters = statement.getParameterReferences(); String methodName = capitalize(method.getName()); int nKilledMutants = countKilledMutants(statement); boolean unused = !Properties.ASSERTIONS ? exception != null : test != null && !test.hasReferences(retval); if (!retval.isVoid() && retval.getAdditionalVariableReference() == null && !unused) { String excStr = (exception == null) ? "" : "WithException"; addCandidateName(retval, CandidateSource.METHOD_STATEMENT_RETURN, "resultFrom" + methodName + excStr, nKilledMutants); } VariableReference callee = statement.getCallee(); if (callee != null && !(callee instanceof ConstantValue)) { String prefix = "invokes"; if (!callee.isAssignableTo(method.getMethod().getDeclaringClass())) { try { // If the concrete callee class has that method then it's ok callee.getVariableClass().getMethod(method.getName(), method.getRawParameterTypes()); } catch (NoSuchMethodException e) { prefix = "castToInvoke"; } } addCandidateName(callee, CandidateSource.METHOD_STATEMENT_CALL, prefix + methodName, nKilledMutants); } int startPos = method.isStatic() ? 0 : 1; handleParameters(method.getParameterTypes(), parameters, startPos, "ToCall" + methodName, nKilledMutants); visitAssertions(statement); } private int countKilledMutants(Statement statement) { Set<Mutation> allKilledMutants = new LinkedHashSet<>(); for (Assertion assertion : statement.getAssertions()) { allKilledMutants.addAll(assertion.getKilledMutations()); } return allKilledMutants.size(); } /* * (non-Javadoc) * * @see org.evosuite.testcase.TestVisitor#visitConstructorStatement(org.evosuite.testcase.ConstructorStatement) */ /** {@inheritDoc} */ @Override public void visitConstructorStatement(ConstructorStatement statement) { GenericConstructor constructor = statement.getConstructor(); VariableReference retval = statement.getReturnValue(); Throwable exception = getException(statement); int nKilledMutants = countKilledMutants(statement); boolean isNonStaticMemberClass = constructor.getConstructor().getDeclaringClass().isMemberClass() && !constructor.isStatic() && !Modifier.isStatic(constructor.getConstructor().getDeclaringClass().getModifiers()); List<VariableReference> parameters = statement.getParameterReferences(); String className = capitalize(getSimpleClassName(retval)); String excStr = (exception == null) ? "" : "WithException"; addCandidateName(retval, CandidateSource.CONSTRUCTOR, "new" + className + excStr, nKilledMutants); int startPos = isNonStaticMemberClass ? 1 : 0; Type[] parameterTypes = constructor.getParameterTypes(); handleParameters(parameterTypes, parameters, startPos, "ToInitialize" + capitalize(className), nKilledMutants); visitAssertions(statement); } /* * (non-Javadoc) * * @see org.evosuite.testcase.TestVisitor#visitArrayStatement(org.evosuite.testcase.ArrayStatement) */ /** {@inheritDoc} */ @Override public void visitArrayStatement(ArrayStatement statement) { VariableReference retval = statement.getReturnValue(); String typeArrStr = (retval.getGenericClass().isGenericArray()) ? "generic" : getSimpleClassName(retval); addCandidateName(retval, CandidateSource.ARRAY_STATEMENT, typeArrStr + "Array", countKilledMutants(statement)); visitAssertions(statement); } /* * (non-Javadoc) * * @see org.evosuite.testcase.TestVisitor#visitAssignmentStatement(org.evosuite.testcase.AssignmentStatement) */ /** {@inheritDoc} */ @Override public void visitAssignmentStatement(AssignmentStatement statement) { VariableReference retval = statement.getReturnValue(); VariableReference parameter = statement.getValue(); int nKilledMutants = countKilledMutants(statement); addCandidateName(retval, CandidateSource.ASSIGNMENT_STATEMENT, "gets" + getSimpleClassName(parameter), nKilledMutants); if (!retval.getVariableClass().equals(parameter.getVariableClass())) { addCandidateName(parameter, CandidateSource.ASSIGNMENT_STATEMENT, "castTo" + getSimpleClassName(retval), nKilledMutants); } visitAssertions(statement); } /* * (non-Javadoc) * * @see org.evosuite.testcase.TestVisitor#visitNullStatement(org.evosuite.testcase.NullStatement) */ /** {@inheritDoc} */ @Override public void visitNullStatement(NullStatement statement) { VariableReference retval = statement.getReturnValue(); addCandidateName(retval, CandidateSource.NULL_STATEMENT, "null" + capitalize(getSimpleClassName(retval))); } @Override public void visitStatement(Statement statement) { super.visitStatement(statement); } public String getSimpleClassName(VariableReference var) { if (var.isPrimitive()) { return var.getGenericClass().getUnboxedType().getSimpleName(); } String className = var.getSimpleClassName(); return className.substring(0, 1).toLowerCase() + className.substring(1).replace(".", "_").replace("[]", ""); } /** * <p> * getVariableName * </p> * * @param variableName * a {@link java.lang.String} object. * @return a {@link java.lang.String} object. */ public String getFinalVariableName(String variableName) { if (!indices.containsKey(variableName)) { indices.put(variableName, 0); } else { int index = indices.get(variableName); indices.put(variableName, index + 1); variableName += index; } return variableName; } public void printAll() { System.out.println("CANDIDATE NAMES MAPPING"); String format = "%-5s| %-10s| %s\n"; System.out.printf(format, "test", "varRef", "candidateName"); for (Map.Entry<VariableReference, SortedSet<CandidateName>> varEntry : varNamesCandidates.entrySet()) { VariableReference var = varEntry.getKey(); varEntry.getValue().forEach((candidate) -> { System.out.printf(format, this.test.getID(), var, candidate.toString()); }); } } public Map<VariableReference, String> getAllVariableNames() { Map<VariableReference, String> variableNames = new HashMap<>(); for (Map.Entry<VariableReference, SortedSet<CandidateName>> varEntry : varNamesCandidates.entrySet()) { VariableReference key = varEntry.getKey(); SortedSet<CandidateName> candidates = varEntry.getValue(); variableNames.put(key, getFinalVariableName(candidates.first().getName())); // ordered list of candidates } return variableNames; } /** * <p> * getException * </p> * * @param statement * a {@link Statement} object. * @return a {@link Throwable} object. */ public Throwable getException(Statement statement) { if (this.itv.getExceptions() != null && this.itv.getExceptions().containsKey(statement.getPosition())) return this.itv.getExceptions().get(statement.getPosition()); return null; } /** * Make first letter upper case * * @param input * @return */ private static String capitalize(String input) { final char[] buffer = input.toCharArray(); buffer[0] = Character.toTitleCase(buffer[0]); return new String(buffer); } /** * <p> * getNumberString * </p> * * @param value * a {@link java.lang.Object} object. * @return a {@link java.lang.String} object. */ public static String getStringForPrimitiveValue(Object value) { assert (value != null); if (value.getClass().equals(char.class) || value.getClass().equals(Character.class)) { if (CharUtils.isAsciiNumeric((Character) value)) return "Numeric"; else if (CharUtils.isAsciiAlpha((Character) value)) return "Alpha"; else return "NotAlphanumeric"; } else if (value.getClass().equals(String.class)) { return ((String) value).isEmpty() ? "EmptyString" : "NonEmptyString"; } else if (value.getClass().equals(float.class) || value.getClass().equals(Float.class)) { if (value.toString().equals("" + Float.NaN)) return "NaN"; else if (value.toString().equals("" + Float.NEGATIVE_INFINITY)) return "NegativeInf"; else if (value.toString().equals("" + Float.POSITIVE_INFINITY)) return "PositiveInf"; else return (((Float) value) < 0F) ? "Negative" : (((Float) value) == 0F) ? "Zero" : "Positive"; } else if (value.getClass().equals(double.class) || value.getClass().equals(Double.class)) { if (value.toString().equals("" + Double.NaN)) return "NaN"; else if (value.toString().equals("" + Double.NEGATIVE_INFINITY)) return "NegativeInf"; else if (value.toString().equals("" + Double.POSITIVE_INFINITY)) return "PositiveInf"; else return (((Double) value) < 0.0) ? "Negative" : (((Double) value) == 0.0) ? "Zero" : "Positive"; } else if (value.getClass().equals(long.class) || value.getClass().equals(Long.class)) { return (((Long) value) < 0) ? "Negative" : (((Long) value) == 0) ? "Zero" : "Positive"; } else if (value.getClass().equals(byte.class) || value.getClass().equals(Byte.class)) { return (((Byte) value) < 0) ? "Negative" : (((Byte) value) == 0) ? "Zero" : "Positive"; } else if (value.getClass().equals(short.class) || value.getClass().equals(Short.class)) { return (((Short) value) < 0) ? "Negative" : (((Short) value) == 0) ? "Zero" : "Positive"; } else if (value.getClass().equals(int.class) || value.getClass().equals(Integer.class)) { int val = ((Integer) value).intValue(); if (val == Integer.MAX_VALUE) return "MaxInt"; else if (val == Integer.MIN_VALUE) return "MinInt"; else return (((Integer) value) < 0) ? "Negative" : (((Integer) value) == 0) ? "Zero" : "Positive"; } else if (value.getClass().isEnum() || value instanceof Enum) { return "EnumValue"; } else if (value.getClass().equals(Boolean.class)) { return capitalize(Boolean.toString((Boolean) value)); } else { // This should not happen assert (false); return value.toString(); } } private void addCandidateName(VariableReference v, CandidateSource source, String name) { addCandidateName(v, source, name, 0); } private void addCandidateName(VariableReference v, CandidateSource source, String name, int nKilledMutants) { if (!varNamesCandidates.containsKey(v)) varNamesCandidates.put(v, new TreeSet<>()); varNamesCandidates.get(v).add(new CandidateName(source, name, nKilledMutants)); } public enum CandidateSource { ASSERTION(0), FIELD_STATEMENT(1), PRIMITIVE_STATEMENT(1), PRIMITIVE_EXPRESSION(1), ARRAY_STATEMENT( 1), ASSIGNMENT_STATEMENT(2), MOCK(2), NULL_STATEMENT( 3), CONSTRUCTOR(3), METHOD_STATEMENT_CALL(4), METHOD_STATEMENT_RETURN(5), PARAMETER(5); private final int priority; CandidateSource(int priority) { this.priority = priority; } } class CandidateName implements Comparable<CandidateName> { private CandidateSource source; private String name; private int nKilledMutants; public CandidateName(CandidateSource source, String name, int nKilledMutants) { this.source = source; this.name = name; this.nKilledMutants = nKilledMutants; } public CandidateSource getSource() { return source; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Candidate{" + "name='" + getName() + '\'' + ", source='" + getSource().name() + '\'' + ", killed=" + nKilledMutants + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; CandidateName that = (CandidateName) o; if (source != null ? !source.equals(that.source) : that.source != null) return false; if (nKilledMutants != that.nKilledMutants) return false; return name != null ? name.equals(that.name) : that.name == null; } @Override public int hashCode() { int result = source != null ? source.hashCode() : 0; result = 31 * result + (name != null ? name.hashCode() : 0); result = 31 * result + nKilledMutants; return result; } @Override public int compareTo(CandidateName o) { if (this == o) return 0; if (o == null) return 1; if (o.nKilledMutants == this.nKilledMutants) { return Integer.compare(o.source.priority, this.source.priority); // reverse comparison } else return Integer.compare(o.nKilledMutants, this.nKilledMutants); // reverse comparison } } }