
com.google.test.metric.Cost Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of testability-explorer Show documentation
Show all versions of testability-explorer Show documentation
A tool that looks at java bytecodes and helps you
identify hard to test code.
The newest version!
/*
* Copyright 2007 Google Inc.
*
* 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 com.google.test.metric;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class Cost {
private static final int[] EMPTY = new int[0];
private static final String COMPLEXITY_COST_HELP_URL = "http://code.google.com/p/testability-explorer/wiki/ComplexityCostExplanation";
private static final String GLOBAL_COST_HELP_URL = "http://code.google.com/p/testability-explorer/wiki/GlobalCostExplanation";
private static final String LAW_OF_DEMETER_COST_HELP_URL = "http://code.google.com/p/testability-explorer/wiki/LawOfDemeterCostExplanation";
private int cyclomaticCost;
private int globalCost;
private int[] lodDistribution;
public Cost() {
this(0, 0, EMPTY);
}
public Cost(int cyclomaticCost, int globalCost, int[] lodDistribution) {
this.cyclomaticCost = cyclomaticCost;
this.globalCost = globalCost;
this.lodDistribution = lodDistribution;
}
public static Cost global(int count) {
return new Cost(0, count, EMPTY);
}
public static Cost lod(int distance) {
int[] distribution = new int[distance + 1];
distribution[distance] = 1;
return new Cost(0, 0, distribution);
}
public static Cost cyclomatic(int cyclomaticCost) {
return new Cost(cyclomaticCost, 0, EMPTY);
}
public static Object lodDistribution(int... counts) {
return new Cost(0, 0, counts);
}
public Cost add(Cost cost) {
cyclomaticCost += cost.cyclomaticCost;
globalCost += cost.globalCost;
int[] other = cost.lodDistribution;
int size = Math.max(lodDistribution.length, other.length);
int[] old = lodDistribution;
if (lodDistribution.length < size) {
lodDistribution = new int[size];
}
for (int i = 0; i < size; i++) {
int count1 = i < old.length ? old[i] : 0;
int count2 = i < other.length ? other[i] : 0;
lodDistribution[i] = count1 + count2;
}
return this;
}
public void addWithoutLod(Cost cost) {
cyclomaticCost += cost.cyclomaticCost;
globalCost += cost.globalCost;
}
public int getCyclomaticComplexityCost() {
return cyclomaticCost;
}
public int getGlobalCost() {
return globalCost;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
String sep = "";
if (cyclomaticCost > 0) {
builder.append(sep);
builder.append("CC: " + cyclomaticCost);
sep = ", ";
}
if (globalCost > 0) {
builder.append(sep);
builder.append("GC: " + globalCost);
sep = ", ";
}
int loDSum = getLoDSum();
if (loDSum > 0) {
builder.append(sep);
builder.append("LOD: " + loDSum);
sep = ", ";
}
return builder.toString();
}
// TODO(jwolter): Refactor me so the html presentation representation is outside the Cost class.
// Probably this means configure the urls in the template, and take all the cost types directly
// in there. Build this string in the templating side of things, rather than in the core Cost
// side of things here. But more important first is to write up useful html pages explaining the
// costs.
public String toHtmlReportString() {
StringBuilder builder = new StringBuilder();
String sep = "";
if (cyclomaticCost > 0) {
builder.append(sep);
builder.append("CC: " + cyclomaticCost + "");
sep = ", ";
}
if (globalCost > 0) {
builder.append(sep);
builder.append("GC: " + globalCost + "");
sep = ", ";
}
int loDSum = getLoDSum();
if (loDSum > 0) {
builder.append(sep);
builder.append("LOD: " + loDSum + "");
sep = ", ";
}
return builder.toString();
}
public int getLoDSum() {
int sum = 0;
for (int value : lodDistribution) {
sum += value;
}
return sum;
}
public Cost copy() {
return new Cost(cyclomaticCost, globalCost, lodDistribution);
}
public Cost copyNoLOD() {
return new Cost(cyclomaticCost, globalCost, EMPTY);
}
public int[] getLoDDistribution() {
return lodDistribution;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + cyclomaticCost;
result = prime * result + globalCost;
result = prime * result + Arrays.hashCode(lodDistribution);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Cost other = (Cost) obj;
if (cyclomaticCost != other.cyclomaticCost) {
return false;
}
if (globalCost != other.globalCost) {
return false;
}
if (!Arrays.equals(lodDistribution, other.lodDistribution)) {
return false;
}
return true;
}
Map getAttributes() {
Map atts = new HashMap();
atts.put("cyclomatic", getCyclomaticComplexityCost());
atts.put("global", getGlobalCost());
atts.put("lod", getLoDSum());
return atts;
}
public void addCyclomaticCost(int cyclomaticCost) {
this.cyclomaticCost += cyclomaticCost;
}
public void addGlobalCost(int globalCost) {
this.globalCost += globalCost;
}
public void addLodDistance(int distance) {
add(Cost.lod(distance));
}
public boolean isEmpty() {
return lodDistribution.length == 0 && cyclomaticCost == 0 && globalCost == 0;
}
public Cost negate() {
int[] negativeLod = new int[lodDistribution.length];
int index = 0;
for (int lod : lodDistribution) {
negativeLod[index++] = -lod;
}
return new Cost(-cyclomaticCost, -globalCost, negativeLod);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy