From a2c85420ff7283a7547efd7ce48081e17f9e6033 Mon Sep 17 00:00:00 2001 From: Bill Huang Date: Thu, 7 May 2026 16:21:37 -0700 Subject: [PATCH 1/9] JDK-83883658 [lworld] Add value class test coverage to java.util.Collections --- test/jdk/java/util/Collections/AddAll.java | 34 +++++++------ .../java/util/Collections/AsLifoQueue.java | 16 +++++- .../util/Collections/BigBinarySearch.java | 20 +++++++- .../BinarySearchNullComparator.java | 11 ++++- .../util/Collections/CheckedListBash.java | 21 +++++++- .../Collections/CheckedListReplaceAll.java | 17 ++++++- .../java/util/Collections/CheckedMapBash.java | 20 +++++++- .../Collections/CheckedMapReplaceAll.java | 19 ++++++- .../java/util/Collections/CheckedQueue.java | 17 ++++++- .../java/util/Collections/CheckedSetBash.java | 23 ++++++++- test/jdk/java/util/Collections/Disjoint.java | 12 ++++- test/jdk/java/util/Collections/Enum.java | 14 +++++- .../Collections/EnumerationAsIterator.java | 11 ++++- .../java/util/Collections/FindSubList.java | 13 ++++- test/jdk/java/util/Collections/Frequency.java | 18 ++++++- test/jdk/java/util/Collections/NCopies.java | 16 +++++- .../java/util/Collections/NullComparator.java | 19 ++++++- .../jdk/java/util/Collections/ReplaceAll.java | 12 ++++- .../java/util/Collections/ReverseOrder.java | 11 ++++- .../java/util/Collections/ReverseOrder2.java | 12 ++++- test/jdk/java/util/Collections/Rotate.java | 11 ++++- test/jdk/java/util/Collections/Ser.java | 49 ++++++++++++++++++- test/jdk/java/util/Collections/Shuffle.java | 16 +++++- .../util/Collections/SingletonIterator.java | 16 +++++- test/jdk/java/util/Collections/Swap.java | 11 ++++- test/jdk/java/util/Collections/T6433170.java | 12 ++++- test/lib/jdk/test/lib/valueclass/Tuple.java | 44 +++++++++++++++++ 27 files changed, 452 insertions(+), 43 deletions(-) create mode 100644 test/lib/jdk/test/lib/valueclass/Tuple.java diff --git a/test/jdk/java/util/Collections/AddAll.java b/test/jdk/java/util/Collections/AddAll.java index 60e6b95bcb7..849b1331a17 100644 --- a/test/jdk/java/util/Collections/AddAll.java +++ b/test/jdk/java/util/Collections/AddAll.java @@ -31,7 +31,7 @@ * @run main AddAll */ -import jdk.test.lib.valueclass.AsValueClass; +import jdk.test.lib.valueclass.Tuple; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -44,24 +44,21 @@ import java.util.Random; public class AddAll { - static final int N = 100; + static final int N = 10; public static void main(String[] args) { test(new ArrayList()); test(new LinkedList()); test(new HashSet()); test(new LinkedHashSet()); - testPoint(new ArrayList()); + + testTuple(new ArrayList()); + testTuple(new LinkedList()); + testTuple(new HashSet()); + testTuple(new LinkedHashSet()); } private static Random rnd = new Random(); - @AsValueClass - static class Point { - int x; - int y; - Point(int x, int y) { this.x = x; this.y = y; } - } - static void test(Collection c) { int x = 0; for (int i = 0; i < N; i++) { @@ -87,21 +84,28 @@ private static Integer[] range(int from, int to) { return result; } - static void testPoint(Collection c) { + static void testTuple(Collection c) { int x = 0; for (int i = 0; i < N; i++) { int rangeLen = rnd.nextInt(10); - if (Collections.addAll(c, rangePoint(x, x + rangeLen)) != + if (Collections.addAll(c, rangeTuple(x, x + rangeLen)) != (rangeLen != 0)) throw new RuntimeException("" + rangeLen); x += rangeLen; } + if (c instanceof List) { + if (!c.equals(Arrays.asList(rangeTuple(0, x)))) + throw new RuntimeException(x + ": " + c); + } else { + if (!c.equals(new HashSet(Arrays.asList(rangeTuple(0, x))))) + throw new RuntimeException(x + ": " + c); + } } - private static Point[] rangePoint(int from, int to) { - Point[] result = new Point[to - from]; + private static Tuple[] rangeTuple(int from, int to) { + Tuple[] result = new Tuple[to - from]; for (int i = from, j = 0; i < to; i++, j++) - result[j] = new Point(i, i); + result[j] = new Tuple(i, i); return result; } } diff --git a/test/jdk/java/util/Collections/AsLifoQueue.java b/test/jdk/java/util/Collections/AsLifoQueue.java index c573e32f49b..c2a951ec8a2 100644 --- a/test/jdk/java/util/Collections/AsLifoQueue.java +++ b/test/jdk/java/util/Collections/AsLifoQueue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,11 @@ * @bug 6301085 6192552 6365601 * @summary Basic tests for asLifoQueue * @author Martin Buchholz + * @library /test/lib + * @run main AsLifoQueue */ +import jdk.test.lib.valueclass.Tuple; import java.util.*; import java.util.concurrent.*; @@ -72,6 +75,17 @@ private static void realMain(String[] args) throws Throwable { } catch (Throwable t) { unexpected(t); } THROWS(NullPointerException.class, () -> Collections.asLifoQueue(null)); + + try { + Deque deq = new ArrayDeque<>(); + Queue q = Collections.asLifoQueue(deq); + check(q.add(new Tuple(1, 1))); + check(q.add(new Tuple(2, 2))); + equal(q.peek(), new Tuple(2, 2)); + equal(q.remove(), new Tuple(2, 2)); + equal(q.poll(), new Tuple(1, 1)); + check(q.isEmpty()); + } catch (Throwable t) { unexpected(t); } } //--------------------- Infrastructure --------------------------- diff --git a/test/jdk/java/util/Collections/BigBinarySearch.java b/test/jdk/java/util/Collections/BigBinarySearch.java index b10081c7582..6e282711e2c 100644 --- a/test/jdk/java/util/Collections/BigBinarySearch.java +++ b/test/jdk/java/util/Collections/BigBinarySearch.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,11 @@ * @bug 5045582 * @summary binarySearch of Collections larger than 1<<30 * @author Martin Buchholz + * @library /test/lib + * @run main BigBinarySearch */ +import jdk.test.lib.valueclass.Tuple; import java.util.AbstractList; import java.util.Collections; import java.util.Comparator; @@ -38,6 +41,13 @@ public class BigBinarySearch { + static class SparseTupleList extends AbstractList implements RandomAccess { + final Map m = new HashMap<>(); + public Tuple get(int i) { return m.getOrDefault(i, new Tuple(0, 0)); } + public int size() { return Collections.max(m.keySet()) + 1; } + public Tuple set(int i, Tuple v) { return m.put(i, v); } + } + // Allows creation of very "big" collections without using too // many real resources static class SparseIntegerList @@ -102,6 +112,14 @@ private static void realMain(String[] args) throws Throwable { big.set(i, - big.get(i)); for (int i : ints) checkBinarySearch(big, i, reverse); + + System.out.println("binarySearch(SparseTupleList, Tuple)"); + SparseTupleList vl = new SparseTupleList(); + vl.set(0, new Tuple(0, 0)); + vl.set(1, new Tuple(1, 1)); + vl.set(n - 2, new Tuple(n - 2, n - 2)); + vl.set(n - 1, new Tuple(n - 1, n - 1)); + equal(n - 1, Collections.binarySearch(vl, new Tuple(n - 1, n - 1))); } //--------------------- Infrastructure --------------------------- diff --git a/test/jdk/java/util/Collections/BinarySearchNullComparator.java b/test/jdk/java/util/Collections/BinarySearchNullComparator.java index 62bf55f9b0e..deb98b3789e 100644 --- a/test/jdk/java/util/Collections/BinarySearchNullComparator.java +++ b/test/jdk/java/util/Collections/BinarySearchNullComparator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,18 +25,27 @@ * @test * @bug 4528331 5006032 * @summary Test Collections.binarySearch() with a null comparator + * @library /test/lib + * @run main BinarySearchNullComparator */ +import jdk.test.lib.valueclass.Tuple; import java.util.Arrays; import java.util.Collections; import java.util.List; public class BinarySearchNullComparator { + public static void main(String[] args) throws Exception { List list = Arrays.asList(new String[] {"I", "Love", "You"}); int result = Collections.binarySearch(list, "You", null); if (result != 2) throw new Exception("Result: " + result); + + List values = Arrays.asList(new Tuple(1, 1), new Tuple(2, 2), new Tuple(3, 3)); + int vresult = Collections.binarySearch(values, new Tuple(3, 3), null); + if (vresult != 2) + throw new Exception("Value result: " + vresult); } } diff --git a/test/jdk/java/util/Collections/CheckedListBash.java b/test/jdk/java/util/Collections/CheckedListBash.java index 1adfc0ddd4a..550fbccd492 100644 --- a/test/jdk/java/util/Collections/CheckedListBash.java +++ b/test/jdk/java/util/Collections/CheckedListBash.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,8 +27,11 @@ * @summary Unit test for Collections.checkedList * @author Josh Bloch * @key randomness + * @library /test/lib + * @run main CheckedListBash */ +import jdk.test.lib.valueclass.Tuple; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -182,6 +185,7 @@ public static void main(String[] args) { || !l.equals(Arrays.asList(ia).subList(0, listSize))) fail("toArray(Object[]) is hosed (3)"); + testValueCheckedList(); } // Done inefficiently so as to exercise toArray @@ -225,4 +229,19 @@ static void AddRandoms(List s, int n) { static void fail(String s) { throw new RuntimeException(s); } + + static void testValueCheckedList() { + List list = Collections.checkedList(new ArrayList<>(), Tuple.class); + list.add(new Tuple(1, 1)); + list.add(new Tuple(2, 2)); + if (!list.contains(new Tuple(1, 1)) || list.indexOf(new Tuple(2, 2)) != 1) + fail("value checkedList lookup failed"); + Tuple[] a = list.toArray(new Tuple[0]); + if (!Arrays.asList(a).equals(list)) + fail("value checkedList toArray failed"); + try { + ((List) list).add("not a Tuple"); + fail("value checkedList accepted wrong type"); + } catch (ClassCastException expected) { } + } } diff --git a/test/jdk/java/util/Collections/CheckedListReplaceAll.java b/test/jdk/java/util/Collections/CheckedListReplaceAll.java index 19042db24d6..5f9842f8820 100644 --- a/test/jdk/java/util/Collections/CheckedListReplaceAll.java +++ b/test/jdk/java/util/Collections/CheckedListReplaceAll.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,12 +26,16 @@ * @bug 8047795 8053938 * @summary Ensure that replaceAll operator cannot add bad elements * @author Mike Duigou + * @library /test/lib + * @run main CheckedListReplaceAll */ +import jdk.test.lib.valueclass.Tuple; import java.util.*; import java.util.function.UnaryOperator; public class CheckedListReplaceAll { + public static void main(String[] args) { List unwrapped = Arrays.asList(new Object[]{1, 2, 3}); List wrapped = Collections.checkedList(unwrapped, Integer.class); @@ -57,5 +61,16 @@ public static void main(String[] args) { thwarted.printStackTrace(System.out); System.out.println("Curses! Foiled again!"); } + + List vList = Collections.checkedList(new ArrayList(Arrays.asList(new Tuple(1, 1))), Tuple.class); + vList.replaceAll(v -> new Tuple(v.x + 1, v.x + 1)); + if (!vList.get(0).equals(new Tuple(2, 2))) + throw new RuntimeException("value checkedList replaceAll failed"); + + List raw = Collections.checkedList(new ArrayList(Arrays.asList(new Tuple(1, 1))), Tuple.class); + try { + raw.replaceAll(e -> "not a Tuple"); + throw new RuntimeException("value checkedList replaceAll accepted wrong type"); + } catch (ClassCastException expected) { } } } diff --git a/test/jdk/java/util/Collections/CheckedMapBash.java b/test/jdk/java/util/Collections/CheckedMapBash.java index a8e3fd9e952..d4eab60ba98 100644 --- a/test/jdk/java/util/Collections/CheckedMapBash.java +++ b/test/jdk/java/util/Collections/CheckedMapBash.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,10 +26,12 @@ * @bug 4904067 5023830 7129185 8072015 8292955 * @summary Unit test for Collections.checkedMap * @author Josh Bloch - * @run testng CheckedMapBash * @key randomness + * @library /test/lib + * @run testng CheckedMapBash */ +import jdk.test.lib.valueclass.Tuple; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -191,4 +193,18 @@ public static void testCheckedMapMerge() { Assert.assertThrows(ClassCastException.class, () -> m.merge("key", "value", (v1, v2) -> null)); Assert.assertThrows(ClassCastException.class, () -> m.merge("key", 3, (v1, v2) -> v2)); } + + @Test + public static void testValueCheckedMap() { + Map m = Collections.checkedMap(new HashMap<>(), Tuple.class, Tuple.class); + m.put(new Tuple(1, 1), new Tuple(10, 10)); + if (!m.containsKey(new Tuple(1, 1)) || !m.containsValue(new Tuple(10, 10))) + fail("value checkedMap lookup failed"); + if (!new HashMap<>(m).equals(m)) + fail("value checkedMap equals failed"); + try { + ((Map) m).put("not a Tuple", new Tuple(2, 2)); + fail("value checkedMap accepted wrong type"); + } catch (ClassCastException expected) { } + } } diff --git a/test/jdk/java/util/Collections/CheckedMapReplaceAll.java b/test/jdk/java/util/Collections/CheckedMapReplaceAll.java index 05c4da3ad5e..b9d7885f0bd 100644 --- a/test/jdk/java/util/Collections/CheckedMapReplaceAll.java +++ b/test/jdk/java/util/Collections/CheckedMapReplaceAll.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,12 +26,16 @@ * @bug 8047795 * @summary Ensure that replaceAll operator cannot add bad elements * @author Mike Duigou + * @library /test/lib + * @run main CheckedMapReplaceAll */ +import jdk.test.lib.valueclass.Tuple; import java.util.*; import java.util.function.BiFunction; public class CheckedMapReplaceAll { + public static void main(String[] args) { Map unwrapped = new HashMap<>(); unwrapped.put(1, 1.0); @@ -50,5 +54,18 @@ public static void main(String[] args) { thwarted.printStackTrace(System.out); System.out.println("Curses! Foiled again!"); } + + Map vMap = Collections.checkedMap(new HashMap<>(), Tuple.class, Tuple.class); + vMap.put(new Tuple(1, 1), new Tuple(2, 2)); + vMap.replaceAll((k, v) -> new Tuple(v.x + 1, v.x + 1)); + if (!vMap.get(new Tuple(1, 1)).equals(new Tuple(3, 3))) + throw new RuntimeException("value checkedMap replaceAll failed"); + + Map raw = Collections.checkedMap(new HashMap(), Tuple.class, Tuple.class); + raw.put(new Tuple(1, 1), new Tuple(2, 2)); + try { + raw.replaceAll((k, v) -> "not a Tuple"); + throw new RuntimeException("value checkedMap replaceAll accepted wrong type"); + } catch (ClassCastException expected) { } } } diff --git a/test/jdk/java/util/Collections/CheckedQueue.java b/test/jdk/java/util/Collections/CheckedQueue.java index fb47e2e5ca1..853d9e774ae 100644 --- a/test/jdk/java/util/Collections/CheckedQueue.java +++ b/test/jdk/java/util/Collections/CheckedQueue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,12 @@ * @test * @bug 5020931 8048207 * @summary Unit test for Collections.checkedQueue + * @library /test/lib * @run testng CheckedQueue */ +import jdk.test.lib.valueclass.Tuple; +import java.util.ArrayDeque; import java.util.Collections; import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; @@ -149,4 +152,16 @@ public void testOffer() { // no room at the inn! assertFalse(q.offer("1"), "queue should be full"); } + + @Test + public void testValueCheckedQueue() { + Queue q = Collections.checkedQueue(new ArrayDeque<>(), Tuple.class); + q.add(new Tuple(1, 1)); + if (!q.peek().equals(new Tuple(1, 1))) + fail("value checkedQueue peek failed"); + try { + ((Queue) q).add("not a Tuple"); + fail("value checkedQueue accepted wrong type"); + } catch (ClassCastException expected) { } + } } diff --git a/test/jdk/java/util/Collections/CheckedSetBash.java b/test/jdk/java/util/Collections/CheckedSetBash.java index 16dfb11b449..d6f4216e47e 100644 --- a/test/jdk/java/util/Collections/CheckedSetBash.java +++ b/test/jdk/java/util/Collections/CheckedSetBash.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,10 +26,12 @@ * @bug 4904067 7129185 * @summary Unit test for Collections.checkedSet * @author Josh Bloch - * @run testng CheckedSetBash * @key randomness + * @library /test/lib + * @run testng CheckedSetBash */ +import jdk.test.lib.valueclass.Tuple; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -177,4 +179,21 @@ public static Collection makeCheckedSets() { }; return Arrays.asList(params); } + + @Test + public static void testValueCheckedSet() { + Set s = Collections.checkedSet(new HashSet<>(), Tuple.class); + s.add(new Tuple(1, 1)); + s.add(new Tuple(2, 2)); + if (!s.contains(new Tuple(1, 1))) + fail("value checkedSet lookup failed"); + Set copy = Collections.checkedSet(new HashSet<>(), Tuple.class); + copy.addAll(Arrays.asList(s.toArray(new Tuple[0]))); + if (!s.equals(copy)) + fail("value checkedSet addAll failed"); + try { + ((Set) s).add("not a Tuple"); + fail("value checkedSet accepted wrong type"); + } catch (ClassCastException expected) { } + } } diff --git a/test/jdk/java/util/Collections/Disjoint.java b/test/jdk/java/util/Collections/Disjoint.java index 13bdac86d5e..110ac6526a2 100644 --- a/test/jdk/java/util/Collections/Disjoint.java +++ b/test/jdk/java/util/Collections/Disjoint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,9 +27,13 @@ * @summary Basic test for Collections.disjoint * @author Josh Bloch * @key randomness + * @library /test/lib + * @run main Disjoint */ +import jdk.test.lib.valueclass.Tuple; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -71,5 +75,11 @@ public static void main(String[] args) { throw new RuntimeException("C: " + i + ", " + j); } } + + List va = Arrays.asList(new Tuple(1, 1), new Tuple(2, 2)); + List vb = Arrays.asList(new Tuple(3, 3), new Tuple(4, 4)); + List vc = Arrays.asList(new Tuple(2, 2), new Tuple(5, 5)); + if (!Collections.disjoint(va, vb)) throw new RuntimeException("value disjoint failed"); + if (Collections.disjoint(va, vc)) throw new RuntimeException("value non-disjoint failed"); } } diff --git a/test/jdk/java/util/Collections/Enum.java b/test/jdk/java/util/Collections/Enum.java index 432d226aaca..8dcf3f95f76 100644 --- a/test/jdk/java/util/Collections/Enum.java +++ b/test/jdk/java/util/Collections/Enum.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,13 +25,19 @@ * @test * @bug 4323074 * @summary Basic test for new Enumeration -> List converter + * @library /test/lib + * @run main Enum */ +import jdk.test.lib.valueclass.Tuple; import java.util.Collections; import java.util.List; import java.util.Vector; public class Enum { + + static final int SIZE = 10; + public static void main(String[] args) throws Exception { int[] sizes = {0, 10, 100}; for (int i=0; i vv = new Vector<>(); + for (int j = 0; j < SIZE; j++) vv.add(new Tuple(j, j)); + List vl = Collections.list(vv.elements()); + if (!vl.equals(vv)) + throw new RuntimeException("value Enumeration -> List failed"); } } diff --git a/test/jdk/java/util/Collections/EnumerationAsIterator.java b/test/jdk/java/util/Collections/EnumerationAsIterator.java index 4901c40303c..ca439cfd83a 100644 --- a/test/jdk/java/util/Collections/EnumerationAsIterator.java +++ b/test/jdk/java/util/Collections/EnumerationAsIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,11 @@ * @test * @bug 8072726 * @summary Tests for Enumeration-to-Iterator conversion. + * @library /test/lib * @run testng EnumerationAsIterator */ +import jdk.test.lib.valueclass.Tuple; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -46,6 +48,7 @@ @Test public class EnumerationAsIterator { + static Object[] of(String description, Supplier> s, Collection exp) { return new Object[]{description, s, exp}; } @@ -111,7 +114,11 @@ public static Iterator others() { of("Arrays.asList(...)", Arrays.asList("a", "b", "c"), - Arrays.asList("a", "b", "c")) + Arrays.asList("a", "b", "c")), + + of("Value Collections.enumeration()", + () -> Collections.enumeration(Arrays.asList(new Tuple(1, 1), new Tuple(2, 2))), + Arrays.asList(new Tuple(1, 1), new Tuple(2, 2))) ).iterator(); } diff --git a/test/jdk/java/util/Collections/FindSubList.java b/test/jdk/java/util/Collections/FindSubList.java index 31bfdc7fb24..dc981a3282c 100644 --- a/test/jdk/java/util/Collections/FindSubList.java +++ b/test/jdk/java/util/Collections/FindSubList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,11 @@ * @test * @bug 4323074 * @summary Basic test for Collections.indexOfSubList/lastIndexOfSubList + * @library /test/lib + * @run main FindSubList */ +import jdk.test.lib.valueclass.Tuple; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -35,6 +38,7 @@ import java.util.Vector; public class FindSubList { + public static void main(String[] args) throws Exception { int N = 500; List source = new ArrayList(3 * N); @@ -103,5 +107,12 @@ public static void main(String[] args) throws Exception { "0")) != -1) throw new Exception(s.getClass()+" lastIndexOfSubList: big tgt"); } + + List vsource = Arrays.asList(new Tuple(1, 1), new Tuple(2, 2), new Tuple(3, 3), new Tuple(2, 2), new Tuple(3, 3)); + List vtarget = Arrays.asList(new Tuple(2, 2), new Tuple(3, 3)); + if (Collections.indexOfSubList(vsource, vtarget) != 1) + throw new Exception("value indexOfSubList failed"); + if (Collections.lastIndexOfSubList(vsource, vtarget) != 3) + throw new Exception("value lastIndexOfSubList failed"); } } diff --git a/test/jdk/java/util/Collections/Frequency.java b/test/jdk/java/util/Collections/Frequency.java index b10ecc63edd..eafe4654423 100644 --- a/test/jdk/java/util/Collections/Frequency.java +++ b/test/jdk/java/util/Collections/Frequency.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,11 @@ * @bug 4193200 * @summary Basic test for Collections.frequency * @author Josh Bloch + * @library /test/lib + * @run main Frequency */ +import jdk.test.lib.valueclass.Tuple; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; @@ -35,9 +38,11 @@ public class Frequency { static final int N = 100; + public static void main(String[] args) { test(new ArrayList()); test(new LinkedList()); + testValue(); } static void test(List list) { @@ -50,4 +55,15 @@ static void test(List list) { if (Collections.frequency(list, i) != i) throw new RuntimeException(list.getClass() + ": " + i); } + + static void testValue() { + List values = new ArrayList<>(); + for (int i = 0; i < N; i++) + for (int j = 0; j < i; j++) + values.add(new Tuple(i, i)); + Collections.shuffle(values); + for (int i = 0; i < N; i++) + if (Collections.frequency(values, new Tuple(i, i)) != i) + throw new RuntimeException("value frequency: " + i); + } } diff --git a/test/jdk/java/util/Collections/NCopies.java b/test/jdk/java/util/Collections/NCopies.java index 48ba92ad842..8c187d46658 100644 --- a/test/jdk/java/util/Collections/NCopies.java +++ b/test/jdk/java/util/Collections/NCopies.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,11 @@ * @bug 6267846 6275009 * @summary Test Collections.nCopies * @author Martin Buchholz + * @library /test/lib + * @run main NCopies */ +import jdk.test.lib.valueclass.Tuple; import java.util.ArrayList; import java.util.Collections; import java.util.AbstractList; @@ -142,6 +145,15 @@ private static void checkReversed() { check(empty.equals(empty.reversed())); } + private static void checkValueCopies() { + List copies = Collections.nCopies(10, new Tuple(7, 7)); + check(copies.indexOf(new Tuple(7, 7)) == 0); + check(copies.lastIndexOf(new Tuple(7, 7)) == 9); + check(copies.equals(referenceNCopies(10, new Tuple(7, 7)))); + check(copies.hashCode() == referenceNCopies(10, new Tuple(7, 7)).hashCode()); + check(copies.equals(copies.reversed())); + } + public static void main(String[] args) { try { List empty = Collections.nCopies(0, "foo"); @@ -158,6 +170,8 @@ public static void main(String[] args) { checkReversed(); + checkValueCopies(); + } catch (Throwable t) { unexpected(t); } System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); diff --git a/test/jdk/java/util/Collections/NullComparator.java b/test/jdk/java/util/Collections/NullComparator.java index fd1134cb905..0c87e236600 100644 --- a/test/jdk/java/util/Collections/NullComparator.java +++ b/test/jdk/java/util/Collections/NullComparator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,14 +25,18 @@ * @test * @bug 4224271 * @summary A null Comparator is now specified to indicate natural ordering. + * @library /test/lib + * @run main NullComparator */ +import jdk.test.lib.valueclass.Tuple; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; public class NullComparator { + public static void main(String[] args) throws Exception { List list = new ArrayList(100); for (int i=0; i<100; i++) @@ -61,5 +65,18 @@ public static void main(String[] args) throws Exception { throw new Exception("Collections.min"); if (!Collections.max(list, null).equals(new Integer(99))) throw new Exception("Collections.max"); + + List vlist = new ArrayList<>(); + for (int i = 0; i < 100; i++) vlist.add(new Tuple(i, i)); + Collections.shuffle(vlist); + Collections.sort(vlist, null); + for (int i = 0; i < 100; i++) + if (!vlist.get(i).equals(new Tuple(i, i))) throw new Exception("value Collections.sort"); + if (Collections.binarySearch(vlist, new Tuple(69, 69), null) != 69) + throw new Exception("value binarySearch"); + if (!Collections.min(vlist, null).equals(new Tuple(0, 0))) + throw new Exception("value min"); + if (!Collections.max(vlist, null).equals(new Tuple(99, 99))) + throw new Exception("value max"); } } diff --git a/test/jdk/java/util/Collections/ReplaceAll.java b/test/jdk/java/util/Collections/ReplaceAll.java index 498e4c25ce6..9473e43e4fb 100644 --- a/test/jdk/java/util/Collections/ReplaceAll.java +++ b/test/jdk/java/util/Collections/ReplaceAll.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,11 @@ * @test * @bug 4323074 * @summary Basic test for new replaceAll algorithm + * @library /test/lib + * @run main ReplaceAll */ +import jdk.test.lib.valueclass.Tuple; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; @@ -57,5 +60,12 @@ public static void main(String[] args) throws Exception { if (Collections.replaceAll(lst, "love", "hate")) throw new Exception("True return value: "+i); } + + List values = new ArrayList<>(); + for (int j = 1; j <= SIZE; j++) values.add(new Tuple(j % 3, j % 3)); + if (!Collections.replaceAll(values, new Tuple(1, 1), new Tuple(99, 99))) + throw new Exception("value false return"); + if (Collections.replaceAll(values, new Tuple(100, 100), new Tuple(0, 0))) + throw new Exception("value true return for absent element"); } } diff --git a/test/jdk/java/util/Collections/ReverseOrder.java b/test/jdk/java/util/Collections/ReverseOrder.java index ceaa5441a0d..d060559265b 100644 --- a/test/jdk/java/util/Collections/ReverseOrder.java +++ b/test/jdk/java/util/Collections/ReverseOrder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,11 @@ * @bug 4593209 8001667 * @summary Reverse comparator was subtly broken * @author Josh Bloch + * @library /test/lib + * @run main ReverseOrder */ +import jdk.test.lib.valueclass.Tuple; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; @@ -38,6 +41,7 @@ import java.util.List; public class ReverseOrder { + static byte[] serialBytes(Object o) { try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); @@ -79,6 +83,11 @@ public static void main(String[] args) throws Exception { Collections.sort(list2, clone); if (!list2.equals(goldenList)) throw new Exception(list.toString()); + + List vl = Arrays.asList(new Tuple(1, 1), new Tuple(3, 3), new Tuple(2, 2)); + Collections.sort(vl, Collections.reverseOrder()); + if (!vl.equals(Arrays.asList(new Tuple(3, 3), new Tuple(2, 2), new Tuple(1, 1)))) + throw new RuntimeException("value reverseOrder failed"); } } diff --git a/test/jdk/java/util/Collections/ReverseOrder2.java b/test/jdk/java/util/Collections/ReverseOrder2.java index 0369b389a80..cc483542d54 100644 --- a/test/jdk/java/util/Collections/ReverseOrder2.java +++ b/test/jdk/java/util/Collections/ReverseOrder2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,11 @@ * @bug 4809442 6366832 4974878 6372554 4890211 6483125 * @summary Basic test for Collections.reverseOrder * @author Josh Bloch, Martin Buchholz + * @library /test/lib + * @run main ReverseOrder2 */ +import jdk.test.lib.valueclass.Tuple; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -35,6 +38,7 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; @@ -66,6 +70,12 @@ static void realMain(String[] args) throws Throwable { test(new LinkedList()); test2(new ArrayList()); test2(new LinkedList()); + + List values = new ArrayList<>(Arrays.asList(new Tuple(0, 0), new Tuple(1, 1), new Tuple(2, 2))); + Collections.shuffle(values); + Collections.sort(values, Collections.reverseOrder()); + if (!values.equals(Arrays.asList(new Tuple(2, 2), new Tuple(1, 1), new Tuple(0, 0)))) + throw new RuntimeException("value reverseOrder2 failed"); } static void test(List list) { diff --git a/test/jdk/java/util/Collections/Rotate.java b/test/jdk/java/util/Collections/Rotate.java index 7ec42f9d2e9..9dacbde4f93 100644 --- a/test/jdk/java/util/Collections/Rotate.java +++ b/test/jdk/java/util/Collections/Rotate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,9 +26,13 @@ * @bug 4323074 * @summary Basic test for new rotate algorithm * @key randomness + * @library /test/lib + * @run main Rotate */ +import jdk.test.lib.valueclass.Tuple; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -69,5 +73,10 @@ public static void main(String[] args) throws Exception { ", should be "+index); } } + + List vl = new ArrayList<>(Arrays.asList(new Tuple(1, 1), new Tuple(2, 2), new Tuple(3, 3), new Tuple(4, 4))); + Collections.rotate(vl, 1); + if (!vl.equals(Arrays.asList(new Tuple(4, 4), new Tuple(1, 1), new Tuple(2, 2), new Tuple(3, 3)))) + throw new RuntimeException("value rotate failed"); } } diff --git a/test/jdk/java/util/Collections/Ser.java b/test/jdk/java/util/Collections/Ser.java index 554a8e7e833..14b594514ce 100644 --- a/test/jdk/java/util/Collections/Ser.java +++ b/test/jdk/java/util/Collections/Ser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,17 +26,36 @@ * @bug 4190323 * @summary EMPTY_SET, EMPTY_LIST, and the collections returned by * nCopies and singleton were spec'd to be serializable, but weren't. + * @library /test/lib + * @run main Ser */ +import jdk.test.lib.valueclass.AsValueClass; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.Serializable; import java.util.Collections; import java.util.List; import java.util.Set; public class Ser { + + @AsValueClass + static class SerV implements Serializable { + int x; + SerV(int x) { this.x = x; } + public boolean equals(Object o) { return o instanceof SerV v && x == v.x; } + public int hashCode() { return x; } + private Object writeReplace() { return new SerProxy(x); } + private static class SerProxy implements Serializable { + int x; + SerProxy(int x) { this.x = x; } + private Object readResolve() { return new SerV(x); } + } + } + public static void main(String[] args) throws Exception { try { @@ -96,5 +115,33 @@ public static void main(String[] args) throws Exception { } catch (Exception e) { throw new RuntimeException("Failed to serialize nCopies:" + e); } + + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(bos); + Set one = Collections.singleton(new SerV(1)); + out.writeObject(one); + out.flush(); + ObjectInputStream in = new ObjectInputStream( + new ByteArrayInputStream(bos.toByteArray())); + if (!one.equals(in.readObject())) + throw new RuntimeException("value singleton Ser/Deser failure"); + } catch (Exception e) { + throw new RuntimeException("Failed to serialize value singleton: " + e); + } + + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(bos); + List many = Collections.nCopies(5, new SerV(2)); + out.writeObject(many); + out.flush(); + ObjectInputStream in = new ObjectInputStream( + new ByteArrayInputStream(bos.toByteArray())); + if (!many.equals(in.readObject())) + throw new RuntimeException("value nCopies Ser/Deser failure"); + } catch (Exception e) { + throw new RuntimeException("Failed to serialize value nCopies: " + e); + } } } diff --git a/test/jdk/java/util/Collections/Shuffle.java b/test/jdk/java/util/Collections/Shuffle.java index 3a33f27f473..c036b2f75ac 100644 --- a/test/jdk/java/util/Collections/Shuffle.java +++ b/test/jdk/java/util/Collections/Shuffle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,11 @@ * @bug 8294693 * @summary Basic test for Collections.shuffle * @key randomness + * @library /test/lib + * @run main Shuffle */ +import jdk.test.lib.valueclass.Tuple; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; @@ -42,6 +45,7 @@ public class Shuffle { public static void main(String[] args) { test(new ArrayList<>()); test(new LinkedList<>()); + testValue(); } static void test(List list) { @@ -62,6 +66,16 @@ static void test(List list) { checkRandom(list, l -> Collections.shuffle(l, generator.copy())); } + static void testValue() { + List values = new ArrayList<>(); + for (int i = 0; i < N; i++) values.add(new Tuple(i, i)); + Collections.shuffle(values, new Random(1)); + if (values.size() != N) throw new RuntimeException("value shuffle size"); + for (int i = 0; i < N; i++) + if (Collections.frequency(values, new Tuple(i, i)) != 1) + throw new RuntimeException("value shuffle lost " + i); + } + private static void checkRandom(List list, Consumer> randomizer) { list.sort(null); randomizer.accept(list); diff --git a/test/jdk/java/util/Collections/SingletonIterator.java b/test/jdk/java/util/Collections/SingletonIterator.java index 0f7dfd17252..b90ea3c148a 100644 --- a/test/jdk/java/util/Collections/SingletonIterator.java +++ b/test/jdk/java/util/Collections/SingletonIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,9 +24,11 @@ /* * @test * @bug 8024500 8166446 + * @library /test/lib * @run testng SingletonIterator */ +import jdk.test.lib.valueclass.Tuple; import java.util.Collections; import java.util.Iterator; import java.util.NoSuchElementException; @@ -63,6 +65,18 @@ public void testForEachRemaining() { static class SingletonException extends RuntimeException { } + @Test + public void testValueSingletonIterator() { + Iterator it = Collections.singleton(new Tuple(42, 42)).iterator(); + AtomicInteger cnt = new AtomicInteger(0); + it.forEachRemaining(v -> { + if (!v.equals(new Tuple(42, 42))) throw new RuntimeException("wrong value"); + cnt.incrementAndGet(); + }); + assertEquals(cnt.get(), 1); + assertIteratorExhausted(it); + } + public void testThrowFromForEachRemaining() { Iterator it = Collections.singleton("TheOne").iterator(); diff --git a/test/jdk/java/util/Collections/Swap.java b/test/jdk/java/util/Collections/Swap.java index 488feeda1ea..6c86bdfa7d4 100644 --- a/test/jdk/java/util/Collections/Swap.java +++ b/test/jdk/java/util/Collections/Swap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,11 @@ * @bug 4323074 * @summary Basic test for newly public swap algorithm * @author Josh Bloch + * @library /test/lib + * @run main Swap */ +import jdk.test.lib.valueclass.Tuple; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -45,5 +48,11 @@ public static void main(String[] args) throws Exception { l2.set(SIZE-1, Boolean.TRUE); if (!l.equals(l2)) throw new RuntimeException("Wrong result"); + + List vl = new ArrayList<>(Collections.nCopies(SIZE, new Tuple(0, 0))); + vl.set(0, new Tuple(1, 1)); + for (int i = 0; i < SIZE - 1; i++) Collections.swap(vl, i, i + 1); + if (!vl.get(SIZE - 1).equals(new Tuple(1, 1))) + throw new RuntimeException("value swap failed"); } } diff --git a/test/jdk/java/util/Collections/T6433170.java b/test/jdk/java/util/Collections/T6433170.java index 65de4ccdbed..2eff84595fd 100644 --- a/test/jdk/java/util/Collections/T6433170.java +++ b/test/jdk/java/util/Collections/T6433170.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,11 @@ * @test * @bug 6433170 * @summary CheckedCollection.addAll should be all-or-nothing + * @library /test/lib + * @run main T6433170 */ +import jdk.test.lib.valueclass.Tuple; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -40,6 +43,7 @@ @SuppressWarnings("unchecked") public class T6433170 { + private void checkEmpty(Collection x) { check(x.isEmpty()); check(x.size() == 0); @@ -56,6 +60,12 @@ void test(String[] args) throws Throwable { test(checkedCollection( checkedCollection(new Vector(), String.class), Object.class)); + + Collection vc = checkedCollection(new ArrayList<>(), Tuple.class); + List mixed = Arrays.asList(new Tuple(1, 1), new Tuple(2, 2), "not a Tuple"); + THROWS(ClassCastException.class, + new F(){void f(){ vc.addAll(mixed); }}); + checkEmpty(vc); } void test(final Collection checked) { diff --git a/test/lib/jdk/test/lib/valueclass/Tuple.java b/test/lib/jdk/test/lib/valueclass/Tuple.java new file mode 100644 index 00000000000..2bb1f3546f6 --- /dev/null +++ b/test/lib/jdk/test/lib/valueclass/Tuple.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib.valueclass; + +/** + * A reusable value class helper for Collections tests. + * Wraps two ints (x, y), supports equality, ordering, and hashing. + * When compiled with -Xplugin:ValueClassPlugin --enable-preview this class + * is treated as a value class; otherwise it is a plain identity class, + * allowing the same tests to exercise both modes. + */ +@AsValueClass +public class Tuple implements Comparable { + public int x; + public int y; + public Tuple(int x, int y) { this.x = x; this.y = y; } + public int compareTo(Tuple other) { + int cmp = Integer.compare(x, other.x); + return cmp != 0 ? cmp : Integer.compare(y, other.y); + } + public boolean equals(Object o) { return o instanceof Tuple t && x == t.x && y == t.y; } + public int hashCode() { return 31 * x + y; } +} From f81ee611b5118792334f9785fa7ed06b6d1c4fa8 Mon Sep 17 00:00:00 2001 From: Bill Huang Date: Mon, 11 May 2026 13:18:49 -0700 Subject: [PATCH 2/9] Update valhalla_adopted test group --- test/jdk/TEST.groups | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index 86676c35596..4ab277dd0f7 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -174,7 +174,8 @@ jdk_util = \ valhalla_adopted = \ java/util/Collections/AddAll.java \ - java/util/Arrays + java/util/Arrays \ + java/util/Collections # All util components not part of some other util category jdk_util_other = \ From 9d395b1fe251cb9fae9c6e3547129ac27b8b5e02 Mon Sep 17 00:00:00 2001 From: Bill Huang Date: Mon, 11 May 2026 13:42:17 -0700 Subject: [PATCH 3/9] Revert AddAll test iteration to 100 --- test/jdk/java/util/Collections/AddAll.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/java/util/Collections/AddAll.java b/test/jdk/java/util/Collections/AddAll.java index 849b1331a17..1bdace7da7a 100644 --- a/test/jdk/java/util/Collections/AddAll.java +++ b/test/jdk/java/util/Collections/AddAll.java @@ -44,7 +44,7 @@ import java.util.Random; public class AddAll { - static final int N = 10; + static final int N = 100; public static void main(String[] args) { test(new ArrayList()); test(new LinkedList()); From fc57bfcc431202ceb1bb91e111d2ab58b1c5815c Mon Sep 17 00:00:00 2001 From: Bill Huang Date: Tue, 19 May 2026 09:31:56 -0700 Subject: [PATCH 4/9] JDK-8384611 [lworld] Add value class test coverage to java.util HashMap and HashSet --- test/jdk/TEST.groups | 8 +- test/jdk/java/util/HashMap/KeySetRemove.java | 11 ++- .../java/util/HashMap/NullKeyAtResize.java | 12 ++- test/jdk/java/util/HashMap/PutNullKey.java | 9 +- .../java/util/HashMap/ReplaceExisting.java | 53 +++++++++++- test/jdk/java/util/HashMap/SetValue.java | 20 ++++- test/jdk/java/util/HashMap/ToArray.java | 57 +++++++++++-- test/jdk/java/util/HashMap/TreeBinAssert.java | 5 +- test/jdk/java/util/Hashtable/EqualsCast.java | 8 +- .../util/Hashtable/SimpleSerialization.java | 25 ++++-- .../ComputeIfAbsentAccessOrder.java | 22 +++++ .../util/LinkedHashMap/EmptyMapIterator.java | 16 ++++ test/jdk/java/util/LinkedList/AddAll.java | 12 ++- test/jdk/java/util/LinkedList/Clone.java | 83 +++++++++++++------ 14 files changed, 286 insertions(+), 55 deletions(-) diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index 4ab277dd0f7..a6292417e24 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -173,9 +173,13 @@ jdk_util = \ :jdk_stream valhalla_adopted = \ - java/util/Collections/AddAll.java \ java/util/Arrays \ - java/util/Collections + java/util/Collections \ + java/util/HashMap \ + java/util/HashSet \ + java/util/HashTable \ + java/util/LinkedHashMap \ + java/util/LinkedList # All util components not part of some other util category jdk_util_other = \ diff --git a/test/jdk/java/util/HashMap/KeySetRemove.java b/test/jdk/java/util/HashMap/KeySetRemove.java index 81f635bc979..b948512c945 100644 --- a/test/jdk/java/util/HashMap/KeySetRemove.java +++ b/test/jdk/java/util/HashMap/KeySetRemove.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,10 @@ * @bug 4286765 * @summary HashMap and TreeMap entrySet().remove(k) spuriously returned * false if the Map previously mapped k to null. + * @library /test/lib */ +import jdk.test.lib.valueclass.Tuple; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; @@ -40,5 +42,12 @@ public static void main(String[] args) throws Exception { if (!m[i].keySet().remove("bananas")) throw new Exception("Yes, we have no bananas: "+i); } + + Map[] valueMaps = {new HashMap<>(), new TreeMap<>()}; + for (int i=0; i new Tuple(i, i)); + } + + private static void test(IntFunction keyFactory) throws Exception { List old_order = new ArrayList<>(); Map m = new HashMap<>(16); int number = 0; while(number < 100000) { m.put(null,null); // try to put in null. This may cause resize. m.remove(null); // remove it. - Integer adding = (number += 100); + Object adding = keyFactory.apply(number += 100); m.put(adding, null); // try to put in a number. This wont cause resize. List new_order = new ArrayList<>(); new_order.addAll(m.keySet()); diff --git a/test/jdk/java/util/HashMap/PutNullKey.java b/test/jdk/java/util/HashMap/PutNullKey.java index 72aade00186..b5e06165cd0 100644 --- a/test/jdk/java/util/HashMap/PutNullKey.java +++ b/test/jdk/java/util/HashMap/PutNullKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,10 @@ * @bug 8046085 * @summary Ensure that when trees are being used for collisions that null key * insertion still works. + * @library /test/lib */ +import jdk.test.lib.valueclass.AsValueClass; import java.util.*; import java.util.stream.IntStream; @@ -45,6 +47,7 @@ public class PutNullKey { // A value 1.0 will ensure that a new threshold == capacity static final float LOAD_FACTOR = 1.0f; + @AsValueClass public static class CollidingHash implements Comparable { private final int value; @@ -79,6 +82,10 @@ public int compareTo(CollidingHash o) { } public static void main(String[] args) throws Exception { + testCollidingHash(); + } + + private static void testCollidingHash() { Map m = new HashMap<>(INITIAL_CAPACITY, LOAD_FACTOR); IntStream.range(0, SIZE) .mapToObj(CollidingHash::new) diff --git a/test/jdk/java/util/HashMap/ReplaceExisting.java b/test/jdk/java/util/HashMap/ReplaceExisting.java index 81795b30b1f..64094a1ff43 100644 --- a/test/jdk/java/util/HashMap/ReplaceExisting.java +++ b/test/jdk/java/util/HashMap/ReplaceExisting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,9 +27,11 @@ * @summary Verify that replacing the value for an existing key does not * corrupt active iterators, in particular due to a resize() occurring and * not updating modCount. + * @library /test/lib * @run main ReplaceExisting */ +import jdk.test.lib.valueclass.Tuple; import java.util.ConcurrentModificationException; import java.util.HashMap; import java.util.HashSet; @@ -43,6 +45,8 @@ public static void main(String[] args) { for (int i = 0; i <= ENTRIES; i++) { HashMap hm = prepHashMap(); testItr(hm, i); + HashMap tupleHm = prepTupleHashMap(); + testTupleItr(tupleHm, i); } } @@ -56,6 +60,15 @@ private static HashMap prepHashMap() { return hm; } + private static HashMap prepTupleHashMap() { + HashMap hm = new HashMap<>(16, 0.75f); + // Add items to one more than the resize threshold + for (int i = 0; i < ENTRIES; i++) { + hm.put(new Tuple(i * 10, i * 10), i * 10); + } + return hm; + } + /* Iterate hm for elemBeforePut elements, then call put() to replace value * for existing key. With bug 8025173, this will also cause a resize, but * not increase the modCount. @@ -98,4 +111,42 @@ private static void testItr(HashMap hm, int elemBeforePut) { throw new RuntimeException("Collected keys do not match original set of keys"); } } + + private static void testTupleItr(HashMap hm, int elemBeforePut) { + if (elemBeforePut > hm.size()) { + throw new IllegalArgumentException("Error in test: elemBeforePut must be <= HashMap size"); + } + // Create a copy of the keys + HashSet keys = new HashSet<>(hm.size()); + keys.addAll(hm.keySet()); + + HashSet collected = new HashSet<>(hm.size()); + + // Run itr for elemBeforePut items, collecting returned elems + Iterator itr = hm.keySet().iterator(); + for (int i = 0; i < elemBeforePut; i++) { + Tuple retVal = itr.next(); + if (!collected.add(retVal)) { + throw new RuntimeException("Corrupt iterator: key " + retVal + " already encountered"); + } + } + + // Do put() to replace entry (and resize table when bug present) + if (null == hm.put(new Tuple(0, 0), 100)) { + throw new RuntimeException("Error in test: expected key (0, 0) to be in the HashMap"); + } + + // Finish itr + collecting returned elems + while(itr.hasNext()) { + Tuple retVal = itr.next(); + if (!collected.add(retVal)) { + throw new RuntimeException("Corrupt iterator: key " + retVal + " already encountered"); + } + } + + // Compare returned elems to original copy of keys + if (!keys.equals(collected)) { + throw new RuntimeException("Collected keys do not match original set of keys"); + } + } } diff --git a/test/jdk/java/util/HashMap/SetValue.java b/test/jdk/java/util/HashMap/SetValue.java index 2f9daf4889c..e8bd739622f 100644 --- a/test/jdk/java/util/HashMap/SetValue.java +++ b/test/jdk/java/util/HashMap/SetValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,10 @@ * @bug 4627516 * @summary HashMap.Entry.setValue() returns new value (as opposed to old) * @author jbloch + * @library /test/lib */ +import jdk.test.lib.valueclass.Tuple; import java.util.HashMap; import java.util.Map; @@ -37,6 +39,11 @@ public class SetValue { static final String newValue = "new"; public static void main(String[] args) throws Exception { + testStringValue(); + testTupleValue(); + } + + private static void testStringValue() { Map m = new HashMap(); m.put(key, oldValue); Map.Entry e = (Map.Entry) m.entrySet().iterator().next(); @@ -44,4 +51,15 @@ public static void main(String[] args) throws Exception { if (!returnVal.equals(oldValue)) throw new RuntimeException("Return value: " + returnVal); } + + private static void testTupleValue() { + Map m = new HashMap<>(); + Tuple oldValue = new Tuple(1, 1); + Tuple newValue = new Tuple(2, 2); + m.put(key, oldValue); + Map.Entry e = m.entrySet().iterator().next(); + Object returnVal = e.setValue(newValue); + if (!returnVal.equals(oldValue)) + throw new RuntimeException("Return value: " + returnVal); + } } diff --git a/test/jdk/java/util/HashMap/ToArray.java b/test/jdk/java/util/HashMap/ToArray.java index b9336dfc4cb..5872060b960 100644 --- a/test/jdk/java/util/HashMap/ToArray.java +++ b/test/jdk/java/util/HashMap/ToArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,27 +31,26 @@ import java.util.List; import java.util.Map; import java.util.stream.LongStream; +import jdk.test.lib.valueclass.Tuple; /* * @test * @bug 8336669 * @summary HashMap.toArray() behavior tests * @author tvaleev + * @library /test/lib */ public class ToArray { - // An interned identity class holding an int (like non-Preview Integer) - record Int(int intValue) implements Comparable { - @Override - public int compareTo(Int o) { - return Integer.compare(intValue, o.intValue); - } - } public static void main(String[] args) { checkMap(false); checkMap(true); checkSet(false); checkSet(true); + checkTupleMap(false); + checkTupleMap(true); + checkTupleSet(false); + checkTupleSet(true); } private static > void checkToArray(String message, T[] expected, Collection collection, @@ -161,4 +160,46 @@ private static void checkSet(boolean ordered) { checkToArray("Collisions", LongStream.range(0, 100).mapToObj(x -> x | (x << 32)) .toArray(Long[]::new), longSet, !ordered); } + + private static void checkTupleMap(boolean ordered) { + Map map = ordered ? new LinkedHashMap<>() : new HashMap<>(); + checkToArray("Empty-tuple-keys", new Tuple[0], map.keySet(), !ordered); + checkToArray("Empty-tuple-values", new Tuple[0], map.values(), !ordered); + + List keys = new ArrayList<>(); + List values = new ArrayList<>(); + for (int i = 0; i < 100; i++) { + keys.add(new Tuple(i, i)); + values.add(new Tuple(i * 2, i * 2)); + map.put(new Tuple(i, i), new Tuple(i * 2, i * 2)); + checkToArray(i + "-tuple-keys", keys.toArray(new Tuple[0]), map.keySet(), !ordered); + checkToArray(i + "-tuple-values", values.toArray(new Tuple[0]), map.values(), !ordered); + } + map.clear(); + checkToArray("Empty-tuple-keys", new Tuple[0], map.keySet(), !ordered); + checkToArray("Empty-tuple-values", new Tuple[0], map.values(), !ordered); + } + + private static void checkTupleSet(boolean ordered) { + Collection set = ordered ? new LinkedHashSet<>() : new HashSet<>(); + checkToArray("Empty-tuple", new Tuple[0], set, !ordered); + set.add(new Tuple(1, 1)); + checkToArray("One-tuple", new Tuple[]{new Tuple(1, 1)}, set, !ordered); + set.add(new Tuple(2, 2)); + checkToArray("Two-tuple", new Tuple[]{new Tuple(1, 1), new Tuple(2, 2)}, set, !ordered); + + Collection tupleSet = ordered ? new LinkedHashSet<>() : new HashSet<>(); + for (int x = 0; x < 100; x++) { + tupleSet.add(new Tuple(x, x)); + } + checkToArray("100-tuple", LongStream.range(0, 100).mapToObj(x -> new Tuple((int) x, (int) x)) + .toArray(Tuple[]::new), tupleSet, !ordered); + tupleSet.clear(); + checkToArray("After-clear-tuple", new Tuple[0], tupleSet, !ordered); + for (int x = 0; x < 100; x++) { + tupleSet.add(new Tuple(x, -31 * x)); + } + checkToArray("Collisions-tuple", LongStream.range(0, 100).mapToObj(x -> new Tuple((int) x, -31 * (int) x)) + .toArray(Tuple[]::new), tupleSet, !ordered); + } } diff --git a/test/jdk/java/util/HashMap/TreeBinAssert.java b/test/jdk/java/util/HashMap/TreeBinAssert.java index bde93b5ce7c..d89dd9aa940 100644 --- a/test/jdk/java/util/HashMap/TreeBinAssert.java +++ b/test/jdk/java/util/HashMap/TreeBinAssert.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,11 @@ * @test * @bug 8205399 * @summary Check for AssertionError from HashMap TreeBin after Iterator.remove + * @library /test/lib * @run testng/othervm -esa TreeBinAssert */ +import jdk.test.lib.valueclass.AsValueClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.testng.annotations.BeforeTest; @@ -154,6 +156,7 @@ private void doTest(Object collection, int[] hashes, /** * Class that will have specified hash code in a HashMap. */ + @AsValueClass static class Key implements Comparable { final int hash; diff --git a/test/jdk/java/util/Hashtable/EqualsCast.java b/test/jdk/java/util/Hashtable/EqualsCast.java index 7451d88473c..06603d95894 100644 --- a/test/jdk/java/util/Hashtable/EqualsCast.java +++ b/test/jdk/java/util/Hashtable/EqualsCast.java @@ -27,8 +27,11 @@ * @summary Hashtable was less robust to extension that it could have been * because the equals and Hashcode methods used internals * unnecessarily. (java.security.Provider tickled this sensitivity.) + * @library /test/lib */ +import jdk.test.lib.valueclass.Tuple; + import java.security.Provider; import java.util.Map; @@ -36,7 +39,9 @@ public class EqualsCast { public static void main(String[] args) throws Exception { Map m1 = new MyProvider("foo", 69, "baz"); Map m2 = new MyProvider("foo", 69, "baz"); - m1.equals(m2); + if (!m1.equals(m2)) { + throw new RuntimeException("Provider maps are not equal"); + } } } @@ -48,6 +53,7 @@ public MyProvider(String name, double version, String info) { super(name, version, info); this.name = name; put("Signature.sigalg", "sigimpl"); + put(new Tuple(1, 1), new Tuple(2, 2)); } public String getName() { diff --git a/test/jdk/java/util/Hashtable/SimpleSerialization.java b/test/jdk/java/util/Hashtable/SimpleSerialization.java index deb322cb7fc..5fa0e0beac5 100644 --- a/test/jdk/java/util/Hashtable/SimpleSerialization.java +++ b/test/jdk/java/util/Hashtable/SimpleSerialization.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,11 +43,15 @@ public class SimpleSerialization { public static void main(final String[] args) throws Exception { - Hashtable h1 = new Hashtable<>(); - System.err.println("*** BEGIN TEST ***"); - h1.put("key", "value"); + test(new Hashtable(), "key", "value"); + test(new Hashtable(), 1, 2); + } + + private static void test(Hashtable h1, K key, V value) + throws Exception { + h1.put(key, value); final ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { @@ -66,11 +70,14 @@ public static void main(final String[] args) throws Exception { } if (false == h1.equals(deserializedObject)) { - Hashtable d1 = (Hashtable) h1; - for(Map.Entry entry: h1.entrySet()) { - System.err.println("h1.key::" + entry.getKey() + " d1.containsKey()::" + d1.containsKey((String) entry.getKey())); - System.err.println("h1.value::" + entry.getValue() + " d1.contains()::" + d1.contains(entry.getValue())); - System.err.println("h1.value == d1.value " + entry.getValue().equals(d1.get((String) entry.getKey()))); + Hashtable copy = (Hashtable) deserializedObject; + for (Map.Entry entry : h1.entrySet()) { + System.err.println("h1.key::" + entry.getKey() + + " copy.containsKey()::" + copy.containsKey(entry.getKey())); + System.err.println("h1.value::" + entry.getValue() + + " copy.contains()::" + copy.contains(entry.getValue())); + System.err.println("h1.value equals copy.value " + + entry.getValue().equals(copy.get(entry.getKey()))); } throw new RuntimeException(getFailureText(h1, deserializedObject)); diff --git a/test/jdk/java/util/LinkedHashMap/ComputeIfAbsentAccessOrder.java b/test/jdk/java/util/LinkedHashMap/ComputeIfAbsentAccessOrder.java index 532f2f78512..53b925a3b09 100644 --- a/test/jdk/java/util/LinkedHashMap/ComputeIfAbsentAccessOrder.java +++ b/test/jdk/java/util/LinkedHashMap/ComputeIfAbsentAccessOrder.java @@ -31,6 +31,11 @@ public class ComputeIfAbsentAccessOrder { public static void main(String args[]) throws Throwable { + testStringKeys(); + testIntegerKeys(); + } + + private static void testStringKeys() { LinkedHashMap map = new LinkedHashMap<>(2, 0.75f, true); map.put("first", null); map.put("second", null); @@ -44,4 +49,21 @@ public static void main(String args[]) throws Throwable { throw new RuntimeException("not expected value " + "first" + "!=" + key); } } + + private static void testIntegerKeys() { + LinkedHashMap map = new LinkedHashMap<>(2, 0.75f, true); + Integer first = Integer.valueOf(1996); + Integer second = Integer.valueOf(2026); + map.put(first, null); + map.put(second, null); + + map.computeIfAbsent(first, l -> null); // should do nothing + + Integer key = map.keySet().stream() + .findFirst() + .orElseThrow(() -> new RuntimeException("no value")); + if (!first.equals(key)) { + throw new RuntimeException("not expected value " + first + "!=" + key); + } + } } diff --git a/test/jdk/java/util/LinkedHashMap/EmptyMapIterator.java b/test/jdk/java/util/LinkedHashMap/EmptyMapIterator.java index 8b552f26ff4..9bdb00e208c 100644 --- a/test/jdk/java/util/LinkedHashMap/EmptyMapIterator.java +++ b/test/jdk/java/util/LinkedHashMap/EmptyMapIterator.java @@ -30,13 +30,29 @@ import java.util.ConcurrentModificationException; import java.util.HashMap; import java.util.Iterator; +import java.util.Map; public class EmptyMapIterator { public static void main(String[] args) throws Exception { + testStringKeys(); + testIntegerKeys(); + } + + private static void testStringKeys() throws Exception { HashMap map = new HashMap(); Iterator iter = map.entrySet().iterator(); map.put("key", "value"); + expectConcurrentModification(iter); + } + + private static void testIntegerKeys() throws Exception { + HashMap map = new HashMap<>(); + Iterator> iter = map.entrySet().iterator(); + map.put(Integer.valueOf(1), Integer.valueOf(2)); + expectConcurrentModification(iter); + } + private static void expectConcurrentModification(Iterator iter) throws Exception { try { iter.next(); throw new Exception("No exception thrown"); diff --git a/test/jdk/java/util/LinkedList/AddAll.java b/test/jdk/java/util/LinkedList/AddAll.java index a7554988178..118ea5ab64c 100644 --- a/test/jdk/java/util/LinkedList/AddAll.java +++ b/test/jdk/java/util/LinkedList/AddAll.java @@ -25,8 +25,11 @@ * @test * @bug 4163207 * @summary AddAll was prepending instead of appending! + * @library /test/lib */ +import jdk.test.lib.valueclass.Tuple; + import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; @@ -34,8 +37,13 @@ public class AddAll { public static void main(String[] args) throws Exception { - List head = Collections.nCopies(7, "deadly sin"); - List tail = Collections.nCopies(4, "basic food group"); + testAddAll(Collections.nCopies(7, "deadly sin"), + Collections.nCopies(4, "basic food group")); + testAddAll(Collections.nCopies(7, new Tuple(7, 1)), + Collections.nCopies(4, new Tuple(4, 2))); + } + + private static void testAddAll(List head, List tail) { List l1 = new ArrayList(head); List l2 = new LinkedList(head); l1.addAll(tail); diff --git a/test/jdk/java/util/LinkedList/Clone.java b/test/jdk/java/util/LinkedList/Clone.java index 7b8908efbf3..e22802ead31 100644 --- a/test/jdk/java/util/LinkedList/Clone.java +++ b/test/jdk/java/util/LinkedList/Clone.java @@ -27,53 +27,84 @@ * @summary Cloning a subclass of LinkedList results in an object that isn't * an instance of the subclass. The same applies to TreeSet and * TreeMap. + * @library /test/lib */ +import jdk.test.lib.valueclass.Tuple; + import java.util.LinkedList; import java.util.TreeMap; import java.util.TreeSet; public class Clone { public static void main(String[] args) { + testStrings(); + testTuples(); + } + + private static void testStrings() { LinkedList2 l = new LinkedList2(); - LinkedList2 lClone = (LinkedList2) l.clone(); - if (!(l.equals(lClone) && lClone.equals(l))) - throw new RuntimeException("LinkedList.clone() is broken 1."); + checkLinkedListClone(l, "LinkedList.clone() is broken 1."); l.add("a"); - lClone = (LinkedList2) l.clone(); - if (!(l.equals(lClone) && lClone.equals(l))) - throw new RuntimeException("LinkedList.clone() is broken 2."); + checkLinkedListClone(l, "LinkedList.clone() is broken 2."); l.add("b"); - lClone = (LinkedList2) l.clone(); - if (!(l.equals(lClone) && lClone.equals(l))) - throw new RuntimeException("LinkedList.clone() is broken 2."); + checkLinkedListClone(l, "LinkedList.clone() is broken 3."); TreeSet2 s = new TreeSet2(); - TreeSet2 sClone = (TreeSet2) s.clone(); - if (!(s.equals(sClone) && sClone.equals(s))) - throw new RuntimeException("TreeSet.clone() is broken."); + checkTreeSetClone(s, "TreeSet.clone() is broken."); s.add("a"); - sClone = (TreeSet2) s.clone(); - if (!(s.equals(sClone) && sClone.equals(s))) - throw new RuntimeException("TreeSet.clone() is broken."); + checkTreeSetClone(s, "TreeSet.clone() is broken."); s.add("b"); - sClone = (TreeSet2) s.clone(); - if (!(s.equals(sClone) && sClone.equals(s))) - throw new RuntimeException("TreeSet.clone() is broken."); + checkTreeSetClone(s, "TreeSet.clone() is broken."); TreeMap2 m = new TreeMap2(); - TreeMap2 mClone = (TreeMap2) m.clone(); - if (!(m.equals(mClone) && mClone.equals(m))) - throw new RuntimeException("TreeMap.clone() is broken."); + checkTreeMapClone(m, "TreeMap.clone() is broken."); m.put("a", "b"); - mClone = (TreeMap2) m.clone(); - if (!(m.equals(mClone) && mClone.equals(m))) - throw new RuntimeException("TreeMap.clone() is broken."); + checkTreeMapClone(m, "TreeMap.clone() is broken."); m.put("c", "d"); - mClone = (TreeMap2) m.clone(); + checkTreeMapClone(m, "TreeMap.clone() is broken."); + } + + private static void testTuples() { + LinkedList2 l = new LinkedList2(); + checkLinkedListClone(l, "LinkedList.clone() is broken for Tuple 1."); + l.add(new Tuple(1, 0)); + checkLinkedListClone(l, "LinkedList.clone() is broken for Tuple 2."); + l.add(new Tuple(2, 0)); + checkLinkedListClone(l, "LinkedList.clone() is broken for Tuple 3."); + + TreeSet2 s = new TreeSet2(); + checkTreeSetClone(s, "TreeSet.clone() is broken for Tuple 1."); + s.add(new Tuple(1, 0)); + checkTreeSetClone(s, "TreeSet.clone() is broken for Tuple 2."); + s.add(new Tuple(2, 0)); + checkTreeSetClone(s, "TreeSet.clone() is broken for Tuple 3."); + + TreeMap2 m = new TreeMap2(); + checkTreeMapClone(m, "TreeMap.clone() is broken for Tuple 1."); + m.put(new Tuple(1, 0), new Tuple(1, 1)); + checkTreeMapClone(m, "TreeMap.clone() is broken for Tuple 2."); + m.put(new Tuple(2, 0), new Tuple(2, 1)); + checkTreeMapClone(m, "TreeMap.clone() is broken for Tuple 3."); + } + + private static void checkLinkedListClone(LinkedList2 l, String message) { + LinkedList2 lClone = (LinkedList2) l.clone(); + if (!(l.equals(lClone) && lClone.equals(l))) + throw new RuntimeException(message); + } + + private static void checkTreeSetClone(TreeSet2 s, String message) { + TreeSet2 sClone = (TreeSet2) s.clone(); + if (!(s.equals(sClone) && sClone.equals(s))) + throw new RuntimeException(message); + } + + private static void checkTreeMapClone(TreeMap2 m, String message) { + TreeMap2 mClone = (TreeMap2) m.clone(); if (!(m.equals(mClone) && mClone.equals(m))) - throw new RuntimeException("TreeMap.clone() is broken."); + throw new RuntimeException(message); } private static class LinkedList2 extends LinkedList {} From 56e6fe2074fcac926d9728ab3762887d513b2ae4 Mon Sep 17 00:00:00 2001 From: Bill Huang Date: Thu, 28 May 2026 10:56:46 -0700 Subject: [PATCH 5/9] Update typo in TEST.groups --- test/jdk/TEST.groups | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index a6292417e24..0e3d9f4e6d5 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -177,8 +177,9 @@ valhalla_adopted = \ java/util/Collections \ java/util/HashMap \ java/util/HashSet \ - java/util/HashTable \ + java/util/Hashtable \ java/util/LinkedHashMap \ + java/util/LinkedHashSet \ java/util/LinkedList # All util components not part of some other util category From 26d33072c76d62ece90ea33f39a665735b3c7311 Mon Sep 17 00:00:00 2001 From: Bill Huang Date: Tue, 2 Jun 2026 14:25:40 -0700 Subject: [PATCH 6/9] Removed Tuple.java from previous commit --- test/lib/jdk/test/lib/valueclass/Tuple.java | 44 --------------------- 1 file changed, 44 deletions(-) delete mode 100644 test/lib/jdk/test/lib/valueclass/Tuple.java diff --git a/test/lib/jdk/test/lib/valueclass/Tuple.java b/test/lib/jdk/test/lib/valueclass/Tuple.java deleted file mode 100644 index 2bb1f3546f6..00000000000 --- a/test/lib/jdk/test/lib/valueclass/Tuple.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.test.lib.valueclass; - -/** - * A reusable value class helper for Collections tests. - * Wraps two ints (x, y), supports equality, ordering, and hashing. - * When compiled with -Xplugin:ValueClassPlugin --enable-preview this class - * is treated as a value class; otherwise it is a plain identity class, - * allowing the same tests to exercise both modes. - */ -@AsValueClass -public class Tuple implements Comparable { - public int x; - public int y; - public Tuple(int x, int y) { this.x = x; this.y = y; } - public int compareTo(Tuple other) { - int cmp = Integer.compare(x, other.x); - return cmp != 0 ? cmp : Integer.compare(y, other.y); - } - public boolean equals(Object o) { return o instanceof Tuple t && x == t.x && y == t.y; } - public int hashCode() { return 31 * x + y; } -} From 62ef28e3dc8ba6b332fcdc551b46b0a3436bd232 Mon Sep 17 00:00:00 2001 From: Bill Huang Date: Tue, 2 Jun 2026 14:58:14 -0700 Subject: [PATCH 7/9] Update copyright headers --- test/jdk/java/util/Hashtable/EqualsCast.java | 2 +- .../jdk/java/util/LinkedHashMap/ComputeIfAbsentAccessOrder.java | 2 +- test/jdk/java/util/LinkedHashMap/EmptyMapIterator.java | 2 +- test/jdk/java/util/LinkedList/AddAll.java | 2 +- test/jdk/java/util/LinkedList/Clone.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/jdk/java/util/Hashtable/EqualsCast.java b/test/jdk/java/util/Hashtable/EqualsCast.java index 342106f7e4d..5a02268d6c8 100644 --- a/test/jdk/java/util/Hashtable/EqualsCast.java +++ b/test/jdk/java/util/Hashtable/EqualsCast.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/java/util/LinkedHashMap/ComputeIfAbsentAccessOrder.java b/test/jdk/java/util/LinkedHashMap/ComputeIfAbsentAccessOrder.java index 53b925a3b09..511e6db60dd 100644 --- a/test/jdk/java/util/LinkedHashMap/ComputeIfAbsentAccessOrder.java +++ b/test/jdk/java/util/LinkedHashMap/ComputeIfAbsentAccessOrder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/java/util/LinkedHashMap/EmptyMapIterator.java b/test/jdk/java/util/LinkedHashMap/EmptyMapIterator.java index 9bdb00e208c..a5531a55418 100644 --- a/test/jdk/java/util/LinkedHashMap/EmptyMapIterator.java +++ b/test/jdk/java/util/LinkedHashMap/EmptyMapIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/java/util/LinkedList/AddAll.java b/test/jdk/java/util/LinkedList/AddAll.java index 081a68cab80..8d260d30a94 100644 --- a/test/jdk/java/util/LinkedList/AddAll.java +++ b/test/jdk/java/util/LinkedList/AddAll.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/java/util/LinkedList/Clone.java b/test/jdk/java/util/LinkedList/Clone.java index 371a0a3cd6e..232dccaa746 100644 --- a/test/jdk/java/util/LinkedList/Clone.java +++ b/test/jdk/java/util/LinkedList/Clone.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it From 0cc66e6c0382552b906700ecd7b6d69f3a98ddbb Mon Sep 17 00:00:00 2001 From: Bill Huang Date: Tue, 2 Jun 2026 15:05:54 -0700 Subject: [PATCH 8/9] Rename function name --- test/jdk/java/util/LinkedList/Clone.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/util/LinkedList/Clone.java b/test/jdk/java/util/LinkedList/Clone.java index 232dccaa746..9c376c6b3f8 100644 --- a/test/jdk/java/util/LinkedList/Clone.java +++ b/test/jdk/java/util/LinkedList/Clone.java @@ -39,7 +39,7 @@ public class Clone { public static void main(String[] args) { testStrings(); - testTuples(); + testVClass(); } private static void testStrings() { @@ -66,7 +66,7 @@ private static void testStrings() { checkTreeMapClone(m, "TreeMap.clone() is broken."); } - private static void testTuples() { + private static void testVClass() { LinkedList2 l = new LinkedList2(); checkLinkedListClone(l, "LinkedList.clone() is broken for VClass 1."); l.add(new VClass(1, new int[] { 0 })); From b704f531f0d9dfada755bf35f4e3a4a7e33a285d Mon Sep 17 00:00:00 2001 From: Bill Huang Date: Wed, 3 Jun 2026 11:33:58 -0700 Subject: [PATCH 9/9] Implemented review comments --- test/jdk/java/util/HashMap/KeySetRemove.java | 10 ++-- test/jdk/java/util/HashMap/PutNullKey.java | 46 ++++++++++++++- test/jdk/java/util/HashMap/SetValue.java | 4 +- test/jdk/java/util/HashMap/ToArray.java | 12 ++-- test/jdk/java/util/HashMap/TreeBinAssert.java | 59 ++++++++++++++++++- 5 files changed, 116 insertions(+), 15 deletions(-) diff --git a/test/jdk/java/util/HashMap/KeySetRemove.java b/test/jdk/java/util/HashMap/KeySetRemove.java index 4696e97d37a..c71f8aa96d6 100644 --- a/test/jdk/java/util/HashMap/KeySetRemove.java +++ b/test/jdk/java/util/HashMap/KeySetRemove.java @@ -36,15 +36,15 @@ public class KeySetRemove { public static void main(String[] args) throws Exception { - Map[] m = {new HashMap(), new TreeMap()}; - for (int i=0; i(), new TreeMap<>()}; - for (int i=0; i(), new TreeMap<>() }; + for (int i = 0; i < valueMaps.length; i++) { valueMaps[i].put(new VClass(1, new int[] { 1 }), null); if (!valueMaps[i].keySet().remove(new VClass(1, new int[] { 1 }))) throw new Exception("Value banana was not removed: " + i); diff --git a/test/jdk/java/util/HashMap/PutNullKey.java b/test/jdk/java/util/HashMap/PutNullKey.java index b5e06165cd0..8a0a07d2c78 100644 --- a/test/jdk/java/util/HashMap/PutNullKey.java +++ b/test/jdk/java/util/HashMap/PutNullKey.java @@ -47,7 +47,6 @@ public class PutNullKey { // A value 1.0 will ensure that a new threshold == capacity static final float LOAD_FACTOR = 1.0f; - @AsValueClass public static class CollidingHash implements Comparable { private final int value; @@ -81,8 +80,43 @@ public int compareTo(CollidingHash o) { } } + @AsValueClass + public static class CollidingHashValue implements Comparable { + + private final int value; + + public CollidingHashValue(int value) { + this.value = value; + } + + @Override + public int hashCode() { + // intentionally bad hashcode. Force into first bin. + return 0; + } + + @Override + public boolean equals(Object o) { + if (null == o) { + return false; + } + + if (o.getClass() != CollidingHashValue.class) { + return false; + } + + return value == ((CollidingHashValue) o).value; + } + + @Override + public int compareTo(CollidingHashValue o) { + return value - o.value; + } + } + public static void main(String[] args) throws Exception { testCollidingHash(); + testCollidingHashValue(); } private static void testCollidingHash() { @@ -94,4 +128,14 @@ private static void testCollidingHash() { // kaboom? m.put(null, null); } + + private static void testCollidingHashValue() { + Map m = new HashMap<>(INITIAL_CAPACITY, LOAD_FACTOR); + IntStream.range(0, SIZE) + .mapToObj(CollidingHashValue::new) + .forEach(e -> { m.put(e, e); }); + + // kaboom? + m.put(null, null); + } } diff --git a/test/jdk/java/util/HashMap/SetValue.java b/test/jdk/java/util/HashMap/SetValue.java index 7103e9dc401..8271ed2a0a0 100644 --- a/test/jdk/java/util/HashMap/SetValue.java +++ b/test/jdk/java/util/HashMap/SetValue.java @@ -40,7 +40,7 @@ public class SetValue { public static void main(String[] args) throws Exception { testStringValue(); - testTupleValue(); + testVClass(); } private static void testStringValue() { @@ -52,7 +52,7 @@ private static void testStringValue() { throw new RuntimeException("Return value: " + returnVal); } - private static void testTupleValue() { + private static void testVClass() { Map m = new HashMap<>(); VClass oldValue = new VClass(1, new int[] { 1 }); VClass newValue = new VClass(2, new int[] { 2 }); diff --git a/test/jdk/java/util/HashMap/ToArray.java b/test/jdk/java/util/HashMap/ToArray.java index af98d2b68c6..e2c4471de9b 100644 --- a/test/jdk/java/util/HashMap/ToArray.java +++ b/test/jdk/java/util/HashMap/ToArray.java @@ -47,10 +47,10 @@ public static void main(String[] args) { checkMap(true); checkSet(false); checkSet(true); - checkTupleMap(false); - checkTupleMap(true); - checkTupleSet(false); - checkTupleSet(true); + checkVClassMap(false); + checkVClassMap(true); + checkVClassSet(false); + checkVClassSet(true); } private static > void checkToArray(String message, T[] expected, Collection collection, @@ -161,7 +161,7 @@ private static void checkSet(boolean ordered) { .toArray(Long[]::new), longSet, !ordered); } - private static void checkTupleMap(boolean ordered) { + private static void checkVClassMap(boolean ordered) { Map map = ordered ? new LinkedHashMap<>() : new HashMap<>(); checkToArray("Empty-tuple-keys", new VClass[0], map.keySet(), !ordered); checkToArray("Empty-tuple-values", new VClass[0], map.values(), !ordered); @@ -180,7 +180,7 @@ private static void checkTupleMap(boolean ordered) { checkToArray("Empty-tuple-values", new VClass[0], map.values(), !ordered); } - private static void checkTupleSet(boolean ordered) { + private static void checkVClassSet(boolean ordered) { Collection set = ordered ? new LinkedHashSet<>() : new HashSet<>(); checkToArray("Empty-tuple", new VClass[0], set, !ordered); set.add(new VClass(1, new int[] { 1 })); diff --git a/test/jdk/java/util/HashMap/TreeBinAssert.java b/test/jdk/java/util/HashMap/TreeBinAssert.java index d89dd9aa940..b310f41c89a 100644 --- a/test/jdk/java/util/HashMap/TreeBinAssert.java +++ b/test/jdk/java/util/HashMap/TreeBinAssert.java @@ -156,7 +156,6 @@ private void doTest(Object collection, int[] hashes, /** * Class that will have specified hash code in a HashMap. */ - @AsValueClass static class Key implements Comparable { final int hash; @@ -175,4 +174,62 @@ public Key(int desiredHash) { return Integer.compare(this.hash, k.hash); } } + + @AsValueClass + static class KeyVClass implements Comparable { + final int hash; + + public KeyVClass(int desiredHash) { + // Account for processing done by HashMap + this.hash = desiredHash ^ (desiredHash >>> 16); + } + + @Override public int hashCode() { return this.hash; } + + @Override public boolean equals(Object o) { + return o.hashCode() == this.hashCode(); + } + + @Override public int compareTo(KeyVClass k) { + return Integer.compare(this.hash, k.hash); + } + } + + @Test(dataProvider = "SizeAndHashes") + public void testMapVClass(int size, int[] hashes) { + Map map = new HashMap<>(size); + + doTestVClass(map, hashes, + (c,k) -> { ((Map)c).put(k,0); }, + (c) -> { return ((Map)c).keySet().iterator(); } + ); + } + + @Test(dataProvider = "SizeAndHashes") + public void testSetVClass(int size, int[] hashes) { + Set set = new LinkedHashSet<>(size); + + doTestVClass(set, hashes, + (c,k) -> { ((Set)c).add(k); }, + (c) -> { return ((Set)c).iterator(); } + ); + } + + private void doTestVClass(Object collection, int[] hashes, + BiConsumer addKey, + Function> mkItr) { + Iterator itr = null; + for (int h : hashes) { + if (h == ITR_RM) { + if (itr == null) { + itr = mkItr.apply(collection); + } + itr.next(); + itr.remove(); + } else { + itr = null; + addKey.accept(collection, new KeyVClass(h)); + } + } + } }