Fix batch parser test (#239)

* fixed batch parser test

* fix batch parser test

* fix batch parser test

* fixed baseline tests for parser and fixed trace output logic

* Update RunEnvironmentInfo.cs

* checking error logs on AppVeyor

* checking error logs on app veyor

* changed file reading encoding

* adding logs to app veyor build

* changed encoding of baseline files

* added error logs for app veyor

* changed error logs for app veyor

* changed how file stream works in batch parser tests

* changed baseline and testscript encodings

* cleaned code for necessary batch parser tests
This commit is contained in:
Aditya Bist
2017-02-24 15:49:45 -08:00
committed by GitHub
parent ab70218249
commit 25c5c27a6e
33 changed files with 834 additions and 773 deletions
@@ -1,244 +1,272 @@
// //
// Copyright (c) Microsoft. All rights reserved. // Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
// //
using System; using System;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Text; using System.Text;
using Microsoft.SqlTools.ServiceLayer.BatchParser; using Microsoft.SqlTools.ServiceLayer.BatchParser;
using Microsoft.SqlTools.ServiceLayer.QueryExecution; using Microsoft.SqlTools.ServiceLayer.Test.Common;
using Microsoft.SqlTools.ServiceLayer.Test.Common; using Microsoft.SqlTools.ServiceLayer.Test.Common.Baselined;
using Microsoft.SqlTools.ServiceLayer.Test.Common.Baselined; using Xunit;
using Xunit; using Microsoft.SqlTools.ServiceLayer.QueryExecution;
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.BatchParser namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.BatchParser
{ {
public class BatchParserTests : BaselinedTest public class BatchParserTests : BaselinedTest
{ {
private bool testFailed = false; private bool testFailed = false;
public BatchParserTests() public BatchParserTests()
{ {
InitializeTest(); InitializeTest();
} }
public void InitializeTest() public void InitializeTest()
{ {
CategoryName = "BatchParser"; CategoryName = "BatchParser";
this.TraceOutputDirectory = RunEnvironmentInfo.GetTestDataLocation(); this.TraceOutputDirectory = RunEnvironmentInfo.GetTraceOutputLocation();
TestInitialize(); TestInitialize();
} }
[Fact] [Fact]
public void VerifyThrowOnUnresolvedVariable() public void VerifyThrowOnUnresolvedVariable()
{ {
string script = "print '$(NotDefined)'"; string script = "print '$(NotDefined)'";
StringBuilder output = new StringBuilder(); StringBuilder output = new StringBuilder();
TestCommandHandler handler = new TestCommandHandler(output); TestCommandHandler handler = new TestCommandHandler(output);
IVariableResolver resolver = new TestVariableResolver(new StringBuilder()); IVariableResolver resolver = new TestVariableResolver(new StringBuilder());
Parser p = new Parser( using (Parser p = new Parser(
handler, handler,
resolver, resolver,
new StringReader(script), new StringReader(script),
"test"); "test"))
p.ThrowOnUnresolvedVariable = true; {
p.ThrowOnUnresolvedVariable = true;
handler.SetParser(p); handler.SetParser(p);
Assert.Throws<BatchParserException>(() => p.Parse()); Assert.Throws<BatchParserException>(() => p.Parse());
} }
}
public void TokenizeWithLexer(string filename, StringBuilder output)
{ private static Stream GenerateStreamFromString(string s)
{
using (Lexer lexer = new Lexer(new StreamReader(File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read)), filename)) MemoryStream stream = new MemoryStream();
{ StreamWriter writer = new StreamWriter(stream);
writer.Write(s);
string inputText = File.ReadAllText(filename); writer.Flush();
inputText = inputText.Replace("\r\n", "\n"); stream.Position = 0;
StringBuilder roundtripTextBuilder = new StringBuilder(); return stream;
StringBuilder outputBuilder = new StringBuilder(); }
StringBuilder tokenizedInput = new StringBuilder();
bool lexerError = false; public void TokenizeWithLexer(string filename, StringBuilder output)
{
Token token = null; // Create a new file by changing CRLFs to LFs and generate a new steam
try // or the tokens generated by the lexer will always have off by one errors
{ string input = File.ReadAllText(filename).Replace("\r\n", "\n");
do var inputStream = GenerateStreamFromString(input);
{ using (Lexer lexer = new Lexer(new StreamReader(inputStream), filename))
lexer.ConsumeToken(); {
token = lexer.CurrentToken;
roundtripTextBuilder.Append(token.Text); string inputText = File.ReadAllText(filename);
outputBuilder.AppendLine(GetTokenString(token)); inputText = inputText.Replace("\r\n", "\n");
tokenizedInput.Append('[').Append(GetTokenCode(token.TokenType)).Append(':').Append(token.Text).Append(']'); StringBuilder roundtripTextBuilder = new StringBuilder();
} while (token.TokenType != LexerTokenType.Eof); StringBuilder outputBuilder = new StringBuilder();
} StringBuilder tokenizedInput = new StringBuilder();
catch (BatchParserException ex) bool lexerError = false;
{
lexerError = true; Token token = null;
outputBuilder.AppendLine(string.Format(CultureInfo.CurrentCulture, "[ERROR: code {0} at {1} - {2} in {3}, message: {4}]", ex.ErrorCode, GetPositionString(ex.Begin), GetPositionString(ex.End), GetFilenameOnly(ex.Begin.Filename), ex.Message)); try
} {
output.AppendLine("Lexer tokenized input:"); do
output.AppendLine("======================"); {
output.AppendLine(tokenizedInput.ToString()); lexer.ConsumeToken();
output.AppendLine("Tokens:"); token = lexer.CurrentToken;
output.AppendLine("======="); roundtripTextBuilder.Append(token.Text.Replace("\r\n", "\n"));
output.AppendLine(outputBuilder.ToString()); outputBuilder.AppendLine(GetTokenString(token));
tokenizedInput.Append('[').Append(GetTokenCode(token.TokenType)).Append(':').Append(token.Text.Replace("\r\n", "\n")).Append(']');
if (lexerError == false) } while (token.TokenType != LexerTokenType.Eof);
{ }
// Verify that all text from tokens can be recombined into original string catch (BatchParserException ex)
Assert.Equal<string>(inputText, roundtripTextBuilder.ToString().Replace("\r\n", "\n")); {
} lexerError = true;
} outputBuilder.AppendLine(string.Format(CultureInfo.CurrentCulture, "[ERROR: code {0} at {1} - {2} in {3}, message: {4}]", ex.ErrorCode, GetPositionString(ex.Begin), GetPositionString(ex.End), GetFilenameOnly(ex.Begin.Filename), ex.Message));
} }
output.AppendLine("Lexer tokenized input:");
private string GetTokenCode(LexerTokenType lexerTokenType) output.AppendLine("======================");
{ output.AppendLine(tokenizedInput.ToString());
switch (lexerTokenType) output.AppendLine("Tokens:");
{ output.AppendLine("=======");
case LexerTokenType.Text: output.AppendLine(outputBuilder.ToString());
return "T";
case LexerTokenType.Whitespace: if (lexerError == false)
return "WS"; {
case LexerTokenType.NewLine: // Verify that all text from tokens can be recombined into original string
return "NL"; Assert.Equal<string>(inputText, roundtripTextBuilder.ToString());
case LexerTokenType.Comment: }
return "C"; }
default: }
return lexerTokenType.ToString();
} private string GetTokenCode(LexerTokenType lexerTokenType)
} {
switch (lexerTokenType)
[Fact] {
public void BatchParserTest() case LexerTokenType.Text:
{ return "T";
Start("err-blockComment"); case LexerTokenType.Whitespace:
Start("err-blockComment2"); return "WS";
Start("err-varDefinition"); case LexerTokenType.NewLine:
Start("err-varDefinition2"); return "NL";
Start("err-varDefinition3"); case LexerTokenType.Comment:
Start("err-varDefinition4"); return "C";
Start("err-varDefinition5"); default:
Start("err-varDefinition6"); return lexerTokenType.ToString();
Start("err-varDefinition7"); }
Start("err-varDefinition8"); }
Start("err-varDefinition9");
Start("err-variableRef"); private static void CopyToOutput(string sourceDirectory, string filename)
Start("err-variableRef2"); {
Start("err-variableRef3"); File.Copy(Path.Combine(sourceDirectory, filename), filename, true);
Start("err-variableRef4"); FileUtilities.SetFileReadWrite(filename);
Start("err-cycle1"); }
Start("input");
Start("input2"); [Fact]
Start("pass-blockComment"); public void BatchParserTest()
Start("pass-lineComment"); {
Start("pass-lineComment2"); CopyToOutput(FilesLocation, "TS-err-cycle1.txt");
Start("pass-noBlockComments"); CopyToOutput(FilesLocation, "cycle2.txt");
Start("pass-noLineComments");
Start("pass-varDefinition"); Start("err-blockComment");
Start("pass-varDefinition2"); Start("err-blockComment2");
Start("pass-varDefinition3"); Start("err-varDefinition");
Start("pass-varDefinition4"); Start("err-varDefinition2");
Start("pass-command-and-comment"); Start("err-varDefinition3");
Assert.False(testFailed, "At least one of test cases failed. Check output for details."); Start("err-varDefinition4");
} Start("err-varDefinition5");
Start("err-varDefinition6");
public void TestParser(string filename, StringBuilder output) Start("err-varDefinition7");
{ Start("err-varDefinition8");
try Start("err-varDefinition9");
{ Start("err-variableRef");
TestCommandHandler commandHandler = new TestCommandHandler(output); Start("err-variableRef2");
Start("err-variableRef3");
Parser parser = new Parser( Start("err-variableRef4");
commandHandler, Start("err-cycle1");
new TestVariableResolver(output), Start("input");
new StreamReader(File.Open(filename, FileMode.Open)), Start("input2");
filename); Start("pass-blockComment");
Start("pass-lineComment");
commandHandler.SetParser(parser); Start("pass-lineComment2");
Start("pass-noBlockComments");
parser.Parse(); Start("pass-noLineComments");
} Start("pass-varDefinition");
catch (BatchParserException ex) Start("pass-varDefinition2");
{ Start("pass-varDefinition3");
output.AppendLine(string.Format(CultureInfo.CurrentCulture, "[PARSER ERROR: code {0} at {1} - {2} in {3}, token text: {4}, message: {5}]", ex.ErrorCode, GetPositionString(ex.Begin), GetPositionString(ex.End), GetFilenameOnly(ex.Begin.Filename), ex.Text, ex.Message)); Start("pass-varDefinition4");
} Start("pass-command-and-comment");
} Assert.False(testFailed, "At least one of test cases failed. Check output for details.");
}
private string GetPositionString(PositionStruct pos)
{ public void TestParser(string filename, StringBuilder output)
return string.Format(CultureInfo.InvariantCulture, "{0}:{1} [{2}]", pos.Line, pos.Column, pos.Offset); {
} try
{
private string GetTokenString(Token token) // Create a new file by changing CRLFs to LFs and generate a new steam
{ // or the tokens generated by the lexer will always have off by one errors
if (token == null) TestCommandHandler commandHandler = new TestCommandHandler(output);
{ string input = File.ReadAllText(filename).Replace("\r\n", "\n");
return "(null)"; var inputStream = GenerateStreamFromString(input);
} StreamReader streamReader = new StreamReader(inputStream);
else
{ using (Parser parser = new Parser(
string tokenText = token.Text; commandHandler,
if (tokenText != null) new TestVariableResolver(output),
{ streamReader,
tokenText = tokenText.Replace("\n", "\\n").Replace("\r", "\\r").Replace("\t", "\\t"); filename))
} {
string tokenFilename = token.Filename; commandHandler.SetParser(parser);
tokenFilename = GetFilenameOnly(tokenFilename); parser.Parse();
return string.Format(CultureInfo.CurrentCulture, "[Token {0} at {1}({2}:{3} [{4}] - {5}:{6} [{7}]): '{8}']", }
token.TokenType, }
tokenFilename, catch (BatchParserException ex)
token.Begin.Line, token.Begin.Column, token.Begin.Offset, {
token.End.Line, token.End.Column, token.End.Offset, output.AppendLine(string.Format(CultureInfo.CurrentCulture, "[PARSER ERROR: code {0} at {1} - {2} in {3}, token text: {4}, message: {5}]", ex.ErrorCode, GetPositionString(ex.Begin), GetPositionString(ex.End), GetFilenameOnly(ex.Begin.Filename), ex.Text, ex.Message));
tokenText); }
} }
}
private string GetPositionString(PositionStruct pos)
internal static string GetFilenameOnly(string fullPath) {
{ return string.Format(CultureInfo.InvariantCulture, "{0}:{1} [{2}]", pos.Line, pos.Column, pos.Offset);
return fullPath != null ? Path.GetFileName(fullPath) : null; }
}
private string GetTokenString(Token token)
public override void Run() {
{ if (token == null)
string inputFilename = GetTestscriptFilePath(CurrentTestName); {
StringBuilder output = new StringBuilder(); return "(null)";
}
TokenizeWithLexer(inputFilename, output); else
TestParser(inputFilename, output); {
string tokenText = token.Text;
string baselineFilename = GetBaselineFilePath(CurrentTestName); if (tokenText != null)
string baseline; {
tokenText = tokenText.Replace("\r\n", "\\n").Replace("\n", "\\n").Replace("\r", "\\r").Replace("\t", "\\t");
try }
{ string tokenFilename = token.Filename;
baseline = GetFileContent(baselineFilename); tokenFilename = GetFilenameOnly(tokenFilename);
} return string.Format(CultureInfo.CurrentCulture, "[Token {0} at {1}({2}:{3} [{4}] - {5}:{6} [{7}]): '{8}']",
catch (FileNotFoundException) token.TokenType,
{ tokenFilename,
baseline = string.Empty; token.Begin.Line, token.Begin.Column, token.Begin.Offset,
} token.End.Line, token.End.Column, token.End.Offset,
tokenText);
string outputString = output.ToString(); }
}
Console.WriteLine(baselineFilename);
internal static string GetFilenameOnly(string fullPath)
if (string.Compare(baseline, outputString, StringComparison.Ordinal) != 0) {
{ return fullPath != null ? Path.GetFileName(fullPath) : null;
DumpToTrace(CurrentTestName, outputString); }
string outputFilename = Path.Combine(TraceFilePath, GetBaselineFileName(CurrentTestName));
Console.WriteLine(":: Output does not match the baseline!"); public override void Run()
Console.WriteLine("code --diff \"" + baselineFilename + "\" \"" + outputFilename + "\""); {
Console.WriteLine(); string inputFilename = GetTestscriptFilePath(CurrentTestName);
Console.WriteLine(":: To update the baseline:"); StringBuilder output = new StringBuilder();
Console.WriteLine("copy \"" + outputFilename + "\" \"" + baselineFilename + "\"");
Console.WriteLine(); TokenizeWithLexer(inputFilename, output);
testFailed = true; TestParser(inputFilename, output);
}
} string baselineFilename = GetBaselineFilePath(CurrentTestName);
} string baseline;
}
try
{
baseline = GetFileContent(baselineFilename).Replace("\r\n", "\n");
}
catch (FileNotFoundException)
{
baseline = string.Empty;
}
string outputString = output.ToString().Replace("\r\n", "\n");
Console.WriteLine(baselineFilename);
if (string.Compare(baseline, outputString, StringComparison.Ordinal) != 0)
{
DumpToTrace(CurrentTestName, outputString);
string outputFilename = Path.Combine(TraceFilePath, GetBaselineFileName(CurrentTestName));
Console.WriteLine(":: Output does not match the baseline!");
Console.WriteLine("code --diff \"" + baselineFilename + "\" \"" + outputFilename + "\"");
Console.WriteLine();
Console.WriteLine(":: To update the baseline:");
Console.WriteLine("copy \"" + outputFilename + "\" \"" + baselineFilename + "\"");
Console.WriteLine();
testFailed = true;
}
}
}
}
@@ -1,454 +1,448 @@
// //
// Copyright (c) Microsoft. All rights reserved. // Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
// //
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Text; using System.Text;
using Xunit; using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.Test.Common.Baselined namespace Microsoft.SqlTools.ServiceLayer.Test.Common.Baselined
{ {
/// <summary> /// <summary>
/// This class serves as the base class for all baselined tests /// This class serves as the base class for all baselined tests
/// It will provide easy services for you to interact with your test files and their baselines /// It will provide easy services for you to interact with your test files and their baselines
/// </summary> /// </summary>
public abstract class BaselinedTest public abstract class BaselinedTest
{ {
/// <summary> /// <summary>
/// Holds the extension for the TestScripts /// Holds the extension for the TestScripts
/// </summary> /// </summary>
private string _testScriptExtension; private string _testScriptExtension;
/// <summary> /// <summary>
/// Holds the extensionf or the Baseline files /// Holds the extensionf or the Baseline files
/// </summary> /// </summary>
private string _baselineExtension; private string _baselineExtension;
/// <summary> /// <summary>
/// Holds the path to the base location of both TestScripts and Baselines /// Holds the path to the base location of both TestScripts and Baselines
/// </summary> /// </summary>
private string _testCategoryName; private string _testCategoryName;
/// <summary> /// <summary>
/// Holds the ROOT Dir for trace output /// Holds the ROOT Dir for trace output
/// </summary> /// </summary>
private string _traceOutputDir; private string _traceOutputDir;
/// <summary> /// <summary>
/// Holds the prefix for the baseline /// Holds the prefix for the baseline
/// </summary> /// </summary>
private string _baselinePrefix; private string _baselinePrefix;
/// <summary> /// <summary>
/// Holds the prefix for the Testscript /// Holds the prefix for the Testscript
/// </summary> /// </summary>
private string _testscriptPrefix; private string _testscriptPrefix;
/// <summary> /// <summary>
/// Holds the name of the current test /// Holds the name of the current test
/// </summary> /// </summary>
private string _currentTestname; private string _currentTestname;
private string _baselineSubDir = string.Empty; private string _baselineSubDir = string.Empty;
public const string TestScriptDirectory = @"Testscripts\"; public const string TestScriptDirectory = @"Testscripts\";
public const string BaselineDirectory = @"Baselines\"; public const string BaselineDirectory = @"Baselines\";
/// <summary> /// <summary>
/// Gets/Sets the extension for the Testscript files /// Gets/Sets the extension for the Testscript files
/// </summary> /// </summary>
public string TestscriptFileExtension public string TestscriptFileExtension
{ {
get get
{ {
return _testScriptExtension; return _testScriptExtension;
} }
set set
{ {
if (string.IsNullOrEmpty(value)) if (string.IsNullOrEmpty(value))
throw new ArgumentException("TestscriptFileExtension needs a value"); throw new ArgumentException("TestscriptFileExtension needs a value");
_testScriptExtension = value; _testScriptExtension = value;
} }
} }
/// <summary> /// <summary>
/// Gets/Sets the extension for the Baseline files /// Gets/Sets the extension for the Baseline files
/// </summary> /// </summary>
public string BaselineFileExtension public string BaselineFileExtension
{ {
get get
{ {
return _baselineExtension; return _baselineExtension;
} }
set set
{ {
if (string.IsNullOrEmpty(value)) if (string.IsNullOrEmpty(value))
throw new ArgumentException("BaselineFileExtension needs a value"); throw new ArgumentException("BaselineFileExtension needs a value");
_baselineExtension = value; _baselineExtension = value;
} }
} }
/// <summary> /// <summary>
/// Gets/Sets the path to the base location of both test scripts and baseline files /// Gets/Sets the path to the base location of both test scripts and baseline files
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Just use the SubDir name /// Just use the SubDir name
/// TestScripts should be in FileBaseLocation\Testscripts; and Baselines should be in FileBaseLocation\Baselines /// TestScripts should be in FileBaseLocation\Testscripts; and Baselines should be in FileBaseLocation\Baselines
/// The value of this will be appended to ROOT_DIR (QA\SrcUTest\Common) /// The value of this will be appended to ROOT_DIR (QA\SrcUTest\Common)
/// </remarks> /// </remarks>
public string CategoryName public string CategoryName
{ {
get get
{ {
return _testCategoryName; return _testCategoryName;
} }
set set
{ {
if (string.IsNullOrEmpty(value)) if (string.IsNullOrEmpty(value))
throw new ArgumentException("FileBaseLocation needs a value"); throw new ArgumentException("FileBaseLocation needs a value");
_testCategoryName = value; _testCategoryName = value;
} }
} }
/// <summary> /// <summary>
/// Gets/Sets the output base directory for trace output (null = no trace output) /// Gets/Sets the output base directory for trace output (null = no trace output)
/// </summary> /// </summary>
public string TraceOutputDirectory public string TraceOutputDirectory
{ {
get get
{ {
return _traceOutputDir; return _traceOutputDir;
} }
set set
{ {
_traceOutputDir = value; _traceOutputDir = value;
} }
} }
/// <summary> /// <summary>
/// Gets the full path of where the files will be pulled from /// Gets the full path of where the files will be pulled from
/// </summary> /// </summary>
public string FilesLocation public string FilesLocation
{ {
get get
{ {
return Path.Combine(RunEnvironmentInfo.GetTestDataLocation(), CategoryName, TestScriptDirectory); return Path.Combine(RunEnvironmentInfo.GetTestDataLocation(), CategoryName, TestScriptDirectory);
} }
} }
/// <summary> /// <summary>
/// Gets or Sets the sub directory in Baselines where the exected baseline results are located /// Gets or Sets the sub directory in Baselines where the exected baseline results are located
/// </summary> /// </summary>
public string BaselinesSubdir public string BaselinesSubdir
{ {
get get
{ {
if (this._baselineSubDir == null) if (this._baselineSubDir == null)
this._baselineSubDir = string.Empty; this._baselineSubDir = string.Empty;
return this._baselineSubDir; return this._baselineSubDir;
} }
set { this._baselineSubDir = value; } set { this._baselineSubDir = value; }
} }
/// <summary> /// <summary>
/// Gets the full path of where the baseline files will be pulled from /// Gets the full path of where the baseline files will be pulled from
/// </summary> /// </summary>
public string BaselineFilePath public string BaselineFilePath
{ {
get get
{ {
return Path.Combine(RunEnvironmentInfo.GetTestDataLocation(), CategoryName, Path.Combine( BaselineDirectory, BaselinesSubdir )); return Path.Combine(RunEnvironmentInfo.GetTestDataLocation(), CategoryName, Path.Combine( BaselineDirectory, BaselinesSubdir ));
} }
} }
/// <summary> /// <summary>
/// Gets the full path of where the Trace will output /// Gets the full path of where the Trace will output
/// </summary> /// </summary>
public string TraceFilePath public string TraceFilePath
{ {
get get
{ {
return Path.Combine(Path.GetFullPath(TraceOutputDirectory), this.CategoryName, this.BaselinesSubdir); return Path.Combine(Path.GetFullPath(TraceOutputDirectory), this.CategoryName, this.BaselinesSubdir);
} }
} }
/// <summary> /// <summary>
/// Gets/Sets the prefix used for baseline files /// Gets/Sets the prefix used for baseline files
/// </summary> /// </summary>
public string BaselinePrefix public string BaselinePrefix
{ {
get get
{ {
return _baselinePrefix; return _baselinePrefix;
} }
set set
{ {
if (string.IsNullOrEmpty(value)) if (string.IsNullOrEmpty(value))
throw new ArgumentException("BaselinePrefix needs a value"); throw new ArgumentException("BaselinePrefix needs a value");
_baselinePrefix = value; _baselinePrefix = value;
} }
} }
/// <summary> /// <summary>
/// Gets/Sets the prefix used for testscript files /// Gets/Sets the prefix used for testscript files
/// </summary> /// </summary>
public string TestscriptPrefix public string TestscriptPrefix
{ {
get get
{ {
return _testscriptPrefix; return _testscriptPrefix;
} }
set set
{ {
if (string.IsNullOrEmpty(value)) if (string.IsNullOrEmpty(value))
throw new ArgumentException("TestscriptPrefix needs a value"); throw new ArgumentException("TestscriptPrefix needs a value");
_testscriptPrefix = value; _testscriptPrefix = value;
} }
} }
/// <summary> /// <summary>
/// Gets/Sets the name of the current test /// Gets/Sets the name of the current test
/// </summary> /// </summary>
public string CurrentTestName public string CurrentTestName
{ {
get get
{ {
return _currentTestname; return _currentTestname;
} }
} }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public BaselinedTest() public BaselinedTest()
{ {
Initialize(); Initialize();
} }
/// <summary> /// <summary>
/// Initializes the class /// Initializes the class
/// </summary> /// </summary>
private void Initialize() private void Initialize()
{ {
_testScriptExtension = _baselineExtension = "txt"; //default to txt _testScriptExtension = _baselineExtension = "txt"; //default to txt
_testCategoryName = null; _testCategoryName = null;
string projectPath = Environment.GetEnvironmentVariable(Constants.ProjectPath); string projectPath = Environment.GetEnvironmentVariable(Constants.ProjectPath);
if (projectPath != null) if (projectPath != null)
{ {
_traceOutputDir = Path.Combine(projectPath, "trace"); _traceOutputDir = Path.Combine(projectPath, "trace");
} }
else else
{ {
_traceOutputDir = Environment.ExpandEnvironmentVariables(@"%SystemDrive%\trace\"); _traceOutputDir = Environment.ExpandEnvironmentVariables(@"%SystemDrive%\trace\");
} }
_baselinePrefix = "BL"; _baselinePrefix = "BL";
_testscriptPrefix = "TS"; _testscriptPrefix = "TS";
} }
/// <summary> /// <summary>
/// This method should be called whenever you do a [TestInitialize] /// This method should be called whenever you do a [TestInitialize]
/// </summary> /// </summary>
public virtual void TestInitialize() public virtual void TestInitialize()
{ {
if (string.IsNullOrEmpty(_testCategoryName)) if (string.IsNullOrEmpty(_testCategoryName))
throw new ArgumentException("Set CategoryName to the name of the directory containing your Testscripts and Baseline files"); throw new ArgumentException("Set CategoryName to the name of the directory containing your Testscripts and Baseline files");
if (!Directory.Exists(FilesLocation)) if (!Directory.Exists(FilesLocation))
throw new FileNotFoundException(string.Format("Path to Testscripts ([{0}]) does not exist.", FilesLocation)); throw new FileNotFoundException(string.Format("Path to Testscripts ([{0}]) does not exist.", FilesLocation));
if (!Directory.Exists(BaselineFilePath)) if (!Directory.Exists(BaselineFilePath))
throw new FileNotFoundException(string.Format("Path to Baseline Files [{0}] does not exist.", BaselineFilePath)); throw new FileNotFoundException(string.Format("Path to Baseline Files [{0}] does not exist.", BaselineFilePath));
if (!string.IsNullOrEmpty(TraceFilePath) && !Directory.Exists(TraceFilePath)) //if this does not exist, then we want it (pronto) if (!string.IsNullOrEmpty(TraceFilePath) && !Directory.Exists(TraceFilePath)) //if this does not exist, then we want it (pronto)
Directory.CreateDirectory(TraceFilePath); Directory.CreateDirectory(TraceFilePath);
} }
/// <summary> /// <summary>
/// Compares two strings and gives appropriate output /// Compares two strings and gives appropriate output
/// </summary> /// </summary>
/// <param name="actualContent">Actual string</param> /// <param name="actualContent">Actual string</param>
/// <param name="baselineContent">Expected string</param> /// <param name="baselineContent">Expected string</param>
/// <remarks>Fails test if strings do not match; comparison is done using an InvariantCulture StringComparer</remarks> /// <remarks>Fails test if strings do not match; comparison is done using an InvariantCulture StringComparer</remarks>
public void CompareActualWithBaseline(string actualContent, string baselineContent) public void CompareActualWithBaseline(string actualContent, string baselineContent)
{ {
int _compareResult = string.Compare(actualContent, baselineContent, StringComparison.OrdinalIgnoreCase); int _compareResult = string.Compare(actualContent, baselineContent, StringComparison.OrdinalIgnoreCase);
if (_compareResult != 0) if (_compareResult != 0)
{ {
Trace.WriteLine("Debug Info:"); Trace.WriteLine("Debug Info:");
Trace.WriteLine("========BEGIN=EXPECTED========"); Trace.WriteLine("========BEGIN=EXPECTED========");
Trace.WriteLine(baselineContent); Trace.WriteLine(baselineContent);
Trace.WriteLine("=========END=EXPECTED========="); Trace.WriteLine("=========END=EXPECTED=========");
Trace.WriteLine("=========BEGIN=ACTUAL========="); Trace.WriteLine("=========BEGIN=ACTUAL=========");
Trace.WriteLine(actualContent); Trace.WriteLine(actualContent);
Trace.WriteLine("==========END=ACTUAL=========="); Trace.WriteLine("==========END=ACTUAL==========");
Assert.True(false, string.Format("Comparison failed! (actualContent {0} baselineContent)", (_compareResult < 0 ? "<" : ">"))); //we already know it is not equal Assert.True(false, string.Format("Comparison failed! (actualContent {0} baselineContent)", (_compareResult < 0 ? "<" : ">"))); //we already know it is not equal
} }
else else
{ {
Trace.WriteLine("Compare match! All is fine..."); Trace.WriteLine("Compare match! All is fine...");
} }
} }
/// <summary> /// <summary>
/// Gets the name of the testscript with the provided name /// Gets the name of the testscript with the provided name
/// </summary> /// </summary>
/// <param name="name">Name of the test</param> /// <param name="name">Name of the test</param>
/// <returns>the path to the baseline file</returns> /// <returns>the path to the baseline file</returns>
/// <remarks>Asserts that file exists</remarks> /// <remarks>Asserts that file exists</remarks>
public string GetTestscriptFilePath(string name) public string GetTestscriptFilePath(string name)
{ {
string retVal = Path.Combine(FilesLocation, string.Format("{0}-{1}.{2}", TestscriptPrefix, name, TestscriptFileExtension)); string retVal = Path.Combine(FilesLocation, string.Format("{0}-{1}.{2}", TestscriptPrefix, name, TestscriptFileExtension));
Assert.True(File.Exists(retVal), string.Format("TestScript [{0}] does not exist", retVal)); Assert.True(File.Exists(retVal), string.Format("TestScript [{0}] does not exist", retVal));
return retVal; return retVal;
} }
/// <summary> /// <summary>
/// Gets the name of the test script with the provided name and the provided index /// Gets the name of the test script with the provided name and the provided index
/// </summary> /// </summary>
/// <param name="name">Name of the test</param> /// <param name="name">Name of the test</param>
/// <param name="index">File index</param> /// <param name="index">File index</param>
/// <returns>the path to the baseline file</returns> /// <returns>the path to the baseline file</returns>
/// <remarks>Asserts that file exists</remarks> /// <remarks>Asserts that file exists</remarks>
public string GetTestscriptFilePath(string name, int index) public string GetTestscriptFilePath(string name, int index)
{ {
string retVal = Path.Combine(FilesLocation, string.Format("{0}-{1}{2}.{3}", TestscriptPrefix, name, index.ToString(), TestscriptFileExtension)); string retVal = Path.Combine(FilesLocation, string.Format("{0}-{1}{2}.{3}", TestscriptPrefix, name, index.ToString(), TestscriptFileExtension));
Assert.True(File.Exists(retVal), string.Format("TestScript [{0}] does not exist", retVal)); Assert.True(File.Exists(retVal), string.Format("TestScript [{0}] does not exist", retVal));
return retVal; return retVal;
} }
/// <summary> /// <summary>
/// Gets the formatted baseline file name /// Gets the formatted baseline file name
/// </summary> /// </summary>
/// <param name="name">Name of the test</param> /// <param name="name">Name of the test</param>
public string GetBaselineFileName(string name) public string GetBaselineFileName(string name)
{ {
return string.Format("{0}-{1}.{2}", BaselinePrefix, name, BaselineFileExtension); return string.Format("{0}-{1}.{2}", BaselinePrefix, name, BaselineFileExtension);
} }
/// <summary> /// <summary>
/// Gets the file path to the baseline file for the named case /// Gets the file path to the baseline file for the named case
/// </summary> /// </summary>
/// <param name="name">Name of the test</param> /// <param name="name">Name of the test</param>
/// <returns>the path to the baseline file</returns> /// <returns>the path to the baseline file</returns>
/// <remarks>Asserts that file exists</remarks> /// <remarks>Asserts that file exists</remarks>
public string GetBaselineFilePath(string name, bool assertIfNotFound) public string GetBaselineFilePath(string name, bool assertIfNotFound)
{ {
string retVal = Path.Combine(BaselineFilePath, GetBaselineFileName(name)); string retVal = Path.Combine(BaselineFilePath, GetBaselineFileName(name));
if (assertIfNotFound) if (assertIfNotFound)
{ {
Assert.True(File.Exists(retVal), string.Format("Baseline [{0}] does not exist", retVal)); Assert.True(File.Exists(retVal), string.Format("Baseline [{0}] does not exist", retVal));
} }
return retVal; return retVal;
} }
public string GetBaselineFilePath(string name) public string GetBaselineFilePath(string name)
{ {
return GetBaselineFilePath(name, true); return GetBaselineFilePath(name, true);
} }
/// <summary> /// <summary>
/// Gets the contents of a file /// Gets the contents of a file
/// </summary> /// </summary>
/// <param name="path">Path of the file to read</param> /// <param name="path">Path of the file to read</param>
/// <returns>The contents of the file</returns> /// <returns>The contents of the file</returns>
public string GetFileContent(string path) public string GetFileContent(string path)
{ {
Trace.WriteLine(string.Format("GetFileContent for [{0}]", Path.GetFullPath(path))); Trace.WriteLine(string.Format("GetFileContent for [{0}]", Path.GetFullPath(path)));
using (StreamReader sr = new StreamReader(File.Open(path, FileMode.Open), Encoding.Unicode)) using (StreamReader sr = new StreamReader(File.Open(path, FileMode.Open), Encoding.UTF8))
{ {
return sr.ReadToEnd(); return sr.ReadToEnd();
} }
} }
/// <summary> /// <summary>
/// Dumps the text to a Trace file /// Dumps the text to a Trace file
/// </summary> /// </summary>
/// <param name="testName">Test name used to create file name</param> /// <param name="testName">Test name used to create file name</param>
/// <param name="text">Text to dump to the trace file</param> /// <param name="text">Text to dump to the trace file</param>
/// <remarks>Overwrites whatever is already in the file (if anything)</remarks> /// <remarks>Overwrites whatever is already in the file (if anything)</remarks>
public string DumpToTrace(string testName, string text) public string DumpToTrace(string testName, string text)
{ {
if (string.IsNullOrEmpty(TraceFilePath)) if (string.IsNullOrEmpty(TraceFilePath))
{ {
return string.Empty; //nothing to do return string.Empty; //nothing to do
} }
string traceFile = Path.Combine(TraceFilePath, GetBaselineFileName(testName)); string traceFile = Path.Combine(TraceFilePath, GetBaselineFileName(testName));
if (File.Exists(traceFile)) if (File.Exists(traceFile))
{ {
Trace.Write(string.Format("Overwriting existing trace file [{0}]", traceFile)); Trace.Write(string.Format("Overwriting existing trace file [{0}]", traceFile));
File.Delete(traceFile); File.Delete(traceFile);
} }
else else
{ {
Trace.Write(string.Format("Dumping to trace file [{0}]", traceFile)); Trace.Write(string.Format("Dumping to trace file [{0}]", traceFile));
} }
if (Directory.Exists(TraceFilePath) == false) if (Directory.Exists(TraceFilePath) == false)
{ {
Directory.CreateDirectory(TraceFilePath); Directory.CreateDirectory(TraceFilePath);
} }
WriteTraceFile(traceFile, text); WriteTraceFile(traceFile, text);
return traceFile; return traceFile;
} }
/// <summary> /// <summary>
/// Writes the context to the trace file /// Writes the context to the trace file
/// </summary> /// </summary>
/// <param name="traceFile">The file name for the trace output</param> /// <param name="traceFile">The file name for the trace output</param>
/// <param name="text">The content for the trace file</param> /// <param name="text">The content for the trace file</param>
public void WriteTraceFile(string traceFile, string text) public void WriteTraceFile(string traceFile, string text)
{ {
Stream traceStream = GetStreamFromString(traceFile); File.WriteAllText(traceFile, text);
using (StreamWriter sw = new StreamWriter(traceStream, Encoding.Unicode)) }
{
sw.Write(text); /// <summary>
sw.Flush(); /// Converts a string to a stream
sw.Dispose(); /// </summary>
} /// <param name="s"></param>
} /// <returns></returns>
private Stream GetStreamFromString(string s)
/// <summary> {
/// Converts a string to a stream MemoryStream stream = new MemoryStream();
/// </summary> StreamWriter writer = new StreamWriter(stream);
/// <param name="s"></param> writer.Write(s);
/// <returns></returns> writer.Flush();
private Stream GetStreamFromString(string s) stream.Position = 0;
{ return stream;
MemoryStream stream = new MemoryStream(); }
StreamWriter writer = new StreamWriter(stream);
writer.Write(s); /// <summary>
writer.Flush(); /// Starts the actual running of the test after nicely initializing
stream.Position = 0; /// </summary>
return stream; /// <param name="testname">Name of the test</param>
} public void Start(string testname)
{
/// <summary> Trace.WriteLine(string.Format("Starting test named [{0}]", testname));
/// Starts the actual running of the test after nicely initializing _currentTestname = testname;
/// </summary>
/// <param name="testname">Name of the test</param> Run();
public void Start(string testname)
{ Trace.WriteLine("Test Completed");
Trace.WriteLine(string.Format("Starting test named [{0}]", testname)); }
_currentTestname = testname;
/// <summary>
Run(); /// Runs the actual test
/// </summary>
Trace.WriteLine("Test Completed"); /// <remarks>Override this method to put in your test logic</remarks>
} public abstract void Run();
/// <summary> }
/// Runs the actual test }
/// </summary>
/// <remarks>Override this method to put in your test logic</remarks>
public abstract void Run();
}
}
@@ -1,73 +1,112 @@
// //
// Copyright (c) Microsoft. All rights reserved. // Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
// //
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Microsoft.SqlTools.ServiceLayer.Test.Common namespace Microsoft.SqlTools.ServiceLayer.Test.Common
{ {
/// <summary> /// <summary>
/// Contains environment information needed when running tests. /// Contains environment information needed when running tests.
/// </summary> /// </summary>
public class RunEnvironmentInfo public class RunEnvironmentInfo
{ {
private static string cachedTestFolderPath; private static string cachedTestFolderPath;
private static string cachedTraceFolderPath;
public static bool IsLabMode()
{ public static bool IsLabMode()
string bvtLabRoot = Environment.GetEnvironmentVariable(Constants.BVTLocalRoot); {
if (string.IsNullOrEmpty(bvtLabRoot)) string bvtLabRoot = Environment.GetEnvironmentVariable(Constants.BVTLocalRoot);
{ if (string.IsNullOrEmpty(bvtLabRoot))
return false; {
} return false;
return true; }
} return true;
}
/// <summary>
/// Location of all test data (baselines, etc). /// <summary>
/// </summary> /// Location of all test data (baselines, etc).
/// <returns>The full path to the test data directory</returns> /// </summary>
public static string GetTestDataLocation() /// <returns>The full path to the test data directory</returns>
{ public static string GetTestDataLocation()
string testFolderPath; {
string testPath = Path.Combine("test", "Microsoft.SqlTools.ServiceLayer.Test.Common", "TestData"); string testFolderPath;
string projectPath = Environment.GetEnvironmentVariable(Constants.ProjectPath); string testPath = Path.Combine("test", "Microsoft.SqlTools.ServiceLayer.Test.Common", "TestData");
string projectPath = Environment.GetEnvironmentVariable(Constants.ProjectPath);
if (projectPath != null)
{ if (projectPath != null)
testFolderPath = Path.Combine(projectPath, testPath); {
} testFolderPath = Path.Combine(projectPath, testPath);
else }
{ else
if (cachedTestFolderPath != null) {
{ if (cachedTestFolderPath != null)
testFolderPath = cachedTestFolderPath; {
} testFolderPath = cachedTestFolderPath;
else }
{ else
// We are running tests locally, which means we expect to be running inside the bin\debug\netcoreapp directory {
// Test Files should be found at the root of the project so go back the necessary number of directories for this // We are running tests locally, which means we expect to be running inside the bin\debug\netcoreapp directory
// to be found. We are manually specifying the testFolderPath here for clarity on where to expect this // Test Files should be found at the root of the project so go back the necessary number of directories for this
// to be found. We are manually specifying the testFolderPath here for clarity on where to expect this
string assemblyDir = Path.GetDirectoryName(typeof(Scripts).GetTypeInfo().Assembly.Location);
string defaultPath = Path.Combine(assemblyDir, GoUpNDirectories(4)); string assemblyDir = Path.GetDirectoryName(typeof(Scripts).GetTypeInfo().Assembly.Location);
testFolderPath = Path.Combine(defaultPath, "Microsoft.SqlTools.ServiceLayer.Test.Common", "TestData"); string defaultPath = Path.Combine(assemblyDir, GoUpNDirectories(4));
testFolderPath = Path.Combine(defaultPath, "Microsoft.SqlTools.ServiceLayer.Test.Common", "TestData");
cachedTestFolderPath = testFolderPath;
} cachedTestFolderPath = testFolderPath;
} }
return testFolderPath; }
} return testFolderPath;
private static string GoUpNDirectories(int n) }
{
string up = ".." + (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "\\" : "/"); /// <summary>
return string.Concat(Enumerable.Repeat(up, n)); /// Location of all trace data (expected output)
} /// </summary>
} /// <returns>The full path to the trace data directory</returns>
} public static string GetTraceOutputLocation()
{
string traceFolderPath;
string testPath = @"test\Microsoft.SqlTools.ServiceLayer.Test.Common\Trace";
string projectPath = Environment.GetEnvironmentVariable(Constants.ProjectPath);
if (projectPath != null)
{
traceFolderPath = Path.Combine(projectPath, testPath);
}
else
{
if (cachedTraceFolderPath != null)
{
traceFolderPath = cachedTraceFolderPath;
}
else
{
// We are running tests locally, which means we expect to be running inside the bin\debug\netcoreapp directory
// Test Files should be found at the root of the project so go back the necessary number of directories for this
// to be found. We are manually specifying the testFolderPath here for clarity on where to expect this
string assemblyDir = Path.GetDirectoryName(typeof(Scripts).GetTypeInfo().Assembly.Location);
string defaultPath = Path.Combine(assemblyDir, GoUpNDirectories(4));
traceFolderPath = Path.Combine(defaultPath, "Microsoft.SqlTools.ServiceLayer.Test.Common", "TestData");
cachedTraceFolderPath = traceFolderPath;
}
}
return traceFolderPath;
}
private static string GoUpNDirectories(int n)
{
string up = ".." + (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "\\" : "/");
return string.Concat(Enumerable.Repeat(up, n));
}
}
}
@@ -1,4 +1,4 @@
GO 2 GO 2
BEGIN BEGIN
:r input-2.txt :r input-2.txt
:r "input-2.txt" :r "input-2.txt"
@@ -135,7 +135,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common
} }
TestServiceProvider.hasInitServices = true; TestServiceProvider.hasInitServices = true;
const string hostName = "SQ Tools Test Service Host"; const string hostName = "SQL Tools Test Service Host";
const string hostProfileId = "SQLToolsTestService"; const string hostProfileId = "SQLToolsTestService";
Version hostVersion = new Version(1, 0); Version hostVersion = new Version(1, 0);