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

View File

@@ -1,244 +1,272 @@
//
// 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.Globalization;
using System.IO;
using System.Text;
using Microsoft.SqlTools.ServiceLayer.BatchParser;
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
using Microsoft.SqlTools.ServiceLayer.Test.Common;
using Microsoft.SqlTools.ServiceLayer.Test.Common.Baselined;
using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.BatchParser
{
public class BatchParserTests : BaselinedTest
{
private bool testFailed = false;
public BatchParserTests()
{
InitializeTest();
}
public void InitializeTest()
{
CategoryName = "BatchParser";
this.TraceOutputDirectory = RunEnvironmentInfo.GetTestDataLocation();
TestInitialize();
}
[Fact]
public void VerifyThrowOnUnresolvedVariable()
{
string script = "print '$(NotDefined)'";
StringBuilder output = new StringBuilder();
TestCommandHandler handler = new TestCommandHandler(output);
IVariableResolver resolver = new TestVariableResolver(new StringBuilder());
Parser p = new Parser(
handler,
resolver,
new StringReader(script),
"test");
p.ThrowOnUnresolvedVariable = true;
handler.SetParser(p);
Assert.Throws<BatchParserException>(() => p.Parse());
}
public void TokenizeWithLexer(string filename, StringBuilder output)
{
using (Lexer lexer = new Lexer(new StreamReader(File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read)), filename))
{
string inputText = File.ReadAllText(filename);
inputText = inputText.Replace("\r\n", "\n");
StringBuilder roundtripTextBuilder = new StringBuilder();
StringBuilder outputBuilder = new StringBuilder();
StringBuilder tokenizedInput = new StringBuilder();
bool lexerError = false;
Token token = null;
try
{
do
{
lexer.ConsumeToken();
token = lexer.CurrentToken;
roundtripTextBuilder.Append(token.Text);
outputBuilder.AppendLine(GetTokenString(token));
tokenizedInput.Append('[').Append(GetTokenCode(token.TokenType)).Append(':').Append(token.Text).Append(']');
} while (token.TokenType != LexerTokenType.Eof);
}
catch (BatchParserException ex)
{
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:");
output.AppendLine("======================");
output.AppendLine(tokenizedInput.ToString());
output.AppendLine("Tokens:");
output.AppendLine("=======");
output.AppendLine(outputBuilder.ToString());
if (lexerError == false)
{
// Verify that all text from tokens can be recombined into original string
Assert.Equal<string>(inputText, roundtripTextBuilder.ToString().Replace("\r\n", "\n"));
}
}
}
private string GetTokenCode(LexerTokenType lexerTokenType)
{
switch (lexerTokenType)
{
case LexerTokenType.Text:
return "T";
case LexerTokenType.Whitespace:
return "WS";
case LexerTokenType.NewLine:
return "NL";
case LexerTokenType.Comment:
return "C";
default:
return lexerTokenType.ToString();
}
}
[Fact]
public void BatchParserTest()
{
Start("err-blockComment");
Start("err-blockComment2");
Start("err-varDefinition");
Start("err-varDefinition2");
Start("err-varDefinition3");
Start("err-varDefinition4");
Start("err-varDefinition5");
Start("err-varDefinition6");
Start("err-varDefinition7");
Start("err-varDefinition8");
Start("err-varDefinition9");
Start("err-variableRef");
Start("err-variableRef2");
Start("err-variableRef3");
Start("err-variableRef4");
Start("err-cycle1");
Start("input");
Start("input2");
Start("pass-blockComment");
Start("pass-lineComment");
Start("pass-lineComment2");
Start("pass-noBlockComments");
Start("pass-noLineComments");
Start("pass-varDefinition");
Start("pass-varDefinition2");
Start("pass-varDefinition3");
Start("pass-varDefinition4");
Start("pass-command-and-comment");
Assert.False(testFailed, "At least one of test cases failed. Check output for details.");
}
public void TestParser(string filename, StringBuilder output)
{
try
{
TestCommandHandler commandHandler = new TestCommandHandler(output);
Parser parser = new Parser(
commandHandler,
new TestVariableResolver(output),
new StreamReader(File.Open(filename, FileMode.Open)),
filename);
commandHandler.SetParser(parser);
parser.Parse();
}
catch (BatchParserException ex)
{
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));
}
}
private string GetPositionString(PositionStruct pos)
{
return string.Format(CultureInfo.InvariantCulture, "{0}:{1} [{2}]", pos.Line, pos.Column, pos.Offset);
}
private string GetTokenString(Token token)
{
if (token == null)
{
return "(null)";
}
else
{
string tokenText = token.Text;
if (tokenText != null)
{
tokenText = tokenText.Replace("\n", "\\n").Replace("\r", "\\r").Replace("\t", "\\t");
}
string tokenFilename = token.Filename;
tokenFilename = GetFilenameOnly(tokenFilename);
return string.Format(CultureInfo.CurrentCulture, "[Token {0} at {1}({2}:{3} [{4}] - {5}:{6} [{7}]): '{8}']",
token.TokenType,
tokenFilename,
token.Begin.Line, token.Begin.Column, token.Begin.Offset,
token.End.Line, token.End.Column, token.End.Offset,
tokenText);
}
}
internal static string GetFilenameOnly(string fullPath)
{
return fullPath != null ? Path.GetFileName(fullPath) : null;
}
public override void Run()
{
string inputFilename = GetTestscriptFilePath(CurrentTestName);
StringBuilder output = new StringBuilder();
TokenizeWithLexer(inputFilename, output);
TestParser(inputFilename, output);
string baselineFilename = GetBaselineFilePath(CurrentTestName);
string baseline;
try
{
baseline = GetFileContent(baselineFilename);
}
catch (FileNotFoundException)
{
baseline = string.Empty;
}
string outputString = output.ToString();
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;
}
}
}
}
//
// 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.Globalization;
using System.IO;
using System.Text;
using Microsoft.SqlTools.ServiceLayer.BatchParser;
using Microsoft.SqlTools.ServiceLayer.Test.Common;
using Microsoft.SqlTools.ServiceLayer.Test.Common.Baselined;
using Xunit;
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.BatchParser
{
public class BatchParserTests : BaselinedTest
{
private bool testFailed = false;
public BatchParserTests()
{
InitializeTest();
}
public void InitializeTest()
{
CategoryName = "BatchParser";
this.TraceOutputDirectory = RunEnvironmentInfo.GetTraceOutputLocation();
TestInitialize();
}
[Fact]
public void VerifyThrowOnUnresolvedVariable()
{
string script = "print '$(NotDefined)'";
StringBuilder output = new StringBuilder();
TestCommandHandler handler = new TestCommandHandler(output);
IVariableResolver resolver = new TestVariableResolver(new StringBuilder());
using (Parser p = new Parser(
handler,
resolver,
new StringReader(script),
"test"))
{
p.ThrowOnUnresolvedVariable = true;
handler.SetParser(p);
Assert.Throws<BatchParserException>(() => p.Parse());
}
}
private static Stream GenerateStreamFromString(string s)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
public void TokenizeWithLexer(string filename, StringBuilder output)
{
// 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
string input = File.ReadAllText(filename).Replace("\r\n", "\n");
var inputStream = GenerateStreamFromString(input);
using (Lexer lexer = new Lexer(new StreamReader(inputStream), filename))
{
string inputText = File.ReadAllText(filename);
inputText = inputText.Replace("\r\n", "\n");
StringBuilder roundtripTextBuilder = new StringBuilder();
StringBuilder outputBuilder = new StringBuilder();
StringBuilder tokenizedInput = new StringBuilder();
bool lexerError = false;
Token token = null;
try
{
do
{
lexer.ConsumeToken();
token = lexer.CurrentToken;
roundtripTextBuilder.Append(token.Text.Replace("\r\n", "\n"));
outputBuilder.AppendLine(GetTokenString(token));
tokenizedInput.Append('[').Append(GetTokenCode(token.TokenType)).Append(':').Append(token.Text.Replace("\r\n", "\n")).Append(']');
} while (token.TokenType != LexerTokenType.Eof);
}
catch (BatchParserException ex)
{
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:");
output.AppendLine("======================");
output.AppendLine(tokenizedInput.ToString());
output.AppendLine("Tokens:");
output.AppendLine("=======");
output.AppendLine(outputBuilder.ToString());
if (lexerError == false)
{
// Verify that all text from tokens can be recombined into original string
Assert.Equal<string>(inputText, roundtripTextBuilder.ToString());
}
}
}
private string GetTokenCode(LexerTokenType lexerTokenType)
{
switch (lexerTokenType)
{
case LexerTokenType.Text:
return "T";
case LexerTokenType.Whitespace:
return "WS";
case LexerTokenType.NewLine:
return "NL";
case LexerTokenType.Comment:
return "C";
default:
return lexerTokenType.ToString();
}
}
private static void CopyToOutput(string sourceDirectory, string filename)
{
File.Copy(Path.Combine(sourceDirectory, filename), filename, true);
FileUtilities.SetFileReadWrite(filename);
}
[Fact]
public void BatchParserTest()
{
CopyToOutput(FilesLocation, "TS-err-cycle1.txt");
CopyToOutput(FilesLocation, "cycle2.txt");
Start("err-blockComment");
Start("err-blockComment2");
Start("err-varDefinition");
Start("err-varDefinition2");
Start("err-varDefinition3");
Start("err-varDefinition4");
Start("err-varDefinition5");
Start("err-varDefinition6");
Start("err-varDefinition7");
Start("err-varDefinition8");
Start("err-varDefinition9");
Start("err-variableRef");
Start("err-variableRef2");
Start("err-variableRef3");
Start("err-variableRef4");
Start("err-cycle1");
Start("input");
Start("input2");
Start("pass-blockComment");
Start("pass-lineComment");
Start("pass-lineComment2");
Start("pass-noBlockComments");
Start("pass-noLineComments");
Start("pass-varDefinition");
Start("pass-varDefinition2");
Start("pass-varDefinition3");
Start("pass-varDefinition4");
Start("pass-command-and-comment");
Assert.False(testFailed, "At least one of test cases failed. Check output for details.");
}
public void TestParser(string filename, StringBuilder output)
{
try
{
// 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
TestCommandHandler commandHandler = new TestCommandHandler(output);
string input = File.ReadAllText(filename).Replace("\r\n", "\n");
var inputStream = GenerateStreamFromString(input);
StreamReader streamReader = new StreamReader(inputStream);
using (Parser parser = new Parser(
commandHandler,
new TestVariableResolver(output),
streamReader,
filename))
{
commandHandler.SetParser(parser);
parser.Parse();
}
}
catch (BatchParserException ex)
{
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));
}
}
private string GetPositionString(PositionStruct pos)
{
return string.Format(CultureInfo.InvariantCulture, "{0}:{1} [{2}]", pos.Line, pos.Column, pos.Offset);
}
private string GetTokenString(Token token)
{
if (token == null)
{
return "(null)";
}
else
{
string tokenText = token.Text;
if (tokenText != null)
{
tokenText = tokenText.Replace("\r\n", "\\n").Replace("\n", "\\n").Replace("\r", "\\r").Replace("\t", "\\t");
}
string tokenFilename = token.Filename;
tokenFilename = GetFilenameOnly(tokenFilename);
return string.Format(CultureInfo.CurrentCulture, "[Token {0} at {1}({2}:{3} [{4}] - {5}:{6} [{7}]): '{8}']",
token.TokenType,
tokenFilename,
token.Begin.Line, token.Begin.Column, token.Begin.Offset,
token.End.Line, token.End.Column, token.End.Offset,
tokenText);
}
}
internal static string GetFilenameOnly(string fullPath)
{
return fullPath != null ? Path.GetFileName(fullPath) : null;
}
public override void Run()
{
string inputFilename = GetTestscriptFilePath(CurrentTestName);
StringBuilder output = new StringBuilder();
TokenizeWithLexer(inputFilename, output);
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;
}
}
}
}

