Files
sqltoolsservice/test/Microsoft.SqlTools.ServiceLayer.UnitTests/LanguageServer/LanguageServiceTests.cs
2023-04-18 20:57:13 -07:00

215 lines
8.3 KiB
C#

//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
#nullable disable
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 NUnit.Framework;
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>
[Test]
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.AreEqual(0, fileMarkers.Length);
}
/// <summary>
/// Verify that the SQL parser correctly detects errors in text
/// </summary>
[Test]
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.AreEqual(0, fileMarkers.Length);
}
/// <summary>
/// Verify that the SQL parser correctly detects errors in text
/// </summary>
[Test]
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.AreEqual(1, fileMarkers.Length);
// verify the position of the error
Assert.AreEqual(9, fileMarkers[0].ScriptRegion.StartColumnNumber);
Assert.AreEqual(1, fileMarkers[0].ScriptRegion.StartLineNumber);
Assert.AreEqual(10, fileMarkers[0].ScriptRegion.EndColumnNumber);
Assert.AreEqual(1, fileMarkers[0].ScriptRegion.EndLineNumber);
}
/// <summary>
/// Verify that the SQL parser correctly detects errors in text
/// </summary>
[Test]
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.AreEqual(2, fileMarkers.Length);
// check position of first error
Assert.AreEqual(9, fileMarkers[0].ScriptRegion.StartColumnNumber);
Assert.AreEqual(1, fileMarkers[0].ScriptRegion.StartLineNumber);
Assert.AreEqual(10, fileMarkers[0].ScriptRegion.EndColumnNumber);
Assert.AreEqual(1, fileMarkers[0].ScriptRegion.EndLineNumber);
// check position of second error
Assert.AreEqual(9, fileMarkers[1].ScriptRegion.StartColumnNumber);
Assert.AreEqual(3, fileMarkers[1].ScriptRegion.StartLineNumber);
Assert.AreEqual(10, fileMarkers[1].ScriptRegion.EndColumnNumber);
Assert.AreEqual(3, fileMarkers[1].ScriptRegion.EndLineNumber);
}
/// <summary>
/// Verify that GetSignatureHelp returns null when the provided TextDocumentPosition
/// has no associated ScriptParseInfo.
/// </summary>
[Test]
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);
}
[Test]
public void EmptyCompletionListTest()
{
Assert.AreEqual(0, AutoCompleteHelper.EmptyCompletionList.Length);
}
internal sealed 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;
}
}
}
[Test]
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);
}
[Test]
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.AreEqual(1, result.Length);
}
}
}