Package com.google.caja.plugin.templates

Source Code of com.google.caja.plugin.templates.IhtmlSanityCheckerTest

// Copyright (C) 2009 Google Inc.
//
// 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 com.google.caja.plugin.templates;

import com.google.caja.lexer.FilePosition;
import com.google.caja.parser.html.AttribKey;
import com.google.caja.parser.html.DomParser;
import com.google.caja.parser.html.ElKey;
import com.google.caja.parser.html.Namespaces;
import com.google.caja.parser.html.Nodes;
import com.google.caja.reporting.MarkupRenderMode;
import com.google.caja.reporting.Message;
import com.google.caja.reporting.MessageLevel;
import com.google.caja.reporting.MessagePart;
import com.google.caja.reporting.MessageType;
import com.google.caja.util.CajaTestCase;

import java.io.StringReader;

import org.w3c.dom.Element;

public class IhtmlSanityCheckerTest extends CajaTestCase {

  public final void testEmptyTemplate() throws Exception {
    runTest(
        "<ihtml:template formals=\"\" name=\"hi\"></ihtml:template>",
        "<ihtml:template formals='' name='hi'/>");
  }
  public final void testHtmlInTemplate() throws Exception {
    runTest(
        "<ihtml:template formals=\"\" name=\"hi\"><p>Hi</p></ihtml:template>",
        "<ihtml:template formals=\"\" name=\"hi\"><p>Hi</p></ihtml:template>");
  }
  public final void testSimpleMessage() throws Exception {
    runTest(
        ""
        + "<ihtml:template formals=\"a\" name=\"t\">"
        + "<ihtml:message name=\"hi\">Hello</ihtml:message>"
        + "</ihtml:template>",
        ""
        + "<ihtml:template formals='a' name='t'>"
        + "<ihtml:message name='hi'>Hello</ihtml:message>"
        + "</ihtml:template>");
  }
  public final void testMultipleFormals() throws Exception {
    runTest(
        ""
        + "<ihtml:template formals=\"a b\" name=\"t\">"
        + "<ihtml:message name=\"hi\">Hello</ihtml:message>"
        + "</ihtml:template>",
        ""
        + "<ihtml:template formals='a b' name='t'>"
        + "<ihtml:message name='hi'>Hello</ihtml:message>"
        + "</ihtml:template>");
  }
  public final void testMultipleVars() throws Exception {
    runTest(
        "<ihtml:do vars=\"a _b\"></ihtml:do>",
        "<ihtml:do vars=\"a _b\" />");
  }
  public final void testUnnamedMessage() throws Exception {
    runTest(
        "<ihtml:template formals=\"a b\" name=\"t\"></ihtml:template>",
        ""
        + "<ihtml:template formals='a b' name='t'>"
        + "<ihtml:message>Hello</ihtml:message>"
        + "</ihtml:template>",
        new Message(IhtmlMessageType.MISSING_ATTRIB,
                    elKey("ihtml:message"), attrKey("ihtml:message", "name"),
                    FilePosition.instance(is, 1, 40, 40, 36))
        );
  }
  public final void testMisnamedMessage() throws Exception {
    runTest(
        "<ihtml:template formals=\"a b\" name=\"t\"></ihtml:template>",
        ""
        + "<ihtml:template formals=\"a b\" name=\"t\">"
        + "<ihtml:message name=\"x__\">"
        + "Hello"
        + "</ihtml:message>"
        + "</ihtml:template>",
        new Message(IhtmlMessageType.BAD_ATTRIB,
                    FilePosition.instance(is, 1, 55, 55, 10),
                    elKey("ihtml:message"), attrKey("ihtml:message", "name"),
                    MessagePart.Factory.valueOf("x__"))
        );
  }
  public final void testMessageWithPlaceholder() throws Exception {
    runTest(
        ""
        + "<ihtml:template formals=\"x\" name=\"t\">"
        + "<ihtml:message name=\"hi\">"
        + "Hello "
        + "<ihtml:ph name=\"planet\"></ihtml:ph>"
        + "<ihtml:dynamic expr=\"planet\"></ihtml:dynamic>"
        + "<ihtml:eph></ihtml:eph>!"
        + "</ihtml:message>"
        + "</ihtml:template>",
        ""
        + "<ihtml:template formals=\"x\" name=\"t\">"
        + "<ihtml:message name=\"hi\">"
        + "Hello "
        + "<ihtml:ph name=\"planet\"/>"
        + "<ihtml:dynamic expr=\"planet\"/>"
        + "<ihtml:eph/>!"
        + "</ihtml:message>"
        + "</ihtml:template>");
  }
  public final void testBadPlaceholderName() throws Exception {
    runTest(
        ""
        + "<ihtml:template formals=\"\" name=\"t\">"
        + "<ihtml:message name=\"hi\">"
        + "Hello "
        + "<ihtml:dynamic expr=\"planet\"></ihtml:dynamic>"
        + "!"
        + "</ihtml:message>"
        + "</ihtml:template>",
        ""
        + "<ihtml:template formals=\"\" name=\"t\">"
        + "<ihtml:message name=\"hi\">"
        + "Hello "
        + "<ihtml:ph name=\"if\"/>"
        + "<ihtml:dynamic expr=\"planet\"/>"
        + "<ihtml:eph/>!"
        + "</ihtml:message>"
        + "</ihtml:template>",
        new Message(
            IhtmlMessageType.BAD_ATTRIB,
            FilePosition.instance(is, 1, 78, 78, 9),
            elKey("ihtml:ph"), attrKey("ihtml:ph", "name"),
            MessagePart.Factory.valueOf("if")),
        new Message(
            IhtmlMessageType.ORPHANED_PLACEHOLDER_END,
            FilePosition.instance(is, 1, 119, 119, 12)));
  }
  public final void testUnnamedPlaceholder() throws Exception {
    runTest(
        ""
        + "<ihtml:template formals=\"\" name=\"t\">"
        + "<ihtml:message name=\"hi\">"
        + "Hello "
        + "<ihtml:dynamic expr=\"planet\"></ihtml:dynamic>"
        + "!"
        + "</ihtml:message>"
        + "</ihtml:template>",
        ""
        + "<ihtml:template formals=\"\" name=\"t\">"
        + "<ihtml:message name=\"hi\">"
        + "Hello "
        + "<ihtml:ph/>"
        + "<ihtml:dynamic expr=\"planet\"/>"
        + "<ihtml:eph/>!"
        + "</ihtml:message>"
        + "</ihtml:template>",
        new Message(
            IhtmlMessageType.MISSING_ATTRIB,
            elKey("ihtml:ph"),attrKey("ihtml:ph", "name"),
            FilePosition.instance(is, 1, 68, 68, 11)),
        new Message(
            IhtmlMessageType.ORPHANED_PLACEHOLDER_END,
            FilePosition.instance(is, 1, 109, 109, 12)));
  }
  public final void testNestedMessage() throws Exception {
    runTest(
        ""
        + "<ihtml:template formals=\"\" name=\"t\">"
        + "<ihtml:message name=\"hi\">"
        + "Hello "
        + "<ihtml:ph name=\"planet\"></ihtml:ph>"
        + "<ihtml:dynamic expr=\"planet\"></ihtml:dynamic>"
        + "<ihtml:eph></ihtml:eph>!"
        + "</ihtml:message>"
        + "</ihtml:template>",
        ""
        + "<ihtml:template formals=\"\" name=\"t\">"
        + "<ihtml:message name=\"hi\">"
        + "<ihtml:message name=\"there\" />"
        + "Hello "
        + "<ihtml:ph name=\"planet\"/>"
        + "<ihtml:dynamic expr=\"planet\"/>"
        + "<ihtml:eph/>!"
        + "</ihtml:message>"
        + "</ihtml:template>",
        new Message(
            IhtmlMessageType.NESTED_MESSAGE,
            FilePosition.instance(is, 1, 62, 62, 30),
            FilePosition.instance(is, 1, 37, 37, 145)));
  }
  public final void testUnclosedPlaceholder() throws Exception {
    runTest(
        ""
        + "<ihtml:template formals=\"\" name=\"t\">"
        + "<ihtml:message name=\"hi\">"
        + "Hello "
        + "<ihtml:dynamic expr=\"planet\"></ihtml:dynamic>!"
        + "</ihtml:message>"
        + "</ihtml:template>",
        ""
        + "<ihtml:template formals=\"\" name=\"t\">"
        + "<ihtml:message name=\"hi\">"
        + "Hello "
        + "<ihtml:ph name=\"planet\"/>"
        + "<ihtml:dynamic expr=\"planet\"/>!"
        + "</ihtml:message>"
        + "</ihtml:template>",
        new Message(
            IhtmlMessageType.UNCLOSED_PLACEHOLDER,
            FilePosition.instance(is, 1, 68, 68, 56)));
  }
  public final void testUnclosedPlaceholder2() throws Exception {
    runTest(
        ""
        + "<ihtml:template formals=\"\" name=\"t\">"
        + "<ihtml:message name=\"hi\">"
        + "Hello "
        + "<ihtml:dynamic expr=\"planet\"></ihtml:dynamic>"
        + "<ihtml:ph name=\"punc\"></ihtml:ph>"
        + "!"
        + "<ihtml:eph></ihtml:eph>"
        + "</ihtml:message>"
        + "</ihtml:template>",
        ""
        + "<ihtml:template formals=\"\" name=\"t\">"
        + "<ihtml:message name=\"hi\">"
        + "Hello "
        + "<ihtml:ph name=\"planet\"/>"
        + "<ihtml:dynamic expr=\"planet\"/>"
        + "<ihtml:ph name=\"punc\"/>"
        + "!"
        + "<ihtml:eph/>"
        + "</ihtml:message>"
        + "</ihtml:template>",
        new Message(
            IhtmlMessageType.UNCLOSED_PLACEHOLDER,
            // Ends before placeholder punc.
            FilePosition.instance(is, 1, 68, 68, 55)));
  }
  public final void testOrphanedPlaceholder() throws Exception {
    runTest(
        ""
        + "<ihtml:template formals=\"\" name=\"t\">"
        + "Hello "
        + "<ihtml:dynamic expr=\"planet\"></ihtml:dynamic>!"
        + "</ihtml:template>",
        ""
        + "<ihtml:template formals=\"\" name=\"t\">"
        + "Hello "
        + "<ihtml:ph name=\"planet\"/>"
        + "<ihtml:dynamic expr=\"planet\"/>!"
        + "<ihtml:eph/>"
        + "</ihtml:template>",
        new Message(
            IhtmlMessageType.ORPHANED_PLACEHOLDER,
            FilePosition.instance(is, 1, 43, 43, 25)),
        new Message(
            IhtmlMessageType.ORPHANED_PLACEHOLDER,
            FilePosition.instance(is, 1, 99, 99, 12)));
  }
  public final void testOrphanedPlaceholderEnd() throws Exception {
    runTest(
        ""
        + "<ihtml:template formals=\"\" name=\"t\">"
        + "Hello "
        + "<ihtml:dynamic expr=\"planet\"></ihtml:dynamic>!"
        + "</ihtml:template>",
        ""
        + "<ihtml:template formals=\"\" name=\"t\">"
        + "Hello "
        + "<ihtml:dynamic expr=\"planet\"/>!"
        + "<ihtml:eph/>"
        + "</ihtml:template>",
        new Message(
            IhtmlMessageType.ORPHANED_PLACEHOLDER,
            FilePosition.instance(is, 1, 74, 74, 12)));
  }
  public final void testIhtmlElementInMessageOutsidePlaceholder()
      throws Exception {
    runTest(
        ""
        + "<ihtml:template formals=\"\" name=\"t\"></ihtml:template>",
        ""
        + "<ihtml:template formals=\"\" name=\"t\">"
        + "<ihtml:message name='SayHowdy'>"
        + "Hello "
        + "<ihtml:dynamic expr=\"planet\"/>!"
        + "</ihtml:message>"
        + "</ihtml:template>",
        new Message(
            IhtmlMessageType.IHTML_IN_MESSAGE_OUTSIDE_PLACEHOLDER,
            FilePosition.instance(is, 1, 74, 74, 30),
            MessagePart.Factory.valueOf("dynamic")));
  }
  public final void testTemplateNames() throws Exception {
    runTest(
        "<ihtml:template formals=\"x\" name=\"hi\"></ihtml:template>",
        ""
        + "<ihtml:template formals='x' name='hi'>"
        + "<ihtml:template name='3nested' formals='a,,x,if,3' zoinks='ahoy'/>"
        + "</ihtml:template>",
        new Message(
            IhtmlMessageType.BAD_ATTRIB,
            FilePosition.instance(is, 1, 55, 55, 14),
            elKey("ihtml:template"), attrKey("ihtml:template", "name"),
            MessagePart.Factory.valueOf("3nested")),
        new Message(
            IhtmlMessageType.BAD_ATTRIB,
            FilePosition.instance(is, 1, 70, 70, 19),
            elKey("ihtml:template"), attrKey("ihtml:template", "formals"),
            MessagePart.Factory.valueOf("a,,x,if,3")),
        new Message(
            IhtmlMessageType.BAD_ATTRIB,
            FilePosition.instance(is, 1, 90, 90, 13),
            elKey("ihtml:template"), attrKey("ihtml:template", "zoinks"),
            MessagePart.Factory.valueOf("ahoy")));
  }
  public final void testCalls() throws Exception {
    runTest(
        ""
        + "<ihtml:template formals=\"\" name=\"hi\">\n"
        // TODO(mikesamuel): move parameters into a separate namespace so they
        // don't collide with the template param.
        + "  <ihtml:call baz=\"boo\" foo=\"bar\" template=\"bye\">"
          + "</ihtml:call>\n"
        + "</ihtml:template>",
        ""
        + "<ihtml:template name='hi' formals=''>\n"
        + "  <ihtml:call ihtml:template='bye' foo='bar' baz='boo'/>\n"
        + "</ihtml:template>");
  }
  public final void testBadCall() throws Exception {
    runTest(
        ""
        + "<ihtml:template formals=\"\" name=\"hi\">\n"
        + "  \n"
        + "</ihtml:template>",
        ""
        + "<ihtml:template name='hi' formals=''>\n"
        + "  <ihtml:call foo='bar' baz:boo='far'/>\n"
        + "</ihtml:template>",
        new Message(
            IhtmlMessageType.MISSING_ATTRIB,
            FilePosition.instance(is, 2, 41, 3, 37),
            elKey("ihtml:call"),
            attrKey("ihtml:call", "ihtml:template")),
        new Message(
            IhtmlMessageType.BAD_ATTRIB,
            FilePosition.instance(is, 2, 63, 25, 13),
            elKey("ihtml:call"),
            AttribKey.forAttribute(
                new Namespaces(Namespaces.XML_SPECIAL, "baz", "unknown:///baz"),
                elKey("ihtml:call"), "baz:boo"),
            MessagePart.Factory.valueOf("far")),
        new Message(
            MessageType.NO_SUCH_NAMESPACE,
            FilePosition.fromLinePositions(is, 2, 25, 2, 32),
            MessagePart.Factory.valueOf("baz"),
            MessagePart.Factory.valueOf("baz:boo"))
        );
  }
  public final void testMisplacedPlaceholderContent() throws Exception {
    runTest(
        ""
        + "<ihtml:template formals=\"\" name=\"t\">\n"
        + "  <ihtml:message name=\"m\">\n"
        + "    \n"
        + "    \n"
        + "  </ihtml:message>\n"
        + "</ihtml:template>",
        ""
        + "<ihtml:template formals=\"\" name=\"t\">\n"
        + "  <ihtml:message name=\"m\">\n"
        + "    <ihtml:ph name=\"p\">Hi</ihtml:ph>\n"
        + "    <ihtml:eph>There</ihtml:eph>\n"
        + "  </ihtml:message>\n"
        + "</ihtml:template>",
        new Message(
            IhtmlMessageType.INAPPROPRIATE_CONTENT,
            FilePosition.instance(is, 3, 88, 24, 2),
            MessagePart.Factory.valueOf("ph")),
        new Message(
            IhtmlMessageType.INAPPROPRIATE_CONTENT,
            FilePosition.instance(is, 4, 117, 16, 5),
            MessagePart.Factory.valueOf("eph")));
  }
  public final void testBadAttr() throws Exception {
    runTest(
        ""
        + "<ihtml:template formals=\"\" name=\"t\">\n"
        + "  \n"
        + "  <div><ihtml:element>p</ihtml:element></div>\n"
        + "</ihtml:template>",
        ""
        + "<ihtml:template formals=\"\" name=\"t\">\n"
        + "  <ihtml:element bogus=\"\">p</ihtml:element>\n"
        + "  <div><ihtml:element>p</ihtml:element></div>\n"
        + "</ihtml:template>",
        new Message(
            IhtmlMessageType.BAD_ATTRIB,
            FilePosition.instance(is, 2, 55, 18, 8),
            elKey("ihtml:element"), attrKey("ihtml:element", "bogus"),
            MessagePart.Factory.valueOf("")));
  }
  public final void testDynamicAttr() throws Exception {
    runTest(
        ""
        + "<ihtml:template formals=\"\" name=\"t\">\n"
        + "  <a>\n"
        + "    <ihtml:attribute name=\"href\">"
              + "<ihtml:dynamic expr=\"url\"></ihtml:dynamic>"
            + "</ihtml:attribute>\n"
        + "    <ihtml:attribute name=\"title\">\n"
        + "      <ihtml:message name=\"linkHover\">Howdy</ihtml:message>\n"
        + "    </ihtml:attribute>\n"
        + "    Link Text\n"
        + "    \n"
        + "  </a>\n"
        + "</ihtml:template>",
        ""
        + "<ihtml:template formals=\"\" name=\"t\">\n"
        + "  <a>\n"
        + "    <ihtml:attribute name=\"href\"><ihtml:dynamic expr=\"url\""
        + "     /></ihtml:attribute>\n"
        + "    <ihtml:attribute name=\"title\">\n"
        + "      <ihtml:message name=\"linkHover\">Howdy</ihtml:message>\n"
        + "    </ihtml:attribute>\n"
        + "    Link Text\n"
        + "    <ihtml:attribute>onclick=\"badness()\"</ihtml:attribute>\n"
        + "  </a>\n"
        + "</ihtml:template>",
        new Message(
            IhtmlMessageType.MISSING_ATTRIB,
            FilePosition.instance(is, 8, 264, 5, 54),
            elKey("ihtml:attribute"), attrKey("ihtml:attribute", "name")));
  }
  public final void testMisplacedElementAndAttribute() throws Exception {
    runTest(
        ""
        + "<ihtml:template formals=\"\" name=\"t\">\n"
        + "  <ihtml:element></ihtml:element>\n"
        + "  <ihtml:message name=\"m\">\n"
        + "    \n"
        + "    <ihtml:ph name=\"ph\"></ihtml:ph>\n"
        + "      \n"
        + "    <ihtml:eph></ihtml:eph>\n"
        + "  </ihtml:message>\n"
        + "  <ihtml:do init=\"maybe\">\n"
        + "    <ihtml:element></ihtml:element>\n"
        + "  <ihtml:else></ihtml:else>\n"
        + "    <ihtml:element></ihtml:element>\n"
        + "  </ihtml:do>\n"
        + "</ihtml:template>",
        ""
        + "<ihtml:template formals=\"\" name=\"t\">\n"
        + "  <ihtml:element/>\n"  // OK inside templates
        + "  <ihtml:message name=\"m\">\n"
        + "    <ihtml:element/>\n"  // But not inside messages
        + "    <ihtml:ph name=\"ph\"/>\n"
        + "      <ihtml:element/>\n"  // Not even inside messages
        + "    <ihtml:eph/>\n"
        + "  </ihtml:message>\n"
        + "  <ihtml:do init=\"maybe\">\n"
        + "    <ihtml:element/>\n"  // OK inside a conditional
        + "  <ihtml:else/>\n"
        + "    <ihtml:element/>\n"  // OK inside a conditional's alternate
        + "  </ihtml:do>\n"
        + "</ihtml:template>",
        new Message(
            IhtmlMessageType.MISPLACED_ELEMENT,
            FilePosition.instance(is, 4, 88, 5, 16),
            MessagePart.Factory.valueOf("ihtml:element"),
            MessagePart.Factory.valueOf("ihtml:message")),
        new Message(
            IhtmlMessageType.MISPLACED_ELEMENT,
            FilePosition.instance(is, 6, 137, 7, 16),
            MessagePart.Factory.valueOf("ihtml:element"),
            MessagePart.Factory.valueOf("ihtml:message")));
  }
  public final void testContentType() throws Exception {
    // The callingContext attribute is set by a later pass, so make sure it
    // can't be passed in.
    runTest(
        ""
        + "<ihtml:template formals=\"\" name=\"main\">\n"
        + "  \n"
        + "</ihtml:template>",
        ""
        + "<ihtml:template formals=\"\" name=\"main\">\n"
        + "  <ihtml:template formals=\"\" name=\"sub\"\n"
        + "   " + IHTML.CALLING_CONTEXT_ATTR + "=\"div\">\n"
        + "  </ihtml:template>\n"
        + "</ihtml:template>",
        new Message(
            IhtmlMessageType.BAD_ATTRIB,
            FilePosition.instance(is, 3, 4, 4, 20),
            elKey("ihtml:template"),
            attrKey("ihtml:template", "callingContext"),
            MessagePart.Factory.valueOf("div")));
  }

