Add additional test cases (#125)

Test-only changes for code coverage.  Please review the comment and I'll include the changes in the next iteration.

* Add more tests

* Add some more additional test cases
This commit is contained in:
Karl Burtram
2016-10-28 20:33:32 -07:00
committed by GitHub
parent 931235c604
commit f46fc0c787
9 changed files with 732 additions and 106 deletions

View File

@@ -94,15 +94,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
private set;
}
/// <summary>
/// Gets the array of filepaths dot sourced in this ScriptFile
/// </summary>
public string[] ReferencedFiles
{
get;
private set;
}
#endregion
#region Constructors
@@ -299,9 +290,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
this.FileLines.Insert(currentLineNumber - 1, finalLine);
currentLineNumber++;
}
// Parse the script again to be up-to-date
this.ParseFileContents();
}
/// <summary>
@@ -447,97 +435,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
.Split('\n')
.Select(line => line.TrimEnd('\r'))
.ToList();
// Parse the contents to get syntax tree and errors
this.ParseFileContents();
}
#endregion
#region Private Methods
/// <summary>
/// Parses the current file contents to get the AST, tokens,
/// and parse errors.
/// </summary>
private void ParseFileContents()
{
#if false
ParseError[] parseErrors = null;
// First, get the updated file range
int lineCount = this.FileLines.Count;
if (lineCount > 0)
{
this.FileRange =
new BufferRange(
new BufferPosition(1, 1),
new BufferPosition(
lineCount + 1,
this.FileLines[lineCount - 1].Length + 1));
}
else
{
this.FileRange = BufferRange.None;
}
try
{
#if SqlToolsv5r2
// This overload appeared with Windows 10 Update 1
if (this.SqlToolsVersion.Major >= 5 &&
this.SqlToolsVersion.Build >= 10586)
{
// Include the file path so that module relative
// paths are evaluated correctly
this.ScriptAst =
Parser.ParseInput(
this.Contents,
this.FilePath,
out this.scriptTokens,
out parseErrors);
}
else
{
this.ScriptAst =
Parser.ParseInput(
this.Contents,
out this.scriptTokens,
out parseErrors);
}
#else
this.ScriptAst =
Parser.ParseInput(
this.Contents,
out this.scriptTokens,
out parseErrors);
#endif
}
catch (RuntimeException ex)
{
var parseError =
new ParseError(
null,
ex.ErrorRecord.FullyQualifiedErrorId,
ex.Message);
parseErrors = new[] { parseError };
this.scriptTokens = new Token[0];
this.ScriptAst = null;
}
// Translate parse errors into syntax markers
this.SyntaxMarkers =
parseErrors
.Select(ScriptFileMarker.FromParseError)
.ToArray();
//Get all dot sourced referenced files and store them
this.ReferencedFiles =
AstOperations.FindDotSourcedIncludes(this.ScriptAst);
#endif
}
#endregion
}
}

View File

@@ -0,0 +1,49 @@
//
// 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.Threading;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Utility;
using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.Test.ServiceHost
{
public class AsyncLockTests
{
[Fact]
public async Task AsyncLockSynchronizesAccess()
{
AsyncLock asyncLock = new AsyncLock();
Task<IDisposable> lockOne = asyncLock.LockAsync();
Task<IDisposable> lockTwo = asyncLock.LockAsync();
Assert.Equal(TaskStatus.RanToCompletion, lockOne.Status);
Assert.Equal(TaskStatus.WaitingForActivation, lockTwo.Status);
lockOne.Result.Dispose();
await lockTwo;
Assert.Equal(TaskStatus.RanToCompletion, lockTwo.Status);
}
[Fact]
public void AsyncLockCancelsWhenRequested()
{
CancellationTokenSource cts = new CancellationTokenSource();
AsyncLock asyncLock = new AsyncLock();
Task<IDisposable> lockOne = asyncLock.LockAsync();
Task<IDisposable> lockTwo = asyncLock.LockAsync(cts.Token);
// Cancel the second lock before the first is released
cts.Cancel();
lockOne.Result.Dispose();
Assert.Equal(TaskStatus.RanToCompletion, lockOne.Status);
Assert.Equal(TaskStatus.Canceled, lockTwo.Status);
}
}
}

View File

