Package org.apache.tapestry.junit.parse

Source Code of org.apache.tapestry.junit.parse.TestTemplateParser

// Copyright 2004, 2005 The Apache Software Foundation
//
// 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.apache.tapestry.junit.parse;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

import junit.framework.TestCase;

import org.apache.hivemind.Location;
import org.apache.hivemind.Resource;
import org.apache.hivemind.impl.DefaultClassResolver;
import org.apache.hivemind.util.ClasspathResource;
import org.apache.tapestry.parse.ITemplateParserDelegate;
import org.apache.tapestry.parse.LocalizationToken;
import org.apache.tapestry.parse.OpenToken;
import org.apache.tapestry.parse.TemplateParseException;
import org.apache.tapestry.parse.TemplateParser;
import org.apache.tapestry.parse.TemplateToken;
import org.apache.tapestry.parse.TemplateTokenFactory;
import org.apache.tapestry.parse.TextToken;
import org.apache.tapestry.parse.TokenType;

/**
* Tests for the Tapestry HTML template parser.
*
* @author Howard Lewis Ship
*/

public class TestTemplateParser extends TestCase
{
    private static class ParserDelegate implements ITemplateParserDelegate
    {
        private final String _componentAttributeName;

        public ParserDelegate()
        {
            this("jwcid");
        }

        public ParserDelegate(String componentAttributeName)
        {
            _componentAttributeName = componentAttributeName;
        }

        public boolean getKnownComponent(String componentId)
        {
            return true;
        }

        public boolean getAllowBody(String componentId, Location location)
        {
            return true;
        }

        public boolean getAllowBody(String libraryId, String type, Location location)
        {
            return true;
        }

        public String getComponentAttributeName()
        {
            return _componentAttributeName;
        }
    }

    protected TemplateToken[] run(char[] templateData, ITemplateParserDelegate delegate,
            Resource location) throws TemplateParseException
    {
        TemplateParser parser = new TemplateParser();

        parser.setFactory(new TemplateTokenFactory());

        return parser.parse(templateData, delegate, location);
    }

    protected TemplateToken[] run(InputStream stream, ITemplateParserDelegate delegate,
            Resource location) throws TemplateParseException
    {
        StringBuffer buffer = new StringBuffer();
        char[] block = new char[1000];
        InputStreamReader reader = new InputStreamReader(stream);

        try
        {
            while (true)
            {
                int count = reader.read(block, 0, block.length);

                if (count < 0)
                    break;

                buffer.append(block, 0, count);
            }

            reader.close();
        }
        catch (IOException ex)
        {
            fail("Unable to read from stream.");
        }

        return run(buffer.toString().toCharArray(), delegate, location);
    }

    protected TemplateToken[] run(String file) throws TemplateParseException
    {
        return run(file, new ParserDelegate());
    }

    protected TemplateToken[] run(String file, ITemplateParserDelegate delegate)
            throws TemplateParseException
    {
        String thisClassName = getClass().getName();
        String thisPath = "/" + thisClassName.replace('.', '/') + "/" + file;

        Resource location = new ClasspathResource(new DefaultClassResolver(), thisPath);

        InputStream stream = getClass().getResourceAsStream(file);

        if (stream == null)
            throw new TemplateParseException("File " + file + " not found.");

        return run(stream, delegate, location);
    }

    private Map buildMap(String[] input)
    {
        Map result = new HashMap();

        for (int i = 0; i < input.length; i += 2)
            result.put(input[i], input[i + 1]);

        return result;
    }

    // Note: the API of TextToken changed ... from startIndex/endIndex to offset/length.
    // Rather than change *all* the tests, we'll just adjust here.

    protected void assertTextToken(TemplateToken token, int startIndex, int endIndex)
    {
        TextToken t = (TextToken) token;

        int expectedLength = endIndex - startIndex + 1;

        assertEquals("Text token type.", TokenType.TEXT, t.getType());
        assertEquals("Text token start index.", startIndex, t.getOffset());
        assertEquals("Text token end index.", expectedLength, t.getLength());
    }

