Skip to content

Commit 4a4c631

Browse files
semblerScott.Embler
and
Scott.Embler
authored
Minor restructuring of Tag internals, increased argument validation, and tests to clarify current behavior. (#175)
Co-authored-by: Scott.Embler <[email protected]>
1 parent be626b6 commit 4a4c631

File tree

4 files changed

+130
-79
lines changed

4 files changed

+130
-79
lines changed

library/src/main/java/j2html/tags/ContainerTag.java

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package j2html.tags;
22

33
import j2html.Config;
4+
import j2html.attributes.Attribute;
5+
46
import java.io.IOException;
57
import java.util.ArrayList;
68
import java.util.List;
79
import java.util.stream.Stream;
810

911
public class ContainerTag<T extends ContainerTag<T>> extends Tag<T> {
10-
//public class ContainerTag extends Tag<ContainerTag> {
1112

1213
private List<DomContent> children;
1314

@@ -209,6 +210,26 @@ private boolean isSelfFormattingTag() {
209210
return "textarea".equals(tagName) || "pre".equals(tagName);
210211
}
211212

213+
protected void renderOpenTag(Appendable writer, Object model) throws IOException {
214+
if (!hasTagName()) { // avoid <null> and <> tags
215+
return;
216+
}
217+
writer.append("<").append(tagName);
218+
for (Attribute attribute : getAttributes()) {
219+
attribute.renderModel(writer, model);
220+
}
221+
writer.append(">");
222+
}
223+
224+
protected void renderCloseTag(Appendable writer) throws IOException {
225+
if (!hasTagName()) { // avoid <null> and <> tags
226+
return;
227+
}
228+
writer.append("</");
229+
writer.append(tagName);
230+
writer.append(">");
231+
}
232+
212233
@Override
213234
public void renderModel(Appendable writer, Object model) throws IOException {
214235
renderOpenTag(writer, model);
@@ -219,12 +240,4 @@ public void renderModel(Appendable writer, Object model) throws IOException {
219240
}
220241
renderCloseTag(writer);
221242
}
222-
223-
@FunctionalInterface
224-
private interface ThrowingBiFunction<T, U, R, E extends Exception> {
225-
226-
R apply(final T t, final U u) throws E;
227-
228-
}
229-
230243
}

library/src/main/java/j2html/tags/EmptyTag.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,15 @@
55
import java.io.IOException;
66

77
public class EmptyTag<T extends EmptyTag<T>> extends Tag<T> {
8-
//public class EmptyTag extends Tag<EmptyTag> {
98

109
public EmptyTag(String tagName) {
1110
super(tagName);
11+
if(tagName == null){
12+
throw new IllegalArgumentException("Illegal tag name: null");
13+
}
14+
if("".equals(tagName)){
15+
throw new IllegalArgumentException("Illegal tag name: \"\"");
16+
}
1217
}
1318

1419
@Override

library/src/main/java/j2html/tags/Tag.java

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -23,38 +23,6 @@ protected boolean hasTagName() {
2323
return tagName != null && !tagName.isEmpty();
2424
}
2525

26-
String renderOpenTag() throws IOException {
27-
StringBuilder stringBuilder = new StringBuilder();
28-
renderOpenTag(stringBuilder, null);
29-
return stringBuilder.toString();
30-
}
31-
32-
String renderCloseTag() throws IOException {
33-
StringBuilder stringBuilder = new StringBuilder();
34-
renderCloseTag(stringBuilder);
35-
return stringBuilder.toString();
36-
}
37-
38-
protected void renderOpenTag(Appendable writer, Object model) throws IOException {
39-
if (!hasTagName()) { // avoid <null> and <> tags
40-
return;
41-
}
42-
writer.append("<").append(tagName);
43-
for (Attribute attribute : attributes) {
44-
attribute.renderModel(writer, model);
45-
}
46-
writer.append(">");
47-
}
48-
49-
protected void renderCloseTag(Appendable writer) throws IOException {
50-
if (!hasTagName()) { // avoid <null> and <> tags
51-
return;
52-
}
53-
writer.append("</");
54-
writer.append(tagName);
55-
writer.append(">");
56-
}
57-
5826
protected ArrayList<Attribute> getAttributes() {
5927
return attributes;
6028
}

library/src/test/java/j2html/tags/TagTest.java

Lines changed: 102 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,117 @@
11
package j2html.tags;
22

33
import j2html.Config;
4+
import j2html.attributes.Attribute;
45
import j2html.model.DynamicHrefAttribute;
56
import java.io.File;
67
import java.io.FileWriter;
78

89
import j2html.tags.specialized.manual.HtmlTag;
10+
import org.junit.After;
11+
import org.junit.Before;
912
import org.junit.Test;
1013
import static j2html.TagCreator.body;
1114
import static j2html.TagCreator.div;
1215
import static j2html.TagCreator.footer;
1316
import static j2html.TagCreator.header;
1417
import static j2html.TagCreator.html;
1518
import static j2html.TagCreator.iff;
16-
import static j2html.TagCreator.img;
17-
import static j2html.TagCreator.input;
1819
import static j2html.TagCreator.main;
1920
import static j2html.TagCreator.p;
2021
import static j2html.TagCreator.tag;
2122
import static org.hamcrest.MatcherAssert.assertThat;
2223
import static org.hamcrest.Matchers.is;
24+
import static org.junit.Assert.fail;
2325

2426
public class TagTest {
2527

28+
@Before
29+
public void setUp(){
30+
Config.closeEmptyTags = false;
31+
}
32+
33+
@After
34+
public void tearDown(){
35+
// Restore Config defaults.
36+
Config.closeEmptyTags = false;
37+
}
38+
39+
// TODO Introduce a different concept for a sequence of tags, and require valid names for all Tags.
40+
41+
@Test
42+
public void unnamed_containers_do_not_render_tags_or_attributes(){
43+
Tag tag = new ContainerTag(null).attr("xyz", "123");
44+
assertThat(tag.render(), is(""));
45+
}
46+
47+
@Test
48+
public void unnamed_containers_render_children(){
49+
ContainerTag tag = new ContainerTag(null)
50+
.with(new EmptyTag("abc"))
51+
.with(new ContainerTag("def"))
52+
.withText("ghi");
53+
assertThat(tag.render(), is("<abc><def></def>ghi"));
54+
}
55+
56+
@Test
57+
public void named_containers_without_children_only_render_tags_and_attributes(){
58+
Tag tag = new ContainerTag("abc").attr("xyz", "123");
59+
assertThat(tag.render(), is("<abc xyz=\"123\"></abc>"));
60+
}
61+
62+
@Test
63+
public void populated_named_containers_render_tags_attributes_and_children(){
64+
Tag tag = new ContainerTag("abc")
65+
.with(new EmptyTag("def"))
66+
.with(new ContainerTag("ghi"))
67+
.withText("jkl")
68+
.attr("xyz", "123");
69+
assertThat(tag.render(), is("<abc xyz=\"123\"><def><ghi></ghi>jkl</abc>"));
70+
}
71+
72+
@Test
73+
public void empty_tags_must_be_named(){
74+
try{
75+
new EmptyTag(null);
76+
fail("Exception was not thrown.");
77+
}catch (IllegalArgumentException e){
78+
assertThat(e.getMessage(), is("Illegal tag name: null"));
79+
}
80+
81+
try{
82+
new EmptyTag("");
83+
fail("Exception was not thrown.");
84+
}catch (IllegalArgumentException e){
85+
assertThat(e.getMessage(), is("Illegal tag name: \"\""));
86+
}
87+
}
88+
2689
@Test
27-
public void testRender() throws Exception {
90+
public void empty_tags_can_be_configured_to_self_close(){
91+
// By default they will not be self-closing.
92+
assertThat(new EmptyTag("xyz").render(), is("<xyz>"));
93+
94+
Config.closeEmptyTags = true;
95+
assertThat(new EmptyTag("xyz").render(), is("<xyz/>"));
96+
}
97+
98+
@Test
99+
public void attributes_are_rendered_in_the_order_that_they_are_defined(){
100+
Tag container = new ContainerTag("abc")
101+
.attr("a","A")
102+
.attr(new Attribute("b","B"))
103+
.attr("c");
104+
assertThat(container.render(), is("<abc a=\"A\" b=\"B\" c></abc>"));
105+
106+
Tag tag = new EmptyTag("abc")
107+
.attr("c")
108+
.attr(new Attribute("b","B"))
109+
.attr("a","A");
110+
assertThat(tag.render(), is("<abc c b=\"B\" a=\"A\">"));
111+
}
112+
113+
@Test
114+
public void testRender() {
28115
ContainerTag testTag = new ContainerTag("a");
29116
testTag.setAttribute("href", "http://example.com");
30117
assertThat(testTag.render(), is("<a href=\"http://example.com\"></a>"));
@@ -40,33 +127,6 @@ public void testRender() throws Exception {
40127
assertThat(complexTestTag.render(), is((expectedResult)));
41128
}
42129

43-
@Test
44-
public void testOpenTag() throws Exception {
45-
ContainerTag testTag = new ContainerTag("a");
46-
assertThat(testTag.renderOpenTag(), is("<a>"));
47-
48-
ContainerTag complexTestTag = new ContainerTag("input");
49-
complexTestTag.attr("type","password").withId("password")
50-
.attr("name","password")
51-
.attr("placeholder","Password").attr("required");
52-
String expectedResult = "<input type=\"password\" id=\"password\" name=\"password\" placeholder=\"Password\" required>";
53-
assertThat(complexTestTag.renderOpenTag(), is(expectedResult));
54-
}
55-
56-
@Test
57-
public void testCloseTag() throws Exception {
58-
ContainerTag testTag = new ContainerTag("a");
59-
assertThat(testTag.renderCloseTag(), is("</a>"));
60-
}
61-
62-
@Test
63-
public void testSelfClosingTags() throws Exception {
64-
Config.closeEmptyTags = true;
65-
assertThat(img().withSrc("/test.png").render(), is("<img src=\"/test.png\"/>"));
66-
assertThat(input().attr("type","text").render(), is("<input type=\"text\"/>"));
67-
Config.closeEmptyTags = false;
68-
}
69-
70130
@Test
71131
public void testFormattedTags() throws Exception { // better test in ComplexRenderTest.java
72132
assertThat(div(p("Hello")).renderFormatted(), is("<div>\n <p>\n Hello\n </p>\n</div>\n"));
@@ -80,13 +140,18 @@ public void testEquals() throws Exception {
80140
}
81141

82142
@Test
83-
public void testAcceptObjectValueAttribute() throws Exception {
84-
Tag complexTestTag = new ContainerTag("input")
85-
.attr("attr1", "value1")
86-
.attr("attr2", 2)
87-
.attr("attr3", null);
88-
String expectedResult = "<input attr1=\"value1\" attr2=\"2\" attr3>";
89-
assertThat(complexTestTag.renderOpenTag(), is(expectedResult));
143+
public void attribute_values_are_converted_to_strings() throws Exception {
144+
Tag container = new ContainerTag("abc")
145+
.attr("string", "value1")
146+
.attr("integer", 2)
147+
.attr("none", null);
148+
assertThat(container.render(), is("<abc string=\"value1\" integer=\"2\" none></abc>"));
149+
150+
Tag tag = new EmptyTag("abc")
151+
.attr("string", "value1")
152+
.attr("integer", 2)
153+
.attr("none", null);
154+
assertThat(tag.render(), is("<abc string=\"value1\" integer=\"2\" none>"));
90155
}
91156

92157
@Test

0 commit comments

Comments
 (0)