/* * Copyright 2010 Henry Coles * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and limitations under the License. */ package org.pitest.mutationtest.engine; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.pitest.classinfo.ClassName; import org.pitest.coverage.ClassLine; import org.pitest.coverage.TestInfo; import org.pitest.util.StringUtil; /** * Captures all data relating to a mutant. */ public final class MutationDetails { private final MutationIdentifier id; private final String filename; private final int block; private final int lineNumber; private final String description; private final ArrayList<TestInfo> testsInOrder = new ArrayList<TestInfo>(); private final boolean isInFinallyBlock; private final boolean poison; public MutationDetails(final MutationIdentifier id, final String filename, final String description, final int lineNumber, final int block) { this(id, filename, description, lineNumber, block, false, false); } public MutationDetails(final MutationIdentifier id, final String filename, final String description, final int lineNumber, final int block, final boolean isInFinallyBlock, final boolean poison) { this.id = id; this.description = description; this.filename = filename; this.lineNumber = lineNumber; this.block = block; this.isInFinallyBlock = isInFinallyBlock; this.poison = poison; } @Override public String toString() { return "MutationDetails [id=" + this.id + ", filename=" + this.filename + ", block=" + this.block + ", lineNumber=" + this.lineNumber + ", description=" + this.description + ", testsInOrder=" + this.testsInOrder + "]"; } /** * Returns the human readable description of the mutation. This may be a * constant string or may provide more contextual information depending on the * mutation operator. * * @return Human readable description of the mutation */ public String getDescription() { return this.description; } /** * Returns the mutation description with special characters escaped * * @return Escaped description string */ @Deprecated public String getHtmlSafeDescription() { // fixme this should not be here used in string template return StringUtil.escapeBasicHtmlChars(this.description); } /** * Returns the method name in which this mutation is located as a string * * @return method name as string */ @Deprecated public String getLocation() { // fixme this should not be here used in string template return this.id.getLocation().describe(); } /** * Returns the class in which this mutation is located * * @return class in which mutation is located */ public ClassName getClassName() { return this.id.getClassName(); } /** * Returns the class in which this mutation is located * * @return class in which mutation is located */ public MethodName getMethod() { return this.id.getLocation().getMethodName(); } /** * Returns the file in which this mutation is located * * @return file in which mutation is located */ public String getFilename() { return this.filename; } /** * Returns the line number on which the mutation occurs as reported within the * jvm bytecode * * @return The line number on which the mutation occurs. */ public int getLineNumber() { return this.lineNumber; } /** * Returns the ClassLine in which this mutation is located * * @return the ClassLine in which this mutation is located */ public ClassLine getClassLine() { return new ClassLine(this.id.getClassName(), this.lineNumber); } /** * Returns the identified for this mutation * * @return a MutationIdentifier */ public MutationIdentifier getId() { return this.id; } /** * Returns the tests that cover this mutation in optimised order * * @return a list of TestInfo objects */ public List<TestInfo> getTestsInOrder() { return this.testsInOrder; } /** * Adds tests to the list of covering tests * * @param testNames * The tests to add */ public void addTestsInOrder(final Collection<TestInfo> testNames) { this.testsInOrder.addAll(testNames); this.testsInOrder.trimToSize(); } /** * Indicates if this mutation might poison state within the jvm (e.g affect * the values of static variable) * * @return true if the mutation might poison the jvm otherwise false */ public boolean mayPoisonJVM() { return this.poison || isInStaticInitializer(); } /** * Indicates if this mutation is in a static initializer block * * @return true if in a static initializer otherwise false */ public boolean isInStaticInitializer() { return this.getMethod().name().trim().startsWith("<clinit>"); } /** * Returns the basic block in which this mutation occurs. See * https://github.com/hcoles/pitest/issues/131 for discussion on block * coverage * * @return the block within the method that this mutation is located in */ public int getBlock() { return this.block; } /** * Returns true if this mutation has a matching identifier * * @param id * the MutationIdentifier to match * @return true if the MutationIdentifier matches otherwise false */ public Boolean matchesId(final MutationIdentifier id) { return this.id.matches(id); } /** * Returns the name of the mutator that created this mutation * * @return the mutator name */ public String getMutator() { return this.id.getMutator(); } /** * Returns the index to the first instruction on which this mutation occurs. * This index is specific to how ASM represents the bytecode. * * @return the zero based index to the instruction */ public int getFirstIndex() { return this.id.getFirstIndex(); } /** * Indicates if the mutation is within a finally block * * @return true if in finally block otherwise false */ public boolean isInFinallyBlock() { return this.isInFinallyBlock; } @Override public int hashCode() { final int prime = 31; int result = 1; result = (prime * result) + ((this.id == null) ? 0 : this.id.hashCode()); return result; } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final MutationDetails other = (MutationDetails) obj; if (this.id == null) { if (other.id != null) { return false; } } else if (!this.id.equals(other.id)) { return false; } return true; } }