Repository: freemarker Updated Branches: refs/heads/3 e8e58ffa5 -> bde40b5e5
FREEMARKER-55 Adding checkbox directive. checked option completed Project: http://git-wip-us.apache.org/repos/asf/freemarker/repo Commit: http://git-wip-us.apache.org/repos/asf/freemarker/commit/bde40b5e Tree: http://git-wip-us.apache.org/repos/asf/freemarker/tree/bde40b5e Diff: http://git-wip-us.apache.org/repos/asf/freemarker/diff/bde40b5e Branch: refs/heads/3 Commit: bde40b5e55a171b75254607b38f0acd7ece93f39 Parents: e8e58ff Author: Woonsan Ko <woon...@apache.org> Authored: Sun Jun 24 23:42:27 2018 -0400 Committer: Woonsan Ko <woon...@apache.org> Committed: Sun Jun 24 23:42:27 2018 -0400 ---------------------------------------------------------------------- ...actCheckedElementTemplateDirectiveModel.java | 71 ++++++++ .../AbstractFormTemplateDirectiveModel.java | 6 + ...gleCheckedElementTemplateDirectiveModel.java | 77 +++++++++ .../form/CheckboxTemplateDirectiveModel.java | 161 +++++++++++++++++++ .../SpringFormTemplateCallableHashModel.java | 1 + .../spring/example/mvc/users/User.java | 26 ++- .../example/mvc/users/UserRepository.java | 20 +++ .../CheckboxTemplateDirectiveModelTest.java | 111 +++++++++++++ .../model/form/checkbox-directive-usages.f3ah | 50 ++++++ 9 files changed, 522 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/freemarker/blob/bde40b5e/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractCheckedElementTemplateDirectiveModel.java ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractCheckedElementTemplateDirectiveModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractCheckedElementTemplateDirectiveModel.java new file mode 100644 index 0000000..f6f27f3 --- /dev/null +++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractCheckedElementTemplateDirectiveModel.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.freemarker.spring.model.form; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.freemarker.core.Environment; +import org.apache.freemarker.core.TemplateException; + +/** + * Corresponds to <code>org.springframework.web.servlet.tags.form.AbstractCheckedElementTag</code>. + */ +abstract class AbstractCheckedElementTemplateDirectiveModel extends AbstractHtmlInputElementTemplateDirectiveModel { + + protected AbstractCheckedElementTemplateDirectiveModel(HttpServletRequest request, HttpServletResponse response) { + super(request, response); + } + + /** + * Return "checkbox" or "radio". + */ + protected abstract String getInputType(); + + protected void renderFromValue(Environment env, Object value, TagOutputter tagOut) + throws TemplateException, IOException { + renderFromValue(env, value, value, tagOut); + } + + protected void renderFromValue(Environment env, Object item, Object value, TagOutputter tagOut) + throws TemplateException, IOException { + String displayValue = getDisplayString(value, getBindStatus()); + tagOut.writeAttribute("value", processFieldValue(env, getName(), displayValue, getInputType())); + + if (isOptionSelected(value) || (value != item && isOptionSelected(item))) { + tagOut.writeAttribute("checked", "checked"); + } + } + + protected void renderFromBoolean(Environment env, Boolean boundValue, TagOutputter tagOut) + throws TemplateException, IOException { + tagOut.writeAttribute("value", processFieldValue(env, getName(), "true", getInputType())); + + if (boundValue != null && boundValue.booleanValue()) { + tagOut.writeAttribute("checked", "checked"); + } + } + + private boolean isOptionSelected(Object value) throws TemplateException { + return SelectableValueComparisonUtils.isEqualValueBoundTo(value, getBindStatus()); + } +} http://git-wip-us.apache.org/repos/asf/freemarker/blob/bde40b5e/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractFormTemplateDirectiveModel.java ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractFormTemplateDirectiveModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractFormTemplateDirectiveModel.java index 83f078e..fa0152e 100644 --- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractFormTemplateDirectiveModel.java +++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractFormTemplateDirectiveModel.java @@ -29,6 +29,7 @@ import org.apache.freemarker.core.CustomStateKey; import org.apache.freemarker.core.TemplateException; import org.apache.freemarker.spring.model.AbstractSpringTemplateDirectiveModel; import org.springframework.util.ObjectUtils; +import org.springframework.web.servlet.support.BindStatus; /** * Corresponds to <code>org.springframework.web.servlet.tags.form.AbstractFormTag</code>. @@ -55,6 +56,11 @@ abstract class AbstractFormTemplateDirectiveModel extends AbstractSpringTemplate return displayValue; } + public static String getDisplayString(Object value, BindStatus bindStatus) { + final PropertyEditor editor = (bindStatus != null && value != null) ? bindStatus.findEditor(value.getClass()) : null; + return getDisplayString(value, editor); + } + public static String getDisplayString(Object value, PropertyEditor propertyEditor) { if (propertyEditor != null && !(value instanceof String)) { try { http://git-wip-us.apache.org/repos/asf/freemarker/blob/bde40b5e/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractSingleCheckedElementTemplateDirectiveModel.java ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractSingleCheckedElementTemplateDirectiveModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractSingleCheckedElementTemplateDirectiveModel.java new file mode 100644 index 0000000..48b9498 --- /dev/null +++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractSingleCheckedElementTemplateDirectiveModel.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.freemarker.spring.model.form; + +import java.io.IOException; +import java.io.Writer; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.freemarker.core.CallPlace; +import org.apache.freemarker.core.Environment; +import org.apache.freemarker.core.TemplateException; +import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper; +import org.apache.freemarker.core.model.TemplateModel; +import org.springframework.web.servlet.support.RequestContext; + +/** + * Corresponds to <code>org.springframework.web.servlet.tags.form.AbstractSingleCheckedElementTag</code>. + */ +abstract class AbstractSingleCheckedElementTemplateDirectiveModel extends AbstractCheckedElementTemplateDirectiveModel { + + protected AbstractSingleCheckedElementTemplateDirectiveModel(HttpServletRequest request, + HttpServletResponse response) { + super(request, response); + } + + @Override + protected void executeInternal(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env, + ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, RequestContext requestContext) + throws TemplateException, IOException { + super.executeInternal(args, callPlace, out, env, objectWrapperAndUnwrapper, requestContext); + + TagOutputter tagOut = new TagOutputter(out); + + tagOut.beginTag("input"); + String id = resolveId(); + writeOptionalAttribute(tagOut, "id", id); + writeOptionalAttribute(tagOut, "name", getName()); + writeOptionalAttributes(tagOut); + writeAdditionalDetails(env, tagOut); + tagOut.endTag(); + + Object resolvedLabel = evaluate("label", getLabel()); + + if (resolvedLabel != null) { + tagOut.beginTag("label"); + tagOut.writeAttribute("for", id); + tagOut.appendValue(getDisplayString(resolvedLabel, getBindStatus())); + tagOut.endTag(); + } + } + + public abstract Object getValue(); + + public abstract Object getLabel(); + + protected abstract void writeAdditionalDetails(Environment env, TagOutputter tagOut) throws TemplateException, IOException; + +} http://git-wip-us.apache.org/repos/asf/freemarker/blob/bde40b5e/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/CheckboxTemplateDirectiveModel.java ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/CheckboxTemplateDirectiveModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/CheckboxTemplateDirectiveModel.java new file mode 100644 index 0000000..95da416 --- /dev/null +++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/CheckboxTemplateDirectiveModel.java @@ -0,0 +1,161 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.freemarker.spring.model.form; + +import java.io.IOException; +import java.io.Writer; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.freemarker.core.CallPlace; +import org.apache.freemarker.core.Environment; +import org.apache.freemarker.core.TemplateException; +import org.apache.freemarker.core.model.ArgumentArrayLayout; +import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper; +import org.apache.freemarker.core.model.TemplateModel; +import org.apache.freemarker.core.util.CallableUtils; +import org.apache.freemarker.core.util.StringToIndexMap; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.servlet.support.RequestContext; + +/** + * Provides <code>TemplateModel</code> for data-binding-aware HTML '{@code <input type="checkbox"/>}' element. + * This tag is provided for completeness if the application relies on a + * <code>org.springframework.web.servlet.support.RequestDataValueProcessor</code>. + * <P> + * This directive supports the following parameters: + * <UL> + * <LI> + * ... TODO ... + * </LI> + * </UL> + * </P> + * <P> + * Some valid example(s): + * </P> + * <PRE> + * <@form.checkbox 'user.receiveNewsletter' /> + * </PRE> + * <P> + * <EM>Note:</EM> Unlike Spring Framework's <code><form:button /></code> JSP Tag Library, this directive + * does not support <code>htmlEscape</code> parameter. It always renders HTML's without escaping + * because it is much easier to control escaping in FreeMarker Template expressions. + * </P> + */ + +class CheckboxTemplateDirectiveModel extends AbstractSingleCheckedElementTemplateDirectiveModel { + + public static final String NAME = "checkbox"; + + private static final int NAMED_ARGS_OFFSET = AbstractHtmlInputElementTemplateDirectiveModel.ARGS_LAYOUT + .getPredefinedNamedArgumentsEndIndex(); + + private static final int VALUE_PARAM_IDX = NAMED_ARGS_OFFSET; + private static final String VALUE_PARAM_NAME = "value"; + + private static final int LABEL_PARAM_IDX = NAMED_ARGS_OFFSET + 1; + private static final String LABEL_PARAM_NAME = "label"; + + protected static final ArgumentArrayLayout ARGS_LAYOUT = ArgumentArrayLayout.create(1, false, + StringToIndexMap.of(AbstractHtmlInputElementTemplateDirectiveModel.ARGS_LAYOUT.getPredefinedNamedArgumentsMap(), + new StringToIndexMap.Entry(VALUE_PARAM_NAME, VALUE_PARAM_IDX), + new StringToIndexMap.Entry(LABEL_PARAM_NAME, LABEL_PARAM_IDX)), + true); + + private String value; + private String label; + + protected CheckboxTemplateDirectiveModel(HttpServletRequest request, HttpServletResponse response) { + super(request, response); + } + + @Override + public ArgumentArrayLayout getDirectiveArgumentArrayLayout() { + return ARGS_LAYOUT; + } + + @Override + public boolean isNestedContentSupported() { + return false; + } + + @Override + protected void executeInternal(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env, + ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, RequestContext requestContext) + throws TemplateException, IOException { + value = CallableUtils.getOptionalStringArgument(args, VALUE_PARAM_IDX, this); + label = CallableUtils.getOptionalStringArgument(args, LABEL_PARAM_IDX, this); + + super.executeInternal(args, callPlace, out, env, objectWrapperAndUnwrapper, requestContext); + } + + @Override + public String getValue() { + return value; + } + + @Override + public String getLabel() { + return label; + } + + @Override + protected void writeAdditionalDetails(Environment env, TagOutputter tagOut) throws TemplateException, IOException { + tagOut.writeAttribute("type", getInputType()); + + Object boundValue = getBindStatus().getValue(); + Class<?> valueType = getBindStatus().getValueType(); + + if (Boolean.class == valueType || boolean.class == valueType) { + if (boundValue instanceof String) { + boundValue = Boolean.valueOf((String) boundValue); + } + + final Boolean booleanValue = (boundValue != null) ? (Boolean) boundValue : Boolean.FALSE; + renderFromBoolean(env, booleanValue, tagOut); + } else { + Object value = getValue(); + + if (value == null) { + throw new IllegalArgumentException("value attribute is missing. It's required to bind to a non-boolean value(s)."); + } + + Object resolvedValue = (value instanceof String ? evaluate("value", value) : value); + renderFromValue(env, resolvedValue, tagOut); + } + + if (!isDisabled()) { + // Spring Web MVC requires to render a hidden input as a 'field was present' marker. + tagOut.beginTag("input"); + tagOut.writeAttribute("type", "hidden"); + String name = WebDataBinder.DEFAULT_FIELD_MARKER_PREFIX + getName(); + tagOut.writeAttribute("name", name); + tagOut.writeAttribute("value", processFieldValue(env, name, "on", getInputType())); + tagOut.endTag(); + } + } + + @Override + protected String getInputType() { + return "checkbox"; + } + +} http://git-wip-us.apache.org/repos/asf/freemarker/blob/bde40b5e/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/SpringFormTemplateCallableHashModel.java ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/SpringFormTemplateCallableHashModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/SpringFormTemplateCallableHashModel.java index b460c4c..aaab1f1 100644 --- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/SpringFormTemplateCallableHashModel.java +++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/SpringFormTemplateCallableHashModel.java @@ -56,6 +56,7 @@ public final class SpringFormTemplateCallableHashModel implements TemplateHashMo modelsMap.put(OptionsTemplateDirectiveModel.NAME, new OptionsTemplateDirectiveModel(request, response)); modelsMap.put(OptionTemplateDirectiveModel.NAME, new OptionTemplateDirectiveModel(request, response)); modelsMap.put(ErrorsTemplateDirectiveModel.NAME, new ErrorsTemplateDirectiveModel(request, response)); + modelsMap.put(CheckboxTemplateDirectiveModel.NAME, new CheckboxTemplateDirectiveModel(request, response)); } @Override http://git-wip-us.apache.org/repos/asf/freemarker/blob/bde40b5e/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/User.java ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/User.java b/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/User.java index 028f920..56330e6 100644 --- a/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/User.java +++ b/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/User.java @@ -31,6 +31,8 @@ public class User { private Date birthDate; private String description; private String favoriteSport; + private boolean receiveNewsletter; + private String[] favoriteFood; public User() { } @@ -99,10 +101,32 @@ public class User { this.favoriteSport = favoriteSport; } + public boolean isReceiveNewsletter() { + return receiveNewsletter; + } + + public void setReceiveNewsletter(boolean receiveNewsletter) { + this.receiveNewsletter = receiveNewsletter; + } + + public String[] getFavoriteFood() { + if (favoriteFood == null) { + return null; + } + + String[] cloned = new String[favoriteFood.length]; + System.arraycopy(favoriteFood, 0, cloned, 0, favoriteFood.length); + return cloned; + } + + public void setFavoriteFood(String[] favoriteFood) { + this.favoriteFood = favoriteFood; + } + @Override public String toString() { return super.toString() + " {id=" + id + ", firstName='" + firstName + "', lastName='" + lastName + "', email='" + email + "', birthDate='" + birthDate + "', description='" + description + "', favoriteSport='" - + favoriteSport + "'}"; + + favoriteSport + "', receiveNewsletter=" + receiveNewsletter + ", favoriteFood=" + favoriteFood + "}"; } } http://git-wip-us.apache.org/repos/asf/freemarker/blob/bde40b5e/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserRepository.java ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserRepository.java b/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserRepository.java index e2a2283..57af289 100644 --- a/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserRepository.java +++ b/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserRepository.java @@ -58,6 +58,8 @@ public class UserRepository { user.setDescription("Lorem ipsum dolor sit amet, \r\nconsectetur adipiscing elit, \r\n" + "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."); user.setFavoriteSport("baseball"); + user.setReceiveNewsletter(false); + user.setFavoriteFood(new String[] { "Sandwich", "Spaghetti" }); usersMap.put(id, user); id = 102L; @@ -74,6 +76,8 @@ public class UserRepository { user.setDescription("Ut enim ad minim veniam, \r\n" + "quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."); user.setFavoriteSport("marathon"); + user.setReceiveNewsletter(true); + user.setFavoriteFood(new String[] { "Sandwich", "Sushi" }); usersMap.put(id, user); } @@ -95,6 +99,20 @@ public class UserRepository { return null; } + public synchronized User getUserByEmail(final String email) { + if (email == null) { + throw new IllegalArgumentException("E-Mail must be non-null."); + } + + for (User user : usersMap.values()) { + if (email.equals(user.getEmail())) { + return cloneUser(user, user.getId()); + } + } + + return null; + } + public synchronized User addOrUpdateUser(final User user) { final Long id = user.getId(); User newUser = cloneUser(user, id); @@ -120,6 +138,8 @@ public class UserRepository { clone.setBirthDate(source.getBirthDate()); clone.setDescription(source.getDescription()); clone.setFavoriteSport(source.getFavoriteSport()); + clone.setReceiveNewsletter(source.isReceiveNewsletter()); + clone.setFavoriteFood(source.getFavoriteFood()); return clone; } } http://git-wip-us.apache.org/repos/asf/freemarker/blob/bde40b5e/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/CheckboxTemplateDirectiveModelTest.java ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/CheckboxTemplateDirectiveModelTest.java b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/CheckboxTemplateDirectiveModelTest.java new file mode 100644 index 0000000..5d74d8c --- /dev/null +++ b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/CheckboxTemplateDirectiveModelTest.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.freemarker.spring.model.form; + +import org.apache.freemarker.spring.example.mvc.users.User; +import org.apache.freemarker.spring.example.mvc.users.UserRepository; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.xpath; + +@RunWith(SpringJUnit4ClassRunner.class) +@WebAppConfiguration("classpath:META-INF/web-resources") +@ContextConfiguration(locations = { "classpath:org/apache/freemarker/spring/example/mvc/users/users-mvc-context.xml" }) +public class CheckboxTemplateDirectiveModelTest { + + @Autowired + private WebApplicationContext wac; + + @Autowired + private UserRepository userRepository; + + private MockMvc mockMvc; + + @Before + public void setUp() { + mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); + } + + @Test + public void testSingleCheckboxWithNotChecked() throws Exception { + final User user = userRepository.getUserByEmail("j...@example.com"); + mockMvc.perform(get("/users/{userId}/", user.getId()).param("viewName", "test/model/form/checkbox-directive-usages") + .accept(MediaType.parseMediaType("text/html"))).andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith("text/html")).andDo(print()) + .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='receiveNewsletter' and @name='receiveNewsletter']/@value").string("true")) + .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='receiveNewsletter' and @name='receiveNewsletter']/@checked").doesNotExist()) + .andExpect(xpath("//form[@id='form1']//input[@type='hidden' and @name='_receiveNewsletter']/@value").string("on")); + } + + @Test + public void testSingleCheckboxWithChecked() throws Exception { + final User user = userRepository.getUserByEmail("j...@example.com"); + mockMvc.perform(get("/users/{userId}/", user.getId()).param("viewName", "test/model/form/checkbox-directive-usages") + .accept(MediaType.parseMediaType("text/html"))).andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith("text/html")).andDo(print()) + .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='receiveNewsletter' and @name='receiveNewsletter']/@value").string("true")) + .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='receiveNewsletter' and @name='receiveNewsletter']/@checked").string("checked")) + .andExpect(xpath("//form[@id='form1']//input[@type='hidden' and @name='_receiveNewsletter']/@value").string("on")); + } + + @Test + public void testMultipleCheckboxes101() throws Exception { + final User user = userRepository.getUserByEmail("j...@example.com"); + mockMvc.perform(get("/users/{userId}/", user.getId()).param("viewName", "test/model/form/checkbox-directive-usages") + .accept(MediaType.parseMediaType("text/html"))).andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith("text/html")).andDo(print()) + .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Sandwich']").exists()) + .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Spaghetti']").exists()) + .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Sushi']").exists()) + .andExpect(xpath("//form[@id='form1']//input[@type='hidden' and @name='_favoriteFood' and @value='on']").exists()) + .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Sandwich']/@checked").string("checked")) + .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Spaghetti']/@checked").string("checked")) + .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Sushi']/@checked").doesNotExist()); + } + + @Test + public void testMultipleCheckboxes102() throws Exception { + final User user = userRepository.getUserByEmail("j...@example.com"); + mockMvc.perform(get("/users/{userId}/", user.getId()).param("viewName", "test/model/form/checkbox-directive-usages") + .accept(MediaType.parseMediaType("text/html"))).andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith("text/html")).andDo(print()) + .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Sandwich']").exists()) + .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Spaghetti']").exists()) + .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Sushi']").exists()) + .andExpect(xpath("//form[@id='form1']//input[@type='hidden' and @name='_favoriteFood' and @value='on']").exists()) + .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Sandwich']/@checked").string("checked")) + .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Spaghetti']/@checked").doesNotExist()) + .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Sushi']/@checked").string("checked")); + } +} http://git-wip-us.apache.org/repos/asf/freemarker/blob/bde40b5e/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/checkbox-directive-usages.f3ah ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/checkbox-directive-usages.f3ah b/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/checkbox-directive-usages.f3ah new file mode 100644 index 0000000..e1d395a --- /dev/null +++ b/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/checkbox-directive-usages.f3ah @@ -0,0 +1,50 @@ +<#-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. +--> +<html> +<body> + + <h1>Form 1</h1> + <hr/> + <form id="form1"> + <table> + <tr> + <th>User:</th> + <td> + ${user.firstName} ${user.lastName} (${user.email}) + </td> + </tr> + <tr> + <th>Receive Newsletter?</th> + <td> + <@form.checkbox "user.receiveNewsletter" /> + </td> + </tr> + <tr> + <th>Favorite Food</th> + <td> + <@form.checkbox "user.favoriteFood" value="Sandwich" />Sandwich + <@form.checkbox "user.favoriteFood" value="Spaghetti" />Spaghetti + <@form.checkbox "user.favoriteFood" value="Sushi" />Sushi + </td> + </tr> + </table> + </form> + +</body> +</html>