1   /*
2    * Copyright 2004-2009 the Seasar Foundation and the Others.
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,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.seasar.cubby.routing.impl;
17  
18  import static org.junit.Assert.assertEquals;
19  import static org.junit.Assert.assertFalse;
20  import static org.junit.Assert.assertNotNull;
21  import static org.junit.Assert.assertNull;
22  import static org.junit.Assert.assertTrue;
23  import static org.junit.Assert.fail;
24  
25  import java.util.ArrayList;
26  import java.util.Collection;
27  import java.util.Collections;
28  import java.util.HashMap;
29  import java.util.Iterator;
30  import java.util.List;
31  import java.util.Map;
32  
33  import org.junit.Before;
34  import org.junit.Test;
35  import org.seasar.cubby.action.Action;
36  import org.seasar.cubby.action.ActionResult;
37  import org.seasar.cubby.action.RequestMethod;
38  import org.seasar.cubby.routing.PathInfo;
39  import org.seasar.cubby.routing.Routing;
40  import org.seasar.cubby.routing.RoutingException;
41  
42  public class PathResolverImplTest {
43  
44  	private PathResolverImpl pathResolver;
45  
46  	@Before
47  	public void setupPathResolver() {
48  		pathResolver = new PathResolverImpl(new PathTemplateParserImpl());
49  		List<Class<?>> actionClasses = new ArrayList<Class<?>>();
50  		actionClasses.add(MockAction.class);
51  		actionClasses.add(MockRootAction.class);
52  		actionClasses.add(MockPathAction.class);
53  		pathResolver.addAll(actionClasses);
54  	}
55  
56  	@Test
57  	public void testClear() {
58  		assertFalse(pathResolver.getRoutings().isEmpty());
59  		pathResolver.clear();
60  		assertTrue(pathResolver.getRoutings().isEmpty());
61  	}
62  
63  	@Test
64  	public void testGetRoutings() {
65  		List<Routing> routings = new ArrayList<Routing>(pathResolver
66  				.getRoutings());
67  		assertEquals(24, routings.size());
68  	}
69  
70  	@Test
71  	public void testAdd() {
72  		int priority = 0;
73  		pathResolver.add("/wiki/edit/{name,.+}", MockAction.class, "update",
74  				RequestMethod.GET, null, priority++);
75  		pathResolver.add("/wiki/edit/{name,.+}", MockAction.class, "update",
76  				RequestMethod.POST, null, priority++);
77  		pathResolver.add("/wiki/{name,.+}", MockAction.class, "update2",
78  				RequestMethod.POST, null, priority++);
79  		pathResolver.add("/wiki/{name,.+}", MockAction.class, "name",
80  				RequestMethod.PUT, null, priority++);
81  
82  		List<Routing> routings = new ArrayList<Routing>(pathResolver
83  				.getRoutings());
84  		assertEquals(28, routings.size());
85  
86  		Iterator<Routing> iterator = routings.iterator();
87  
88  		Routing routing1 = iterator.next();
89  		assertEquals("^/wiki/edit/(.+)$", routing1.getPattern().pattern());
90  		assertEquals(RequestMethod.GET, routing1.getRequestMethod());
91  		assertEquals(0, routing1.getPriority());
92  
93  		Routing routing2 = iterator.next();
94  		assertEquals("^/wiki/edit/(.+)$", routing2.getPattern().pattern());
95  		assertEquals(RequestMethod.POST, routing2.getRequestMethod());
96  		assertEquals(1, routing2.getPriority());
97  
98  		Routing routing3 = iterator.next();
99  		assertEquals("^/wiki/(.+)$", routing3.getPattern().pattern());
100 		assertEquals(RequestMethod.POST, routing3.getRequestMethod());
101 		assertEquals(2, routing3.getPriority());
102 
103 		Routing routing4 = iterator.next();
104 		assertEquals("^/wiki/(.+)$", routing4.getPattern().pattern());
105 		assertEquals(RequestMethod.PUT, routing4.getRequestMethod());
106 		assertEquals(3, routing4.getPriority());
107 
108 		// Routing routing5 = iterator.next();
109 		// assertEquals("^/mockPriority/update$",
110 		// routing5.getPattern().pattern());
111 		// assertEquals(100, routing5.getPriority());
112 		// assertEquals(RequestMethod.PUT, routing5.getRequestMethod());
113 	}
114 
115 	@Test
116 	public void testRoot1() throws Exception {
117 		PathInfo info = pathResolver.getPathInfo("/", "GET", "UTF-8");
118 		assertNotNull(info);
119 		Map<String, Object[]> parameterMap = Collections.emptyMap();
120 		Routing routing = info.dispatch(parameterMap);
121 		assertEquals(MockRootAction.class, routing.getActionClass());
122 		assertEquals(MockRootAction.class.getMethod("index"), routing
123 				.getActionMethod());
124 		assertEquals(0, routing.getUriParameterNames().size());
125 
126 		Map<String, String[]> uriParameters = info.getURIParameters();
127 		assertEquals(0, uriParameters.size());
128 	}
129 
130 	@Test
131 	public void testRoot2() throws Exception {
132 		PathInfo info = pathResolver.getPathInfo("/dummy1", "GET", "UTF-8");
133 		assertNotNull(info);
134 		Map<String, Object[]> parameterMap = Collections.emptyMap();
135 		Routing routing = info.dispatch(parameterMap);
136 		assertEquals(MockRootAction.class, routing.getActionClass());
137 		assertEquals(MockRootAction.class.getMethod("dummy1"), routing
138 				.getActionMethod());
139 		assertEquals(0, routing.getUriParameterNames().size());
140 
141 		Map<String, String[]> uriParameters = info.getURIParameters();
142 		assertEquals(0, uriParameters.size());
143 	}
144 
145 	@Test
146 	public void testDefault1() throws Exception {
147 		PathInfo info = pathResolver
148 				.getPathInfo("/mock/update", "GET", "UTF-8");
149 		assertNotNull(info);
150 		Map<String, Object[]> parameterMap = Collections.emptyMap();
151 		Routing routing = info.dispatch(parameterMap);
152 		assertEquals(MockAction.class, routing.getActionClass());
153 		assertEquals(MockAction.class.getMethod("update"), routing
154 				.getActionMethod());
155 		assertEquals(0, routing.getUriParameterNames().size());
156 
157 		Map<String, String[]> uriParameters = info.getURIParameters();
158 		assertEquals(0, uriParameters.size());
159 	}
160 
161 	@Test
162 	public void testDefault2() throws Exception {
163 		PathInfo info = pathResolver
164 				.getPathInfo("/mock/create", "GET", "UTF-8");
165 		assertNotNull(info);
166 		Map<String, Object[]> parameterMap = Collections.emptyMap();
167 		Routing routing = info.dispatch(parameterMap);
168 		assertEquals(MockAction.class, routing.getActionClass());
169 		assertEquals(MockAction.class.getMethod("insert"), routing
170 				.getActionMethod());
171 		assertEquals(0, routing.getUriParameterNames().size());
172 
173 		Map<String, String[]> uriParameters = info.getURIParameters();
174 		assertEquals(0, uriParameters.size());
175 	}
176 
177 	@Test
178 	public void testDefault3() throws Exception {
179 		PathInfo info = pathResolver.getPathInfo("/mock/delete/10", "GET",
180 				"UTF-8");
181 		assertNotNull(info);
182 		Map<String, Object[]> parameterMap = Collections.emptyMap();
183 		Routing routing = info.dispatch(parameterMap);
184 		assertEquals(MockAction.class, routing.getActionClass());
185 		assertEquals(MockAction.class.getMethod("delete"), routing
186 				.getActionMethod());
187 		assertEquals(1, routing.getUriParameterNames().size());
188 
189 		Map<String, String[]> uriParameters = info.getURIParameters();
190 		assertEquals(1, uriParameters.size());
191 		String[] value = uriParameters.get("value");
192 		assertEquals(1, value.length);
193 		assertEquals("10", value[0]);
194 	}
195 
196 	@Test
197 	public void testDefault4() throws Exception {
198 		PathInfo info = pathResolver.getPathInfo("/mock/delete/a", "GET",
199 				"UTF-8");
200 		assertNull(info);
201 	}
202 
203 	@Test
204 	public void testDefault5() throws Exception {
205 		PathInfo info = pathResolver.getPathInfo("/mock/cubby", "GET", "UTf-8");
206 		assertNotNull(info);
207 		Map<String, Object[]> parameterMap = Collections.emptyMap();
208 		Routing routing = info.dispatch(parameterMap);
209 		assertEquals(MockAction.class, routing.getActionClass());
210 		assertEquals(MockAction.class.getMethod("name"), routing
211 				.getActionMethod());
212 		assertEquals(1, routing.getUriParameterNames().size());
213 
214 		Map<String, String[]> uriParameters = info.getURIParameters();
215 		assertEquals(1, uriParameters.size());
216 		String[] value = uriParameters.get("name");
217 		assertEquals(1, value.length);
218 		assertEquals("cubby", value[0]);
219 	}
220 
221 	@Test
222 	public void testPath1() throws Exception {
223 		PathInfo info = pathResolver.getPathInfo("/foo/4/update", "GET",
224 				"UTF-8");
225 		assertNotNull(info);
226 		Map<String, Object[]> parameterMap = Collections.emptyMap();
227 		Routing routing = info.dispatch(parameterMap);
228 		assertEquals(MockPathAction.class, routing.getActionClass());
229 		assertEquals(MockPathAction.class.getMethod("update"), routing
230 				.getActionMethod());
231 		assertEquals(1, routing.getUriParameterNames().size());
232 
233 		Map<String, String[]> uriParameters = info.getURIParameters();
234 		assertEquals(1, uriParameters.size());
235 		String[] value = uriParameters.get("id");
236 		assertEquals(1, value.length);
237 		assertEquals("4", value[0]);
238 	}
239 
240 	@Test
241 	public void testPath2() throws Exception {
242 		PathInfo info = pathResolver.getPathInfo("/foo/4/create", "GET",
243 				"UTF-8");
244 		assertNotNull(info);
245 		Map<String, Object[]> parameterMap = Collections.emptyMap();
246 		Routing routing = info.dispatch(parameterMap);
247 		assertEquals(MockPathAction.class, routing.getActionClass());
248 		assertEquals(MockPathAction.class.getMethod("insert"), routing
249 				.getActionMethod());
250 		assertEquals(1, routing.getUriParameterNames().size());
251 
252 		Map<String, String[]> uriParameters = info.getURIParameters();
253 		assertEquals(1, uriParameters.size());
254 		String[] value = uriParameters.get("id");
255 		assertEquals(1, value.length);
256 		assertEquals("4", value[0]);
257 	}
258 
259 	@Test
260 	public void testPath3() throws Exception {
261 		PathInfo info = pathResolver.getPathInfo("/foo/4/delete/10", "GET",
262 				"UTF-8");
263 		assertNotNull(info);
264 		Map<String, Object[]> parameterMap = Collections.emptyMap();
265 		Routing routing = info.dispatch(parameterMap);
266 		assertEquals(MockPathAction.class, routing.getActionClass());
267 		assertEquals(MockPathAction.class.getMethod("delete"), routing
268 				.getActionMethod());
269 		assertEquals(2, routing.getUriParameterNames().size());
270 
271 		Map<String, String[]> uriParameters = info.getURIParameters();
272 		assertEquals(2, uriParameters.size());
273 		String[] id = uriParameters.get("id");
274 		assertEquals(1, id.length);
275 		assertEquals("4", id[0]);
276 		String[] value = uriParameters.get("value");
277 		assertEquals(1, value.length);
278 		assertEquals("10", value[0]);
279 	}
280 
281 	@Test
282 	public void testPath4() throws Exception {
283 		PathInfo info = pathResolver.getPathInfo("/foo/4/delete/a", "GET",
284 				"UTF-8");
285 		assertNull(info);
286 	}
287 
288 	@Test
289 	public void testPath5() throws Exception {
290 		PathInfo info = pathResolver
291 				.getPathInfo("/foo/4/cubby", "GET", "UTF-8");
292 		assertNotNull(info);
293 		Map<String, Object[]> parameterMap = Collections.emptyMap();
294 		Routing routing = info.dispatch(parameterMap);
295 		assertEquals(MockPathAction.class, routing.getActionClass());
296 		assertEquals(MockPathAction.class.getMethod("name"), routing
297 				.getActionMethod());
298 		assertEquals(2, routing.getUriParameterNames().size());
299 
300 		Map<String, String[]> uriParameters = info.getURIParameters();
301 		assertEquals(2, uriParameters.size());
302 		String[] id = uriParameters.get("id");
303 		assertEquals(1, id.length);
304 		assertEquals("4", id[0]);
305 		String[] value = uriParameters.get("name");
306 		assertEquals(1, value.length);
307 		assertEquals("cubby", value[0]);
308 	}
309 
310 	// @Test
311 	public void testAddAbstractClass() throws Exception {
312 		try {
313 			pathResolver.add("/parent/m1", ParentAction.class, "m1",
314 					RequestMethod.GET, null, 0);
315 			fail();
316 		} catch (RoutingException e) {
317 			// assertEquals("アクションクラスではないクラスを登録するとエラー(抽象クラス)", "ECUB0002",
318 			// e.getMessageCode());
319 		}
320 		try {
321 			pathResolver.add("/child/m3", ChildAction.class, "m3",
322 					RequestMethod.GET, null, 0);
323 			fail();
324 		} catch (RoutingException e) {
325 			// assertEquals("アクションメソッドではないメソッドを登録するとエラー(戻り値がObject)",
326 			// "ECUB0003", e.getMessageCode());
327 		}
328 		pathResolver.add("/child/m1", ChildAction.class, "m1",
329 				RequestMethod.GET, null, 0);
330 		pathResolver.add("/child/m1", ChildAction.class, "m1",
331 				RequestMethod.POST, null, 0);
332 		pathResolver.add("/child/m2", ChildAction.class, "m2",
333 				RequestMethod.GET, null, 0);
334 		pathResolver.add("/child/m2", ChildAction.class, "m2",
335 				RequestMethod.POST, null, 0);
336 		Collection<Routing> routings = pathResolver.getRoutings();
337 		assertEquals("正常に登録できたルーティング情報の数", 28, routings.size());
338 		Iterator<Routing> it = routings.iterator();
339 		assertRouting(it.next(), "/child/m1", RequestMethod.GET,
340 				ChildAction.class, "m1");
341 		assertRouting(it.next(), "/child/m1", RequestMethod.POST,
342 				ChildAction.class, "m1");
343 		assertRouting(it.next(), "/child/m2", RequestMethod.GET,
344 				ChildAction.class, "m2");
345 		assertRouting(it.next(), "/child/m2", RequestMethod.POST,
346 				ChildAction.class, "m2");
347 	}
348 
349 	private void assertRouting(Routing routing, String path,
350 			RequestMethod requestMethod, Class<? extends Action> actionClass,
351 			String actionMethod) {
352 		assertEquals(path, routing.getActionPath());
353 		assertEquals(requestMethod, routing.getRequestMethod());
354 		assertEquals(actionClass, routing.getActionClass());
355 		assertEquals(actionMethod, routing.getActionMethod().getName());
356 	}
357 
358 	public abstract class ParentAction extends Action {
359 		public ActionResult m1() {
360 			return null;
361 		}
362 	}
363 
364 	public class ChildAction extends ParentAction {
365 		public ActionResult m2() {
366 			return null;
367 		}
368 
369 		public Object m3() {
370 			return null;
371 		}
372 	}
373 
374 	static class Query {
375 		private String path;
376 		private Map<String, List<String>> params;
377 
378 		public Query(String path) {
379 			String[] tokens = path.split("\\?", 2);
380 			switch (tokens.length) {
381 			case 1:
382 				this.path = tokens[0];
383 				this.params = new HashMap<String, List<String>>();
384 				break;
385 			case 2:
386 				this.path = tokens[0];
387 				this.params = parseQueryString(tokens[1]);
388 
389 				break;
390 			default:
391 				fail("illegal path " + path);
392 				break;
393 			}
394 		}
395 
396 		private Map<String, List<String>> parseQueryString(String queryString) {
397 			Map<String, List<String>> params = new HashMap<String, List<String>>();
398 			String[] tokens = queryString.split("&");
399 			for (String token : tokens) {
400 				String[] param = parseQueryParameter(token);
401 				String name = param[0];
402 				String value = param[1];
403 				List<String> values;
404 				if (params.containsKey(name)) {
405 					values = params.get(name);
406 				} else {
407 					values = new ArrayList<String>();
408 					params.put(name, values);
409 				}
410 				values.add(value);
411 			}
412 			return params;
413 		}
414 
415 		private String[] parseQueryParameter(String token) {
416 			return token.split("=");
417 		}
418 
419 		public String getPath() {
420 			return path;
421 		}
422 
423 		public List<String> getParam(String name) {
424 			return params.get(name);
425 		}
426 
427 		public boolean isEmptyParameter() {
428 			return params.isEmpty();
429 		}
430 
431 		public int getParameterSize() {
432 			return params.size();
433 		}
434 	}
435 
436 }