Skip to content

fix(test): schedule one-shot mocks by call index - #7098

Merged
proggeramlug merged 4 commits into
PerryTS:mainfrom
proggeramlug:fix/6767-node-test-mock-once-indices
Jul 31, 2026
Merged

fix(test): schedule one-shot mocks by call index#7098
proggeramlug merged 4 commits into
PerryTS:mainfrom
proggeramlug:fix/6767-node-test-mock-once-indices

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

  • store mockImplementationOnce replacements by absolute call index instead of FIFO order
  • forward and validate the optional onCall argument, with duplicate indices replacing the prior entry like Node's Map
  • preserve recorded calls and scheduled implementations when .mock.restore() restores the underlying implementation
  • keep indexed entries visible to the runtime root scanner and apply the side-table write barrier

This clears two more failures in #6767: mock-fn/implementations and mock-fn/once-indices.

Validation

  • cargo fmt --all -- --check
  • cargo check -p perry-runtime
  • cargo test -p perry-runtime default_once_scheduling_overwrites_the_current_call_index -- --nocapture
  • cargo test -p perry-runtime indexed_once_scheduling_uses_absolute_call_indices -- --nocapture
  • cargo test -p perry-runtime restoring_a_mock_preserves_calls_and_scheduled_implementations -- --nocapture
  • ./run_parity_tests.sh --suite node-suite --module test --filter node-suite/test/mock-fn/implementations (1/1 pass, 100%)
  • ./run_parity_tests.sh --suite node-suite --module test --filter node-suite/test/mock-fn/once-indices (1/1 pass, 100%)
  • git diff --check

Refs #6767

Summary by CodeRabbit

  • New Features

    • One-time mock implementations can be scheduled for specific call numbers.
    • Schedules can be replaced for the same call number.
    • Mock methods, getters, and setters support call-specific options with validation.
    • Created mocks preserve original function names and argument counts.
    • Test exports support optional test aliases.
  • Bug Fixes

    • Improved restoration behavior while preserving call counts and scheduled implementations.
    • Improved handling of reentrant mock calls.
  • Tests

    • Added coverage for indexed scheduling, overwriting schedules, restoration, and reentrant calls.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 78e88e85-d840-4321-ad0c-a00d5a742293

📥 Commits

Reviewing files that changed from the base of the PR and between ed19d74 and 764b68a.

📒 Files selected for processing (1)
  • crates/perry-runtime/src/node_submodules/test_once_unit_tests.rs

📝 Walkthrough

Walkthrough

Mock one-time implementations now use absolute call indices, support optional indexed scheduling with replacement, select implementations by invocation count, and preserve scheduled state during restoration. Mock APIs also accept accessor options and preserve function metadata.

Changes

Node test mock behavior

Layer / File(s) Summary
Mock API options and metadata
crates/perry-runtime/src/node_submodules/test.rs
Mock method, getter, and setter APIs accept validated options, support accessor routing, preserve function names and lengths, and root generated test exports.
Indexed scheduling and invocation
crates/perry-runtime/src/node_submodules/test.rs
Mock state stores indexed implementations; mockImplementationOnce validates optional indices, invocation selects matching implementations, restoration preserves schedules, and GC scans entries.
Indexed behavior and restoration tests
crates/perry-runtime/src/node_submodules/test_once_unit_tests.rs, crates/perry-runtime/src/node_submodules/test.rs, changelog.d/7098-node-test-mock-once-indices.md
Unit tests cover duplicate-index replacement, absolute call-index selection, reentrant dispatch, and restoration behavior; test modules and the changelog are updated.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TestContext
  participant MockExport
  participant MockHandler
  participant MockState
  participant MockInvocation
  TestContext->>MockExport: decorate test export
  MockExport->>MockHandler: pass implementation and options
  MockHandler->>MockState: configure mock
  MockInvocation->>MockState: read current call index
  MockState-->>MockInvocation: return matching implementation
  MockInvocation->>MockState: consume scheduled implementation
Loading

Possibly related PRs

Suggested labels: bug

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: scheduling one-shot mocks by call index.
Description check ✅ Passed The description explains the changes, references issue #6767, and provides detailed validation commands, though it omits the template headings and checklist.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/perry-runtime/src/node_submodules/test.rs`:
- Around line 645-652: The mock dispatch flow around take_mock_implementation
and mock_state_call_count must track invocation order before implementation
execution, separately from completed state.calls records. Reserve and increment
an internal invocation index before dispatch, reset it wherever call history is
reset, and use it for onCall/default scheduling while preserving completed-call
recording. Add a regression test covering a recursively invoked mock and
verifying the scheduled implementations run on the correct invocation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ccf4dce5-918a-4c35-88d2-44b3fed5a20d

📥 Commits

Reviewing files that changed from the base of the PR and between c86835f and b75feee.

📒 Files selected for processing (3)
  • changelog.d/7098-node-test-mock-once-indices.md
  • crates/perry-runtime/src/node_submodules/test.rs
  • crates/perry-runtime/src/node_submodules/test_once_unit_tests.rs