  private void runTest(
      String goldenIhtml, String inputIhtml, Message... expectedMessages)
      throws Exception {
    Element ihtmlRoot = new DomParser(
        DomParser.makeTokenQueue(
            FilePosition.startOfFile(is), new StringReader(inputIhtml), true,
            false),
        true, mq)
        .parseDocument();
    new IhtmlSanityChecker(mq).check(ihtmlRoot);

    for (Message msg : expectedMessages) {
      assertMessage(true, msg.getMessageType(), msg.getMessageLevel(),
                    msg.getMessageParts().toArray(new MessagePart[0]));
    }
    assertMessagesLessSevereThan(MessageLevel.WARNING);

    String checkedIhtml = Nodes.render(ihtmlRoot, MarkupRenderMode.XML);
    assertEquals(goldenIhtml, checkedIhtml);
  }

  static ElKey elKey(String qname) {
    return ElKey.forElement(Namespaces.HTML_DEFAULT, qname);
  }

  static AttribKey attrKey(String elQName, String aQName) {
    return AttribKey.forAttribute(
        Namespaces.HTML_DEFAULT,
        ElKey.forElement(Namespaces.HTML_DEFAULT, elQName), aQName);
  }
}
TOP

Related Classes of com.google.caja.plugin.templates.IhtmlSanityCheckerTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.