Skip to content

Add generic Pair utility class with full test coverage for DSA convenience. #25020

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 162 additions & 0 deletions src/java.base/share/classes/java/util/Couple.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package java.util;

Check failure on line 1 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 18: carriage return (^M)

Check failure on line 2 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 0: carriage return (^M)
/**

Check failure on line 3 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 3: carriage return (^M)
* The {@code Couple} class represents a mutable, ordered Couple of elements.

Check failure on line 4 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 77: carriage return (^M)
* <p>

Check failure on line 5 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 6: carriage return (^M)
* This class mimics the behavior of the C++ Standard Library's `std::Couple`, providing two values, referred to as

Check failure on line 6 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 115: carriage return (^M)
* the "first" and the "second" elements, of possibly different types.

Check failure on line 7 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 70: carriage return (^M)
* <p>

Check failure on line 8 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 6: carriage return (^M)
* The {@code Couple} class provides a parameterized constructor to initialize both elements and allows access to them

Check failure on line 9 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 118: carriage return (^M)
* through getter and setter methods.

Check failure on line 10 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 37: carriage return (^M)
*

Check failure on line 11 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 2: carriage return (^M)
* @param <K> the type of the first element

Check failure on line 12 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 43: carriage return (^M)
* @param <V> the type of the second element

Check failure on line 13 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 44: carriage return (^M)
*

Check failure on line 14 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 2: carriage return (^M)
* @author Adarsh Sharma

Check failure on line 15 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 24: carriage return (^M)
* @since 1.0

Check failure on line 16 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 13: carriage return (^M)
*/

Check failure on line 17 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 3: carriage return (^M)
public class Couple<K extends Comparable<? super K>, V extends Comparable<? super V>>

Check failure on line 18 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 85: carriage return (^M)
implements Comparable<Couple<K, V>> {

Check failure on line 19 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 45: carriage return (^M)
private K first;

Check failure on line 20 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 20: carriage return (^M)
private V second;

Check failure on line 21 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 21: carriage return (^M)

Check failure on line 22 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 0: carriage return (^M)
/**

Check failure on line 23 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 7: carriage return (^M)
* Constructs a new Couple with the specified values.

Check failure on line 24 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 57: carriage return (^M)
*

Check failure on line 25 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 6: carriage return (^M)
* @param first the first element of the Couple

Check failure on line 26 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 51: carriage return (^M)
* @param second the second element of the Couple

Check failure on line 27 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 53: carriage return (^M)
*/

Check failure on line 28 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 7: carriage return (^M)
public Couple(K first, V second) {

Check failure on line 29 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 38: carriage return (^M)
this.first = first;

Check failure on line 30 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 27: carriage return (^M)
this.second = second;

Check failure on line 31 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 29: carriage return (^M)
}

Check failure on line 32 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 5: carriage return (^M)

Check failure on line 33 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 0: carriage return (^M)
/**

Check failure on line 34 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 7: carriage return (^M)
* Returns the first element of the Couple.

Check failure on line 35 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 47: carriage return (^M)
*

Check failure on line 36 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 6: carriage return (^M)
* @return the first element of the Couple

Check failure on line 37 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 46: carriage return (^M)
*/

Check failure on line 38 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 7: carriage return (^M)
public K getFirst() {

Check failure on line 39 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 25: carriage return (^M)
return first;

Check failure on line 40 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 21: carriage return (^M)
}

Check failure on line 41 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 5: carriage return (^M)

Check failure on line 42 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 0: carriage return (^M)
/**

Check failure on line 43 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 7: carriage return (^M)
* Sets the first element of the Couple.

Check failure on line 44 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 44: carriage return (^M)
*

Check failure on line 45 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 6: carriage return (^M)
* @param first the first element of the Couple

Check failure on line 46 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 51: carriage return (^M)
*/

Check failure on line 47 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 7: carriage return (^M)
public void setFirst(K first) {

Check failure on line 48 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 35: carriage return (^M)
this.first = first;

Check failure on line 49 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 27: carriage return (^M)
}

Check failure on line 50 in src/java.base/share/classes/java/util/Couple.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk-25020

Whitespace error

Column 5: carriage return (^M)

/**
* Returns the second element of the Couple.
*
* @return the second element of the Couple
*/
public V getSecond() {
return second;
}

/**
* Sets the second element of the Couple.
*
* @param second the second element of the Couple
*/
public void setSecond(V second) {
this.second = second;
}

/**
* Compares this Couple with the specified Couple for order.
* <p>
* Comparison is based first on the {@code first} elements, and if they are equal,
* then on the {@code second} elements. Both elements are compared using their natural ordering,
* unless they are {@code null}, in which case {@code null} is considered less than non-null.
* <p>
* This method is {@code null}-safe and consistent with equals when both elements are non-null.
*
* @param other the Couple to be compared
* @return a negative integer, zero, or a positive integer as this Couple
* is less than, equal to, or greater than the specified Couple
* @throws NullPointerException if {@code other} is {@code null}
*/
@Override
public int compareTo(Couple<K, V> other) {
if (other == null) {
throw new NullPointerException("Compared Couple must not be null");
}

int cmp = compareNullable(this.first, other.first);
if (cmp != 0) {
return cmp;
}

return compareNullable(this.second, other.second);
}

/**
* Helper method to compare two Comparable objects, handling nulls.
* {@code null} is considered less than any non-null value.
*
* @param a first value
* @param b second value
* @return comparison result
*/
@SuppressWarnings("unchecked")
private <T extends Comparable<? super T>> int compareNullable(T a, T b) {
if (a == b) return 0;
if (a == null) return -1;
if (b == null) return 1;
return a.compareTo(b);
}

/**
* Returns a string representation of this Couple in the format {@code (first, second)}.
*
* @return a string representation of this Couple
*/
@Override
public String toString() {
return "(" + first + ", " + second + ")";
}

/**
* Checks if this Couple is equal to another object. Two Couples are considered equal if both the first and second
* elements are equal.
*
* @param o the object to compare this Couple with
* @return {@code true} if this Couple is equal to the specified object
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Couple<?, ?> Couple = (Couple<?, ?>) o;
return Objects.equals(first, Couple.first) && Objects.equals(second, Couple.second);
}

/**
* Returns the hash code for this Couple, computed based on the hash codes of the first and second elements.
*
* @return the hash code for this Couple
*/
@Override
public int hashCode() {
return Objects.hash(first, second);
}

/**
* Creates a new {@code Couple} with the given first and second elements.
*
* @param first the first element of the Couple
* @param second the second element of the Couple
* @param <K> the type of the first element, must be Comparable
* @param <V> the type of the second element, must be Comparable
* @return a new {@code Couple} containing the given elements
*/
public static <K extends Comparable<? super K>, V extends Comparable<? super V>>
Couple<K, V> makeCouple(K first, V second) {
return new Couple<>(first, second);
}
}
190 changes: 190 additions & 0 deletions test/jdk/java/util/Couple/CoupleTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import org.testng.Assert;
import org.testng.annotations.Test;