Comment thread crates/perry-runtime/src/node_submodules/test.rs

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/perry-runtime/src/node_submodules/test_once_unit_tests.rs`:
- Around line 69-87: Update
reentrant_dispatch_uses_completed_call_indices_like_node to exercise nested
dispatch through an outer mock implementation that recursively invokes the same
mock, rather than directly calling take_mock_implementation and manually setting
the count. Assert the onCall=1 entry remains pending after the outer and nested
invocations, then schedule another implementation using the actual completed
count and verify it is selected on the next invocation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bd0c1769-a635-416d-8240-61a0285e14ca

📥 Commits

Reviewing files that changed from the base of the PR and between b75feee and 5471c66.

📒 Files selected for processing (1)
  • crates/perry-runtime/src/node_submodules/test_once_unit_tests.rs

Comment thread crates/perry-runtime/src/node_submodules/test_once_unit_tests.rs Outdated
@proggeramlug
proggeramlug force-pushed the fix/6767-node-test-mock-once-indices branch from 5471c66 to ed19d74 Compare July 31, 2026 01:23

@coderabbitai coderabbitai Bot 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
crates/perry-runtime/src/node_submodules/test.rs (2)

676-699: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Root the restored closure before any GC-capable call.

The only metadata helpers used here are static lookups, but set_bound_native_closure_name allocates a String, so reusing closure_ptr afterwards is a stale native-stack pointer across GC candidates. Reload closure_ptr from function.get_nanbox_f64() before set_builtin_closure_length, set_builtin_property_attrs, and closure_set_dynamic_prop.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/perry-runtime/src/node_submodules/test.rs` around lines 676 - 699,
Update the closure setup in the mock-function initialization flow so the
restored closure remains rooted across the allocation in
set_bound_native_closure_name. Reload closure_ptr from function.get_nanbox_f64()
after set_bound_native_closure_name and use that refreshed pointer for
set_builtin_closure_length, set_builtin_property_attrs, and
closure_set_dynamic_prop.

Source: Learnings


545-551: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Don’t normalize accessor args the same as methods.

normalize_mock_method_args() currently swaps whenever implementation is a non-callable pointer. For mock.getter() / mock.setter(), keep the second argument as options even when the implementation is an object/array/string; otherwise mock.getter(obj, 'p', {}, { getter: true }) discards the explicit options and passes the non-function implementation blindly to assert_callable_arg("implementation", implementation).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/perry-runtime/src/node_submodules/test.rs` around lines 545 - 551, The
argument normalization in normalize_mock_method_args must distinguish accessor
calls from method calls: preserve the explicit options argument for
mock.getter/mock.setter even when implementation is an object, array, or string,
while retaining the existing swap behavior for regular methods. Update the
relevant caller or normalization flow so accessor implementations still reach
assert_callable_arg("implementation", implementation) correctly without
discarding accessor options.
🧹 Nitpick comments (1)
crates/perry-runtime/src/node_submodules/test.rs (1)

849-851: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Move the metadata_tests declaration with the other test modules.

test_metadata_unit_tests.rs exists, so this doesn’t block compilation; keep it grouped with the other #[cfg(test)] #[path = ...] declarations outside production code.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/perry-runtime/src/node_submodules/test.rs` around lines 849 - 851,
Move the metadata_tests module declaration, including its #[cfg(test)] and
#[path = "test_metadata_unit_tests.rs"] attributes, out of the production-code
section and group it with the other test module declarations in the file.
Preserve the module name and path unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@crates/perry-runtime/src/node_submodules/test.rs`:
- Around line 676-699: Update the closure setup in the mock-function
initialization flow so the restored closure remains rooted across the allocation
in set_bound_native_closure_name. Reload closure_ptr from
function.get_nanbox_f64() after set_bound_native_closure_name and use that
refreshed pointer for set_builtin_closure_length, set_builtin_property_attrs,
and closure_set_dynamic_prop.
- Around line 545-551: The argument normalization in normalize_mock_method_args
must distinguish accessor calls from method calls: preserve the explicit options
argument for mock.getter/mock.setter even when implementation is an object,
array, or string, while retaining the existing swap behavior for regular
methods. Update the relevant caller or normalization flow so accessor
implementations still reach assert_callable_arg("implementation",
implementation) correctly without discarding accessor options.

---

Nitpick comments:
In `@crates/perry-runtime/src/node_submodules/test.rs`:
- Around line 849-851: Move the metadata_tests module declaration, including its
#[cfg(test)] and #[path = "test_metadata_unit_tests.rs"] attributes, out of the
production-code section and group it with the other test module declarations in
the file. Preserve the module name and path unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e97ba8ea-12bf-42fb-8f71-3dc5bde54553

📥 Commits

Reviewing files that changed from the base of the PR and between 5471c66 and ed19d74.

📒 Files selected for processing (3)
  • changelog.d/7098-node-test-mock-once-indices.md
  • crates/perry-runtime/src/node_submodules/test.rs
  • crates/perry-runtime/src/node_submodules/test_once_unit_tests.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • changelog.d/7098-node-test-mock-once-indices.md

@proggeramlug
proggeramlug merged commit 2670ec6 into PerryTS:main Jul 31, 2026
7 checks passed
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.

1 participant