| // Copyright 2006, 2007 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.tapestry5.internal.services; |
| |
| import org.apache.tapestry5.internal.parser.*; |
| import org.apache.tapestry5.internal.test.InternalBaseTestCase; |
| import org.apache.tapestry5.ioc.Locatable; |
| import org.apache.tapestry5.ioc.Location; |
| import org.apache.tapestry5.ioc.Resource; |
| import org.apache.tapestry5.ioc.internal.util.ClasspathResource; |
| import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newSet; |
| import org.apache.tapestry5.ioc.internal.util.TapestryException; |
| import org.apache.tapestry5.test.TapestryTestConstants; |
| import org.testng.annotations.DataProvider; |
| import org.testng.annotations.Test; |
| |
| import static java.lang.String.format; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.Set; |
| |
| /** |
| * This is used to test the template parser ... and in some cases, the underlying behavior of the SAX APIs. |
| */ |
| public class TemplateParserImplTest extends InternalBaseTestCase |
| { |
| |
| private TemplateParser getParser() |
| { |
| return this.getService(TemplateParser.class); |
| } |
| |
| private synchronized ComponentTemplate parse(String file) |
| { |
| Resource resource = getResource(file); |
| |
| return getParser().parseTemplate(resource); |
| } |
| |
| private synchronized List<TemplateToken> tokens(String file) |
| { |
| Resource resource = getResource(file); |
| |
| return getParser().parseTemplate(resource).getTokens(); |
| } |
| |
| private Resource getResource(String file) |
| { |
| String packageName = getClass().getPackage().getName(); |
| |
| String path = packageName.replace('.', '/') + "/" + file; |
| |
| ClassLoader loader = getClass().getClassLoader(); |
| |
| return new ClasspathResource(loader, path); |
| } |
| |
| @SuppressWarnings("unchecked") |
| private <T extends TemplateToken> T get(List l, int index) |
| { |
| Object raw = l.get(index); |
| |
| return (T) raw; |
| } |
| |
| private void checkLine(Locatable l, int expectedLineNumber) |
| { |
| assertEquals(l.getLocation().getLine(), expectedLineNumber); |
| } |
| |
| @Test |
| public void just_HTML() |
| { |
| Resource resource = getResource("justHTML.tml"); |
| |
| ComponentTemplate template = getParser().parseTemplate(resource); |
| |
| assertSame(template.getResource(), resource); |
| |
| List<TemplateToken> tokens = template.getTokens(); |
| |
| // They add up quick ... |
| |
| assertEquals(tokens.size(), 20); |
| |
| StartElementToken t0 = get(tokens, 0); |
| |
| // Spot check a few things ... |
| |
| assertEquals(t0.getName(), "html"); |
| assertEquals(t0.getNamespaceURI(), ""); |
| checkLine(t0, 1); |
| |
| TextToken t1 = get(tokens, 1); |
| // Concerned this may not work cross platform. |
| assertEquals(t1.getText(), "\n "); |
| |
| StartElementToken t2 = get(tokens, 2); |
| assertEquals(t2.getName(), "head"); |
| checkLine(t2, 2); |
| |
| TextToken t5 = get(tokens, 5); |
| assertEquals(t5.getText(), "title"); |
| checkLine(t5, 3); |
| |
| get(tokens, 6); |
| |
| StartElementToken t12 = get(tokens, 12); |
| assertEquals(t12.getName(), "p"); |
| |
| AttributeToken t13 = get(tokens, 13); |
| assertEquals(t13.getName(), "class"); |
| assertEquals(t13.getValue(), "important"); |
| assertEquals(t13.getNamespaceURI(), ""); |
| |
| TextToken t14 = get(tokens, 14); |
| // Simplify the text, converting consecutive whitespace to just a single space. |
| assertEquals(t14.getText().replaceAll("\\s+", " ").trim(), "Tapestry rocks! Line 2"); |
| |
| // Line number is the *start* line of the whole text block. |
| checkLine(t14, 6); |
| } |
| |
| @Test |
| public void namespaced_element() |
| { |
| Resource resource = getResource("namespaced_element.tml"); |
| |
| ComponentTemplate template = getParser().parseTemplate(resource); |
| |
| assertSame(template.getResource(), resource); |
| |
| List<TemplateToken> tokens = template.getTokens(); |
| |
| // They add up quick ... |
| |
| assertEquals(tokens.size(), 8); |
| |
| StartElementToken t0 = get(tokens, 0); |
| |
| String expectedURI = "http://foo.com"; |
| |
| assertEquals(t0.getNamespaceURI(), expectedURI); |
| assertEquals(t0.getName(), "bar"); |
| |
| DefineNamespacePrefixToken t1 = get(tokens, 1); |
| |
| assertEquals(t1.getNamespacePrefix(), "foo"); |
| assertEquals(t1.getNamespaceURI(), expectedURI); |
| |
| AttributeToken t2 = get(tokens, 2); |
| |
| assertEquals(t2.getName(), "biff"); |
| assertEquals(t2.getValue(), "baz"); |
| assertEquals(t2.getNamespaceURI(), expectedURI); |
| |
| StartElementToken t4 = get(tokens, 4); |
| |
| assertEquals(t4.getNamespaceURI(), ""); |
| assertEquals(t4.getName(), "gnip"); |
| |
| // The rest are close tokens |
| } |
| |
| @Test |
| public void container_element() |
| { |
| List<TemplateToken> tokens = tokens("container_element.tml"); |
| |
| assertEquals(tokens.size(), 4); |
| |
| TextToken t0 = get(tokens, 0); |
| |
| assertEquals(t0.getText().trim(), "A bit of text."); |
| |
| StartElementToken t1 = get(tokens, 1); |
| |
| assertEquals(t1.getName(), "foo"); |
| |
| EndElementToken t2 = get(tokens, 2); |
| |
| assertNotNull(t2); // Keep compiler happy |
| |
| TextToken t3 = get(tokens, 3); |
| |
| assertEquals(t3.getText().trim(), "Some more text."); |
| } |
| |
| @Test |
| public void xml_entity() |
| { |
| List<TemplateToken> tokens = tokens("xmlEntity.tml"); |
| |
| assertEquals(tokens.size(), 3); |
| |
| TextToken t = get(tokens, 1); |
| |
| // This is OK because the org.apache.tapestry5.dom.Text will convert the characters back into |
| // XML entities. |
| |
| assertEquals(t.getText().trim(), "lt:< gt:> amp:&"); |
| } |
| |
| @Test |
| public void html_entity() |
| { |
| String expectedURI = "http://www.w3.org/1999/xhtml"; |
| |
| List<TemplateToken> tokens = tokens("html_entity.tml"); |
| |
| assertEquals(tokens.size(), 5); |
| |
| DTDToken t0 = get(tokens, 0); |
| |
| assertEquals(t0.getName(), "html"); |
| assertEquals(t0.getPublicId(), "-//W3C//DTD XHTML 1.0 Transitional//EN"); |
| assertEquals(t0.getSystemId(), "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"); |
| |
| StartElementToken t1 = get(tokens, 1); |
| |
| assertEquals(t1.getNamespaceURI(), expectedURI); |
| assertEquals(t1.getName(), "html"); |
| |
| DefineNamespacePrefixToken t2 = get(tokens, 2); |
| |
| assertEquals(t2.getNamespaceURI(), expectedURI); |
| assertEquals(t2.getNamespacePrefix(), ""); |
| |
| |
| TextToken t = get(tokens, 3); |
| |
| // HTML entities are parsed into values that will ultimately |
| // be output as numeric entities. This is less than ideal; would like |
| // to find a way to keep the entities in their original form (possibly |
| // involving a new type of token), but SAX seems to be fighting me on this. |
| // You have to have a DOCTYPE just to parse a template that uses |
| // an HTML entity. |
| |
| assertEquals(t.getText().trim(), "nbsp:[\u00a0]"); |
| } |
| |
| @Test |
| public void cdata() |
| { |
| List<TemplateToken> tokens = tokens("cdata.tml"); |
| |
| // Whitespace text tokens around the CDATA |
| |
| assertEquals(tokens.size(), 5); |
| |
| CDATAToken t = get(tokens, 2); |
| |
| assertEquals(t.getContent(), "CDATA: <foo> & <bar> and <baz>"); |
| checkLine(t, 2); |
| } |
| |
| @Test |
| public void comment() |
| { |
| List<TemplateToken> tokens = tokens("comment.tml"); |
| |
| // Again, whitespace before and after the comment adds some tokens |
| |
| assertEquals(tokens.size(), 3); |
| |
| CommentToken token1 = get(tokens, 1); |
| |
| // Comments are now trimmed of leading and trailing whitespace. This may mean |
| // that the output isn't precisely what's in the template, but a) its a comment |
| // and b) that's pretty much true of everything in the templates. |
| |
| assertEquals(token1.getComment(), "Single line comment"); |
| } |
| |
| @Test |
| public void multiline_comment() |
| { |
| List<TemplateToken> tokens = tokens("multilineComment.tml"); |
| |
| // Again, whitespace before and after the comment adds some tokens |
| |
| assertEquals(tokens.size(), 5); |
| |
| CommentToken t = get(tokens, 2); |
| |
| String comment = t.getComment().trim().replaceAll("\\s+", " "); |
| |
| assertEquals(comment, "Line one Line two Line three"); |
| } |
| |
| @Test |
| public void component() |
| { |
| List<TemplateToken> tokens = tokens("component.tml"); |
| |
| assertEquals(tokens.size(), 6); |
| |
| StartComponentToken t = get(tokens, 2); |
| assertEquals(t.getId(), "fred"); |
| assertEquals(t.getComponentType(), "somecomponent"); |
| assertNull(t.getMixins()); |
| checkLine(t, 2); |
| |
| get(tokens, 3); |
| } |
| |
| @Test |
| public void component_with_body() |
| { |
| List<TemplateToken> tokens = tokens("componentWithBody.tml"); |
| |
| assertEquals(tokens.size(), 7); |
| |
| get(tokens, 2); |
| |
| TextToken t = get(tokens, 3); |
| |
| assertEquals(t.getText().trim(), "fred's body"); |
| |
| get(tokens, 4); |
| } |
| |
| @Test |
| public void root_element_is_component() |
| { |
| List<TemplateToken> tokens = tokens("root_element_is_component.tml"); |
| |
| assertEquals(tokens.size(), 3); |
| |
| StartComponentToken start = get(tokens, 0); |
| |
| assertEquals(start.getId(), "fred"); |
| assertEquals(start.getComponentType(), "Fred"); |
| assertNull(start.getElementName()); |
| |
| AttributeToken attr = get(tokens, 1); |
| |
| assertEquals(attr.getName(), "param"); |
| assertEquals(attr.getValue(), "value"); |
| |
| assertTrue(EndElementToken.class.isInstance(tokens.get(2))); |
| } |
| |
| @Test |
| public void instrumented_element() |
| { |
| ComponentTemplate template = parse("instrumented_element.tml"); |
| List<TemplateToken> tokens = template.getTokens(); |
| |
| assertEquals(tokens.size(), 3); |
| |
| StartComponentToken start = get(tokens, 0); |
| |
| assertEquals(start.getId(), "fred"); |
| assertEquals(start.getComponentType(), "Fred"); |
| assertEquals(start.getElementName(), "html"); |
| |
| AttributeToken attr = get(tokens, 1); |
| |
| assertEquals(attr.getName(), "param"); |
| assertEquals(attr.getValue(), "value"); |
| |
| assertTrue(EndElementToken.class.isInstance(tokens.get(2))); |
| |
| assertEquals(template.getComponentIds(), Arrays.asList("fred")); |
| } |
| |
| @Test |
| public void body_element() |
| { |
| List<TemplateToken> tokens = tokens("body_element.tml"); |
| |
| // start(html), text, body, text, end(html) |
| assertEquals(tokens.size(), 5); |
| |
| // javac bug requires use of isInstance() instead of instanceof |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=113218 |
| assertTrue(BodyToken.class.isInstance(get(tokens, 2))); |
| } |
| |
| @Test |
| public void content_within_body_element() |
| { |
| List<TemplateToken> tokens = parse("content_within_body_element.tml").getTokens(); |
| |
| assertEquals(tokens.size(), 5); |
| |
| // javac bug is requires use of isInstance() instead of instanceof |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=113218 |
| |
| assertTrue(BodyToken.class.isInstance(get(tokens, 2))); |
| assertTrue(TextToken.class.isInstance(get(tokens, 3))); |
| assertTrue(EndElementToken.class.isInstance(get(tokens, 4))); |
| } |
| |
| @Test |
| public void component_with_parameters() |
| { |
| List<TemplateToken> tokens = tokens("componentWithParameters.tml"); |
| |
| assertEquals(tokens.size(), 9); |
| |
| TemplateToken templateToken = get(tokens, 2); |
| Location l = templateToken.getLocation(); |
| |
| AttributeToken t1 = get(tokens, 3); |
| |
| // TODO: Not sure what order the attributes appear in. Order in the XML? Sorted |
| // alphabetically? Random 'cause they're hashed? |
| |
| assertEquals(t1.getName(), "cherry"); |
| assertEquals(t1.getValue(), "bomb"); |
| assertSame(t1.getLocation(), l); |
| |
| AttributeToken t2 = get(tokens, 4); |
| assertEquals(t2.getName(), "align"); |
| assertEquals(t2.getValue(), "right"); |
| assertSame(t2.getLocation(), l); |
| |
| TextToken t3 = get(tokens, 5); |
| |
| assertEquals(t3.getText().trim(), "fred's body"); |
| |
| get(tokens, 6); |
| } |
| |
| @Test |
| public void component_with_mixins() |
| { |
| List<TemplateToken> tokens = tokens("component_with_mixins.tml"); |
| |
| assertEquals(tokens.size(), 4); |
| |
| StartComponentToken token1 = get(tokens, 1); |
| |
| assertEquals(token1.getId(), "fred"); |
| assertEquals(token1.getComponentType(), "comp"); |
| assertEquals(token1.getMixins(), "Barney"); |
| } |
| |
| @Test |
| public void empty_string_mixins_is_null() |
| { |
| List<TemplateToken> tokens = tokens("empty_string_mixins_is_null.tml"); |
| |
| assertEquals(tokens.size(), 6); |
| |
| StartComponentToken t = get(tokens, 2); |
| |
| assertEquals(t.getId(), "fred"); |
| // We also check that empty string type is null .. |
| assertNull(t.getComponentType()); |
| assertNull(t.getMixins()); |
| } |
| |
| @Test |
| public void component_ids() |
| { |
| ComponentTemplate template = parse("component_ids.tml"); |
| |
| Set<String> ids = template.getComponentIds(); |
| |
| assertEquals(ids, newSet(Arrays.asList("bomb", "border", "zebra"))); |
| } |
| |
| @Test |
| public void expansions_in_normal_text() |
| { |
| List<TemplateToken> tokens = tokens("expansions_in_normal_text.tml"); |
| |
| assertEquals(tokens.size(), 7); |
| |
| TextToken t1 = get(tokens, 1); |
| |
| assertEquals(t1.getText().trim(), "Expansion #1["); |
| |
| ExpansionToken t2 = get(tokens, 2); |
| assertEquals(t2.getExpression(), "expansion1"); |
| |
| TextToken t3 = get(tokens, 3); |
| assertEquals(t3.getText().replaceAll("\\s+", " "), "] Expansion #2["); |
| |
| ExpansionToken t4 = get(tokens, 4); |
| assertEquals(t4.getExpression(), "expansion2"); |
| |
| TextToken t5 = get(tokens, 5); |
| assertEquals(t5.getText().trim(), "]"); |
| } |
| |
| @Test |
| public void expansions_must_be_on_one_line() |
| { |
| List<TemplateToken> tokens = tokens("expansions_must_be_on_one_line.tml"); |
| |
| assertEquals(tokens.size(), 3); |
| |
| TextToken t1 = get(tokens, 1); |
| |
| assertEquals(t1.getText().replaceAll("\\s+", " "), " ${expansions must be on a single line} "); |
| |
| } |
| |
| @Test |
| public void multiple_expansions_on_one_line() |
| { |
| List<TemplateToken> tokens = tokens("multiple_expansions_on_one_line.tml"); |
| |
| assertEquals(tokens.size(), 10); |
| |
| ExpansionToken token3 = get(tokens, 3); |
| |
| assertEquals(token3.getExpression(), "classLoader"); |
| |
| TextToken token4 = get(tokens, 4); |
| |
| assertEquals(token4.getText(), " ["); |
| |
| ExpansionToken token5 = get(tokens, 5); |
| |
| assertEquals(token5.getExpression(), "classLoader.class.name"); |
| |
| TextToken token6 = get(tokens, 6); |
| |
| assertEquals(token6.getText(), "]"); |
| } |
| |
| @Test |
| public void expansions_not_allowed_in_cdata() |
| { |
| List<TemplateToken> tokens = tokens("expansions_not_allowed_in_cdata.tml"); |
| |
| assertEquals(tokens.size(), 5); |
| |
| CDATAToken t2 = get(tokens, 2); |
| |
| assertEquals(t2.getContent(), "${not-an-expansion}"); |
| } |
| |
| @Test |
| public void expansions_not_allowed_in_attributes() |
| { |
| List<TemplateToken> tokens = tokens("expansions_not_allowed_in_attributes.tml"); |
| |
| assertEquals(tokens.size(), 3); |
| |
| AttributeToken token1 = get(tokens, 1); |
| |
| assertEquals(token1.getName(), "exp"); |
| assertEquals(token1.getValue(), "${not-an-expansion}"); |
| } |
| |
| @Test |
| public void parameter_element() |
| { |
| List<TemplateToken> tokens = tokens("parameter_element.tml"); |
| |
| ParameterToken token4 = get(tokens, 4); |
| assertEquals(token4.getName(), "fred"); |
| |
| CommentToken token6 = get(tokens, 6); |
| assertEquals(token6.getComment(), "fred content"); |
| |
| TemplateToken token8 = get(tokens, 8); |
| |
| assertEquals(token8.getTokenType(), TokenType.END_ELEMENT); |
| } |
| |
| @Test |
| public void complex_component_type() |
| { |
| List<TemplateToken> tokens = tokens("complex_component_type.tml"); |
| |
| assertEquals(tokens.size(), 4); |
| |
| StartComponentToken token1 = get(tokens, 1); |
| |
| assertEquals(token1.getComponentType(), "subfolder/nifty"); |
| } |
| |
| @Test |
| public void block_element() |
| { |
| List<TemplateToken> tokens = tokens("block_element.tml"); |
| |
| BlockToken token1 = get(tokens, 1); |
| assertEquals(token1.getId(), "block0"); |
| |
| CommentToken token2 = get(tokens, 2); |
| assertEquals(token2.getComment(), "block0 content"); |
| |
| BlockToken token4 = get(tokens, 4); |
| assertNull(token4.getId()); |
| |
| CommentToken token5 = get(tokens, 5); |
| assertEquals(token5.getComment(), "anon block content"); |
| } |
| |
| @DataProvider(name = "parse_failure_data") |
| public Object[][] parse_failure_data() |
| { |
| return new Object[][] { |
| |
| { "mixin_requires_id_or_type.tml", |
| "You may not specify mixins for element <span> because it does not represent a component (which requires either an id attribute or a type attribute).", |
| 2 }, |
| |
| { "illegal_nesting_within_body_element.tml", "Element 'xyz' is nested within a Tapestry body element", |
| 2 }, |
| |
| { "unexpected_attribute_in_parameter_element.tml", |
| "Element <parameter> does not support an attribute named 'grok'. The only allowed attribute name is 'name'.", |
| 4 }, |
| |
| { "name_attribute_of_parameter_element_omitted.tml", |
| "The name attribute of the <parameter> element must be specified.", 4 }, |
| |
| { "name_attribute_of_parameter_element_blank.tml", |
| "The name attribute of the <parameter> element must be specified.", 4 }, |
| |
| { "unexpected_attribute_in_block_element.tml", |
| "Element <block> does not support an attribute named 'name'. The only allowed attribute name is 'id'.", |
| 3 }, |
| |
| }; |
| } |
| |
| @Test(dataProvider = "parse_failure_data") |
| public void parse_failure(String fileName, String errorMessageSubstring, int expectedLine) |
| { |
| try |
| { |
| parse(fileName); |
| unreachable(); |
| } |
| catch (TapestryException ex) |
| { |
| if (!ex.getMessage().contains(errorMessageSubstring)) |
| { |
| throw new AssertionError(format("Message [%s] does not contain substring [%s].", ex.getMessage(), |
| errorMessageSubstring)); |
| } |
| |
| assertEquals(ex.getLocation().getLine(), expectedLine); |
| } |
| } |
| |
| @DataProvider(name = "doctype_parsed_correctly_data") |
| public Object[][] doctype_parsed_correctly_data() |
| { |
| return new Object[][] { { "xhtml1_strict_doctype.tml" }, { "xhtml1_transitional_doctype.tml" }, |
| { "xhtml1_frameset_doctype.tml" } }; |
| } |
| |
| @Test(dataProvider = "doctype_parsed_correctly_data") |
| public void doctype_parsed_correctly(String fileName) throws Exception |
| { |
| List<TemplateToken> tokens = tokens(fileName); |
| assertEquals(tokens.size(), 12); |
| TextToken t = get(tokens, 9); |
| assertEquals(t.getText().trim(), "<Test>"); |
| } |
| |
| @DataProvider(name = "doctype_token_added_correctly_data") |
| public Object[][] doctype_token_added_correctly_data() |
| { |
| return new Object[][] { |
| |
| { "xhtml1_strict_doctype.tml", "html", "-//W3C//DTD XHTML 1.0 Strict//EN", |
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" }, |
| |
| { "xhtml1_transitional_doctype.tml", "html", "-//W3C//DTD XHTML 1.0 Transitional//EN", |
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" }, |
| |
| { "xhtml1_frameset_doctype.tml", "html", "-//W3C//DTD XHTML 1.0 Frameset//EN", |
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd" }, |
| |
| { "html4_strict_doctype.tml", "HTML", "-//W3C//DTD HTML 4.01//EN", |
| "http://www.w3.org/TR/html4/strict.dtd" }, |
| |
| { "html4_transitional_doctype.tml", "HTML", "-//W3C//DTD HTML 4.01 Transitional//EN", |
| "http://www.w3.org/TR/html4/loose.dtd" }, |
| |
| { "html4_frameset_doctype.tml", "HTML", "-//W3C//DTD HTML 4.01 Frameset//EN", |
| "http://www.w3.org/TR/html4/frameset.dtd" }, |
| |
| { "system_doctype.xml", "foo", null, |
| "src/test/resources/org/apache/tapestry5/internal/services/simple.dtd" } }; |
| } |
| |
| @Test(dataProvider = "doctype_token_added_correctly_data") |
| public void doctype_added_correctly(String fileName, String name, String publicId, String systemId) throws Exception |
| { |
| System.setProperty("user.dir", TapestryTestConstants.MODULE_BASE_DIR_PATH); |
| |
| List<TemplateToken> tokens = tokens(fileName); |
| DTDToken t2 = get(tokens, 0); |
| assertEquals(t2.getName(), name); |
| assertEquals(t2.getPublicId(), publicId); |
| assertEquals(t2.getSystemId(), systemId); |
| } |
| |
| @Test |
| public void invalid_component_id() throws Exception |
| { |
| try |
| { |
| parse("invalid_component_id.tml"); |
| unreachable(); |
| } |
| catch (RuntimeException ex) |
| { |
| assertMessageContains(ex, "Component id 'not-valid' is not valid"); |
| } |
| } |
| |
| @Test |
| public void invalid_block_id() throws Exception |
| { |
| try |
| { |
| parse("invalid_block_id.tml"); |
| unreachable(); |
| } |
| catch (RuntimeException ex) |
| { |
| assertMessageContains(ex, "Block id 'not-valid' is not valid"); |
| } |
| } |
| |
| /** |
| * Because of common code, this covers t:block and t:parameter. |
| */ |
| @Test |
| public void space_preserved_in_block() throws Exception |
| { |
| List<TemplateToken> tokens = tokens("space_preserved_in_block.tml"); |
| |
| TextToken token1 = get(tokens, 1); |
| |
| assertEquals(token1.getText(), "\n" + " line in the middle\n" + " "); |
| } |
| |
| /** |
| * t:container is a bit of a different code path than t:block/t:parameter |
| */ |
| @Test |
| public void space_preserved_in_container() throws Exception |
| { |
| List<TemplateToken> tokens = tokens("space_preserved_in_container.tml"); |
| |
| TextToken token0 = get(tokens, 0); |
| assertEquals(token0.getText(), "\n" + " "); |
| |
| TextToken token2 = get(tokens, 2); |
| assertEquals(token2.getText(), "\n" + " some text\n" + " "); |
| |
| } |
| |
| @Test |
| public void minimal_whitespace_maintained_inside_tags() throws Exception |
| { |
| List<TemplateToken> tokens = tokens("minimal_whitespace_maintained_inside_tags.tml"); |
| |
| // A line feed or carriage return surrounded by other whitespace is reduced to |
| // just a line feed. |
| |
| TextToken token1 = get(tokens, 1); |
| assertEquals(token1.getText(), "\nWhitespace\n"); |
| |
| |
| TextToken token5 = get(tokens, 5); |
| assertEquals(token5.getText(), "\nis maintained.\n"); |
| |
| } |
| } |