PageRenderTime 40ms CodeModel.GetById 12ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 1ms

/testability-explorer/src/main/java/com/google/test/metric/Cost.java

http://testability-explorer.googlecode.com/
Java | 229 lines | 179 code | 30 blank | 20 comment | 26 complexity | ecb4387d5c16c1af862216475de08c82 MD5 | raw file
  1/*
  2 * Copyright 2007 Google Inc.
  3 *
  4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5 * use this file except in compliance with the License. You may obtain a copy of
  6 * the License at
  7 *
  8 * http://www.apache.org/licenses/LICENSE-2.0
  9 *
 10 * Unless required by applicable law or agreed to in writing, software
 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 13 * License for the specific language governing permissions and limitations under
 14 * the License.
 15 */
 16package com.google.test.metric;
 17
 18import java.util.Arrays;
 19import java.util.HashMap;
 20import java.util.Map;
 21
 22public class Cost {
 23
 24  private static final int[] EMPTY = new int[0];
 25
 26  private static final String COMPLEXITY_COST_HELP_URL = "http://code.google.com/p/testability-explorer/wiki/ComplexityCostExplanation";
 27  private static final String GLOBAL_COST_HELP_URL = "http://code.google.com/p/testability-explorer/wiki/GlobalCostExplanation";
 28  private static final String LAW_OF_DEMETER_COST_HELP_URL = "http://code.google.com/p/testability-explorer/wiki/LawOfDemeterCostExplanation";
 29  private int cyclomaticCost;
 30  private int globalCost;
 31  private int[] lodDistribution;
 32
 33
 34  public Cost() {
 35    this(0, 0, EMPTY);
 36  }
 37
 38  public Cost(int cyclomaticCost, int globalCost, int[] lodDistribution) {
 39    this.cyclomaticCost = cyclomaticCost;
 40    this.globalCost = globalCost;
 41    this.lodDistribution = lodDistribution;
 42  }
 43
 44  public static Cost global(int count) {
 45    return new Cost(0, count, EMPTY);
 46  }
 47
 48  public static Cost lod(int distance) {
 49    int[] distribution = new int[distance + 1];
 50    distribution[distance] = 1;
 51    return new Cost(0, 0, distribution);
 52  }
 53
 54  public static Cost cyclomatic(int cyclomaticCost) {
 55    return new Cost(cyclomaticCost, 0, EMPTY);
 56  }
 57
 58  public static Object lodDistribution(int... counts) {
 59    return new Cost(0, 0, counts);
 60  }
 61
 62  public Cost add(Cost cost) {
 63    cyclomaticCost += cost.cyclomaticCost;
 64    globalCost += cost.globalCost;
 65    int[] other = cost.lodDistribution;
 66    int size = Math.max(lodDistribution.length, other.length);
 67    int[] old = lodDistribution;
 68    if (lodDistribution.length < size) {
 69      lodDistribution = new int[size];
 70    }
 71    for (int i = 0; i < size; i++) {
 72      int count1 = i < old.length ? old[i] : 0;
 73      int count2 = i < other.length ? other[i] : 0;
 74      lodDistribution[i] = count1 + count2;
 75    }
 76    return this;
 77  }
 78
 79  public void addWithoutLod(Cost cost) {
 80    cyclomaticCost += cost.cyclomaticCost;
 81    globalCost += cost.globalCost;
 82  }
 83
 84  public int getCyclomaticComplexityCost() {
 85    return cyclomaticCost;
 86  }
 87
 88  public int getGlobalCost() {
 89    return globalCost;
 90  }
 91
 92  @Override
 93  public String toString() {
 94    StringBuilder builder = new StringBuilder();
 95    String sep = "";
 96    if (cyclomaticCost > 0) {
 97      builder.append(sep);
 98      builder.append("CC: " + cyclomaticCost);
 99      sep = ", ";
100    }
101    if (globalCost > 0) {
102      builder.append(sep);
103      builder.append("GC: " + globalCost);
104      sep = ", ";
105    }
106    int loDSum = getLoDSum();
107    if (loDSum > 0) {
108      builder.append(sep);
109      builder.append("LOD: " + loDSum);
110      sep = ", ";
111    }
112    return builder.toString();
113  }
114
115  // TODO(jwolter): Refactor me so the html presentation representation is outside the Cost class.
116  // Probably this means configure the urls in the template, and take all the cost types directly
117  // in there. Build this string in the templating side of things, rather than in the core Cost
118  // side of things here. But more important first is to write up useful html pages explaining the
119  // costs.
120  public String toHtmlReportString() {
121    StringBuilder builder = new StringBuilder();
122    String sep = "";
123    if (cyclomaticCost > 0) {
124      builder.append(sep);
125      builder.append("<a href=\"" + COMPLEXITY_COST_HELP_URL + "\">CC: " + cyclomaticCost + "</a>");
126      sep = ", ";
127    }
128    if (globalCost > 0) {
129      builder.append(sep);
130      builder.append("<a href=\"" + GLOBAL_COST_HELP_URL + "\">GC: " + globalCost + "</a>");
131      sep = ", ";
132    }
133    int loDSum = getLoDSum();
134    if (loDSum > 0) {
135      builder.append(sep);
136      builder.append("<a href=\"" + LAW_OF_DEMETER_COST_HELP_URL + "\">LOD: " + loDSum + "</a>");
137      sep = ", ";
138    }
139    return builder.toString();
140  }
141
142  public int getLoDSum() {
143    int sum = 0;
144    for (int value : lodDistribution) {
145      sum += value;
146    }
147    return sum;
148  }
149
150  public Cost copy() {
151    return new Cost(cyclomaticCost, globalCost, lodDistribution);
152  }
153
154  public Cost copyNoLOD() {
155    return new Cost(cyclomaticCost, globalCost, EMPTY);
156  }
157
158
159  public int[] getLoDDistribution() {
160    return lodDistribution;
161  }
162
163  @Override
164  public int hashCode() {
165    final int prime = 31;
166    int result = 1;
167    result = prime * result + cyclomaticCost;
168    result = prime * result + globalCost;
169    result = prime * result + Arrays.hashCode(lodDistribution);
170    return result;
171  }
172
173  @Override
174  public boolean equals(Object obj) {
175    if (this == obj) {
176      return true;
177    }
178    if (obj == null) {
179      return false;
180    }
181    if (getClass() != obj.getClass()) {
182      return false;
183    }
184    Cost other = (Cost) obj;
185    if (cyclomaticCost != other.cyclomaticCost) {
186      return false;
187    }
188    if (globalCost != other.globalCost) {
189      return false;
190    }
191    if (!Arrays.equals(lodDistribution, other.lodDistribution)) {
192      return false;
193    }
194    return true;
195  }
196
197  Map<String, Object> getAttributes() {
198    Map<String, Object> atts = new HashMap<String, Object>();
199    atts.put("cyclomatic", getCyclomaticComplexityCost());
200    atts.put("global", getGlobalCost());
201    atts.put("lod", getLoDSum());
202    return atts;
203  }
204
205  public void addCyclomaticCost(int cyclomaticCost) {
206    this.cyclomaticCost += cyclomaticCost;
207  }
208
209  public void addGlobalCost(int globalCost) {
210    this.globalCost += globalCost;
211  }
212
213  public void addLodDistance(int distance) {
214    add(Cost.lod(distance));
215  }
216
217  public boolean isEmpty() {
218    return lodDistribution.length == 0 && cyclomaticCost == 0 && globalCost == 0;
219  }
220
221  public Cost negate() {
222    int[] negativeLod = new int[lodDistribution.length];
223    int index = 0;
224    for (int lod : lodDistribution) {
225      negativeLod[index++] = -lod;
226    }
227    return new Cost(-cyclomaticCost, -globalCost, negativeLod);
228  }
229}