    /** @since 3.0 * */

    protected void checkLine(TemplateToken token, int line)
    {
        assertEquals("Token line", line, token.getLocation().getLineNumber());
    }

    /** @since 2.0.4 * */

    protected void assertLocalizationToken(TemplateToken token, String key, Map attributes, int line)
    {
        LocalizationToken t = (LocalizationToken) token;

        assertEquals("Localization token type.", TokenType.LOCALIZATION, t.getType());
        assertEquals("Localization key.", key, t.getKey());

        assertEquals("Localization attributes.", attributes, t.getAttributes());

        checkLine(token, line);
    }

    protected void assertOpenToken(TemplateToken token, String id, String tag, int line)
    {
        assertOpenToken(token, id, null, tag, line);
    }

    protected void assertOpenToken(TemplateToken token, String id, String componentType,
            String tag, int line)
    {
        OpenToken t = (OpenToken) token;

        assertEquals("Open token type", TokenType.OPEN, t.getType());
        assertEquals("Open token id", id, t.getId());
        assertEquals("Open token component type", componentType, t.getComponentType());
        assertEquals("Open token tag", tag, t.getTag());

        checkLine(token, line);
    }

    protected void assertTemplateAttributes(TemplateToken token, Map expected)
    {
        OpenToken t = (OpenToken) token;

        assertEquals("Attributes", expected, t.getAttributesMap());
    }

    protected void assertCloseToken(TemplateToken token, int line)
    {
        assertEquals("Close token type.", TokenType.CLOSE, token.getType());

        checkLine(token, line);
    }

    protected void assertTokenCount(TemplateToken[] tokens, int count)
    {
        assertNotNull("Parsed tokens.", tokens);
        assertEquals("Parsed token count.", count, tokens.length);
    }

    private void runFailure(String file, String message)
    {
        runFailure(file, new ParserDelegate(), message);
    }

    private void runFailure(String file, ITemplateParserDelegate delegate, String message)
    {
        try
        {
            run(file, delegate);

            fail("Invalid document " + file + " parsed without exception.");
        }
        catch (TemplateParseException ex)
        {
            assertEquals(message, ex.getMessage());
            assertTrue(ex.getLocation().toString().indexOf(file) > 0);
        }
    }

    public void testAllStatic() throws TemplateParseException
    {
        TemplateToken[] tokens = run("AllStatic.html");

        assertTokenCount(tokens, 1);
        assertTextToken(tokens[0], 0, 172);
    }

    public void testSingleEmptyTag() throws TemplateParseException
    {
        TemplateToken[] tokens = run("SingleEmptyTag.html");

        assertTokenCount(tokens, 4);

        assertTextToken(tokens[0], 0, 38);
        assertOpenToken(tokens[1], "emptyTag", "span", 3);
        assertCloseToken(tokens[2], 3);
        assertTextToken(tokens[3], 63, 102);
    }

    public void testSimpleNested() throws TemplateParseException
    {
        TemplateToken[] tokens = run("SimpleNested.html");

        assertTokenCount(tokens, 8);
        assertOpenToken(tokens[1], "outer", "span", 3);
        assertOpenToken(tokens[3], "inner", "span", 4);
        assertCloseToken(tokens[4], 4);
        assertCloseToken(tokens[6], 5);
    }

    public void testMixedNesting() throws TemplateParseException
    {
        TemplateToken[] tokens = run("MixedNesting.html");

        assertTokenCount(tokens, 5);
        assertOpenToken(tokens[1], "row", "span", 4);
        assertCloseToken(tokens[3], 7);
    }

    public void testSingleQuotes() throws TemplateParseException
    {
        TemplateToken[] tokens = run("SingleQuotes.html");

        assertTokenCount(tokens, 7);
        assertOpenToken(tokens[1], "first", "span", 5);
        assertOpenToken(tokens[4], "second", "span", 7);
    }

