Skip to content

Cover persistent list implementation gaps with tests - #285

Open
DmitryNekrasov wants to merge 5 commits into
masterfrom
dmitry.nekrasov/list-tests
Open

Cover persistent list implementation gaps with tests#285
DmitryNekrasov wants to merge 5 commits into
masterfrom
dmitry.nekrasov/list-tests

Conversation

@DmitryNekrasov

Copy link
Copy Markdown
Collaborator

Deterministic tests for the persistent list paths that were exercised only by randomized stress runs or not at all, with sizes at the trie shape boundaries: tail fill, leaf push into the root, height growth.

Coverage of kotlinx.collections.immutable.implementations.immutableList by the deterministic suites (stress tests excluded):

Class, % Method, % Branch, % Line, % Instruction, %
Before 92.3% (12/13) 76.3% (103/135) 49.7% (187/376) 56.1% (469/836) 51.1% (2311/4520)
After 100% (13/13) 100% (135/135) 92.8% (349/376) 100% (836/836) 98.6% (4458/4520)

@DmitryNekrasov DmitryNekrasov self-assigned this Jul 21, 2026
class PersistentListBuilderInsertionTest {

init {
check(MAX_BUFFER_SIZE == 32) { "Test sizes assume a trie buffer size of 32" }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If we decide to change it, for some reason, how to update the test? I mean, it would be nice to mention it in a comment nearby

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

If the buffer size ever changes, the tests will fail on this check, and I'd recommend revisiting all the values manually and carefully verifying that every branch of the code under test is still covered. Automatically deriving all the constants in the tests looks less reliable to me, complicates the test logic and makes it less obvious, and isn't worth it: realistically, we are unlikely to ever change MAX_BUFFER_SIZE.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Sure, but right now it's unclear how constants were picked and how to choose new values if MAX_BUFFER_SIZE change.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Done. Documented the picking rules in checkTrieShapeAssumptions()'s KDoc.

@DmitryNekrasov
DmitryNekrasov force-pushed the dmitry.nekrasov/list-tests branch from 6aadeb9 to a51d05a Compare July 27, 2026 20:00
checkTrieShapeAssumptions()
}

private fun ownedBuilderOf(range: IntRange): PersistentList.Builder<Int> {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The lower bound is always 0, and with that it's essentially the same function as PersistentListBuilderInsertionTest.ownedBuilderOf.

It might be worth either extracting it into a base class (or into a separate internal utility function).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Done: extracted ownedBuilderOf(size) as an internal top-level function in listTestUtils.kt.

return vector
}

private fun assertElementsEqual(expected: List<Int>, actual: List<Int>) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

kotlin.test.assertContentEquals?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Done, dropped the helper, call sites use assertContentEquals directly.

return builder
}

private fun assertBuilderContents(expected: List<Int>, builder: PersistentList.Builder<Int>) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It seems like this one is also can be replaced with kotlin.test.assertContentEquals

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Done.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds deterministic coverage for persistent-list trie boundaries, iterator traversal, and builder mutation paths.

Changes:

  • Tests vector growth, insertion, removal, replacement, and bulk operations.
  • Covers mutable iterators and owned versus frozen builder behavior.
  • Documents and validates trie-shape boundary assumptions.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
TrieIteratorTest.kt Tests backward traversal at trie boundaries.
trieShapeAssumptions.kt Documents and validates boundary sizes.
PersistentVectorTest.kt Covers immutable vector operations.
PersistentListIteratorTest.kt Covers persistent and mutable iterators.
PersistentListBuilderRemovalTest.kt Tests builder removal and replacement paths.
PersistentListBuilderInsertionTest.kt Tests builder insertion and trie growth.
listTestUtils.kt Adds an owned-builder test helper.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants