mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-16 10:58:30 -05:00
Fixing bad data issue w/closing/opening untitled doc (#142)
* Adding useful unit tests for this functionality * Adding callback functionality for when a file is closed * Fixing bad data issue w/closing/opening untitled doc * Adding useful unit tests for this functionality * Adding callback functionality for when a file is closed * Moving from public to internal
This commit is contained in:
@@ -14,7 +14,12 @@ namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class EventContext
|
public class EventContext
|
||||||
{
|
{
|
||||||
private MessageWriter messageWriter;
|
private readonly MessageWriter messageWriter;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parameterless constructor required for mocking
|
||||||
|
/// </summary>
|
||||||
|
public EventContext() { }
|
||||||
|
|
||||||
public EventContext(MessageWriter messageWriter)
|
public EventContext(MessageWriter messageWriter)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
|
|||||||
ConfigChangeCallbacks = new List<ConfigChangeCallback>();
|
ConfigChangeCallbacks = new List<ConfigChangeCallback>();
|
||||||
TextDocChangeCallbacks = new List<TextDocChangeCallback>();
|
TextDocChangeCallbacks = new List<TextDocChangeCallback>();
|
||||||
TextDocOpenCallbacks = new List<TextDocOpenCallback>();
|
TextDocOpenCallbacks = new List<TextDocOpenCallback>();
|
||||||
|
TextDocCloseCallbacks = new List<TextDocCloseCallback>();
|
||||||
|
|
||||||
CurrentSettings = new TConfig();
|
CurrentSettings = new TConfig();
|
||||||
}
|
}
|
||||||
@@ -55,7 +56,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Workspace object for the service. Virtual to allow for mocking
|
/// Workspace object for the service. Virtual to allow for mocking
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual Workspace Workspace { get; private set; }
|
public virtual Workspace Workspace { get; internal set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Current settings for the workspace
|
/// Current settings for the workspace
|
||||||
@@ -84,7 +85,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
|
|||||||
/// <param name="openFile">File that was opened</param>
|
/// <param name="openFile">File that was opened</param>
|
||||||
/// <param name="eventContext">Context of the event raised for the changed files</param>
|
/// <param name="eventContext">Context of the event raised for the changed files</param>
|
||||||
public delegate Task TextDocOpenCallback(ScriptFile openFile, EventContext eventContext);
|
public delegate Task TextDocOpenCallback(ScriptFile openFile, EventContext eventContext);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delegate for callbacks that occur when a text document is closed
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="closedFile">File that was closed</param>
|
||||||
|
/// <param name="eventContext">Context of the event raised for changed files</param>
|
||||||
|
public delegate Task TextDocCloseCallback(ScriptFile closedFile, EventContext eventContext);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// List of callbacks to call when the configuration of the workspace changes
|
/// List of callbacks to call when the configuration of the workspace changes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -100,6 +108,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private List<TextDocOpenCallback> TextDocOpenCallbacks { get; set; }
|
private List<TextDocOpenCallback> TextDocOpenCallbacks { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of callbacks to call when a text document is closed
|
||||||
|
/// </summary>
|
||||||
|
private List<TextDocCloseCallback> TextDocCloseCallbacks { get; set; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -161,6 +173,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
|
|||||||
TextDocChangeCallbacks.Add(task);
|
TextDocChangeCallbacks.Add(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a new task to be called when a text document closes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="task">Delegate to call when the document closes</param>
|
||||||
|
public void RegisterTextDocCloseCallback(TextDocCloseCallback task)
|
||||||
|
{
|
||||||
|
TextDocCloseCallbacks.Add(task);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a new task to be called when a file is opened
|
/// Adds a new task to be called when a file is opened
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -177,7 +198,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles text document change events
|
/// Handles text document change events
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Task HandleDidChangeTextDocumentNotification(
|
internal Task HandleDidChangeTextDocumentNotification(
|
||||||
DidChangeTextDocumentParams textChangeParams,
|
DidChangeTextDocumentParams textChangeParams,
|
||||||
EventContext eventContext)
|
EventContext eventContext)
|
||||||
{
|
{
|
||||||
@@ -216,7 +237,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task HandleDidOpenTextDocumentNotification(
|
internal async Task HandleDidOpenTextDocumentNotification(
|
||||||
DidOpenTextDocumentNotification openParams,
|
DidOpenTextDocumentNotification openParams,
|
||||||
EventContext eventContext)
|
EventContext eventContext)
|
||||||
{
|
{
|
||||||
@@ -232,18 +253,31 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
|
|||||||
await Task.WhenAll(textDocOpenTasks);
|
await Task.WhenAll(textDocOpenTasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Task HandleDidCloseTextDocumentNotification(
|
internal async Task HandleDidCloseTextDocumentNotification(
|
||||||
DidCloseTextDocumentParams closeParams,
|
DidCloseTextDocumentParams closeParams,
|
||||||
EventContext eventContext)
|
EventContext eventContext)
|
||||||
{
|
{
|
||||||
Logger.Write(LogLevel.Verbose, "HandleDidCloseTextDocumentNotification");
|
Logger.Write(LogLevel.Verbose, "HandleDidCloseTextDocumentNotification");
|
||||||
return Task.FromResult(true);
|
|
||||||
|
// Skip closing this file if the file doesn't exist
|
||||||
|
var closedFile = Workspace.GetFile(closeParams.TextDocument.Uri);
|
||||||
|
if (closedFile == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trash the existing document from our mapping
|
||||||
|
Workspace.CloseFile(closedFile);
|
||||||
|
|
||||||
|
// Send out a notification to other services that have subscribed to this event
|
||||||
|
var textDocClosedTasks = TextDocCloseCallbacks.Select(t => t(closedFile, eventContext));
|
||||||
|
await Task.WhenAll(textDocClosedTasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles the configuration change event
|
/// Handles the configuration change event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected async Task HandleDidChangeConfigurationNotification(
|
internal async Task HandleDidChangeConfigurationNotification(
|
||||||
DidChangeConfigurationParams<TConfig> configChangeParams,
|
DidChangeConfigurationParams<TConfig> configChangeParams,
|
||||||
EventContext eventContext)
|
EventContext eventContext)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Workspace;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
|
||||||
|
using Microsoft.SqlTools.Test.Utility;
|
||||||
|
using Moq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.Test.Workspace
|
||||||
|
{
|
||||||
|
public class WorkspaceTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task FileClosedSuccessfully()
|
||||||
|
{
|
||||||
|
// Given:
|
||||||
|
// ... A workspace that has a single file open
|
||||||
|
var workspace = new ServiceLayer.Workspace.Workspace();
|
||||||
|
var workspaceService = new WorkspaceService<SqlToolsSettings> {Workspace = workspace};
|
||||||
|
var openedFile = workspace.GetFileBuffer(TestObjects.ScriptUri, string.Empty);
|
||||||
|
Assert.NotNull(openedFile);
|
||||||
|
Assert.NotEmpty(workspace.GetOpenedFiles());
|
||||||
|
|
||||||
|
// ... And there is a callback registered for the file closed event
|
||||||
|
ScriptFile closedFile = null;
|
||||||
|
workspaceService.RegisterTextDocCloseCallback((f, c) =>
|
||||||
|
{
|
||||||
|
closedFile = f;
|
||||||
|
return Task.FromResult(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// If:
|
||||||
|
// ... An event to close the open file occurs
|
||||||
|
var eventContext = new Mock<EventContext>().Object;
|
||||||
|
var requestParams = new DidCloseTextDocumentParams
|
||||||
|
{
|
||||||
|
TextDocument = new TextDocumentItem {Uri = TestObjects.ScriptUri}
|
||||||
|
};
|
||||||
|
await workspaceService.HandleDidCloseTextDocumentNotification(requestParams, eventContext);
|
||||||
|
|
||||||
|
// Then:
|
||||||
|
// ... The file should no longer be in the open files
|
||||||
|
Assert.Empty(workspace.GetOpenedFiles());
|
||||||
|
|
||||||
|
// ... The callback should have been called
|
||||||
|
// ... The provided script file should be the one we created
|
||||||
|
Assert.NotNull(closedFile);
|
||||||
|
Assert.Equal(openedFile, closedFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task FileClosedNotOpen()
|
||||||
|
{
|
||||||
|
// Given:
|
||||||
|
// ... A workspace that has no files open
|
||||||
|
var workspace = new ServiceLayer.Workspace.Workspace();
|
||||||
|
var workspaceService = new WorkspaceService<SqlToolsSettings> {Workspace = workspace};
|
||||||
|
Assert.Empty(workspace.GetOpenedFiles());
|
||||||
|
|
||||||
|
// ... And there is a callback registered for the file closed event
|
||||||
|
bool callbackCalled = false;
|
||||||
|
workspaceService.RegisterTextDocCloseCallback((f, c) =>
|
||||||
|
{
|
||||||
|
callbackCalled = true;
|
||||||
|
return Task.FromResult(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// If:
|
||||||
|
// ... An event to close the a file occurs
|
||||||
|
var eventContext = new Mock<EventContext>().Object;
|
||||||
|
var requestParams = new DidCloseTextDocumentParams
|
||||||
|
{
|
||||||
|
TextDocument = new TextDocumentItem {Uri = TestObjects.ScriptUri}
|
||||||
|
};
|
||||||
|
// Then:
|
||||||
|
// ... There should be a file not found exception thrown
|
||||||
|
// TODO: This logic should be changed to not create the ScriptFile
|
||||||
|
await Assert.ThrowsAsync<IOException>(
|
||||||
|
() => workspaceService.HandleDidCloseTextDocumentNotification(requestParams, eventContext));
|
||||||
|
|
||||||
|
// ... There should still be no open files
|
||||||
|
// ... The callback should not have been called
|
||||||
|
Assert.Empty(workspace.GetOpenedFiles());
|
||||||
|
Assert.False(callbackCalled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user