/*
* Copyright 2013 ArcBees Inc.
*
* 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 com.gwtplatform.mvp.shared.proxy;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jukito.JukitoModule;
import org.jukito.JukitoRunner;
import org.jukito.TestSingleton;
import org.junit.Test;
import org.junit.runner.RunWith;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject;
import com.gwtplatform.common.shared.UrlUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
/**
* Unit tests for {@link com.gwtplatform.mvp.shared.proxy.RouteTokenFormatter}.
*/
@RunWith(JukitoRunner.class)
public class RouteTokenFormatterTest {
public static class Module extends JukitoModule {
@Override
protected void configureTest() {
bind(UrlUtils.class).to(UrlUtilsTestImpl.class).in(TestSingleton.class);
bind(PlaceTokenRegistry.class).to(PlaceTokenRegistryTestImpl.class).in(TestSingleton.class);
}
}
static class UrlUtilsTestImpl implements UrlUtils {
@Override
public String decodePathSegment(final String encodedPathSegment) {
return decode(encodedPathSegment);
}
@Override
public String decodeQueryString(final String encodedUrlComponent) {
return decode(encodedUrlComponent);
}
@Override
public String decodeMatrixParameter(String encodedMatrixParameter) {
return decode(encodedMatrixParameter);
}
@Override
public String encodePathSegment(final String decodedPathSegment) {
return encode(decodedPathSegment);
}
@Override
public String encodeQueryString(final String decodedUrlComponent) {
return encode(decodedUrlComponent);
}
@Override
public String encodeMatrixParameter(String decodedMatrixParameter) {
return encodePathSegment(decodedMatrixParameter);
}
private String decode(String encodedPathSegment) {
try {
return URLDecoder.decode(encodedPathSegment, "UTF-8");
} catch (final UnsupportedEncodingException e) {
// THIS won't happen
return null;
}
}
private String encode(String decodedPathSegment) {
try {
return URLEncoder.encode(decodedPathSegment, "UTF-8");
} catch (final UnsupportedEncodingException e) {
// THIS won't happen
return null;
}
}
}
static class PlaceTokenRegistryTestImpl implements PlaceTokenRegistry {
@Override
public Set<String> getAllPlaceTokens() {
return ImmutableSet.<String>builder()
.add("/user/{userId}/groups/{groupId}")
.add("/user/{userId}/albums/{albumId}")
.add("/user/{userId}/albums/staticAlbumId")
.add("/user/staticUserId/albums/{albumId}")
.add("/user/staticUserId/albums/staticAlbumId")
.add("/{vanityId}")
.add("!/crawl/{vanityId}")
.add("/privacy")
.add("/")
.build();
}
}
@Inject
RouteTokenFormatter tokenFormatter;
@Test
public void testToPlaceTokenWithoutQueryString() {
// Given
PlaceRequest placeRequest = new PlaceRequest.Builder()
.nameToken("/user/{userId}/albums/{albumId}")
.with("userId", "0x42")
.with("albumId", "0xAFFE")
.build();
String expectedPlacePattern = "^\\/user\\/0x42\\/albums\\/0xAFFE$";
Map<String, String> expectedQueryParameters = null;
// When
String placeToken = tokenFormatter.toPlaceToken(placeRequest);
Map<String, String> queryParameters = (placeToken.indexOf('?') != -1) ? tokenFormatter.parseQueryString(
placeToken.substring(placeToken.indexOf('?') + 1), null) : null;
// Then
assertTrue(placeToken.matches(expectedPlacePattern));
assertEquals(expectedQueryParameters, queryParameters);
}
@Test
public void testToPlaceTokenWithEmbeddedUrlUnsafeParam() {
// Given
PlaceRequest placeRequest = new PlaceRequest.Builder()
.nameToken("/user/{userId}/albums/{albumId}")
.with("userId", "Two Words")
.with("albumId", "Then Three Words")
.build();
String expectedPlacePattern = "/user/Two+Words/albums/Then+Three+Words";
// When
String placeToken = tokenFormatter.toPlaceToken(placeRequest);
// Then
assertTrue(placeToken.equals(expectedPlacePattern));
// And in reverse
PlaceRequest placeRequest1 = tokenFormatter.toPlaceRequest(placeToken);
assertEquals(placeRequest1.getParameter("userId", ""), "Two Words");
}
@Test
public void testToPlaceTokenWithOneQueryStringParameter() {
// Given
PlaceRequest placeRequest = new PlaceRequest.Builder()
.nameToken("/user/{userId}/albums/{albumId}")
.with("userId", "0x42")
.with("albumId", "0xAFFE")
.with("start", "0")
.build();
String expectedPlacePattern = "^\\/user\\/0x42\\/albums\\/0xAFFE\\?\\w*=\\d*$";
Map<String, String> expectedQueryParameters = ImmutableMap.<String, String>builder().put("start", "0").build();
// When
String placeToken = tokenFormatter.toPlaceToken(placeRequest);
Map<String, String> queryParameters = (placeToken.indexOf('?') != -1) ? tokenFormatter.parseQueryString(
placeToken.substring(placeToken.indexOf('?') + 1), null) : null;
// Then
assertTrue(placeToken.matches(expectedPlacePattern));
assertEquals(expectedQueryParameters, queryParameters);
}
@Test
public void testToPlaceTokenWithSeveralQueryStringParameter() {
// Given
PlaceRequest placeRequest = new PlaceRequest.Builder()
.nameToken("/user/{userId}/albums/{albumId}")
.with("userId", "0x42")
.with("albumId", "0xAFFE")
.with("start", "15")
.with("limit", "20")
.build();
String expectedPlacePattern = "^\\/user\\/0x42\\/albums\\/0xAFFE\\?\\w*=\\d*&\\w*=\\d*$";
Map<String, String> expectedQueryParameters = ImmutableMap.<String, String>builder()
.put("start", "15")
.put("limit", "20")
.build();
// When
String placeToken = tokenFormatter.toPlaceToken(placeRequest);
Map<String, String> queryParameters = (placeToken.indexOf('?') != -1) ? tokenFormatter.parseQueryString(
placeToken.substring(placeToken.indexOf('?') + 1), null) : null;
// Then
assertTrue(placeToken.matches(expectedPlacePattern));
assertEquals(expectedQueryParameters, queryParameters);
}
@Test
public void testToHistoryToken() {
tokenFormatter = spy(tokenFormatter);
// Given
PlaceRequest placeRequest = new PlaceRequest.Builder().nameToken("token").build();
List<PlaceRequest> placeRequestHierarchy = ImmutableList.<PlaceRequest>builder().add(placeRequest).build();
// When
tokenFormatter.toHistoryToken(placeRequestHierarchy);
// Then
verify(tokenFormatter).toPlaceToken(placeRequest);
}
@Test
public void testToPlaceRequestStaticVsParameterMatch() {
// When
PlaceRequest placeRequest01 = tokenFormatter.toPlaceRequest("/user/0x42/albums/0xAFFE");
PlaceRequest placeRequest02 = tokenFormatter.toPlaceRequest("/user/staticUserId/albums/staticAlbumId");
PlaceRequest placeRequest03 = tokenFormatter.toPlaceRequest("/user/0x42/albums/staticAlbumId");
PlaceRequest placeRequest04 = tokenFormatter.toPlaceRequest("/user/staticUserId/albums/0xAFFE");
PlaceRequest placeRequest05 = tokenFormatter.toPlaceRequest("/privacy");
PlaceRequest placeRequest06 = tokenFormatter.toPlaceRequest("/vanity");
PlaceRequest placeRequest07 = tokenFormatter.toPlaceRequest("/user/0x42/albums/0xAFFE?start=0");
PlaceRequest placeRequest08 = tokenFormatter.toPlaceRequest("/vanity?a=valueA&b=valueB");
PlaceRequest placeRequest09 = tokenFormatter.toPlaceRequest("vanity?a=valueA&b=valueB");
PlaceRequest placeRequest10 = tokenFormatter.toPlaceRequest("!/crawl/vanity");
PlaceRequest placeRequest11 = tokenFormatter.toPlaceRequest("!/crawl/vanity?a=valueA&b=valueB");
// Then
assertEquals("/user/{userId}/albums/{albumId}", placeRequest01.getNameToken());
assertEquals(2, placeRequest01.getParameterNames().size());
assertEquals("0x42", placeRequest01.getParameter("userId", null));
assertEquals("0xAFFE", placeRequest01.getParameter("albumId", null));
assertEquals("/user/staticUserId/albums/staticAlbumId", placeRequest02.getNameToken());
assertEquals(0, placeRequest02.getParameterNames().size());
assertEquals("/user/{userId}/albums/staticAlbumId", placeRequest03.getNameToken());
assertEquals(1, placeRequest03.getParameterNames().size());
assertEquals("0x42", placeRequest03.getParameter("userId", null));
assertEquals("/user/staticUserId/albums/{albumId}", placeRequest04.getNameToken());
assertEquals(1, placeRequest04.getParameterNames().size());
assertEquals("0xAFFE", placeRequest04.getParameter("albumId", null));
assertEquals("/privacy", placeRequest05.getNameToken());
assertEquals(0, placeRequest05.getParameterNames().size());
assertEquals("/{vanityId}", placeRequest06.getNameToken());
assertEquals(1, placeRequest06.getParameterNames().size());
assertEquals("vanity", placeRequest06.getParameter("vanityId", null));
assertEquals("/user/{userId}/albums/{albumId}", placeRequest07.getNameToken());
assertEquals(3, placeRequest07.getParameterNames().size());
assertEquals("0x42", placeRequest07.getParameter("userId", null));
assertEquals("0xAFFE", placeRequest07.getParameter("albumId", null));
assertEquals("0", placeRequest07.getParameter("start", null));
assertEquals("/{vanityId}", placeRequest08.getNameToken());
assertEquals(3, placeRequest08.getParameterNames().size());
assertEquals("vanity", placeRequest08.getParameter("vanityId", null));
assertEquals("valueA", placeRequest08.getParameter("a", null));
assertEquals("valueB", placeRequest08.getParameter("b", null));
assertEquals("/{vanityId}", placeRequest09.getNameToken());
assertEquals(3, placeRequest09.getParameterNames().size());
assertEquals("vanity", placeRequest09.getParameter("vanityId", null));
assertEquals("valueA", placeRequest09.getParameter("a", null));
assertEquals("valueB", placeRequest09.getParameter("b", null));
assertEquals("!/crawl/{vanityId}", placeRequest10.getNameToken());
assertEquals(1, placeRequest10.getParameterNames().size());
assertEquals("vanity", placeRequest10.getParameter("vanityId", null));
assertEquals("!/crawl/{vanityId}", placeRequest11.getNameToken());
assertEquals(3, placeRequest11.getParameterNames().size());
assertEquals("vanity", placeRequest10.getParameter("vanityId", null));
assertEquals("valueA", placeRequest11.getParameter("a", null));
assertEquals("valueB", placeRequest11.getParameter("b", null));
}
@Test
public void testToPlaceRequestEmptyRoute() {
// When
PlaceRequest placeRequest10 = tokenFormatter.toPlaceRequest("/");
PlaceRequest placeRequest11 = tokenFormatter.toPlaceRequest("/?a=valueA&b=valueB");
PlaceRequest placeRequest12 = tokenFormatter.toPlaceRequest("");
PlaceRequest placeRequest13 = tokenFormatter.toPlaceRequest("?a=valueA&b=valueB");
// Then
assertEquals("/", placeRequest10.getNameToken());
assertEquals(0, placeRequest10.getParameterNames().size());
assertEquals("/", placeRequest11.getNameToken());
assertEquals(2, placeRequest11.getParameterNames().size());
assertEquals("valueA", placeRequest11.getParameter("a", null));
assertEquals("valueB", placeRequest11.getParameter("b", null));
assertEquals("/", placeRequest12.getNameToken());
assertEquals(0, placeRequest12.getParameterNames().size());
assertEquals("/", placeRequest13.getNameToken());
assertEquals(2, placeRequest13.getParameterNames().size());
assertEquals("valueA", placeRequest13.getParameter("a", null));
assertEquals("valueB", placeRequest13.getParameter("b", null));
}
public void testToPlaceRequestNotExistingRoute() {
// When
PlaceRequest placeRequest13 = tokenFormatter.toPlaceRequest("/not/existing");
PlaceRequest placeRequest14 = tokenFormatter.toPlaceRequest("/not/existing?a=valueA&b=valueB");
PlaceRequest placeRequest15 = tokenFormatter.toPlaceRequest("not/existing");
// Then
assertEquals("/not/existing", placeRequest13.getNameToken());
assertEquals(0, placeRequest13.getParameterNames().size());
assertEquals("/not/existing", placeRequest14.getNameToken());
assertEquals(2, placeRequest14.getParameterNames().size());
assertEquals("valueA", placeRequest14.getParameter("a", null));
assertEquals("valueB", placeRequest14.getParameter("b", null));
assertEquals("/not/existing", placeRequest15.getNameToken());
assertEquals(0, placeRequest15.getParameterNames().size());
}
@Test
public void testToPlaceRequestHierarchy() {
tokenFormatter = spy(tokenFormatter);
// Given
String historyToken = "token";
// When
tokenFormatter.toPlaceRequestHierarchy(historyToken);
// Then
verify(tokenFormatter).toPlaceRequest(historyToken);
}
}