View File

@@ -1,454 +1,448 @@
//
// 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.Diagnostics;
using System.IO;
using System.Text;
using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.Test.Common.Baselined
{
/// <summary>
/// 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
/// </summary>
public abstract class BaselinedTest
{
/// <summary>
/// Holds the extension for the TestScripts
/// </summary>
private string _testScriptExtension;
/// <summary>
/// Holds the extensionf or the Baseline files
/// </summary>
private string _baselineExtension;
/// <summary>
/// Holds the path to the base location of both TestScripts and Baselines
/// </summary>
private string _testCategoryName;
/// <summary>
/// Holds the ROOT Dir for trace output
/// </summary>
private string _traceOutputDir;
/// <summary>
/// Holds the prefix for the baseline
/// </summary>
private string _baselinePrefix;
/// <summary>
/// Holds the prefix for the Testscript
/// </summary>
private string _testscriptPrefix;
/// <summary>
/// Holds the name of the current test
/// </summary>
private string _currentTestname;
private string _baselineSubDir = string.Empty;
public const string TestScriptDirectory = @"Testscripts\";
public const string BaselineDirectory = @"Baselines\";
/// <summary>
/// Gets/Sets the extension for the Testscript files
/// </summary>
public string TestscriptFileExtension
{
get
{
return _testScriptExtension;
}
set
{
if (string.IsNullOrEmpty(value))
throw new ArgumentException("TestscriptFileExtension needs a value");
_testScriptExtension = value;
}
}
/// <summary>
/// Gets/Sets the extension for the Baseline files
/// </summary>
public string BaselineFileExtension
{
get
{
return _baselineExtension;
}
set
{
if (string.IsNullOrEmpty(value))
throw new ArgumentException("BaselineFileExtension needs a value");
_baselineExtension = value;
}
}
/// <summary>
/// Gets/Sets the path to the base location of both test scripts and baseline files
/// </summary>
/// <remarks>
/// Just use the SubDir name
/// 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)
/// </remarks>
public string CategoryName
{
get
{
return _testCategoryName;
}
set
{
if (string.IsNullOrEmpty(value))
throw new ArgumentException("FileBaseLocation needs a value");
_testCategoryName = value;
}
}
/// <summary>
/// Gets/Sets the output base directory for trace output (null = no trace output)
/// </summary>
public string TraceOutputDirectory
{
get
{
return _traceOutputDir;
}
set
{
_traceOutputDir = value;
}
}
/// <summary>
/// Gets the full path of where the files will be pulled from
/// </summary>
public string FilesLocation
{
get
{
return Path.Combine(RunEnvironmentInfo.GetTestDataLocation(), CategoryName, TestScriptDirectory);
}
}
/// <summary>
/// Gets or Sets the sub directory in Baselines where the exected baseline results are located
/// </summary>
public string BaselinesSubdir
{
get
{
if (this._baselineSubDir == null)
this._baselineSubDir = string.Empty;
return this._baselineSubDir;
}
set { this._baselineSubDir = value; }
}
/// <summary>
/// Gets the full path of where the baseline files will be pulled from
/// </summary>
public string BaselineFilePath
{
get
{
return Path.Combine(RunEnvironmentInfo.GetTestDataLocation(), CategoryName, Path.Combine( BaselineDirectory, BaselinesSubdir ));
}
}
/// <summary>
/// Gets the full path of where the Trace will output
/// </summary>
public string TraceFilePath
{
get
{
return Path.Combine(Path.GetFullPath(TraceOutputDirectory), this.CategoryName, this.BaselinesSubdir);
}
}
/// <summary>
/// Gets/Sets the prefix used for baseline files
/// </summary>
public string BaselinePrefix
{
get
{
return _baselinePrefix;
}
set
{
if (string.IsNullOrEmpty(value))
throw new ArgumentException("BaselinePrefix needs a value");
_baselinePrefix = value;
}
}
/// <summary>
/// Gets/Sets the prefix used for testscript files
/// </summary>
public string TestscriptPrefix
{
get
{
return _testscriptPrefix;
}
set
{
if (string.IsNullOrEmpty(value))
throw new ArgumentException("TestscriptPrefix needs a value");
_testscriptPrefix = value;
}
}
/// <summary>
/// Gets/Sets the name of the current test
/// </summary>
public string CurrentTestName
{
get
{
return _currentTestname;
}
}
/// <summary>
/// Constructor
/// </summary>
public BaselinedTest()
{
Initialize();
}
/// <summary>
/// Initializes the class
/// </summary>
private void Initialize()
{
_testScriptExtension = _baselineExtension = "txt"; //default to txt
_testCategoryName = null;
string projectPath = Environment.GetEnvironmentVariable(Constants.ProjectPath);
if (projectPath != null)
{
_traceOutputDir = Path.Combine(projectPath, "trace");
}
else
{
_traceOutputDir = Environment.ExpandEnvironmentVariables(@"%SystemDrive%\trace\");
}
_baselinePrefix = "BL";
_testscriptPrefix = "TS";
}
/// <summary>
/// This method should be called whenever you do a [TestInitialize]
/// </summary>
public virtual void TestInitialize()
{
if (string.IsNullOrEmpty(_testCategoryName))
throw new ArgumentException("Set CategoryName to the name of the directory containing your Testscripts and Baseline files");
if (!Directory.Exists(FilesLocation))
throw new FileNotFoundException(string.Format("Path to Testscripts ([{0}]) does not exist.", FilesLocation));
if (!Directory.Exists(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)
Directory.CreateDirectory(TraceFilePath);
}
/// <summary>
/// Compares two strings and gives appropriate output
/// </summary>
/// <param name="actualContent">Actual string</param>
/// <param name="baselineContent">Expected string</param>
/// <remarks>Fails test if strings do not match; comparison is done using an InvariantCulture StringComparer</remarks>
public void CompareActualWithBaseline(string actualContent, string baselineContent)
{
int _compareResult = string.Compare(actualContent, baselineContent, StringComparison.OrdinalIgnoreCase);
if (_compareResult != 0)
{
Trace.WriteLine("Debug Info:");
Trace.WriteLine("========BEGIN=EXPECTED========");
Trace.WriteLine(baselineContent);
Trace.WriteLine("=========END=EXPECTED=========");
Trace.WriteLine("=========BEGIN=ACTUAL=========");
Trace.WriteLine(actualContent);
Trace.WriteLine("==========END=ACTUAL==========");
Assert.True(false, string.Format("Comparison failed! (actualContent {0} baselineContent)", (_compareResult < 0 ? "<" : ">"))); //we already know it is not equal
}
else
{
Trace.WriteLine("Compare match! All is fine...");
}
}
/// <summary>
/// Gets the name of the testscript with the provided name
/// </summary>
/// <param name="name">Name of the test</param>
/// <returns>the path to the baseline file</returns>
/// <remarks>Asserts that file exists</remarks>
public string GetTestscriptFilePath(string name)
{
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));
return retVal;
}
/// <summary>
/// Gets the name of the test script with the provided name and the provided index
/// </summary>
/// <param name="name">Name of the test</param>
/// <param name="index">File index</param>
/// <returns>the path to the baseline file</returns>
/// <remarks>Asserts that file exists</remarks>
public string GetTestscriptFilePath(string name, int index)
{
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));
return retVal;
}
/// <summary>
/// Gets the formatted baseline file name
/// </summary>
/// <param name="name">Name of the test</param>
public string GetBaselineFileName(string name)
{
return string.Format("{0}-{1}.{2}", BaselinePrefix, name, BaselineFileExtension);
}
/// <summary>
/// Gets the file path to the baseline file for the named case
/// </summary>
/// <param name="name">Name of the test</param>
/// <returns>the path to the baseline file</returns>
/// <remarks>Asserts that file exists</remarks>
public string GetBaselineFilePath(string name, bool assertIfNotFound)
{
string retVal = Path.Combine(BaselineFilePath, GetBaselineFileName(name));
if (assertIfNotFound)
{
Assert.True(File.Exists(retVal), string.Format("Baseline [{0}] does not exist", retVal));
}
return retVal;
}
public string GetBaselineFilePath(string name)
{
return GetBaselineFilePath(name, true);
}
/// <summary>
/// Gets the contents of a file
/// </summary>
/// <param name="path">Path of the file to read</param>
/// <returns>The contents of the file</returns>
public string GetFileContent(string path)
{
Trace.WriteLine(string.Format("GetFileContent for [{0}]", Path.GetFullPath(path)));
using (StreamReader sr = new StreamReader(File.Open(path, FileMode.Open), Encoding.Unicode))
{
return sr.ReadToEnd();
}
}
/// <summary>
/// Dumps the text to a Trace file
/// </summary>
/// <param name="testName">Test name used to create file name</param>
/// <param name="text">Text to dump to the trace file</param>
/// <remarks>Overwrites whatever is already in the file (if anything)</remarks>
public string DumpToTrace(string testName, string text)
{
if (string.IsNullOrEmpty(TraceFilePath))
{
return string.Empty; //nothing to do
}
string traceFile = Path.Combine(TraceFilePath, GetBaselineFileName(testName));
if (File.Exists(traceFile))
{
Trace.Write(string.Format("Overwriting existing trace file [{0}]", traceFile));
File.Delete(traceFile);
}
else
{
Trace.Write(string.Format("Dumping to trace file [{0}]", traceFile));
}
if (Directory.Exists(TraceFilePath) == false)
{
Directory.CreateDirectory(TraceFilePath);
}
WriteTraceFile(traceFile, text);
return traceFile;
}
/// <summary>
/// Writes the context to the trace file
/// </summary>
/// <param name="traceFile">The file name for the trace output</param>
/// <param name="text">The content for the trace file</param>
public void WriteTraceFile(string traceFile, string text)
{
Stream traceStream = GetStreamFromString(traceFile);
using (StreamWriter sw = new StreamWriter(traceStream, Encoding.Unicode))
{
sw.Write(text);
sw.Flush();
sw.Dispose();
}
}
/// <summary>
/// Converts a string to a stream
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
private Stream GetStreamFromString(string s)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
/// <summary>
/// Starts the actual running of the test after nicely initializing
/// </summary>
/// <param name="testname">Name of the test</param>
public void Start(string testname)
{
Trace.WriteLine(string.Format("Starting test named [{0}]", testname));
_currentTestname = testname;
Run();
Trace.WriteLine("Test Completed");
}
/// <summary>
/// Runs the actual test
/// </summary>
/// <remarks>Override this method to put in your test logic</remarks>
public abstract void Run();
}
}
//
// 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.Diagnostics;
using System.IO;
using System.Text;
using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.Test.Common.Baselined
{
/// <summary>
/// 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
/// </summary>
public abstract class BaselinedTest
{
/// <summary>
/// Holds the extension for the TestScripts
/// </summary>
private string _testScriptExtension;
/// <summary>
/// Holds the extensionf or the Baseline files
/// </summary>
private string _baselineExtension;
/// <summary>
/// Holds the path to the base location of both TestScripts and Baselines
/// </summary>
private string _testCategoryName;
/// <summary>
/// Holds the ROOT Dir for trace output
/// </summary>
private string _traceOutputDir;
/// <summary>
/// Holds the prefix for the baseline
/// </summary>
private string _baselinePrefix;
/// <summary>
/// Holds the prefix for the Testscript
/// </summary>
private string _testscriptPrefix;
/// <summary>
/// Holds the name of the current test
/// </summary>
private string _currentTestname;
private string _baselineSubDir = string.Empty;
public const string TestScriptDirectory = @"Testscripts\";
public const string BaselineDirectory = @"Baselines\";
/// <summary>
/// Gets/Sets the extension for the Testscript files
/// </summary>
public string TestscriptFileExtension
{
get
{
return _testScriptExtension;
}
set
{
if (string.IsNullOrEmpty(value))
throw new ArgumentException("TestscriptFileExtension needs a value");
_testScriptExtension = value;
}
}
/// <summary>
/// Gets/Sets the extension for the Baseline files
/// </summary>
public string BaselineFileExtension
{
get
{
return _baselineExtension;
}
set
{
if (string.IsNullOrEmpty(value))
throw new ArgumentException("BaselineFileExtension needs a value");
_baselineExtension = value;
}
}
/// <summary>
/// Gets/Sets the path to the base location of both test scripts and baseline files
/// </summary>
/// <remarks>
/// Just use the SubDir name
/// 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)
/// </remarks>
public string CategoryName
{
get
{
return _testCategoryName;
}
set
{
if (string.IsNullOrEmpty(value))
throw new ArgumentException("FileBaseLocation needs a value");
_testCategoryName = value;
}
}
/// <summary>
/// Gets/Sets the output base directory for trace output (null = no trace output)
/// </summary>
public string TraceOutputDirectory
{
get
{
return _traceOutputDir;
}
set
{
_traceOutputDir = value;
}
}
/// <summary>
/// Gets the full path of where the files will be pulled from
/// </summary>
public string FilesLocation
{
get
{
return Path.Combine(RunEnvironmentInfo.GetTestDataLocation(), CategoryName, TestScriptDirectory);
}
}
/// <summary>
/// Gets or Sets the sub directory in Baselines where the exected baseline results are located
/// </summary>
public string BaselinesSubdir
{
get
{
if (this._baselineSubDir == null)
this._baselineSubDir = string.Empty;
return this._baselineSubDir;
}
set { this._baselineSubDir = value; }
}
/// <summary>
/// Gets the full path of where the baseline files will be pulled from
/// </summary>
public string BaselineFilePath
{
get
{
return Path.Combine(RunEnvironmentInfo.GetTestDataLocation(), CategoryName, Path.Combine( BaselineDirectory, BaselinesSubdir ));
}
}
/// <summary>
/// Gets the full path of where the Trace will output
/// </summary>
public string TraceFilePath
{
get
{
return Path.Combine(Path.GetFullPath(TraceOutputDirectory), this.CategoryName, this.BaselinesSubdir);
}
}
/// <summary>
/// Gets/Sets the prefix used for baseline files
/// </summary>
public string BaselinePrefix
{
get
{
return _baselinePrefix;
}
set
{
if (string.IsNullOrEmpty(value))
throw new ArgumentException("BaselinePrefix needs a value");
_baselinePrefix = value;
}
}
/// <summary>
/// Gets/Sets the prefix used for testscript files
/// </summary>
public string TestscriptPrefix
{
get
{
return _testscriptPrefix;
}
set
{
if (string.IsNullOrEmpty(value))
throw new ArgumentException("TestscriptPrefix needs a value");
_testscriptPrefix = value;
}
}
/// <summary>
/// Gets/Sets the name of the current test
/// </summary>
public string CurrentTestName
{
get
{
return _currentTestname;
}
}
/// <summary>
/// Constructor
/// </summary>
public BaselinedTest()
{
Initialize();
}
/// <summary>
/// Initializes the class
/// </summary>
private void Initialize()
{
_testScriptExtension = _baselineExtension = "txt"; //default to txt
_testCategoryName = null;
string projectPath = Environment.GetEnvironmentVariable(Constants.ProjectPath);
if (projectPath != null)
{
_traceOutputDir = Path.Combine(projectPath, "trace");
}
else
{
_traceOutputDir = Environment.ExpandEnvironmentVariables(@"%SystemDrive%\trace\");
}
_baselinePrefix = "BL";
_testscriptPrefix = "TS";
}
/// <summary>
/// This method should be called whenever you do a [TestInitialize]
/// </summary>
public virtual void TestInitialize()
{
if (string.IsNullOrEmpty(_testCategoryName))
throw new ArgumentException("Set CategoryName to the name of the directory containing your Testscripts and Baseline files");
if (!Directory.Exists(FilesLocation))
throw new FileNotFoundException(string.Format("Path to Testscripts ([{0}]) does not exist.", FilesLocation));
if (!Directory.Exists(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)
Directory.CreateDirectory(TraceFilePath);
}
/// <summary>
/// Compares two strings and gives appropriate output
/// </summary>
/// <param name="actualContent">Actual string</param>
/// <param name="baselineContent">Expected string</param>
/// <remarks>Fails test if strings do not match; comparison is done using an InvariantCulture StringComparer</remarks>
public void CompareActualWithBaseline(string actualContent, string baselineContent)
{
int _compareResult = string.Compare(actualContent, baselineContent, StringComparison.OrdinalIgnoreCase);
if (_compareResult != 0)
{
Trace.WriteLine("Debug Info:");
Trace.WriteLine("========BEGIN=EXPECTED========");
Trace.WriteLine(baselineContent);
Trace.WriteLine("=========END=EXPECTED=========");
Trace.WriteLine("=========BEGIN=ACTUAL=========");
Trace.WriteLine(actualContent);
Trace.WriteLine("==========END=ACTUAL==========");
Assert.True(false, string.Format("Comparison failed! (actualContent {0} baselineContent)", (_compareResult < 0 ? "<" : ">"))); //we already know it is not equal
}
else
{
Trace.WriteLine("Compare match! All is fine...");
}
}
/// <summary>
/// Gets the name of the testscript with the provided name
/// </summary>
/// <param name="name">Name of the test</param>
/// <returns>the path to the baseline file</returns>
/// <remarks>Asserts that file exists</remarks>
public string GetTestscriptFilePath(string name)
{
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));
return retVal;
}
/// <summary>
/// Gets the name of the test script with the provided name and the provided index
/// </summary>
/// <param name="name">Name of the test</param>
/// <param name="index">File index</param>
/// <returns>the path to the baseline file</returns>
/// <remarks>Asserts that file exists</remarks>
public string GetTestscriptFilePath(string name, int index)
{
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));
return retVal;
}
/// <summary>
/// Gets the formatted baseline file name
/// </summary>
/// <param name="name">Name of the test</param>
public string GetBaselineFileName(string name)
{
return string.Format("{0}-{1}.{2}", BaselinePrefix, name, BaselineFileExtension);
}
/// <summary>
/// Gets the file path to the baseline file for the named case
/// </summary>
/// <param name="name">Name of the test</param>
/// <returns>the path to the baseline file</returns>
/// <remarks>Asserts that file exists</remarks>
public string GetBaselineFilePath(string name, bool assertIfNotFound)
{
string retVal = Path.Combine(BaselineFilePath, GetBaselineFileName(name));
if (assertIfNotFound)
{
Assert.True(File.Exists(retVal), string.Format("Baseline [{0}] does not exist", retVal));
}
return retVal;
}
public string GetBaselineFilePath(string name)
{
return GetBaselineFilePath(name, true);
}
/// <summary>
/// Gets the contents of a file
/// </summary>
/// <param name="path">Path of the file to read</param>
/// <returns>The contents of the file</returns>
public string GetFileContent(string path)
{
Trace.WriteLine(string.Format("GetFileContent for [{0}]", Path.GetFullPath(path)));
using (StreamReader sr = new StreamReader(File.Open(path, FileMode.Open), Encoding.UTF8))
{
return sr.ReadToEnd();
}
}
/// <summary>
/// Dumps the text to a Trace file
/// </summary>
/// <param name="testName">Test name used to create file name</param>
/// <param name="text">Text to dump to the trace file</param>
/// <remarks>Overwrites whatever is already in the file (if anything)</remarks>
public string DumpToTrace(string testName, string text)
{
if (string.IsNullOrEmpty(TraceFilePath))
{
return string.Empty; //nothing to do
}
string traceFile = Path.Combine(TraceFilePath, GetBaselineFileName(testName));
if (File.Exists(traceFile))
{
Trace.Write(string.Format("Overwriting existing trace file [{0}]", traceFile));
File.Delete(traceFile);
}
else
{
Trace.Write(string.Format("Dumping to trace file [{0}]", traceFile));
}
if (Directory.Exists(TraceFilePath) == false)
{
Directory.CreateDirectory(TraceFilePath);
}
WriteTraceFile(traceFile, text);
return traceFile;
}
/// <summary>
/// Writes the context to the trace file
/// </summary>
/// <param name="traceFile">The file name for the trace output</param>
/// <param name="text">The content for the trace file</param>
public void WriteTraceFile(string traceFile, string text)
{
File.WriteAllText(traceFile, text);
}
/// <summary>
/// Converts a string to a stream
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
private Stream GetStreamFromString(string s)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
/// <summary>
/// Starts the actual running of the test after nicely initializing
/// </summary>
/// <param name="testname">Name of the test</param>
public void Start(string testname)
{
Trace.WriteLine(string.Format("Starting test named [{0}]", testname));
_currentTestname = testname;
Run();
Trace.WriteLine("Test Completed");
}
/// <summary>
/// Runs the actual test
/// </summary>
/// <remarks>Override this method to put in your test logic</remarks>
public abstract void Run();
}
}

