diff --git a/backend/src/test/java/de/bund/digitalservice/ris/norms/adapter/input/restapi/controller/TableOfContentsControllerTest.java b/backend/src/test/java/de/bund/digitalservice/ris/norms/adapter/input/restapi/controller/TableOfContentsControllerTest.java new file mode 100644 index 000000000..cfc6d69ec --- /dev/null +++ b/backend/src/test/java/de/bund/digitalservice/ris/norms/adapter/input/restapi/controller/TableOfContentsControllerTest.java @@ -0,0 +1,129 @@ +package de.bund.digitalservice.ris.norms.adapter.input.restapi.controller; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import de.bund.digitalservice.ris.norms.application.exception.RegelungstextNotFoundException; +import de.bund.digitalservice.ris.norms.application.port.input.*; +import de.bund.digitalservice.ris.norms.config.SecurityConfig; +import de.bund.digitalservice.ris.norms.domain.entity.*; +import de.bund.digitalservice.ris.norms.domain.entity.eli.DokumentExpressionEli; +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.springframework.test.web.servlet.MockMvc; + +/** + * Not using SpringBootTest annotation to avoid needing a database connection. Using @Import to load + * the {@link SecurityConfig} in order to avoid http 401 Unauthorised + */ +@WithMockUser +@WebMvcTest( + controllers = TableOfContentsController.class, + excludeAutoConfiguration = OAuth2ClientAutoConfiguration.class +) +class TableOfContentsControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockitoBean + private LoadTocFromRegelungstextUseCase loadTocFromRegelungstextUseCase; + + @Test + void itReturnsTableOfContents() throws Exception { + // Given + var eli = DokumentExpressionEli.fromString( + "eli/bund/bgbl-1/2017/s419/2017-03-15/1/deu/regelungstext-1" + ); + final TableOfContentsItem childItem = new TableOfContentsItem( + "child-id", + "child-marker", + "child-heading", + "child-type", + Collections.emptyList() + ); + final TableOfContentsItem parentItem = new TableOfContentsItem( + "parent-id", + "parent-marker", + "parent-heading", + "parent-type", + List.of(childItem) + ); + when(loadTocFromRegelungstextUseCase.loadTocFromRegelungstext(any())) + .thenReturn(List.of(parentItem)); + + // When // Then + mockMvc + .perform(get("/api/v1/norms/" + eli + "/toc").accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id").value("parent-id")) + .andExpect(jsonPath("$[0].marker").value("parent-marker")) + .andExpect(jsonPath("$[0].heading").value("parent-heading")) + .andExpect(jsonPath("$[0].type").value("parent-type")) + .andExpect(jsonPath("$[0].children[0].id").value("child-id")) + .andExpect(jsonPath("$[0].children[0].marker").value("child-marker")) + .andExpect(jsonPath("$[0].children[0].heading").value("child-heading")) + .andExpect(jsonPath("$[0].children[0].type").value("child-type")); + } + + @Test + void itReturnsEmptyListWhenNoTableOfContentsExists() throws Exception { + // Given + var eli = DokumentExpressionEli.fromString( + "eli/bund/bgbl-1/2017/s419/2017-03-15/1/deu/regelungstext-1" + ); + when(loadTocFromRegelungstextUseCase.loadTocFromRegelungstext(any())).thenReturn(List.of()); + + // When // Then + mockMvc + .perform(get("/api/v1/norms/" + eli + "/toc").accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$").isEmpty()); + } + + @Test + void return404IfRegelungstextNotFound() throws Exception { + // given no norm + var eli = DokumentExpressionEli.fromString( + "eli/bund/NONEXISTENT_NORM/1964/s593/1964-08-05/1/deu/regelungstext-1" + ); + + when(loadTocFromRegelungstextUseCase.loadTocFromRegelungstext(any())) + .thenThrow(new RegelungstextNotFoundException(eli.toString())); + + // when + mockMvc + .perform(get("/api/v1/norms/" + eli + "/toc").accept(MediaType.APPLICATION_JSON_VALUE)) + // then + .andExpect(status().isNotFound()) + .andExpect(jsonPath("type").value("/errors/regelungstext-not-found")) + .andExpect(jsonPath("title").value("Regelungstext not found")) + .andExpect(jsonPath("status").value(404)) + .andExpect( + jsonPath("detail") + .value( + "Regelungstext with eli eli/bund/NONEXISTENT_NORM/1964/s593/1964-08-05/1/deu/regelungstext-1 does not exist" + ) + ) + .andExpect( + jsonPath("instance") + .value( + "/api/v1/norms/eli/bund/NONEXISTENT_NORM/1964/s593/1964-08-05/1/deu/regelungstext-1/toc" + ) + ) + .andExpect( + jsonPath("eli") + .value("eli/bund/NONEXISTENT_NORM/1964/s593/1964-08-05/1/deu/regelungstext-1") + ); + } +} diff --git a/backend/src/test/java/de/bund/digitalservice/ris/norms/adapter/input/restapi/mapper/TableOfContentsResponseMapperTest.java b/backend/src/test/java/de/bund/digitalservice/ris/norms/adapter/input/restapi/mapper/TableOfContentsResponseMapperTest.java new file mode 100644 index 000000000..13c29aaa1 --- /dev/null +++ b/backend/src/test/java/de/bund/digitalservice/ris/norms/adapter/input/restapi/mapper/TableOfContentsResponseMapperTest.java @@ -0,0 +1,66 @@ +package de.bund.digitalservice.ris.norms.adapter.input.restapi.mapper; + +import static org.assertj.core.api.Assertions.assertThat; + +import de.bund.digitalservice.ris.norms.adapter.input.restapi.schema.TableOfContentsResponseSchema; +import de.bund.digitalservice.ris.norms.domain.entity.TableOfContentsItem; +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.Test; + +class TableOfContentsResponseMapperTest { + + @Test + void shouldMapTableOfContentsItemsToResponseSchema() { + // Given + final TableOfContentsItem childItem = new TableOfContentsItem( + "child-id", + "child-marker", + "child-heading", + "child-type", + Collections.emptyList() + ); + final TableOfContentsItem parentItem = new TableOfContentsItem( + "parent-id", + "parent-marker", + "parent-heading", + "parent-type", + List.of(childItem) + ); + + final List tableOfContents = List.of(parentItem); + + // When + final List response = + TableOfContentsResponseMapper.fromTableOfContents(tableOfContents); + + // Then + assertThat(response).hasSize(1); + final TableOfContentsResponseSchema parentResponse = response.getFirst(); + assertThat(parentResponse.getId()).isEqualTo("parent-id"); + assertThat(parentResponse.getMarker()).isEqualTo("parent-marker"); + assertThat(parentResponse.getHeading()).isEqualTo("parent-heading"); + assertThat(parentResponse.getType()).isEqualTo("parent-type"); + assertThat(parentResponse.getChildren()).hasSize(1); + + final TableOfContentsResponseSchema childResponse = parentResponse.getChildren().getFirst(); + assertThat(childResponse.getId()).isEqualTo("child-id"); + assertThat(childResponse.getMarker()).isEqualTo("child-marker"); + assertThat(childResponse.getHeading()).isEqualTo("child-heading"); + assertThat(childResponse.getType()).isEqualTo("child-type"); + assertThat(childResponse.getChildren()).isEmpty(); + } + + @Test + void shouldReturnEmptyListWhenTableOfContentsIsEmpty() { + // Given + final List tableOfContents = List.of(); + + // When + final List response = + TableOfContentsResponseMapper.fromTableOfContents(tableOfContents); + + // Then + assertThat(response).isEmpty(); + } +}