/* * Copyright 2014 Google Inc. All rights reserved. * * 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.polimi.zarathustra; import org.custommonkey.xmlunit.Difference; import org.custommonkey.xmlunit.NodeDetail; import com.google.common.base.Strings; class Heuristics { private static boolean checkBlacklistedElement(NodeDetail nodeDetail, String[] blacklistedKeywords) { String value = nodeDetail.getValue(); String xPath = nodeDetail.getXpathLocation(); for (String keyword : blacklistedKeywords) { if (keyword.equalsIgnoreCase(value)) { return true; } if ((xPath != null) && xPath.endsWith(keyword)) { return true; } } return false; } /** * Given a node and the name of an element, returns "true" its direct parent IS NOT an element * with that name */ private static boolean checkNodeNotInParent(NodeDetail nodeDetail, String parentName) { String value; try { value = nodeDetail.getNode().getParentNode().getNodeName(); if (value == null) { return true; } else { return !parentName.equalsIgnoreCase(value); } } catch (NullPointerException e) { return true; } } /** * Checks this heuristic: if a modified text is not in a script, consider it a false difference. * This difference was introduced after finding an injection on the content of an existing script. * Most of "modified text" differences are harmless and occur on span elements */ static boolean differentTextNotInScript(Difference difference) { if (difference.getId() == 14) { NodeDetail controlNode = difference.getControlNodeDetail(); NodeDetail testNode = difference.getTestNodeDetail(); String parentName = "script"; return checkNodeNotInParent(controlNode, parentName) || checkNodeNotInParent(testNode, parentName); } return false; } /** * Checks this heuristic: if the attribute that has been modified is the "value" attribute of an * "input" element, it is much likely to be a false difference */ static boolean differentValueAttributeOnInput(Difference difference) { String controlNodeXpath = difference.getTestNodeDetail().getXpathLocation(); if ((controlNodeXpath != null) && controlNodeXpath.endsWith("@value") && (difference.getId() == 3)) { String nodeName = "input"; String[] elements = controlNodeXpath.split("/"); String secondLastElement = elements[elements.length - 2]; if ((secondLastElement != null) && secondLastElement.startsWith(nodeName)) { return true; } } return false; } /** * Checks this heuristic: if an added/deleted/edited attribute or an edited text have different * xpaths on the control and test nodes, consider them as a false difference. This is needed to * deal with the recurring behavior of the comparer according to which elements are erroneously * seen as moved and hence compared with completely different nodes on different xpaths. */ static boolean editedElementOnDifferentXpath(Difference difference) { String firstXPath = Strings.nullToEmpty(difference.getControlNodeDetail().getXpathLocation()); String secondXPath = Strings.nullToEmpty(difference.getTestNodeDetail().getXpathLocation()); if (((difference.getId() == 2) || (difference.getId() == 3) || (difference.getId() == 14)) && !firstXPath.equalsIgnoreCase(secondXPath)) { return true; } else { return false; } } /** * Checks this heuristic: if a keyword that usually appears alongside a false difference is found * as the name (value) of an added element or as the last element in the xpath, the difference is * handled as false. This happens in particular with formatting elements. */ static boolean onBlacklistedElement(Difference difference) { NodeDetail controlNode = difference.getControlNodeDetail(); NodeDetail testNode = difference.getTestNodeDetail(); String[] blacklistedKeywords = {"style", "class", "width", "height", "sizset", "sizcache", "alt"}; return checkBlacklistedElement(controlNode, blacklistedKeywords) || checkBlacklistedElement(testNode, blacklistedKeywords); } private Heuristics() {} }