1 /*
2  * Copyright 2002-2008 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package org.springframework.web.servlet.tags.form;
18 
19 import java.beans.PropertyEditor;
20 import java.io.StringReader;
21 import java.util.ArrayList;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25 
26 import javax.servlet.http.HttpServletRequest;
27 import javax.servlet.jsp.tagext.BodyTag;
28 import javax.servlet.jsp.tagext.Tag;
29 
30 import org.dom4j.Document;
31 import org.dom4j.Element;
32 import org.dom4j.Node;
33 import org.dom4j.io.SAXReader;
34 import org.springframework.beans.TestBean;
35 import org.springframework.mock.web.MockHttpServletRequest;
36 import org.springframework.mock.web.MockPageContext;
37 import org.springframework.validation.BeanPropertyBindingResult;
38 import org.springframework.validation.BindingResult;
39 import org.springframework.validation.Errors;
40 import org.springframework.web.servlet.support.BindStatus;
41 import org.springframework.web.servlet.support.RequestContext;
42 import org.springframework.web.servlet.tags.RequestContextAwareTag;
43 
44 /**
45  * @author Rob Harrop
46  * @author Juergen Hoeller
47  * @author Scott Andrews
48  * @author Jeremy Grelle
49  */
50 public final class OptionsTagTests extends AbstractHtmlElementTagTests {
51 
52 	private static final String COMMAND_NAME = "testBean";
53 
54 	private SelectTag selectTag;
55 	private OptionsTag tag;
56 
onSetUp()57 	protected void onSetUp() {
58 		this.tag = new OptionsTag() {
59 			protected TagWriter createTagWriter() {
60 				return new TagWriter(getWriter());
61 			}
62 		};
63 		selectTag = new SelectTag() {
64 			protected TagWriter createTagWriter() {
65 				return new TagWriter(getWriter());
66 			}
67 			public String getName() {
68 				// Should not be used other than to delegate to
69 				// RequestDataValueDataProcessor
70 				return "testName";
71 			}
72 		};
73 		selectTag.setPageContext(getPageContext());
74 		this.tag.setParent(selectTag);
75 		this.tag.setPageContext(getPageContext());
76 	}
77 
testWithCollection()78 	public void testWithCollection() throws Exception {
79 		getPageContext().setAttribute(
80 				SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), "testBean.country", false));
81 
82 		this.tag.setItems("${countries}");
83 		this.tag.setItemValue("isoCode");
84 		this.tag.setItemLabel("name");
85 		this.tag.setId("myOption");
86 		this.tag.setCssClass("myClass");
87 		this.tag.setOnclick("CLICK");
88 		int result = this.tag.doStartTag();
89 		assertEquals(Tag.SKIP_BODY, result);
90 		String output = getOutput();
91 		output = "<doc>" + output + "</doc>";
92 
93 		SAXReader reader = new SAXReader();
94 		Document document = reader.read(new StringReader(output));
95 		Element rootElement = document.getRootElement();
96 
97 		List children = rootElement.elements();
98 		assertEquals("Incorrect number of children", 4, children.size());
99 
100 		Element element = (Element) rootElement.selectSingleNode("option[@value = 'UK']");
101 		assertEquals("UK node not selected", "selected", element.attribute("selected").getValue());
102 		assertEquals("myOption3", element.attribute("id").getValue());
103 		assertEquals("myClass", element.attribute("class").getValue());
104 		assertEquals("CLICK", element.attribute("onclick").getValue());
105 	}
106 
testWithCollectionAndDynamicAttributes()107 	public void testWithCollectionAndDynamicAttributes() throws Exception {
108 		String dynamicAttribute1 = "attr1";
109 		String dynamicAttribute2 = "attr2";
110 
111 		getPageContext().setAttribute(
112 				SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), "testBean.country", false));
113 
114 		this.tag.setItems("${countries}");
115 		this.tag.setItemValue("isoCode");
116 		this.tag.setItemLabel("name");
117 		this.tag.setId("myOption");
118 		this.tag.setCssClass("myClass");
119 		this.tag.setOnclick("CLICK");
120 		this.tag.setDynamicAttribute(null, dynamicAttribute1, dynamicAttribute1);
121 		this.tag.setDynamicAttribute(null, dynamicAttribute2, dynamicAttribute2);
122 
123 		int result = this.tag.doStartTag();
124 		assertEquals(Tag.SKIP_BODY, result);
125 		String output = getOutput();
126 		output = "<doc>" + output + "</doc>";
127 
128 		SAXReader reader = new SAXReader();
129 		Document document = reader.read(new StringReader(output));
130 		Element rootElement = document.getRootElement();
131 
132 		List children = rootElement.elements();
133 		assertEquals("Incorrect number of children", 4, children.size());
134 
135 		Element element = (Element) rootElement.selectSingleNode("option[@value = 'UK']");
136 		assertEquals("UK node not selected", "selected", element.attribute("selected").getValue());
137 		assertEquals("myOption3", element.attribute("id").getValue());
138 		assertEquals("myClass", element.attribute("class").getValue());
139 		assertEquals("CLICK", element.attribute("onclick").getValue());
140 		assertEquals(dynamicAttribute1, element.attribute(dynamicAttribute1).getValue());
141 		assertEquals(dynamicAttribute2, element.attribute(dynamicAttribute2).getValue());
142 	}
143 
testWithCollectionAndCustomEditor()144 	public void testWithCollectionAndCustomEditor() throws Exception {
145 		PropertyEditor propertyEditor = new SimpleFloatEditor();
146 
147 		TestBean target = new TestBean();
148 		target.setMyFloat(new Float("12.34"));
149 
150 		BeanPropertyBindingResult errors = new BeanPropertyBindingResult(target, COMMAND_NAME);
151 		errors.getPropertyAccessor().registerCustomEditor(Float.class, propertyEditor);
152 		exposeBindingResult(errors);
153 
154 		getPageContext().setAttribute(
155 				SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), "testBean.myFloat", false));
156 
157 		this.tag.setItems("${floats}");
158 		int result = this.tag.doStartTag();
159 		assertEquals(Tag.SKIP_BODY, result);
160 		String output = getOutput();
161 		output = "<doc>" + output + "</doc>";
162 
163 		SAXReader reader = new SAXReader();
164 		Document document = reader.read(new StringReader(output));
165 		Element rootElement = document.getRootElement();
166 
167 		List children = rootElement.elements();
168 		assertEquals("Incorrect number of children", 6, children.size());
169 
170 		Element element = (Element) rootElement.selectSingleNode("option[text() = '12.34f']");
171 		assertNotNull("Option node should not be null", element);
172 		assertEquals("12.34 node not selected", "selected", element.attribute("selected").getValue());
173 		assertNull("No id rendered", element.attribute("id"));
174 
175 		element = (Element) rootElement.selectSingleNode("option[text() = '12.35f']");
176 		assertNotNull("Option node should not be null", element);
177 		assertNull("12.35 node incorrectly selected", element.attribute("selected"));
178 		assertNull("No id rendered", element.attribute("id"));
179 	}
180 
testWithItemsNullReference()181 	public void testWithItemsNullReference() throws Exception {
182 		getPageContext().getRequest().removeAttribute("countries");
183 		getPageContext().setAttribute(
184 				SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), "testBean.country", false));
185 
186 		this.tag.setItems("${countries}");
187 		this.tag.setItemValue("isoCode");
188 		this.tag.setItemLabel("name");
189 		int result = this.tag.doStartTag();
190 		assertEquals(Tag.SKIP_BODY, result);
191 		String output = getOutput();
192 		output = "<doc>" + output + "</doc>";
193 
194 		SAXReader reader = new SAXReader();
195 		Document document = reader.read(new StringReader(output));
196 		Element rootElement = document.getRootElement();
197 
198 		List children = rootElement.elements();
199 		assertEquals("Incorrect number of children", 0, children.size());
200 	}
201 
testWithoutItems()202 	public void testWithoutItems() throws Exception {
203 		this.tag.setItemValue("isoCode");
204 		this.tag.setItemLabel("name");
205 		this.selectTag.setPath("testBean");
206 
207 		this.selectTag.doStartTag();
208 		int result = this.tag.doStartTag();
209 		assertEquals(Tag.SKIP_BODY, result);
210 		this.tag.doEndTag();
211 		this.selectTag.doEndTag();
212 
213 		String output = getOutput();
214 		SAXReader reader = new SAXReader();
215 		Document document = reader.read(new StringReader(output));
216 		Element rootElement = document.getRootElement();
217 
218 		List children = rootElement.elements();
219 		assertEquals("Incorrect number of children", 0, children.size());
220 	}
221 
testWithoutItemsEnumParent()222 	public void testWithoutItemsEnumParent() throws Exception {
223 		BeanWithEnum testBean = new BeanWithEnum();
224 		testBean.setTestEnum(TestEnum.VALUE_2);
225 		getPageContext().getRequest().setAttribute("testBean", testBean);
226 
227 		this.selectTag.setPath("testBean.testEnum");
228 
229 		this.selectTag.doStartTag();
230 		int result = this.tag.doStartTag();
231 		assertEquals(BodyTag.SKIP_BODY, result);
232 		result = this.tag.doEndTag();
233 		assertEquals(Tag.EVAL_PAGE, result);
234 		this.selectTag.doEndTag();
235 
236 		String output = getWriter().toString();
237 		SAXReader reader = new SAXReader();
238 		Document document = reader.read(new StringReader(output));
239 		Element rootElement = document.getRootElement();
240 
241 		assertEquals(2, rootElement.elements().size());
242 		Node value1 = rootElement.selectSingleNode("option[@value = 'VALUE_1']");
243 		Node value2 = rootElement.selectSingleNode("option[@value = 'VALUE_2']");
244 		assertEquals("TestEnum: VALUE_1", value1.getText());
245 		assertEquals("TestEnum: VALUE_2", value2.getText());
246 		assertEquals(value2, rootElement.selectSingleNode("option[@selected]"));
247 	}
248 
testWithoutItemsEnumParentWithExplicitLabelsAndValues()249 	public void testWithoutItemsEnumParentWithExplicitLabelsAndValues() throws Exception {
250 		BeanWithEnum testBean = new BeanWithEnum();
251 		testBean.setTestEnum(TestEnum.VALUE_2);
252 		getPageContext().getRequest().setAttribute("testBean", testBean);
253 
254 		this.selectTag.setPath("testBean.testEnum");
255 		this.tag.setItemLabel("enumLabel");
256 		this.tag.setItemValue("enumValue");
257 
258 		this.selectTag.doStartTag();
259 		int result = this.tag.doStartTag();
260 		assertEquals(BodyTag.SKIP_BODY, result);
261 		result = this.tag.doEndTag();
262 		assertEquals(Tag.EVAL_PAGE, result);
263 		this.selectTag.doEndTag();
264 
265 		String output = getWriter().toString();
266 		SAXReader reader = new SAXReader();
267 		Document document = reader.read(new StringReader(output));
268 		Element rootElement = document.getRootElement();
269 
270 		assertEquals(2, rootElement.elements().size());
271 		Node value1 = rootElement.selectSingleNode("option[@value = 'Value: VALUE_1']");
272 		Node value2 = rootElement.selectSingleNode("option[@value = 'Value: VALUE_2']");
273 		assertEquals("Label: VALUE_1", value1.getText());
274 		assertEquals("Label: VALUE_2", value2.getText());
275 		assertEquals(value2, rootElement.selectSingleNode("option[@selected]"));
276 	}
277 
extendRequest(MockHttpServletRequest request)278 	protected void extendRequest(MockHttpServletRequest request) {
279 		TestBean bean = new TestBean();
280 		bean.setName("foo");
281 		bean.setCountry("UK");
282 		bean.setMyFloat(new Float("12.34"));
283 		request.setAttribute(COMMAND_NAME, bean);
284 		request.setAttribute("countries", Country.getCountries());
285 
286 		List floats = new ArrayList();
287 		floats.add(new Float("12.30"));
288 		floats.add(new Float("12.31"));
289 		floats.add(new Float("12.32"));
290 		floats.add(new Float("12.33"));
291 		floats.add(new Float("12.34"));
292 		floats.add(new Float("12.35"));
293 
294 		request.setAttribute("floats", floats);
295 	}
296 
exposeBindingResult(Errors errors)297 	protected void exposeBindingResult(Errors errors) {
298 		// wrap errors in a Model
299 		Map model = new HashMap();
300 		model.put(BindingResult.MODEL_KEY_PREFIX + COMMAND_NAME, errors);
301 
302 		// replace the request context with one containing the errors
303 		MockPageContext pageContext = getPageContext();
304 		RequestContext context = new RequestContext((HttpServletRequest) pageContext.getRequest(), model);
305 		pageContext.setAttribute(RequestContextAwareTag.REQUEST_CONTEXT_PAGE_ATTRIBUTE, context);
306 	}
307 
308 }
309