    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 }