    public void testComplex() throws TemplateParseException
    {
        TemplateToken[] tokens = run("Complex.html");

        assertTokenCount(tokens, 19);

        // Just pick a few highlights out of it.

        assertOpenToken(tokens[1], "ifData", "span", 3);
        assertOpenToken(tokens[3], "e", "span", 10);
        assertOpenToken(tokens[5], "row", "tr", 11);
    }

    public void testStartWithStaticTag() throws TemplateParseException
    {
        TemplateToken[] tokens = run("StartWithStaticTag.html");

        assertTokenCount(tokens, 4);
        assertTextToken(tokens[0], 0, 232);
        assertOpenToken(tokens[1], "justBecause", "span", 9);
    }

    public void testUnterminatedCommentFailure()
    {
        runFailure("UnterminatedComment.html", "Comment on line 3 did not end.");
    }

    public void testUnclosedOpenTagFailure()
    {
        runFailure("UnclosedOpenTag.html", "Tag <body> on line 4 is never closed.");
    }

    public void testMissingAttributeValueFailure()
    {
        runFailure(
                "MissingAttributeValue.html",
                "Tag <img> on line 9 is missing a value for attribute src.");
    }

    public void testIncompleteCloseFailure()
    {
        runFailure("IncompleteClose.html", "Incomplete close tag on line 6.");
    }

    public void testMismatchedCloseTagsFailure()
    {
        runFailure(
                "MismatchedCloseTags.html",
                "Closing tag </th> on line 9 does not have a matching open tag.");
    }

    public void testInvalidDynamicNestingFailure()
    {
        runFailure(
                "InvalidDynamicNesting.html",
                "Closing tag </body> on line 12 is improperly nested with tag <span> on line 8.");
    }

    public void testUnknownComponentIdFailure()
    {
        ITemplateParserDelegate delegate = new ITemplateParserDelegate()
        {
            public boolean getKnownComponent(String componentId)
            {
                return !componentId.equals("row");
            }

            public boolean getAllowBody(String componentId, Location location)
            {
                return true;
            }

            public boolean getAllowBody(String libraryId, String type, Location location)
            {
                return true;
            }

            public String getComponentAttributeName()
            {
                return "jwcid";
            }
        };

        runFailure(
                "Complex.html",
                delegate,
                "Tag <tr> on line 11 references unknown component id 'row'.");
    }

    public void testBasicRemove() throws TemplateParseException
    {
        TemplateToken[] tokens = run("BasicRemove.html");

        assertTokenCount(tokens, 10);
        assertTextToken(tokens[0], 0, 119);
        assertTextToken(tokens[1], 188, 268);
        assertOpenToken(tokens[2], "e", "span", 23);
        assertTextToken(tokens[3], 341, 342);
        assertOpenToken(tokens[4], "row", "tr", 24);
        assertTextToken(tokens[5], 359, 377);
        assertCloseToken(tokens[6], 26);
        assertTextToken(tokens[7], 383, 383);
        assertCloseToken(tokens[8], 27);
        assertTextToken(tokens[9], 391, 401);
    }

    public void testBodyRemove() throws TemplateParseException
    {
        ITemplateParserDelegate delegate = new ITemplateParserDelegate()
        {
            public boolean getKnownComponent(String id)
            {
                return true;
            }

            public boolean getAllowBody(String id, Location location)
            {
                return id.equals("form");
            }

            public boolean getAllowBody(String libraryId, String type, Location location)
            {
                return true;
            }

            public String getComponentAttributeName()
            {
                return "jwcid";
            }
        };

        TemplateToken[] tokens = run("BodyRemove.html", delegate);

        assertTokenCount(tokens, 8);
        assertOpenToken(tokens[1], "form", "form", 9);
        assertOpenToken(tokens[3], "inputType", "select", 11);
        assertCloseToken(tokens[4], 15);
        assertCloseToken(tokens[6], 16);
    }

