// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixTestTools
{
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using WixInternal.TestSupport;
using Xunit;
public class TestTool : ExternalExecutable
{
///
/// Constructor for a TestTool
///
public TestTool()
: this(null)
{
}
///
/// Constructor for a TestTool
///
/// The full path to the tool. Eg. c:\bin\candle.exe
public TestTool(string toolFile)
: base(toolFile)
{
this.PrintOutputToConsole = true;
}
///
/// The alternate expected exit code of the tool
///
public int? AlternateExitCode { get; set; }
///
/// The arguments to pass to the tool
///
public virtual string Arguments { get; set; }
///
/// Stores the errors that occurred when a run was checked against its expected results
///
public List Errors { get; set; }
///
/// A list of Regex's that are expected to match stderr
///
public List ExpectedErrorRegexs { get; set; } = new List();
///
/// The expected error strings to stderr
///
public List ExpectedErrorStrings { get; set; } = new List();
///
/// The expected exit code of the tool
///
public int? ExpectedExitCode { get; set; }
///
/// A list of Regex's that are expected to match stdout
///
public List ExpectedOutputRegexs { get; set; } = new List();
///
/// The expected output strings to stdout
///
public List ExpectedOutputStrings { get; set; } = new List();
///
/// Print output from the tool execution to the console
///
public bool PrintOutputToConsole { get; set; }
///
/// The working directory of the tool
///
public string WorkingDirectory { get; set; }
///
/// Print the errors from the last run
///
public void PrintErrors()
{
if (null != this.Errors)
{
Console.WriteLine("Errors:");
foreach (string error in this.Errors)
{
Console.WriteLine(error);
}
}
}
///
/// Run the tool
///
/// The results of the run
public ExternalExecutableResult Run()
{
return this.Run(true);
}
///
/// Run the tool
///
/// Throw an exception if the expected results don't match the actual results
/// Thrown when the expected results don't match the actual results
/// The results of the run
public virtual ExternalExecutableResult Run(bool assertOnError)
{
var result = this.Run(this.Arguments, workingDirectory: this.WorkingDirectory ?? String.Empty);
if (this.PrintOutputToConsole)
{
Console.WriteLine(FormatResult(result));
}
this.Errors = this.CheckResult(result);
if (assertOnError && 0 < this.Errors.Count)
{
if (this.PrintOutputToConsole)
{
this.PrintErrors();
}
WixAssert.StringCollectionEmpty(this.Errors);
}
return result;
}
///
/// Checks that the result from a run matches the expected results
///
/// A result from a run
/// A list of errors
public virtual List CheckResult(ExternalExecutableResult result)
{
List errors = new List();
// Verify that the expected return code matched the actual return code
if (null != this.ExpectedExitCode && this.ExpectedExitCode != result.ExitCode &&
(null == this.AlternateExitCode || this.AlternateExitCode != result.ExitCode))
{
errors.Add(String.Format("Expected exit code {0} did not match actual exit code {1}", this.ExpectedExitCode, result.ExitCode));
}
var standardErrorString = String.Join(Environment.NewLine, result.StandardError);
// Verify that the expected error string are in stderr
if (null != this.ExpectedErrorStrings)
{
foreach (string expectedString in this.ExpectedErrorStrings)
{
if (!standardErrorString.Contains(expectedString))
{
errors.Add(String.Format("The text '{0}' was not found in stderr", expectedString));
}
}
}
var standardOutputString = String.Join(Environment.NewLine, result.StandardOutput);
// Verify that the expected output string are in stdout
if (null != this.ExpectedOutputStrings)
{
foreach (string expectedString in this.ExpectedOutputStrings)
{
if (!standardOutputString.Contains(expectedString))
{
errors.Add(String.Format("The text '{0}' was not found in stdout", expectedString));
}
}
}
// Verify that the expected regular expressions match stderr
if (null != this.ExpectedOutputRegexs)
{
foreach (Regex expectedRegex in this.ExpectedOutputRegexs)
{
if (!expectedRegex.IsMatch(standardOutputString))
{
errors.Add(String.Format("Regex {0} did not match stdout", expectedRegex.ToString()));
}
}
}
// Verify that the expected regular expressions match stdout
if (null != this.ExpectedErrorRegexs)
{
foreach (Regex expectedRegex in this.ExpectedErrorRegexs)
{
if (!expectedRegex.IsMatch(standardErrorString))
{
errors.Add(String.Format("Regex {0} did not match stderr", expectedRegex.ToString()));
}
}
}
return errors;
}
///
/// Clears all of the expected results and resets them to the default values
///
public virtual void SetDefaultExpectedResults()
{
this.ExpectedErrorRegexs = new List();
this.ExpectedErrorStrings = new List();
this.ExpectedExitCode = null;
this.ExpectedOutputRegexs = new List();
this.ExpectedOutputStrings = new List();
}
///
/// Returns a string with data contained in the result.
///
/// A string
private static string FormatResult(ExternalExecutableResult result)
{
var returnValue = new StringBuilder();
returnValue.AppendLine();
returnValue.AppendLine("----------------");
returnValue.AppendLine("Tool run result:");
returnValue.AppendLine("----------------");
returnValue.AppendLine("Command:");
returnValue.AppendLine($"\"{result.FileName}\" {result.Arguments}");
returnValue.AppendLine();
returnValue.AppendLine("Standard Output:");
foreach (var line in result.StandardOutput ?? new string[0])
{
returnValue.AppendLine(line);
}
returnValue.AppendLine("Standard Error:");
foreach (var line in result.StandardError ?? new string[0])
{
returnValue.AppendLine(line);
}
returnValue.AppendLine("Exit Code:");
returnValue.AppendLine(Convert.ToString(result.ExitCode));
returnValue.AppendLine("----------------");
return returnValue.ToString();
}
}
}