import java.util.Objects;
import java.util.Stack;

/**
* Unit tests for the {@link Couple} class.
* <p>
* This class validates all functionalities of the {@code Couple} class including construction, getters/setters,
* equality, comparison, hash code generation, string representation, and utility methods like {@code swap} and
* {@code makeCouple}. It ensures correct behavior across different data types and edge cases (nulls, identity, etc.).
* </p>
*
* @author Adarsh Sharma
* @since 1.0
*/
public class CoupleTest {

/**
* Verifies that the constructor initializes the first and second elements correctly.
*/
@Test
public void testConstructor() {
Couple<Integer, String> Couple = new Couple<>(1, "one");
Assert.assertEquals(Couple.getFirst(), Integer.valueOf(1));
Assert.assertEquals(Couple.getSecond(), "one");
}

/**
* Verifies that the getter and setter methods update and retrieve values as expected.
*/
@Test
public void testGettersAndSetters() {
Couple<Integer, String> Couple = new Couple<>(1, "one");
Couple.setFirst(2);
Couple.setSecond("two");
Assert.assertEquals(Couple.getFirst(), Integer.valueOf(2));
Assert.assertEquals(Couple.getSecond(), "two");
}

/**
* Verifies that the {@code equals} method correctly evaluates object equality.
*/
@Test
public void testEquals() {
Couple<Integer, String> Couple1 = new Couple<>(1, "one");
Couple<Integer, String> Couple2 = new Couple<>(1, "one");
Couple<Integer, String> Couple3 = new Couple<>(2, "two");

Assert.assertTrue(Couple1.equals(Couple2));
Assert.assertFalse(Couple1.equals(Couple3));
Assert.assertFalse(Couple1.equals(null));
Assert.assertFalse(Couple1.equals("not a Couple"));
Assert.assertTrue(Couple1.equals(Couple1)); // Self-comparison
}

/**
* Verifies equality behavior when one or both elements are {@code null}.
*/
@Test
public void testEqualsWithNullElements() {
Couple<String, String> Couple1 = new Couple<>(null, "one");
Couple<String, String> Couple2 = new Couple<>(null, "one");
Assert.assertTrue(Couple1.equals(Couple2));
Couple<String, String> Couple3 = new Couple<>(null, null);
Couple<String, String> Couple4 = new Couple<>(null, null);
Assert.assertTrue(Couple1.equals(Couple2));
Assert.assertTrue(Couple2.equals(Couple1));
}

/**
* Validates that {@code hashCode} is consistent for equal Couples.
*/
@Test
public void testHashCode() {
Couple<Integer, String> Couple1 = new Couple<>(1, "one");
Couple<Integer, String> Couple2 = new Couple<>(1, "one");
Assert.assertEquals(Couple1.hashCode(), Couple2.hashCode());
}

/**
* Ensures {@code hashCode} handles {@code null} elements correctly.
*/
@Test
public void testHashCodeWithNulls() {
Couple<String, String> Couple = new Couple<>(null, null);
Assert.assertEquals(Couple.hashCode(), Objects.hash(null, null));
}

/**
* Validates the static factory method {@code makeCouple} creates an equivalent {@code Couple}.
*/
@Test
public void testMakeCouple() {
Couple<Integer, String> Couple = Couple.makeCouple(1, "one");
Assert.assertEquals(Couple.getFirst(), Integer.valueOf(1));
Assert.assertEquals(Couple.getSecond(), "one");
}

/**
* Tests usage of {@code Couple} with custom objects such as {@code Stack}.
*/
@Test
public void testCustomObjects() {
Couple<Stack<Integer>, String> Couple = new Couple<>(new Stack<>(), "test");
Couple.getFirst().push(1);
Couple.getFirst().push(2);
Assert.assertEquals(Couple.getFirst().size(), 2);
Assert.assertEquals(Couple.getSecond(), "test");
}

/**
* Validates the {@code toString} representation for non-null elements.
*/
@Test
public void testToString() {
Couple<Integer, String> Couple = new Couple<>(1, "one");
Assert.assertEquals(Couple.toString(), "(1, one)");
}

/**
* Validates the {@code toString} representation when both elements are {@code null}.
*/
@Test
public void testToStringWithNulls() {
Couple<String, String> Couple = new Couple<>(null, null);
Assert.assertEquals(Couple.toString(), "(null, null)");
}

/**
* Validates that {@code compareTo} returns zero for equal Couples.
*/
@Test
public void testCompareToEqual() {
Couple<String, String> Couple1 = new Couple<>("a", "b");
Couple<String, String> Couple2 = new Couple<>("a", "b");
Assert.assertEquals(Couple1.compareTo(Couple2), 0);
}

/**
* Validates that {@code compareTo} returns a negative or positive value
* when the first elements differ.
*/
@Test
public void testCompareToFirstDifferent() {
Couple<String, String> Couple1 = new Couple<>("a", "b");
Couple<String, String> Couple2 = new Couple<>("b", "b");
Assert.assertTrue(Couple1.compareTo(Couple2) < 0);
Assert.assertTrue(Couple2.compareTo(Couple1) > 0);
}

/**
* Validates that {@code compareTo} evaluates second elements when first are equal.
*/
@Test
public void testCompareToSecondDifferent() {
Couple<String, String> Couple1 = new Couple<>("a", "b");
Couple<String, String> Couple2 = new Couple<>("a", "c");
Assert.assertTrue(Couple1.compareTo(Couple2) < 0);
}

/**
* Tests {@code compareTo} behavior when one or both elements are {@code null}.
*/
@Test
public void testCompareToWithNulls() {
Couple<String, String> Couple1 = new Couple<>(null, "b");
Couple<String, String> Couple2 = new Couple<>("a", "b");
Assert.assertTrue(Couple1.compareTo(Couple2) < 0);

Couple<String, String> Couple3 = new Couple<>("a", null);
Couple<String, String> Couple4 = new Couple<>("a", "b");
Assert.assertTrue(Couple3.compareTo(Couple4) < 0);

Couple<String, String> Couple5 = new Couple<>(null, null);
Couple<String, String> Couple6 = new Couple<>(null, null);
Assert.assertEquals(Couple5.compareTo(Couple6), 0);
// null is considered less than non-null for comparison
}

/**
* Verifies that passing {@code null} to {@code compareTo} throws {@code NullPointerException}.
*/
@Test(expectedExceptions = NullPointerException.class)
public void testCompareToNull() {
Couple<String, String> Couple = new Couple<>("a", "b");
Couple.compareTo(null);
}
}