    public void testRemovedComponentFailure()
    {
        runFailure(
                "RemovedComponent.html",
                "Tag <span> on line 5 is a dynamic component, and may not appear inside an ignored block.");
    }

    public void testNestedRemoveFailure()
    {
        runFailure(
                "NestedRemove.html",
                "Tag <span> on line 4 should be ignored, but is already inside "
                        + "an ignored block (ignored blocks may not be nested).");
    }

    public void testBasicContent() throws TemplateParseException
    {
        TemplateToken[] tokens = run("BasicContent.html");

        assertTokenCount(tokens, 4);
        assertTextToken(tokens[0], 108, 165);
        assertOpenToken(tokens[1], "nested", "span", 9);
        assertCloseToken(tokens[2], 9);
        assertTextToken(tokens[3], 188, 192);
    }

    public void testIgnoredContentFailure()
    {
        runFailure(
                "IgnoredContent.html",
                "Tag <td> on line 7 is the template content, and may not be in an ignored block.");
    }

    public void testTagAttributes() throws TemplateParseException
    {
        TemplateToken[] tokens = run("TagAttributes.html");

        assertTokenCount(tokens, 5);
        assertOpenToken(tokens[1], "tag", null, "span", 3);

        assertTemplateAttributes(tokens[1], buildMap(new String[]
        { "class", "zip", "align", "right", "color", "#ff00ff" }));

    }

    /**
     * @since 2.0.4
     */

    public void testBasicLocalization() throws TemplateParseException
    {
        TemplateToken[] tokens = run("BasicLocalization.html");

        assertTokenCount(tokens, 3);
        assertTextToken(tokens[0], 0, 35);
        assertLocalizationToken(tokens[1], "the.localization.key", null, 3);
        assertTextToken(tokens[2], 89, 117);
    }

    /**
     * Test that the parser fails if a localization block contains a component.
     *
     * @since 2.0.4
     */

    public void testComponentInsideLocalization()
    {
        runFailure(
                "ComponentInsideLocalization.html",
                "Tag <span> on line 9 is a dynamic component, and may not appear inside an ignored block.");
    }

    /**
     * Test that the parser fails if an invisible localization is nested within another invisible
     * localization.
     *
     * @since 2.0.4
     */

    public void testNestedLocalizations()
    {
        runFailure(
                "NestedLocalizations.html",
                "Tag <span> on line 4 is a dynamic component, and may not appear inside an ignored block.");
    }

    /**
     * Test that the abbreviated form (a tag with no body) works.
     *
     * @since 2.0.4
     */

    public void testEmptyLocalization() throws TemplateParseException
    {
        TemplateToken[] tokens = run("EmptyLocalization.html");

        assertTokenCount(tokens, 3);
        assertTextToken(tokens[0], 0, 62);
        assertLocalizationToken(tokens[1], "empty.localization", null, 3);
        assertTextToken(tokens[2], 95, 122);
    }

    /**
     * Test attributes in the span. Also, checks that the parser caselessly identifies the "key"
     * attribute and the tag name ("span").
     *
     * @since 2.0.4
     */

    public void testLocalizationAttributes() throws TemplateParseException
    {
        TemplateToken[] tokens = run("LocalizationAttributes.html");

        Map attributes = buildMap(new String[]
        { "alpha", "beta", "Fred", "Wilma" });

        assertLocalizationToken(tokens[1], "localization.with.attributes", attributes, 3);
    }

    /**
     * Tests for implicit components (both named and anonymous).
     *
     * @since 3.0
     */