@@ -0,0 +1,91 @@
//
// 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.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Utility;
using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.Test.ServiceHost
{
public class AsyncQueueTests
{
[Fact]
public async Task AsyncQueueSynchronizesAccess()
{
ConcurrentBag<int> outputItems = new ConcurrentBag<int>();
AsyncQueue<int> inputQueue = new AsyncQueue<int>(Enumerable.Range(0, 100));
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
try
{
// Start 5 consumers
await Task.WhenAll(
Task.Run(() => ConsumeItems(inputQueue, outputItems, cancellationTokenSource.Token)),
Task.Run(() => ConsumeItems(inputQueue, outputItems, cancellationTokenSource.Token)),
Task.Run(() => ConsumeItems(inputQueue, outputItems, cancellationTokenSource.Token)),
Task.Run(() => ConsumeItems(inputQueue, outputItems, cancellationTokenSource.Token)),
Task.Run(() => ConsumeItems(inputQueue, outputItems, cancellationTokenSource.Token)),
Task.Run(
async () =>
{
// Wait for a bit and then add more items to the queue
await Task.Delay(250);
foreach (var i in Enumerable.Range(100, 200))
{
await inputQueue.EnqueueAsync(i);
}
// Cancel the waiters
cancellationTokenSource.Cancel();
}));
}
catch (TaskCanceledException)
{
// Do nothing, this is expected.
}
// At this point, numbers 0 through 299 should be in the outputItems
IEnumerable<int> expectedItems = Enumerable.Range(0, 300);
Assert.Equal(0, expectedItems.Except(outputItems).Count());
}
[Fact]
public async Task AsyncQueueSkipsCancelledTasks()
{
AsyncQueue<int> inputQueue = new AsyncQueue<int>();
// Queue up a couple of tasks to wait for input
CancellationTokenSource cancellationSource = new CancellationTokenSource();
Task<int> taskOne = inputQueue.DequeueAsync(cancellationSource.Token);
Task<int> taskTwo = inputQueue.DequeueAsync();
// Cancel the first task and then enqueue a number
cancellationSource.Cancel();
await inputQueue.EnqueueAsync(1);
// Did the second task get the number?
Assert.Equal(TaskStatus.Canceled, taskOne.Status);
Assert.Equal(TaskStatus.RanToCompletion, taskTwo.Status);
Assert.Equal(1, taskTwo.Result);
}
private async Task ConsumeItems(
AsyncQueue<int> inputQueue,
ConcurrentBag<int> outputItems,
CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
int consumedItem = await inputQueue.DequeueAsync(cancellationToken);
outputItems.Add(consumedItem);
}
}
}
}

View File

