From 9aef0ca8936cfb3e524b507fa694affb7025ae6d Mon Sep 17 00:00:00 2001 From: Sebastian Baltes Date: Wed, 22 May 2024 10:43:27 +0200 Subject: [PATCH] Add code from Spring Boot live demo * refactored and commented for assignment 4 --- README.md | 12 +- api/pom.xml | 32 +++++ .../list/api/controller/ListController.java | 59 ++++++++ .../teaching/list/api/dto/ListElementDto.java | 11 ++ application/pom.xml | 48 +++++++ .../se/teaching/list/Application.java | 3 + .../src/main/resources/application.yaml | 15 ++ business/pom.xml | 30 ++++ .../list/business/impl}/DoublyLinkedList.java | 8 +- .../list/business/impl/ListServiceImpl.java | 32 +++++ .../list/business/ports/ListService.java | 11 ++ .../teaching/list/business/ports/Value.java | 12 ++ .../impl/CucumberDoublyLinkedListSteps.java | 54 ++++---- .../business/impl/CucumberListTestRunner.java | 7 +- .../business/impl}/DoublyLinkedListTest.java | 128 +++++++++--------- .../business/impl}/append-to-list.feature | 0 .../list/business/impl}/invert-list.feature | 0 .../list/business/impl}/list-to-array.feature | 0 lombok.config | 4 + pom.xml | 123 +++++++++++------ .../de/unibayreuth/se/teaching/list/Main.java | 22 --- src/main/resources/application.yaml | 3 - 22 files changed, 450 insertions(+), 164 deletions(-) create mode 100644 api/pom.xml create mode 100644 api/src/main/java/de/unibayreuth/se/teaching/list/api/controller/ListController.java create mode 100644 api/src/main/java/de/unibayreuth/se/teaching/list/api/dto/ListElementDto.java create mode 100644 application/pom.xml rename {src => application/src}/main/java/de/unibayreuth/se/teaching/list/Application.java (81%) create mode 100644 application/src/main/resources/application.yaml create mode 100644 business/pom.xml rename {src/main/java/de/unibayreuth/se/teaching/list => business/src/main/java/de/unibayreuth/se/teaching/list/business/impl}/DoublyLinkedList.java (95%) create mode 100644 business/src/main/java/de/unibayreuth/se/teaching/list/business/impl/ListServiceImpl.java create mode 100644 business/src/main/java/de/unibayreuth/se/teaching/list/business/ports/ListService.java create mode 100644 business/src/main/java/de/unibayreuth/se/teaching/list/business/ports/Value.java rename src/test/java/de/unibayreuth/se/teaching/list/CucumberSteps.java => business/src/test/java/de/unibayreuth/se/teaching/list/business/impl/CucumberDoublyLinkedListSteps.java (72%) rename src/test/java/de/unibayreuth/se/teaching/list/CucumberTestRunner.java => business/src/test/java/de/unibayreuth/se/teaching/list/business/impl/CucumberListTestRunner.java (62%) rename {src/test/java/de/unibayreuth/se/teaching/list => business/src/test/java/de/unibayreuth/se/teaching/list/business/impl}/DoublyLinkedListTest.java (61%) rename {src/test/resources/de/unibayreuth/se/teaching/list => business/src/test/resources/de/unibayreuth/se/teaching/list/business/impl}/append-to-list.feature (100%) rename {src/test/resources/de/unibayreuth/se/teaching/list => business/src/test/resources/de/unibayreuth/se/teaching/list/business/impl}/invert-list.feature (100%) rename {src/test/resources/de/unibayreuth/se/teaching/list => business/src/test/resources/de/unibayreuth/se/teaching/list/business/impl}/list-to-array.feature (100%) create mode 100644 lombok.config delete mode 100644 src/main/java/de/unibayreuth/se/teaching/list/Main.java delete mode 100644 src/main/resources/application.yaml diff --git a/README.md b/README.md index d507dbe..1b5ca77 100644 --- a/README.md +++ b/README.md @@ -20,19 +20,13 @@ curl http://localhost:8080/list ### Append to list ```bash - curl --header "Content-Type: application/json" --request POST --data '[0.5, 0.6]' http://localhost:8080/list + curl --header "Content-Type: application/json" --request POST --data '[{"value": 0.5, "metadata": ""}, {"value": 0.6, "metadata": ""}]' http://localhost:8080/list ``` -### Append to list with verbose output +### Append to list (malformed body) ```bash - curl --verbose --header "Content-Type: application/json" --request POST --data '[0.5, 0.6]' http://localhost:8080/list -``` - -### Append to list with verbose output (malformed body) - -```bash - curl --verbose --header "Content-Type: application/json" --request POST --data '[0.5, 0.6' http://localhost:8080/list + curl --header "Content-Type: application/json" --request POST --data '[{"value": 0.5; "metadata": ""}]' http://localhost:8080/list ``` ### Clear list diff --git a/api/pom.xml b/api/pom.xml new file mode 100644 index 0000000..fa94c3e --- /dev/null +++ b/api/pom.xml @@ -0,0 +1,32 @@ + + 4.0.0 + + + de.unibayreuth.se.teaching.list + parent + 0.5.0 + + + api + + + + de.unibayreuth.se.teaching.list + business + ${project.version} + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + ${springdoc.openapi.version} + + + org.mapstruct + mapstruct + ${mapstruct.version} + provided + + + + \ No newline at end of file diff --git a/api/src/main/java/de/unibayreuth/se/teaching/list/api/controller/ListController.java b/api/src/main/java/de/unibayreuth/se/teaching/list/api/controller/ListController.java new file mode 100644 index 0000000..c80b7cc --- /dev/null +++ b/api/src/main/java/de/unibayreuth/se/teaching/list/api/controller/ListController.java @@ -0,0 +1,59 @@ +package de.unibayreuth.se.teaching.list.api.controller; + +import de.unibayreuth.se.teaching.list.api.dto.ListElementDto; +import de.unibayreuth.se.teaching.list.business.ports.ListService; +import de.unibayreuth.se.teaching.list.business.ports.Value; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +import java.util.List; + +@Controller +@RequiredArgsConstructor +public class ListController { + private final ListService listService; + + @GetMapping(value = "/list") + public ResponseEntity> getList() { + return ResponseEntity.ok(listService.get().stream() + // this::toDto is short for "apply that method to all elements in the stream" + // in this case: map(element -> toDto(element) + .map(this::toDto) + .toList() + ); + } + + @PostMapping(value = "/list") + public ResponseEntity> appendList(@RequestBody List elements) { + listService.append(elements.stream() + .map(this::toValue) + .toList() + ); + // ResponseEntity.ok(...) is a shortcut for "create a response entity with status 200 (OK) and the provided body + return ResponseEntity.ok(listService.get().stream() + .map(this::toDto) + .toList()); + } + + /** + * Mapper function to convert a Value to a ListElementDto. + * @param value the Value object (from the business layer) to map to a ListElementDto + * @return the mapped ListElementDto + */ + private ListElementDto toDto(Value value) { + return new ListElementDto(value.getDoubleValue(), ""); + } + + /** + * Mapper function to convert a ListElementDto to a Value. + * @param dto the ListElementDto object to map to a Value object (for the business layer) + * @return the mapped Value object + */ + private Value toValue(ListElementDto dto) { + return new Value(dto.value()); + } +} diff --git a/api/src/main/java/de/unibayreuth/se/teaching/list/api/dto/ListElementDto.java b/api/src/main/java/de/unibayreuth/se/teaching/list/api/dto/ListElementDto.java new file mode 100644 index 0000000..8cf0fd9 --- /dev/null +++ b/api/src/main/java/de/unibayreuth/se/teaching/list/api/dto/ListElementDto.java @@ -0,0 +1,11 @@ +package de.unibayreuth.se.teaching.list.api.dto; + +/** + * Data transfer object for list elements, to be used in the list controller API endpoints. + * + * @param value The value of the list element. + * @param metadata Metadata of the list element (to showcase the DTO might look different from the internal data model). + */ +public record ListElementDto(double value, String metadata) { + +} diff --git a/application/pom.xml b/application/pom.xml new file mode 100644 index 0000000..44e128d --- /dev/null +++ b/application/pom.xml @@ -0,0 +1,48 @@ + + 4.0.0 + + + de.unibayreuth.se.teaching.list + parent + 0.5.0 + + + application + + + + de.unibayreuth.se.teaching.list + business + ${project.version} + + + de.unibayreuth.se.teaching.list + api + ${project.version} + + + + org.springframework.boot + spring-boot-testcontainers + + + org.testcontainers + postgresql + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/src/main/java/de/unibayreuth/se/teaching/list/Application.java b/application/src/main/java/de/unibayreuth/se/teaching/list/Application.java similarity index 81% rename from src/main/java/de/unibayreuth/se/teaching/list/Application.java rename to application/src/main/java/de/unibayreuth/se/teaching/list/Application.java index 1f9c3c2..7d2b475 100644 --- a/src/main/java/de/unibayreuth/se/teaching/list/Application.java +++ b/application/src/main/java/de/unibayreuth/se/teaching/list/Application.java @@ -3,6 +3,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +/** + * Main class to start the Spring Boot application in production. + */ @SpringBootApplication public class Application { public static void main(String[] args) { diff --git a/application/src/main/resources/application.yaml b/application/src/main/resources/application.yaml new file mode 100644 index 0000000..89694f6 --- /dev/null +++ b/application/src/main/resources/application.yaml @@ -0,0 +1,15 @@ +spring: + application: + name: se24-demo + #datasource: + # driver-class-name: org.postgresql.Driver + #flyway: + # enabled: true + # locations: classpath:db/migration + # validate-on-migrate: true + +#springdoc: +# api-docs: +# path: /api-docs +# swagger-ui: +# path: /swagger-ui.html diff --git a/business/pom.xml b/business/pom.xml new file mode 100644 index 0000000..b4024d5 --- /dev/null +++ b/business/pom.xml @@ -0,0 +1,30 @@ + + 4.0.0 + + + de.unibayreuth.se.teaching.list + parent + 0.5.0 + + + business + + + de.unibayreuth.se.teaching.list.business.impl.CucumberListTestRunner + + + + + + + maven-surefire-plugin + ${maven.plugin.surefire.version} + + ${maven.cucumber.testsuite} + + + + + + \ No newline at end of file diff --git a/src/main/java/de/unibayreuth/se/teaching/list/DoublyLinkedList.java b/business/src/main/java/de/unibayreuth/se/teaching/list/business/impl/DoublyLinkedList.java similarity index 95% rename from src/main/java/de/unibayreuth/se/teaching/list/DoublyLinkedList.java rename to business/src/main/java/de/unibayreuth/se/teaching/list/business/impl/DoublyLinkedList.java index d4dfea2..06c81bd 100644 --- a/src/main/java/de/unibayreuth/se/teaching/list/DoublyLinkedList.java +++ b/business/src/main/java/de/unibayreuth/se/teaching/list/business/impl/DoublyLinkedList.java @@ -1,4 +1,4 @@ -package de.unibayreuth.se.teaching.list; +package de.unibayreuth.se.teaching.list.business.impl; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -6,13 +6,15 @@ import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; /** - * Doubly linked list + * Our doubly linked list implementation from previous assignments. */ @Getter @Setter @Slf4j +@Component public class DoublyLinkedList { private Element start; private Element end; @@ -137,7 +139,7 @@ public boolean isEmpty() { } /** - * Add an element at the correct position in a sorted list + * Insert an element at the correct position in a sorted list * @param e Element to insert into the sorted list */ public void insert(Element e) { diff --git a/business/src/main/java/de/unibayreuth/se/teaching/list/business/impl/ListServiceImpl.java b/business/src/main/java/de/unibayreuth/se/teaching/list/business/impl/ListServiceImpl.java new file mode 100644 index 0000000..4f4342d --- /dev/null +++ b/business/src/main/java/de/unibayreuth/se/teaching/list/business/impl/ListServiceImpl.java @@ -0,0 +1,32 @@ +package de.unibayreuth.se.teaching.list.business.impl; + +import de.unibayreuth.se.teaching.list.business.ports.ListService; +import de.unibayreuth.se.teaching.list.business.ports.Value; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class ListServiceImpl implements ListService { + private final DoublyLinkedList list; + + @Override + public List get() { + return Arrays.stream(list.asArray()) + // Our list uses the primitive type "double" but streams require the reference type "Double." + // Related concept: Autoboxing (https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html) + .boxed() + .map(Value::new) // same shortcut as used in the controller, here: call constructor with value as argument + .toList(); + } + + @Override + public void append(List valuesToAppend) { + valuesToAppend.forEach( + value -> list.append(value.getDoubleValue()) + ); + } +} diff --git a/business/src/main/java/de/unibayreuth/se/teaching/list/business/ports/ListService.java b/business/src/main/java/de/unibayreuth/se/teaching/list/business/ports/ListService.java new file mode 100644 index 0000000..d736070 --- /dev/null +++ b/business/src/main/java/de/unibayreuth/se/teaching/list/business/ports/ListService.java @@ -0,0 +1,11 @@ +package de.unibayreuth.se.teaching.list.business.ports; + +import java.util.List; + +/** + * Interface for the implementation of the list service that the business layer provides as a port. + */ +public interface ListService { + List get(); + void append(List valuesToAppend); +} diff --git a/business/src/main/java/de/unibayreuth/se/teaching/list/business/ports/Value.java b/business/src/main/java/de/unibayreuth/se/teaching/list/business/ports/Value.java new file mode 100644 index 0000000..5b40ab0 --- /dev/null +++ b/business/src/main/java/de/unibayreuth/se/teaching/list/business/ports/Value.java @@ -0,0 +1,12 @@ +package de.unibayreuth.se.teaching.list.business.ports; + +import lombok.Data; + +/** + * Class which stores the value of a list element. + */ +@Data +public class Value { + private final Double doubleValue; + private Long longValue; // example for a derived value that the business layer might provide +} diff --git a/src/test/java/de/unibayreuth/se/teaching/list/CucumberSteps.java b/business/src/test/java/de/unibayreuth/se/teaching/list/business/impl/CucumberDoublyLinkedListSteps.java similarity index 72% rename from src/test/java/de/unibayreuth/se/teaching/list/CucumberSteps.java rename to business/src/test/java/de/unibayreuth/se/teaching/list/business/impl/CucumberDoublyLinkedListSteps.java index f91270e..39d5d36 100644 --- a/src/test/java/de/unibayreuth/se/teaching/list/CucumberSteps.java +++ b/business/src/test/java/de/unibayreuth/se/teaching/list/business/impl/CucumberDoublyLinkedListSteps.java @@ -1,18 +1,20 @@ -package de.unibayreuth.se.teaching.list; +package de.unibayreuth.se.teaching.list.business.impl; import io.cucumber.java.Before; import io.cucumber.java.en.Given; import io.cucumber.java.en.When; import io.cucumber.java.en.Then; +import org.junit.jupiter.api.Assertions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; -import static org.junit.jupiter.api.Assertions.*; - -public class CucumberSteps { - private static final Logger logger = LoggerFactory.getLogger(CucumberSteps.class); +/** + * Step definitions for the Cucumber tests of the doubly-linked list. + */ +public class CucumberDoublyLinkedListSteps { + private static final Logger logger = LoggerFactory.getLogger(CucumberDoublyLinkedListSteps.class); private DoublyLinkedList list; private double value; @@ -24,20 +26,11 @@ public void initialization() { list = new DoublyLinkedList(); } + // Given ----------------------------------------------------------------------- + @Given("^an empty list$") public void anEmptyList() { - assertTrue(list.isEmpty()); - } - - @When("^I append an element with value (\\d+.\\d+)$") - public void iAppendAnElementWithValue(double value) { - this.value = value; - list.append(value); - } - - @Then("^the list should contain that element$") - public void theListShouldContainThatElement() { - assertArrayEquals(new double[]{value}, list.asArray()); + Assertions.assertTrue(list.isEmpty()); } @Given("^I have elements with the following values in my list:$") @@ -46,21 +39,36 @@ public void iHaveElementsWithTheFollowingValuesInMyList(List values) { arrayFromValues = values.stream().mapToDouble(Double::doubleValue).toArray(); } + // When ----------------------------------------------------------------------- + + @When("^I append an element with value (\\d+.\\d+)$") + public void iAppendAnElementWithValue(double value) { + this.value = value; + list.append(value); + } + @When("^I convert the list to an array$") public void iConvertTheListToAnArray() { arrayFromList = list.asArray(); } - @Then("^the array should contain the same elements in the same order$") - public void theArrayShouldContainTheSameElementsInTheSameOrder() { - assertArrayEquals(arrayFromValues, arrayFromList); - } - @When("^I invert the list$") public void iInvertTheList() { logger.info("%s not implemented yet.".formatted(Thread.currentThread().getStackTrace()[1].getMethodName())); } + // Then ----------------------------------------------------------------------- + + @Then("^the list should contain that element$") + public void theListShouldContainThatElement() { + Assertions.assertArrayEquals(new double[]{value}, list.asArray()); + } + + @Then("^the array should contain the same elements in the same order$") + public void theArrayShouldContainTheSameElementsInTheSameOrder() { + Assertions.assertArrayEquals(arrayFromValues, arrayFromList); + } + @Then("^the list should contain the elements in the following order:$") public void theListShouldContainTheElementsInTheFollowingOrder(List values) { logger.info("%s not implemented yet.".formatted(Thread.currentThread().getStackTrace()[1].getMethodName())); @@ -68,6 +76,6 @@ public void theListShouldContainTheElementsInTheFollowingOrder(List valu @Then("the list should contain {int} element(s)") public void theListShouldContainElement(int count) { - assertEquals(count, list.getLength()); + Assertions.assertEquals(count, list.getLength()); } } diff --git a/src/test/java/de/unibayreuth/se/teaching/list/CucumberTestRunner.java b/business/src/test/java/de/unibayreuth/se/teaching/list/business/impl/CucumberListTestRunner.java similarity index 62% rename from src/test/java/de/unibayreuth/se/teaching/list/CucumberTestRunner.java rename to business/src/test/java/de/unibayreuth/se/teaching/list/business/impl/CucumberListTestRunner.java index b4133ac..39cf12e 100644 --- a/src/test/java/de/unibayreuth/se/teaching/list/CucumberTestRunner.java +++ b/business/src/test/java/de/unibayreuth/se/teaching/list/business/impl/CucumberListTestRunner.java @@ -1,11 +1,14 @@ -package de.unibayreuth.se.teaching.list; +package de.unibayreuth.se.teaching.list.business.impl; import io.cucumber.junit.platform.engine.Constants; import org.junit.platform.suite.api.*; +/** + * Test runner for the Cucumber tests of the double-linked list. + */ @Suite @SelectPackages("de.unibayreuth.se.teaching.list") @ConfigurationParameter(key = Constants.PLUGIN_PROPERTY_NAME,value = "pretty, html:target/cucumber-report/cucumber.html") -public class CucumberTestRunner { +public class CucumberListTestRunner { } \ No newline at end of file diff --git a/src/test/java/de/unibayreuth/se/teaching/list/DoublyLinkedListTest.java b/business/src/test/java/de/unibayreuth/se/teaching/list/business/impl/DoublyLinkedListTest.java similarity index 61% rename from src/test/java/de/unibayreuth/se/teaching/list/DoublyLinkedListTest.java rename to business/src/test/java/de/unibayreuth/se/teaching/list/business/impl/DoublyLinkedListTest.java index 3e42fb6..f5dbf77 100644 --- a/src/test/java/de/unibayreuth/se/teaching/list/DoublyLinkedListTest.java +++ b/business/src/test/java/de/unibayreuth/se/teaching/list/business/impl/DoublyLinkedListTest.java @@ -1,10 +1,12 @@ -package de.unibayreuth.se.teaching.list; +package de.unibayreuth.se.teaching.list.business.impl; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - +/** + * Unit tests for the doubly linked list. + */ class DoublyLinkedListTest { private DoublyLinkedList list; @@ -16,108 +18,108 @@ void setUp() { @Test void testAppendElement() { // given: the list is empty... - assertEquals(0, list.getLength()); + Assertions.assertEquals(0, list.getLength()); var element = new DoublyLinkedList.Element(0.9); // when: appending an element list.append(element); // then: the list has one element... - assertEquals(1, list.getLength()); + Assertions.assertEquals(1, list.getLength()); // ...and the new element is the start and end of the list - assertEquals(element, list.getStart()); - assertEquals(element, list.getEnd()); + Assertions.assertEquals(element, list.getStart()); + Assertions.assertEquals(element, list.getEnd()); // ...and the start and end pointers do not have predecessors or successors - assertNull(list.getStart().getPrev()); - assertNull(list.getStart().getNext()); - assertNull(list.getEnd().getPrev()); - assertNull(list.getEnd().getNext()); + Assertions.assertNull(list.getStart().getPrev()); + Assertions.assertNull(list.getStart().getNext()); + Assertions.assertNull(list.getEnd().getPrev()); + Assertions.assertNull(list.getEnd().getNext()); } @Test void testInsertNewMinimum() { // given: the list as four sorted elements - assertTrue(list.isEmpty()); + Assertions.assertTrue(list.isEmpty()); list.append(new double[]{0.2, 0.4, 0.5, 0.8}); // when: inserting a new element with a value smaller than the minimum of the list list.insert(new DoublyLinkedList.Element(0.1)); // then: the new element is the start of the list - assertArrayEquals(new double[]{0.1, 0.2, 0.4, 0.5, 0.8}, list.asArray()); + Assertions.assertArrayEquals(new double[]{0.1, 0.2, 0.4, 0.5, 0.8}, list.asArray()); } @Test void testInsertNewMaximum() { // given: the list as four sorted elements - assertTrue(list.isEmpty()); + Assertions.assertTrue(list.isEmpty()); list.append(new double[]{0.2, 0.4, 0.5, 0.8}); // when: inserting a new element with a value greater than the maximum of the list list.insert(new DoublyLinkedList.Element(0.9)); // then: the new element is the end of the list - assertArrayEquals(new double[]{0.2, 0.4, 0.5, 0.8, 0.9}, list.asArray()); + Assertions.assertArrayEquals(new double[]{0.2, 0.4, 0.5, 0.8, 0.9}, list.asArray()); } @Test void testInsertNeitherMinimumNorMaximum() { // given: the list as four sorted elements - assertTrue(list.isEmpty()); + Assertions.assertTrue(list.isEmpty()); list.append(new double[]{0.2, 0.4, 0.5, 0.8}); // when: inserting a new element with a value between the minimum and the maximum of the list list.insert(new DoublyLinkedList.Element(0.6)); // then: the new element is placed in the right position - assertArrayEquals(new double[]{0.2, 0.4, 0.5, 0.6, 0.8}, list.asArray()); + Assertions.assertArrayEquals(new double[]{0.2, 0.4, 0.5, 0.6, 0.8}, list.asArray()); } @Test void testAppendElementFromOtherList() { // give: an empty list and another list with three elements - assertTrue(list.isEmpty()); + Assertions.assertTrue(list.isEmpty()); DoublyLinkedList otherList = new DoublyLinkedList(); otherList.append(new double[]{0.9, 0.5, 0.4}); // when: appending the first element from the other list // then: expect an exception to be raised var firstElement = otherList.getStart(); - assertThrows(IllegalArgumentException.class, () -> list.append(firstElement)); + Assertions.assertThrows(IllegalArgumentException.class, () -> list.append(firstElement)); // when: appending the second element from the other list // then: expect an exception to be raised var secondElement = otherList.getStart().getNext(); - assertThrows(IllegalArgumentException.class, () -> list.append(secondElement)); + Assertions.assertThrows(IllegalArgumentException.class, () -> list.append(secondElement)); // when: appending the third element from the other list // then: expect an exception to be raised var lastElement = otherList.getEnd(); - assertThrows(IllegalArgumentException.class, () -> list.append(lastElement)); + Assertions.assertThrows(IllegalArgumentException.class, () -> list.append(lastElement)); } @Test void testAppendOneElementByValue() { // given: the list is empty - assertEquals(0, list.getLength()); + Assertions.assertEquals(0, list.getLength()); // when: appending a new element list.append(0.9); // then: the list has one element... - assertEquals(1, list.getLength()); + Assertions.assertEquals(1, list.getLength()); // ...and the new element is the start and end of the list - assertEquals(0.9, list.getStart().getValue()); - assertEquals(0.9, list.getEnd().getValue()); + Assertions.assertEquals(0.9, list.getStart().getValue()); + Assertions.assertEquals(0.9, list.getEnd().getValue()); // ...and the start and end pointers do not have predecessors or successors - assertNull(list.getStart().getPrev()); - assertNull(list.getStart().getNext()); - assertNull(list.getEnd().getPrev()); - assertNull(list.getEnd().getNext()); + Assertions.assertNull(list.getStart().getPrev()); + Assertions.assertNull(list.getStart().getNext()); + Assertions.assertNull(list.getEnd().getPrev()); + Assertions.assertNull(list.getEnd().getNext()); } @Test void testAppendTwoElementsByValue() { // given: the list is empty - assertEquals(0, list.getLength()); + Assertions.assertEquals(0, list.getLength()); // when: appending two new elements list.append(0.9); list.append(0.5); // then: the list has two elements... - assertEquals(2, list.getLength()); + Assertions.assertEquals(2, list.getLength()); // ...and the first element is the start and the second element is the end of the list - assertEquals(0.9, list.getStart().getValue()); - assertEquals(0.5, list.getEnd().getValue()); + Assertions.assertEquals(0.9, list.getStart().getValue()); + Assertions.assertEquals(0.5, list.getEnd().getValue()); // ...and they are correctly linked - assertEquals(0.5, list.getStart().getNext().getValue()); - assertEquals(0.9, list.getEnd().getPrev().getValue()); + Assertions.assertEquals(0.5, list.getStart().getNext().getValue()); + Assertions.assertEquals(0.9, list.getEnd().getPrev().getValue()); // ...and the start and end pointers are correctly set testBeginEndPointers(list); } @@ -125,19 +127,19 @@ void testAppendTwoElementsByValue() { @Test void testAppendThreeElementsByValue() { // given: the list is empty - assertEquals(0, list.getLength()); + Assertions.assertEquals(0, list.getLength()); // when: appending three new elements list.append(0.9); list.append(0.5); list.append(0.4); // then: the list has three elements... - assertEquals(3, list.getLength()); + Assertions.assertEquals(3, list.getLength()); // ...and the first element is the start and the third element is the end of the list - assertEquals(0.9, list.getStart().getValue()); - assertEquals(0.4, list.getEnd().getValue()); + Assertions.assertEquals(0.9, list.getStart().getValue()); + Assertions.assertEquals(0.4, list.getEnd().getValue()); // ...and all elements are correctly linked - assertEquals(0.5, list.getStart().getNext().getValue()); - assertEquals(0.5, list.getEnd().getPrev().getValue()); + Assertions.assertEquals(0.5, list.getStart().getNext().getValue()); + Assertions.assertEquals(0.5, list.getEnd().getPrev().getValue()); // ...and the start and end pointers are correctly set testBeginEndPointers(list); } @@ -145,91 +147,91 @@ void testAppendThreeElementsByValue() { @Test void testEmptyListToArray() { // given: the list is empty - assertEquals(0, list.getLength()); + Assertions.assertEquals(0, list.getLength()); // then: the array representation of the list is equal to an empty array - assertArrayEquals(new double[]{}, list.asArray()); + Assertions.assertArrayEquals(new double[]{}, list.asArray()); list.append(0.9); list.append(0.5); list.append(0.4); - assertArrayEquals(new double[]{0.9, 0.5, 0.4}, list.asArray()); + Assertions.assertArrayEquals(new double[]{0.9, 0.5, 0.4}, list.asArray()); } @Test void testListToArray() { // given: the list is empty - assertEquals(0, list.getLength()); + Assertions.assertEquals(0, list.getLength()); // when: appending three elements list.append(0.9); list.append(0.5); list.append(0.4); // then: the array representation of the list is equal to the array with the elements in the same order - assertArrayEquals(new double[]{0.9, 0.5, 0.4}, list.asArray()); + Assertions.assertArrayEquals(new double[]{0.9, 0.5, 0.4}, list.asArray()); } @Test void testAppendArray() { // given: the list is empty - assertEquals(0, list.getLength()); + Assertions.assertEquals(0, list.getLength()); // when: appending an array with three elements double[] data = new double[]{0.9, 0.5, 0.4}; list.append(data); // then: the array representation of the list is equal to the appended array - assertArrayEquals(data, list.asArray()); + Assertions.assertArrayEquals(data, list.asArray()); } @Test void testIsEmptyOnEmptyList() { // given: the list is empty - assertTrue(list.isEmpty()); + Assertions.assertTrue(list.isEmpty()); // then: the array representation of the list is equal to an empty array - assertEquals(0, list.asArray().length); + Assertions.assertEquals(0, list.asArray().length); } @Test void testIsEmptyOnNonEmptyList() { // given: the list has three elements - assertTrue(list.isEmpty()); + Assertions.assertTrue(list.isEmpty()); list.append(0.9); list.append(0.5); list.append(0.4); // then: the list is not empty - assertFalse(list.isEmpty()); + Assertions.assertFalse(list.isEmpty()); // when: clearing the list list.clear(); // then: the list is empty again - assertTrue(list.isEmpty()); + Assertions.assertTrue(list.isEmpty()); } @Test void testAppendOtherList() { // give: an empty list and another list with three elements - assertTrue(list.isEmpty()); + Assertions.assertTrue(list.isEmpty()); var data = new double[]{0.9, 0.5, 0.4}; DoublyLinkedList otherList = new DoublyLinkedList(); otherList.append(data); // when: appending the other list list.append(otherList); // then: expect the list to contain the elements of the other list in the same order - assertArrayEquals(data, list.asArray()); + Assertions.assertArrayEquals(data, list.asArray()); } @Test void testToStringEmptyList() { // given: the list is empty - assertTrue(list.isEmpty()); + Assertions.assertTrue(list.isEmpty()); // then: the string representation of the list is "Empty." - assertEquals("Empty.", list.toString()); + Assertions.assertEquals("Empty.", list.toString()); } @Test void testToStringNonEmptyList() { // given: the list has three elements - assertTrue(list.isEmpty()); + Assertions.assertTrue(list.isEmpty()); list.append(0.9); list.append(0.5); list.append(0.4); // then: the string representation of the list is "0.9<->0.5<->0.4" - assertEquals("0.9<->0.5<->0.4", list.toString()); + Assertions.assertEquals("0.9<->0.5<->0.4", list.toString()); } /** @@ -237,9 +239,9 @@ void testToStringNonEmptyList() { * @param list List to test */ private static void testBeginEndPointers(DoublyLinkedList list) { - assertNull(list.getStart().getPrev()); - assertSame(list.getStart().getNext().getPrev(), list.getStart()); - assertNull(list.getEnd().getNext()); - assertSame(list.getEnd().getPrev().getNext(), list.getEnd()); + Assertions.assertNull(list.getStart().getPrev()); + Assertions.assertSame(list.getStart().getNext().getPrev(), list.getStart()); + Assertions.assertNull(list.getEnd().getNext()); + Assertions.assertSame(list.getEnd().getPrev().getNext(), list.getEnd()); } } diff --git a/src/test/resources/de/unibayreuth/se/teaching/list/append-to-list.feature b/business/src/test/resources/de/unibayreuth/se/teaching/list/business/impl/append-to-list.feature similarity index 100% rename from src/test/resources/de/unibayreuth/se/teaching/list/append-to-list.feature rename to business/src/test/resources/de/unibayreuth/se/teaching/list/business/impl/append-to-list.feature diff --git a/src/test/resources/de/unibayreuth/se/teaching/list/invert-list.feature b/business/src/test/resources/de/unibayreuth/se/teaching/list/business/impl/invert-list.feature similarity index 100% rename from src/test/resources/de/unibayreuth/se/teaching/list/invert-list.feature rename to business/src/test/resources/de/unibayreuth/se/teaching/list/business/impl/invert-list.feature diff --git a/src/test/resources/de/unibayreuth/se/teaching/list/list-to-array.feature b/business/src/test/resources/de/unibayreuth/se/teaching/list/business/impl/list-to-array.feature similarity index 100% rename from src/test/resources/de/unibayreuth/se/teaching/list/list-to-array.feature rename to business/src/test/resources/de/unibayreuth/se/teaching/list/business/impl/list-to-array.feature diff --git a/lombok.config b/lombok.config new file mode 100644 index 0000000..bd85f8b --- /dev/null +++ b/lombok.config @@ -0,0 +1,4 @@ +# Copy the Qualifier annotation from the instance variables to the constructor +# see https://github.com/rzwitserloot/lombok/issues/745 +lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier +lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Value diff --git a/pom.xml b/pom.xml index 0255ef5..1de0caf 100644 --- a/pom.xml +++ b/pom.xml @@ -10,29 +10,39 @@ List - de.unibayreuth.se.teaching - list - 0.4.0 + de.unibayreuth.se.teaching.list + parent + 0.5.0 https://github.com/se-ubt/se24-assignment4 + pom + + + business + + api + application + + 21 UTF-8 UTF-8 + de.unibayreuth.se.teaching.list.Application ${java.version} ${java.version} - de.unibayreuth.se.teaching.list.Main - de.unibayreuth.se.teaching.list.CucumberTestRunner 3.13.0 3.2.5 + + 3.4.1 3.3.2 @@ -46,6 +56,9 @@ 3.11.0.3922 + + 3.2.5 + 5.11.0-M1 @@ -59,6 +72,14 @@ 1.18.32 + + 0.2.0 + + 1.6.0.Beta2 + + 10.13.0 + + 2.5.0 @@ -70,6 +91,25 @@ + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.springframework.boot + spring-boot-starter-test + + + org.projectlombok + lombok + ${lombok.version} + provided + org.junit.jupiter junit-jupiter-api @@ -88,12 +128,6 @@ ${hamcrest.version} test - - org.projectlombok - lombok - ${lombok.version} - provided - io.cucumber cucumber-java @@ -106,19 +140,6 @@ ${cucumber.version} test - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-configuration-processor - true - - - org.springframework.boot - spring-boot-starter-test - @@ -133,14 +154,33 @@ -proc:full + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + org.projectlombok + lombok + ${lombok.version} + + + org.projectlombok + lombok-mapstruct-binding + ${lombok.mapstruct.version} + + + org.springframework.boot + spring-boot-configuration-processor + ${spring.boot.version} + + maven-surefire-plugin ${maven.plugin.surefire.version} - - ${maven.cucumber.testsuite} - org.apache.maven.plugins @@ -174,6 +214,23 @@ + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + + true + + **/application-*.yaml + + + org.jacoco jacoco-maven-plugin @@ -208,18 +265,6 @@ sonar-maven-plugin ${maven.plugin.sonar.scanner.version} - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - diff --git a/src/main/java/de/unibayreuth/se/teaching/list/Main.java b/src/main/java/de/unibayreuth/se/teaching/list/Main.java deleted file mode 100644 index a55fa4b..0000000 --- a/src/main/java/de/unibayreuth/se/teaching/list/Main.java +++ /dev/null @@ -1,22 +0,0 @@ -package de.unibayreuth.se.teaching.list; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Main class for demo purposes. - */ -public class Main { - private static final Logger logger = LoggerFactory.getLogger(Main.class); - - public static void main(String[] args) { - - // Create list and add some values... - DoublyLinkedList list = new DoublyLinkedList(); - list.append(new double[]{0.5, 4.2, 3.3, 0.9}); - - logger.info("The list contains the following elements:"); - String listAsString = list.toString(); - logger.info(listAsString); - } -} diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml deleted file mode 100644 index 3c508a6..0000000 --- a/src/main/resources/application.yaml +++ /dev/null @@ -1,3 +0,0 @@ -spring: - application: - name: se24-linked-list