PageRenderTime 16ms CodeModel.GetById 1ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

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

http://testability-explorer.googlecode.com/
Java | 123 lines | 96 code | 21 blank | 6 comment | 27 complexity | d37dedc34e06e039545f5e1757aec6f6 MD5 | raw file
  1package com.google.test.metric.report;
  2
  3import static com.google.test.metric.report.XMLReportGenerator.CLASS_COST_ATTRIBUTE;
  4import static com.google.test.metric.report.XMLReportGenerator.CLASS_NAME_ATTRIBUTE;
  5import static com.google.test.metric.report.XMLReportGenerator.CLASS_NODE;
  6import static com.google.test.metric.report.XMLReportGenerator.METHOD_NAME_ATTRIBUTE;
  7import static com.google.test.metric.report.XMLReportGenerator.METHOD_OVERALL_COST_ATTRIBUTE;
  8
  9import java.util.Collections;
 10import java.util.HashMap;
 11import java.util.HashSet;
 12import java.util.LinkedList;
 13import java.util.List;
 14import java.util.Map;
 15import java.util.Set;
 16import java.util.logging.Level;
 17import java.util.logging.Logger;
 18
 19import org.w3c.dom.Document;
 20import org.w3c.dom.Node;
 21import org.w3c.dom.NodeList;
 22
 23/**
 24 * Calculate the differences between classes and methods in two XML
 25 * testability reports.
 26 *
 27 * @author alexeagle@google.com (Alex Eagle)
 28 */
 29public class XMLReportDiffer {
 30  Logger logger = Logger.getLogger(XMLReportDiffer.class.getCanonicalName());
 31
 32  public Diff diff(Document oldDoc, Document newDoc) {
 33    List<Diff.ClassDiff> result = new LinkedList<Diff.ClassDiff>();
 34
 35    NodeList oldClasses = oldDoc.getElementsByTagName(CLASS_NODE);
 36    NodeList newClasses = newDoc.getElementsByTagName(CLASS_NODE);
 37
 38    Map<String, Node> oldClassMap = buildChildMap(oldClasses, CLASS_NAME_ATTRIBUTE);
 39    Map<String, Node> newClassMap = buildChildMap(newClasses, CLASS_NAME_ATTRIBUTE);
 40
 41    Set<String> classNames = new HashSet<String>();
 42    classNames.addAll(oldClassMap.keySet());
 43    classNames.addAll(newClassMap.keySet());
 44
 45    for (String className : classNames) {
 46      Integer oldCost = getNumericalAttributeOfNode(oldClassMap, className, CLASS_COST_ATTRIBUTE);
 47      Integer newCost = getNumericalAttributeOfNode(newClassMap, className, CLASS_COST_ATTRIBUTE);
 48
 49      List<Diff.MethodDiff> methodDiffs = diffMethods(oldClassMap.get(className), newClassMap.get(className));
 50
 51      if (!methodDiffs.isEmpty() || different(oldCost, newCost)) {
 52        result.add(new Diff.ClassDiff(className,  oldCost, newCost, methodDiffs));
 53      }
 54    }
 55
 56    return new Diff(result);
 57  }
 58
 59  private boolean different(Integer oldCost, Integer newCost) {
 60    return (oldCost == null && newCost != null) || (oldCost != null && (newCost == null || !oldCost.equals(newCost)));
 61  }
 62
 63  @SuppressWarnings("unchecked")
 64  private List<Diff.MethodDiff> diffMethods(Node oldClassNode, Node newClassNode) {
 65    List<Diff.MethodDiff> result = new LinkedList<Diff.MethodDiff>();
 66
 67    Set<String> methodNames = new HashSet<String>();
 68    Map<String, Node> oldMethodMap = Collections.EMPTY_MAP;
 69    Map<String, Node> newMethodMap = Collections.EMPTY_MAP;
 70
 71    if (oldClassNode != null) {
 72      oldMethodMap = buildChildMap(oldClassNode.getChildNodes(), METHOD_NAME_ATTRIBUTE);
 73      methodNames.addAll(oldMethodMap.keySet());
 74    }
 75    if (newClassNode != null) {
 76      newMethodMap = buildChildMap(newClassNode.getChildNodes(), METHOD_NAME_ATTRIBUTE);
 77      methodNames.addAll(newMethodMap.keySet());
 78    }
 79
 80    for (String methodName : methodNames) {
 81      Integer oldCost = getNumericalAttributeOfNode(oldMethodMap, methodName, METHOD_OVERALL_COST_ATTRIBUTE);
 82      Integer newCost = getNumericalAttributeOfNode(newMethodMap, methodName, METHOD_OVERALL_COST_ATTRIBUTE);
 83      if (different(oldCost, newCost)) {
 84         result.add(new Diff.MethodDiff(methodName, oldCost, newCost));
 85      }
 86    }
 87    return result;
 88  }
 89
 90  private Integer getNumericalAttributeOfNode(Map<String, Node> newClassMap, String className, String attribute) {
 91    Integer newCost = null;
 92    if (newClassMap.containsKey(className)) {
 93      try {
 94        String stringValue = extractAttribute(newClassMap.get(className), attribute);
 95        if (stringValue != null) {
 96          newCost = Integer.valueOf(stringValue);
 97        }
 98      } catch (NumberFormatException e) {
 99        logger.log(Level.WARNING,
100            String.format("Invalid cost attribute for class %s", className), e);
101      }
102    }
103    return newCost;
104  }
105
106  private Map<String, Node> buildChildMap(NodeList nodeList, String keyAttributeName) {
107    Map<String, Node> childMap = new HashMap<String, Node>();
108
109    for (int count = 0; count < nodeList.getLength(); count++) {
110      Node node = nodeList.item(count);
111      String keyValue = extractAttribute(node, keyAttributeName);
112      childMap.put(keyValue, node);
113    }
114    return childMap;
115  }
116
117  private String extractAttribute(Node node, String classNameAttribute) {
118    if (node == null || node.getAttributes() == null || node.getAttributes().getNamedItem(classNameAttribute) == null) {
119      return null;
120    }
121    return node.getAttributes().getNamedItem(classNameAttribute).getNodeValue();
122  }
123}