Skip to content
9 changes: 7 additions & 2 deletions test/jdk/TEST.groups
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,14 @@ 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/LinkedHashSet \
java/util/LinkedList

# All util components not part of some other util category
jdk_util_other = \
Expand Down
11 changes: 10 additions & 1 deletion test/jdk/java/util/HashMap/KeySetRemove.java
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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.VClass;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
Expand All @@ -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<valueMaps.length; i++) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please update indentation (spaces)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm, are you referring to the spacing inside the for loop parentheses, e.g. changing for (int i=0; i<valueMaps.length; i++) to for (int i = 0; i < valueMaps.length; i++)?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly.

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);
}
}
}
12 changes: 10 additions & 2 deletions test/jdk/java/util/HashMap/NullKeyAtResize.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 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
Expand Down Expand Up @@ -27,19 +27,27 @@
* @summary If the key to be inserted into a HashMap is null and the table
* needs to be resized as part of the insertion then addEntry will try to
* recalculate the hash of a null key. This will fail with an NPE.
* @library /test/lib
*/

import jdk.test.lib.valueclass.VClass;
import java.util.*;
import java.util.function.IntFunction;

public class NullKeyAtResize {
public static void main(String[] args) throws Exception {
test(Integer::valueOf);
test(i -> new VClass(i, new int[] { i }));
}

private static void test(IntFunction<Object> keyFactory) throws Exception {
List<Object> old_order = new ArrayList<>();
Map<Object,Object> 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<Object> new_order = new ArrayList<>();
new_order.addAll(m.keySet());
Expand Down
9 changes: 8 additions & 1 deletion test/jdk/java/util/HashMap/PutNullKey.java
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;

Expand All @@ -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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add the second testcase and new class
CollidingHashValue
that is ' @AsValueClass'

You fix is going to work perfectly now, but later the plan is to rewrite @AsValueClass with 'value class' and don't run the test with and without preview. So 2 testcases would be reuiqred.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

public static class CollidingHash implements Comparable<CollidingHash> {

private final int value;
Expand Down Expand Up @@ -79,6 +82,10 @@ public int compareTo(CollidingHash o) {
}

public static void main(String[] args) throws Exception {
testCollidingHash();
}

private static void testCollidingHash() {
Map<Object,Object> m = new HashMap<>(INITIAL_CAPACITY, LOAD_FACTOR);
IntStream.range(0, SIZE)
.mapToObj(CollidingHash::new)
Expand Down
53 changes: 52 additions & 1 deletion test/jdk/java/util/HashMap/ReplaceExisting.java
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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.VClass;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.HashSet;
Expand All @@ -43,6 +45,8 @@ public static void main(String[] args) {
for (int i = 0; i <= ENTRIES; i++) {
HashMap<Integer,Integer> hm = prepHashMap();
testItr(hm, i);
HashMap<VClass,Integer> tupleHm = prepTupleHashMap();
testTupleItr(tupleHm, i);
}
}

Expand All @@ -56,6 +60,15 @@ private static HashMap<Integer,Integer> prepHashMap() {
return hm;
}

private static HashMap<VClass,Integer> prepTupleHashMap() {
HashMap<VClass,Integer> 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 VClass(i * 10, new int[] { 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.
Expand Down Expand Up @@ -98,4 +111,42 @@ private static void testItr(HashMap<Integer,Integer> hm, int elemBeforePut) {
throw new RuntimeException("Collected keys do not match original set of keys");
}
}

private static void testTupleItr(HashMap<VClass,Integer> 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<VClass> keys = new HashSet<>(hm.size());
keys.addAll(hm.keySet());

HashSet<VClass> collected = new HashSet<>(hm.size());

// Run itr for elemBeforePut items, collecting returned elems
Iterator<VClass> itr = hm.keySet().iterator();
for (int i = 0; i < elemBeforePut; i++) {
VClass 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 VClass(0, new int[] { 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()) {
VClass 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");
}
}
}
20 changes: 19 additions & 1 deletion test/jdk/java/util/HashMap/SetValue.java
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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.VClass;
import java.util.HashMap;
import java.util.Map;

Expand All @@ -37,11 +39,27 @@ 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();
Object returnVal = e.setValue(newValue);
if (!returnVal.equals(oldValue))
throw new RuntimeException("Return value: " + returnVal);
}

private static void testTupleValue() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if tuple is good name here, might be testVClassValue?

Map<String, VClass> m = new HashMap<>();
VClass oldValue = new VClass(1, new int[] { 1 });
VClass newValue = new VClass(2, new int[] { 2 });
m.put(key, oldValue);
Map.Entry<String, VClass> e = m.entrySet().iterator().next();
Object returnVal = e.setValue(newValue);
if (!returnVal.equals(oldValue))
throw new RuntimeException("Return value: " + returnVal);
}
}
57 changes: 49 additions & 8 deletions test/jdk/java/util/HashMap/ToArray.java
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -31,27 +31,26 @@
import java.util.List;
import java.util.Map;
import java.util.stream.LongStream;
import jdk.test.lib.valueclass.VClass;

/*
* @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<Int> {
@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);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same about tuple in name.
"Not sure if tuple is good name here, might be testVClassValue?"

checkTupleMap(true);
checkTupleSet(false);
checkTupleSet(true);
}

private static <T extends Comparable<T>> void checkToArray(String message, T[] expected, Collection<T> collection,
Expand Down Expand Up @@ -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<VClass, VClass> 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);

List<VClass> keys = new ArrayList<>();
List<VClass> values = new ArrayList<>();
for (int i = 0; i < 100; i++) {
keys.add(new VClass(i, new int[] { i }));
values.add(new VClass(i * 2, new int[] { i * 2 }));
map.put(new VClass(i, new int[] { i }), new VClass(i * 2, new int[] { i * 2 }));
checkToArray(i + "-tuple-keys", keys.toArray(new VClass[0]), map.keySet(), !ordered);
checkToArray(i + "-tuple-values", values.toArray(new VClass[0]), map.values(), !ordered);
}
map.clear();
checkToArray("Empty-tuple-keys", new VClass[0], map.keySet(), !ordered);
checkToArray("Empty-tuple-values", new VClass[0], map.values(), !ordered);
}

private static void checkTupleSet(boolean ordered) {
Collection<VClass> set = ordered ? new LinkedHashSet<>() : new HashSet<>();
checkToArray("Empty-tuple", new VClass[0], set, !ordered);
set.add(new VClass(1, new int[] { 1 }));
checkToArray("One-tuple", new VClass[]{new VClass(1, new int[] { 1 })}, set, !ordered);
set.add(new VClass(2, new int[] { 2 }));
checkToArray("Two-tuple", new VClass[]{new VClass(1, new int[] { 1 }), new VClass(2, new int[] { 2 })}, set, !ordered);

Collection<VClass> tupleSet = ordered ? new LinkedHashSet<>() : new HashSet<>();
for (int x = 0; x < 100; x++) {
tupleSet.add(new VClass(x, new int[] { x }));
}
checkToArray("100-tuple", LongStream.range(0, 100).mapToObj(x -> new VClass((int) x, new int[] { (int) x }))
.toArray(VClass[]::new), tupleSet, !ordered);
tupleSet.clear();
checkToArray("After-clear-tuple", new VClass[0], tupleSet, !ordered);
for (int x = 0; x < 100; x++) {
tupleSet.add(new VClass(x, new int[] { -31 * x }));
}
checkToArray("Collisions-tuple", LongStream.range(0, 100).mapToObj(x -> new VClass((int) x, new int[] { -31 * (int) x }))
.toArray(VClass[]::new), tupleSet, !ordered);
}
}
5 changes: 4 additions & 1 deletion test/jdk/java/util/HashMap/TreeBinAssert.java
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -154,6 +156,7 @@ private void doTest(Object collection, int[] hashes,
/**
* Class that will have specified hash code in a HashMap.
*/
@AsValueClass

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same comment about having 2 testcases.

static class Key implements Comparable<Key> {
final int hash;

Expand Down
Loading