From 0004d4721f7a9789f83d80747836a0dfe779b5c5 Mon Sep 17 00:00:00 2001 From: Diego Leonardo Urban Date: Fri, 6 Nov 2026 16:36:56 +0100 Subject: [PATCH 1/2] Fix LinkedList and Vector removal bugs found by branch tests Adds tests for the untested branches of LinkedList, Set, Vector and Element. Two of them exposed bugs: - LinkedList.removeFromEnd on a one-element list decremented the size twice (once in removeFromStart, once after the if/else), leaving -1. The decrement now only happens in the branch that doesn't delegate. - Vector.remove read elements[i + 1] up to the last element, so removing from a full vector threw ArrayIndexOutOfBoundsException. The loop now stops one before the end. Co-Authored-By: Claude Opus 5.5 --- .../datastructure/linkedlist/LinkedList.java | 3 +- .../datastructure/vector/Vector.java | 2 +- .../algorithms/datastructure/ElementTest.java | 24 ++++++ .../linkedlist/LinkedListTest.java | 78 ++++++++++++++++++- .../algorithms/datastructure/set/SetTest.java | 38 +++++++-- .../datastructure/vector/VectorTest.java | 47 ++++++++++- 6 files changed, 179 insertions(+), 13 deletions(-) create mode 100644 src/test/java/io/github/diegourban/algorithms/datastructure/ElementTest.java diff --git a/src/main/java/io/github/diegourban/algorithms/datastructure/linkedlist/LinkedList.java b/src/main/java/io/github/diegourban/algorithms/datastructure/linkedlist/LinkedList.java index e162d23..e9b9153 100644 --- a/src/main/java/io/github/diegourban/algorithms/datastructure/linkedlist/LinkedList.java +++ b/src/main/java/io/github/diegourban/algorithms/datastructure/linkedlist/LinkedList.java @@ -96,9 +96,8 @@ public void removeFromEnd() { LinkedListNode previous = this.last.getPrevious(); previous.setNext(null); this.last = previous; + this.totalElements--; } - - this.totalElements--; } public void remove(final int position) { diff --git a/src/main/java/io/github/diegourban/algorithms/datastructure/vector/Vector.java b/src/main/java/io/github/diegourban/algorithms/datastructure/vector/Vector.java index 7430021..f0c4717 100644 --- a/src/main/java/io/github/diegourban/algorithms/datastructure/vector/Vector.java +++ b/src/main/java/io/github/diegourban/algorithms/datastructure/vector/Vector.java @@ -45,7 +45,7 @@ private boolean positionOccupied(final int position) { } public void remove(final int position) { - for(int i = position; i < this.totalElements; i++) { + for(int i = position; i < this.totalElements - 1; i++) { this.elements[i] = this.elements[i+1]; } totalElements--; diff --git a/src/test/java/io/github/diegourban/algorithms/datastructure/ElementTest.java b/src/test/java/io/github/diegourban/algorithms/datastructure/ElementTest.java new file mode 100644 index 0000000..d56df8b --- /dev/null +++ b/src/test/java/io/github/diegourban/algorithms/datastructure/ElementTest.java @@ -0,0 +1,24 @@ +package io.github.diegourban.algorithms.datastructure; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class ElementTest { + + @Test + void shouldEqualAnElementWithTheSameName() { + assertThat(new Element("diego")).isEqualTo(new Element("diego")); + assertThat(new Element("diego")).isNotEqualTo(new Element("paulo")); + } + + @Test + void shouldNotEqualNull() { + assertThat(new Element("diego").equals(null)).isFalse(); + } + + @Test + void shouldPrintItsName() { + assertThat(new Element("diego")).hasToString("diego"); + } +} diff --git a/src/test/java/io/github/diegourban/algorithms/datastructure/linkedlist/LinkedListTest.java b/src/test/java/io/github/diegourban/algorithms/datastructure/linkedlist/LinkedListTest.java index 926e270..28ed1ae 100644 --- a/src/test/java/io/github/diegourban/algorithms/datastructure/linkedlist/LinkedListTest.java +++ b/src/test/java/io/github/diegourban/algorithms/datastructure/linkedlist/LinkedListTest.java @@ -1,10 +1,12 @@ package io.github.diegourban.algorithms.datastructure.linkedlist; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; + import io.github.diegourban.algorithms.datastructure.Element; import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; - class LinkedListTest { @Test @@ -121,4 +123,76 @@ void shouldPrint() { assertThat(linkedList).hasToString("[diego,paulo,josé,]"); } + + @Test + void shouldAddAtPositionOfEmptyList() { + LinkedList linkedList = new LinkedList(); + linkedList.add(0, new Element("diego")); + + assertThat(linkedList.size()).isEqualTo(1); + assertThat(linkedList.get(0)).isEqualTo(new Element("diego")); + } + + @Test + void shouldAddAtPositionEqualToSizeAsLast() { + LinkedList linkedList = new LinkedList(); + linkedList.addAtEnd(new Element("diego")); + linkedList.add(1, new Element("paulo")); + + assertThat(linkedList).hasToString("[diego,paulo,]"); + } + + @Test + void shouldRejectGettingAMissingPosition() { + LinkedList linkedList = new LinkedList(); + linkedList.addAtEnd(new Element("diego")); + + assertThatIllegalArgumentException().isThrownBy(() -> linkedList.get(1)); + assertThatIllegalArgumentException().isThrownBy(() -> linkedList.get(-1)); + } + + @Test + void shouldRejectRemovingFromStartOfEmptyList() { + assertThatIllegalStateException().isThrownBy(() -> new LinkedList().removeFromStart()); + } + + @Test + void shouldBecomeEmptyAfterRemovingTheOnlyElementFromStart() { + LinkedList linkedList = new LinkedList(); + linkedList.addAtEnd(new Element("diego")); + linkedList.removeFromStart(); + + assertThat(linkedList.size()).isZero(); + assertThat(linkedList).hasToString("[]"); + } + + @Test + void shouldBecomeEmptyAfterRemovingTheOnlyElementFromEnd() { + LinkedList linkedList = new LinkedList(); + linkedList.addAtEnd(new Element("diego")); + linkedList.removeFromEnd(); + + assertThat(linkedList.size()).isZero(); + assertThat(linkedList).hasToString("[]"); + } + + @Test + void shouldRemoveFirstAndLastByPosition() { + LinkedList linkedList = new LinkedList(); + linkedList.addAtEnd(new Element("diego")); + linkedList.addAtEnd(new Element("paulo")); + linkedList.addAtEnd(new Element("josé")); + + linkedList.remove(0); + assertThat(linkedList).hasToString("[paulo,josé,]"); + + linkedList.remove(1); + assertThat(linkedList).hasToString("[paulo,]"); + assertThat(linkedList.size()).isEqualTo(1); + } + + @Test + void shouldPrintEmptyList() { + assertThat(new LinkedList()).hasToString("[]"); + } } diff --git a/src/test/java/io/github/diegourban/algorithms/datastructure/set/SetTest.java b/src/test/java/io/github/diegourban/algorithms/datastructure/set/SetTest.java index 3f6b865..f532aae 100644 --- a/src/test/java/io/github/diegourban/algorithms/datastructure/set/SetTest.java +++ b/src/test/java/io/github/diegourban/algorithms/datastructure/set/SetTest.java @@ -1,9 +1,9 @@ package io.github.diegourban.algorithms.datastructure.set; -import org.junit.jupiter.api.Test; - import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.Test; + class SetTest { @Test @@ -12,7 +12,9 @@ void shouldAdd() { set.add("Diego"); set.add("André"); set.add("Zuleika"); - assertThat(set).hasToString("[[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [Zuleika], [André], [], [], [Diego], [], [], []]"); + assertThat(set) + .hasToString( + "[[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [Zuleika], [André], [], [], [Diego], [], [], []]"); } @Test @@ -21,8 +23,34 @@ void shouldRemove() { set.add("Diego"); set.add("André"); set.add("Zuleika"); - assertThat(set).hasToString("[[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [Zuleika], [André], [], [], [Diego], [], [], []]"); + assertThat(set) + .hasToString( + "[[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [Zuleika], [André], [], [], [Diego], [], [], []]"); set.remove("André"); - assertThat(set).hasToString("[[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [Zuleika], [], [], [], [Diego], [], [], []]"); + assertThat(set) + .hasToString( + "[[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [Zuleika], [], [], [], [Diego], [], [], []]"); + } + + @Test + void shouldIgnoreDuplicates() { + Set set = new Set(); + set.add("Diego"); + set.add("Diego"); + + assertThat(set) + .hasToString( + "[[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [Diego], [], [], []]"); + } + + @Test + void shouldIgnoreRemovingAMissingWord() { + Set set = new Set(); + set.add("Diego"); + set.remove("Daniel"); + + assertThat(set) + .hasToString( + "[[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [Diego], [], [], []]"); } } diff --git a/src/test/java/io/github/diegourban/algorithms/datastructure/vector/VectorTest.java b/src/test/java/io/github/diegourban/algorithms/datastructure/vector/VectorTest.java index 28efa45..6332813 100644 --- a/src/test/java/io/github/diegourban/algorithms/datastructure/vector/VectorTest.java +++ b/src/test/java/io/github/diegourban/algorithms/datastructure/vector/VectorTest.java @@ -1,10 +1,11 @@ package io.github.diegourban.algorithms.datastructure.vector; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + import io.github.diegourban.algorithms.datastructure.Element; import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; - class VectorTest { @Test @@ -26,10 +27,50 @@ void test() { vector.remove(1); - for(int i = 0; i < 300; i++) { + for (int i = 0; i < 300; i++) { Element e = new Element("Element " + i); vector.add(e); } System.out.println(vector); } + + @Test + void shouldRejectAddingAtAnInvalidPosition() { + Vector vector = new Vector(); + vector.add(new Element("Joao")); + + assertThatIllegalArgumentException().isThrownBy(() -> vector.add(-1, new Element("Jose"))); + assertThatIllegalArgumentException().isThrownBy(() -> vector.add(5, new Element("Jose"))); + } + + @Test + void shouldRejectGettingAnInvalidPosition() { + Vector vector = new Vector(); + vector.add(new Element("Joao")); + + assertThat(vector.get(0)).isEqualTo(new Element("Joao")); + assertThatIllegalArgumentException().isThrownBy(() -> vector.get(1)); + assertThatIllegalArgumentException().isThrownBy(() -> vector.get(-1)); + } + + @Test + void shouldNotContainAMissingElement() { + Vector vector = new Vector(); + vector.add(new Element("Joao")); + + assertThat(vector.contains(new Element("Mario"))).isFalse(); + } + + @Test + void shouldRemoveFromAFullVector() { + Vector vector = new Vector(); + for (int i = 0; i < 100; i++) { + vector.add(new Element("Element " + i)); + } + + vector.remove(0); + + assertThat(vector.size()).isEqualTo(99); + assertThat(vector.get(0)).isEqualTo(new Element("Element 1")); + } } From e3210a5877aa40a2bd65b5d670b6c5ea2eda214f Mon Sep 17 00:00:00 2001 From: Diego Leonardo Urban Date: Fri, 6 Nov 2026 16:39:04 +0100 Subject: [PATCH 2/2] Check Element.equals(null) through AssertJ instead of calling it directly Codacy/PMD EqualsNull flagged the direct equals(null) call in the test. assertThat(element).isNotEqualTo(null) still invokes Element.equals(null), so the null branch stays covered (JaCoCo: 2/2 branches). Co-Authored-By: Claude Opus 5.5 --- .../github/diegourban/algorithms/datastructure/ElementTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/io/github/diegourban/algorithms/datastructure/ElementTest.java b/src/test/java/io/github/diegourban/algorithms/datastructure/ElementTest.java index d56df8b..bd7c4ea 100644 --- a/src/test/java/io/github/diegourban/algorithms/datastructure/ElementTest.java +++ b/src/test/java/io/github/diegourban/algorithms/datastructure/ElementTest.java @@ -14,7 +14,7 @@ void shouldEqualAnElementWithTheSameName() { @Test void shouldNotEqualNull() { - assertThat(new Element("diego").equals(null)).isFalse(); + assertThat(new Element("diego")).isNotEqualTo(null); } @Test