/* * Copyright (c) 2014. Escalon System-Entwicklung, Dietrich Schulten * * 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 de.escalon.hypermedia.spring; import de.escalon.hypermedia.affordance.ActionDescriptor; import de.escalon.hypermedia.affordance.ActionInputParameter; import de.escalon.hypermedia.affordance.Affordance; import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockServletContext; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; public class AffordanceBuilderTest { @Before public void setUp() { MockHttpServletRequest request = MockMvcRequestBuilders.get("http://example.com/") .buildRequest(new MockServletContext()); final RequestAttributes requestAttributes = new ServletRequestAttributes(request); RequestContextHolder.setRequestAttributes(requestAttributes); } public static class Thing { } enum EventStatusType { EVENT_POSTPONED, EVENT_RESCHEDULED, EVENT_SCHEDULED, EVENT_CANCELLED } public static class DummyController { @RequestMapping("/things") public ResponseEntity createThing(@RequestBody Thing thing) { return new ResponseEntity(HttpStatus.CREATED); } @RequestMapping(value = "/things/{id}/eventStatus", method = RequestMethod.PUT) public ResponseEntity updateThing(@PathVariable int id, @RequestParam EventStatusType eventStatus) { return new ResponseEntity(HttpStatus.OK); } @RequestMapping(value = "/things/{id}", method = RequestMethod.PUT) public ResponseEntity updateThing(@PathVariable int id, @RequestBody Thing thing) { return new ResponseEntity(HttpStatus.OK); } } @Test public void testWithSingleRel() throws Exception { final Affordance affordance = AffordanceBuilder.linkTo(AffordanceBuilder.methodOn(DummyController.class) .createThing(new Thing())) .rel("next") .build(); Assert.assertEquals("Link: <http://example.com/things>; rel=\"next\"", affordance.toString()); } @Test public void testWithTitle() { final Affordance affordance = AffordanceBuilder.linkTo(AffordanceBuilder.methodOn(DummyController.class) .createThing(new Thing())) .withTitle("my-title") .rel("next") .build(); Assert.assertEquals("Link: <http://example.com/things>; rel=\"next\"; title=\"my-title\"", affordance.toString()); } @Test public void testWithTitleStar() { final Affordance affordance = AffordanceBuilder.linkTo(AffordanceBuilder.methodOn(DummyController.class) .createThing(new Thing())) .withTitleStar("UTF-8'de'n%c3%a4chstes%20Kapitel") .rel("next") .build(); Assert.assertEquals("Link: <http://example.com/things>; rel=\"next\"; " + "title*=\"UTF-8'de'n%c3%a4chstes%20Kapitel\"", affordance.toString()); } @Test public void testWithAnchor() { final Affordance affordance = AffordanceBuilder.linkTo(AffordanceBuilder.methodOn(DummyController.class) .createThing(new Thing())) .withAnchor("http://api.example.com/api") .rel("next") .build(); Assert.assertEquals("Link: <http://example.com/things>; rel=\"next\"; anchor=\"http://api.example.com/api\"", affordance.toString()); } @Test public void testWithType() { final Affordance affordance = AffordanceBuilder.linkTo(AffordanceBuilder.methodOn(DummyController.class) .createThing(new Thing())) .withType("application/pdf") .rel("next") .build(); Assert.assertEquals("Link: <http://example.com/things>; rel=\"next\"; type=\"application/pdf\"", affordance.toString()); } @Test public void testWithMedia() { final Affordance affordance = AffordanceBuilder.linkTo(AffordanceBuilder.methodOn(DummyController.class) .createThing(new Thing())) .withMedia("qhd") .rel("next") .build(); Assert.assertEquals("Link: <http://example.com/things>; rel=\"next\"; media=\"qhd\"", affordance.toString()); } @Test public void testWithHreflang() { final Affordance affordance = AffordanceBuilder.linkTo(AffordanceBuilder.methodOn(DummyController.class) .createThing(new Thing())) .withHreflang("en-us") .withHreflang("de") .rel("next") .build(); Assert.assertEquals("Link: <http://example.com/things>; rel=\"next\"; hreflang=\"en-us\"; hreflang=\"de\"", affordance.toString()); } @Test public void testWithLinkParam() { final Affordance affordance = AffordanceBuilder.linkTo(AffordanceBuilder.methodOn(DummyController.class) .createThing(new Thing())) .withLinkParam("param1", "foo") .withLinkParam("param1", "bar") .withLinkParam("param2", "baz") .rel("next") .build(); Assert.assertEquals("Link: <http://example.com/things>; rel=\"next\"; param1=\"foo\"; param1=\"bar\"; " + "param2=\"baz\"", affordance.toString()); } @Test public void testActionDescriptorForRequestParams() { final Affordance affordance = AffordanceBuilder.linkTo(AffordanceBuilder.methodOn(DummyController.class) .updateThing(1, (EventStatusType) null)) .rel("eventStatus") .build(); Assert.assertEquals("Link-Template: <http://example.com/things/1/eventStatus{?eventStatus}>; " + "rel=\"eventStatus\"", affordance.toString()); final ActionDescriptor actionDescriptor = affordance.getActionDescriptors() .get(0); Assert.assertThat((EventStatusType[]) actionDescriptor.getActionInputParameter("eventStatus") .getPossibleValues(actionDescriptor), Matchers.arrayContainingInAnyOrder( EventStatusType.EVENT_CANCELLED, EventStatusType.EVENT_POSTPONED, EventStatusType.EVENT_RESCHEDULED, EventStatusType.EVENT_SCHEDULED)); Assert.assertEquals("updateThing", actionDescriptor.getActionName()); } @Test public void testActionDescriptorForRequestBody() { final Affordance affordance = AffordanceBuilder.linkTo(AffordanceBuilder.methodOn(DummyController.class) .updateThing(1, (Thing) null)) .rel("event") .build(); Assert.assertEquals("Link: <http://example.com/things/1>; rel=\"event\"", affordance.toString()); final ActionDescriptor actionDescriptor = affordance.getActionDescriptors() .get(0); final ActionInputParameter thingParameter = actionDescriptor.getRequestBody(); Assert.assertEquals("Thing", ((Class) thingParameter.getGenericParameterType()).getSimpleName()); Assert.assertThat(thingParameter.isRequestBody(), Matchers.is(true)); Assert.assertEquals("updateThing", actionDescriptor.getActionName()); } @Test public void testBuild() throws Exception { final Affordance affordance = AffordanceBuilder.linkTo(AffordanceBuilder.methodOn(DummyController.class) .createThing(new Thing())) .rel("next") .rel("thing") .build(); Assert.assertEquals("Link: <http://example.com/things>; rel=\"next thing\"", affordance.toString()); } @Test public void testBuildNoArgs() throws Exception { final Affordance affordance = AffordanceBuilder.linkTo(AffordanceBuilder.methodOn(DummyController.class) .createThing(new Thing())) .rel("next") .rel("thing") .reverseRel("reverted", "for-hal") .build(); Assert.assertEquals("Link: <http://example.com/things>; rel=\"next thing for-hal\"; rev=\"reverted\"", affordance.toString()); } @Test(expected = IllegalArgumentException.class) public void testRejectsEmptyRel() throws Exception { final Affordance affordance = AffordanceBuilder.linkTo(AffordanceBuilder.methodOn(DummyController.class) .createThing(new Thing())) .rel("") .build(); } @Test(expected = IllegalStateException.class) public void testRejectsMissingRel() throws Exception { final Affordance affordance = AffordanceBuilder.linkTo(AffordanceBuilder.methodOn(DummyController.class) .createThing(new Thing())) .build(); } @Test(expected = IllegalArgumentException.class) public void testRejectsNullRel() throws Exception { final Affordance affordance = AffordanceBuilder.linkTo(AffordanceBuilder.methodOn(DummyController.class) .createThing(new Thing())) .rel(null) .build(); } }