Zettelkasten-Team / Zettelkasten

Zettelkasten-Developer-Builds
http://zettelkasten.danielluedecke.de
GNU General Public License v3.0
737 stars 94 forks source link

Improve EntryID Class Documentation and Equality Logic #527

Closed RalfBarkow closed 5 months ago

RalfBarkow commented 5 months ago

The EntryID class requires improvements to its documentation and equality logic. The current implementation uses assertions in the equals method, which is not appropriate for production code. Additionally, the class and its methods lack proper Javadoc comments.

Tasks:

  1. Add Javadoc Comments:

    • Add class-level Javadoc to describe the purpose of the EntryID class.
    • Add Javadoc comments to the constructors and methods explaining their parameters, return values, and any exceptions thrown.
  2. Refactor equals Method:

    • Replace the assertion in the equals method with proper null checks and type checks using instanceof.
  3. Add TestNG Tests:

    • Create TestNG test cases to cover the following scenarios:
      • Construction from integer and string.
      • Handling invalid string input.
      • asInt and asString methods.
      • Equality checks (same object, null, different class, same entry number, different entry number).
      • Hash code consistency for equal and different objects.

Proposed Solution: Refactor the EntryID class as follows:

package de.danielluedecke.zettelkasten;

import java.util.Objects;

/**
 * Represents an entry number with two constructors for initialization,
 * and provides methods to retrieve the entry number as an int or a String.
 */
public class EntryID {
    private int entryNumber;

    /**
     * Constructs an EntryID with the specified integer entry number.
     *
     * @param entryNumber the entry number
     */
    public EntryID(int entryNumber) {
        this.entryNumber = entryNumber;
    }

    /**
     * Constructs an EntryID with the specified string entry number.
     * The string is parsed into an integer.
     *
     * @param entryNumber the entry number as a string
     * @throws NumberFormatException if the string does not contain a parsable integer
     */
    public EntryID(String entryNumber) throws NumberFormatException {
        this.entryNumber = Integer.parseInt(entryNumber);
    }

    /**
     * Returns the entry number as an integer.
     *
     * @return the entry number
     */
    public int asInt() {
        return entryNumber;
    }

    /**
     * Returns the entry number as a string.
     *
     * @return the entry number as a string
     */
    public String asString() {
        return Integer.toString(entryNumber);
    }

    @Override
    public int hashCode() {
        return Objects.hash(entryNumber);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null || getClass() != obj.getClass())
            return false;
        EntryID other = (EntryID) obj;
        return entryNumber == other.entryNumber;
    }
}

Add the corresponding TestNG test cases to EntryIDTest class.

RalfBarkow commented 5 months ago

TestNG Test Cases for EntryID Class

Let's create a set of TestNG test cases to verify the behavior of the EntryID class. These tests will cover various scenarios, including construction, method functionality, and equality checks.

Test Class: EntryIDTest

package de.danielluedecke.zettelkasten;

import org.testng.annotations.Test;
import static org.testng.Assert.*;

public class EntryIDTest {

    @Test
    public void testEntryIDIntConstructor() {
        EntryID entryID = new EntryID(123);
        assertEquals(entryID.asInt(), 123, "The entry number should be 123");
    }

    @Test
    public void testEntryIDStringConstructor() {
        EntryID entryID = new EntryID("456");
        assertEquals(entryID.asInt(), 456, "The entry number should be 456");
    }

    @Test(expectedExceptions = NumberFormatException.class)
    public void testEntryIDStringConstructorWithInvalidNumber() {
        new EntryID("invalid");
    }

    @Test
    public void testAsInt() {
        EntryID entryID = new EntryID(789);
        assertEquals(entryID.asInt(), 789, "The entry number should be 789");
    }

    @Test
    public void testAsString() {
        EntryID entryID = new EntryID(1011);
        assertEquals(entryID.asString(), "1011", "The entry number string should be '1011'");
    }

    @Test
    public void testEqualsSameObject() {
        EntryID entryID = new EntryID(1213);
        assertTrue(entryID.equals(entryID), "An EntryID should be equal to itself");
    }

    @Test
    public void testEqualsNull() {
        EntryID entryID = new EntryID(1415);
        assertFalse(entryID.equals(null), "An EntryID should not be equal to null");
    }

    @Test
    public void testEqualsDifferentClass() {
        EntryID entryID = new EntryID(1617);
        String notAnEntryID = "notAnEntryID";
        assertFalse(entryID.equals(notAnEntryID), "An EntryID should not be equal to an object of a different class");
    }

    @Test
    public void testEqualsSameEntryNumber() {
        EntryID entryID1 = new EntryID(1819);
        EntryID entryID2 = new EntryID(1819);
        assertTrue(entryID1.equals(entryID2), "EntryIDs with the same entry number should be equal");
    }

    @Test
    public void testEqualsDifferentEntryNumber() {
        EntryID entryID1 = new EntryID(2021);
        EntryID entryID2 = new EntryID(2223);
        assertFalse(entryID1.equals(entryID2), "EntryIDs with different entry numbers should not be equal");
    }

    @Test
    public void testHashCode() {
        EntryID entryID1 = new EntryID(2425);
        EntryID entryID2 = new EntryID(2425);
        assertEquals(entryID1.hashCode(), entryID2.hashCode(), "Equal EntryIDs should have the same hash code");
    }

    @Test
    public void testHashCodeDifferent() {
        EntryID entryID1 = new EntryID(2627);
        EntryID entryID2 = new EntryID(2829);
        assertNotEquals(entryID1.hashCode(), entryID2.hashCode(), "Different EntryIDs should have different hash codes");
    }
}

Explanation of Test Cases

  1. Constructor Tests:

    • testEntryIDIntConstructor: Tests the integer constructor.
    • testEntryIDStringConstructor: Tests the string constructor with a valid number.
    • testEntryIDStringConstructorWithInvalidNumber: Tests the string constructor with an invalid number, expecting a NumberFormatException.
  2. Method Tests:

    • testAsInt: Verifies the asInt method.
    • testAsString: Verifies the asString method.
  3. Equality Tests:

    • testEqualsSameObject: Checks if an object is equal to itself.
    • testEqualsNull: Checks if an object is not equal to null.
    • testEqualsDifferentClass: Checks if an object is not equal to an object of a different class.
    • testEqualsSameEntryNumber: Checks if two objects with the same entry number are equal.
    • testEqualsDifferentEntryNumber: Checks if two objects with different entry numbers are not equal.
  4. Hash Code Tests:

    • testHashCode: Verifies that equal objects have the same hash code.
    • testHashCodeDifferent: Verifies that different objects have different hash codes.