// // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // #nullable disable using System; using System.Diagnostics; using System.IO; using System.Text; using NUnit.Framework; namespace Microsoft.SqlTools.ServiceLayer.Test.Common.Baselined { /// /// 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 /// public abstract class BaselinedTest { /// /// Holds the extension for the TestScripts /// private string _testScriptExtension; /// /// Holds the extensionf or the Baseline files /// private string _baselineExtension; /// /// Holds the path to the base location of both TestScripts and Baselines /// private string _testCategoryName; /// /// Holds the ROOT Dir for trace output /// private string _traceOutputDir; /// /// Holds the prefix for the baseline /// private string _baselinePrefix; /// /// Holds the prefix for the Testscript /// private string _testscriptPrefix; /// /// Holds the name of the current test /// private string _currentTestname; private string _baselineSubDir = string.Empty; public const string TestScriptDirectory = @"Testscripts"; public const string BaselineDirectory = @"Baselines"; /// /// Gets/Sets the extension for the Testscript files /// public string TestscriptFileExtension { get { return _testScriptExtension; } set { if (string.IsNullOrEmpty(value)) throw new ArgumentException("TestscriptFileExtension needs a value"); _testScriptExtension = value; } } /// /// Gets/Sets the extension for the Baseline files /// public string BaselineFileExtension { get { return _baselineExtension; } set { if (string.IsNullOrEmpty(value)) throw new ArgumentException("BaselineFileExtension needs a value"); _baselineExtension = value; } } /// /// Gets/Sets the path to the base location of both test scripts and baseline files /// /// /// 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) /// public string CategoryName { get { return _testCategoryName; } set { if (string.IsNullOrEmpty(value)) throw new ArgumentException("FileBaseLocation needs a value"); _testCategoryName = value; } } /// /// Gets/Sets the output base directory for trace output (null = no trace output) /// public string TraceOutputDirectory { get { return _traceOutputDir; } set { _traceOutputDir = value; } } /// /// Gets the full path of where the files will be pulled from /// public string FilesLocation { get { return Path.Combine(RunEnvironmentInfo.GetTestDataLocation(), CategoryName, TestScriptDirectory); } } /// /// Gets or Sets the sub directory in Baselines where the exected baseline results are located /// public string BaselinesSubdir { get { this._baselineSubDir ??= string.Empty; return this._baselineSubDir; } set { this._baselineSubDir = value; } } /// /// Gets the full path of where the baseline files will be pulled from /// public string BaselineFilePath { get { return Path.Combine(RunEnvironmentInfo.GetTestDataLocation(), CategoryName, Path.Combine( BaselineDirectory, BaselinesSubdir )); } } /// /// Gets the full path of where the Trace will output /// public string TraceFilePath { get { return Path.Combine(Path.GetFullPath(TraceOutputDirectory), this.CategoryName, this.BaselinesSubdir); } } /// /// Gets/Sets the prefix used for baseline files /// public string BaselinePrefix { get { return _baselinePrefix; } set { if (string.IsNullOrEmpty(value)) throw new ArgumentException("BaselinePrefix needs a value"); _baselinePrefix = value; } } /// /// Gets/Sets the prefix used for testscript files /// public string TestscriptPrefix { get { return _testscriptPrefix; } set { if (string.IsNullOrEmpty(value)) throw new ArgumentException("TestscriptPrefix needs a value"); _testscriptPrefix = value; } } /// /// Gets/Sets the name of the current test /// public string CurrentTestName { get { return _currentTestname; } } /// /// Constructor /// public BaselinedTest() { Initialize(); } /// /// Initializes the class /// 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"; } /// /// This method should be called whenever you do a [TestInitialize] /// 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); } /// /// Gets the name of the testscript with the provided name /// /// Name of the test /// the path to the baseline file /// Asserts that file exists 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; } /// /// Gets the name of the test script with the provided name and the provided index /// /// Name of the test /// File index /// the path to the baseline file /// Asserts that file exists 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; } /// /// Gets the formatted baseline file name /// /// Name of the test public string GetBaselineFileName(string name) { return string.Format("{0}-{1}.{2}", BaselinePrefix, name, BaselineFileExtension); } /// /// Gets the file path to the baseline file for the named case /// /// Name of the test /// the path to the baseline file /// Asserts that file exists 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); } /// /// Gets the contents of a file /// /// Path of the file to read /// The contents of the file 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(); } } /// /// Dumps the text to a Trace file /// /// Test name used to create file name /// Text to dump to the trace file /// Overwrites whatever is already in the file (if anything) 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; } /// /// Writes the context to the trace file /// /// The file name for the trace output /// The content for the trace file public void WriteTraceFile(string traceFile, string text) { File.WriteAllText(traceFile, text); } /// /// Converts a string to a stream /// /// /// private Stream GetStreamFromString(string s) { MemoryStream stream = new MemoryStream(); StreamWriter writer = new StreamWriter(stream); writer.Write(s); writer.Flush(); stream.Position = 0; return stream; } /// /// Starts the actual running of the test after nicely initializing /// /// Name of the test public void Start(string testname) { Trace.WriteLine(string.Format("Starting test named [{0}]", testname)); _currentTestname = testname; Run(); Trace.WriteLine("Test Completed"); } /// /// Runs the actual test /// /// Override this method to put in your test logic public abstract void Run(); } }