Make Foreground dispatchable methods noop if parser is disposed.

- Added tests to validate each of the new noopable methods.

#1750
This commit is contained in:
N. Taylor Mullen 2017-11-06 15:52:34 -08:00
parent 834fd5a5d0
commit 399dcca4f2
2 changed files with 66 additions and 4 deletions

View File

@ -38,6 +38,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
private RazorTemplateEngine _templateEngine; private RazorTemplateEngine _templateEngine;
private RazorCodeDocument _codeDocument; private RazorCodeDocument _codeDocument;
private ITextSnapshot _snapshot; private ITextSnapshot _snapshot;
private bool _disposed;
// For testing only // For testing only
internal DefaultVisualStudioRazorParser(RazorCodeDocument codeDocument) internal DefaultVisualStudioRazorParser(RazorCodeDocument codeDocument)
@ -127,6 +128,8 @@ namespace Microsoft.VisualStudio.Editor.Razor
_documentTracker.ContextChanged -= DocumentTracker_ContextChanged; _documentTracker.ContextChanged -= DocumentTracker_ContextChanged;
StopIdleTimer(); StopIdleTimer();
_disposed = true;
} }
// Internal for testing // Internal for testing
@ -264,10 +267,16 @@ namespace Microsoft.VisualStudio.Editor.Razor
} }
} }
private void OnIdle(object state) // Internal for testing
internal void OnIdle(object state)
{ {
_dispatcher.AssertForegroundThread(); _dispatcher.AssertForegroundThread();
if (_disposed)
{
return;
}
OnNotifyForegroundIdle(); OnNotifyForegroundIdle();
foreach (var textView in _documentTracker.TextViews) foreach (var textView in _documentTracker.TextViews)
@ -283,13 +292,13 @@ namespace Microsoft.VisualStudio.Editor.Razor
QueueReparse(); QueueReparse();
} }
private void ReparseOnForeground(object state) // Internal for testing
internal void ReparseOnForeground(object state)
{ {
_dispatcher.AssertForegroundThread(); _dispatcher.AssertForegroundThread();
if (_parser == null) if (_disposed)
{ {
Debug.Fail("Reparse being attempted after the parser has been disposed.");
return; return;
} }
@ -354,6 +363,11 @@ namespace Microsoft.VisualStudio.Editor.Razor
{ {
_dispatcher.AssertForegroundThread(); _dispatcher.AssertForegroundThread();
if (_disposed)
{
return;
}
var args = (DocumentStructureChangedEventArgs)state; var args = (DocumentStructureChangedEventArgs)state;
if (_latestChangeReference == null || // extra hardening if (_latestChangeReference == null || // extra hardening
!_latestChangeReference.IsAssociatedWith(args)) !_latestChangeReference.IsAssociatedWith(args))

View File

@ -27,6 +27,54 @@ namespace Microsoft.VisualStudio.Editor.Razor
return documentTracker; return documentTracker;
} }
[ForegroundFact]
public void ReparseOnForeground_NoopsIfDisposed()
{
// Arrange
var parser = new DefaultVisualStudioRazorParser(
Dispatcher,
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>());
parser.Dispose();
// Act & Assert
parser.ReparseOnForeground(null);
}
[ForegroundFact]
public void OnIdle_NoopsIfDisposed()
{
// Arrange
var parser = new DefaultVisualStudioRazorParser(
Dispatcher,
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>());
parser.Dispose();
// Act & Assert
parser.OnIdle(null);
}
[ForegroundFact]
public void OnDocumentStructureChanged_NoopsIfDisposed()
{
// Arrange
var parser = new DefaultVisualStudioRazorParser(
Dispatcher,
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>());
parser.Dispose();
// Act & Assert
parser.OnDocumentStructureChanged(new object());
}
[ForegroundFact] [ForegroundFact]
public void OnDocumentStructureChanged_IgnoresEditsThatAreOld() public void OnDocumentStructureChanged_IgnoresEditsThatAreOld()
{ {