text: /***
   * 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.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.http.MutableRequest;
  
  import com.google.common.collect.ImmutableMap;
  
  public class DefaultParametersControlTest {
  
  	private @Mock MutableRequest request;
  	private @Mock Converters converters;
  	private @Mock TwoWayConverter converter;
  	private final Evaluator evaluator = new JavaEvaluator();
  
  	@Before
  	public void setup() {
  		MockitoAnnotations.initMocks(this);
  	}
  
  	@Test
  	public void registerExtraParametersFromAcessedUrl() throws SecurityException, NoSuchMethodException {
  		DefaultParametersControl control = new DefaultParametersControl("/clients/{dog.id}", converters, evaluator);
  		control.fillIntoRequest("/clients/45", request);
  		verify(request).setParameter("dog.id", new String[] {"45"});
  	}
  
  	@Test
  	public void registerParametersWithAsterisks() throws SecurityException, NoSuchMethodException {
  		DefaultParametersControl control = new DefaultParametersControl("/clients/{my.path*}", converters, evaluator);
  		control.fillIntoRequest("/clients/one/path", request);
  		verify(request).setParameter("my.path", new String[] {"one/path"});
  	}
  
  	@Test
  	public void registerParametersWithRegexes() throws SecurityException, NoSuchMethodException {
  		DefaultParametersControl control = new DefaultParametersControl("/clients/{hexa:[0-9A-Z]+}", converters, evaluator);
  
  		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);
  
  		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 = new DefaultParametersControl("/clients/{dog.id}", converters, evaluator);
  		assertThat(control.matches("/clients/15"), is(equalTo(true)));
  	}
  
  	@Test
  	public void worksWithBasicRegexEvaluation() throws SecurityException, NoSuchMethodException {
  		DefaultParametersControl control = new DefaultParametersControl("/clients.*", converters, evaluator);
  		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() {
  		String uri = new DefaultParametersControl("/clients/.*", converters, evaluator).fillUri(new String[] {"client"}, client(3L));
  		assertThat(uri, is(equalTo("/clients/")));
  	}
  
  	@Test
  	public void shouldTranslatePatternArgs() {
  	String uri = new DefaultParametersControl("/clients/{client.id}", converters, evaluator).fillUri(new String[] {"client"}, client(3L));
  	assertThat(uri, is(equalTo("/clients/3")));
  	}
  
  	@Test
  	public void shouldTranslatePatternArgsWithRegex() {
  	String uri = new DefaultParametersControl("/clients/{id:[0-9]{1,}}", converters, evaluator).fillUri(new String[] {"id"}, 30L);
  	assertThat(uri, is(equalTo("/clients/30")));
  	}
  
  	@Test
  	public void shouldTranslatePatternArgsWithMultipleRegexes() {
  	String uri = new DefaultParametersControl("/test/{hash1:[a-z0-9]{16}}{id}{hash2:[a-z0-9]{16}}/", converters, evaluator).fillUri(new String[] {"hash1", "id", "hash2"}, "0123456789abcdef", "1234", "fedcba9876543210");
  	assertThat(uri, is(equalTo("/test/0123456789abcdef1234fedcba9876543210/")));
  	}
  	
  	@Test
  	public void shouldTranslatePatternArgNullAsEmpty() {
  		String uri = new DefaultParametersControl("/clients/{client.id}", converters, evaluator).fillUri(new String[] {"client"}, client(null));
  		assertThat(uri, is(equalTo("/clients/")));
  	}
  
  	@Test
  	public void shouldUseConverterIfItExists() {
  		when(converters.existsTwoWayFor(Client.class)).thenReturn(true);
  		when(converters.twoWayConverterFor(Client.class)).thenReturn(converter);
  		when(converter.convert(any(Client.class))).thenReturn("john");
  
  		String uri = new DefaultParametersControl("/clients/{client}", converters, evaluator).fillUri(new String[] {"client"}, client(null));
  		assertThat(uri, is(equalTo("/clients/john")));
  
  	}
  
  	@Test
  	public void shouldTranslatePatternArgInternalNullAsEmpty() {
  		String uri = new DefaultParametersControl("/clients/{client.child.id}", converters, evaluator) .fillUri(new String[] {"client"}, client(null));
  		assertThat(uri, is(equalTo("/clients/")));
  	}
  
  	@Test
  	public void shouldMatchPatternLazily() throws Exception {
  		DefaultParametersControl wrong = new DefaultParametersControl("/clients/{client.id}/", converters, evaluator);
  		DefaultParametersControl right = new DefaultParametersControl("/clients/{client.id}/subtask/", converters, evaluator);
  		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 = new DefaultParametersControl("/clients/{client.id}/subtask/{task.id}/", converters, evaluator);
  
  		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 = new DefaultParametersControl("/clients/{pathToFile*}", converters, evaluator);
  
  		assertThat(control.matches("/clients/my/path/to/file/"), is(true));
  	}
  	@Test
  	public void shouldNotBeGreedyAtPatternCompiling() throws Exception {
  		DefaultParametersControl control = new DefaultParametersControl("/project/{project.name}/build/{buildId}/view/{filename*}", converters, evaluator);
  
  		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 = new DefaultParametersControl("/clients/{pathToFile*}", converters, evaluator);
  
  		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 = new DefaultParametersControl("/clients/{path.to.file*}", converters, evaluator);
  
  		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 {
  		DefaultParametersControl control = new DefaultParametersControl("/clients/{pathToFile*}", converters, evaluator);
  
  		String filled = control.fillUri(new String[] {"pathToFile"}, "my/path/to/file");
  
  		assertThat(filled, is("/clients/my/path/to/file"));
  	}
  	@Test
  	public void fillURLWithoutGreedyParameters() throws SecurityException, NoSuchMethodException {
  		DefaultParametersControl control = new DefaultParametersControl("/clients/{pathToFile}", converters, evaluator);
  
  		String filled = control.fillUri(new String[] {"pathToFile"}, "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);
  		assertTrue(control.matches("/any/ICanPutAnythingInHere/what"));
  	}
  	@Test
  	public void whenParameterPatternsAreGivenShouldMatchAccordingToGivenPatterns() throws Exception {
  		ParametersControl control = new DefaultParametersControl("/any/{aParameter}/what",
  				new ImmutableMap.Builder<String, String>().put("aParameter", "aaa\\d{3}bbb").build(), converters, evaluator);
  		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/",
  				new ImmutableMap.Builder<String, String>().put("project.id", "\\d+").build(), converters, evaluator);
  
  		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 = new DefaultParametersControl("/clients/{name}", converters, evaluator);
  
  		control.fillIntoRequest("/clients/Joao+Leno", request);
  
  		verify(request).setParameter("name", "Joao Leno");
  
  		control.fillIntoRequest("/clients/Paulo%20Macartinei", request);
  
  		verify(request).setParameter("name", "Paulo Macartinei");
  	}
  
  }
  