Skip to content

Commit 86b835d

Browse files
committed
AgentRunner using ResultReporter
1 parent bc71e6d commit 86b835d

File tree

7 files changed

+46
-280
lines changed

7 files changed

+46
-280
lines changed

src/NUnitCommon/nunit.agent.core.tests/AgentDirectRunnerTests.cs

+4-8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.IO;
77
using System.Linq;
88
using System.Text;
9+
using NUnit.Common;
910
using NUnit.Framework;
1011
using NUnit.TestData.Assemblies;
1112

@@ -28,6 +29,7 @@ private static void RunTestUnderTestBed(string testAssembly)
2829
#else
2930
string agentExe = Path.ChangeExtension(agentAssembly, ".exe");
3031
#endif
32+
MockAssembly.DisplayCounts();
3133

3234
var startInfo = new ProcessStartInfo(agentExe);
3335
startInfo.Arguments = testAssembly;
@@ -39,16 +41,10 @@ private static void RunTestUnderTestBed(string testAssembly)
3941
if (process is not null)
4042
{
4143
process.WaitForExit();
42-
43-
string output = process.StandardOutput.ReadToEnd();
44-
int index = output.IndexOf("Test Run Summary");
45-
if (index > 0)
46-
output = output.Substring(index);
47-
48-
Console.WriteLine(output);
4944
Console.WriteLine($"Agent process exited with rc={process.ExitCode}");
5045

51-
if (index < 0)
46+
string output = process.StandardOutput.ReadToEnd();
47+
if (!output.Contains("Test Run Summary"))
5248
Assert.Fail("No Summary Report found");
5349
}
5450
}

src/NUnitCommon/nunit.agent.core.tests/Drivers/NUnitFrameworkDriverTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public void RunTestsAction_AfterLoad_ReturnsRunnableSuite()
107107
Assert.That(result.GetAttribute("runstate"), Is.EqualTo("Runnable"));
108108
Assert.That(result.GetAttribute("testcasecount"), Is.EqualTo(MockAssembly.Tests.ToString()));
109109
Assert.That(result.GetAttribute("result"), Is.EqualTo("Failed"));
110-
Assert.That(result.GetAttribute("passed"), Is.EqualTo(MockAssembly.PassedInAttribute.ToString()));
110+
Assert.That(result.GetAttribute("passed"), Is.EqualTo(MockAssembly.Passed.ToString()));
111111
Assert.That(result.GetAttribute("failed"), Is.EqualTo(MockAssembly.Failed.ToString()));
112112
Assert.That(result.GetAttribute("skipped"), Is.EqualTo(MockAssembly.Skipped.ToString()));
113113
Assert.That(result.GetAttribute("inconclusive"), Is.EqualTo(MockAssembly.Inconclusive.ToString()));

