// Bug 210976 - StringIndexOutOfBoundsException: String index out of range: 399
  public void testIssue210976() throws ParseException {
    String code = "<a href=\"@&msc=@@@&klub=@@@\"></a>";
    //             01234567 8901234567890123456 7890123
    //             0          1         2          3

    HtmlParseResult result = parse(code);
    Node root = result.root();
    assertNotNull(root);

    //        ElementUtils.dumpTree(root);

    OpenTag a = ElementUtils.query(root, "html/body/a");
    assertNotNull(a);
    assertEquals(0, a.from());
    assertEquals(29, a.to());

    Attribute attr = a.getAttribute("href");
    assertNotNull(attr);

    assertNotNull(attr.value());
    assertNotNull(attr.unquotedValue());

    assertEquals("\"@&msc=@@@&klub=@@@\"", attr.value());
    assertEquals("@&msc=@@@&klub=@@@", attr.unquotedValue());
  }
 public Attribute getAttribute(String name, boolean ignoreCase) {
   for (Attribute ta : attributes()) {
     if (LexerUtils.equals(ta.name(), name, ignoreCase, false)) {
       return ta;
     }
   }
   return null;
 }
  private void processElements(
      Attribute attribute,
      CssElementType elementType,
      Map<String, Collection<FileObject>> elements2files) {
    CharSequence value = attribute.unquotedValue();
    if (value == null) {
      return;
    }

    if (value.length() == 0) {
      return; // ignore empty value
    }

    // all files containing the id declaration
    Collection<FileObject> filesWithTheId = elements2files.get(value.toString());

    // all referred files with the id declaration
    Collection<FileObject> referredFilesWithTheId = new LinkedList<FileObject>();
    if (filesWithTheId != null) {
      referredFilesWithTheId.addAll(filesWithTheId);
      referredFilesWithTheId.retainAll(referredFiles);
    }

    if (referredFilesWithTheId.isEmpty()) {
      // unknown id
      hints.add(
          new MissingCssElement(
              rule, context, getAttributeValueOffsetRange(attribute, context), filesWithTheId));
    }
  }
  public void testParseTagAttributeWithoutValue() throws ParseException {
    String code = "<!doctype html><body><div align/></body>";
    HtmlParseResult result = parse(code);
    Node root = result.root();
    assertNotNull(root);

    //        ElementUtils.dumpTree(root);

    OpenTag div = ElementUtils.query(root, "html/body/div");
    assertNotNull(div);

    Attribute attr = div.getAttribute("align");
    assertNotNull(attr);

    assertNull(attr.value());
    assertNull(attr.unquotedValue());
  }
  public void testAttributes() throws ParseException {
    HtmlParseResult result =
        parse(
            "<!DOCTYPE html><html><head><title>hello</title></head><body onclick=\"alert()\"></body></html>");
    Node root = result.root();
    //        NodeUtils.dumpTree(root);
    assertNotNull(root);
    OpenTag body = ElementUtils.query(root, "html/body");
    assertNotNull(body);

    assertEquals(1, body.attributes().size());

    Attribute attr = body.attributes().iterator().next();
    assertNotNull(attr);
    assertEquals("onclick", attr.name().toString());
    assertEquals("\"alert()\"", attr.value().toString());
  }
  //    //Bug 193268 - AssertionError: Unexpected node type ENDTAG
  //    public void testScriptTagInBody() throws ParseException {
  //        String scriptOpenTag = "<script type=\"text/javascript\" src=\"test.js\">";
  //        //                   0123456789012 3456789012345678 901234 56789012
  // 345678901234567890123456789
  //        //                   0         1          2          3          4          5
  //        String code = "<!doctype html>"
  //                + "<html>"
  //                + "<head>"
  //                + "<title></title>"
  //                + "</head>"
  //                + "<body>"
  //                + "<canvas>"
  //                + "<a/>"
  //                + "</canvas>"
  //                + scriptOpenTag + "</script>"
  //                + "</body>"
  //                + "</html>";
  //
  ////        ParseTreeBuilder.setLoggerLevel(Level.FINER);
  //        HtmlParseResult result = parse(code);
  //        Node root = result.root();
  //
  //        assertNotNull(root);
  //        ElementUtils.dumpTree(root);
  //
  //        OpenTag title = ElementUtils.query(root, "html/head/title");
  //        assertNotNull(title);
  //        assertNotNull(title.matchingCloseTag());
  //
  //        OpenTag a = ElementUtils.query(root, "html/body/canvas/a");
  //        assertNotNull(a);
  //        assertTrue(a.isEmpty());
  //
  //        OpenTag scriptOpen = ElementUtils.query(root, "html/body/script");
  //        assertNotNull(scriptOpen);
  //
  //        assertEquals(76, scriptOpen.from());
  //        assertEquals(76 + 45, scriptOpen.to());
  //
  //        CloseTag scriptEnd = scriptOpen.matchingCloseTag();
  //        assertNotNull(scriptEnd);
  //
  //        assertEquals(121, scriptEnd.from());
  //        assertEquals(130, scriptEnd.to());
  //
  //    }
  // [Bug 195103] Refactoring changes a changed filename incorrectly in the html <script> tag
  public void testIsAttributeQuoted() throws ParseException {
    String code =
        "<!doctype html>"
            + "<html>"
            + "<head>"
            + "<title></title>"
            + "</head>"
            + "<body>"
            + "<div onclick=\"alert()\">x</div>"
            + "<p onclick='alert()'>x</p>"
            + "<a onclick=alert>x</a>"
            + "</body>"
            + "</html>";

    HtmlParseResult result = parse(code);
    Node root = result.root();

    assertNotNull(root);
    //        NodeUtils.dumpTree(root);

    OpenTag div = ElementUtils.query(root, "html/body/div");
    assertNotNull(div);

    Attribute attr = div.getAttribute("onclick");
    assertNotNull(attr);
    assertTrue(attr.isValueQuoted());

    OpenTag p = ElementUtils.query(root, "html/body/p");
    assertNotNull(p);

    attr = p.getAttribute("onclick");
    assertNotNull(attr);
    assertTrue(attr.isValueQuoted());

    OpenTag a = ElementUtils.query(root, "html/body/a");
    assertNotNull(a);

    attr = a.getAttribute("onclick");
    assertNotNull(attr);
    assertFalse(attr.isValueQuoted());
  }
  // Bug 211792
  // http://netbeans.org/bugzilla/show_bug.cgi?id=211792
  public void testIssue211792() throws ParseException {
    //        ParseTreeBuilder.setLoggerLevel(Level.ALL);

    String code = "<a href=\"\"</p>";
    //             01234567 8 901234
    //             0         1
    Node root = parse(code).root();

    //        ElementUtils.dumpTree(root);

    OpenTag a = ElementUtils.query(root, "html/body/a");
    assertNotNull(a);

    Collection<Attribute> attrs = a.attributes();
    assertNotNull(attrs);

    //        for(Attribute attr : attrs) {
    //            System.out.println("from:" + attr.from());
    //            System.out.println("to:" + attr.to());
    //            System.out.println("nameoffset:" + attr.nameOffset());
    //            System.out.println("valueoffset:" + attr.valueOffset());
    //            System.out.println("name:"+attr.name());
    //            System.out.println("value:"+attr.value());
    //        }

    // properly the number of the attributes should be one, but the
    // html parser itself serves the three attributes, where first one
    // is correct, second one is completely
    // out of the source are and a third one which represents
    // the close tag after the quotes.
    assertEquals(2, attrs.size());

    Attribute href = attrs.iterator().next();
    assertNotNull(href);

    assertEquals(3, href.from());
    assertEquals(10, href.to());
    assertEquals(3, href.nameOffset());
    assertEquals(8, href.valueOffset());
    assertEquals("href", href.name().toString());
    assertEquals("\"\"", href.value().toString());
    assertEquals("", href.unquotedValue().toString());
  }
 private static OffsetRange getAttributeValueOffsetRange(Attribute attr, HtmlRuleContext context) {
   boolean quoted = attr.isValueQuoted();
   int from = attr.valueOffset() + (quoted ? 1 : 0);
   int to = from + attr.unquotedValue().length();
   return EmbeddingUtil.convertToDocumentOffsets(from, to, context.getSnapshot());
 }