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