src/NUnitCommon/nunit.agent.core.tests/Runners/TestAgentRunnerTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ private static void CheckRunResult(TestEngineResult result)
114114
private static void CheckRunResult(XmlNode result)
115115
{
116116
CheckBasicResult(result);
117-
Assert.That(result.GetAttribute("passed", 0), Is.EqualTo(MockAssembly.PassedInAttribute));
117+
Assert.That(result.GetAttribute("passed", 0), Is.EqualTo(MockAssembly.Passed));
118118
Assert.That(result.GetAttribute("failed", 0), Is.EqualTo(MockAssembly.Failed));
119119
Assert.That(result.GetAttribute("skipped", 0), Is.EqualTo(MockAssembly.Skipped));
120120
Assert.That(result.GetAttribute("inconclusive", 0), Is.EqualTo(MockAssembly.Inconclusive));

src/NUnitCommon/nunit.agent.core/AgentDirectRunner.cs

+3-250
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt
22

33
using System;
4-
using System.Globalization;
54
using System.IO;
6-
using System.Reflection;
75
using System.Xml;
86
using NUnit.TextDisplay;
97
using NUnit.Engine;
@@ -17,7 +15,6 @@ public class AgentDirectRunner
1715
private AgentOptions _options;
1816

1917
private ColorConsoleWriter OutWriter { get; } = new ColorConsoleWriter();
20-
private int ReportIndex { get; set; }
2118

2219
public AgentDirectRunner(AgentOptions options)
2320
{
@@ -30,7 +27,7 @@ public void ExecuteTestsDirectly()
3027
{
3128
var testFile = _options.Files[0];
3229

33-
WriteHeader(OutWriter);
30+
ResultReporter.WriteHeader(OutWriter);
3431

3532
TestPackage package = new TestPackage(testFile).SubPackages[0];
3633

@@ -40,18 +37,9 @@ public void ExecuteTestsDirectly()
4037
var runner = new LocalTestRunner(package);
4138
#endif
4239
var xmlResult = runner.Run(null, TestFilter.Empty).Xml;
40+
var summary = new ResultSummary(xmlResult);
4341

44-
WriteRunSettingsReport(xmlResult);
45-
46-
var result = xmlResult.GetAttribute("result");
47-
if (result == "Failed" || result == "Warning")
48-
WriteErrorsFailuresAndWarningsReport(xmlResult);
49-
50-
int notrunCount = int.Parse(xmlResult.GetAttribute("skipped") ?? "0");
51-
if (notrunCount > 0)
52-
WriteNotRunReport(xmlResult);
53-
54-
WriteSummaryReport(xmlResult);
42+
ResultReporter.ReportResults(summary, OutWriter);
5543

5644
var pathToResultFile = Path.Combine(_options.WorkDirectory, "TestResult.xml");
5745
WriteResultFile(xmlResult, pathToResultFile);
@@ -66,241 +54,6 @@ public void ExecuteTestsDirectly()
6654
Environment.Exit(AgentExitCodes.OK);
6755
}
6856

69-
private static void WriteHeader(ExtendedTextWriter outWriter)
70-
{
71-
var ea = Assembly.GetEntryAssembly();
72-
if (ea is not null)
73-
{
74-
var title = GetAttribute<AssemblyTitleAttribute>(ea)?.Title;
75-
var version = GetAttribute<AssemblyFileVersionAttribute>(ea)?.Version;
76-
var copyright = GetAttribute<AssemblyCopyrightAttribute>(ea)?.Copyright;
77-
78-
outWriter.WriteLine(ColorStyle.Header, $"{title} {version}");
79-
if (copyright is not null)
80-
outWriter.WriteLine(ColorStyle.SubHeader, copyright);
81-
outWriter.WriteLine(ColorStyle.SubHeader, DateTime.Now.ToString(CultureInfo.CurrentCulture.DateTimeFormat.FullDateTimePattern));
82-
outWriter.WriteLine();
83-
}
84-
}
85-
86-
private static TAttr? GetAttribute<TAttr>(Assembly assembly)
87-
where TAttr : Attribute
88-
{
89-
return assembly?.GetCustomAttribute<TAttr>();
90-
}
91-
92-
internal void WriteRunSettingsReport(XmlNode resultNode)
93-
{
94-
var settings = resultNode.SelectNodes("settings/setting");
95-
96-
if (settings is not null && settings.Count > 0)
97-
{
98-
OutWriter.WriteLine(ColorStyle.SectionHeader, "Run Settings");
99-
settings.ForEachNode(WriteSettingsNode);
100-
OutWriter.WriteLine();
101-
}
102-
}
103-
104-
private void WriteSettingsNode(XmlNode node)
105-
{
106-
var items = node.SelectNodes("item");
107-
var name = node.GetAttribute("name");
108-
var val = node.GetAttribute("value") ?? string.Empty;
109-
110-
if (items is not null)
111-
{
112-
OutWriter.WriteLabelLine($" {name}:", items.Count > 0 ? string.Empty : $" {val}");
113-
114-
items.ForEachNode((item) =>
115-
{
116-
var key = item.GetAttribute("key");
117-
var value = item.GetAttribute("value");
118-
OutWriter.WriteLine(ColorStyle.Value, $" {key} -> {value}");
119-
});
120-
}
121-
}
122-
123-
public void WriteSummaryReport(XmlNode resultNode)
124-
{
125-
var overallResult = resultNode.GetAttribute("result") ?? "Unknown";
126-
if (overallResult == "Skipped")
127-
overallResult = "Warning";
128-
129-
ColorStyle resultColor = overallResult == "Passed"
130-
? ColorStyle.Pass
131-
: overallResult == "Failed" || overallResult == "Unknown"
132-
? ColorStyle.Failure
133-
: overallResult == "Warning"
134-
? ColorStyle.Warning
135-
: ColorStyle.Output;
136-
137-
OutWriter.WriteLine(ColorStyle.SectionHeader, "Test Run Summary");
138-
OutWriter.WriteLabelLine(overallResult, resultColor);
139-
140-
int cases = resultNode.GetAttribute("testcasecount", 0);
141-
int passed = resultNode.GetAttribute("passed", 0);
142-
int failed = resultNode.GetAttribute("failed", 0);
143-
int warnings = resultNode.GetAttribute("warnings", 0);
144-
int inconclusive = resultNode.GetAttribute("inconclusive", 0);
145-
int skipped = resultNode.GetAttribute("skipped", 0);
146-
147-
WriteSummaryCount(" Test Cases: ", cases);
148-
WriteSummaryCount(", Passed: ", passed);
149-
WriteSummaryCount(", Failed: ", failed, ColorStyle.Failure);
150-
WriteSummaryCount(", Warnings: ", warnings, ColorStyle.Warning);
151-
WriteSummaryCount(", Inconclusive: ", inconclusive);
152-
WriteSummaryCount(", Skipped: ", skipped);
153-
OutWriter.WriteLine();
154-
155-
var duration = resultNode.GetAttribute("duration", 0.0);
156-
var startTime = resultNode.GetAttribute("start-time", DateTime.MinValue);
157-
var endTime = resultNode.GetAttribute("end-time", DateTime.MaxValue);
158-
159-
OutWriter.WriteLabelLine(" Start time: ", startTime.ToString("u"));
160-
OutWriter.WriteLabelLine(" End time: ", endTime.ToString("u"));
161-
OutWriter.WriteLabelLine(" Duration: ", string.Format(NumberFormatInfo.InvariantInfo, "{0:0.000} seconds", duration));
162-
OutWriter.WriteLine();
163-
}
164-
165-
public void WriteErrorsFailuresAndWarningsReport(XmlNode resultNode)
166-
{
167-
ReportIndex = 0;
168-
OutWriter.WriteLine(ColorStyle.SectionHeader, "Errors, Failures and Warnings");
169-
OutWriter.WriteLine();
170-
171-
WriteErrorsFailuresAndWarnings(resultNode);
172-
}
173-
174-
private void WriteErrorsFailuresAndWarnings(XmlNode resultNode)
175-
{
176-
const string OLD_NUNIT_CHILD_HAD_ERRORS_MESSAGE = "One or more child tests had errors";
177-
const string OLD_NUNIT_CHILD_HAD_WARNINGS_MESSAGE = "One or more child tests had errors";
178-
179-
string resultState = resultNode.GetAttribute("result") ?? string.Empty;
180-
181-
switch (resultNode.Name)
182-
{
183-
case "test-case":
184-
if (resultState == "Failed" || resultState == "Warning")
185-
DisplayResultItem(resultNode);
186-
return;
187-
188-
// Not present in this agent but retain for use with other agents
189-
case "test-run":
190-
resultNode.ForEachChildNode(WriteErrorsFailuresAndWarnings);
191-
break;
192-
193-
case "test-suite":
194-
if (resultState == "Failed" || resultState == "Warning")
195-
{
196-
var suiteType = resultNode.GetAttribute("type");
197-
if (suiteType == "Theory")
198-
{
199-
// Report failure of the entire theory and then go on
200-
// to list the individual cases that failed
201-
DisplayResultItem(resultNode);
202-
}
203-
else
204-
{
205-
// Where did this happen? Default is in the current test.
206-
var site = resultNode.GetAttribute("site");
207-
208-
// Correct a problem in some framework versions, whereby warnings and some failures
209-
// are promulgated to the containing suite without setting the FailureSite.
210-
if (site is null)
211-
{
212-
if (resultNode.SelectSingleNode("reason/message")?.InnerText == OLD_NUNIT_CHILD_HAD_WARNINGS_MESSAGE ||
213-
resultNode.SelectSingleNode("failure/message")?.InnerText == OLD_NUNIT_CHILD_HAD_ERRORS_MESSAGE)
214-
{
215-
site = "Child";
216-
}
217-
else
218-
site = "Test";
219-
}
220-
221-
// Only report errors in the current test method, setup or teardown
222-
if (site == "SetUp" || site == "TearDown" || site == "Test")
223-
{
224-
DisplayResultItem(resultNode);
225-
}
226-
227-
// Do not list individual "failed" tests after a one-time setup failure
228-
if (site == "SetUp")
229-
return;
230-
}
231-
}
232-
233-
resultNode.ForEachChildNode(WriteErrorsFailuresAndWarnings);
234-
235-
break;
236-
}
237-
}
238-
239-
public void WriteNotRunReport(XmlNode resultNode)
240-
{
241-
ReportIndex = 0;
242-
OutWriter.WriteLine(ColorStyle.SectionHeader, "Tests Not Run");
243-
OutWriter.WriteLine();
244-
WriteNotRunResults(resultNode);
245-
}
246-
247-
private void WriteNotRunResults(XmlNode resultNode)
248-
{
249-
switch (resultNode.Name)
250-
{
251-
case "test-case":
252-
string? status = resultNode.GetAttribute("result");
253-
254-
if (status == "Skipped")
255-
DisplayResultItem(resultNode);
256-
257-
break;
258-
259-
case "test-suite":
260-
case "test-run":
261-
resultNode.ForEachChildNode(WriteNotRunResults);
262-
263-
break;
264-
}
265-
}
266-
267-
private static readonly char[] EOL_CHARS = new char[] { '\r', '\n' };
268-
269-
private void DisplayResultItem(XmlNode resultNode)
270-
{
271-
string? resultState = resultNode.GetAttribute("result");
272-
string? fullName = resultNode.GetAttribute("fullname");
273-
string? message = (resultNode.SelectSingleNode("failure/message") ?? resultNode.SelectSingleNode("reason/message"))?.InnerText.Trim(EOL_CHARS);
274-
275-
OutWriter.WriteLine(GetColorStyle(),
276-
string.Format($"{++ReportIndex}) {resultState} : {fullName}"));
277-
if (!string.IsNullOrEmpty(message))
278-
OutWriter.WriteLine(ColorStyle.Output, message);
279-
var stackTrace = resultNode.SelectSingleNode("failure/stack-trace")?.InnerText;
280-
if (!string.IsNullOrEmpty(stackTrace))
281-
OutWriter.WriteLine(stackTrace);
282-
OutWriter.WriteLine();
283-
284-
ColorStyle GetColorStyle()
285-
{
286-
return resultState == "Failed"
287-
? ColorStyle.Failure
288-
: resultState == "Warning"
289-
? ColorStyle.Warning
290-
: ColorStyle.Output;
291-
}
292-
}
293-
294-
private void WriteSummaryCount(string label, int count)
295-
{
296-
OutWriter.WriteLabel(label, count.ToString(CultureInfo.CurrentUICulture));
297-
}
298-
299-
private void WriteSummaryCount(string label, int count, ColorStyle color)
300-
{
301-
OutWriter.WriteLabel(label, count.ToString(CultureInfo.CurrentUICulture), count > 0 ? color : ColorStyle.Value);
302-
}
303-
30457
public static void WriteResultFile(XmlNode resultNode, string outputPath)
30558
{
30659
using (var stream = new FileStream(outputPath, FileMode.Create, FileAccess.Write))

src/NUnitCommon/nunit.common.tests/TextDisplay/ResultReporterTests.cs

+8-8
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,9 @@ public void SummaryReportTest()
103103
{
104104
"Test Run Summary",
105105
" Overall result: Failed",
106-
$" Test Count: {MockAssembly.Tests}, Pass: {MockAssembly.Passed}, Fail: 11, Warn: 1, Inconclusive: 1, Skip: 7",
107-
" Failed Tests - Failures: 1, Errors: 7, Invalid: 3",
108-
" Skipped Tests - Ignored: 4, Explicit: 3, Other: 0",
106+
$" Test Count: {MockAssembly.Tests}, Pass: {MockAssembly.Passed}, Fail: {MockAssembly.Failed}, Warn: {MockAssembly.Warnings}, Inconclusive: {MockAssembly.Inconclusive}, Skip: {MockAssembly.Skipped}",
107+
$" Failed Tests - Failures: {MockAssembly.Failed_Other}, Errors: {MockAssembly.Failed_Error}, Invalid: {MockAssembly.Failed_NotRunnable}",
108+
$" Skipped Tests - Ignored: 4, Explicit: 3, Other: 0",
109109
" Start time: 2015-10-19 02:12:28Z",
110110
" End time: 2015-10-19 02:12:29Z",
111111
" Duration: 0.349 seconds",
@@ -178,11 +178,11 @@ public void TestsNotRunTest()
178178
Assert.That(ReportLines, Is.EqualTo(expected));
179179
}
180180

181-
[Test, Explicit("Displays failure behavior")]
182-
public void WarningsOnlyDisplayOnce()
183-
{
184-
Assert.Warn("Just a warning");
185-
}
181+
//[Test, Explicit("Displays failure behavior")]
182+
//public void WarningsOnlyDisplayOnce()
183+
//{
184+
// Assert.Warn("Just a warning");
185+
//}
186186

187187
[Test]
188188
public void TestParameterSettingsWrittenCorrectly()

src/NUnitCommon/nunit.common/ResultSummary.cs

+7-6
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ public class ResultSummary
1212
{
1313
public ResultSummary(XmlNode resultNode)
1414
{
15-
if (resultNode.Name != "test-run")
16-
throw new InvalidOperationException("Expected <test-run> as top-level element but was <" + resultNode.Name + ">");
15+
if (resultNode.Name != "test-run" && resultNode.Name != "test-suite")
16+
throw new InvalidOperationException("Expected <test-run> or <test-suite> as top-level element but was <" + resultNode.Name + ">");
1717

1818
InitializeCounters();
1919

@@ -216,10 +216,11 @@ private void Summarize(XmlNode node, bool failedInFixtureTearDown)
216216
InvalidAssemblies++;
217217
UnexpectedError = true;
218218
}
219-
if ((type == "SetUpFixture" || type == "TestFixture") && status == "Failed" && label == "Error" && site == "TearDown")
220-
{
221-
failedInFixtureTearDown = true;
222-
}
219+
// TODO: This seems wrong and causes failures. Leaving it commented while awaiting feedback.
220+
//if ((type == "SetUpFixture" || type == "TestFixture") && status == "Failed" && label == "Error" && site == "TearDown")
221+
//{
222+
// failedInFixtureTearDown = true;
223+
//}
223224

224225
Summarize(node.ChildNodes, failedInFixtureTearDown);
225226
break;

0 commit comments

Comments
 (0)