    public void testImplicitComponents() throws TemplateParseException
    {
        TemplateToken[] tokens = run("ImplicitComponents.html");

        assertTokenCount(tokens, 18);

        assertOpenToken(tokens[1], "$Body", "Body", "body", 4);
        assertOpenToken(tokens[3], "loop", "Foreach", "tr", 7);

        assertTemplateAttributes(tokens[3], buildMap(new String[]
        { "element", "tr", "source", "ognl:items" }));

        assertOpenToken(tokens[5], "$Insert", "Insert", "span", 10);

        assertTemplateAttributes(tokens[5], buildMap(new String[]
        { "value", "ognl:components.loop.value.name" }));

        assertOpenToken(tokens[8], "$Insert_0", "Insert", "span", 11);

        assertTemplateAttributes(tokens[8], buildMap(new String[]
        { "value", "ognl:components.loop.value.price" }));

        assertOpenToken(tokens[13], "$InspectorButton", "contrib:InspectorButton", "span", 15);
    }

    /**
     * Test for encoded characters in an expression.
     *
     * @since 3.0
     */

    public void testEncodedExpressionCharacters() throws TemplateParseException
    {
        TemplateToken[] tokens = run("EncodedExpressionCharacters.html");

        assertTokenCount(tokens, 3);

        assertOpenToken(tokens[0], "$Insert", "Insert", "span", 1);

        String expression = "ognl: { \"<&>\", \"Fun!\" }";

        assertTemplateAttributes(tokens[0], buildMap(new String[]
        { "value", expression }));

    }

    /**
     * Test ability to read string attributes.
     */

    public void testStringAttributes() throws TemplateParseException
    {
        TemplateToken[] tokens = run("StringAttributes.html");

        assertTokenCount(tokens, 4);

        assertOpenToken(tokens[1], "$Image", "Image", "img", 2);

        assertTemplateAttributes(tokens[1], buildMap(new String[]
        { "image", "ognl:assets.logo", "alt", "message:logo-title" }));

    }

    /**
     * Test ability to use a different attribute name than the default ("jwcid").
     *
     * @since 4.0
     */

    public void testOverrideDefaultAttributeName() throws Exception
    {
        TemplateToken[] tokens = run("OverrideDefaultAttributeName.html", new ParserDelegate("id"));

        assertTokenCount(tokens, 8);
        assertOpenToken(tokens[1], "outer", "span", 3);
        assertOpenToken(tokens[3], "inner", "span", 4);
        assertCloseToken(tokens[4], 4);
        assertCloseToken(tokens[6], 5);
    }

    /**
     * Like {@link #testOverrideDefaultAttributeName()}, but uses a more complicated attribute name
     * (with a XML-style namespace prefix).
     */

    public void testNamespaceAttributeName() throws Exception
    {
        TemplateToken[] tokens = run("NamespaceAttributeName.html", new ParserDelegate("t:id"));

        assertTokenCount(tokens, 8);
        assertOpenToken(tokens[1], "outer", "span", 3);
        assertOpenToken(tokens[3], "inner", "span", 4);
        assertCloseToken(tokens[4], 4);
        assertCloseToken(tokens[6], 5);
    }

    /** @since 4.0 */
    public void testDuplicateTagAttributeFailure()
    {
        runFailure(
                "DuplicateTagAttribute.html",
                "Tag <input> on line 3 contains more than one 'value' attribute.");
    }

    /** @since 4.0 */
    public void testDuplicateTagAttributeFailureSingleQuotes()
    {
        runFailure(
                "DuplicateTagAttributeSingleQuotes.html",
                "Tag <input> on line 3 contains more than one 'value' attribute.");
    }

    /** @since 4.0 */
    public void testSlashInComponentType() throws Exception
    {
        TemplateToken[] tokens = run("SlashInComponentType.html", new ParserDelegate());

        assertEquals(6, tokens.length);

        OpenToken token1 = (OpenToken) tokens[1];

        assertEquals("$foo$Bar", token1.getId());
        assertEquals("foo/Bar", token1.getComponentType());

        OpenToken token2 = (OpenToken) tokens[4];

        assertEquals("baz", token2.getId());
        assertEquals("biff/bop/Boop", token2.getComponentType());
    }
}
TOP

Related Classes of org.apache.tapestry.junit.parse.TestTemplateParser

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.