main
cs 251 lines 8.85 KB
Raw
1 // 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.
2
3 namespace WixTestTools
4 {
5 using System;
6 using System.Collections.Generic;
7 using System.Text;
8 using System.Text.RegularExpressions;
9 using WixInternal.TestSupport;
10 using Xunit;
11
12 public class TestTool : ExternalExecutable
13 {
14 /// <summary>
15 /// Constructor for a TestTool
16 /// </summary>
17 public TestTool()
18 : this(null)
19 {
20 }
21
22 /// <summary>
23 /// Constructor for a TestTool
24 /// </summary>
25 /// <param name="toolFile">The full path to the tool. Eg. c:\bin\candle.exe</param>
26 public TestTool(string toolFile)
27 : base(toolFile)
28 {
29 this.PrintOutputToConsole = true;
30 }
31
32 /// <summary>
33 /// The alternate expected exit code of the tool
34 /// </summary>
35 public int? AlternateExitCode { get; set; }
36
37 /// <summary>
38 /// The arguments to pass to the tool
39 /// </summary>
40 public virtual string Arguments { get; set; }
41
42 /// <summary>
43 /// Stores the errors that occurred when a run was checked against its expected results
44 /// </summary>
45 public List<string> Errors { get; set; }
46
47 /// <summary>
48 /// A list of Regex's that are expected to match stderr
49 /// </summary>
50 public List<Regex> ExpectedErrorRegexs { get; set; } = new List<Regex>();
51
52 /// <summary>
53 /// The expected error strings to stderr
54 /// </summary>
55 public List<string> ExpectedErrorStrings { get; set; } = new List<string>();
56
57 /// <summary>
58 /// The expected exit code of the tool
59 /// </summary>
60 public int? ExpectedExitCode { get; set; }
61
62 /// <summary>
63 /// A list of Regex's that are expected to match stdout
64 /// </summary>
65 public List<Regex> ExpectedOutputRegexs { get; set; } = new List<Regex>();
66
67 /// <summary>
68 /// The expected output strings to stdout
69 /// </summary>
70 public List<string> ExpectedOutputStrings { get; set; } = new List<string>();
71
72 /// <summary>
73 /// Print output from the tool execution to the console
74 /// </summary>
75 public bool PrintOutputToConsole { get; set; }
76
77 /// <summary>
78 /// The working directory of the tool
79 /// </summary>
80 public string WorkingDirectory { get; set; }
81
82 /// <summary>
83 /// Print the errors from the last run
84 /// </summary>
85 public void PrintErrors()
86 {
87 if (null != this.Errors)
88 {
89 Console.WriteLine("Errors:");
90
91 foreach (string error in this.Errors)
92 {
93 Console.WriteLine(error);
94 }
95 }
96 }
97
98 /// <summary>
99 /// Run the tool
100 /// </summary>
101 /// <returns>The results of the run</returns>
102 public ExternalExecutableResult Run()
103 {
104 return this.Run(true);
105 }
106
107 /// <summary>
108 /// Run the tool
109 /// </summary>
110 /// <param name="exceptionOnError">Throw an exception if the expected results don't match the actual results</param>
111 /// <exception cref="System.Exception">Thrown when the expected results don't match the actual results</exception>
112 /// <returns>The results of the run</returns>
113 public virtual ExternalExecutableResult Run(bool assertOnError)
114 {
115 var result = this.Run(this.Arguments, workingDirectory: this.WorkingDirectory ?? String.Empty);
116
117 if (this.PrintOutputToConsole)
118 {
119 Console.WriteLine(FormatResult(result));
120 }
121
122 this.Errors = this.CheckResult(result);
123
124 if (assertOnError && 0 < this.Errors.Count)
125 {
126 if (this.PrintOutputToConsole)
127 {
128 this.PrintErrors();
129 }
130
131 WixAssert.StringCollectionEmpty(this.Errors);
132 }
133
134 return result;
135 }
136
137 /// <summary>
138 /// Checks that the result from a run matches the expected results
139 /// </summary>
140 /// <param name="result">A result from a run</param>
141 /// <returns>A list of errors</returns>
142 public virtual List<string> CheckResult(ExternalExecutableResult result)
143 {
144 List<string> errors = new List<string>();
145
146 // Verify that the expected return code matched the actual return code
147 if (null != this.ExpectedExitCode && this.ExpectedExitCode != result.ExitCode &&
148 (null == this.AlternateExitCode || this.AlternateExitCode != result.ExitCode))
149 {
150 errors.Add(String.Format("Expected exit code {0} did not match actual exit code {1}", this.ExpectedExitCode, result.ExitCode));
151 }
152
153 var standardErrorString = String.Join(Environment.NewLine, result.StandardError);
154
155 // Verify that the expected error string are in stderr
156 if (null != this.ExpectedErrorStrings)
157 {
158 foreach (string expectedString in this.ExpectedErrorStrings)
159 {
160 if (!standardErrorString.Contains(expectedString))
161 {
162 errors.Add(String.Format("The text '{0}' was not found in stderr", expectedString));
163 }
164 }
165 }
166
167 var standardOutputString = String.Join(Environment.NewLine, result.StandardOutput);
168
169 // Verify that the expected output string are in stdout
170 if (null != this.ExpectedOutputStrings)
171 {
172 foreach (string expectedString in this.ExpectedOutputStrings)
173 {
174 if (!standardOutputString.Contains(expectedString))
175 {
176 errors.Add(String.Format("The text '{0}' was not found in stdout", expectedString));
177 }
178 }
179 }
180
181 // Verify that the expected regular expressions match stderr
182 if (null != this.ExpectedOutputRegexs)
183 {
184 foreach (Regex expectedRegex in this.ExpectedOutputRegexs)
185 {
186 if (!expectedRegex.IsMatch(standardOutputString))
187 {
188 errors.Add(String.Format("Regex {0} did not match stdout", expectedRegex.ToString()));
189 }
190 }
191 }
192
193 // Verify that the expected regular expressions match stdout
194 if (null != this.ExpectedErrorRegexs)
195 {
196 foreach (Regex expectedRegex in this.ExpectedErrorRegexs)
197 {
198 if (!expectedRegex.IsMatch(standardErrorString))
199 {
200 errors.Add(String.Format("Regex {0} did not match stderr", expectedRegex.ToString()));
201 }
202 }
203 }
204
205 return errors;
206 }
207
208 /// <summary>
209 /// Clears all of the expected results and resets them to the default values
210 /// </summary>
211 public virtual void SetDefaultExpectedResults()
212 {
213 this.ExpectedErrorRegexs = new List<Regex>();
214 this.ExpectedErrorStrings = new List<string>();
215 this.ExpectedExitCode = null;
216 this.ExpectedOutputRegexs = new List<Regex>();
217 this.ExpectedOutputStrings = new List<string>();
218 }
219
220 /// <summary>
221 /// Returns a string with data contained in the result.
222 /// </summary>
223 /// <returns>A string</returns>
224 private static string FormatResult(ExternalExecutableResult result)
225 {
226 var returnValue = new StringBuilder();
227 returnValue.AppendLine();
228 returnValue.AppendLine("----------------");
229 returnValue.AppendLine("Tool run result:");
230 returnValue.AppendLine("----------------");
231 returnValue.AppendLine("Command:");
232 returnValue.AppendLine($"\"{result.FileName}\" {result.Arguments}");
233 returnValue.AppendLine();
234 returnValue.AppendLine("Standard Output:");
235 foreach (var line in result.StandardOutput ?? new string[0])
236 {
237 returnValue.AppendLine(line);
238 }
239 returnValue.AppendLine("Standard Error:");
240 foreach (var line in result.StandardError ?? new string[0])
241 {
242 returnValue.AppendLine(line);
243 }
244 returnValue.AppendLine("Exit Code:");
245 returnValue.AppendLine(Convert.ToString(result.ExitCode));
246 returnValue.AppendLine("----------------");
247
248 return returnValue.ToString();
249 }
250 }
251 }