Skip to content

testlib: Add concurrent collection spliterator tests via derived suite builders#8173

Open
nickita-khylkouski wants to merge 4 commits intogoogle:masterfrom
nickita-khylkouski:add-concurrent-map-spliterator-tests
Open

testlib: Add concurrent collection spliterator tests via derived suite builders#8173
nickita-khylkouski wants to merge 4 commits intogoogle:masterfrom
nickita-khylkouski:add-concurrent-map-spliterator-tests

Conversation

@nickita-khylkouski
Copy link
Contributor

@nickita-khylkouski nickita-khylkouski commented Jan 26, 2026

Summary

Adds testlib support for verifying Spliterator characteristics on ConcurrentMap views.

Architecture (per @chaoren's feedback):

  • Add ConcurrentCollectionSpliteratorTester - tests that a collection's spliterator has the CONCURRENT characteristic
  • Add ConcurrentSetTestSuiteBuilder and ConcurrentCollectionTestSuiteBuilder - reusable builders that include the concurrent tester
  • Override createDerivedEntrySetSuite, createDerivedKeySetSuite, createDerivedValueCollectionSuite in ConcurrentMapTestSuiteBuilder to use the concurrent builders
  • Add spec invariant checks to CollectionSpliteratorTester (applies to ALL collections):
    • CONCURRENT and SIZED must not coexist
    • CONCURRENT and IMMUTABLE must not coexist
    • SUBSIZED requires SIZED
    • SORTED requires ORDERED

Motivation

Per issue #7855 and maintainer guidance from @chaoren:

  • ConcurrentMap implementations should return spliterators with the CONCURRENT characteristic
  • The Java specification mandates several characteristic invariants

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

  • Do NOT have CONCURRENT (should have it)
  • DO have SIZED (incompatible with CONCURRENT per spec)

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

Testing

  • Classes compile successfully
  • Tests follow the existing ConcurrentMap*Tester pattern (plain @GwtCompatible, @NullMarked, no reflection methods)
  • Verified JDK's ConcurrentHashMap correctly returns CONCURRENT=true, SIZED=false

Fixes #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.

* 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.

…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
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.
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.
@nickita-khylkouski nickita-khylkouski force-pushed the add-concurrent-map-spliterator-tests branch from fcdfd31 to 9c3cb22 Compare February 4, 2026 07:45
@nickita-khylkouski nickita-khylkouski changed the title testlib: Add ConcurrentMapSpliteratorTester for spliterator characteristics testlib: Add concurrent collection spliterator tests via derived suite builders Feb 4, 2026
@nickita-khylkouski
Copy link
Contributor Author

Done - moved the spec invariant checks to CollectionSpliteratorTester and set up the derived suite overrides so the concurrent builders get used for entrySet/keySet/values. Rebased on latest master too. Let me know if anything else needs adjusting.

Update @author tags from "Guava Authors" to the contributor's name,
matching the pattern used by sibling testers (ConcurrentMapPutIfAbsentTester,
ConcurrentMapRemoveTester, etc. all use @author Louis Wasserman).
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