[d16-5] Cherry-picked all xharness fixes done for Xml parsing.
This commit is contained in:
Коммит
768ee83dad
|
@ -48,14 +48,16 @@
|
|||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Mono.Options" Version="5.3.0.1" />
|
||||
<PackageReference Include="System.Buffers" Version="4.5.0" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.2" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.2" />
|
||||
<PackageReference Include="System.Buffers" Version="4.4.0" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.1" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.analyzers" Version="0.10.0" />
|
||||
<PackageReference Include="xunit.extensibility.core" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.extensibility.execution" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.runner.utility" Version="2.4.0" />
|
||||
|
||||
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System">
|
||||
|
@ -99,6 +101,9 @@
|
|||
<Compile Include="templates\common\TestRunner.NUnit\ClassOrNamespaceFilter.cs">
|
||||
<Link>TestRunner.NUnit\ClassOrNamespaceFilter.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="templates\common\TestRunner.NUnit\XmlOutputWriter.cs">
|
||||
<Link>TestRunner.NUnit\XmlOutputWriter.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="templates\common\TestRunner.NUnit\TestMethodFilter.cs">
|
||||
<Link>TestRunner.NUnit\TestMethodFilter.cs</Link>
|
||||
</Compile>
|
||||
|
|
|
@ -122,15 +122,15 @@
|
|||
<MtouchI18n>cjk,mideast,other,rare,west</MtouchI18n>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Mono.Options" Version="5.3.0.1" />
|
||||
<PackageReference Include="System.Buffers" Version="4.4.0" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.1" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.0" />
|
||||
<PackageReference Include="Mono.Options" Version="6.6.0.161" />
|
||||
<PackageReference Include="System.Buffers" Version="4.5.0" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.3" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.7.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.analyzers" Version="0.10.0" />
|
||||
<PackageReference Include="xunit.extensibility.core" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.extensibility.execution" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.runner.utility" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.extensibility.core" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.extensibility.execution" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.utility" Version="2.4.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
|
@ -176,6 +176,9 @@
|
|||
<Compile Include="templates\common\TestRunner.NUnit\TestMethodFilter.cs">
|
||||
<Link>TestRunner.NUnit\TestMethodFilter.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="templates\common\TestRunner.NUnit\XmlOutputWriter.cs">
|
||||
<Link>TestRunner.NUnit\XmlOutputWriter.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="templates\common\TestRunner.Core\Extensions.Bool.cs">
|
||||
<Link>TestRunner.Core\Extensions.Bool.cs</Link>
|
||||
</Compile>
|
||||
|
|
|
@ -128,15 +128,15 @@
|
|||
<MtouchLink>SdkOnly</MtouchLink>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Mono.Options" Version="5.3.0.1" />
|
||||
<PackageReference Include="System.Buffers" Version="4.4.0" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.1" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.0" />
|
||||
<PackageReference Include="Mono.Options" Version="6.6.0.161" />
|
||||
<PackageReference Include="System.Buffers" Version="4.5.0" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.3" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.7.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.analyzers" Version="0.10.0" />
|
||||
<PackageReference Include="xunit.extensibility.core" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.extensibility.execution" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.runner.utility" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.extensibility.core" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.extensibility.execution" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.utility" Version="2.4.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
|
@ -206,6 +206,9 @@
|
|||
<Compile Include="templates\common\TestRunner.NUnit\TestMethodFilter.cs">
|
||||
<Link>TestRunner.NUnit\TestMethodFilter.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="templates\common\TestRunner.NUnit\XmlOutputWriter.cs">
|
||||
<Link>TestRunner.NUnit\XmlOutputWriter.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="templates\common\TestRunner.xUnit\XUnitFilter.cs">
|
||||
<Link>TestRunner.xUnit\XUnitFilter.cs</Link>
|
||||
</Compile>
|
||||
|
|
|
@ -135,15 +135,15 @@
|
|||
<MtouchI18n>cjk,mideast,other,rare,west</MtouchI18n>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Mono.Options" Version="5.3.0.1" />
|
||||
<PackageReference Include="System.Buffers" Version="4.4.0" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.1" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.0" />
|
||||
<PackageReference Include="Mono.Options" Version="6.6.0.161" />
|
||||
<PackageReference Include="System.Buffers" Version="4.5.0" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.3" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.7.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.analyzers" Version="0.10.0" />
|
||||
<PackageReference Include="xunit.extensibility.core" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.extensibility.execution" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.runner.utility" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.extensibility.core" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.extensibility.execution" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.utility" Version="2.4.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
|
@ -189,6 +189,9 @@
|
|||
<Compile Include="templates\common\TestRunner.NUnit\TestMethodFilter.cs">
|
||||
<Link>TestRunner.NUnit\TestMethodFilter.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="templates\common\TestRunner.NUnit\XmlOutputWriter.cs">
|
||||
<Link>TestRunner.NUnit\XmlOutputWriter.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="templates\common\TestRunner.Core\Extensions.Bool.cs">
|
||||
<Link>TestRunner.Core\Extensions.Bool.cs</Link>
|
||||
</Compile>
|
||||
|
|
|
@ -9,10 +9,8 @@ using System.Threading.Tasks;
|
|||
|
||||
using Foundation;
|
||||
|
||||
using NUnitLite.Runner;
|
||||
using NUnit.Framework.Api;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.WorkItems;
|
||||
using NUnit.Framework.Internal.Filters;
|
||||
|
||||
using NUnitTest = NUnit.Framework.Internal.Test;
|
||||
|
|
|
@ -0,0 +1,349 @@
|
|||
// ***********************************************************************
|
||||
// Copyright (c) 2011 Charlie Poole
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ***********************************************************************
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
using System.IO;
|
||||
using NUnit.Framework.Api;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnitLite.Runner;
|
||||
#if CLR_2_0 || CLR_4_0
|
||||
using System.Collections.Generic;
|
||||
#else
|
||||
using System.Collections.Specialized;
|
||||
#endif
|
||||
|
||||
namespace Xamarin.iOS.UnitTests.NUnit {
|
||||
/// <summary>
|
||||
/// NUnit2XmlOutputWriter is able to create an xml file representing
|
||||
/// the result of a test run in NUnit 2.x format.
|
||||
/// </summary>
|
||||
public class NUnit2XmlOutputWriter : OutputWriter {
|
||||
private XmlWriter xmlWriter;
|
||||
private DateTime startTime;
|
||||
|
||||
#if CLR_2_0 || CLR_4_0
|
||||
private static Dictionary<string, string> resultStates = new Dictionary<string, string>();
|
||||
#else
|
||||
private static StringDictionary resultStates = new StringDictionary ();
|
||||
#endif
|
||||
|
||||
static NUnit2XmlOutputWriter ()
|
||||
{
|
||||
resultStates ["Passed"] = "Success";
|
||||
resultStates ["Failed"] = "Failure";
|
||||
resultStates ["Failed:Error"] = "Error";
|
||||
resultStates ["Failed:Cancelled"] = "Cancelled";
|
||||
resultStates ["Inconclusive"] = "Inconclusive";
|
||||
resultStates ["Skipped"] = "Skipped";
|
||||
resultStates ["Skipped:Ignored"] = "Ignored";
|
||||
resultStates ["Skipped:Invalid"] = "NotRunnable";
|
||||
}
|
||||
|
||||
public NUnit2XmlOutputWriter (DateTime startTime)
|
||||
{
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the result of a test run to a specified TextWriter.
|
||||
/// </summary>
|
||||
/// <param name="result">The test result for the run</param>
|
||||
/// <param name="writer">The TextWriter to which the xml will be written</param>
|
||||
public override void WriteResultFile (ITestResult result, TextWriter writer)
|
||||
{
|
||||
// NOTE: Under .NET 1.1, XmlTextWriter does not implement IDisposable,
|
||||
// but does implement Close(). Hence we cannot use a 'using' clause.
|
||||
//using (XmlTextWriter xmlWriter = new XmlTextWriter(writer))
|
||||
#if SILVERLIGHT
|
||||
XmlWriter xmlWriter = XmlWriter.Create(writer);
|
||||
#else
|
||||
XmlTextWriter xmlWriter = new XmlTextWriter (writer);
|
||||
xmlWriter.Formatting = Formatting.Indented;
|
||||
#endif
|
||||
|
||||
try {
|
||||
WriteXmlOutput (result, xmlWriter);
|
||||
} finally {
|
||||
writer.Close ();
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteXmlOutput (ITestResult result, XmlWriter xmlWriter)
|
||||
{
|
||||
this.xmlWriter = xmlWriter;
|
||||
|
||||
InitializeXmlFile (result);
|
||||
WriteResultElement (result);
|
||||
TerminateXmlFile ();
|
||||
}
|
||||
|
||||
private void InitializeXmlFile (ITestResult result)
|
||||
{
|
||||
ResultSummary summaryResults = new ResultSummary (result);
|
||||
|
||||
xmlWriter.WriteStartDocument (false);
|
||||
xmlWriter.WriteComment ("This file represents the results of running a test suite");
|
||||
|
||||
xmlWriter.WriteStartElement ("test-results");
|
||||
|
||||
xmlWriter.WriteAttributeString ("name", result.FullName);
|
||||
xmlWriter.WriteAttributeString ("total", summaryResults.TestCount.ToString ());
|
||||
xmlWriter.WriteAttributeString ("errors", summaryResults.ErrorCount.ToString ());
|
||||
xmlWriter.WriteAttributeString ("failures", summaryResults.FailureCount.ToString ());
|
||||
xmlWriter.WriteAttributeString ("not-run", summaryResults.NotRunCount.ToString ());
|
||||
xmlWriter.WriteAttributeString ("inconclusive", summaryResults.InconclusiveCount.ToString ());
|
||||
xmlWriter.WriteAttributeString ("ignored", summaryResults.IgnoreCount.ToString ());
|
||||
xmlWriter.WriteAttributeString ("skipped", summaryResults.SkipCount.ToString ());
|
||||
xmlWriter.WriteAttributeString ("invalid", summaryResults.InvalidCount.ToString ());
|
||||
|
||||
xmlWriter.WriteAttributeString ("date", XmlConvert.ToString (startTime, "yyyy-MM-dd"));
|
||||
xmlWriter.WriteAttributeString ("time", XmlConvert.ToString (startTime, "HH:mm:ss"));
|
||||
WriteEnvironment ();
|
||||
WriteCultureInfo ();
|
||||
xmlWriter.Flush ();
|
||||
}
|
||||
|
||||
private void WriteCultureInfo ()
|
||||
{
|
||||
xmlWriter.WriteStartElement ("culture-info");
|
||||
xmlWriter.WriteAttributeString ("current-culture",
|
||||
CultureInfo.CurrentCulture.ToString ());
|
||||
xmlWriter.WriteAttributeString ("current-uiculture",
|
||||
CultureInfo.CurrentUICulture.ToString ());
|
||||
xmlWriter.WriteEndElement ();
|
||||
xmlWriter.Flush ();
|
||||
}
|
||||
|
||||
private void WriteEnvironment ()
|
||||
{
|
||||
xmlWriter.WriteStartElement ("environment");
|
||||
AssemblyName assemblyName = AssemblyHelper.GetAssemblyName (Assembly.GetExecutingAssembly ());
|
||||
xmlWriter.WriteAttributeString ("nunit-version",
|
||||
assemblyName.Version.ToString ());
|
||||
xmlWriter.WriteAttributeString ("clr-version",
|
||||
Environment.Version.ToString ());
|
||||
xmlWriter.WriteAttributeString ("os-version",
|
||||
Environment.OSVersion.ToString ());
|
||||
xmlWriter.WriteAttributeString ("platform",
|
||||
Environment.OSVersion.Platform.ToString ());
|
||||
#if !NETCF
|
||||
xmlWriter.WriteAttributeString ("cwd",
|
||||
Environment.CurrentDirectory);
|
||||
#if !SILVERLIGHT
|
||||
xmlWriter.WriteAttributeString ("machine-name",
|
||||
Environment.MachineName);
|
||||
xmlWriter.WriteAttributeString ("user",
|
||||
Environment.UserName);
|
||||
xmlWriter.WriteAttributeString ("user-domain",
|
||||
Environment.UserDomainName);
|
||||
#endif
|
||||
#endif
|
||||
xmlWriter.WriteEndElement ();
|
||||
xmlWriter.Flush ();
|
||||
}
|
||||
|
||||
private void WriteResultElement (ITestResult result)
|
||||
{
|
||||
StartTestElement (result);
|
||||
|
||||
WriteProperties (result);
|
||||
|
||||
switch (result.ResultState.Status) {
|
||||
case TestStatus.Skipped:
|
||||
WriteReasonElement (result.Message);
|
||||
break;
|
||||
case TestStatus.Failed:
|
||||
WriteFailureElement (result.Message, result.StackTrace);
|
||||
break;
|
||||
}
|
||||
|
||||
if (result.Test is TestSuite)
|
||||
WriteChildResults (result);
|
||||
|
||||
xmlWriter.WriteEndElement (); // test element
|
||||
xmlWriter.Flush ();
|
||||
}
|
||||
|
||||
private void TerminateXmlFile ()
|
||||
{
|
||||
xmlWriter.WriteEndElement (); // test-results
|
||||
xmlWriter.WriteEndDocument ();
|
||||
xmlWriter.Flush ();
|
||||
xmlWriter.Close ();
|
||||
}
|
||||
|
||||
|
||||
#region Element Creation Helpers
|
||||
|
||||
private void StartTestElement (ITestResult result)
|
||||
{
|
||||
ITest test = result.Test;
|
||||
TestSuite suite = test as TestSuite;
|
||||
|
||||
if (suite != null) {
|
||||
xmlWriter.WriteStartElement ("test-suite");
|
||||
xmlWriter.WriteAttributeString ("type", suite.TestType);
|
||||
xmlWriter.WriteAttributeString ("name", suite.TestType == "Assembly"
|
||||
? result.Test.FullName
|
||||
: result.Test.Name);
|
||||
} else {
|
||||
xmlWriter.WriteStartElement ("test-case");
|
||||
xmlWriter.WriteAttributeString ("name", result.Name);
|
||||
}
|
||||
|
||||
if (test.Properties.ContainsKey (PropertyNames.Description)) {
|
||||
string description = (string)test.Properties.Get (PropertyNames.Description);
|
||||
xmlWriter.WriteAttributeString ("description", description);
|
||||
}
|
||||
|
||||
TestStatus status = result.ResultState.Status;
|
||||
string translatedResult = resultStates [result.ResultState.ToString ()];
|
||||
|
||||
if (status != TestStatus.Skipped) {
|
||||
xmlWriter.WriteAttributeString ("executed", "True");
|
||||
xmlWriter.WriteAttributeString ("result", translatedResult);
|
||||
xmlWriter.WriteAttributeString ("success", status == TestStatus.Passed ? "True" : "False");
|
||||
xmlWriter.WriteAttributeString ("time", result.Duration.TotalSeconds.ToString ());
|
||||
xmlWriter.WriteAttributeString ("asserts", result.AssertCount.ToString ());
|
||||
} else {
|
||||
xmlWriter.WriteAttributeString ("executed", "False");
|
||||
xmlWriter.WriteAttributeString ("result", translatedResult);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteProperties (ITestResult result)
|
||||
{
|
||||
IPropertyBag properties = result.Test.Properties;
|
||||
int nprops = 0;
|
||||
|
||||
foreach (string key in properties.Keys) {
|
||||
if (key != PropertyNames.Category) {
|
||||
if (nprops++ == 0)
|
||||
xmlWriter.WriteStartElement ("properties");
|
||||
|
||||
foreach (object prop in properties [key]) {
|
||||
xmlWriter.WriteStartElement ("property");
|
||||
xmlWriter.WriteAttributeString ("name", key);
|
||||
xmlWriter.WriteAttributeString ("value", prop.ToString ());
|
||||
xmlWriter.WriteEndElement ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nprops > 0)
|
||||
xmlWriter.WriteEndElement ();
|
||||
}
|
||||
|
||||
private void WriteReasonElement (string message)
|
||||
{
|
||||
xmlWriter.WriteStartElement ("reason");
|
||||
xmlWriter.WriteStartElement ("message");
|
||||
xmlWriter.WriteCData (message);
|
||||
xmlWriter.WriteEndElement ();
|
||||
xmlWriter.WriteEndElement ();
|
||||
}
|
||||
|
||||
private void WriteFailureElement (string message, string stackTrace)
|
||||
{
|
||||
xmlWriter.WriteStartElement ("failure");
|
||||
xmlWriter.WriteStartElement ("message");
|
||||
WriteCData (message);
|
||||
xmlWriter.WriteEndElement ();
|
||||
xmlWriter.WriteStartElement ("stack-trace");
|
||||
if (stackTrace != null)
|
||||
WriteCData (stackTrace);
|
||||
xmlWriter.WriteEndElement ();
|
||||
xmlWriter.WriteEndElement ();
|
||||
}
|
||||
|
||||
private void WriteChildResults (ITestResult result)
|
||||
{
|
||||
xmlWriter.WriteStartElement ("results");
|
||||
|
||||
foreach (ITestResult childResult in result.Children)
|
||||
WriteResultElement (childResult);
|
||||
|
||||
xmlWriter.WriteEndElement ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Output Helpers
|
||||
///// <summary>
|
||||
///// Makes string safe for xml parsing, replacing control chars with '?'
|
||||
///// </summary>
|
||||
///// <param name="encodedString">string to make safe</param>
|
||||
///// <returns>xml safe string</returnCs>
|
||||
//private static string CharacterSafeString(string encodedString)
|
||||
//{
|
||||
// /*The default code page for the system will be used.
|
||||
// Since all code pages use the same lower 128 bytes, this should be sufficient
|
||||
// for finding uprintable control characters that make the xslt processor error.
|
||||
// We use characters encoded by the default code page to avoid mistaking bytes as
|
||||
// individual characters on non-latin code pages.*/
|
||||
// char[] encodedChars = System.Text.Encoding.Default.GetChars(System.Text.Encoding.Default.GetBytes(encodedString));
|
||||
|
||||
// System.Collections.ArrayList pos = new System.Collections.ArrayList();
|
||||
// for (int x = 0; x < encodedChars.Length; x++)
|
||||
// {
|
||||
// char currentChar = encodedChars[x];
|
||||
// //unprintable characters are below 0x20 in Unicode tables
|
||||
// //some control characters are acceptable. (carriage return 0x0D, line feed 0x0A, horizontal tab 0x09)
|
||||
// if (currentChar < 32 && (currentChar != 9 && currentChar != 10 && currentChar != 13))
|
||||
// {
|
||||
// //save the array index for later replacement.
|
||||
// pos.Add(x);
|
||||
// }
|
||||
// }
|
||||
// foreach (int index in pos)
|
||||
// {
|
||||
// encodedChars[index] = '?';//replace unprintable control characters with ?(3F)
|
||||
// }
|
||||
// return System.Text.Encoding.Default.GetString(System.Text.Encoding.Default.GetBytes(encodedChars));
|
||||
//}
|
||||
|
||||
private void WriteCData (string text)
|
||||
{
|
||||
int start = 0;
|
||||
while (true) {
|
||||
int illegal = text.IndexOf ("]]>", start);
|
||||
if (illegal < 0)
|
||||
break;
|
||||
xmlWriter.WriteCData (text.Substring (start, illegal - start + 2));
|
||||
start = illegal + 2;
|
||||
if (start >= text.Length)
|
||||
return;
|
||||
}
|
||||
|
||||
if (start > 0)
|
||||
xmlWriter.WriteCData (text.Substring (start));
|
||||
else
|
||||
xmlWriter.WriteCData (text);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@ namespace Xamarin.iOS.UnitTests.XUnit
|
|||
List<XUnitFilter> filters = new List<XUnitFilter> ();
|
||||
bool runAssemblyByDefault;
|
||||
|
||||
public XUnitResultFileFormat ResultFileFormat { get; set; } = XUnitResultFileFormat.NUnit;
|
||||
public XUnitResultFileFormat ResultFileFormat { get; set; } = XUnitResultFileFormat.XunitV2;
|
||||
public AppDomainSupport AppDomainSupport { get; set; } = AppDomainSupport.Denied;
|
||||
protected override string ResultsFileName { get; set; } = "TestResults.xUnit.xml";
|
||||
|
||||
|
@ -795,9 +795,10 @@ namespace Xamarin.iOS.UnitTests.XUnit
|
|||
{
|
||||
if (assembliesElement == null)
|
||||
return String.Empty;
|
||||
|
||||
// remove all the empty nodes
|
||||
assembliesElement.Descendants ().Where (e => e.Name == "collection" && !e.Descendants ().Any ()).Remove ();
|
||||
string outputFilePath = GetResultsFilePath ();
|
||||
var settings = new XmlWriterSettings { Indent = true };
|
||||
var settings = new XmlWriterSettings { Indent = true};
|
||||
using (var xmlWriter = XmlWriter.Create (outputFilePath, settings)) {
|
||||
switch (ResultFileFormat) {
|
||||
case XUnitResultFileFormat.XunitV2:
|
||||
|
@ -818,6 +819,8 @@ namespace Xamarin.iOS.UnitTests.XUnit
|
|||
{
|
||||
if (assembliesElement == null)
|
||||
return;
|
||||
// remove all the empty nodes
|
||||
assembliesElement.Descendants ().Where (e => e.Name == "collection" && !e.Descendants ().Any ()).Remove ();
|
||||
var settings = new XmlWriterSettings { Indent = true };
|
||||
using (var xmlWriter = XmlWriter.Create (writer, settings)) {
|
||||
switch (ResultFileFormat) {
|
||||
|
|
|
@ -334,120 +334,9 @@ namespace xharness
|
|||
}
|
||||
}
|
||||
|
||||
bool IsTouchUnitResult (StreamReader stream)
|
||||
(string resultLine, bool failed, bool crashed) ParseResult (string test_log_path, bool timed_out, bool crashed)
|
||||
{
|
||||
// TouchUnitTestRun is the very first node in the TouchUnit xml result
|
||||
// which is not preset in the xunit xml, therefore we know the runner
|
||||
// quite quickly
|
||||
bool isTouchUnit = false;
|
||||
using (var reader = XmlReader.Create (stream)) {
|
||||
while (reader.Read ()) {
|
||||
if (reader.NodeType == XmlNodeType.Element && reader.Name == "TouchUnitTestRun") {
|
||||
isTouchUnit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// we want to reuse the stream (and we are sync)
|
||||
stream.BaseStream.Position = 0;
|
||||
stream.DiscardBufferedData ();
|
||||
return isTouchUnit;
|
||||
}
|
||||
|
||||
(string resultLine, bool failed) ParseTouchUnitXml (StreamReader stream, StreamWriter writer)
|
||||
{
|
||||
long total, errors, failed, notRun, inconclusive, ignored, skipped, invalid;
|
||||
total = errors = failed = notRun = inconclusive = ignored = skipped = invalid = 0L;
|
||||
using (var reader = XmlReader.Create (stream)) {
|
||||
while (reader.Read ()) {
|
||||
if (reader.NodeType == XmlNodeType.Element && reader.Name == "test-results") {
|
||||
total = long.Parse (reader ["total"]);
|
||||
errors = long.Parse (reader ["errors"]);
|
||||
failed = long.Parse (reader ["failures"]);
|
||||
notRun = long.Parse (reader ["not-run"]);
|
||||
inconclusive = long.Parse (reader ["inconclusive"]);
|
||||
ignored = long.Parse (reader ["ignored"]);
|
||||
skipped = long.Parse (reader ["skipped"]);
|
||||
invalid = long.Parse (reader ["invalid"]);
|
||||
}
|
||||
if (reader.NodeType == XmlNodeType.Element && reader.Name == "TouchUnitExtraData") {
|
||||
// move fwd to get to the CData
|
||||
if (reader.Read ())
|
||||
writer.Write (reader.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
var passed = total - errors - failed - notRun - inconclusive - ignored - skipped - invalid;
|
||||
var resultLine = $"Tests run: {total} Passed: {passed} Inconclusive: {inconclusive} Failed: {failed + errors} Ignored: {ignored + skipped + invalid}";
|
||||
return (resultLine, total == 0 || errors != 0 || failed != 0);
|
||||
}
|
||||
|
||||
(string resultLine, bool failed) ParseNUnitXml (StreamReader stream, StreamWriter writer)
|
||||
{
|
||||
long total, errors, failed, notRun, inconclusive, ignored, skipped, invalid;
|
||||
total = errors = failed = notRun = inconclusive = ignored = skipped = invalid = 0L;
|
||||
using (var reader = XmlReader.Create (stream)) {
|
||||
while (reader.Read ()) {
|
||||
if (reader.NodeType == XmlNodeType.Element && reader.Name == "test-results") {
|
||||
total = long.Parse (reader ["total"]);
|
||||
errors = long.Parse (reader ["errors"]);
|
||||
failed = long.Parse (reader ["failures"]);
|
||||
notRun = long.Parse (reader ["not-run"]);
|
||||
inconclusive = long.Parse (reader ["inconclusive"]);
|
||||
ignored = long.Parse (reader ["ignored"]);
|
||||
skipped = long.Parse (reader ["skipped"]);
|
||||
invalid = long.Parse (reader ["invalid"]);
|
||||
}
|
||||
if (reader.NodeType == XmlNodeType.Element && reader.Name == "test-suite" && (reader["type"] == "TestFixture" || reader["type"] == "TestCollection")) {
|
||||
var testCaseName = reader ["name"];
|
||||
writer.WriteLine (testCaseName);
|
||||
var time = reader.GetAttribute ("time") ?? "0"; // some nodes might not have the time :/
|
||||
// get the first node and then move in the siblings of the same type
|
||||
reader.ReadToDescendant ("test-case");
|
||||
do {
|
||||
if (reader.Name != "test-case")
|
||||
break;
|
||||
// read the test cases in the current node
|
||||
var status = reader ["result"];
|
||||
switch (status) {
|
||||
case "Success":
|
||||
writer.Write ("\t[PASS] ");
|
||||
break;
|
||||
case "Ignored":
|
||||
writer.Write ("\t[IGNORED] ");
|
||||
break;
|
||||
case "Error":
|
||||
case "Failure":
|
||||
writer.Write ("\t[FAIL] ");
|
||||
break;
|
||||
case "Inconclusive":
|
||||
writer.Write ("\t[INCONCLUSIVE] ");
|
||||
break;
|
||||
default:
|
||||
writer.Write ("\t[INFO] ");
|
||||
break;
|
||||
}
|
||||
writer.Write (reader ["name"]);
|
||||
if (status == "Failure" || status == "Error") { // we need to print the message
|
||||
writer.Write ($" : {reader.ReadElementContentAsString ()}");
|
||||
}
|
||||
// add a new line
|
||||
writer.WriteLine ();
|
||||
} while (reader.ReadToNextSibling ("test-case"));
|
||||
writer.WriteLine ($"{testCaseName} {time} ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
var passed = total - errors - failed - notRun - inconclusive - ignored - skipped - invalid;
|
||||
string resultLine = $"Tests run: {total} Passed: {passed} Inconclusive: {inconclusive} Failed: {failed + errors} Ignored: {ignored + skipped + invalid}";
|
||||
writer.WriteLine (resultLine);
|
||||
|
||||
return (resultLine, total == 0 | errors != 0 || failed != 0);
|
||||
}
|
||||
|
||||
(string resultLine, bool failed, bool crashed) ParseResult (Log listener_log, bool timed_out, bool crashed)
|
||||
{
|
||||
if (!File.Exists (listener_log.FullPath))
|
||||
if (!File.Exists (test_log_path))
|
||||
return (null, false, true); // if we do not have a log file, the test crashes
|
||||
|
||||
// parsing the result is different if we are in jenkins or not.
|
||||
|
@ -457,58 +346,47 @@ namespace xharness
|
|||
// wraps the NUnit xml output with additional information, which we need to unwrap so that Jenkins understands it.
|
||||
//
|
||||
// On the other hand, the nunit and xunit do not have that data and have to be parsed.
|
||||
if (Harness.InJenkins) {
|
||||
(string resultLine, bool failed, bool crashed) parseResult = (null, false, false);
|
||||
// move the xml to a tmp path, that path will be use to read the xml
|
||||
// in the reader, and the writer will use the stream from the logger to
|
||||
// write the human readable log
|
||||
var tmpFile = Path.Combine (Path.GetTempPath (), Guid.NewGuid ().ToString ());
|
||||
//
|
||||
// This if statement has a small trick, we found out that internet sharing in some of the bots (VSTS) does not work, in
|
||||
// that case, we cannot do a TCP connection to xharness to get the log, this is a problem since if we did not get the xml
|
||||
// from the TCP connection, we are going to fail when trying to read it and not parse it. Therefore, we are not only
|
||||
// going to check if we are in CI, but also if the listener_log is valid.
|
||||
var path = Path.ChangeExtension (test_log_path, "xml");
|
||||
XmlResultParser.CleanXml (test_log_path, path);
|
||||
|
||||
File.Move (listener_log.FullPath, tmpFile);
|
||||
if (Harness.InCI && XmlResultParser.IsValidXml (path, out var xmlType)) {
|
||||
(string resultLine, bool failed, bool crashed) parseResult = (null, false, false);
|
||||
crashed = false;
|
||||
try {
|
||||
using (var streamReaderTmp = new StreamReader (tmpFile)) {
|
||||
var isTouchUnit = IsTouchUnitResult (streamReaderTmp); // method resets position
|
||||
using (var writer = new StreamWriter (listener_log.FullPath, true)) { // write the human result to the log file
|
||||
if (isTouchUnit) {
|
||||
var (resultLine, failed)= ParseTouchUnitXml (streamReaderTmp, writer);
|
||||
parseResult.resultLine = resultLine;
|
||||
parseResult.failed = failed;
|
||||
} else {
|
||||
var (resultLine, failed)= ParseNUnitXml (streamReaderTmp, writer);
|
||||
parseResult.resultLine = resultLine;
|
||||
parseResult.failed = failed;
|
||||
}
|
||||
}
|
||||
// reset pos of the stream
|
||||
streamReaderTmp.BaseStream.Position = 0;
|
||||
streamReaderTmp.DiscardBufferedData ();
|
||||
var path = listener_log.FullPath;
|
||||
path = Path.ChangeExtension (path, "xml");
|
||||
// both the nunit and xunit runners are not
|
||||
// setting the test results correctly, lets add them
|
||||
using (var xmlWriter = new StreamWriter (path)) {
|
||||
string line;
|
||||
while ((line = streamReaderTmp.ReadLine ()) != null) {
|
||||
if (line.Contains ("<test-results")) {
|
||||
if (line.Contains ("name=\"\"")) { // NUnit case
|
||||
xmlWriter.WriteLine (line.Replace ("name=\"\"", $"name=\"{appName + " " + configuration}\""));
|
||||
xmlWriter.WriteLine (line);
|
||||
} else if (line.Contains ($"name=\"com.xamarin.bcltests.{appName}\"")) { // xunit case
|
||||
xmlWriter.WriteLine (line.Replace ($"name=\"com.xamarin.bcltests.{appName}\"", $"name=\"{appName + " " + configuration}\""));
|
||||
}
|
||||
} else {
|
||||
xmlWriter.WriteLine (line);
|
||||
}
|
||||
}
|
||||
}
|
||||
// we do not longer need the tmp file
|
||||
Logs.AddFile (path, "Test xml");
|
||||
}
|
||||
var newFilename = XmlResultParser.GetXmlFilePath (path, xmlType);
|
||||
|
||||
// rename the path to the correct value
|
||||
File.Move (path, newFilename);
|
||||
path = newFilename;
|
||||
|
||||
// write the human readable results in a tmp file, which we later use to step on the logs
|
||||
var tmpFile = Path.Combine (Path.GetTempPath (), Guid.NewGuid ().ToString ());
|
||||
(parseResult.resultLine, parseResult.failed) = XmlResultParser.GenerateHumanReadableResults (path, tmpFile, xmlType);
|
||||
File.Copy (tmpFile, test_log_path, true);
|
||||
File.Delete (tmpFile);
|
||||
|
||||
// we do not longer need the tmp file
|
||||
Logs.AddFile (path, "Test xml");
|
||||
return parseResult;
|
||||
|
||||
} catch (Exception e) {
|
||||
main_log.WriteLine ("Could not parse xml result file: {0}", e);
|
||||
|
||||
// print file for better debugging
|
||||
main_log.WriteLine ("File data is:");
|
||||
main_log.WriteLine (new string ('#', 10));
|
||||
using (var stream = new StreamReader (path)) {
|
||||
string line;
|
||||
while ((line = stream.ReadLine ()) != null) {
|
||||
main_log.WriteLine (line);
|
||||
}
|
||||
}
|
||||
main_log.WriteLine (new string ('#', 10));
|
||||
main_log.WriteLine ("End of xml results.");
|
||||
if (timed_out) {
|
||||
Harness.LogWrench ($"@MonkeyWrench: AddSummary: <b><i>{mode} timed out</i></b><br/>");
|
||||
return parseResult;
|
||||
|
@ -519,17 +397,16 @@ namespace xharness
|
|||
parseResult.crashed = true;
|
||||
return parseResult;
|
||||
}
|
||||
} finally {
|
||||
if (File.Exists (tmpFile))
|
||||
File.Delete (tmpFile);
|
||||
}
|
||||
|
||||
} else {
|
||||
// delete not needed copy
|
||||
File.Delete (path);
|
||||
// not the most efficient way but this just happens when we run
|
||||
// the tests locally and we usually do not run all tests, we are
|
||||
// more interested to be efficent on the bots
|
||||
string resultLine = null;
|
||||
using (var reader = new StreamReader (listener_log.FullPath)) {
|
||||
using (var reader = new StreamReader (test_log_path)) {
|
||||
string line = null;
|
||||
bool failed = false;
|
||||
while ((line = reader.ReadLine ()) != null)
|
||||
|
@ -548,9 +425,9 @@ namespace xharness
|
|||
}
|
||||
}
|
||||
|
||||
public bool TestsSucceeded (Log listener_log, bool timed_out, bool crashed)
|
||||
public bool TestsSucceeded (string test_log_path, bool timed_out, bool crashed)
|
||||
{
|
||||
var (resultLine, failed, crashed_out) = ParseResult (listener_log, timed_out, crashed);
|
||||
var (resultLine, failed, crashed_out) = ParseResult (test_log_path, timed_out, crashed);
|
||||
// read the parsed logs in a human readable way
|
||||
if (resultLine != null) {
|
||||
var tests_run = resultLine.Replace ("Tests run: ", "");
|
||||
|
@ -614,7 +491,7 @@ namespace xharness
|
|||
args.Add ("-argument=-app-arg:-enablenetwork");
|
||||
args.Add ("-setenv=NUNIT_ENABLE_NETWORK=true");
|
||||
// detect if we are using a jenkins bot.
|
||||
var useXmlOutput = Harness.InJenkins;
|
||||
var useXmlOutput = Harness.InCI;
|
||||
if (useXmlOutput) {
|
||||
args.Add ("-setenv=NUNIT_ENABLE_XML_OUTPUT=true");
|
||||
args.Add ("-setenv=NUNIT_ENABLE_XML_MODE=wrapped");
|
||||
|
@ -899,7 +776,7 @@ namespace xharness
|
|||
var crashed = false;
|
||||
if (File.Exists (listener_log.FullPath)) {
|
||||
Harness.LogWrench ("@MonkeyWrench: AddFile: {0}", listener_log.FullPath);
|
||||
success = TestsSucceeded (listener_log, timed_out, crashed);
|
||||
success = TestsSucceeded (listener_log.FullPath, timed_out, crashed);
|
||||
} else if (timed_out) {
|
||||
Harness.LogWrench ("@MonkeyWrench: AddSummary: <b><i>{0} never launched</i></b><br/>", mode);
|
||||
main_log.WriteLine ("Test run never launched");
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace xharness.BCLTestImporter {
|
|||
MacMonoSDKPath = Harness.MONO_MAC_SDK_DESTDIR,
|
||||
Override = true,
|
||||
GuidGenerator = Harness.NewStableGuid,
|
||||
GroupTests = Harness.InJenkins || Harness.UseGroupedApps,
|
||||
GroupTests = Harness.InCI || Harness.UseGroupedApps,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ namespace xharness
|
|||
|
||||
public Harness ()
|
||||
{
|
||||
LaunchTimeout = InWrench ? 3 : 120;
|
||||
LaunchTimeout = InCI ? 3 : 120;
|
||||
}
|
||||
|
||||
public bool GetIncludeSystemPermissionTests (TestPlatform platform, bool device)
|
||||
|
@ -667,26 +667,12 @@ namespace xharness
|
|||
|
||||
public void LogWrench (string message)
|
||||
{
|
||||
if (!InWrench)
|
||||
if (!InCI)
|
||||
return;
|
||||
|
||||
Console.WriteLine (message);
|
||||
}
|
||||
|
||||
public bool InWrench {
|
||||
get {
|
||||
var buildRev = Environment.GetEnvironmentVariable ("BUILD_REVISION");
|
||||
return !string.IsNullOrEmpty (buildRev) && buildRev != "jenkins";
|
||||
}
|
||||
}
|
||||
|
||||
public bool InJenkins {
|
||||
get {
|
||||
var buildRev = Environment.GetEnvironmentVariable ("BUILD_REVISION");
|
||||
return !string.IsNullOrEmpty (buildRev) && buildRev == "jenkins";
|
||||
}
|
||||
}
|
||||
|
||||
public bool InCI {
|
||||
get {
|
||||
// We use the 'BUILD_REVISION' variable to detect whether we're running CI or not.
|
||||
|
|
|
@ -1153,7 +1153,7 @@ namespace xharness
|
|||
try {
|
||||
Directory.CreateDirectory (LogDirectory);
|
||||
Log log = Logs.Create ($"Harness-{Harness.Timestamp}.log", "Harness log");
|
||||
if (Harness.InWrench)
|
||||
if (Harness.InCI)
|
||||
log = Log.CreateAggregatedLog (log, new ConsoleLog ());
|
||||
Harness.HarnessLog = MainLog = log;
|
||||
|
||||
|
@ -1161,7 +1161,7 @@ namespace xharness
|
|||
if (IsServerMode)
|
||||
tasks.Add (RunTestServer ());
|
||||
|
||||
if (Harness.InJenkins) {
|
||||
if (Harness.InCI) {
|
||||
Task.Factory.StartNew (async () => {
|
||||
while (true) {
|
||||
await Task.Delay (TimeSpan.FromMinutes (10));
|
||||
|
@ -3735,7 +3735,7 @@ namespace xharness
|
|||
}
|
||||
|
||||
// Also clean up after us locally.
|
||||
if (Harness.InJenkins || Harness.InWrench || (Jenkins.CleanSuccessfulTestRuns && Succeeded))
|
||||
if (Harness.InCI || (Jenkins.CleanSuccessfulTestRuns && Succeeded))
|
||||
await BuildTask.CleanAsync ();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -211,7 +211,7 @@ namespace xharness
|
|||
|
||||
public static void CreateMakefile (Harness harness, IEnumerable<UnifiedTarget> unified_targets, IEnumerable<TVOSTarget> tvos_targets, IEnumerable<WatchOSTarget> watchos_targets, IEnumerable<TodayExtensionTarget> today_targets)
|
||||
{
|
||||
var executeSim32 = !harness.InWrench; // Waiting for iOS 10.3 simulator to be installed on wrench
|
||||
var executeSim32 = !harness.InCI; // Waiting for iOS 10.3 simulator to be installed on wrench
|
||||
var makefile = Path.Combine (Harness.RootDirectory, "Makefile.inc");
|
||||
using (var writer = new StreamWriter (makefile, false, new UTF8Encoding (false))) {
|
||||
writer.WriteLine (".stamp-configure-projects: Makefile xharness/xharness.exe");
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace xharness
|
|||
do {
|
||||
Log.WriteLine ("Test log server listening on: {0}:{1}", Address, Port);
|
||||
using (TcpClient client = server.AcceptTcpClient ()) {
|
||||
client.ReceiveBufferSize = buffer.Length;
|
||||
processed = Processing (client);
|
||||
}
|
||||
} while (!AutoExit || !processed);
|
||||
|
|
|
@ -0,0 +1,258 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
|
||||
namespace xharness {
|
||||
public static class XmlResultParser {
|
||||
|
||||
public enum Jargon {
|
||||
TouchUnit,
|
||||
NUnit,
|
||||
xUnit,
|
||||
Missing,
|
||||
}
|
||||
|
||||
// test if the file is valid xml, or at least, that can be read it.
|
||||
public static bool IsValidXml (string path, out Jargon type)
|
||||
{
|
||||
type = Jargon.Missing;
|
||||
if (!File.Exists (path))
|
||||
return false;
|
||||
|
||||
using (var stream = File.OpenText (path)) {
|
||||
string line;
|
||||
while ((line = stream.ReadLine ()) != null) { // special case when get got the tcp connection
|
||||
if (line.Contains ("ping"))
|
||||
continue;
|
||||
if (line.Contains ("TouchUnitTestRun")) {
|
||||
type = Jargon.TouchUnit;
|
||||
return true;
|
||||
}
|
||||
if (line.Contains ("nunit-version")) {
|
||||
type = Jargon.NUnit;
|
||||
return true;
|
||||
}
|
||||
if (line.Contains ("xUnit")) {
|
||||
type = Jargon.xUnit;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static (string resultLine, bool failed) ParseTouchUnitXml (StreamReader stream, StreamWriter writer)
|
||||
{
|
||||
long total, errors, failed, notRun, inconclusive, ignored, skipped, invalid;
|
||||
total = errors = failed = notRun = inconclusive = ignored = skipped = invalid = 0L;
|
||||
|
||||
using (var reader = XmlReader.Create (stream)) {
|
||||
while (reader.Read ()) {
|
||||
if (reader.NodeType == XmlNodeType.Element && reader.Name == "test-results") {
|
||||
long.TryParse (reader ["total"], out total);
|
||||
long.TryParse (reader ["errors"], out errors);
|
||||
long.TryParse (reader ["failures"], out failed);
|
||||
long.TryParse (reader ["not-run"], out notRun);
|
||||
long.TryParse (reader ["inconclusive"], out inconclusive);
|
||||
long.TryParse (reader ["ignored"], out ignored);
|
||||
long.TryParse (reader ["skipped"], out skipped );
|
||||
long.TryParse (reader ["invalid"], out invalid);
|
||||
}
|
||||
if (reader.NodeType == XmlNodeType.Element && reader.Name == "TouchUnitExtraData") {
|
||||
// move fwd to get to the CData
|
||||
if (reader.Read ())
|
||||
writer.Write (reader.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
var passed = total - errors - failed - notRun - inconclusive - ignored - skipped - invalid;
|
||||
var resultLine = $"Tests run: {total} Passed: {passed} Inconclusive: {inconclusive} Failed: {failed + errors} Ignored: {ignored + skipped + invalid}";
|
||||
return (resultLine, total == 0 || errors != 0 || failed != 0);
|
||||
}
|
||||
|
||||
static (string resultLine, bool failed) ParseNUnitXml (StreamReader stream, StreamWriter writer)
|
||||
{
|
||||
long total, errors, failed, notRun, inconclusive, ignored, skipped, invalid;
|
||||
total = errors = failed = notRun = inconclusive = ignored = skipped = invalid = 0L;
|
||||
XmlReaderSettings settings = new XmlReaderSettings ();
|
||||
settings.ValidationType = ValidationType.None;
|
||||
using (var reader = XmlReader.Create (stream, settings)) {
|
||||
while (reader.Read ()) {
|
||||
if (reader.NodeType == XmlNodeType.Element && reader.Name == "test-results") {
|
||||
long.TryParse (reader ["total"], out total);
|
||||
long.TryParse (reader ["errors"], out errors);
|
||||
long.TryParse (reader ["failures"], out failed);
|
||||
long.TryParse (reader ["not-run"], out notRun);
|
||||
long.TryParse (reader ["inconclusive"], out inconclusive);
|
||||
long.TryParse (reader ["ignored"], out ignored);
|
||||
long.TryParse (reader ["skipped"], out skipped);
|
||||
long.TryParse (reader ["invalid"], out invalid);
|
||||
}
|
||||
if (reader.NodeType == XmlNodeType.Element && reader.Name == "test-suite" && (reader ["type"] == "TestFixture" || reader ["type"] == "TestCollection")) {
|
||||
var testCaseName = reader ["name"];
|
||||
writer.WriteLine (testCaseName);
|
||||
var time = reader.GetAttribute ("time") ?? "0"; // some nodes might not have the time :/
|
||||
// get the first node and then move in the siblings of the same type
|
||||
reader.ReadToDescendant ("test-case");
|
||||
do {
|
||||
if (reader.Name != "test-case")
|
||||
break;
|
||||
// read the test cases in the current node
|
||||
var status = reader ["result"];
|
||||
switch (status) {
|
||||
case "Success":
|
||||
writer.Write ("\t[PASS] ");
|
||||
break;
|
||||
case "Ignored":
|
||||
writer.Write ("\t[IGNORED] ");
|
||||
break;
|
||||
case "Error":
|
||||
case "Failure":
|
||||
writer.Write ("\t[FAIL] ");
|
||||
break;
|
||||
case "Inconclusive":
|
||||
writer.Write ("\t[INCONCLUSIVE] ");
|
||||
break;
|
||||
default:
|
||||
writer.Write ("\t[INFO] ");
|
||||
break;
|
||||
}
|
||||
writer.Write (reader ["name"]);
|
||||
if (status == "Failure" || status == "Error") { // we need to print the message
|
||||
reader.ReadToDescendant ("message");
|
||||
writer.Write ($" : {reader.ReadElementContentAsString ()}");
|
||||
reader.ReadToNextSibling ("stack-trace");
|
||||
writer.Write ($" : {reader.ReadElementContentAsString ()}");
|
||||
}
|
||||
// add a new line
|
||||
writer.WriteLine ();
|
||||
} while (reader.ReadToNextSibling ("test-case"));
|
||||
writer.WriteLine ($"{testCaseName} {time} ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
var passed = total - errors - failed - notRun - inconclusive - ignored - skipped - invalid;
|
||||
string resultLine = $"Tests run: {total} Passed: {passed} Inconclusive: {inconclusive} Failed: {failed + errors} Ignored: {ignored + skipped + invalid}";
|
||||
writer.WriteLine (resultLine);
|
||||
|
||||
return (resultLine, total == 0 | errors != 0 || failed != 0);
|
||||
}
|
||||
|
||||
static (string resultLine, bool failed) ParsexUnitXml (StreamReader stream, StreamWriter writer)
|
||||
{
|
||||
long total, errors, failed, notRun, inconclusive, ignored, skipped, invalid;
|
||||
total = errors = failed = notRun = inconclusive = ignored = skipped = invalid = 0L;
|
||||
using (var reader = XmlReader.Create (stream)) {
|
||||
while (reader.Read ()) {
|
||||
if (reader.NodeType == XmlNodeType.Element && reader.Name == "assembly") {
|
||||
long.TryParse (reader ["total"], out var assemblyCount);
|
||||
total += assemblyCount;
|
||||
long.TryParse (reader ["errors"], out var assemblyErrors);
|
||||
errors += assemblyErrors;
|
||||
long.TryParse (reader ["failed"], out var assemblyFailures);
|
||||
failed += assemblyFailures;
|
||||
long.TryParse (reader ["skipped"], out var assemblySkipped);
|
||||
skipped += assemblySkipped;
|
||||
}
|
||||
if (reader.NodeType == XmlNodeType.Element && reader.Name == "collection") {
|
||||
var testCaseName = reader ["name"].Replace ("Test collection for ", "");
|
||||
writer.WriteLine (testCaseName);
|
||||
var time = reader.GetAttribute ("time") ?? "0"; // some nodes might not have the time :/
|
||||
// get the first node and then move in the siblings of the same type
|
||||
reader.ReadToDescendant ("test");
|
||||
do {
|
||||
if (reader.Name != "test")
|
||||
break;
|
||||
// read the test cases in the current node
|
||||
var status = reader ["result"];
|
||||
switch (status) {
|
||||
case "Pass":
|
||||
writer.Write ("\t[PASS] ");
|
||||
break;
|
||||
case "Skip":
|
||||
writer.Write ("\t[IGNORED] ");
|
||||
break;
|
||||
case "Fail":
|
||||
writer.Write ("\t[FAIL] ");
|
||||
break;
|
||||
default:
|
||||
writer.Write ("\t[FAIL] ");
|
||||
break;
|
||||
}
|
||||
writer.Write (reader ["name"]);
|
||||
if (status == "Fail") { // we need to print the message
|
||||
reader.ReadToDescendant ("message");
|
||||
writer.Write ($" : {reader.ReadElementContentAsString ()}");
|
||||
reader.ReadToNextSibling ("stack-trace");
|
||||
writer.Write ($" : {reader.ReadElementContentAsString ()}");
|
||||
}
|
||||
// add a new line
|
||||
writer.WriteLine ();
|
||||
} while (reader.ReadToNextSibling ("test"));
|
||||
writer.WriteLine ($"{testCaseName} {time} ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
var passed = total - errors - failed - notRun - inconclusive - ignored - skipped - invalid;
|
||||
string resultLine = $"Tests run: {total} Passed: {passed} Inconclusive: {inconclusive} Failed: {failed + errors} Ignored: {ignored + skipped + invalid}";
|
||||
writer.WriteLine (resultLine);
|
||||
|
||||
return (resultLine, total == 0 | errors != 0 || failed != 0);
|
||||
}
|
||||
|
||||
public static string GetXmlFilePath (string path, Jargon xmlType)
|
||||
{
|
||||
var fileName = Path.GetFileName (path);
|
||||
switch (xmlType) {
|
||||
case Jargon.TouchUnit:
|
||||
case Jargon.NUnit:
|
||||
return path.Replace (fileName, $"nunit-{fileName}");
|
||||
case Jargon.xUnit:
|
||||
return path.Replace (fileName, $"xunit-{fileName}");
|
||||
default:
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
public static void CleanXml (string source, string destination)
|
||||
{
|
||||
using (var reader = new StreamReader (source))
|
||||
using (var writer = new StreamWriter (destination)) {
|
||||
string line;
|
||||
while ((line = reader.ReadLine ()) != null) {
|
||||
if (line.StartsWith ("ping", StringComparison.Ordinal) || line.Contains ("TouchUnitTestRun") || line.Contains ("NUnitOutput") || line.Contains ("<!--")) {
|
||||
continue;
|
||||
}
|
||||
if (line == "") // remove white lines, some files have them
|
||||
continue;
|
||||
if (line.Contains ("TouchUnitExtraData")) // always last node in TouchUnit
|
||||
break;
|
||||
writer.WriteLine (line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static (string resultLine, bool failed) GenerateHumanReadableResults (string source, string destination, Jargon xmlType)
|
||||
{
|
||||
(string resultLine, bool failed) parseData;
|
||||
using (var reader = new StreamReader (source))
|
||||
using (var writer = new StreamWriter (destination, true)) {
|
||||
switch (xmlType) {
|
||||
case Jargon.TouchUnit:
|
||||
parseData = ParseTouchUnitXml (reader, writer);
|
||||
break;
|
||||
case Jargon.NUnit:
|
||||
parseData = ParseNUnitXml (reader, writer);
|
||||
break;
|
||||
case Jargon.xUnit:
|
||||
parseData = ParsexUnitXml (reader, writer);
|
||||
break;
|
||||
default:
|
||||
parseData = ("", true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return parseData;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -128,6 +128,7 @@
|
|||
<Compile Include="..\..\tools\bcl-test-importer\BCLTestImporter\BCLTestInfoPlistGenerator.cs">
|
||||
<Link>BCLTestImporter\BCLTestInfoPlistGenerator.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="XmlResultParser.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="BCLTestImporter\" />
|
||||
|
|
Загрузка…
Ссылка в новой задаче