/testability-explorer/src/main/java/com/google/test/metric/report/XMLReportDiffer.java
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}