/**
* Copyright (C) 2012-2017 the original author or authors.
*
* 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 ninja;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.when;
import ninja.utils.NinjaProperties;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import com.google.inject.Injector;
import com.google.inject.Provider;
import java.util.Collections;
import java.util.Map;
import ninja.ControllerMethods.ControllerMethod0;
import ninja.ControllerMethods.ControllerMethod1;
import ninja.params.Param;
import ninja.params.ParamParsers;
import ninja.utils.MethodReference;
import ninja.utils.NinjaBaseDirectoryResolver;
import ninja.validation.ValidationImpl;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.aMapWithSize;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* => Most tests are done via class RoutesTest in project
* ninja-servlet-integration-test.
*/
@RunWith(MockitoJUnitRunner.class)
public class RouterImplTest {
Router router;
@Mock
NinjaProperties ninjaProperties;
NinjaBaseDirectoryResolver ninjaBaseDirectoryResolver;
@Mock
Injector injector;
@Mock
Provider<TestController> testControllerProvider;
@Before
@SuppressWarnings("Convert2Lambda")
public void before() {
this.ninjaBaseDirectoryResolver = new NinjaBaseDirectoryResolver(ninjaProperties);
when(testControllerProvider.get()).thenReturn(new TestController());
when(injector.getProvider(TestController.class)).thenReturn(testControllerProvider);
when(injector.getInstance(ParamParsers.class)).thenReturn(new ParamParsers(Collections.emptySet()));
Provider<RouteBuilderImpl> routeBuilderImplProvider = mock(Provider.class);
when(routeBuilderImplProvider.get()).thenAnswer(
(invocation) -> new RouteBuilderImpl(ninjaProperties, ninjaBaseDirectoryResolver));
router = new RouterImpl(injector, ninjaProperties, routeBuilderImplProvider);
// add route:
router.GET().route("/testroute").with(TestController.class, "index");
router.GET().route("/user/{email}/{id: .*}").with(TestController.class, "user");
router.GET().route("/u{userId: .*}/entries/{entryId: .*}").with(TestController.class, "entry");
// second route to index should not break reverse routing matching the first
router.GET().route("/testroute/another_url_by_index").with(TestController.class, "index");
router.GET().route("/ref").with(new MethodReference(TestController.class, "ref"));
// functional interface / lambda routing
TestController testController1 = new TestController("Hi!");
router.GET().route("/any_instance_method_ref").with(TestController::home);
router.GET().route("/any_instance_method_ref_exception").with(TestController::exception);
router.GET().route("/any_instance_method_ref2").with(ControllerMethods.of(TestController::home));
router.GET().route("/specific_instance_method_ref").with(testController1::message);
router.GET().route("/specific_instance_method_ref_annotations").with(testController1::status);
router.GET().route("/anonymous_method_ref").with(() -> Results.status(202));
Result staticResult = Results.status(208);
router.GET().route("/anonymous_method_ref_captured").with(() -> staticResult);
router.GET().route("/anonymous_method_ref_context").with((Context context) -> Results.status(context.getParameterAsInteger("status")));
router.GET().route("/anonymous_class").with(new ControllerMethod0() {
@Override
public Result apply() {
return Results.status(203);
}
});
router.GET().route("/anonymous_class_annotations").with(new ControllerMethod1<Integer>() {
@Override
public Result apply(@Param("status") Integer status) {
return Results.status(status);
}
});
router.compileRoutes();
}
@Test
public void getPathParametersEncodedWithNoPathParams() {
Route route = router.getRouteFor("GET", "/testroute");
Map<String,String> pathParameters = route.getPathParametersEncoded("/testroute");
assertThat(pathParameters, aMapWithSize(0));
}
@Test
public void getReverseRouteWithNoContextPathWorks() {
String contextPath = "";
when(ninjaProperties.getContextPath()).thenReturn(contextPath);
String route = router.getReverseRoute(TestController.class, "index");
assertThat(route, is("/testroute"));
}
@Test
public void getReverseRouteContextPathWorks() {
String contextPath = "/myappcontext";
when(ninjaProperties.getContextPath()).thenReturn(contextPath);
String route = router.getReverseRoute(TestController.class, "index");
assertThat(route, is("/myappcontext/testroute"));
}
@Test
public void getReverseRouteWithRegexWorks() {
String contextPath = "";
when(ninjaProperties.getContextPath()).thenReturn(contextPath);
String route = router.getReverseRoute(
TestController.class,
"user",
"email",
"me@me.com",
"id",
10000);
assertThat(route, is("/user/me@me.com/10000"));
}
@Test
public void getReverseRouteWithRegexAndQueryParametersWorks() {
String contextPath = "";
when(ninjaProperties.getContextPath()).thenReturn(contextPath);
String route = router.getReverseRoute(
TestController.class,
"user",
"email",
"me@me.com",
"id",
10000,
"q",
"froglegs");
assertThat(route, equalTo("/user/me@me.com/10000?q=froglegs"));
}
@Test
public void getReverseRouteWithMultipleRegexWorks() {
String contextPath = "";
when(ninjaProperties.getContextPath()).thenReturn(contextPath);
String route = router.getReverseRoute(TestController.class, "entry", "userId", 1, "entryId", 100);
assertThat(route, equalTo("/u1/entries/100"));
}
@Test
public void getReverseRouteWithMethodReference() {
String contextPath = "";
when(ninjaProperties.getContextPath()).thenReturn(contextPath);
String route = router.getReverseRoute(TestController.class, "ref");
String route2 = router.getReverseRoute(new MethodReference(TestController.class, "ref"));
assertThat(route, is("/ref"));
assertThat(route2, is("/ref"));
}
@Test
public void routeForAnyInstanceMethodReference() {
Route route = router.getRouteFor("GET", "/any_instance_method_ref");
Result result = route.getFilterChain().next(null);
assertThat(result.getStatusCode(), is(201));
}
@Test
public void routeForAnyInstanceMethodReferenceThrowsException() {
Route route = router.getRouteFor("GET", "/any_instance_method_ref_exception");
try {
Result result = route.getFilterChain().next(null);
fail();
} catch (Exception e) {
assertThat(e.getCause().getMessage(), is("test"));
}
}
@Test
public void routeForAnyInstanceMethodReference2() {
Route route = router.getRouteFor("GET", "/any_instance_method_ref2");
Result result = route.getFilterChain().next(null);
assertThat(result.getStatusCode(), is(201));
}
@Test
public void routeForSpecificInstanceMethodReference() {
Route route = router.getRouteFor("GET", "/specific_instance_method_ref");
Result result = route.getFilterChain().next(null);
// message set on specific instance
assertThat(result.getRenderable(), is("Hi!"));
}
@Test
public void routeForSpecificInstanceMethodReferenceWithAnnotations() {
Context context = mock(Context.class);
when(context.getParameter("status")).thenReturn("207");
when(context.getValidation()).thenReturn(new ValidationImpl());
Route route = router.getRouteFor("GET", "/specific_instance_method_ref_annotations");
Result result = route.getFilterChain().next(context);
// message set on specific instance
assertThat(result.getStatusCode(), is(207));
assertThat(result.getRenderable(), is("Hi!"));
}
@Test
public void routeForAnonymoumsMethodReference() {
Route route = router.getRouteFor("GET", "/anonymous_method_ref");
Result result = route.getFilterChain().next(null);
assertThat(result.getStatusCode(), is(202));
}
@Test
public void routeForAnonymoumsMethodReferenceWithCaptured() {
Context context = mock(Context.class);
Route route = router.getRouteFor("GET", "/anonymous_method_ref_captured");
Result result = route.getFilterChain().next(context);
assertThat(result.getStatusCode(), is(208));
}
@Test
public void routeForAnonymoumsMethodReferenceWithContext() {
Context context = mock(Context.class);
when(context.getParameterAsInteger("status")).thenReturn(206);
Route route = router.getRouteFor("GET", "/anonymous_method_ref_context");
Result result = route.getFilterChain().next(context);
assertThat(result.getStatusCode(), is(206));
}
@Test
public void routeForAnonymoumsClassInstance() {
Route route = router.getRouteFor("GET", "/anonymous_class");
Result result = route.getFilterChain().next(null);
assertThat(result.getStatusCode(), is(203));
}
@Test
public void routeForAnonymoumsClassInstanceWithAnnotations() {
Context context = mock(Context.class);
when(context.getParameter("status")).thenReturn("205");
when(context.getValidation()).thenReturn(new ValidationImpl());
Route route = router.getRouteFor("GET", "/anonymous_class_annotations");
Result result = route.getFilterChain().next(context);
assertThat(result.getStatusCode(), is(205));
}
/**
* A dummy TestController for mocking.
*/
public static class TestController {
private final String message;
public TestController() {
this("not set");
}
public TestController(String message) {
this.message = message;
}
public Result index() {
return Results.ok();
}
public Result user() {
return Results.ok();
}
public Result entry() {
return Results.ok();
}
public Result ref() {
return Results.ok();
}
public Result home() {
return Results.status(201);
}
public Result message() {
return Results.ok().render(message);
}
public Result status(@Param("status") Integer status) {
return Results.status(status).render(message);
}
public Result exception() throws Exception {
throw new Exception("test");
}
}
}