@Test
  public void abuseWeaknessNoNamespaceIdTest() throws Exception {

    SoapTestDocument soap = new SoapTestDocument();
    Document doc = soap.getDocument();

    Element signed = soap.getDummyPayloadBody();
    String id = "signed";
    Attr idAttr = doc.createAttribute("ID");
    idAttr.setTextContent(id);
    signed.setAttributeNode(idAttr);

    Element payload = (Element) signed.cloneNode(true);

    soap.getHeader().appendChild(payload);

    String xpath = "/soapenv:Envelope//*[@ID='" + id + "']";
    log.info("Using XPath: " + xpath);
    AbsoluteLocationPath abs = new AbsoluteLocationPath(xpath);
    Step step = abs.getRelativeLocationPaths().get(2);

    XPathAttributeWeaknessPostProcess aw = new XPathAttributeWeaknessPostProcess(step);

    assertEquals(3, aw.getNumberOfPossibilities());

    Attr sa, pa;

    aw.abuseWeakness(0, new SignedElement(signed, null), new PayloadElement(payload, null));
    log.info("abuseWeakness(0, signed, payload)\n" + domToString(doc, true));
    sa = signed.getAttributeNode("ID");
    pa = payload.getAttributeNode("ID");
    assertNotNull(sa);
    assertNotNull(pa);
    assertEquals(sa.getTextContent(), id);
    assertFalse(pa.getTextContent().isEmpty());
    assertFalse(pa.getTextContent().equals(id));
    assertFalse(sa.getTextContent().equals(pa.getTextContent()));

    aw.abuseWeakness(2, new SignedElement(signed, null), new PayloadElement(payload, null));
    log.info("abuseWeakness(2, signed, payload)\n" + domToString(doc, true));
    sa = signed.getAttributeNode("ID");
    pa = payload.getAttributeNode("ID");
    assertNotNull(sa);
    assertNotNull(pa);
    assertEquals(sa.getTextContent(), id);
    assertFalse(pa.getTextContent().isEmpty());
    assertEquals(sa.getTextContent(), pa.getTextContent());

    aw.abuseWeakness(1, new SignedElement(signed, null), new PayloadElement(payload, null));
    log.info("abuseWeakness(1, signed, payload)\n" + domToString(doc, true));
    sa = signed.getAttributeNode("ID");
    pa = payload.getAttributeNode("ID");
    assertNotNull(sa);
    assertNull(pa);
    assertEquals(sa.getTextContent(), id);
  }
  /**
   * Validates if the given XPath follows the FastXPath grammar but without prefixes. This is known
   * to be most secure.
   *
   * @return
   */
  public boolean isPrefixfreeTransformedFastXPath() {
    for (Step step : xpath.getRelativeLocationPaths()) {
      if (!step.getAxisSpecifier().getAxisName().toFullString().equals("child")) {
        return false;
      }
      if (step.getAxisSpecifier().getNodeName() != null) {
        return false;
      }
      if (step.getAxisSpecifier().getNodeType() == null) {
        return false;
      }
      if (!step.getAxisSpecifier().getNodeType().getNodeTypeName().equals("node")) {
        return false;
      }

      List<Predicate> predicates = step.getPredicates();
      if (predicates.isEmpty() || predicates.size() > 3) {
        return false;
      }
      int positions = 0;
      int attributes = 0;
      int ln = 0;
      int uri = 0;
      for (Predicate pred : step.getPredicates()) {
        if (pred.getOrExpressions().size() != 1) {
          return false;
        }
        if (pred.getOrExpressions().get(0).getAndExpressions().size() != 1) {
          List<AndExpression> andExpressions = pred.getOrExpressions().get(0).getAndExpressions();
          if (andExpressions.size() > 2 || andExpressions.size() < 1) {
            return false;
          }
          for (AndExpression and : andExpressions) {
            if (and instanceof LocalNameAndExpression) {
              ++ln;
            } else if (and instanceof NamespaceUriAndExpression) {
              ++uri;
            }
          }
        } else {
          AndExpression and = pred.getOrExpressions().get(0).getAndExpressions().get(0);
          if (and instanceof PositionAndExpression) {
            ++positions;
          } else if (and instanceof AttributeAndExpression) {
            ++attributes;
          }
        }
      }
      if (ln != 1 || uri != 1 || positions > 1 || attributes > 1 || (attributes + positions) == 0) {
        return false;
      }
    }
    return true;
  }
  /**
   * Validates if the given XPath follows the FastXPath grammar. These are known to be fast and only
   * vulnerable to namespace injection.
   *
   * @return
   */
  public boolean isFastXPath() {
    for (Step step : xpath.getRelativeLocationPaths()) {
      if (!step.getAxisSpecifier().getAxisName().toFullString().equals("child")) {
        return false;
      }
      if (step.getAxisSpecifier().getNodeType() != null) {
        return false;
      }
      if (step.getAxisSpecifier().getNodeName() == null) {
        return false;
      }
      // if (step.getAxisSpecifier().getNodeName().getPrefix().isEmpty())
      // return false;
      if (step.getAxisSpecifier().getNodeName().getNodeName().isEmpty()) {
        return false;
      }

      List<Predicate> predicates = step.getPredicates();
      if (predicates.isEmpty() || predicates.size() > 2) {
        return false;
      }
      int positions = 0;
      int attributes = 0;
      for (Predicate pred : step.getPredicates()) {
        if (pred.getOrExpressions().size() != 1) {
          return false;
        }
        if (pred.getOrExpressions().get(0).getAndExpressions().size() != 1) {
          return false;
        }
        AndExpression and = pred.getOrExpressions().get(0).getAndExpressions().get(0);
        if (and instanceof PositionAndExpression) {
          ++positions;
        } else if (and instanceof AttributeAndExpression) {
          ++attributes;
        }
      }
      if (positions > 1 || attributes > 1 || (attributes + positions) == 0) {
        return false;
      }
    }
    return true;
  }