Repository: freemarker
Updated Branches:
  refs/heads/3 2d799d492 -> 034b056c8


FREEMARKER-55: Handling selected for select/options/option directives


Project: http://git-wip-us.apache.org/repos/asf/freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/freemarker/commit/034b056c
Tree: http://git-wip-us.apache.org/repos/asf/freemarker/tree/034b056c
Diff: http://git-wip-us.apache.org/repos/asf/freemarker/diff/034b056c

Branch: refs/heads/3
Commit: 034b056c8b12caa4f80fe6ff8d61cb23b3f8951b
Parents: 2d799d4
Author: Woonsan Ko <[email protected]>
Authored: Fri Apr 27 16:25:06 2018 -0400
Committer: Woonsan Ko <[email protected]>
Committed: Fri Apr 27 16:25:06 2018 -0400

----------------------------------------------------------------------
 .../spring/model/form/OptionOutputHelper.java   |  9 +-
 .../form/OptionTemplateDirectiveModel.java      |  4 -
 .../form/SelectableValueComparisonUtils.java    |  3 +
 .../spring/example/mvc/users/User.java          |  3 +-
 .../example/mvc/users/UserController.java       | 16 +---
 .../example/mvc/users/UserRepository.java       | 15 ++++
 .../spring/model/ElementAttributeMatcher.java   | 86 ++++++++++++++++++++
 .../model/MissingElementAttributeMatcher.java   | 31 +++++++
 .../form/SelectTemplateDirectiveModelTest.java  | 81 ++++++++++++++----
 .../model/form/select-directive-usages.f3ah     | 17 +++-
 10 files changed, 228 insertions(+), 37 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/freemarker/blob/034b056c/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/OptionOutputHelper.java
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/OptionOutputHelper.java
 
b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/OptionOutputHelper.java
index f8a5537..d06b1bf 100644
--- 
a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/OptionOutputHelper.java
+++ 
b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/OptionOutputHelper.java
@@ -31,6 +31,9 @@ import org.springframework.util.CollectionUtils;
 import org.springframework.util.ObjectUtils;
 import org.springframework.web.servlet.support.BindStatus;
 
+/**
+ * Helper to write &lt;option&gt; HTML element.
+ */
 class OptionOutputHelper {
 
     private Object optionItems;
@@ -113,15 +116,16 @@ class OptionOutputHelper {
 
         valueDisplayString = processOptionValue(valueDisplayString);
 
-        // allows render values to handle some strange browser compat issues.
         tagOut.writeAttribute("value", valueDisplayString);
 
         if (isOptionSelected(value) || (value != item && 
isOptionSelected(item))) {
             tagOut.writeAttribute("selected", "selected");
         }
+
         if (isOptionDisabled()) {
             tagOut.writeAttribute("disabled", "disabled");
         }
+
         tagOut.appendValue(labelDisplayString);
         tagOut.endTag();
     }
@@ -146,8 +150,7 @@ class OptionOutputHelper {
     }
 
     private boolean isOptionSelected(Object resolvedValue) throws 
TemplateException {
-        // FIXME: need to compare selected value based on bindStatus values.
-        return false;
+        return 
SelectableValueComparisonUtils.isEqualValueBoundTo(resolvedValue, bindStatus);
     }
 
     protected boolean isOptionDisabled() throws TemplateException {

http://git-wip-us.apache.org/repos/asf/freemarker/blob/034b056c/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/OptionTemplateDirectiveModel.java
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/OptionTemplateDirectiveModel.java
 
b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/OptionTemplateDirectiveModel.java
index 7ad31ad..b6f8c76 100644
--- 
a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/OptionTemplateDirectiveModel.java
+++ 
b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/OptionTemplateDirectiveModel.java
@@ -131,10 +131,6 @@ class OptionTemplateDirectiveModel extends 
AbstractHtmlInputElementTemplateDirec
             tagOut.writeAttribute("selected", "selected");
         }
 
-        if (isDisabled()) {
-            tagOut.writeAttribute("disabled", "disabled");
-        }
-
         tagOut.appendValue(label);
         tagOut.endTag();
     }

http://git-wip-us.apache.org/repos/asf/freemarker/blob/034b056c/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/SelectableValueComparisonUtils.java
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/SelectableValueComparisonUtils.java
 
