/******************************************************************************* * Copyright 2013 Ivan Shubin http://mindengine.net * * 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 net.mindengine.blogix.tests.acceptance; import static net.mindengine.blogix.tests.TestGroups.ACCEPTANCE; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.mindengine.blogix.Blogix; import net.mindengine.blogix.components.MockedController; import net.mindengine.blogix.web.routes.ControllerDefinition; import net.mindengine.blogix.web.routes.Route; import net.mindengine.blogix.web.routes.RouteParserException; import net.mindengine.blogix.web.routes.RouteProviderDefinition; import net.mindengine.blogix.web.routes.RouteURL; import net.mindengine.blogix.web.routes.RoutesContainer; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import providers.DefaultMockedProvider; import controllers.DefaultMockedController; @Test(groups=ACCEPTANCE) public class RoutesContainerAccTest { private static final String[] DEFAULT_PROVIDER_PACKAGES = new String[]{"providers"}; private static final String[] DEFAULT_CONTROLLER_PACKAGES = new String[]{"controllers"}; private static final String BASE_TEST = "shouldLoadFromSpecifiedFile"; RoutesContainer container; @BeforeClass public void initialize() { container = new RoutesContainer(Blogix.defaultClassLoaders()); } @Test public void shouldLoadFromSpecifiedFile() throws URISyntaxException, IOException { container.load(new File(getClass().getResource("/routes-test.cfg").toURI()), DEFAULT_CONTROLLER_PACKAGES, DEFAULT_PROVIDER_PACKAGES); assertThat("Routes list should be not null", container.getRoutes(), is(notNullValue())); assertThat("Routes list should contain 7 routes", container.getRoutes().size(), is(7)); } @Test(dependsOnMethods = BASE_TEST) public void shouldIgnoreCommentsFollowingByHash() throws Exception { for ( Route route : container.getRoutes() ) { if ( route.getUrl().getUrlPattern().startsWith("/commented")) { throw new Exception("Commented route was processed as normal"); } } } @Test(dependsOnMethods = BASE_TEST) public void shouldParseSimpleRoutesUrl() { assertThat( urlInRoute(0).getUrlPattern(), is("/")); assertThat( urlInRoute(1).getUrlPattern(), is("/another/route")); assertThat( urlInRoute(2).getUrlPattern(), is("/another/route2")); assertThat( urlInRoute(4).getUrlPattern(), is("/simple/view/route/")); assertThat( urlInRoute(0).getParameters(), is( empty() )); assertThat( urlInRoute(1).getParameters(), is( empty() )); assertThat( urlInRoute(2).getParameters(), is( empty() )); assertThat( urlInRoute(4).getParameters(), is( empty() )); } @Test(dependsOnMethods = BASE_TEST) public void shouldParseSimpleRouteWithoutController() { assertThat( controllerInRoute(4), is (nullValue())); assertThat( viewNameInRoute(4), is ("some-simple-view")); } @Test(dependsOnMethods = BASE_TEST) public void shouldParseRouteWithoutView() { assertThat( urlInRoute(5).getUrlPattern(), is ("/viewless")); assertThat( viewNameInRoute(5), is (nullValue())); } @SuppressWarnings("unchecked") @Test(dependsOnMethods = BASE_TEST) public void shouldParse_basicModelParameters_forEachRoute() { assertThat(modelInRoute(6), allOf(hasEntry("title", (Object)"Title value"))); assertThat(modelInRoute(6), allOf(hasEntry("longNumber", (Object)new Long(123)))); assertThat(modelInRoute(6), allOf(hasEntry("double", (Object)(1231.3412)))); assertThat(modelInRoute(6), allOf(hasEntry("doubleMinus", (Object)(-1.3)))); } @Test(dependsOnMethods = BASE_TEST) public void shouldGenerateRegexPatternOnlyOnce () { for ( int i = 0; i < 4; i++) { Pattern pattern = urlInRoute(i).asRegexPattern(); assertThat( pattern, is ( notNullValue() )); assertThat( urlInRoute(i).asRegexPattern(), is ( pattern )); } } @Test(dependsOnMethods = BASE_TEST, dataProvider="provideRegexCheckSamples") public void shouldGenerateProperRegexPatterns(String urlSample, boolean expectedToMatch) { Matcher matcher = urlInRoute(3).asRegexPattern().matcher(urlSample); if ( expectedToMatch ) { assertThat( urlSample + " text does not match the parameterized route regex pattern: " + urlInRoute(3).getUrlPattern() , matcher.matches(), is (true)); } else assertThat( urlSample + " text matches the parameterized route regex pattern but it should not: " + urlInRoute(3).getUrlPattern(), matcher.matches(), is (false)); } @DataProvider public Object[][] provideRegexCheckSamples() { return new Object[][]{ {"/parameterized/rout/abc/gap/qwe/", true}, {"/parameterized/rout/ab.c/gap/qwe/", true}, {"/parameterized/rout/ab/c/gap/qwe/", false}, {"/parameterized/rout/a/gap/q/", true}, {"/parameterized/rout/9/gap/qwe/", true}, {"/parameterized/rout/_c/gap/123/", true}, {"/parameterized/rout/_c/g/ap/123/", false}, {"/parameterized/rout/_-_/gap/11-/", true}, {"/rout/abc/gap/qwe/", false}}; } @Test(dependsOnMethods = BASE_TEST) public void shouldParseParameterizedRoute() { assertThat(urlInRoute(3).getUrlPattern(), is("/parameterized/rout/([a-zA-Z0-9_\\-\\.]*)/gap/([a-zA-Z0-9_\\-\\.]*)/")); assertThat(urlInRoute(3).getParameters(), is(list("param1","param2"))); } @Test(dependsOnMethods = BASE_TEST) public void shouldFindControllerClassInControllersPackageByDefault() { assertThat(controllerInRoute(0).getControllerClass().getName(), is(MockedController.class.getName())); assertThat(controllerInRoute(0).getControllerMethod().getName(), is ("someMethod")); assertThat(controllerInRoute(1).getControllerClass().getName(), is(DefaultMockedController.class.getName())); assertThat(controllerInRoute(1).getControllerMethod().getName(), is ("someMethod")); assertThat(controllerInRoute(2).getControllerClass().getName(), is(DefaultMockedController.class.getName())); assertThat(controllerInRoute(2).getControllerMethod().getName(), is ("someParameterizedMethod")); assertThat(controllerInRoute(3).getControllerClass().getName(), is(DefaultMockedController.class.getName())); assertThat(controllerInRoute(3).getControllerMethod().getName(), is ("someParameterizedMethod")); } @Test(dependsOnMethods = BASE_TEST) public void shouldParseMethodArgumentsInParameterizedController() { assertThat(controllerInRoute(0).getParameters(), is (empty())); assertThat(controllerInRoute(1).getParameters(), is (empty())); assertThat(controllerInRoute(2).getParameters(), is (empty())); assertThat(controllerInRoute(3).getParameters(), is(not(empty()))); assertThat(controllerInRoute(3).getParameters(), is(list("param1", "param2"))); } @Test(dependsOnMethods = BASE_TEST) public void shouldReadViewNameAfterController() { assertThat(viewNameInRoute(0), is("some-view-name")); assertThat(viewNameInRoute(1), is("some-view-name-2")); assertThat(viewNameInRoute(2), is("some-view-name-3")); assertThat(viewNameInRoute(3), is("some-view-name-4")); } @Test(dependsOnMethods = BASE_TEST) public void shouldReadProvider() { assertThat(providerInRoute(0), is(nullValue())); assertThat(providerInRoute(1), is(nullValue())); assertThat(providerInRoute(2), is(nullValue())); RouteProviderDefinition rpd = providerInRoute(3); assertThat(rpd, is(notNullValue())); assertThat(rpd.getProviderClass().getName(), is (DefaultMockedProvider.class.getName())); assertThat(rpd.getProviderMethod().getName(), is ("someProviderMethod")); } private RouteProviderDefinition providerInRoute(int index) { return container.getRoutes().get(index).getProvider(); } @Test( expectedExceptions=RouteParserException.class, expectedExceptionsMessageRegExp="Provider is not defined for parameterized route: /route/\\{param1\\}/and/\\{param2\\}") public void shouldGiveErrorIfParameterizedRouteDoesNotHaveProviderSpecified() throws IOException, URISyntaxException { new RoutesContainer(Blogix.defaultClassLoaders()).load(new File(getClass().getResource("/routes-no-provider-for-parametrized-route-error.cfg").toURI()), DEFAULT_CONTROLLER_PACKAGES, DEFAULT_PROVIDER_PACKAGES); } @Test(expectedExceptions=RouteParserException.class, expectedExceptionsMessageRegExp="Route url should start with /") public void shouldGiveErrorIfRouteDoesNotStartWithSlash () throws IOException, URISyntaxException { new RoutesContainer(Blogix.defaultClassLoaders()).load(new File(getClass().getResource("/routes-no-slash-url-error.cfg").toURI()), DEFAULT_CONTROLLER_PACKAGES, DEFAULT_PROVIDER_PACKAGES); } @Test (expectedExceptions=RouteParserException.class, expectedExceptionsMessageRegExp="Route url parameter 'param1' is not used in controller arguments for route: /route/\\{param1\\}/and/\\{param2\\}") public void shouldGiveErrorIfUrlParamsDoNotMatchWithControllerArguments() throws IOException, URISyntaxException { new RoutesContainer(Blogix.defaultClassLoaders()).load(new File(getClass().getResource("/routes-no-param-arg-match-error.cfg").toURI()), DEFAULT_CONTROLLER_PACKAGES, DEFAULT_PROVIDER_PACKAGES); } @Test (expectedExceptions=RouteParserException.class, expectedExceptionsMessageRegExp="Controller controllers.DefaultMockedController.voidMethod returns void type") public void shouldGiveErrorIfControllerMethodReturnsVoidType() throws IOException, URISyntaxException { new RoutesContainer(Blogix.defaultClassLoaders()).load(new File(getClass().getResource("/routes-void-controller-error.cfg").toURI()), DEFAULT_CONTROLLER_PACKAGES, DEFAULT_PROVIDER_PACKAGES); } @Test (expectedExceptions=RouteParserException.class, expectedExceptionsMessageRegExp="Provider providers.DefaultMockedProvider.someNonArrayMethod does not return Map\\[\\] type") public void shouldGiveErrorIfProviderMethodDoesNotReturnArrayOfMapType() throws IOException, URISyntaxException { new RoutesContainer(Blogix.defaultClassLoaders()).load(new File(getClass().getResource("/routes-non-list-provider-error.cfg").toURI()), DEFAULT_CONTROLLER_PACKAGES, DEFAULT_PROVIDER_PACKAGES); } @Test( expectedExceptions=RouteParserException.class, expectedExceptionsMessageRegExp="Non-parameterized route /some-route does not need a provider") public void shouldGiveErrorIfSimpleUrlHasAProvider() throws IOException, URISyntaxException { new RoutesContainer(Blogix.defaultClassLoaders()).load(new File(getClass().getResource("/routes-simple-url-with-provider-error.cfg").toURI()), DEFAULT_CONTROLLER_PACKAGES, DEFAULT_PROVIDER_PACKAGES); } @Test( expectedExceptions=RouteParserException.class, expectedExceptionsMessageRegExp="View is not defined for route: /url\nNo view is only allowed for controllers with return type File") public void shouldGiveErrorIfControllerAndViewAreNotDefined() throws IOException, URISyntaxException { new RoutesContainer(Blogix.defaultClassLoaders()).load(new File(getClass().getResource("/routes-no-controller-error.cfg").toURI()), DEFAULT_CONTROLLER_PACKAGES, DEFAULT_PROVIDER_PACKAGES); } @Test(expectedExceptions=RouteParserException.class, expectedExceptionsMessageRegExp="View is not defined for route: /url\nNo view is only allowed for controllers with return type File") public void shouldGiveErrorIfViewIsNotDefinedAndControllerDoesNotReturnFileType() throws IOException, URISyntaxException { new RoutesContainer(Blogix.defaultClassLoaders()).load(new File(getClass().getResource("/routes-no-view-error.cfg").toURI()), DEFAULT_CONTROLLER_PACKAGES, DEFAULT_PROVIDER_PACKAGES); } private ControllerDefinition controllerInRoute(int index) { return container.getRoutes().get(index).getController(); } private String viewNameInRoute(int index) { return container.getRoutes().get(index).getView(); } private RouteURL urlInRoute(int number) { return container.getRoutes().get(number).getUrl(); } private Map<String, Object> modelInRoute(int index) { return container.getRoutes().get(index).getModel(); } private List<String> list(String ... items) { List<String> list = new LinkedList<String>(); for ( String item : items ) { list.add(item); } return list; } }