/*** * Copyright (c) 2009 Caelum - www.caelum.com.br/opensource * All rights reserved. * * Licensed 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 br.com.caelum.vraptor.http.route; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.lang.reflect.Method; import java.util.Collections; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import br.com.caelum.vraptor.TwoWayConverter; import br.com.caelum.vraptor.core.Converters; import br.com.caelum.vraptor.core.DefaultReflectionProvider; import br.com.caelum.vraptor.http.EncodingHandler; import br.com.caelum.vraptor.http.MutableRequest; import br.com.caelum.vraptor.http.ParameterNameProvider; import br.com.caelum.vraptor.http.ParanamerNameProvider; public class DefaultParametersControlTest { private @Mock MutableRequest request; private @Mock Converters converters; private @Mock TwoWayConverter converter; private @Mock EncodingHandler encodingHandler; private Evaluator evaluator; private ParameterNameProvider nameProvider; @Before public void setup() { MockitoAnnotations.initMocks(this); when(encodingHandler.getEncoding()).thenReturn("UTF-8"); evaluator = new JavaEvaluator(new DefaultReflectionProvider()); nameProvider = new ParanamerNameProvider(); } @Test public void registerExtraParametersFromAcessedUrl() throws SecurityException, NoSuchMethodException { DefaultParametersControl control = getDefaultParameterControlForUrl("/clients/{dog.id}"); control.fillIntoRequest("/clients/45", request); verify(request).setParameter("dog.id", new String[] {"45"}); } private DefaultParametersControl getDefaultParameterControlForUrl(String url) { return new DefaultParametersControl(url, converters, evaluator,encodingHandler); } @Test public void registerParametersWithAsterisks() throws SecurityException, NoSuchMethodException { DefaultParametersControl control = getDefaultParameterControlForUrl("/clients/{my.path*}"); control.fillIntoRequest("/clients/one/path", request); verify(request).setParameter("my.path", new String[] {"one/path"}); } @Test public void registerParametersWithRegexes() throws SecurityException, NoSuchMethodException { DefaultParametersControl control = getDefaultParameterControlForUrl("/clients/{hexa:[0-9A-Z]+}"); control.fillIntoRequest("/clients/FAF323", request); verify(request).setParameter("hexa", new String[] {"FAF323"}); } @Test public void registerParametersWithMultipleRegexes() throws SecurityException, NoSuchMethodException { DefaultParametersControl control = new DefaultParametersControl("/test/{hash1:[a-z0-9]{16}}{id}{hash2:[a-z0-9]{16}}/", Collections.singletonMap("id", "\\d+"), converters, evaluator,encodingHandler); control.fillIntoRequest("/test/0123456789abcdef1234fedcba9876543210/", request); verify(request).setParameter("hash1", new String[] {"0123456789abcdef"}); verify(request).setParameter("id", new String[] {"1234"}); verify(request).setParameter("hash2", new String[] {"fedcba9876543210"}); } @Test public void worksAsRegexWhenUsingParameters() throws SecurityException, NoSuchMethodException { DefaultParametersControl control = getDefaultParameterControlForUrl("/clients/{dog.id}"); assertThat(control.matches("/clients/15"), is(equalTo(true))); } @Test public void worksWithBasicRegexEvaluation() throws SecurityException, NoSuchMethodException { DefaultParametersControl control = getDefaultParameterControlForUrl("/clients.*"); assertThat(control.matches("/clientsWhatever"), is(equalTo(true))); } class Client { private final Long id; private Client child; public Client(Long id) { this.id = id; } public Client getChild() { return child; } public Long getId() { return id; } } @Test public void shouldTranslateAsteriskAsEmpty() throws Exception { Method method = Controller.class.getDeclaredMethod("store", Client.class); String uri = getDefaultParameterControlForUrl("/clients/.*").fillUri(nameProvider.parametersFor(method), client(3L)); assertThat(uri, is(equalTo("/clients/"))); } @Test public void shouldTranslatePatternArgs() throws Exception { Method method = Controller.class.getDeclaredMethod("store", Client.class); String uri = getDefaultParameterControlForUrl("/clients/{client.id}").fillUri(nameProvider.parametersFor(method), client(3L)); assertThat(uri, is(equalTo("/clients/3"))); } @Test public void shouldTranslatePatternArgsWithRegex() throws Exception { Method method = Controller.class.getDeclaredMethod("show", Long.class); String uri = getDefaultParameterControlForUrl("/clients/{id:[0-9]{1,}}").fillUri(nameProvider.parametersFor(method), 30L); assertThat(uri, is(equalTo("/clients/30"))); } @Test public void shouldTranslatePatternArgsWithMultipleRegexes() throws Exception { Method method = Controller.class.getDeclaredMethod("mregex", String.class, String.class, String.class); String uri = getDefaultParameterControlForUrl("/test/{hash1:[a-z0-9]{16}}{id}{hash2:[a-z0-9]{16}}/") .fillUri(nameProvider.parametersFor(method), "0123456789abcdef", "1234", "fedcba9876543210"); assertThat(uri, is(equalTo("/test/0123456789abcdef1234fedcba9876543210/"))); } @Test public void shouldTranslatePatternArgNullAsEmpty() throws Exception { Method method = Controller.class.getDeclaredMethod("store", Client.class); String uri = getDefaultParameterControlForUrl("/clients/{client.id}") .fillUri(nameProvider.parametersFor(method), client(null)); assertThat(uri, is(equalTo("/clients/"))); } @Test public void shouldUseConverterIfItExists() throws Exception { Method method = Controller.class.getDeclaredMethod("store", Client.class); when(converters.existsTwoWayFor(Client.class)).thenReturn(true); when(converters.twoWayConverterFor(Client.class)).thenReturn(converter); when(converter.convert(any(Client.class))).thenReturn("john"); String uri = getDefaultParameterControlForUrl("/clients/{client}") .fillUri(nameProvider.parametersFor(method), client(null)); assertThat(uri, is(equalTo("/clients/john"))); } @Test public void shouldTranslatePatternArgInternalNullAsEmpty() throws Exception { Method method = Controller.class.getDeclaredMethod("store", Client.class); String uri = getDefaultParameterControlForUrl("/clients/{client.child.id}") .fillUri(nameProvider.parametersFor(method), client(null)); assertThat(uri, is(equalTo("/clients/"))); } @Test public void shouldMatchPatternLazily() throws Exception { DefaultParametersControl wrong = getDefaultParameterControlForUrl("/clients/{client.id}/"); DefaultParametersControl right = getDefaultParameterControlForUrl("/clients/{client.id}/subtask/"); String uri = "/clients/3/subtask/"; assertThat(wrong.matches(uri), is(false)); assertThat(right.matches(uri), is(true)); } @Test public void shouldMatchMoreThanOneVariable() throws Exception { DefaultParametersControl control = getDefaultParameterControlForUrl("/clients/{client.id}/subtask/{task.id}/"); assertThat(control.matches("/clients/3/subtask/5/"), is(true)); } private Client client(Long id) { return new Client(id); } @Test public void shouldBeGreedyWhenIPutAnAsteriskOnExpression() throws Exception { DefaultParametersControl control = getDefaultParameterControlForUrl("/clients/{pathToFile*}"); assertThat(control.matches("/clients/my/path/to/file/"), is(true)); } @Test public void shouldNotBeGreedyAtPatternCompiling() throws Exception { DefaultParametersControl control = getDefaultParameterControlForUrl("/project/{project.name}/build/{buildId}/view/{filename*}"); String uri = "/project/Vraptor3/build/12345/view/artifacts/vraptor.jar"; assertThat(control.matches(uri), is(true)); control.fillIntoRequest(uri, request); verify(request).setParameter("project.name", "Vraptor3"); verify(request).setParameter("filename", new String[] {"artifacts/vraptor.jar"}); verify(request).setParameter("buildId", new String[] {"12345"}); assertThat(control.apply(new String[] {"Vraptor3", "12345", "artifacts/vraptor.jar"}), is(uri)); } @Test public void registerExtraParametersFromAcessedUrlWithGreedyParameters() throws SecurityException, NoSuchMethodException { DefaultParametersControl control = getDefaultParameterControlForUrl("/clients/{pathToFile*}"); control.fillIntoRequest("/clients/my/path/to/file", request); verify(request).setParameter("pathToFile", new String[] {"my/path/to/file"}); } @Test public void registerExtraParametersFromAcessedUrlWithGreedyAndDottedParameters() throws SecurityException, NoSuchMethodException { DefaultParametersControl control = getDefaultParameterControlForUrl("/clients/{path.to.file*}"); control.fillIntoRequest("/clients/my/path/to/file", request); verify(request).setParameter("path.to.file", new String[] {"my/path/to/file"}); } static class PathToFile { public void withPath(String pathToFile) { } } @Test public void fillURLWithGreedyParameters() throws SecurityException, NoSuchMethodException { when(encodingHandler.getEncoding()).thenReturn(null); DefaultParametersControl control = getDefaultParameterControlForUrl("/clients/{pathToFile*}"); Method method = Controller.class.getDeclaredMethod("pathToFile", String.class); String filled = control.fillUri(nameProvider.parametersFor(method), "my/path/to/file"); assertThat(filled, is("/clients/my/path/to/file")); } @Test public void fillURLWithoutGreedyParameters() throws SecurityException, NoSuchMethodException { when(encodingHandler.getEncoding()).thenReturn(null); DefaultParametersControl control = getDefaultParameterControlForUrl("/clients/{pathToFile}"); Method method = Controller.class.getDeclaredMethod("pathToFile", String.class); String filled = control.fillUri(nameProvider.parametersFor(method), "my/path/to/file"); assertThat(filled, is("/clients/my/path/to/file")); } @Test public void whenNoParameterPatternsAreGivenShouldMatchAnything() throws Exception { ParametersControl control = new DefaultParametersControl("/any/{aParameter}/what", Collections.<String,String>emptyMap(), converters, evaluator,encodingHandler); assertTrue(control.matches("/any/ICanPutAnythingInHere/what")); } @Test public void whenParameterPatternsAreGivenShouldMatchAccordingToGivenPatterns() throws Exception { ParametersControl control = new DefaultParametersControl("/any/{aParameter}/what", Collections.singletonMap("aParameter", "aaa\\d{3}bbb"), converters, evaluator,encodingHandler); assertFalse(control.matches("/any/ICantPutAnythingInHere/what")); assertFalse(control.matches("/any/aaa12bbb/what")); assertTrue(control.matches("/any/aaa123bbb/what")); } @Test public void shouldFillRequestWhenAPatternIsSpecified() throws Exception { DefaultParametersControl control = new DefaultParametersControl("/project/{project.id}/build/", Collections.singletonMap("project.id", "\\d+"), converters, evaluator,encodingHandler); String uri = "/project/15/build/"; assertThat(control.matches(uri), is(true)); control.fillIntoRequest(uri, request); verify(request).setParameter("project.id", "15"); assertThat(control.apply(new String[] {"15"}),is(uri)); } @Test public void shouldDecodeUriParameters() throws Exception { DefaultParametersControl control = getDefaultParameterControlForUrl("/clients/{name}"); control.fillIntoRequest("/clients/Joao+Leno", request); verify(request).setParameter("name", "Joao Leno"); control.fillIntoRequest("/clients/Paulo%20Macartinei", request); verify(request).setParameter("name", "Paulo Macartinei"); } @Test public void shouldEncodeUriParameters() throws Exception { Method method = Controller.class.getDeclaredMethod("lang", String.class); when(encodingHandler.getEncoding()).thenReturn("UTF-8"); String uri = getDefaultParameterControlForUrl("/language/{lang}/about") .fillUri(nameProvider.parametersFor(method), "c#"); assertThat(uri, is(equalTo("/language/c%23/about"))); } public static class Controller { void lang(String lang) {} void show(Long id) {} void store(Client client) {} void pathToFile(String pathToFile) {} void mregex(String hash1, String id, String hash2) {} } }