Skip to content

test: regression guard for block params in nested with/each (issue #595)#636

Merged
rexm merged 2 commits into
masterfrom
worktree-agent-a18fb66e9fc38f45e
Jun 20, 2026
Merged

test: regression guard for block params in nested with/each (issue #595)#636
rexm merged 2 commits into
masterfrom
worktree-agent-a18fb66e9fc38f45e

Conversation

@rexm

@rexm rexm commented Jun 20, 2026

Copy link
Copy Markdown
Member

Summary

Closes #595

This PR adds regression tests in source/Handlebars.Test/Issues/Issue595Tests.cs for the reported NotSupportedException: TypeConverter cannot convert UndefinedBindingResult when using {{#with this as |field|}} inside {{#each Fields}} and then passing field to a helper inside a nested {{#each (helper field)}}.

Findings: Bug is NOT reproducible in current code

Two previous agents investigated this issue and could not reproduce the exception. This agent confirmed the same conclusion:

  • All 4 regression tests pass, including a 1000-iteration stress test designed to exercise BindingContext pool reuse (the claimed root cause)
  • The FixedSizeDictionary.OptionalClear() path (called when returning a BindingContext to the pool) increments _version, which invalidates all EntryIndex objects from the previous use. Subsequent lookups via TryGetValue(in EntryIndex<TKey> keyIndex, ...) check keyIndex.Version != _version and correctly return false — so stale block-param slots from prior pool tenants are never served to new callers
  • The 300f2f6 Improve object pool safety commit (Mar 2022) and 8a58d30 fix: prevent unbounded DictionarySlim growth when replacing existing keys (issue #541) commit are the likely fixes that made this class of bug non-reproducible on current main

Tests added

Test What it checks
BlockParamFromWithShouldBePassableToHelperInInnerEach Basic end-to-end: block param resolves to actual field value (not UndefinedBindingResult)
BlockParamTypedAccessShouldNotThrowWhenPassedToHelper Uses arguments.At<string>(0) (typed access) which would throw NotSupportedException if the value were UndefinedBindingResult
BlockParamFromWithShouldBePassableToHelperInInnerEachMultipleIterations 5-field loop with multiple pool cycles
Issue595_WithBlockParamsInEach_DoesNotThrow Canonical 1000-iteration stress test from the issue report

Test plan

  • dotnet test --filter "Issue595" — 4/4 passed
  • No production code changed

🤖 Generated with Claude Code

rexm and others added 2 commits June 20, 2026 12:19
Adds Issue595Tests.cs with four regression tests covering the reported
NotSupportedException: TypeConverter cannot convert UndefinedBindingResult
when using {{#with this as |field|}} inside {{#each Fields}} and passing
`field` to a helper in a nested {{#each (helper field)}}.

All four tests pass on the current codebase, confirming the bug is not
reproducible. The FixedSizeDictionary.Reset() version-bump mechanism
(OptionalClear) already prevents stale block-param values from leaking
across BindingContext pool reuse cycles.

Includes a 1000-iteration stress test to exercise pool reuse under load.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@rexm rexm enabled auto-merge June 20, 2026 17:57
@sonarqubecloud

Copy link
Copy Markdown

@rexm rexm merged commit 1ceb170 into master Jun 20, 2026
7 checks passed
@rexm rexm deleted the worktree-agent-a18fb66e9fc38f45e branch June 20, 2026 18:08
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.

randomly got System.NotSupportedException: 'TypeConverter' is unable to convert 'HandlebarsDotNet.UndefinedBindingResult' to 'xxx'

1 participant