mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-23 01:25:42 -05:00
Isolate Shared Test Code (#252)
The goal of this make sure that test code is correctly organized to ensure that test suites aren't dependent on each other.
* UnitTests get their own project now (renaming Microsoft.SqlTools.ServiceLayer.Test to Microsoft.SqlTools.ServiceLayer.UnitTests) which is about 90% of the changes to the files.
* IntegrationTests no longer depends on UnitTests, only Test.Common
* Any shared components from TestObjects that spins up a "live" connection has been moved to IntegrationTests Utility/LiveConnectionHelper.cs
* The dictionary-based mock file stream factory has been moved to Test.Common since it is used by UnitTests and IntegrationTests
* Added a overload that doesn't take a dictionary for when we don't care about monitoring the storage (about 90% of the time)
* The RunIf* wrapper methods have been moved to Test.Common
* OwnerUri and StandardQuery constants have been moved to Test.Common Constants file
* Updating to latest SDK version available at https://www.microsoft.com/net/core#windowscmd
* Moving unit tests to unit test folder
* Changing namespaces to UnitTests
* Moving some constants and shared functionality into common project, making the UnitTests reference it
* Unit tests are working!
* Integration tests are working
* Updating automated test runs
* Fixing one last broken unit test
* Exposing internals for other projects
* Moving edit data tests to UnitTest project
* Applying refactor fixes to unit tests
* Fixing flaky test that wasn't awaiting completion
This commit is contained in:
@@ -0,0 +1,225 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Binder;
|
||||
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Parser;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
||||
using Microsoft.SqlTools.ServiceLayer.UnitTests.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
|
||||
using GlobalCommon = Microsoft.SqlTools.ServiceLayer.Test.Common;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.LanguageServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests for the language service autocomplete component
|
||||
/// </summary>
|
||||
public class AutocompleteTests
|
||||
{
|
||||
private const int TaskTimeout = 60000;
|
||||
|
||||
private readonly string testScriptUri = TestObjects.ScriptUri;
|
||||
|
||||
private readonly string testConnectionKey = "testdbcontextkey";
|
||||
|
||||
private Mock<ConnectedBindingQueue> bindingQueue;
|
||||
|
||||
private Mock<WorkspaceService<SqlToolsSettings>> workspaceService;
|
||||
|
||||
private Mock<RequestContext<CompletionItem[]>> requestContext;
|
||||
|
||||
private Mock<ScriptFile> scriptFile;
|
||||
|
||||
private Mock<IBinder> binder;
|
||||
|
||||
private ScriptParseInfo scriptParseInfo;
|
||||
|
||||
private TextDocumentPosition textDocument;
|
||||
|
||||
private void InitializeTestObjects()
|
||||
{
|
||||
// initial cursor position in the script file
|
||||
textDocument = new TextDocumentPosition
|
||||
{
|
||||
TextDocument = new TextDocumentIdentifier {Uri = this.testScriptUri},
|
||||
Position = new Position
|
||||
{
|
||||
Line = 0,
|
||||
Character = 0
|
||||
}
|
||||
};
|
||||
|
||||
// default settings are stored in the workspace service
|
||||
WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings = new SqlToolsSettings();
|
||||
|
||||
// set up file for returning the query
|
||||
scriptFile = new Mock<ScriptFile>();
|
||||
scriptFile.SetupGet(file => file.Contents).Returns(GlobalCommon.Constants.StandardQuery);
|
||||
scriptFile.SetupGet(file => file.ClientFilePath).Returns(this.testScriptUri);
|
||||
|
||||
// set up workspace mock
|
||||
workspaceService = new Mock<WorkspaceService<SqlToolsSettings>>();
|
||||
workspaceService.Setup(service => service.Workspace.GetFile(It.IsAny<string>()))
|
||||
.Returns(scriptFile.Object);
|
||||
|
||||
// setup binding queue mock
|
||||
bindingQueue = new Mock<ConnectedBindingQueue>();
|
||||
bindingQueue.Setup(q => q.AddConnectionContext(It.IsAny<ConnectionInfo>(), It.IsAny<bool>()))
|
||||
.Returns(this.testConnectionKey);
|
||||
|
||||
// inject mock instances into the Language Service
|
||||
LanguageService.WorkspaceServiceInstance = workspaceService.Object;
|
||||
LanguageService.ConnectionServiceInstance = TestObjects.GetTestConnectionService();
|
||||
ConnectionInfo connectionInfo = TestObjects.GetTestConnectionInfo();
|
||||
LanguageService.ConnectionServiceInstance.OwnerToConnectionMap.Add(this.testScriptUri, connectionInfo);
|
||||
LanguageService.Instance.BindingQueue = bindingQueue.Object;
|
||||
|
||||
// setup the mock for SendResult
|
||||
requestContext = new Mock<RequestContext<CompletionItem[]>>();
|
||||
requestContext.Setup(rc => rc.SendResult(It.IsAny<CompletionItem[]>()))
|
||||
.Returns(Task.FromResult(0));
|
||||
|
||||
// setup the IBinder mock
|
||||
binder = new Mock<IBinder>();
|
||||
binder.Setup(b => b.Bind(
|
||||
It.IsAny<IEnumerable<ParseResult>>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<BindMode>()));
|
||||
|
||||
scriptParseInfo = new ScriptParseInfo();
|
||||
LanguageService.Instance.AddOrUpdateScriptParseInfo(this.testScriptUri, scriptParseInfo);
|
||||
scriptParseInfo.IsConnected = true;
|
||||
scriptParseInfo.ConnectionKey = LanguageService.Instance.BindingQueue.AddConnectionContext(connectionInfo);
|
||||
|
||||
// setup the binding context object
|
||||
ConnectedBindingContext bindingContext = new ConnectedBindingContext();
|
||||
bindingContext.Binder = binder.Object;
|
||||
bindingContext.MetadataDisplayInfoProvider = new MetadataDisplayInfoProvider();
|
||||
LanguageService.Instance.BindingQueue.BindingContextMap.Add(scriptParseInfo.ConnectionKey, bindingContext);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HandleCompletionRequestDisabled()
|
||||
{
|
||||
InitializeTestObjects();
|
||||
WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings.SqlTools.IntelliSense.EnableIntellisense = false;
|
||||
Assert.NotNull(LanguageService.HandleCompletionRequest(null, null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HandleCompletionResolveRequestDisabled()
|
||||
{
|
||||
InitializeTestObjects();
|
||||
WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings.SqlTools.IntelliSense.EnableIntellisense = false;
|
||||
Assert.NotNull(LanguageService.HandleCompletionResolveRequest(null, null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HandleSignatureHelpRequestDisabled()
|
||||
{
|
||||
InitializeTestObjects();
|
||||
WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings.SqlTools.IntelliSense.EnableIntellisense = false;
|
||||
Assert.NotNull(LanguageService.HandleSignatureHelpRequest(null, null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddOrUpdateScriptParseInfoNullUri()
|
||||
{
|
||||
InitializeTestObjects();
|
||||
LanguageService.Instance.AddOrUpdateScriptParseInfo("abracadabra", scriptParseInfo);
|
||||
Assert.True(LanguageService.Instance.ScriptParseInfoMap.ContainsKey("abracadabra"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDefinitionInvalidTextDocument()
|
||||
{
|
||||
InitializeTestObjects();
|
||||
textDocument.TextDocument.Uri = "invaliduri";
|
||||
Assert.Null(LanguageService.Instance.GetDefinition(textDocument, null, null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveScriptParseInfoNullUri()
|
||||
{
|
||||
InitializeTestObjects();
|
||||
Assert.False(LanguageService.Instance.RemoveScriptParseInfo("abc123"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsPreviewWindowNullScriptFileTest()
|
||||
{
|
||||
InitializeTestObjects();
|
||||
Assert.False(LanguageService.Instance.IsPreviewWindow(null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetCompletionItemsInvalidTextDocument()
|
||||
{
|
||||
InitializeTestObjects();
|
||||
textDocument.TextDocument.Uri = "somethinggoeshere";
|
||||
Assert.True(LanguageService.Instance.GetCompletionItems(textDocument, scriptFile.Object, null).Length > 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDiagnosticFromMarkerTest()
|
||||
{
|
||||
var scriptFileMarker = new ScriptFileMarker()
|
||||
{
|
||||
Message = "Message",
|
||||
Level = ScriptFileMarkerLevel.Error,
|
||||
ScriptRegion = new ScriptRegion()
|
||||
{
|
||||
File = "file://nofile.sql",
|
||||
StartLineNumber = 1,
|
||||
StartColumnNumber = 1,
|
||||
StartOffset = 0,
|
||||
EndLineNumber = 1,
|
||||
EndColumnNumber = 1,
|
||||
EndOffset = 0
|
||||
}
|
||||
};
|
||||
var diagnostic = DiagnosticsHelper.GetDiagnosticFromMarker(scriptFileMarker);
|
||||
Assert.Equal(diagnostic.Message, scriptFileMarker.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MapDiagnosticSeverityTest()
|
||||
{
|
||||
var level = ScriptFileMarkerLevel.Error;
|
||||
Assert.Equal(DiagnosticsHelper.MapDiagnosticSeverity(level), DiagnosticSeverity.Error);
|
||||
level = ScriptFileMarkerLevel.Warning;
|
||||
Assert.Equal(DiagnosticsHelper.MapDiagnosticSeverity(level), DiagnosticSeverity.Warning);
|
||||
level = ScriptFileMarkerLevel.Information;
|
||||
Assert.Equal(DiagnosticsHelper.MapDiagnosticSeverity(level), DiagnosticSeverity.Information);
|
||||
level = (ScriptFileMarkerLevel)100;
|
||||
Assert.Equal(DiagnosticsHelper.MapDiagnosticSeverity(level), DiagnosticSeverity.Error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests the primary completion list event handler
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetCompletionsHandlerTest()
|
||||
{
|
||||
InitializeTestObjects();
|
||||
|
||||
// request the completion list
|
||||
Task handleCompletion = LanguageService.HandleCompletionRequest(textDocument, requestContext.Object);
|
||||
handleCompletion.Wait(TaskTimeout);
|
||||
|
||||
// verify that send result was called with a completion array
|
||||
requestContext.Verify(m => m.SendResult(It.IsAny<CompletionItem[]>()), Times.Once());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System.Threading;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.SmoMetadataProvider;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Binder;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Common;
|
||||
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Parser;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.LanguageServer
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Test class for the test binding context
|
||||
/// </summary>
|
||||
public class TestBindingContext : IBindingContext
|
||||
{
|
||||
public TestBindingContext()
|
||||
{
|
||||
this.BindingLock = new ManualResetEvent(true);
|
||||
this.BindingTimeout = 3000;
|
||||
}
|
||||
|
||||
public bool IsConnected { get; set; }
|
||||
|
||||
public ServerConnection ServerConnection { get; set; }
|
||||
|
||||
public MetadataDisplayInfoProvider MetadataDisplayInfoProvider { get; set; }
|
||||
|
||||
public SmoMetadataProvider SmoMetadataProvider { get; set; }
|
||||
|
||||
public IBinder Binder { get; set; }
|
||||
|
||||
public ManualResetEvent BindingLock { get; set; }
|
||||
|
||||
public int BindingTimeout { get; set; }
|
||||
|
||||
public ParseOptions ParseOptions { get; }
|
||||
|
||||
public ServerVersion ServerVersion { get; }
|
||||
|
||||
public DatabaseEngineType DatabaseEngineType { get; }
|
||||
|
||||
public TransactSqlVersion TransactSqlVersion { get; }
|
||||
|
||||
public DatabaseCompatibilityLevel DatabaseCompatibilityLevel { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests for the Binding Queue
|
||||
/// </summary>
|
||||
public class BindingQueueTests
|
||||
{
|
||||
private int bindCallCount = 0;
|
||||
|
||||
private int timeoutCallCount = 0;
|
||||
|
||||
private int bindCallbackDelay = 0;
|
||||
|
||||
private bool isCancelationRequested = false;
|
||||
|
||||
private IBindingContext bindingContext = null;
|
||||
|
||||
private BindingQueue<TestBindingContext> bindingQueue = null;
|
||||
|
||||
private void InitializeTestSettings()
|
||||
{
|
||||
this.bindCallCount = 0;
|
||||
this.timeoutCallCount = 0;
|
||||
this.bindCallbackDelay = 10;
|
||||
this.isCancelationRequested = false;
|
||||
this.bindingContext = GetMockBindingContext();
|
||||
this.bindingQueue = new BindingQueue<TestBindingContext>();
|
||||
}
|
||||
|
||||
private IBindingContext GetMockBindingContext()
|
||||
{
|
||||
return new TestBindingContext();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test bind operation callback
|
||||
/// </summary>
|
||||
private object TestBindOperation(
|
||||
IBindingContext bindContext,
|
||||
CancellationToken cancelToken)
|
||||
{
|
||||
cancelToken.WaitHandle.WaitOne(this.bindCallbackDelay);
|
||||
this.isCancelationRequested = cancelToken.IsCancellationRequested;
|
||||
if (!this.isCancelationRequested)
|
||||
{
|
||||
++this.bindCallCount;
|
||||
}
|
||||
return new CompletionItem[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test callback for the bind timeout operation
|
||||
/// </summary>
|
||||
private object TestTimeoutOperation(
|
||||
IBindingContext bindingContext)
|
||||
{
|
||||
++this.timeoutCallCount;
|
||||
return new CompletionItem[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queues a single task
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void QueueOneBindingOperationTest()
|
||||
{
|
||||
InitializeTestSettings();
|
||||
|
||||
this.bindingQueue.QueueBindingOperation(
|
||||
key: "testkey",
|
||||
bindOperation: TestBindOperation,
|
||||
timeoutOperation: TestTimeoutOperation);
|
||||
|
||||
Thread.Sleep(1000);
|
||||
|
||||
this.bindingQueue.StopQueueProcessor(15000);
|
||||
|
||||
Assert.True(this.bindCallCount == 1);
|
||||
Assert.True(this.timeoutCallCount == 0);
|
||||
Assert.False(this.isCancelationRequested);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue a 100 short tasks
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Queue100BindingOperationTest()
|
||||
{
|
||||
InitializeTestSettings();
|
||||
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
this.bindingQueue.QueueBindingOperation(
|
||||
key: "testkey",
|
||||
bindOperation: TestBindOperation,
|
||||
timeoutOperation: TestTimeoutOperation);
|
||||
}
|
||||
|
||||
Thread.Sleep(2000);
|
||||
|
||||
this.bindingQueue.StopQueueProcessor(15000);
|
||||
|
||||
Assert.True(this.bindCallCount == 100);
|
||||
Assert.True(this.timeoutCallCount == 0);
|
||||
Assert.False(this.isCancelationRequested);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue an task with a long operation causing a timeout
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void QueueWithTimeout()
|
||||
{
|
||||
InitializeTestSettings();
|
||||
|
||||
this.bindCallbackDelay = 1000;
|
||||
|
||||
this.bindingQueue.QueueBindingOperation(
|
||||
key: "testkey",
|
||||
bindingTimeout: bindCallbackDelay / 2,
|
||||
bindOperation: TestBindOperation,
|
||||
timeoutOperation: TestTimeoutOperation);
|
||||
|
||||
Thread.Sleep(this.bindCallbackDelay + 100);
|
||||
|
||||
this.bindingQueue.StopQueueProcessor(15000);
|
||||
|
||||
Assert.True(this.bindCallCount == 0);
|
||||
Assert.True(this.timeoutCallCount == 1);
|
||||
Assert.True(this.isCancelationRequested);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
|
||||
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.LanguageServer
|
||||
{
|
||||
public class CompletionServiceTest
|
||||
{
|
||||
[Fact]
|
||||
public void CompletionItemsShouldCreatedUsingSqlParserIfTheProcessDoesNotTimeout()
|
||||
{
|
||||
ConnectedBindingQueue bindingQueue = new ConnectedBindingQueue();
|
||||
ScriptDocumentInfo docInfo = CreateScriptDocumentInfo();
|
||||
CompletionService completionService = new CompletionService(bindingQueue);
|
||||
ConnectionInfo connectionInfo = new ConnectionInfo(null, null, null);
|
||||
bool useLowerCaseSuggestions = true;
|
||||
CompletionItem[] defaultCompletionList = AutoCompleteHelper.GetDefaultCompletionItems(docInfo, useLowerCaseSuggestions);
|
||||
|
||||
List<Declaration> declarations = new List<Declaration>();
|
||||
|
||||
var sqlParserWrapper = new Mock<ISqlParserWrapper>();
|
||||
sqlParserWrapper.Setup(x => x.FindCompletions(docInfo.ScriptParseInfo.ParseResult, docInfo.ParserLine, docInfo.ParserColumn,
|
||||
It.IsAny<IMetadataDisplayInfoProvider>())).Returns(declarations);
|
||||
completionService.SqlParserWrapper = sqlParserWrapper.Object;
|
||||
|
||||
AutoCompletionResult result = completionService.CreateCompletions(connectionInfo, docInfo, useLowerCaseSuggestions);
|
||||
Assert.NotNull(result);
|
||||
Assert.NotEqual(result.CompletionItems == null ? 0 : result.CompletionItems.Count(), defaultCompletionList.Count());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompletionItemsShouldCreatedUsingDefaultListIfTheSqlParserProcessTimesout()
|
||||
{
|
||||
ConnectedBindingQueue bindingQueue = new ConnectedBindingQueue();
|
||||
ScriptDocumentInfo docInfo = CreateScriptDocumentInfo();
|
||||
CompletionService completionService = new CompletionService(bindingQueue);
|
||||
ConnectionInfo connectionInfo = new ConnectionInfo(null, null, null);
|
||||
bool useLowerCaseSuggestions = true;
|
||||
List<Declaration> declarations = new List<Declaration>();
|
||||
CompletionItem[] defaultCompletionList = AutoCompleteHelper.GetDefaultCompletionItems(docInfo, useLowerCaseSuggestions);
|
||||
|
||||
var sqlParserWrapper = new Mock<ISqlParserWrapper>();
|
||||
sqlParserWrapper.Setup(x => x.FindCompletions(docInfo.ScriptParseInfo.ParseResult, docInfo.ParserLine, docInfo.ParserColumn,
|
||||
It.IsAny<IMetadataDisplayInfoProvider>())).Callback(() => Thread.Sleep(LanguageService.BindingTimeout + 100)).Returns(declarations);
|
||||
completionService.SqlParserWrapper = sqlParserWrapper.Object;
|
||||
|
||||
AutoCompletionResult result = completionService.CreateCompletions(connectionInfo, docInfo, useLowerCaseSuggestions);
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(result.CompletionItems.Count(), defaultCompletionList.Count());
|
||||
Thread.Sleep(3000);
|
||||
Assert.True(connectionInfo.IntellisenseMetrics.Quantile.Any());
|
||||
}
|
||||
|
||||
private ScriptDocumentInfo CreateScriptDocumentInfo()
|
||||
{
|
||||
TextDocumentPosition doc = new TextDocumentPosition()
|
||||
{
|
||||
TextDocument = new TextDocumentIdentifier
|
||||
{
|
||||
Uri = "script file"
|
||||
},
|
||||
Position = new Position()
|
||||
{
|
||||
Line = 1,
|
||||
Character = 14
|
||||
}
|
||||
};
|
||||
ScriptFile scriptFile = new ScriptFile()
|
||||
{
|
||||
Contents = "Select * from sys.all_objects"
|
||||
};
|
||||
|
||||
ScriptParseInfo scriptParseInfo = new ScriptParseInfo() { IsConnected = true };
|
||||
ScriptDocumentInfo docInfo = new ScriptDocumentInfo(doc, scriptFile, scriptParseInfo);
|
||||
|
||||
return docInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.LanguageServer
|
||||
{
|
||||
public class InteractionMetricsTest
|
||||
{
|
||||
[Fact]
|
||||
public void MetricsShouldGetSortedGivenUnSortedArray()
|
||||
{
|
||||
int[] metrics = new int[] { 4, 8, 1, 11, 3 };
|
||||
int[] expected = new int[] { 1, 3, 4, 8, 11 };
|
||||
InteractionMetrics<int> interactionMetrics = new InteractionMetrics<int>(metrics);
|
||||
|
||||
Assert.Equal(interactionMetrics.Metrics, expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MetricsShouldThrowExceptionGivenNullInput()
|
||||
{
|
||||
int[] metrics = null;
|
||||
Assert.Throws<ArgumentNullException>(() => new InteractionMetrics<int>(metrics));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MetricsShouldThrowExceptionGivenEmptyInput()
|
||||
{
|
||||
int[] metrics = new int[] { };
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => new InteractionMetrics<int>(metrics));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MetricsShouldNotChangeGivenSortedArray()
|
||||
{
|
||||
int[] metrics = new int[] { 1, 3, 4, 8, 11 };
|
||||
int[] expected = new int[] { 1, 3, 4, 8, 11 };
|
||||
InteractionMetrics<int> interactionMetrics = new InteractionMetrics<int>(metrics);
|
||||
|
||||
Assert.Equal(interactionMetrics.Metrics, expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MetricsShouldNotChangeGivenArrayWithOneItem()
|
||||
{
|
||||
int[] metrics = new int[] { 11 };
|
||||
int[] expected = new int[] { 11 };
|
||||
InteractionMetrics<int> interactionMetrics = new InteractionMetrics<int>(metrics);
|
||||
|
||||
Assert.Equal(interactionMetrics.Metrics, expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MetricsCalculateQuantileCorrectlyGivenSeveralUpdates()
|
||||
{
|
||||
int[] metrics = new int[] { 50, 100, 300, 500, 1000, 2000 };
|
||||
Func<string, double, double> updateValueFactory = (k, current) => current + 1;
|
||||
InteractionMetrics<double> interactionMetrics = new InteractionMetrics<double>(metrics);
|
||||
interactionMetrics.UpdateMetrics(54.4, 1, updateValueFactory);
|
||||
interactionMetrics.UpdateMetrics(345, 1, updateValueFactory);
|
||||
interactionMetrics.UpdateMetrics(23, 1, updateValueFactory);
|
||||
interactionMetrics.UpdateMetrics(51, 1, updateValueFactory);
|
||||
interactionMetrics.UpdateMetrics(500, 1, updateValueFactory);
|
||||
interactionMetrics.UpdateMetrics(4005, 1, updateValueFactory);
|
||||
interactionMetrics.UpdateMetrics(2500, 1, updateValueFactory);
|
||||
interactionMetrics.UpdateMetrics(123, 1, updateValueFactory);
|
||||
|
||||
Dictionary<string, double> quantile = interactionMetrics.Quantile;
|
||||
Assert.NotNull(quantile);
|
||||
Assert.Equal(quantile.Count, 5);
|
||||
Assert.Equal(quantile["50"], 1);
|
||||
Assert.Equal(quantile["100"], 2);
|
||||
Assert.Equal(quantile["300"], 1);
|
||||
Assert.Equal(quantile["500"], 2);
|
||||
Assert.Equal(quantile["2000"], 2);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.UnitTests.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.LanguageServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests for the ServiceHost Language Service tests
|
||||
/// </summary>
|
||||
public class LanguageServiceTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Verify that the latest SqlParser (2016 as of this writing) is used by default
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void LatestSqlParserIsUsedByDefault()
|
||||
{
|
||||
// This should only parse correctly on SQL server 2016 or newer
|
||||
const string sql2016Text =
|
||||
@"CREATE SECURITY POLICY [FederatedSecurityPolicy]" + "\r\n" +
|
||||
@"ADD FILTER PREDICATE [rls].[fn_securitypredicate]([CustomerId])" + "\r\n" +
|
||||
@"ON [dbo].[Customer];";
|
||||
|
||||
LanguageService service = TestObjects.GetTestLanguageService();
|
||||
|
||||
// parse
|
||||
var scriptFile = new ScriptFile();
|
||||
scriptFile.SetFileContents(sql2016Text);
|
||||
ScriptFileMarker[] fileMarkers = service.GetSemanticMarkers(scriptFile);
|
||||
|
||||
// verify that no errors are detected
|
||||
Assert.Equal(0, fileMarkers.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that the SQL parser correctly detects errors in text
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ParseSelectStatementWithoutErrors()
|
||||
{
|
||||
// sql statement with no errors
|
||||
const string sqlWithErrors = "SELECT * FROM sys.objects";
|
||||
|
||||
// get the test service
|
||||
LanguageService service = TestObjects.GetTestLanguageService();
|
||||
|
||||
// parse the sql statement
|
||||
var scriptFile = new ScriptFile();
|
||||
scriptFile.SetFileContents(sqlWithErrors);
|
||||
ScriptFileMarker[] fileMarkers = service.GetSemanticMarkers(scriptFile);
|
||||
|
||||
// verify there are no errors
|
||||
Assert.Equal(0, fileMarkers.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that the SQL parser correctly detects errors in text
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ParseSelectStatementWithError()
|
||||
{
|
||||
// sql statement with errors
|
||||
const string sqlWithErrors = "SELECT *** FROM sys.objects";
|
||||
|
||||
// get test service
|
||||
LanguageService service = TestObjects.GetTestLanguageService();
|
||||
|
||||
// parse sql statement
|
||||
var scriptFile = new ScriptFile();
|
||||
scriptFile.SetFileContents(sqlWithErrors);
|
||||
ScriptFileMarker[] fileMarkers = service.GetSemanticMarkers(scriptFile);
|
||||
|
||||
// verify there is one error
|
||||
Assert.Equal(1, fileMarkers.Length);
|
||||
|
||||
// verify the position of the error
|
||||
Assert.Equal(9, fileMarkers[0].ScriptRegion.StartColumnNumber);
|
||||
Assert.Equal(1, fileMarkers[0].ScriptRegion.StartLineNumber);
|
||||
Assert.Equal(10, fileMarkers[0].ScriptRegion.EndColumnNumber);
|
||||
Assert.Equal(1, fileMarkers[0].ScriptRegion.EndLineNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that the SQL parser correctly detects errors in text
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ParseMultilineSqlWithErrors()
|
||||
{
|
||||
// multiline sql with errors
|
||||
const string sqlWithErrors =
|
||||
"SELECT *** FROM sys.objects;\n" +
|
||||
"GO\n" +
|
||||
"SELECT *** FROM sys.objects;\n";
|
||||
|
||||
// get test service
|
||||
LanguageService service = TestObjects.GetTestLanguageService();
|
||||
|
||||
// parse sql
|
||||
var scriptFile = new ScriptFile();
|
||||
scriptFile.SetFileContents(sqlWithErrors);
|
||||
ScriptFileMarker[] fileMarkers = service.GetSemanticMarkers(scriptFile);
|
||||
|
||||
// verify there are two errors
|
||||
Assert.Equal(2, fileMarkers.Length);
|
||||
|
||||
// check position of first error
|
||||
Assert.Equal(9, fileMarkers[0].ScriptRegion.StartColumnNumber);
|
||||
Assert.Equal(1, fileMarkers[0].ScriptRegion.StartLineNumber);
|
||||
Assert.Equal(10, fileMarkers[0].ScriptRegion.EndColumnNumber);
|
||||
Assert.Equal(1, fileMarkers[0].ScriptRegion.EndLineNumber);
|
||||
|
||||
// check position of second error
|
||||
Assert.Equal(9, fileMarkers[1].ScriptRegion.StartColumnNumber);
|
||||
Assert.Equal(3, fileMarkers[1].ScriptRegion.StartLineNumber);
|
||||
Assert.Equal(10, fileMarkers[1].ScriptRegion.EndColumnNumber);
|
||||
Assert.Equal(3, fileMarkers[1].ScriptRegion.EndLineNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that GetSignatureHelp returns null when the provided TextDocumentPosition
|
||||
/// has no associated ScriptParseInfo.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetSignatureHelpReturnsNullIfParseInfoNotInitialized()
|
||||
{
|
||||
// Given service doesn't have parseinfo intialized for a document
|
||||
const string docContent = "SELECT * FROM sys.objects";
|
||||
LanguageService service = TestObjects.GetTestLanguageService();
|
||||
var scriptFile = new ScriptFile();
|
||||
scriptFile.SetFileContents(docContent);
|
||||
|
||||
// When requesting SignatureHelp
|
||||
SignatureHelp signatureHelp = service.GetSignatureHelp(TestObjects.GetTestDocPosition(), scriptFile);
|
||||
|
||||
// Then null is returned as no parse info can be used to find the signature
|
||||
Assert.Null(signatureHelp);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EmptyCompletionListTest()
|
||||
{
|
||||
Assert.Equal(AutoCompleteHelper.EmptyCompletionList.Length, 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetWorkspaceServiceInstanceTest()
|
||||
{
|
||||
AutoCompleteHelper.WorkspaceServiceInstance = null;
|
||||
// workspace will be recreated if it's set to null
|
||||
Assert.NotNull(AutoCompleteHelper.WorkspaceServiceInstance);
|
||||
}
|
||||
|
||||
internal class TestScriptDocumentInfo : ScriptDocumentInfo
|
||||
{
|
||||
public TestScriptDocumentInfo(TextDocumentPosition textDocumentPosition, ScriptFile scriptFile, ScriptParseInfo scriptParseInfo,
|
||||
string tokenText = null)
|
||||
:base(textDocumentPosition, scriptFile, scriptParseInfo)
|
||||
{
|
||||
this.tokenText = string.IsNullOrEmpty(tokenText) ? "doesntmatchanythingintheintellisensedefaultlist" : tokenText;
|
||||
}
|
||||
|
||||
private string tokenText;
|
||||
|
||||
public override string TokenText
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.tokenText;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDefaultCompletionListWithNoMatchesTest()
|
||||
{
|
||||
var scriptFile = new ScriptFile();
|
||||
scriptFile.SetFileContents("koko wants a bananas");
|
||||
|
||||
ScriptParseInfo scriptInfo = new ScriptParseInfo { IsConnected = false };
|
||||
|
||||
var scriptDocumentInfo = new TestScriptDocumentInfo(
|
||||
new TextDocumentPosition()
|
||||
{
|
||||
TextDocument = new TextDocumentIdentifier() { Uri = TestObjects.ScriptUri },
|
||||
Position = new Position() { Line = 0, Character = 0 }
|
||||
}, scriptFile, scriptInfo);
|
||||
|
||||
AutoCompleteHelper.GetDefaultCompletionItems(scriptDocumentInfo, false);
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDefaultCompletionListWithMatchesTest()
|
||||
{
|
||||
var scriptFile = new ScriptFile();
|
||||
scriptFile.SetFileContents("koko wants a bananas");
|
||||
|
||||
ScriptParseInfo scriptInfo = new ScriptParseInfo { IsConnected = false };
|
||||
|
||||
var scriptDocumentInfo = new TestScriptDocumentInfo(
|
||||
new TextDocumentPosition()
|
||||
{
|
||||
TextDocument = new TextDocumentIdentifier() { Uri = TestObjects.ScriptUri },
|
||||
Position = new Position() { Line = 0, Character = 0 }
|
||||
}, scriptFile, scriptInfo, "all");
|
||||
|
||||
CompletionItem[] result = AutoCompleteHelper.GetDefaultCompletionItems(scriptDocumentInfo, false);
|
||||
Assert.Equal(result.Length, 1);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,402 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Binder;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
|
||||
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Parser;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
||||
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
||||
using Microsoft.SqlTools.ServiceLayer.UnitTests.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
|
||||
using Moq;
|
||||
using GlobalCommon = Microsoft.SqlTools.ServiceLayer.Test.Common;
|
||||
using Xunit;
|
||||
using Location = Microsoft.SqlTools.ServiceLayer.Workspace.Contracts.Location;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.LanguageServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests for the language service peek definition/ go to definition feature
|
||||
/// </summary>
|
||||
public class PeekDefinitionTests
|
||||
{
|
||||
private const int TaskTimeout = 30000;
|
||||
|
||||
private readonly string testScriptUri = TestObjects.ScriptUri;
|
||||
|
||||
private readonly string testConnectionKey = "testdbcontextkey";
|
||||
|
||||
private Mock<ConnectedBindingQueue> bindingQueue;
|
||||
|
||||
private Mock<WorkspaceService<SqlToolsSettings>> workspaceService;
|
||||
|
||||
private Mock<RequestContext<Location[]>> requestContext;
|
||||
|
||||
private Mock<IBinder> binder;
|
||||
|
||||
private TextDocumentPosition textDocument;
|
||||
|
||||
private void InitializeTestObjects()
|
||||
{
|
||||
// initial cursor position in the script file
|
||||
textDocument = new TextDocumentPosition
|
||||
{
|
||||
TextDocument = new TextDocumentIdentifier {Uri = this.testScriptUri},
|
||||
Position = new Position
|
||||
{
|
||||
Line = 0,
|
||||
Character = 23
|
||||
}
|
||||
};
|
||||
|
||||
// default settings are stored in the workspace service
|
||||
WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings = new SqlToolsSettings();
|
||||
|
||||
// set up file for returning the query
|
||||
var fileMock = new Mock<ScriptFile>();
|
||||
fileMock.SetupGet(file => file.Contents).Returns(GlobalCommon.Constants.StandardQuery);
|
||||
fileMock.SetupGet(file => file.ClientFilePath).Returns(this.testScriptUri);
|
||||
|
||||
// set up workspace mock
|
||||
workspaceService = new Mock<WorkspaceService<SqlToolsSettings>>();
|
||||
workspaceService.Setup(service => service.Workspace.GetFile(It.IsAny<string>()))
|
||||
.Returns(fileMock.Object);
|
||||
|
||||
// setup binding queue mock
|
||||
bindingQueue = new Mock<ConnectedBindingQueue>();
|
||||
bindingQueue.Setup(q => q.AddConnectionContext(It.IsAny<ConnectionInfo>(), It.IsAny<bool>()))
|
||||
.Returns(this.testConnectionKey);
|
||||
|
||||
// inject mock instances into the Language Service
|
||||
LanguageService.WorkspaceServiceInstance = workspaceService.Object;
|
||||
LanguageService.ConnectionServiceInstance = TestObjects.GetTestConnectionService();
|
||||
ConnectionInfo connectionInfo = TestObjects.GetTestConnectionInfo();
|
||||
LanguageService.ConnectionServiceInstance.OwnerToConnectionMap.Add(this.testScriptUri, connectionInfo);
|
||||
LanguageService.Instance.BindingQueue = bindingQueue.Object;
|
||||
|
||||
// setup the mock for SendResult
|
||||
requestContext = new Mock<RequestContext<Location[]>>();
|
||||
requestContext.Setup(rc => rc.SendResult(It.IsAny<Location[]>()))
|
||||
.Returns(Task.FromResult(0));
|
||||
requestContext.Setup(rc => rc.SendError(It.IsAny<DefinitionError>())).Returns(Task.FromResult(0));;
|
||||
requestContext.Setup(r => r.SendEvent(It.IsAny<EventType<TelemetryParams>>(), It.IsAny<TelemetryParams>())).Returns(Task.FromResult(0));;
|
||||
requestContext.Setup(r => r.SendEvent(It.IsAny<EventType<StatusChangeParams>>(), It.IsAny<StatusChangeParams>())).Returns(Task.FromResult(0));;
|
||||
|
||||
// setup the IBinder mock
|
||||
binder = new Mock<IBinder>();
|
||||
binder.Setup(b => b.Bind(
|
||||
It.IsAny<IEnumerable<ParseResult>>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<BindMode>()));
|
||||
|
||||
var testScriptParseInfo = new ScriptParseInfo();
|
||||
LanguageService.Instance.AddOrUpdateScriptParseInfo(this.testScriptUri, testScriptParseInfo);
|
||||
testScriptParseInfo.IsConnected = false;
|
||||
testScriptParseInfo.ConnectionKey = LanguageService.Instance.BindingQueue.AddConnectionContext(connectionInfo);
|
||||
|
||||
// setup the binding context object
|
||||
ConnectedBindingContext bindingContext = new ConnectedBindingContext();
|
||||
bindingContext.Binder = binder.Object;
|
||||
bindingContext.MetadataDisplayInfoProvider = new MetadataDisplayInfoProvider();
|
||||
LanguageService.Instance.BindingQueue.BindingContextMap.Add(testScriptParseInfo.ConnectionKey, bindingContext);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Tests the definition event handler. When called with no active connection, an error is sent
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task DefinitionsHandlerWithNoConnectionTest()
|
||||
{
|
||||
InitializeTestObjects();
|
||||
// request definition
|
||||
var definitionTask = await Task.WhenAny(LanguageService.HandleDefinitionRequest(textDocument, requestContext.Object), Task.Delay(TaskTimeout));
|
||||
await definitionTask;
|
||||
// verify that send result was not called and send error was called
|
||||
requestContext.Verify(m => m.SendResult(It.IsAny<Location[]>()), Times.Never());
|
||||
requestContext.Verify(m => m.SendError(It.IsAny<DefinitionError>()), Times.Once());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests creating location objects on windows and non-windows systems
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetLocationFromFileForValidFilePathTest()
|
||||
{
|
||||
string filePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "C:\\test\\script.sql" : "/test/script.sql";
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
Location[] locations = peekDefinition.GetLocationFromFile(filePath, 0);
|
||||
|
||||
string expectedFilePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "file:///C:/test/script.sql" : "file:/test/script.sql";
|
||||
Assert.Equal(locations[0].Uri, expectedFilePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test PeekDefinition.GetSchemaFromDatabaseQualifiedName with a valid database name
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetSchemaFromDatabaseQualifiedNameWithValidNameTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string validDatabaseQualifiedName = "master.test.test_table";
|
||||
string objectName = "test_table";
|
||||
string expectedSchemaName = "test";
|
||||
|
||||
string actualSchemaName = peekDefinition.GetSchemaFromDatabaseQualifiedName(validDatabaseQualifiedName, objectName);
|
||||
Assert.Equal(actualSchemaName, expectedSchemaName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test PeekDefinition.GetSchemaFromDatabaseQualifiedName with a valid object name and no schema
|
||||
/// </summary>
|
||||
|
||||
[Fact]
|
||||
public void GetSchemaFromDatabaseQualifiedNameWithNoSchemaTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string validDatabaseQualifiedName = "test_table";
|
||||
string objectName = "test_table";
|
||||
string expectedSchemaName = "dbo";
|
||||
|
||||
string actualSchemaName = peekDefinition.GetSchemaFromDatabaseQualifiedName(validDatabaseQualifiedName, objectName);
|
||||
Assert.Equal(actualSchemaName, expectedSchemaName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test PeekDefinition.GetSchemaFromDatabaseQualifiedName with a invalid database name
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetSchemaFromDatabaseQualifiedNameWithInvalidNameTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string validDatabaseQualifiedName = "x.y.z";
|
||||
string objectName = "test_table";
|
||||
string expectedSchemaName = "dbo";
|
||||
|
||||
string actualSchemaName = peekDefinition.GetSchemaFromDatabaseQualifiedName(validDatabaseQualifiedName, objectName);
|
||||
Assert.Equal(actualSchemaName, expectedSchemaName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test deletion of peek definition scripts for a valid temp folder that exists
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void DeletePeekDefinitionScriptsTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
var languageService = LanguageService.Instance;
|
||||
Assert.True(Directory.Exists(FileUtilities.PeekDefinitionTempFolder));
|
||||
languageService.DeletePeekDefinitionScripts();
|
||||
Assert.False(Directory.Exists(FileUtilities.PeekDefinitionTempFolder));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test deletion of peek definition scripts for a temp folder that does not exist
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void DeletePeekDefinitionScriptsWhenFolderDoesNotExistTest()
|
||||
{
|
||||
var languageService = LanguageService.Instance;
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
FileUtilities.SafeDirectoryDelete(FileUtilities.PeekDefinitionTempFolder, true);
|
||||
Assert.False(Directory.Exists(FileUtilities.PeekDefinitionTempFolder));
|
||||
// Expected not to throw any exception
|
||||
languageService.DeletePeekDefinitionScripts();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test extracting the full object name from quickInfoText.
|
||||
/// Given a valid object name string and a vaild quickInfo string containing the object name
|
||||
/// Expect the full object name (database.schema.objectName)
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetFullObjectNameFromQuickInfoWithValidStringsTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string objectName = "testTable";
|
||||
string quickInfoText = "table master.dbo.testTable";
|
||||
string result = peekDefinition.GetFullObjectNameFromQuickInfo(quickInfoText, objectName, StringComparison.Ordinal);
|
||||
string expected = "master.dbo.testTable";
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test extracting the full object name from quickInfoText with case insensitive comparison.
|
||||
/// Given a valid object name string and a vaild quickInfo string containing the object name
|
||||
/// Expect the full object name (database.schema.objectName)
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetFullObjectNameFromQuickInfoWithValidStringsandIgnoreCaseTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string objectName = "testtable";
|
||||
string quickInfoText = "table master.dbo.testTable";
|
||||
string result = peekDefinition.GetFullObjectNameFromQuickInfo(quickInfoText, objectName, StringComparison.OrdinalIgnoreCase);
|
||||
string expected = "master.dbo.testTable";
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test extracting the full object name from quickInfoText.
|
||||
/// Given a null object name string and a vaild quickInfo string containing the object name( and vice versa)
|
||||
/// Expect null
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetFullObjectNameFromQuickInfoWithNullStringsTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string expected = null;
|
||||
|
||||
string objectName = null;
|
||||
string quickInfoText = "table master.dbo.testTable";
|
||||
string result = peekDefinition.GetFullObjectNameFromQuickInfo(quickInfoText, objectName, StringComparison.Ordinal);
|
||||
Assert.Equal(expected, result);
|
||||
|
||||
quickInfoText = null;
|
||||
objectName = "tableName";
|
||||
result = peekDefinition.GetFullObjectNameFromQuickInfo(quickInfoText, objectName, StringComparison.Ordinal);
|
||||
Assert.Equal(expected, result);
|
||||
|
||||
quickInfoText = null;
|
||||
objectName = null;
|
||||
result = peekDefinition.GetFullObjectNameFromQuickInfo(quickInfoText, objectName, StringComparison.Ordinal);
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test extracting the full object name from quickInfoText.
|
||||
/// Given a valid object name string and a vaild quickInfo string that does not contain the object name
|
||||
/// Expect null
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetFullObjectNameFromQuickInfoWithIncorrectObjectNameTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string objectName = "test";
|
||||
string quickInfoText = "table master.dbo.tableName";
|
||||
string result = peekDefinition.GetFullObjectNameFromQuickInfo(quickInfoText, objectName, StringComparison.Ordinal);
|
||||
string expected = null;
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test extracting the object type from quickInfoText.
|
||||
/// Given a valid object name string and a vaild quickInfo string containing the object name
|
||||
/// Expect correct object type
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetTokenTypeFromQuickInfoWithValidStringsTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string objectName = "tableName";
|
||||
string quickInfoText = "table master.dbo.tableName";
|
||||
string result = peekDefinition.GetTokenTypeFromQuickInfo(quickInfoText, objectName, StringComparison.Ordinal);
|
||||
string expected = "table";
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Test extracting the object type from quickInfoText with case insensitive comparison.
|
||||
/// Given a valid object name string and a vaild quickInfo string containing the object name
|
||||
/// Expect correct object type
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetTokenTypeFromQuickInfoWithValidStringsandIgnoreCaseTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string objectName = "tablename";
|
||||
string quickInfoText = "table master.dbo.tableName";
|
||||
string result = peekDefinition.GetTokenTypeFromQuickInfo(quickInfoText, objectName, StringComparison.OrdinalIgnoreCase);
|
||||
string expected = "table";
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test extracting theobject type from quickInfoText.
|
||||
/// Given a null object name string and a vaild quickInfo string containing the object name( and vice versa)
|
||||
/// Expect null
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetTokenTypeFromQuickInfoWithNullStringsTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string expected = null;
|
||||
|
||||
string objectName = null;
|
||||
string quickInfoText = "table master.dbo.testTable";
|
||||
string result = peekDefinition.GetTokenTypeFromQuickInfo(quickInfoText, objectName, StringComparison.Ordinal);
|
||||
Assert.Equal(expected, result);
|
||||
|
||||
quickInfoText = null;
|
||||
objectName = "tableName";
|
||||
result = peekDefinition.GetTokenTypeFromQuickInfo(quickInfoText, objectName, StringComparison.Ordinal);
|
||||
Assert.Equal(expected, result);
|
||||
|
||||
quickInfoText = null;
|
||||
objectName = null;
|
||||
result = peekDefinition.GetTokenTypeFromQuickInfo(quickInfoText, objectName, StringComparison.Ordinal);
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test extracting the object type from quickInfoText.
|
||||
/// Given a valid object name string and a vaild quickInfo string that does not containthe object name
|
||||
/// Expect null
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetTokenTypeFromQuickInfoWithIncorrectObjectNameTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string objectName = "test";
|
||||
string quickInfoText = "table master.dbo.tableName";
|
||||
string result = peekDefinition.GetTokenTypeFromQuickInfo(quickInfoText, objectName, StringComparison.Ordinal);
|
||||
string expected = null;
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test getting definition using quickInfo text without a live connection
|
||||
/// Expect an error result (because you cannot script without a live connection)
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetDefinitionUsingQuickInfoWithoutConnectionTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string objectName = "tableName";
|
||||
string quickInfoText = "table master.dbo.tableName";
|
||||
DefinitionResult result = peekDefinition.GetDefinitionUsingQuickInfoText(quickInfoText, objectName, null);
|
||||
Assert.NotNull(result);
|
||||
Assert.True(result.IsErrorResult);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test getting definition using declaration Type without a live connection
|
||||
/// Expect an error result (because you cannot script without a live connection)
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetDefinitionUsingDeclarationItemWithoutConnectionTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string objectName = "tableName";
|
||||
string fullObjectName = "master.dbo.tableName";
|
||||
DefinitionResult result = peekDefinition.GetDefinitionUsingDeclarationType(DeclarationType.Table, fullObjectName, objectName, null);
|
||||
Assert.NotNull(result);
|
||||
Assert.True(result.IsErrorResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,617 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.LanguageServer
|
||||
{
|
||||
public class SqlCompletionItemTests
|
||||
{
|
||||
private static readonly string[] ReservedWords = new string[]
|
||||
{
|
||||
"all",
|
||||
"alter",
|
||||
"and",
|
||||
"apply",
|
||||
"as",
|
||||
"asc",
|
||||
"at",
|
||||
"backup",
|
||||
"begin",
|
||||
"binary",
|
||||
"bit",
|
||||
"break",
|
||||
"bulk",
|
||||
"by",
|
||||
"call",
|
||||
"cascade",
|
||||
"case",
|
||||
"catch",
|
||||
"char",
|
||||
"character",
|
||||
"check",
|
||||
"checkpoint",
|
||||
"close",
|
||||
"clustered",
|
||||
"column",
|
||||
"columnstore",
|
||||
"commit",
|
||||
"connect",
|
||||
"constraint",
|
||||
"continue",
|
||||
"create",
|
||||
"cross",
|
||||
"current_date",
|
||||
"cursor",
|
||||
"cursor_close_on_commit",
|
||||
"cursor_default",
|
||||
"data",
|
||||
"data_compression",
|
||||
"database",
|
||||
"date",
|
||||
"datetime",
|
||||
"datetime2",
|
||||
"days",
|
||||
"dbcc",
|
||||
"dec",
|
||||
"decimal",
|
||||
"declare",
|
||||
"default",
|
||||
"delete",
|
||||
"deny",
|
||||
"desc",
|
||||
"description",
|
||||
"disabled",
|
||||
"disk",
|
||||
"distinct",
|
||||
"double",
|
||||
"drop",
|
||||
"drop_existing",
|
||||
"dump",
|
||||
"dynamic",
|
||||
"else",
|
||||
"enable",
|
||||
"encrypted",
|
||||
"end",
|
||||
"end-exec",
|
||||
"exec",
|
||||
"execute",
|
||||
"exists",
|
||||
"exit",
|
||||
"external",
|
||||
"fast_forward",
|
||||
"fetch",
|
||||
"file",
|
||||
"filegroup",
|
||||
"filename",
|
||||
"filestream",
|
||||
"filter",
|
||||
"first",
|
||||
"float",
|
||||
"for",
|
||||
"foreign",
|
||||
"from",
|
||||
"full",
|
||||
"function",
|
||||
"geography",
|
||||
"get",
|
||||
"global",
|
||||
"go",
|
||||
"goto",
|
||||
"grant",
|
||||
"group",
|
||||
"hash",
|
||||
"hashed",
|
||||
"having",
|
||||
"hidden",
|
||||
"hierarchyid",
|
||||
"holdlock",
|
||||
"hours",
|
||||
"identity",
|
||||
"identitycol",
|
||||
"if",
|
||||
"image",
|
||||
"immediate",
|
||||
"include",
|
||||
"index",
|
||||
"inner",
|
||||
"insert",
|
||||
"instead",
|
||||
"int",
|
||||
"integer",
|
||||
"intersect",
|
||||
"into",
|
||||
"isolation",
|
||||
"join",
|
||||
"json",
|
||||
"key",
|
||||
"language",
|
||||
"last",
|
||||
"left",
|
||||
"level",
|
||||
"lineno",
|
||||
"load",
|
||||
"local",
|
||||
"locate",
|
||||
"location",
|
||||
"login",
|
||||
"masked",
|
||||
"maxdop",
|
||||
"merge",
|
||||
"message",
|
||||
"modify",
|
||||
"move",
|
||||
"namespace",
|
||||
"native_compilation",
|
||||
"nchar",
|
||||
"next",
|
||||
"no",
|
||||
"nocheck",
|
||||
"nocount",
|
||||
"nonclustered",
|
||||
"none",
|
||||
"norecompute",
|
||||
"not",
|
||||
"now",
|
||||
"null",
|
||||
"numeric",
|
||||
"object",
|
||||
"of",
|
||||
"off",
|
||||
"offsets",
|
||||
"on",
|
||||
"online",
|
||||
"open",
|
||||
"openrowset",
|
||||
"openxml",
|
||||
"option",
|
||||
"or",
|
||||
"order",
|
||||
"out",
|
||||
"outer",
|
||||
"output",
|
||||
"over",
|
||||
"owner",
|
||||
"partial",
|
||||
"partition",
|
||||
"password",
|
||||
"path",
|
||||
"percent",
|
||||
"percentage",
|
||||
"period",
|
||||
"persisted",
|
||||
"plan",
|
||||
"policy",
|
||||
"precision",
|
||||
"predicate",
|
||||
"primary",
|
||||
"print",
|
||||
"prior",
|
||||
"proc",
|
||||
"procedure",
|
||||
"public",
|
||||
"query_store",
|
||||
"quoted_identifier",
|
||||
"raiserror",
|
||||
"range",
|
||||
"raw",
|
||||
"read",
|
||||
"read_committed_snapshot",
|
||||
"read_only",
|
||||
"read_write",
|
||||
"readonly",
|
||||
"readtext",
|
||||
"real",
|
||||
"rebuild",
|
||||
"receive",
|
||||
"reconfigure",
|
||||
"recovery",
|
||||
"recursive",
|
||||
"recursive_triggers",
|
||||
"references",
|
||||
"relative",
|
||||
"remove",
|
||||
"reorganize",
|
||||
"required",
|
||||
"restart",
|
||||
"restore",
|
||||
"restrict",
|
||||
"resume",
|
||||
"return",
|
||||
"returns",
|
||||
"revert",
|
||||
"revoke",
|
||||
"rollback",
|
||||
"rollup",
|
||||
"row",
|
||||
"rowcount",
|
||||
"rowguidcol",
|
||||
"rows",
|
||||
"rule",
|
||||
"sample",
|
||||
"save",
|
||||
"schema",
|
||||
"schemabinding",
|
||||
"scoped",
|
||||
"scroll",
|
||||
"secondary",
|
||||
"security",
|
||||
"select",
|
||||
"send",
|
||||
"sent",
|
||||
"sequence",
|
||||
"server",
|
||||
"session",
|
||||
"set",
|
||||
"sets",
|
||||
"setuser",
|
||||
"simple",
|
||||
"smallint",
|
||||
"smallmoney",
|
||||
"snapshot",
|
||||
"sql",
|
||||
"standard",
|
||||
"start",
|
||||
"started",
|
||||
"state",
|
||||
"statement",
|
||||
"static",
|
||||
"statistics",
|
||||
"statistics_norecompute",
|
||||
"status",
|
||||
"stopped",
|
||||
"sysname",
|
||||
"system",
|
||||
"system_time",
|
||||
"table",
|
||||
"take",
|
||||
"target",
|
||||
"then",
|
||||
"throw",
|
||||
"time",
|
||||
"timestamp",
|
||||
"tinyint",
|
||||
"to",
|
||||
"top",
|
||||
"tran",
|
||||
"transaction",
|
||||
"trigger",
|
||||
"truncate",
|
||||
"try",
|
||||
"tsql",
|
||||
"type",
|
||||
"uncommitted",
|
||||
"union",
|
||||
"unique",
|
||||
"uniqueidentifier",
|
||||
"updatetext",
|
||||
"use",
|
||||
"user",
|
||||
"using",
|
||||
"value",
|
||||
"values",
|
||||
"varchar",
|
||||
"version",
|
||||
"view",
|
||||
"waitfor",
|
||||
"when",
|
||||
"where",
|
||||
"while",
|
||||
"with",
|
||||
"within",
|
||||
"without",
|
||||
"writetext",
|
||||
"xact_abort",
|
||||
"xml",
|
||||
};
|
||||
|
||||
[Fact]
|
||||
public void InsertTextShouldIncludeBracketGivenNameWithSpace()
|
||||
{
|
||||
string declarationTitle = "name with space";
|
||||
string expected = "[" + declarationTitle + "]";
|
||||
|
||||
DeclarationType declarationType = DeclarationType.Table;
|
||||
string tokenText = "";
|
||||
SqlCompletionItem item = new SqlCompletionItem(declarationTitle, declarationType, tokenText);
|
||||
CompletionItem completionItem = item.CreateCompletionItem(0, 1, 2);
|
||||
|
||||
Assert.True(completionItem.InsertText.StartsWith("[") && completionItem.InsertText.EndsWith("]"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConstructorShouldThrowExceptionGivenEmptyDeclarionType()
|
||||
{
|
||||
string declarationTitle = "";
|
||||
DeclarationType declarationType = DeclarationType.Table;
|
||||
string tokenText = "";
|
||||
Assert.Throws<ArgumentException>(() => new SqlCompletionItem(declarationTitle, declarationType, tokenText));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConstructorShouldThrowExceptionGivenNullDeclarion()
|
||||
{
|
||||
string tokenText = "";
|
||||
Assert.Throws<ArgumentException>(() => new SqlCompletionItem(null, tokenText));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InsertTextShouldIncludeBracketGivenNameWithSpecialCharacter()
|
||||
{
|
||||
string declarationTitle = "name @";
|
||||
string expected = "[" + declarationTitle + "]";
|
||||
DeclarationType declarationType = DeclarationType.Table;
|
||||
string tokenText = "";
|
||||
SqlCompletionItem item = new SqlCompletionItem(declarationTitle, declarationType, tokenText);
|
||||
CompletionItem completionItem = item.CreateCompletionItem(0, 1, 2);
|
||||
|
||||
Assert.Equal(completionItem.InsertText, expected);
|
||||
Assert.Equal(completionItem.Detail, declarationTitle);
|
||||
Assert.Equal(completionItem.Label, declarationTitle);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LabelShouldIncludeBracketGivenTokenWithBracket()
|
||||
{
|
||||
string declarationTitle = "name";
|
||||
string expected = "[" + declarationTitle + "]";
|
||||
DeclarationType declarationType = DeclarationType.Table;
|
||||
string tokenText = "[";
|
||||
SqlCompletionItem item = new SqlCompletionItem(declarationTitle, declarationType, tokenText);
|
||||
CompletionItem completionItem = item.CreateCompletionItem(0, 1, 2);
|
||||
|
||||
Assert.Equal(completionItem.Label, expected);
|
||||
Assert.Equal(completionItem.InsertText, expected);
|
||||
Assert.Equal(completionItem.Detail, expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LabelShouldIncludeBracketGivenTokenWithBrackets()
|
||||
{
|
||||
string declarationTitle = "name";
|
||||
string expected = "[" + declarationTitle + "]";
|
||||
DeclarationType declarationType = DeclarationType.Table;
|
||||
string tokenText = "[]";
|
||||
SqlCompletionItem item = new SqlCompletionItem(declarationTitle, declarationType, tokenText);
|
||||
CompletionItem completionItem = item.CreateCompletionItem(0, 1, 2);
|
||||
|
||||
Assert.Equal(completionItem.Label, expected);
|
||||
Assert.Equal(completionItem.InsertText, expected);
|
||||
Assert.Equal(completionItem.Detail, expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LabelShouldIncludeBracketGivenSqlObjectNameWithBracket()
|
||||
{
|
||||
string declarationTitle = @"Bracket\[";
|
||||
string expected = "[" + declarationTitle + "]";
|
||||
DeclarationType declarationType = DeclarationType.Table;
|
||||
string tokenText = "";
|
||||
SqlCompletionItem item = new SqlCompletionItem(declarationTitle, declarationType, tokenText);
|
||||
CompletionItem completionItem = item.CreateCompletionItem(0, 1, 2);
|
||||
|
||||
Assert.Equal(completionItem.Label, declarationTitle);
|
||||
Assert.Equal(completionItem.InsertText, expected);
|
||||
Assert.Equal(completionItem.Detail, declarationTitle);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LabelShouldIncludeBracketGivenSqlObjectNameWithBracketAndTokenWithBracket()
|
||||
{
|
||||
string declarationTitle = @"Bracket\[";
|
||||
string expected = "[" + declarationTitle + "]";
|
||||
DeclarationType declarationType = DeclarationType.Table;
|
||||
string tokenText = "[]";
|
||||
SqlCompletionItem item = new SqlCompletionItem(declarationTitle, declarationType, tokenText);
|
||||
CompletionItem completionItem = item.CreateCompletionItem(0, 1, 2);
|
||||
|
||||
Assert.Equal(completionItem.Label, expected);
|
||||
Assert.Equal(completionItem.InsertText, expected);
|
||||
Assert.Equal(completionItem.Detail, expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LabelShouldNotIncludeBracketGivenNameWithBrackets()
|
||||
{
|
||||
string declarationTitle = "[name]";
|
||||
string expected = declarationTitle;
|
||||
DeclarationType declarationType = DeclarationType.Table;
|
||||
string tokenText = "[]";
|
||||
SqlCompletionItem item = new SqlCompletionItem(declarationTitle, declarationType, tokenText);
|
||||
CompletionItem completionItem = item.CreateCompletionItem(0, 1, 2);
|
||||
|
||||
Assert.Equal(completionItem.Label, expected);
|
||||
Assert.Equal(completionItem.InsertText, expected);
|
||||
Assert.Equal(completionItem.Detail, expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LabelShouldIncludeBracketGivenNameWithOneBracket()
|
||||
{
|
||||
string declarationTitle = "[name";
|
||||
string expected = "[" + declarationTitle + "]";
|
||||
DeclarationType declarationType = DeclarationType.Table;
|
||||
string tokenText = "[]";
|
||||
SqlCompletionItem item = new SqlCompletionItem(declarationTitle, declarationType, tokenText);
|
||||
CompletionItem completionItem = item.CreateCompletionItem(0, 1, 2);
|
||||
|
||||
Assert.Equal(completionItem.Label, expected);
|
||||
Assert.Equal(completionItem.InsertText, expected);
|
||||
Assert.Equal(completionItem.Detail, expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LabelShouldIncludeQuotedIdentifiersGivenTokenWithQuotedIdentifier()
|
||||
{
|
||||
string declarationTitle = "name";
|
||||
string expected = "\"" + declarationTitle + "\"";
|
||||
DeclarationType declarationType = DeclarationType.Table;
|
||||
string tokenText = "\"";
|
||||
SqlCompletionItem item = new SqlCompletionItem(declarationTitle, declarationType, tokenText);
|
||||
CompletionItem completionItem = item.CreateCompletionItem(0, 1, 2);
|
||||
|
||||
Assert.Equal(completionItem.Label, expected);
|
||||
Assert.Equal(completionItem.InsertText, expected);
|
||||
Assert.Equal(completionItem.Detail, expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LabelShouldIncludeQuotedIdentifiersGivenTokenWithQuotedIdentifiers()
|
||||
{
|
||||
string declarationTitle = "name";
|
||||
string expected = "\"" + declarationTitle + "\"";
|
||||
DeclarationType declarationType = DeclarationType.Table;
|
||||
string tokenText = "\"\"";
|
||||
SqlCompletionItem item = new SqlCompletionItem(declarationTitle, declarationType, tokenText);
|
||||
CompletionItem completionItem = item.CreateCompletionItem(0, 1, 2);
|
||||
|
||||
Assert.Equal(completionItem.Label, expected);
|
||||
Assert.Equal(completionItem.InsertText, expected);
|
||||
Assert.Equal(completionItem.Detail, expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InsertTextShouldIncludeBracketGivenReservedName()
|
||||
{
|
||||
foreach (string word in ReservedWords)
|
||||
{
|
||||
string declarationTitle = word;
|
||||
string expected = "[" + declarationTitle + "]";
|
||||
DeclarationType declarationType = DeclarationType.Table;
|
||||
string tokenText = "";
|
||||
SqlCompletionItem item = new SqlCompletionItem(declarationTitle, declarationType, tokenText);
|
||||
CompletionItem completionItem = item.CreateCompletionItem(0, 1, 2);
|
||||
|
||||
Assert.Equal(completionItem.Label, word);
|
||||
Assert.Equal(completionItem.InsertText, expected);
|
||||
Assert.Equal(completionItem.Detail, word);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LabelShouldNotIncludeBracketIfTokenIncludesQuotedIdentifiersGivenReservedName()
|
||||
{
|
||||
string declarationTitle = "User";
|
||||
string expected = "\"" + declarationTitle + "\"";
|
||||
DeclarationType declarationType = DeclarationType.Table;
|
||||
string tokenText = "\"";
|
||||
SqlCompletionItem item = new SqlCompletionItem(declarationTitle, declarationType, tokenText);
|
||||
CompletionItem completionItem = item.CreateCompletionItem(0, 1, 2);
|
||||
|
||||
Assert.Equal(completionItem.Label, expected);
|
||||
Assert.Equal(completionItem.InsertText, expected);
|
||||
Assert.Equal(completionItem.Detail, expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LabelShouldNotIncludeDoubleBracketIfTokenIncludesBracketsGivenReservedName()
|
||||
{
|
||||
string declarationTitle = "User";
|
||||
string expected = "[" + declarationTitle + "]";
|
||||
DeclarationType declarationType = DeclarationType.Table;
|
||||
string tokenText = "[";
|
||||
SqlCompletionItem item = new SqlCompletionItem(declarationTitle, declarationType, tokenText);
|
||||
CompletionItem completionItem = item.CreateCompletionItem(0, 1, 2);
|
||||
|
||||
Assert.Equal(completionItem.Label, expected);
|
||||
Assert.Equal(completionItem.InsertText, expected);
|
||||
Assert.Equal(completionItem.Detail, expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TempTablesShouldNotBeEscaped()
|
||||
{
|
||||
string declarationTitle = "#TestTable";
|
||||
string expected = declarationTitle;
|
||||
DeclarationType declarationType = DeclarationType.Table;
|
||||
string tokenText = "";
|
||||
SqlCompletionItem item = new SqlCompletionItem(declarationTitle, declarationType, tokenText);
|
||||
CompletionItem completionItem = item.CreateCompletionItem(0, 1, 2);
|
||||
|
||||
Assert.Equal(completionItem.Label, expected);
|
||||
Assert.Equal(completionItem.InsertText, expected);
|
||||
Assert.Equal(completionItem.Detail, expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void KindShouldBeModuleGivenSchemaDeclarationType()
|
||||
{
|
||||
CompletionItemKind expectedType = CompletionItemKind.Module;
|
||||
DeclarationType declarationType = DeclarationType.Schema;
|
||||
ValidateDeclarationType(declarationType, expectedType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void KindShouldBeFieldGivenColumnDeclarationType()
|
||||
{
|
||||
CompletionItemKind expectedType = CompletionItemKind.Field;
|
||||
DeclarationType declarationType = DeclarationType.Column;
|
||||
ValidateDeclarationType(declarationType, expectedType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void KindShouldBeFileGivenTableDeclarationType()
|
||||
{
|
||||
CompletionItemKind expectedType = CompletionItemKind.File;
|
||||
DeclarationType declarationType = DeclarationType.Table;
|
||||
ValidateDeclarationType(declarationType, expectedType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void KindShouldBeFileGivenViewDeclarationType()
|
||||
{
|
||||
CompletionItemKind expectedType = CompletionItemKind.File;
|
||||
DeclarationType declarationType = DeclarationType.View;
|
||||
ValidateDeclarationType(declarationType, expectedType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void KindShouldBeMethodGivenDatabaseDeclarationType()
|
||||
{
|
||||
CompletionItemKind expectedType = CompletionItemKind.Method;
|
||||
DeclarationType declarationType = DeclarationType.Database;
|
||||
ValidateDeclarationType(declarationType, expectedType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void KindShouldBeValueGivenScalarValuedFunctionDeclarationType()
|
||||
{
|
||||
CompletionItemKind expectedType = CompletionItemKind.Value;
|
||||
DeclarationType declarationType = DeclarationType.ScalarValuedFunction;
|
||||
ValidateDeclarationType(declarationType, expectedType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void KindShouldBeValueGivenTableValuedFunctionDeclarationType()
|
||||
{
|
||||
CompletionItemKind expectedType = CompletionItemKind.Value;
|
||||
DeclarationType declarationType = DeclarationType.TableValuedFunction;
|
||||
ValidateDeclarationType(declarationType, expectedType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void KindShouldBeUnitGivenUnknownDeclarationType()
|
||||
{
|
||||
CompletionItemKind expectedType = CompletionItemKind.Unit;
|
||||
DeclarationType declarationType = DeclarationType.XmlIndex;
|
||||
ValidateDeclarationType(declarationType, expectedType);
|
||||
}
|
||||
|
||||
private void ValidateDeclarationType(DeclarationType declarationType, CompletionItemKind expectedType)
|
||||
{
|
||||
string declarationTitle = "name";
|
||||
string tokenText = "";
|
||||
SqlCompletionItem item = new SqlCompletionItem(declarationTitle, declarationType, tokenText);
|
||||
CompletionItem completionItem = item.CreateCompletionItem(0, 1, 2);
|
||||
|
||||
|
||||
Assert.Equal(completionItem.Kind, expectedType);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user