View File

@@ -1,73 +1,112 @@
//
// 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 System.Reflection;
using System.Runtime.InteropServices;
namespace Microsoft.SqlTools.ServiceLayer.Test.Common
{
/// <summary>
/// Contains environment information needed when running tests.
/// </summary>
public class RunEnvironmentInfo
{
private static string cachedTestFolderPath;
public static bool IsLabMode()
{
string bvtLabRoot = Environment.GetEnvironmentVariable(Constants.BVTLocalRoot);
if (string.IsNullOrEmpty(bvtLabRoot))
{
return false;
}
return true;
}
/// <summary>
/// Location of all test data (baselines, etc).
/// </summary>
/// <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 projectPath = Environment.GetEnvironmentVariable(Constants.ProjectPath);
if (projectPath != null)
{
testFolderPath = Path.Combine(projectPath, testPath);
}
else
{
if (cachedTestFolderPath != null)
{
testFolderPath = cachedTestFolderPath;
}
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));
testFolderPath = Path.Combine(defaultPath, "Microsoft.SqlTools.ServiceLayer.Test.Common", "TestData");
cachedTestFolderPath = testFolderPath;
}
}
return testFolderPath;
}
private static string GoUpNDirectories(int n)
{
string up = ".." + (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "\\" : "/");
return string.Concat(Enumerable.Repeat(up, n));
}
}
}
//
// 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 System.Reflection;
using System.Runtime.InteropServices;
namespace Microsoft.SqlTools.ServiceLayer.Test.Common
{
/// <summary>
/// Contains environment information needed when running tests.
/// </summary>
public class RunEnvironmentInfo
{
private static string cachedTestFolderPath;
private static string cachedTraceFolderPath;
public static bool IsLabMode()
{
string bvtLabRoot = Environment.GetEnvironmentVariable(Constants.BVTLocalRoot);
if (string.IsNullOrEmpty(bvtLabRoot))
{
return false;
}
return true;
}
/// <summary>
/// Location of all test data (baselines, etc).
/// </summary>
/// <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 projectPath = Environment.GetEnvironmentVariable(Constants.ProjectPath);
if (projectPath != null)
{
testFolderPath = Path.Combine(projectPath, testPath);
}
else
{
if (cachedTestFolderPath != null)
{
testFolderPath = cachedTestFolderPath;
}
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));
testFolderPath = Path.Combine(defaultPath, "Microsoft.SqlTools.ServiceLayer.Test.Common", "TestData");
cachedTestFolderPath = testFolderPath;
}
}
return testFolderPath;
}
/// <summary>
/// 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));
}
}
}

View File

@@ -1,4 +1,4 @@
GO 2
GO 2
BEGIN
:r input-2.txt
:r "input-2.txt"

View File

@@ -135,7 +135,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common
}
TestServiceProvider.hasInitServices = true;
const string hostName = "SQ Tools Test Service Host";
const string hostName = "SQL Tools Test Service Host";
const string hostProfileId = "SQLToolsTestService";
Version hostVersion = new Version(1, 0);