Repository: TheAlgorithms/Java
Pull request #5991 (2024-10-25 12:04:01)

refactor: Enhance docs, add tests in `CircleLinkedList`
<!--
Thank you for your contribution!
In order to reduce the number of notifications sent to the maintainers, please:
- create your PR as draft, cf. https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests#draft-pull-requests,
- make sure that all of the CI checks pass,
- mark your PR as ready for review, cf. https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request#marking-a-pull-request-as-ready-for-review
-->

<!-- For completed items, change [ ] to [x] -->

- [x] I have read [CONTRIBUTING.md](https://github.com/TheAlgorithms/Java/blob/master/CONTRIBUTING.md).
- [x] This pull request is all my own work -- I have not plagiarized it.
- [x] All filenames are in PascalCase.
- [x] All functions and variable names follow Java naming conventions.
- [x] All new algorithms have a URL in their comments that points to Wikipedia or other similar explanations.
- [x] All new code is formatted with `clang-format -i --style=file path/to/your/file.java`

codecov-commenter: ## [Codecov](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5991?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms) Report
Attention: Patch coverage is `83.33333%` with `1 line` in your changes missing coverage. Please review.
> Project coverage is 67.98%. Comparing base [(`5246f63`)](https://app.codecov.io/gh/TheAlgorithms/Java/commit/5246f635797194f5f0d7ac93af61099a5764fa4f?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms) to head [(`80c43eb`)](https://app.codecov.io/gh/TheAlgorithms/Java/commit/80c43eb900f6ae020c2814a3224f2233de2e8ae4?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms).

| [Files with missing lines](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5991?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms) | Patch % | Lines |
|---|---|---|
| [...orithms/datastructures/lists/CircleLinkedList.java](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5991?src=pr&el=tree&filepath=src%2Fmain%2Fjava%2Fcom%2Fthealgorithms%2Fdatastructures%2Flists%2FCircleLinkedList.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms#diff-c3JjL21haW4vamF2YS9jb20vdGhlYWxnb3JpdGhtcy9kYXRhc3RydWN0dXJlcy9saXN0cy9DaXJjbGVMaW5rZWRMaXN0LmphdmE=) | 83.33% | [1 Missing :warning: ](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5991?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms) |

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff              @@
##             master    #5991      +/-   ##
============================================
- Coverage     67.98%   67.98%   -0.01%     
- Complexity     4586     4587       +1     
============================================
  Files           620      620              
  Lines         17116    17115       -1     
  Branches       3305     3305              
============================================
- Hits          11636    11635       -1     
  Misses         5035     5035              
  Partials        445      445              
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5991?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms).


Patch:
diff --git a/src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java b/src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java
index 2b50f731..422e8953 100644
--- a/src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java
+++ b/src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java
@@ -1,8 +1,23 @@
 package com.thealgorithms.datastructures.lists;
 
+/**
+ * This class is a circular singly linked list implementation. In a circular linked list,
+ * the last node points back to the first node, creating a circular chain.
+ *
+ * <p>This implementation includes basic operations such as appending elements
+ * to the end, removing elements from a specified position, and converting
+ * the list to a string representation.
+ *
+ * @param <E> the type of elements held in this list
+ */
 public class CircleLinkedList<E> {
 
-    private static final class Node<E> {
+    /**
+     * A static nested class representing a node in the circular linked list.
+     *
+     * @param <E> the type of element stored in the node
+     */
+    static final class Node<E> {
 
         Node<E> next;
         E value;
@@ -13,44 +28,56 @@ public class CircleLinkedList<E> {
         }
     }
 
-    // For better O.O design this should be private allows for better black box design
     private int size;
-    // this will point to dummy node;
-    private Node<E> head = null;
-    private Node<E> tail = null; // keeping a tail pointer to keep track of the end of list
+    Node<E> head = null;
+    private Node<E> tail;
 
-    // constructor for class.. here we will make a dummy node for circly linked list implementation
-    // with reduced error catching as our list will never be empty;
+    /**
+     * Initializes a new circular linked list. A dummy head node is used for simplicity,
+     * pointing initially to itself to ensure the list is never empty.
+     */
     public CircleLinkedList() {
-        // creation of the dummy node
-        head = new Node<E>(null, head);
+        head = new Node<>(null, head);
         tail = head;
         size = 0;
     }
 
-    // getter for the size... needed because size is private.
+    /**
+     * Returns the current size of the list.
+     *
+     * @return the number of elements in the list
+     */
     public int getSize() {
         return size;
     }
 
-    // for the sake of simplistiy this class will only contain the append function or addLast other
-    // add functions can be implemented however this is the basses of them all really.
+    /**
+     * Appends a new element to the end of the list. Throws a NullPointerException if
+     * a null value is provided.
+     *
+     * @param value the value to append to the list
+     * @throws NullPointerException if the value is null
+     */
     public void append(E value) {
         if (value == null) {
-            // we do not want to add null elements to the list.
             throw new NullPointerException("Cannot add null element to the list");
         }
-        // head.next points to the last element;
         if (tail == null) {
-            tail = new Node<E>(value, head);
+            tail = new Node<>(value, head);
             head.next = tail;
         } else {
-            tail.next = new Node<E>(value, head);
+            tail.next = new Node<>(value, head);
             tail = tail.next;
         }
         size++;
     }
 
+    /**
+     * Returns a string representation of the list in the format "[ element1, element2, ... ]".
+     * An empty list is represented as "[]".
+     *
+     * @return the string representation of the list
+     */
     public String toString() {
         if (size == 0) {
             return "[]";
@@ -68,23 +95,27 @@ public class CircleLinkedList<E> {
         return sb.toString();
     }
 
+    /**
+     * Removes and returns the element at the specified position in the list.
+     * Throws an IndexOutOfBoundsException if the position is invalid.
+     *
+     * @param pos the position of the element to remove
+     * @return the value of the removed element
+     * @throws IndexOutOfBoundsException if the position is out of range
+     */
     public E remove(int pos) {
         if (pos >= size || pos < 0) {
-            // catching errors
-            throw new IndexOutOfBoundsException("position cannot be greater than size or negative");
+            throw new IndexOutOfBoundsException("Position out of bounds");
         }
-        // we need to keep track of the element before the element we want to remove we can see why
-        // bellow.
+
         Node<E> before = head;
         for (int i = 1; i <= pos; i++) {
             before = before.next;
         }
         Node<E> destroy = before.next;
         E saved = destroy.value;
-        // assigning the next reference to the element following the element we want to remove...
-        // the last element will be assigned to the head.
-        before.next = before.next.next;
-        // scrubbing
+        before.next = destroy.next;
+
         if (destroy == tail) {
             tail = before;
         }


Test patch:
diff --git a/src/test/java/com/thealgorithms/datastructures/lists/CircleLinkedListTest.java b/src/test/java/com/thealgorithms/datastructures/lists/CircleLinkedListTest.java
index b7a05ef2..883d2b02 100644
--- a/src/test/java/com/thealgorithms/datastructures/lists/CircleLinkedListTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/lists/CircleLinkedListTest.java
@@ -1,78 +1,115 @@
 package com.thealgorithms.datastructures.lists;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 public class CircleLinkedListTest {
 
+    private CircleLinkedList<Integer> list;
+
+    @BeforeEach
+    public void setUp() {
+        list = new CircleLinkedList<>();
+    }
+
+    @Test
+    public void testInitialSize() {
+        assertEquals(0, list.getSize(), "Initial size should be 0.");
+    }
+
     @Test
     public void testAppendAndSize() {
-        CircleLinkedList<Integer> list = new CircleLinkedList<>();
         list.append(1);
         list.append(2);
         list.append(3);
 
-        assertEquals(3, list.getSize());
-        assertEquals("[ 1, 2, 3 ]", list.toString());
+        assertEquals(3, list.getSize(), "Size after three appends should be 3.");
+        assertEquals("[ 1, 2, 3 ]", list.toString(), "List content should match appended values.");
     }
 
     @Test
     public void testRemove() {
-        CircleLinkedList<Integer> list = new CircleLinkedList<>();
         list.append(1);
         list.append(2);
         list.append(3);
         list.append(4);
 
-        assertEquals(2, list.remove(1));
-        assertEquals(3, list.remove(1));
-        assertEquals("[ 1, 4 ]", list.toString());
-        assertEquals(2, list.getSize());
+        assertEquals(2, list.remove(1), "Removed element at index 1 should be 2.");
+        assertEquals(3, list.remove(1), "Removed element at index 1 after update should be 3.");
+        assertEquals("[ 1, 4 ]", list.toString(), "List content should reflect removals.");
+        assertEquals(2, list.getSize(), "Size after two removals should be 2.");
     }
 
     @Test
     public void testRemoveInvalidIndex() {
-        CircleLinkedList<Integer> list = new CircleLinkedList<>();
         list.append(1);
         list.append(2);
 
-        assertThrows(IndexOutOfBoundsException.class, () -> list.remove(2));
-        assertThrows(IndexOutOfBoundsException.class, () -> list.remove(-1));
+        assertThrows(IndexOutOfBoundsException.class, () -> list.remove(2), "Should throw on out-of-bounds index.");
+        assertThrows(IndexOutOfBoundsException.class, () -> list.remove(-1), "Should throw on negative index.");
     }
 
     @Test
     public void testToStringEmpty() {
-        CircleLinkedList<Integer> list = new CircleLinkedList<>();
-        assertEquals("[]", list.toString());
+        assertEquals("[]", list.toString(), "Empty list should be represented by '[]'.");
     }
 
     @Test
     public void testToStringAfterRemoval() {
-        CircleLinkedList<Integer> list = new CircleLinkedList<>();
         list.append(1);
         list.append(2);
         list.append(3);
         list.remove(1);
 
-        assertEquals("[ 1, 3 ]", list.toString());
+        assertEquals("[ 1, 3 ]", list.toString(), "List content should match remaining elements after removal.");
     }
 
     @Test
     public void testSingleElement() {
-        CircleLinkedList<Integer> list = new CircleLinkedList<>();
         list.append(1);
 
-        assertEquals(1, list.getSize());
-        assertEquals("[ 1 ]", list.toString());
-        assertEquals(1, list.remove(0));
-        assertEquals("[]", list.toString());
+        assertEquals(1, list.getSize(), "Size after single append should be 1.");
+        assertEquals("[ 1 ]", list.toString(), "Single element list should display properly.");
+        assertEquals(1, list.remove(0), "Single element removed should match appended value.");
+        assertEquals("[]", list.toString(), "List should be empty after removing the single element.");
     }
 
     @Test
     public void testNullElement() {
-        CircleLinkedList<String> list = new CircleLinkedList<>();
-        assertThrows(NullPointerException.class, () -> list.append(null));
+        assertThrows(NullPointerException.class, () -> list.append(null), "Appending null should throw exception.");
+    }
+
+    @Test
+    public void testCircularReference() {
+        list.append(1);
+        list.append(2);
+        list.append(3);
+        CircleLinkedList.Node<Integer> current = list.head;
+
+        // Traverse one full cycle and verify the circular reference
+        for (int i = 0; i <= list.getSize(); i++) {
+            current = current.next;
+        }
+        assertEquals(list.head, current, "End of list should point back to the head (circular structure).");
+    }
+
+    @Test
+    public void testClear() {
+        list.append(1);
+        list.append(2);
+        list.append(3);
+
+        // Remove all elements to simulate clearing the list
+        for (int i = list.getSize() - 1; i >= 0; i--) {
+            list.remove(i);
+        }
+
+        assertEquals(0, list.getSize(), "Size after clearing should be 0.");
+        assertEquals("[]", list.toString(), "Empty list should be represented by '[]' after clear.");
+        assertSame(list.head.next, list.head, "Head's next should point to itself after clearing.");
     }
 }