diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
new file mode 100644
index 0000000..ddc0a0c
--- /dev/null
+++ b/.github/workflows/maven.yml
@@ -0,0 +1,46 @@
+# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
+# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven
+
+# This workflow uses actions that are not certified by GitHub.
+# They are provided by a third-party and are governed by
+# separate terms of service, privacy policy, and support
+# documentation.
+
+name: Java CI with Maven
+
+on:
+ push:
+ branches: [ "main" ]
+ pull_request:
+ branches: [ "main" ]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+ environment: default
+ env:
+ SONAR_ORGANIZATION: se-ubt
+ SONAR_PROJECT_KEY: se-ubt_se24-ci-demo
+
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Set up JDK 21
+ uses: actions/setup-java@v4
+ with:
+ java-version: '21'
+ distribution: 'temurin'
+ cache: maven
+
+ - name: Build with Maven
+ run: mvn -B package --file pom.xml
+
+ #- name: Scan with SonarCloud
+ # run: mvn clean verify sonar:sonar -Dsonar.token=${{ secrets.SONAR_TOKEN }} -Dsonar.host.url=https://sonarcloud.io -Dsonar.organization=$SONAR_ORGANIZATION -Dsonar.projectKey=$SONAR_PROJECT_KEY
+
+ # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive
+ #- name: Update dependency graph
+ # uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ad23210
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,46 @@
+######################
+# OS generated files #
+######################
+*~
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+#Icon?
+ehthumbs.db
+Thumbs.db
+
+##############
+# Java/Scala #
+##############
+*.class
+
+##########################
+# Webstorm/IntelliJ IDEA #
+##########################
+.idea/
+*.iml
+
+#########
+# Excel #
+#########
+~$*
+
+###########
+# RStudio #
+###########
+.Rhistory
+.RData
+
+#########
+# Maven #
+##########
+target/
+
+########
+# Misc #
+########
+*.log
+*.log.*
+*.lck
diff --git a/.tool-versions b/.tool-versions
new file mode 100644
index 0000000..5877eb8
--- /dev/null
+++ b/.tool-versions
@@ -0,0 +1,4 @@
+git 2.44.0
+java temurin-21.0.3+9.0.LTS
+maven 3.9.6
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..a4659bc
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2020 Sebastian Baltes
+
+ 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.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4276c68
--- /dev/null
+++ b/README.md
@@ -0,0 +1,4 @@
+# Software Engineering Summer 2024
+
+This repository is used to showcase concepts such as build automation, code quality monitoring, continuous integration,
+behavior-driven development, as well as architectures for web applications.
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..0255ef5
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,236 @@
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.2.5
+
+
+
+ List
+ de.unibayreuth.se.teaching
+ list
+ 0.4.0
+ https://github.com/se-ubt/se24-assignment4
+
+
+ 21
+
+
+ UTF-8
+ UTF-8
+
+
+ ${java.version}
+ ${java.version}
+ de.unibayreuth.se.teaching.list.Main
+ de.unibayreuth.se.teaching.list.CucumberTestRunner
+
+
+
+ 3.13.0
+
+ 3.2.5
+
+ 3.3.2
+
+ 4.0.0-M13
+
+ 3.5.0
+
+ 3.22.0
+
+ 0.8.12
+
+ 3.11.0.3922
+
+
+
+ 5.11.0-M1
+
+ 1.11.0-M1
+
+ 2.2
+
+ 7.17.0
+
+
+
+ 1.18.32
+
+
+
+
+ maven-central
+ maven-central
+ https://repo1.maven.org/maven2
+
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ ${junit.jupiter.version}
+ test
+
+
+ org.junit.platform
+ junit-platform-suite
+ ${junit.platform.suite.version}
+ test
+
+
+ org.hamcrest
+ hamcrest
+ ${hamcrest.version}
+ test
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+ provided
+
+
+ io.cucumber
+ cucumber-java
+ ${cucumber.version}
+ test
+
+
+ io.cucumber
+ cucumber-junit-platform-engine
+ ${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
+
+
+
+
+
+
+ maven-compiler-plugin
+ ${maven.plugin.compiler.version}
+
+ ${java.version}
+
+ ${maven.compiler.target}
+
+ -proc:full
+
+
+
+
+ maven-surefire-plugin
+ ${maven.plugin.surefire.version}
+
+ ${maven.cucumber.testsuite}
+
+
+
+ org.apache.maven.plugins
+ maven-jxr-plugin
+ ${maven.plugin.jxr.version}
+
+
+ generate-cross-references
+ site
+
+ jxr
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-pmd-plugin
+ ${maven.plugin.pmd.version}
+
+ true
+
+
+
+ generate-pmd-report
+ verify
+
+ check
+ cpd-check
+
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ ${maven.plugin.jacoco.version}
+
+
+ prepare-agent
+
+ prepare-agent
+
+
+
+ report
+
+ report
+
+
+
+ XML
+
+
+
+
+
+
+ **/Main.class
+
+
+
+
+ org.sonarsource.scanner.maven
+ sonar-maven-plugin
+ ${maven.plugin.sonar.scanner.version}
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jxr-plugin
+ ${maven.plugin.jxr.version}
+
+
+
+
+
diff --git a/src/main/java/de/unibayreuth/se/teaching/list/Application.java b/src/main/java/de/unibayreuth/se/teaching/list/Application.java
new file mode 100644
index 0000000..1f9c3c2
--- /dev/null
+++ b/src/main/java/de/unibayreuth/se/teaching/list/Application.java
@@ -0,0 +1,11 @@
+package de.unibayreuth.se.teaching.list;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+}
diff --git a/src/main/java/de/unibayreuth/se/teaching/list/DoublyLinkedList.java b/src/main/java/de/unibayreuth/se/teaching/list/DoublyLinkedList.java
new file mode 100644
index 0000000..6b1458a
--- /dev/null
+++ b/src/main/java/de/unibayreuth/se/teaching/list/DoublyLinkedList.java
@@ -0,0 +1,182 @@
+package de.unibayreuth.se.teaching.list;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Doubly linked list
+ */
+@Getter
+@Setter
+@Slf4j
+public class DoublyLinkedList {
+ private Element start;
+ private Element end;
+ private int length;
+
+ private static final Logger logger = LoggerFactory.getLogger(DoublyLinkedList.class);
+
+ /**
+ * Add an element at the end of the list
+ * @param e New list element
+ * @param elementValidation If true, the method checks whether the element is already part of a list
+ */
+ public void append(Element e, boolean elementValidation) {
+ if (elementValidation && (e.getPrev() != null || e.getNext() != null)) {
+ throw new IllegalArgumentException("Element is already part of a list.");
+ }
+
+ if (start == null) {
+ start = e;
+ end = e;
+ e.setPrev(null);
+ e.setNext(null);
+ } else {
+ Element tmp = end;
+ end = e;
+ tmp.setNext(e);
+ e.setPrev(tmp);
+ e.setNext(null);
+ }
+ length++;
+ }
+
+ /**
+ * Add an element at the end of the list with element validation enabled
+ * @param e New list element
+ */
+ public void append(Element e) {
+ append(e, true);
+ }
+
+ /**
+ * Create a new element with the provided value and append it to the list
+ * @param value Value of the new list element
+ */
+ public void append(double value) {
+ append(new Element(value));
+ }
+
+ /**
+ * Append all elements in the provided list to this list
+ * @param list The list of which the elements should be appended
+ */
+ public void append(DoublyLinkedList list) {
+ Element e = list.getStart();
+ while (e != null) {
+ Element next = e.getNext(); // append sets e.next to null
+ append(e, false);
+ e = next;
+ }
+ }
+
+ /**
+ * Create one element per value in the array and append the new elements to this list
+ * @param values Array with values to append
+ */
+ public void append(double[] values) {
+ for (double value : values) {
+ append(value);
+ }
+ }
+
+ /**
+ * Create a new array with the elements in this list (in the same order)
+ * @return Array with list elements (same order)
+ */
+ public double[] asArray() {
+ double[] array = new double[length];
+ Element element = start;
+ int arrayPos = 0;
+ while (element != null) {
+ array[arrayPos] = element.value;
+ arrayPos++;
+ element = element.next;
+ }
+ return array;
+ }
+
+ /**
+ * Print the list to the standard output
+ */
+ @Override
+ public String toString() {
+ if (isEmpty()) {
+ return "Empty.";
+ }
+ StringBuilder stringBuilder = new StringBuilder();
+ Element pos = start;
+ stringBuilder.append(start.getValue());
+ pos = pos.next;
+ while (pos != null) {
+ stringBuilder.append("<->").append(pos.getValue());
+ pos = pos.next;
+ }
+ return stringBuilder.toString();
+ }
+
+ /**
+ * Remove all list elements
+ */
+ public void empty() {
+ start = null;
+ end = null;
+ length = 0;
+ }
+
+ /**
+ * Checks whether list does not contain any elements
+ * @return true if list is empty
+ */
+ public boolean isEmpty() {
+ return start == null && end == null && length == 0;
+ }
+
+ /**
+ * Add an element at the correct position in a sorted list
+ * @param e Element to insert into the sorted list
+ */
+ public void insert(Element e) {
+ if (isEmpty()) { // If the list is empty, just append the new element
+ append(e);
+ } else { // Otherwise the element needs to be sorted in...
+ Element pos = start;
+ Element pred = null;
+ // Find position pos, before which the element is supposed to be located
+ while (pos != null && pos.getValue() < e.getValue()) {
+ pred = pos;
+ pos = pos.getNext();
+ }
+ if (pos == null) { // There is no larger element => append new element to the list
+ append(e);
+ } else { // Add the new element before element at pos
+ e.setNext(pos);
+ pos.setPrev(e);
+ if (pred != null) { // If pos is not first element in list...
+ e.setPrev(pred);
+ pred.setNext(e);
+ } else { // If pos is the first element in the list...
+ start = e;
+ }
+ length++;
+ }
+ }
+ }
+
+ /**
+ * Inner class for doubly linked list elements
+ */
+ @Setter
+ @Getter
+ @RequiredArgsConstructor
+ public static class Element {
+ private final double value;
+ private Element next;
+ private Element prev;
+ }
+
+}
diff --git a/src/main/java/de/unibayreuth/se/teaching/list/Main.java b/src/main/java/de/unibayreuth/se/teaching/list/Main.java
new file mode 100644
index 0000000..a55fa4b
--- /dev/null
+++ b/src/main/java/de/unibayreuth/se/teaching/list/Main.java
@@ -0,0 +1,22 @@
+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
new file mode 100644
index 0000000..3c508a6
--- /dev/null
+++ b/src/main/resources/application.yaml
@@ -0,0 +1,3 @@
+spring:
+ application:
+ name: se24-linked-list
diff --git a/src/test/java/de/unibayreuth/se/teaching/list/CucumberSteps.java b/src/test/java/de/unibayreuth/se/teaching/list/CucumberSteps.java
new file mode 100644
index 0000000..f91270e
--- /dev/null
+++ b/src/test/java/de/unibayreuth/se/teaching/list/CucumberSteps.java
@@ -0,0 +1,73 @@
+package de.unibayreuth.se.teaching.list;
+
+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.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);
+
+ private DoublyLinkedList list;
+ private double value;
+ private double[] arrayFromValues;
+ private double[] arrayFromList;
+
+ @Before
+ public void initialization() {
+ list = new DoublyLinkedList();
+ }
+
+ @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());
+ }
+
+ @Given("^I have elements with the following values in my list:$")
+ public void iHaveElementsWithTheFollowingValuesInMyList(List values) {
+ values.forEach(list::append);
+ arrayFromValues = values.stream().mapToDouble(Double::doubleValue).toArray();
+ }
+
+ @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("^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()));
+ }
+
+ @Then("the list should contain {int} element(s)")
+ public void theListShouldContainElement(int count) {
+ assertEquals(count, list.getLength());
+ }
+}
diff --git a/src/test/java/de/unibayreuth/se/teaching/list/CucumberTestRunner.java b/src/test/java/de/unibayreuth/se/teaching/list/CucumberTestRunner.java
new file mode 100644
index 0000000..b4133ac
--- /dev/null
+++ b/src/test/java/de/unibayreuth/se/teaching/list/CucumberTestRunner.java
@@ -0,0 +1,11 @@
+package de.unibayreuth.se.teaching.list;
+
+import io.cucumber.junit.platform.engine.Constants;
+import org.junit.platform.suite.api.*;
+
+@Suite
+@SelectPackages("de.unibayreuth.se.teaching.list")
+@ConfigurationParameter(key = Constants.PLUGIN_PROPERTY_NAME,value = "pretty, html:target/cucumber-report/cucumber.html")
+public class CucumberTestRunner {
+
+}
\ No newline at end of file
diff --git a/src/test/java/de/unibayreuth/se/teaching/list/DoublyLinkedListTest.java b/src/test/java/de/unibayreuth/se/teaching/list/DoublyLinkedListTest.java
new file mode 100644
index 0000000..48093a9
--- /dev/null
+++ b/src/test/java/de/unibayreuth/se/teaching/list/DoublyLinkedListTest.java
@@ -0,0 +1,245 @@
+package de.unibayreuth.se.teaching.list;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class DoublyLinkedListTest {
+ private DoublyLinkedList list;
+
+ @BeforeEach
+ void setUp() {
+ list = new DoublyLinkedList();
+ }
+
+ @Test
+ void testAppendElement() {
+ // given: the list is empty...
+ 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());
+ // ...and the new element is the start and end of the list
+ assertEquals(element, list.getStart());
+ 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());
+ }
+
+ @Test
+ void testInsertNewMinimum() {
+ // given: the list as four sorted elements
+ 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());
+ }
+
+ @Test
+ void testInsertNewMaximum() {
+ // given: the list as four sorted elements
+ 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());
+ }
+
+ @Test
+ void testInsertNeitherMinimumNorMaximum() {
+ // given: the list as four sorted elements
+ 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());
+ }
+
+ @Test
+ void testAppendElementFromOtherList() {
+ // give: an empty list and another list with three elements
+ 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));
+ // 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));
+ // 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));
+ }
+
+ @Test
+ void testAppendOneElementByValue() {
+ // given: the list is empty
+ assertEquals(0, list.getLength());
+ // when: appending a new element
+ list.append(0.9);
+ // then: the list has one element...
+ 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());
+ // ...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());
+ }
+
+ @Test
+ void testAppendTwoElementsByValue() {
+ // given: the list is empty
+ 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());
+ // ...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());
+ // ...and they are correctly linked
+ assertEquals(0.5, list.getStart().getNext().getValue());
+ assertEquals(0.9, list.getEnd().getPrev().getValue());
+ // ...and the start and end pointers are correctly set
+ testBeginEndPointers(list);
+ }
+
+ @Test
+ void testAppendThreeElementsByValue() {
+ // given: the list is empty
+ 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());
+ // ...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());
+ // ...and all elements are correctly linked
+ assertEquals(0.5, list.getStart().getNext().getValue());
+ assertEquals(0.5, list.getEnd().getPrev().getValue());
+ // ...and the start and end pointers are correctly set
+ testBeginEndPointers(list);
+ }
+
+ @Test
+ void testEmptyListToArray() {
+ // given: the list is empty
+ assertEquals(0, list.getLength());
+ // then: the array representation of the list is equal to an empty array
+ 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());
+ }
+
+ @Test
+ void testListToArray() {
+ // given: the list is empty
+ 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());
+ }
+
+ @Test
+ void testAppendArray() {
+ // given: the list is empty
+ 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());
+ }
+
+ @Test
+ void testIsEmptyOnEmptyList() {
+ // given: the list is empty
+ assertTrue(list.isEmpty());
+ // then: the array representation of the list is equal to an empty array
+ assertEquals(0, list.asArray().length);
+ }
+
+ @Test
+ void testIsEmptyOnNonEmptyList() {
+ // given: the list has three elements
+ assertTrue(list.isEmpty());
+ list.append(0.9);
+ list.append(0.5);
+ list.append(0.4);
+ // then: the list is not empty
+ assertFalse(list.isEmpty());
+ // when: emptying the list
+ list.empty();
+ // then: the list is empty again
+ assertTrue(list.isEmpty());
+ }
+
+ @Test
+ void testAppendOtherList() {
+ // give: an empty list and another list with three elements
+ 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());
+ }
+
+ @Test
+ void testToStringEmptyList() {
+ // given: the list is empty
+ assertTrue(list.isEmpty());
+ // then: the string representation of the list is "Empty."
+ assertEquals("Empty.", list.toString());
+ }
+
+ @Test
+ void testToStringNonEmptyList() {
+ // given: the list has three elements
+ 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());
+ }
+
+ /**
+ * Helper method to test begin and end pointers of a doubly linked list
+ * @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());
+ }
+}
diff --git a/src/test/resources/de/unibayreuth/se/teaching/list/append-to-list.feature b/src/test/resources/de/unibayreuth/se/teaching/list/append-to-list.feature
new file mode 100644
index 0000000..1765644
--- /dev/null
+++ b/src/test/resources/de/unibayreuth/se/teaching/list/append-to-list.feature
@@ -0,0 +1,17 @@
+Feature: AppendToListAcceptanceTests
+ This feature appends list elements by value.
+
+ Scenario: Append one element by value
+ Given an empty list
+ When I append an element with value 0.4
+ Then the list should contain 1 element
+ And the list should contain that element
+
+ Scenario: Append multiple elements to an empty list
+ Given an empty list
+ When I append an element with value 0.2
+ And I append an element with value 0.3
+ Then the list should contain 2 elements
+ And the list should contain the elements in the following order:
+ | 0.2 |
+ | 0.3 |
diff --git a/src/test/resources/de/unibayreuth/se/teaching/list/invert-list.feature b/src/test/resources/de/unibayreuth/se/teaching/list/invert-list.feature
new file mode 100644
index 0000000..6cb99e4
--- /dev/null
+++ b/src/test/resources/de/unibayreuth/se/teaching/list/invert-list.feature
@@ -0,0 +1,14 @@
+Feature: InvertListAcceptanceTests
+ This feature showcases how one can write acceptance tests for features that are not yet implemented.
+ Here: Inversion of the list.
+
+ Scenario: Invert the list
+ Given I have elements with the following values in my list:
+ | 1.1 |
+ | 2.3 |
+ | 4.1 |
+ When I invert the list
+ Then the list should contain the elements in the following order:
+ | 4.1 |
+ | 2.3 |
+ | 1.1 |
diff --git a/src/test/resources/de/unibayreuth/se/teaching/list/list-to-array.feature b/src/test/resources/de/unibayreuth/se/teaching/list/list-to-array.feature
new file mode 100644
index 0000000..63a0473
--- /dev/null
+++ b/src/test/resources/de/unibayreuth/se/teaching/list/list-to-array.feature
@@ -0,0 +1,16 @@
+Feature: ListToArrayAcceptanceTests
+ This feature converts the list to an array with the same elements in the same order.
+
+ Scenario: Convert a list with one element
+ Given I have elements with the following values in my list:
+ | 1.1 |
+ When I convert the list to an array
+ Then the array should contain the same elements in the same order
+
+ Scenario: Convert a list with three elements
+ Given I have elements with the following values in my list:
+ | 1.1 |
+ | 2.0 |
+ | 3.6 |
+ When I convert the list to an array
+ Then the array should contain the same elements in the same order