diff --git a/exercises/practice/simple-linked-list/.meta/src/reference/java/SimpleLinkedList.java b/exercises/practice/simple-linked-list/.meta/src/reference/java/SimpleLinkedList.java index a5e82d1bf..4519e7b42 100644 --- a/exercises/practice/simple-linked-list/.meta/src/reference/java/SimpleLinkedList.java +++ b/exercises/practice/simple-linked-list/.meta/src/reference/java/SimpleLinkedList.java @@ -1,20 +1,17 @@ - import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.List; import java.util.NoSuchElementException; import java.util.Objects; class SimpleLinkedList { - private static class Element { - final T value; Element next; - Element(T value) { this.value = value; } } - private Element head; private int size; @@ -48,6 +45,13 @@ T pop() { return value; } + T peek() { + if (Objects.isNull(head)) { + throw new NoSuchElementException(); + } + return head.value; + } + void reverse() { Element current = head; Element next; @@ -61,6 +65,16 @@ void reverse() { head = previous; } + List toList() { + List result = new ArrayList<>(); + Element current = head; + while (Objects.nonNull(current)) { + result.add(current.value); + current = current.next; + } + return result; + } + T[] asArray(Class clazz) { T[] result = newArray(clazz, size); int index = 0; @@ -75,7 +89,6 @@ T[] asArray(Class clazz) { private T[] newArray(Class clazz, int size) { @SuppressWarnings("unchecked") T[] arr = (T[]) Array.newInstance(clazz, size); - return arr; } diff --git a/exercises/practice/simple-linked-list/.meta/tests.toml b/exercises/practice/simple-linked-list/.meta/tests.toml new file mode 100644 index 000000000..cbf51c34e --- /dev/null +++ b/exercises/practice/simple-linked-list/.meta/tests.toml @@ -0,0 +1,104 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[962d998c-c203-41e2-8fbd-85a7b98b79b9] +description = "count -> Empty list has length of zero" + +[9760262e-d7e4-4639-9840-87e2e2fbb115] +description = "count -> Singleton list has length of one" + +[d9955c90-637c-441b-b41d-8cfb48e924a8] +description = "count -> Non-empty list has correct length" + +[0c3966db-58f9-4632-b94c-8ea13e54c2c8] +description = "pop -> Pop from empty list is an error" + +[a4f9d2e1-7425-49ef-9ee8-6c0cb3407cf0] +description = "pop -> Can pop from singleton list" + +[6dcbb2c9-d98a-47bc-a010-9c19703d3ea2] +description = "pop -> Can pop from non-empty list" + +[e83aade9-f030-4096-aaf0-f9dc6491e6cf] +description = "pop -> Can pop multiple items" + +[5c46bcf2-c0a9-4654-ae17-f3192436fcf1] +description = "pop -> Pop updates the count" + +[70d747a1-2e84-4ebc-bc3f-dcbee6a05f6b] +description = "push -> Can push to an empty list" +include = false + +[f3197f0a-1fea-45a5-939f-4a5ea60387ec] +description = "push -> Can push to an empty list" +reimplements = "70d747a1-2e84-4ebc-bc3f-dcbee6a05f6b" + +[391e332e-1f91-4033-b1e0-0e0c17812fa7] +description = "push -> Can push to a non-empty list" + +[ed4b0e01-3bbd-4895-af25-152b5914b3da] +description = "push -> Push updates count" + +[41666790-b932-4e5a-b323-e848a83d12d5] +description = "push -> Push and pop" + +[930a4a5c-76f6-47ec-9be3-4e70993173a1] +description = "peek -> Peek on empty list is an error" + +[43255a50-d919-4e81-afce-e4a271eaedbd] +description = "peek -> Can peek on singleton list" + +[48353020-e25d-4621-a854-e35fb1e15fa7] +description = "peek -> Can peek on non-empty list" + +[96fcead9-a713-46c2-8005-3f246c873851] +description = "peek -> Peek does not change the count" + +[7576ed05-7ff7-4b84-8efb-d34d62c110f5] +description = "peek -> Can peek after a pop and push" + +[b97d00b6-2fab-435d-ae74-3233dcc13698] +description = "toList LIFO -> Empty linked list to list is empty" + +[eedeb95f-b5cf-431d-8ad6-5854ba6b251c] +description = "toList LIFO -> To list with multiple values" + +[838678de-eaf3-4c14-b34e-7e35b6d851e8] +description = "toList LIFO -> To list after a pop" + +[03fc83a5-48a8-470b-a2d2-a286c5e8365f] +description = "toList FIFO -> Empty linked list to list is empty" +include = false + +[1282484e-a58c-426a-972e-90746bda61fc] +description = "toList FIFO -> To list with multiple values" +include = false + +[05ca3109-1249-4c0c-a567-a3b2f8352a7c] +description = "toList FIFO -> To list after a pop" +include = false + +[5e6c1a3d-e34b-46d3-be59-3f132a820ed5] +description = "reverse -> Reversed empty list has same values" + +[93c87ed3-862a-474f-820b-ba3fd6b6daf6] +description = "reverse -> Reversed singleton list is same list" + +[92851ebe-9f52-4406-b92e-0718c441a2ab] +description = "reverse -> Reversed non-empty list is reversed" +include = false + +[1210eeda-b23f-4790-930c-7ac6d0c8e723] +description = "reverse -> Reversed non-empty list is reversed" +reimplements = "92851ebe-9f52-4406-b92e-0718c441a2ab" + +[9b53af96-7494-4cfa-9b77-b7366fed5c4c] +description = "reverse -> Double reverse" diff --git a/exercises/practice/simple-linked-list/src/main/java/SimpleLinkedList.java b/exercises/practice/simple-linked-list/src/main/java/SimpleLinkedList.java index 9cff1bdc7..8926bee3d 100644 --- a/exercises/practice/simple-linked-list/src/main/java/SimpleLinkedList.java +++ b/exercises/practice/simple-linked-list/src/main/java/SimpleLinkedList.java @@ -1,29 +1,31 @@ +import java.util.List; + class SimpleLinkedList { SimpleLinkedList() { throw new UnsupportedOperationException("Please implement the SimpleLinkedList() constructor."); } - SimpleLinkedList(T[] values) { throw new UnsupportedOperationException("Please implement the SimpleLinkedList(T[]) constructor."); } - void push(T value) { throw new UnsupportedOperationException("Please implement the SimpleLinkedList.push() method."); } - T pop() { throw new UnsupportedOperationException("Please implement the SimpleLinkedList.pop() method."); } - + T peek() { + throw new UnsupportedOperationException("Please implement the SimpleLinkedList.peek() method."); + } void reverse() { throw new UnsupportedOperationException("Please implement the SimpleLinkedList.reverse() method."); } - + List toList() { + throw new UnsupportedOperationException("Please implement the SimpleLinkedList.toList() method."); + } T[] asArray(Class clazz) { throw new UnsupportedOperationException("Please implement the SimpleLinkedList.asArray() method."); } - int size() { throw new UnsupportedOperationException("Please implement the SimpleLinkedList.size() method."); } -} +} \ No newline at end of file diff --git a/exercises/practice/simple-linked-list/src/test/java/SimpleLinkedListTest.java b/exercises/practice/simple-linked-list/src/test/java/SimpleLinkedListTest.java index 109d3b3a7..d559a6221 100644 --- a/exercises/practice/simple-linked-list/src/test/java/SimpleLinkedListTest.java +++ b/exercises/practice/simple-linked-list/src/test/java/SimpleLinkedListTest.java @@ -1,68 +1,238 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; - import java.util.NoSuchElementException; - import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; public class SimpleLinkedListTest { @Test - @DisplayName("A new list is empty") - public void aNewListIsEmpty() { + @DisplayName("count -> Empty list has length of zero") + public void countEmptyListHasLengthOfZero() { SimpleLinkedList list = new SimpleLinkedList<>(); assertThat(list.size()).isEqualTo(0); } @Disabled("Remove to run test") @Test - @DisplayName("Create list from array") - public void canCreateFromArray() { - Character[] values = new Character[]{'1', '2', '3'}; - SimpleLinkedList list = new SimpleLinkedList(values); - assertThat(list.size()).isEqualTo(3); + @DisplayName("count -> Singleton list has length of one") + public void countSingletonListHasLengthOfOne() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1}); + assertThat(list.size()).isEqualTo(1); } @Disabled("Remove to run test") @Test - @DisplayName("Popping an empty list throws NoSuchElementException") - public void popOnEmptyListWillThrow() { - SimpleLinkedList list = new SimpleLinkedList(); + @DisplayName("count -> Non-empty list has correct length") + public void countNonEmptyListHasCorrectLength() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2, 3}); + assertThat(list.size()).isEqualTo(3); + } + @Disabled("Remove to run test") + @Test + @DisplayName("pop -> Pop from empty list is an error") + public void popFromEmptyListIsAnError() { + SimpleLinkedList list = new SimpleLinkedList<>(); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(list::pop); } @Disabled("Remove to run test") @Test - @DisplayName("Pop returns last added element (LIFO)") - public void popReturnsLastAddedElement() { - SimpleLinkedList list = new SimpleLinkedList(); - list.push(9); - list.push(8); + @DisplayName("pop -> Can pop from singleton list") + public void canPopFromSingletonList() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1}); + assertThat(list.pop()).isEqualTo(1); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("pop -> Can pop from non-empty list") + public void canPopFromNonEmptyList() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2}); + assertThat(list.pop()).isEqualTo(1); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("pop -> Can pop multiple items") + public void canPopMultipleItems() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2}); + assertThat(list.pop()).isEqualTo(1); + assertThat(list.pop()).isEqualTo(2); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("pop -> Pop updates the count") + public void popUpdatesTheCount() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2}); assertThat(list.size()).isEqualTo(2); - assertThat(list.pop()).isEqualTo(8); - assertThat(list.pop()).isEqualTo(9); + assertThat(list.pop()).isEqualTo(1); + assertThat(list.size()).isEqualTo(1); + assertThat(list.pop()).isEqualTo(2); assertThat(list.size()).isEqualTo(0); } @Disabled("Remove to run test") @Test - @DisplayName("Reverse reverses the list order") - public void reverseReversesList() { - SimpleLinkedList list = new SimpleLinkedList(); - list.push("9"); - list.push("8"); - list.push("7"); - list.push("6"); - list.push("5"); + @DisplayName("push -> Can push to an empty list") + public void canPushToAnEmptyList() { + SimpleLinkedList list = new SimpleLinkedList<>(); + list.push(1); + assertThat(list.size()).isEqualTo(1); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("push -> Can push to a non-empty list") + public void canPushToANonEmptyList() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2}); + list.push(3); + assertThat(list.size()).isEqualTo(3); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("push -> Push updates count") + public void pushUpdatesCount() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2}); + list.push(3); + assertThat(list.size()).isEqualTo(3); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("push -> Push and pop") + public void pushAndPop() { + SimpleLinkedList list = new SimpleLinkedList<>(); + list.push(1); + list.push(2); + assertThat(list.pop()).isEqualTo(2); + list.push(3); + assertThat(list.size()).isEqualTo(2); + assertThat(list.pop()).isEqualTo(3); + assertThat(list.pop()).isEqualTo(1); + assertThat(list.size()).isEqualTo(0); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("peek -> Peek on empty list is an error") + public void peekOnEmptyListIsAnError() { + SimpleLinkedList list = new SimpleLinkedList<>(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(list::peek); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("peek -> Can peek on singleton list") + public void canPeekOnSingletonList() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1}); + assertThat(list.peek()).isEqualTo(1); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("peek -> Can peek on non-empty list") + public void canPeekOnNonEmptyList() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2}); + assertThat(list.peek()).isEqualTo(1); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("peek -> Peek does not change the count") + public void peekDoesNotChangeTheCount() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2}); + assertThat(list.peek()).isEqualTo(1); + assertThat(list.size()).isEqualTo(2); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("peek -> Can peek after a pop and push") + public void canPeekAfterAPopAndPush() { + SimpleLinkedList list = new SimpleLinkedList<>(); + list.push(1); + list.push(2); + assertThat(list.peek()).isEqualTo(2); + assertThat(list.pop()).isEqualTo(2); + assertThat(list.peek()).isEqualTo(1); + list.push(3); + assertThat(list.peek()).isEqualTo(3); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("toList LIFO -> Empty linked list to list is empty") + public void toListLifoEmptyLinkedListToListIsEmpty() { + SimpleLinkedList list = new SimpleLinkedList<>(); + assertThat(list.toList()).isEmpty(); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("toList LIFO -> To list with multiple values") + public void toListLifoToListWithMultipleValues() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2, 3}); + assertThat(list.toList()).containsExactly(1, 2, 3); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("toList LIFO -> To list after a pop") + public void toListLifoToListAfterAPop() { + SimpleLinkedList list = new SimpleLinkedList<>(); + list.push(1); + list.push(2); + list.push(3); + assertThat(list.pop()).isEqualTo(3); + list.push(4); + assertThat(list.toList()).containsExactly(4, 2, 1); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("reverse -> Reversed empty list has same values") + public void reversedEmptyListHasSameValues() { + SimpleLinkedList list = new SimpleLinkedList<>(); + list.reverse(); + assertThat(list.toList()).isEmpty(); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("reverse -> Reversed singleton list is same list") + public void reversedSingletonListIsSameList() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1}); list.reverse(); - assertThat(list.pop()).isEqualTo("9"); - assertThat(list.pop()).isEqualTo("8"); - assertThat(list.pop()).isEqualTo("7"); - assertThat(list.pop()).isEqualTo("6"); - assertThat(list.pop()).isEqualTo("5"); + assertThat(list.toList()).containsExactly(1); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("reverse -> Reversed non-empty list is reversed") + public void reversedNonEmptyListIsReversed() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2, 3}); + list.reverse(); + assertThat(list.size()).isEqualTo(3); + assertThat(list.pop()).isEqualTo(3); + assertThat(list.pop()).isEqualTo(2); + assertThat(list.pop()).isEqualTo(1); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("reverse -> Double reverse") + public void doubleReverse() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2, 3}); + list.reverse(); + list.reverse(); + assertThat(list.pop()).isEqualTo(1); + assertThat(list.pop()).isEqualTo(2); + assertThat(list.pop()).isEqualTo(3); } @Disabled("Remove to run test") @@ -88,4 +258,12 @@ public void canReturnEmptyListAsEmptyArray() { assertThat(list.asArray(Object.class)).isEqualTo(expected); } + @Disabled("Remove to run test") + @Test + @DisplayName("Create list from array") + public void canCreateFromArray() { + Character[] values = new Character[]{'1', '2', '3'}; + SimpleLinkedList list = new SimpleLinkedList(values); + assertThat(list.size()).isEqualTo(3); + } }