@@ -0,0 +1,502 @@
//
// 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.IO;
using System.Linq;
using Microsoft.SqlTools.ServiceLayer.Utility;
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.Test.ServiceHost
{
/// <summary>
/// ScriptFile test case
/// </summary>
public class ScriptFileTests
{
internal static object fileLock = new object();
private static readonly string query =
"SELECT * FROM sys.objects as o1" + Environment.NewLine +
"SELECT * FROM sys.objects as o2" + Environment.NewLine +
"SELECT * FROM sys.objects as o3" + Environment.NewLine;
internal static ScriptFile GetTestScriptFile(string initialText = null)
{
if (initialText == null)
{
initialText = ScriptFileTests.query;
}
string ownerUri = System.IO.Path.GetTempFileName();
// Write the query text to a backing file
lock (fileLock)
{
System.IO.File.WriteAllText(ownerUri, initialText);
}
return new ScriptFile(ownerUri, ownerUri, initialText);
}
/// <summary>
/// Validate GetLinesInRange with invalid range
/// </summary>
[Fact]
public void GetLinesInRangeWithInvalidRangeTest()
{
ScriptFile scriptFile = GetTestScriptFile();
bool exceptionRaised = false;
try
{
scriptFile.GetLinesInRange(
new BufferRange(
new BufferPosition(1, 0),
new BufferPosition(2, 0)));
}
catch (ArgumentOutOfRangeException)
{
exceptionRaised = true;
}
Assert.True(exceptionRaised, "ArgumentOutOfRangeException raised for invalid index");
}
/// <summary>
/// Validate GetLinesInRange
/// </summary>
[Fact]
public void GetLinesInRangeTest()
{
ScriptFile scriptFile = GetTestScriptFile();
string id = scriptFile.Id;
Assert.True(!string.IsNullOrWhiteSpace(id));
BufferRange range =scriptFile.FileRange;
Assert.Null(range);
string[] lines = scriptFile.GetLinesInRange(
new BufferRange(
new BufferPosition(2, 1),
new BufferPosition(2, 7)));
Assert.True(lines.Length == 1, "One line in range");
Assert.True(lines[0].Equals("SELECT"), "Range text is correct");
string[] queryLines = query.Split('\n');
string line = scriptFile.GetLine(2);
Assert.True(queryLines[1].StartsWith(line), "GetLine text is correct");
}
[Fact]
public void GetOffsetAtPositionTest()
{
ScriptFile scriptFile = GetTestScriptFile();
int offset = scriptFile.GetOffsetAtPosition(2, 5);
Assert.True(offset == 37, "Offset is at expected location");
BufferPosition position = scriptFile.GetPositionAtOffset(offset);
Assert.True(position.Line == 2 && position.Column == 5, "Position is at expected location");
}
[Fact]
public void GetRangeBetweenOffsetsTest()
{
ScriptFile scriptFile = GetTestScriptFile();
BufferRange range = scriptFile.GetRangeBetweenOffsets(
scriptFile.GetOffsetAtPosition(2, 1),
scriptFile.GetOffsetAtPosition(2, 7));
Assert.NotNull(range);
}
[Fact]
public void CanApplySingleLineInsert()
{
this.AssertFileChange(
"This is a test.",
"This is a working test.",
new FileChange
{
Line = 1,
EndLine = 1,
Offset = 10,
EndOffset = 10,
InsertString = " working"
});
}
[Fact]
public void CanApplySingleLineReplace()
{
this.AssertFileChange(
"This is a potentially broken test.",
"This is a working test.",
new FileChange
{
Line = 1,
EndLine = 1,
Offset = 11,
EndOffset = 29,
InsertString = "working"
});
}
[Fact]
public void CanApplySingleLineDelete()
{
this.AssertFileChange(
"This is a test of the emergency broadcasting system.",
"This is a test.",
new FileChange
{
Line = 1,
EndLine = 1,
Offset = 15,
EndOffset = 52,
InsertString = ""
});
}
[Fact]
public void CanApplyMultiLineInsert()
{
this.AssertFileChange(
"first\r\nsecond\r\nfifth",
"first\r\nsecond\r\nthird\r\nfourth\r\nfifth",
new FileChange
{
Line = 3,
EndLine = 3,
Offset = 1,
EndOffset = 1,
InsertString = "third\r\nfourth\r\n"
});
}
[Fact]
public void CanApplyMultiLineReplace()
{
this.AssertFileChange(
"first\r\nsecoXX\r\nXXfth",
"first\r\nsecond\r\nthird\r\nfourth\r\nfifth",
new FileChange
{
Line = 2,
EndLine = 3,
Offset = 5,
EndOffset = 3,
InsertString = "nd\r\nthird\r\nfourth\r\nfi"
});
}
[Fact]
public void CanApplyMultiLineReplaceWithRemovedLines()
{
this.AssertFileChange(
"first\r\nsecoXX\r\nREMOVE\r\nTHESE\r\nLINES\r\nXXfth",
"first\r\nsecond\r\nthird\r\nfourth\r\nfifth",
new FileChange
{
Line = 2,
EndLine = 6,
Offset = 5,
EndOffset = 3,
InsertString = "nd\r\nthird\r\nfourth\r\nfi"
});
}
[Fact]
public void CanApplyMultiLineDelete()
{
this.AssertFileChange(
"first\r\nsecond\r\nREMOVE\r\nTHESE\r\nLINES\r\nthird",
"first\r\nsecond\r\nthird",
new FileChange
{
Line = 3,
EndLine = 6,
Offset = 1,
EndOffset = 1,
InsertString = ""
});
}
[Fact]
public void ThrowsExceptionWithEditOutsideOfRange()
{
Assert.Throws(
typeof(ArgumentOutOfRangeException),
() =>
{
this.AssertFileChange(
"first\r\nsecond\r\nREMOVE\r\nTHESE\r\nLINES\r\nthird",
"first\r\nsecond\r\nthird",
new FileChange
{
Line = 3,
EndLine = 7,
Offset = 1,
EndOffset = 1,
InsertString = ""
});
});
}
private void AssertFileChange(
string initialString,
string expectedString,
FileChange fileChange)
{
// Create an in-memory file from the StringReader
ScriptFile fileToChange = GetTestScriptFile(initialString);
// Apply the FileChange and assert the resulting contents
fileToChange.ApplyChange(fileChange);
Assert.Equal(expectedString, fileToChange.Contents);
}
}
public class ScriptFileGetLinesTests
{
private ScriptFile scriptFile;
private const string TestString = "Line One\r\nLine Two\r\nLine Three\r\nLine Four\r\nLine Five";
private readonly string[] TestStringLines =
TestString.Split(
new string[] { "\r\n" },
StringSplitOptions.None);
public ScriptFileGetLinesTests()
{
this.scriptFile =
ScriptFileTests.GetTestScriptFile(
"Line One\r\nLine Two\r\nLine Three\r\nLine Four\r\nLine Five\r\n");
}
[Fact]
public void CanGetWholeLine()
{
string[] lines =
this.scriptFile.GetLinesInRange(
new BufferRange(5, 1, 5, 10));
Assert.Equal(1, lines.Length);
Assert.Equal("Line Five", lines[0]);
}
[Fact]
public void CanGetMultipleWholeLines()
{
string[] lines =
this.scriptFile.GetLinesInRange(
new BufferRange(2, 1, 4, 10));
Assert.Equal(TestStringLines.Skip(1).Take(3), lines);
}
[Fact]
public void CanGetSubstringInSingleLine()
{
string[] lines =
this.scriptFile.GetLinesInRange(
new BufferRange(4, 3, 4, 8));
Assert.Equal(1, lines.Length);
Assert.Equal("ne Fo", lines[0]);
}
[Fact]
public void CanGetEmptySubstringRange()
{
string[] lines =
this.scriptFile.GetLinesInRange(
new BufferRange(4, 3, 4, 3));
Assert.Equal(1, lines.Length);
Assert.Equal("", lines[0]);
}
[Fact]
public void CanGetSubstringInMultipleLines()
{
string[] expectedLines = new string[]
{
"Two",
"Line Three",
"Line Fou"
};
string[] lines =
this.scriptFile.GetLinesInRange(
new BufferRange(2, 6, 4, 9));
Assert.Equal(expectedLines, lines);
}
[Fact]
public void CanGetRangeAtLineBoundaries()
{
string[] expectedLines = new string[]
{
"",
"Line Three",
""
};
string[] lines =
this.scriptFile.GetLinesInRange(
new BufferRange(2, 9, 4, 1));
Assert.Equal(expectedLines, lines);
}
}
public class ScriptFilePositionTests
{
private ScriptFile scriptFile;
public ScriptFilePositionTests()
{
this.scriptFile =
ScriptFileTests.GetTestScriptFile(@"
First line
Second line is longer
Third line
");
}
[Fact]
public void CanOffsetByLine()
{
this.AssertNewPosition(
1, 1,
2, 0,
3, 1);
this.AssertNewPosition(
3, 1,
-2, 0,
1, 1);
}
[Fact]
public void CanOffsetByColumn()
{
this.AssertNewPosition(
2, 1,
0, 2,
2, 3);
this.AssertNewPosition(
2, 5,
0, -3,
2, 2);
}
[Fact]
public void ThrowsWhenPositionOutOfRange()
{
// Less than line range
Assert.Throws(
typeof(ArgumentOutOfRangeException),
() =>
{
scriptFile.CalculatePosition(
new BufferPosition(1, 1),
-10, 0);
});
// Greater than line range
Assert.Throws(
typeof(ArgumentOutOfRangeException),
() =>
{
scriptFile.CalculatePosition(
new BufferPosition(1, 1),
10, 0);
});
// Less than column range
Assert.Throws(
typeof(ArgumentOutOfRangeException),
() =>
{
scriptFile.CalculatePosition(
new BufferPosition(1, 1),
0, -10);
});
// Greater than column range
Assert.Throws(
typeof(ArgumentOutOfRangeException),
() =>
{
scriptFile.CalculatePosition(
new BufferPosition(1, 1),
0, 10);
});
}
[Fact]
public void CanFindBeginningOfLine()
{
this.AssertNewPosition(
4, 12,
pos => pos.GetLineStart(),
4, 5);
}
[Fact]
public void CanFindEndOfLine()
{
this.AssertNewPosition(
4, 12,
pos => pos.GetLineEnd(),
4, 15);
}
[Fact]
public void CanComposePositionOperations()
{
this.AssertNewPosition(
4, 12,
pos => pos.AddOffset(-1, 1).GetLineStart(),
3, 3);
}
private void AssertNewPosition(
int originalLine, int originalColumn,
int lineOffset, int columnOffset,
int expectedLine, int expectedColumn)
{
this.AssertNewPosition(
originalLine, originalColumn,
pos => pos.AddOffset(lineOffset, columnOffset),
expectedLine, expectedColumn);
}
private void AssertNewPosition(
int originalLine, int originalColumn,
Func<FilePosition, FilePosition> positionOperation,
int expectedLine, int expectedColumn)
{
var newPosition =
positionOperation(
new FilePosition(
this.scriptFile,
originalLine,
originalColumn));
Assert.Equal(expectedLine, newPosition.Line);
Assert.Equal(expectedColumn, newPosition.Column);
}
}
}

View File

@@ -62,8 +62,8 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Driver
{
coverageOutput = "coverage.xml";
}
serviceHostArguments = "-target:" + serviceHostExecutable + " -targetargs:" + serviceHostArguments
serviceHostArguments = "-mergeoutput -target:" + serviceHostExecutable + " -targetargs:" + serviceHostArguments
+ " -register:user -oldstyle -filter:\"+[Microsoft.SqlTools.*]* -[xunit*]*\" -output:" + coverageOutput + " -searchdirs:" + serviceHostDirectory;
serviceHostExecutable = coverageToolPath;

View File

@@ -8,6 +8,9 @@ using System.Reflection;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.TestDriver.Driver;
using Microsoft.SqlTools.ServiceLayer.Utility;
using Xunit;
[assembly: CollectionBehavior(DisableTestParallelization = true)]
namespace Microsoft.SqlTools.ServiceLayer.TestDriver
{

View File

@@ -0,0 +1,45 @@
//
// 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.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts;
using Microsoft.SqlTools.ServiceLayer.TestDriver.Utility;
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
{
/// <summary>
/// Language Service end-to-end integration tests
/// </summary>
public class ConnectionTests : TestBase
{
/// <summary>
/// Try to connect with invalid credentials
/// </summary>
//[Fact]
public async Task InvalidConnection()
{
try
{
string ownerUri = System.IO.Path.GetTempFileName();
bool connected = await Connect(ownerUri, ConnectionTestUtils.InvalidConnection);
Assert.False(connected, "Invalid connection is failed to connect");
await Disconnect(ownerUri);
}
finally
{
WaitForExit();
}
}
}
}

View File

@@ -155,7 +155,6 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
string query = "SELECT *** FROM sys.objects";
DidOpenTextDocumentNotification openParams = new DidOpenTextDocumentNotification()
{
TextDocument = new TextDocumentItem()
@@ -168,7 +167,6 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
};
await RequestOpenDocumentNotification(openParams);
Thread.Sleep(5000);

View File

@@ -10,12 +10,52 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.TestDriver.Utility;
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
{
public class QueryExecutionTests : TestBase
{
[Fact]
public async Task ExecuteBasicQueryTest()
{
try
{
string ownerUri = System.IO.Path.GetTempFileName();
bool connected = await Connect(ownerUri, ConnectionTestUtils.LocalhostConnection);
Assert.True(connected, "Connection is successful");
Thread.Sleep(500);
string query = "SELECT * FROM sys.objects";
DidOpenTextDocumentNotification openParams = new DidOpenTextDocumentNotification()
{
TextDocument = new TextDocumentItem()
{
Uri = ownerUri,
LanguageId = "enu",
Version = 1,
Text = query
}
};
await RequestOpenDocumentNotification(openParams);
var queryResult = await RunQuery(ownerUri, query);
Assert.NotNull(queryResult);
Assert.NotNull(queryResult.BatchSummaries);
await Disconnect(ownerUri);
}
finally
{
WaitForExit();
}
}
//[Fact]
public async Task TestQueryingAfterCompletionRequests()
{
@@ -27,7 +67,6 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
await Connect(ownerUri, ConnectionTestUtils.AzureTestServerConnection);
Enumerable.Range(0, 10).ToList().ForEach(arg => tasks.Add(RequestCompletion(ownerUri, query, 0, 10)));
var queryTask = RunQuery(ownerUri, query);
tasks.Add(queryTask);