Skip to content

Commit b342aa2

Browse files
committed
fix: ensure dispose checks are performed before and after entering render lock
1 parent 4e01d4b commit b342aa2

File tree

1 file changed

+28
-10
lines changed

1 file changed

+28
-10
lines changed

src/bunit.core/Rendering/TestRenderer.cs

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ public Task DispatchEventAsync(
113113
// if the event contains associated data.
114114
lock (renderTreeUpdateLock)
115115
{
116+
if (disposed)
117+
throw new ObjectDisposedException(nameof(TestRenderer));
118+
116119
var result = Dispatcher.InvokeAsync(() =>
117120
{
118121
ResetUnhandledException();
@@ -190,10 +193,16 @@ public void DisposeComponents()
190193
/// <inheritdoc/>
191194
internal void SetDirectParameters(IRenderedFragmentBase renderedComponent, ParameterView parameters)
192195
{
196+
if (disposed)
197+
throw new ObjectDisposedException(nameof(TestRenderer));
198+
193199
// Calling SetDirectParameters updates the render tree
194200
// if the event contains associated data.
195201
lock (renderTreeUpdateLock)
196202
{
203+
if (disposed)
204+
throw new ObjectDisposedException(nameof(TestRenderer));
205+
197206
var result = Dispatcher.InvokeAsync(() =>
198207
{
199208
try
@@ -240,20 +249,20 @@ protected override void ProcessPendingRender()
240249
// so there is no need to lock in that method.
241250
lock (renderTreeUpdateLock)
242251
{
252+
if (disposed)
253+
{
254+
logger.LogRenderCycleActiveAfterDispose();
255+
return;
256+
}
257+
243258
base.ProcessPendingRender();
244259
}
245260
}
246261

247262
/// <inheritdoc/>
248263
protected override Task UpdateDisplayAsync(in RenderBatch renderBatch)
249264
{
250-
if (disposed)
251-
{
252-
return Task.CompletedTask;
253-
}
254-
255265
var renderEvent = new RenderEvent();
256-
257266
PrepareRenderEvent(renderBatch);
258267
InvokeApplyRenderEvent();
259268

@@ -394,10 +403,13 @@ protected override void Dispose(bool disposing)
394403
if (disposed)
395404
return;
396405

397-
disposed = true;
398-
399406
lock (renderTreeUpdateLock)
400407
{
408+
if (disposed)
409+
return;
410+
411+
disposed = true;
412+
401413
if (disposing)
402414
{
403415
foreach (var rc in renderedComponents.Values)
@@ -467,6 +479,9 @@ private IReadOnlyList<IRenderedComponentBase<TComponent>> FindComponents<TCompon
467479
// while this method searches through it.
468480
lock (renderTreeUpdateLock)
469481
{
482+
if (disposed)
483+
throw new ObjectDisposedException(nameof(TestRenderer));
484+
470485
FindComponentsInRenderTree(parentComponent.ComponentId);
471486
}
472487

@@ -579,11 +594,14 @@ private void AssertNoUnhandledExceptions()
579594
// tests failing that should not be failing.
580595
lock (renderTreeUpdateLock)
581596
{
582-
if (capturedUnhandledException is Exception unhandled && !disposed)
597+
if (disposed)
598+
return;
599+
600+
if (capturedUnhandledException is { } unhandled)
583601
{
584602
capturedUnhandledException = null;
585603

586-
if (unhandled is AggregateException aggregateException && aggregateException.InnerExceptions.Count == 1)
604+
if (unhandled is AggregateException { InnerExceptions.Count: 1 } aggregateException)
587605
{
588606
ExceptionDispatchInfo.Capture(aggregateException.InnerExceptions[0]).Throw();
589607
}

0 commit comments

Comments
 (0)