title: Finding eventual bugs with my homemade LinkedList
body: <p>I have made a singly linked list (LinkedList) with test codes to the LinkedList class and I had handed out all of my codes to my teacher, but he did not approve my homemade singly linked list because he has found some bugs in my implementation of the singly LinkedList and therefore, I was assigned to find all the bugs by the help of JUnit testing. He had referred to me that I was "missing" some test cases in the test codes which would help me to improve the LinkedList class and remove the eventual bugs.</p>
  
  <p>The following codes are those represented in the LinkedList class:</p>
  
  <pre><code>/**
   * A singly linked list.
   * 
   * @author 
   * @version
   */
  public class LinkedList&lt;T&gt; { 
      private ListElement&lt;T&gt; first;   // First element in list.
      private ListElement&lt;T&gt; last;    // Last element in list.
      private int size;               // Number of elements in list.
  
      /**
       * A list element.
       */
      private static class ListElement&lt;T&gt; {
          public T data;
          public ListElement&lt;T&gt; next;
  
          public ListElement(T data) {
              this.data = data;
              this.next = null;
          }
      }
  
          /**
       * Creates an empty list.
       */
      public LinkedList() {
          first = new ListElement&lt;&gt;(null);
          last = new ListElement&lt;&gt;(null);
          size = 0;
      }
  
      /**
       * This TEST METHOD returns true if the following invariants hold:
       * &lt;ul&gt;
       *   &lt;li&gt; size equals the number of list elements, &lt;/li&gt;
       *   &lt;li&gt; if size == 0, first == null and last == null, &lt;/li&gt;
       *   &lt;li&gt; if size &gt; 0, first != null and last != null, &lt;/li&gt;
       *   &lt;li&gt; if size == 1, first == last, &lt;/li&gt;
       *   &lt;li&gt; last.next == null. &lt;/li&gt;
       * &lt;/ul&gt;
       */
      public boolean isHealthy() {
          boolean health = true;
          int numberOfListElements = 0;
          ListElement&lt;T&gt; anElement = first;
  
          for(int i=0;i&lt;size;i++) {
              if(anElement != null) 
              numberOfListElements++;
  
              anElement = anElement.next;
          }
  
          if(size != numberOfListElements)
          health = false;
  
          if((size == 0) &amp;&amp; (health != false)) {
              if((first.data == null) &amp;&amp; (last.data == null)) {
              }
              else {
                  health = false;
              }
          }
          if((size == 1) &amp;&amp; (health != false)) {
              if((first == last) &amp;&amp; (last == first)) {
              }
              else {
                  health = false;
              }
          }
          else if((size &gt; 1) &amp;&amp; (health != false)) {
              if((first == null) || (last == null))
              health = false;
          }
  
          if(last.next != null)
          health = false;
  
          return health;
      }
  
      /**
       * Inserts the given element at the beginning of this list.
       */
      public void addFirst(T element) {
          if(size &lt;= 0) {
              first = new ListElement&lt;&gt;(element);
              last = first;
          }
          else {
              ListElement&lt;T&gt; anElement = first;
              first = new ListElement&lt;&gt;(element);
              first.next = anElement;
          }
          size++;
      }
  
      /**
       * Inserts the given element at the end of this list.
       */
      public void addLast(T element) {
          if(size &lt;= 0) {
              last = new ListElement&lt;&gt;(element);
              first = last;
          }
          else {
              ListElement&lt;T&gt; anElement = new ListElement&lt;&gt;(element);
              last.next = anElement;
              last = anElement;
          }
          size++;
      }
  
      /**
       * Returns the first element of this list.
       * Returns &lt;code&gt;null&lt;/code&gt; if the list is empty.
       */
      public T getFirst() {
          if(size() == 0)
          return null;
  
          return first.data;
      }
  
      /**
       * Returns the last element of this list.
       * Returns &lt;code&gt;null&lt;/code&gt; if the list is empty.
       */
      public T getLast() {
          if(size == 0)
              return null;
  
          return last.data;
      }
  
      /**
       * Returns the element at the specified position in this list.
       * Returns &lt;code&gt;null&lt;/code&gt; if &lt;code&gt;index&lt;/code&gt; is out of bounds.
       * @param Specify a value lying in the intervall 0-(size-1).
       */
      public T get(int index) {
          ListElement&lt;T&gt; anElement = first;
  
          if((index &lt; 0) || (index &gt;= size))
              return null;
  
          else {
              for(int i=0;i&lt;index;i++) {
                  anElement = anElement.next;
              }
          }
  
          return anElement.data;
      }
  
      /**
       * Removes and returns the first element from this list.
       * Returns &lt;code&gt;null&lt;/code&gt; if the list is empty.
       */
      public T removeFirst() {
          ListElement&lt;T&gt; removedElement = first;
          first = first.next;
  
          if(size&gt;0)
              size--;
  
          return removedElement.data;
      }
  
      /**
       * Removes all of the elements from this list.
       */
      public void clear() {
          first = new ListElement&lt;&gt;(null);
          last = new ListElement&lt;&gt;(null);
          last.next = null;
          size = 0;
      }
  
      /**
       * Returns the number of elements in this list.
       */
      public int size() {
          return size;
      }
  
      /**
       * Returns &lt;code&gt;true&lt;/code&gt; if this list contains no elements.
       */
      public boolean isEmpty() {
          ListElement&lt;T&gt; anElement = first;
  
          for(int i=0;i&lt;size;i++) {
              if(anElement != null)
              return false;
  
              anElement = anElement.next;
          }
  
          return true;
      }
  
      /**
       * Returns a string representation of this list. The string
       * representation consists of a list of the elements enclosed in
       * square brackets ("[]"). Adjacent elements are separated by the
       * characters ", " (comma and space). Elements are converted to
       * strings by the method toString() inherited from Object.
       */
      public String toString() {
          String representation = "[";
          ListElement&lt;T&gt; anElement = first;
  
          for(int i=1;i&lt;=size;i++) {
              representation += "" + anElement.data;
  
              if(i&lt;size) {
                  representation += ", ";
                  anElement = anElement.next;
              }
          }
          representation += "]";
  
          return representation;
      }
  }
  </code></pre>
  
  <p>The next following codes are the current test codes by the help of JUnit testing:</p>
  
  <pre><code>import static org.junit.Assert.*;
  import org.junit.After;
  import org.junit.Before;
  import org.junit.Test;
  
  /**
   * The test class LinkedListTest.
   *
   * @author  (your name)
   * @version (a version number or a date)
   */
  public class LinkedListTest
  {
      LinkedList&lt;Object&gt; test;
  
      /**
       * Default constructor for test class LinkedListTest
       */
      public LinkedListTest()
      {
          test = new LinkedList&lt;&gt;();
      }
  
      /**
       * Sets up the test fixture.
       *
       * Called before every test case method.
       */
      @Before
      public void setUp()
      {
      }
  
      /**
       * Tears down the test fixture.
       *
       * Called after every test case method.
       */
      @After
      public void tearDown()
      {
          test = null;
      }
  
      /**
       * Checks if the method addFirst() works properly. BE AWARE: This test only checks when the input is a type of an String.
       */
      @Test
      public void testAddFirst()
      {
          // When size = 0, row 50
          assertEquals(null, test.getFirst());
          assertEquals(null, test.getLast());
          assertEquals(0, test.size());
          assertTrue(test.isHealthy());
  
          // When size = 1
          test.addFirst("Hejsan");
          assertEquals("Hejsan", test.getFirst());
          assertEquals(test.getLast(), test.getFirst());
          assertEquals(1, test.size());
          assertTrue(test.isHealthy());
  
          // When size = 2
          test.addFirst("Svejsan");
          assertEquals("Svejsan", test.getFirst());
          assertEquals("Hejsan", test.getLast());
          assertEquals(2, test.size());
          assertTrue(test.isHealthy());
  
          //When size = 3
          test.addFirst("Hej då");
          assertEquals("Hej då", test.getFirst());
          assertEquals("Hejsan", test.getLast());
          assertEquals(3, test.size());
          assertTrue(test.isHealthy());
      }
  
      /**
       * Checks if the method addLast() works properly. BE AWARE: This test only checks when the input is a type of an String.
       */
      @Test
      public void testAddLast()
      {
          // When size = 0
          assertEquals(null, test.getFirst());
          assertEquals(null, test.getLast());
          assertEquals(0, test.size());
          assertTrue(test.isHealthy());
  
          // When size = 1
          test.addLast("Hejsan");
          assertEquals("Hejsan", test.getFirst());
          assertEquals(test.getLast(), test.getFirst());
          assertEquals(1, test.size());
          assertTrue(test.isHealthy());
  
          // When size = 2
          test.addLast("Svejsan");
          assertEquals("Hejsan", test.getFirst());
          assertEquals("Svejsan", test.getLast());
          assertEquals(2, test.size());
          assertTrue(test.isHealthy());
  
          // When size = 3
          test.addLast("Hej då");
          assertEquals("Hejsan", test.getFirst());
          assertEquals("Hej då", test.getLast());
          assertEquals(3, test.size());
          assertTrue(test.isHealthy());
      }
  
      /**
       * Checks if the method getFirst() works properly. BE AWARE: This test only checks when the input is a type of an String.
       */
      @Test
      public void testGetFirst()
      {
          assertEquals(null, test.getFirst());
  
          test.addFirst("1");
          test.addLast("2");
          test.addFirst("3");
          test.addFirst("4");
          test.addLast("5");
          test.addLast("6");
          test.addLast("7");
          test.addFirst("8");
          test.addLast("9");
          test.addLast("10");
  
          assertEquals("8", test.getFirst());
      }
  
      /**
       * Checks if the method getLast() works properly.
       */
      @Test
      public void testGetLast()
      {
          assertEquals(null, test.getLast());
  
          test.addLast("1");
          test.addLast("2");
          test.addFirst("4");
          test.addLast("8");
          test.addFirst("16");
          test.addFirst("32");
          test.addLast("64");
          test.addFirst("128");
          test.addFirst("256");
          test.addLast("512");
          test.addFirst("1024");
  
          assertEquals("512", test.getLast());
      }
  
      /**
       * Checks if the method get() works properly.
       */
      @Test
      public void testGet()
      {
          assertEquals(null, test.get(-1));
  
          test.addLast("1");
          test.addLast("2");
          test.addLast("4");
          test.addLast("8");
          test.addLast("16");
          test.addLast("32");
          test.addLast("64");
          test.addLast("128");
          test.addLast("256");
          test.addLast("512");
          test.addLast("1024");
          test.addLast("1");
          test.addLast("2");
          test.addLast("3");
          test.addLast("4");
          test.addLast("5");
          test.addLast("6");
          test.addLast("7");
          test.addLast("8");
          test.addLast("9");
          test.addLast("10");
  
          assertEquals("1", test.get(0));
          assertEquals("32", test.get(5));
          assertEquals("128", test.get(7));
          assertEquals("1024", test.get(10));
          assertEquals("1", test.get(11));
          assertEquals("10", test.get(20));
  
          assertEquals(null, test.get(test.size()));
      }
  
      /**
       * Checks if the method removeFirst() works properly.
       */
      @Test
      public void testRemoveFirst()
      {
          test.removeFirst();
          assertTrue(test.isHealthy());
          assertEquals(0, test.size());
  
          test.addLast("1");
          test.addLast("2");
          test.addLast("4");
          test.addLast("8");
          test.addLast("16");
          test.addLast("32");
          test.addLast("64");
          test.addLast("128");
          test.addLast("256");
          test.addLast("512");
          test.addLast("1024");
  
          assertEquals(11, test.size());
  
          test.removeFirst();
          assertEquals("2", test.getFirst());
          assertEquals(10, test.size());
      }
  
      /**
       * Checks if the method removeFirst() works properly.
       */
      @Test
      public void testClear()
      {
          assertTrue(test.isEmpty());
          assertTrue(test.isHealthy());
          test.clear();
          assertTrue(test.isHealthy());
          assertTrue(test.isEmpty());
  
          test.addLast("1");
          test.addLast("2");
          test.addLast("4");
          test.addLast("8");
          test.addLast("16");
          test.addLast("32");
          test.addLast("64");
          test.addLast("128");
          test.addLast("256");
          test.addLast("512");
          test.addLast("1024");
  
          assertEquals(11, test.size());
          assertFalse(test.isEmpty());
          assertTrue(test.isHealthy());
  
          test.clear();
          assertTrue(test.isEmpty());
          assertEquals(0, test.size());
          assertTrue(test.isHealthy());
      }
  
      /**
       * Checks if the method size() works properly.
       */
      @Test
      public void testSize()
      {
          assertEquals(0, test.size());
          assertTrue(test.isEmpty());
          assertTrue(test.isHealthy());
  
          test.addLast("1");
          test.addLast("2");
          test.addLast("4");
          test.addLast("8");
  
          assertEquals(4, test.size());
          assertFalse(test.isEmpty());
          assertTrue(test.isHealthy());
      }
  
      /**
       * Checks if the method isEmpty() works properly.
       */
      @Test
      public void testIsEmpty()
      {
          assertTrue(test.isEmpty());
          assertTrue(test.isHealthy());
          assertEquals(0, test.size());
  
          test.addLast("1");
          test.addLast("2");
          test.addLast("3");
          test.addLast("4");
  
          assertFalse(test.isEmpty());
          assertTrue(test.isHealthy());
          assertEquals(4, test.size());
  
          test.clear();
  
          assertTrue(test.isEmpty());
          assertTrue(test.isHealthy());
          assertEquals(0, test.size());
      }
  
      /**
       * Checks if the method toString() works properly.
       */
      @Test
      public void testToString()
      {
          assertEquals("[]", test.toString());
  
          test.addFirst("1");
          test.addLast("2");
          test.addFirst("3");
          test.addFirst("4");
          test.addLast("5");
  
          assertTrue(test.isHealthy());
          assertEquals("[4, 3, 1, 2, 5]", test.toString());
  
          test.clear();
  
          assertTrue(test.isHealthy());
          assertEquals("[]", test.toString());
      }
  }
  </code></pre>
  
  <p>Earlier I have missed the test case that when calling the removeFirst() method when the size of the linked list was zero, then the size should not be changed and the the method would return null, but the size only went down to -1, -2 and so on. But as you can see, this is already fixed. But just after that discouver, I had problems with finding other potential bugs in my codes :/</p>
  
  <p>But can you see other potential bugs in my codes? Could you give some clues about where I should look over in the test codes or something like that so I at least try to think on my own hand?</p>
  
  <p>Eventually, I would also to get some advices for how to write good test codes, perhaps according to some rule you might have for yourself when implementing data classes by the help of test codes or similarliy.</p>
  
  <p>I appreciate a fast answer from you!</p>
  
  <p>Thanks in advance!</p>
  
  <p>/Confused person :D</p>