Skip to content

Conversation

@nickita-khylkouski
Copy link

Summary

  • Add ConcurrentMapSpliteratorTester to verify spliterator characteristics on ConcurrentMap views
  • Tests verify that entrySet(), keySet(), and values() spliterators have the CONCURRENT characteristic
  • Tests verify that no spliterator has both CONCURRENT and SIZED characteristics (mutually incompatible per Java spec)

Motivation

Per issue #7855 and maintainer guidance from @chaoren:

  • ConcurrentMap implementations should return spliterators with the CONCURRENT characteristic
  • The Java specification states that a top-level Spliterator should not report both CONCURRENT and SIZED

Currently, some Guava ConcurrentMap implementations (e.g., LocalCache, MapMakerInternalMap) return spliterators that:

  • Do NOT have CONCURRENT (should have it)
  • DO have SIZED (should not have it for concurrent collections)

This PR adds tests to document the expected behavior. A follow-up PR can fix the implementations.

Testing

  • Tests follow the existing ConcurrentMap*Tester pattern in testlib
  • Includes reflection helper methods for test suppression if needed
  • Verified JDK's ConcurrentHashMap correctly returns CONCURRENT=true, SIZED=false

Related Issues

Fixes #7855

…istics

Add tests to verify that ConcurrentMap implementations return spliterators
with the CONCURRENT characteristic on their entrySet(), keySet(), and
values() views. Also verifies that no spliterator reports both CONCURRENT
and SIZED characteristics (which are mutually incompatible per the Java
specification).

Fixes google#7855
@eamonnmcmanus eamonnmcmanus added the P3 no SLO label Jan 28, 2026
@chaoren chaoren requested review from chaoren and removed request for lowasser February 2, 2026 21:03
Spliterator<?> spliterator = getMap().values().spliterator();
assertTrue(
"values().spliterator() should have CONCURRENT characteristic",
spliterator.hasCharacteristics(Spliterator.CONCURRENT));
Copy link
Member

@chaoren chaoren Feb 2, 2026

Choose a reason for hiding this comment

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

I think we can move the testEntrySetSpliteratorNotConcurrentAndSized, testKeySetSpliteratorNotConcurrentAndSized, and testValuesSpliteratorNotConcurrentAndSized tests to CollectionSpliteratorTester instead.

Per https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Spliterator.html#CONCURRENT,

A top-level Spliterator should not report both CONCURRENT and SIZED
A top-level Spliterator should not report both CONCURRENT and IMMUTABLE

and that should apply to all top-level Spliterators, not just concurrent ones.

Also, https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Spliterator.html#SUBSIZED says

A Spliterator that does not report SIZED as required by SUBSIZED is inconsistent

We can check that as well.

Per review feedback — the spec invariants apply to all spliterators,
not just ConcurrentMap ones, so they belong in the common tester.

Added checks for all four spec-mandated invariants:
- CONCURRENT + SIZED must not coexist
- CONCURRENT + IMMUTABLE must not coexist
- SUBSIZED requires SIZED
- SORTED requires ORDERED

Stripped ConcurrentMapSpliteratorTester down to just the
CONCURRENT-must-exist assertions and dropped the reflection methods
to match the other ConcurrentMap*Tester classes.
* Tests that if the spliterator reports {@code SORTED}, it also reports {@code ORDERED}, as
* required by the {@link Spliterator} specification.
*/
public void testSpliteratorSortedRequiresOrdered() {
Copy link
Member

Choose a reason for hiding this comment

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

Good catch! Thanks for adding this as well.

ConcurrentMapRemoveTester.class,
ConcurrentMapReplaceTester.class,
ConcurrentMapReplaceEntryTester.class);
ConcurrentMapReplaceEntryTester.class,
Copy link
Member

Choose a reason for hiding this comment

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

Instead of adding a new tester here, we can maybe override the

  • createDerivedEntrySetSuite
  • createDerivedKeySetSuite
  • createDerivedValueCollectionSuite

methods to append a ConcurrentCollectionSpliteratorTester, so it could be reused for arbitrary concurrent collections.

Instead of adding ConcurrentMapSpliteratorTester to the map tester list,
use the derived suite architecture as @chaoren suggested:

- Add ConcurrentCollectionSpliteratorTester that tests any collection's
  spliterator for the CONCURRENT characteristic
- Add ConcurrentSetTestSuiteBuilder and ConcurrentCollectionTestSuiteBuilder
  that include this tester
- Override createDerivedEntrySetSuite/KeySetSuite/ValueCollectionSuite in
  ConcurrentMapTestSuiteBuilder to use the concurrent builders
- Delete ConcurrentMapSpliteratorTester (no longer needed)

This approach is more composable - the tester can be reused for any
concurrent collection, not just ConcurrentMap views.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P3 no SLO

Projects

None yet

Development

Successfully merging this pull request may close these issues.

testlib: add tests for ConcurrentMap to make sure its derived Sets are concurrent

3 participants