b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/SelectableValueComparisonUtils.java
index e17ab05..842d5fc 100644
--- 
a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/SelectableValueComparisonUtils.java
+++ 
b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/SelectableValueComparisonUtils.java
@@ -28,6 +28,9 @@ import org.springframework.util.CollectionUtils;
 import org.springframework.util.ObjectUtils;
 import org.springframework.web.servlet.support.BindStatus;
 
+/**
+ * Utility to check if a value (mostly from an option item) equals to the 
value bound to.
+ */
 class SelectableValueComparisonUtils {
 
     private SelectableValueComparisonUtils() {

http://git-wip-us.apache.org/repos/asf/freemarker/blob/034b056c/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 c271b0e..028f920 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
@@ -102,6 +102,7 @@ public class User {
     @Override
     public String toString() {
         return super.toString() + " {id=" + id + ", firstName='" + firstName + 
"', lastName='" + lastName + "', email='"
-                + email + "', birthDate='" + birthDate + "', description='" + 
description + "'}";
+                + email + "', birthDate='" + birthDate + "', description='" + 
description + "', favoriteSport='"
+                + favoriteSport + "'}";
     }
 }

http://git-wip-us.apache.org/repos/asf/freemarker/blob/034b056c/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserController.java
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserController.java
 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserController.java
index 71ba8e0..dfc1ed8 100644
--- 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserController.java
+++ 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserController.java
@@ -20,9 +20,6 @@
 package org.apache.freemarker.spring.example.mvc.users;
 
 import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
@@ -46,15 +43,6 @@ import org.springframework.web.bind.annotation.RequestParam;
 @Controller
 public class UserController {
 
-    public static final List<String> INDOOR_SPORTS = Collections
-            .unmodifiableList(Arrays.asList("bowling", "gymnastics", 
"handball"));
-
-    public static final List<String> OUTDOOR_SPORTS = Collections
-            .unmodifiableList(Arrays.asList("baseball", "football", 
"marathon"));
-
-    public static final List<String> ALL_SPORTS = Collections
-            .unmodifiableList(Arrays.asList("bowling", "gymnastics", 
"handball", "baseball", "football", "marathon"));
-
     private static final String DEFAULT_USER_LIST_VIEW_NAME = 
"example/users/userlist";
 
     private static final String DEFAULT_USER_EDIT_VIEW_NAME = 
"example/users/useredit";
@@ -84,8 +72,8 @@ public class UserController {
     @RequestMapping(value = "/users/{id:\\d+}", method = RequestMethod.GET)
     public String getUser(@PathVariable("id") Long id,
             @RequestParam(value = "viewName", required = false) String 
viewName, Model model) {
-        model.addAttribute("indoorSports", INDOOR_SPORTS);
-        model.addAttribute("outdoorSports", OUTDOOR_SPORTS);
+        model.addAttribute("indoorSports", UserRepository.INDOOR_SPORTS);
+        model.addAttribute("outdoorSports", UserRepository.OUTDOOR_SPORTS);
 
         User user = userRepository.getUser(id);
 

http://git-wip-us.apache.org/repos/asf/freemarker/blob/034b056c/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 73c8d4d..e2a2283 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
@@ -19,7 +19,10 @@
 
 package org.apache.freemarker.spring.example.mvc.users;
 
+import java.util.Arrays;
 import java.util.Calendar;
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
@@ -30,6 +33,15 @@ import org.springframework.stereotype.Repository;
 @Repository
 public class UserRepository {
 
+    public static final List<String> INDOOR_SPORTS = Collections
+            .unmodifiableList(Arrays.asList("bowling", "gymnastics", 
"handball"));
+
+    public static final List<String> OUTDOOR_SPORTS = Collections
+            .unmodifiableList(Arrays.asList("baseball", "football", 
"marathon"));
+
+    public static final List<String> ALL_SPORTS = Collections
+            .unmodifiableList(Arrays.asList("bowling", "gymnastics", 
"handball", "baseball", "football", "marathon"));
+
     private Map<Long, User> usersMap = new ConcurrentHashMap<>();
     {
         Long id = 101L;
@@ -45,6 +57,7 @@ public class UserRepository {
         user.setBirthDate(birthDate.getTime());
         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");
         usersMap.put(id, user);
 
         id = 102L;
@@ -60,6 +73,7 @@ public class UserRepository {
         user.setBirthDate(birthDate.getTime());
         user.setDescription("Ut enim ad minim veniam, \r\n"
                 + "quis nostrud exercitation ullamco laboris nisi ut aliquip 
ex ea commodo consequat.");
+        user.setFavoriteSport("marathon");
         usersMap.put(id, user);
     }
 
@@ -105,6 +119,7 @@ public class UserRepository {
         clone.setLastName(source.getLastName());
         clone.setBirthDate(source.getBirthDate());
         clone.setDescription(source.getDescription());
+        clone.setFavoriteSport(source.getFavoriteSport());
         return clone;
     }
 }

http://git-wip-us.apache.org/repos/asf/freemarker/blob/034b056c/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/ElementAttributeMatcher.java
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/ElementAttributeMatcher.java
 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/ElementAttributeMatcher.java
new file mode 100644
index 0000000..b194dbf
--- /dev/null
+++ 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/ElementAttributeMatcher.java
@@ -0,0 +1,86 @@
+/*
+ * 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;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.w3c.dom.Attr;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+/**
+ * DOM Element Attribute value matcher.
+ * This matches if there's an attribute having the same value as {@code 
attrName}.
+ */
+public class ElementAttributeMatcher extends BaseMatcher<Node> {
+
+    private String attrName;
+    private String expectedAttrValue;
+    private String actualAttrValue;
+
+    public ElementAttributeMatcher(String attrName, String expectedAttrValue) {
+        if (attrName == null) {
+            throw new IllegalArgumentException("Attribute name must not be 
null.");
+        }
+
+        this.attrName = attrName;
+        this.expectedAttrValue = expectedAttrValue;
+    }
+
+    @Override
+    public boolean matches(Object item) {
+        actualAttrValue = getAttributeValue((Node) item, attrName);
+        return (expectedAttrValue == null) ? (actualAttrValue == null) : 
expectedAttrValue.equals(actualAttrValue);
+    }
+
+    @Override
+    public void describeTo(Description description) {
+        if (expectedAttrValue == null) {
+            description.appendText("The attribute value (@" + attrName + ") 
should be null");
+        } else {
+            description.appendText("The attribute value (@" + attrName + ") 
should be '" + expectedAttrValue + "'");
+        }
+    }
+
+    @Override
+    public void describeMismatch(Object item, Description description) {
+        description.appendText("was ").appendValue(actualAttrValue);
+    }
+
+    private String getAttributeValue(final Node node, final String attrName) {
+        final NamedNodeMap attrsMap = node.getAttributes();
+
+        if (attrsMap == null) {
+            return null;
+        }
+
+        final int length = attrsMap.getLength();
+
+        for (int i = 0; i < length; i++) {
+            final Attr attr = (Attr) attrsMap.item(i);
+
+            if (attrName.equals(attr.getName())) {
+                return attr.getValue();
+            }
+        }
+
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/freemarker/blob/034b056c/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/MissingElementAttributeMatcher.java
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/MissingElementAttributeMatcher.java
 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/MissingElementAttributeMatcher.java
new file mode 100644
index 0000000..329970d
--- /dev/null
+++ 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/MissingElementAttributeMatcher.java
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+/**
+ * DOM Element Attribute missing matcher.
+ * This matches if there's no attribute by {@code attrName}.
+ */
+public class MissingElementAttributeMatcher extends ElementAttributeMatcher {
+
+    public MissingElementAttributeMatcher(String attrName) {
+        super(attrName, null);
+    }
+}

http://git-wip-us.apache.org/repos/asf/freemarker/blob/034b056c/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/SelectTemplateDirectiveModelTest.java
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/SelectTemplateDirectiveModelTest.java
 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/SelectTemplateDirectiveModelTest.java
index eafd098..a9bba59 100644
--- 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/SelectTemplateDirectiveModelTest.java
+++ 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/SelectTemplateDirectiveModelTest.java
@@ -20,8 +20,9 @@
 package org.apache.freemarker.spring.model.form;
 
 import org.apache.freemarker.spring.example.mvc.users.User;
-import org.apache.freemarker.spring.example.mvc.users.UserController;
 import org.apache.freemarker.spring.example.mvc.users.UserRepository;
+import org.apache.freemarker.spring.model.ElementAttributeMatcher;
+import org.apache.freemarker.spring.model.MissingElementAttributeMatcher;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -32,6 +33,7 @@ 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.ResultActions;
+import org.springframework.test.web.servlet.result.XpathResultMatchers;
 import org.springframework.test.web.servlet.setup.MockMvcBuilders;
 import org.springframework.web.context.WebApplicationContext;
 
@@ -63,30 +65,81 @@ public class SelectTemplateDirectiveModelTest {
     public void testBasicUsages() throws Exception {
         final Long userId = userRepository.getUserIds().iterator().next();
         final User user = userRepository.getUser(userId);
+        final String favoriteSport = user.getFavoriteSport();
+
         final ResultActions resultAcctions =
                 mockMvc.perform(get("/users/{userId}/", 
userId).param("viewName", "test/model/form/select-directive-usages")
                 
.accept(MediaType.parseMediaType("text/html"))).andExpect(status().isOk())
                 
.andExpect(content().contentTypeCompatibleWith("text/html")).andDo(print());
 
-        for (int i = 0; i < UserController.INDOOR_SPORTS.size(); i++) {
-            String sport = UserController.INDOOR_SPORTS.get(i);
-            
resultAcctions.andExpect(xpath("//form[@id='form1']//select[@name='favoriteSport']//option["
 + (i + 1) + "]").string(sport));
+        XpathResultMatchers xPathMatchers = 
xpath("//form[@id='form1']//select[@name='favoriteSport']");
+        resultAcctions.andExpect(xPathMatchers.node(new 
MissingElementAttributeMatcher("size")));
+        resultAcctions.andExpect(xPathMatchers.node(new 
MissingElementAttributeMatcher("multiple")));
+
+        for (int i = 0; i < UserRepository.INDOOR_SPORTS.size(); i++) {
+            final String sport = UserRepository.INDOOR_SPORTS.get(i);
+            xPathMatchers = 
xpath("//form[@id='form1']//select[@name='favoriteSport']//option[" + (i + 1) + 
"]");
+            resultAcctions.andExpect(xPathMatchers.string(sport));
+
+            if (sport.equals(favoriteSport)) {
+                resultAcctions.andExpect(xPathMatchers.node(new 
ElementAttributeMatcher("selected", "selected")));
+            } else {
+                resultAcctions.andExpect(xPathMatchers.node(new 
MissingElementAttributeMatcher("selected")));
+            }
         }
 
-        for (int i = 0; i < UserController.OUTDOOR_SPORTS.size(); i++) {
-            String sport = UserController.OUTDOOR_SPORTS.get(i);
-            
resultAcctions.andExpect(xpath("//form[@id='form2']//select[@name='favoriteSport']//option["
 + (i + 1) + "]").string(sport));
+        xPathMatchers = 
xpath("//form[@id='form2']//select[@name='favoriteSport']");
+        resultAcctions.andExpect(xPathMatchers.node(new 
MissingElementAttributeMatcher("size")));
+        resultAcctions.andExpect(xPathMatchers.node(new 
MissingElementAttributeMatcher("multiple")));
+
+        for (int i = 0; i < UserRepository.OUTDOOR_SPORTS.size(); i++) {
+            final String sport = UserRepository.OUTDOOR_SPORTS.get(i);
+            xPathMatchers = 
xpath("//form[@id='form2']//select[@name='favoriteSport']//option[" + (i + 1) + 
"]");
+            resultAcctions.andExpect(xPathMatchers.string(sport));
+
+            if (sport.equals(favoriteSport)) {
+                resultAcctions.andExpect(xPathMatchers.node(new 
ElementAttributeMatcher("selected", "selected")));
+            } else {
+                resultAcctions.andExpect(xPathMatchers.node(new 
MissingElementAttributeMatcher("selected")));
+            }
         }
 
-        for (int i = 0; i < UserController.ALL_SPORTS.size(); i++) {
-            String sport = UserController.ALL_SPORTS.get(i);
-            
resultAcctions.andExpect(xpath("//form[@id='form3']//select[@name='favoriteSport']//option["
 + (i + 1) + "]").string(sport));
+        xPathMatchers = 
xpath("//form[@id='form3']//select[@name='favoriteSport']");
+        resultAcctions.andExpect(xPathMatchers.node(new 
ElementAttributeMatcher("size", "3")));
+        resultAcctions.andExpect(xPathMatchers.node(new 
ElementAttributeMatcher("multiple", "multiple")));
+
+        for (int i = 0; i < UserRepository.ALL_SPORTS.size(); i++) {
+            final String sport = UserRepository.ALL_SPORTS.get(i);
+            xPathMatchers = 
xpath("//form[@id='form3']//select[@name='favoriteSport']//option[" + (i + 1) + 
"]");
+            resultAcctions.andExpect(xPathMatchers.string(sport));
+
+            if (sport.equals(favoriteSport)) {
+                resultAcctions.andExpect(xPathMatchers.node(new 
ElementAttributeMatcher("selected", "selected")));
+            } else {
+                resultAcctions.andExpect(xPathMatchers.node(new 
MissingElementAttributeMatcher("selected")));
+            }
         }
 
-        
resultAcctions.andExpect(xpath("//form[@id='form4']//select[@name='favoriteSport']//option[1]").string("---
 Select ---"));
-        for (int i = 0; i < UserController.OUTDOOR_SPORTS.size(); i++) {
-            String sport = UserController.OUTDOOR_SPORTS.get(i);
-            
resultAcctions.andExpect(xpath("//form[@id='form4']//select[@name='favoriteSport']//option["
 + (i + 2) + "]").string(sport));
+        xPathMatchers = 
xpath("//form[@id='form4']//select[@name='favoriteSport']");
+        resultAcctions.andExpect(xPathMatchers.node(new 
MissingElementAttributeMatcher("size")));
+        resultAcctions.andExpect(xPathMatchers.node(new 
MissingElementAttributeMatcher("multiple")));
+
+        xPathMatchers = 
xpath("//form[@id='form4']//select[@name='favoriteSport']//option[1]");
+        resultAcctions.andExpect(xPathMatchers.string("--- Select ---"));
+
+        for (int i = 0; i < UserRepository.OUTDOOR_SPORTS.size(); i++) {
+            final String sport = UserRepository.OUTDOOR_SPORTS.get(i);
+            xPathMatchers = 
xpath("//form[@id='form4']//select[@name='favoriteSport']//option[" + (i + 2) + 
"]");
+            resultAcctions.andExpect(xPathMatchers.string(sport));
+
+            if (sport.equals(favoriteSport)) {
+                resultAcctions.andExpect(xPathMatchers.node(new 
ElementAttributeMatcher("selected", "selected")));
+            } else {
+                resultAcctions.andExpect(xPathMatchers.node(new 
MissingElementAttributeMatcher("selected")));
+            }
         }
+
+        xPathMatchers = 
xpath("//form[@id='form5']//select[@name='favoriteSport']//option[1]");
+        resultAcctions.andExpect(xPathMatchers.node(new 
ElementAttributeMatcher("disabled", "disabled")));
     }
 }

http://git-wip-us.apache.org/repos/asf/freemarker/blob/034b056c/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/select-directive-usages.f3ah
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/select-directive-usages.f3ah
 
b/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/select-directive-usages.f3ah
index 327bf4a..34319d3 100644
--- 
a/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/select-directive-usages.f3ah
+++ 
b/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/select-directive-usages.f3ah
@@ -54,7 +54,7 @@
       <tr>
         <th>Favorite Sport:</th>
         <td>
-          <@form.select 'user.favoriteSport' items=indoorSports>
+          <@form.select 'user.favoriteSport' items=indoorSports multiple=true 
size="3">
             <@form.options items=outdoorSports />
           </@form.select>
         </td>
@@ -78,5 +78,20 @@
     </table>
   </form>
 
+  <h1>Form 5</h1>
+  <hr/>
+  <form id="form5">
+    <table>
+      <tr>
+        <th>Favorite Sport:</th>
+        <td>
+          <@form.select 'user.favoriteSport'>
+            <@form.option value="" label="--- Select ---" disabled=true />
+          </@form.select>
+        </td>
+      </tr>
+    </table>
+  </form>
+
 </body>
 </html>

Reply via email to