Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support NUnit test properties #89

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/extension/Event.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace NUnit.Engine.Listeners
{
using System;
using System.Xml;

public struct Event
Expand All @@ -8,9 +9,13 @@ public struct Event
public readonly string MessageName;
public readonly string FullName;
public readonly string Name;
public readonly string Type;
public readonly string Id;
public readonly string ParentId;

// ReSharper disable once InconsistentNaming
public readonly string TestId;

// ReSharper disable once InconsistentNaming
public readonly XmlNode TestEvent;

Expand All @@ -22,6 +27,7 @@ public Event(
string id,
string parentId,
string testId,
string type,
XmlNode testEvent)
{
RootFlowId = rootFlowId;
Expand All @@ -31,12 +37,15 @@ public Event(
Id = id;
ParentId = parentId;
TestId = testId;
Type = type;
TestEvent = testEvent;
}

public override string ToString()
{
return string.Format("RootFlowId: {0}, MessageName: {1}, FullName: {2}, Id: {3}, ParentId: {4}, Event: {5}", RootFlowId, MessageName, FullName, Id, ParentId, TestEvent.OuterXml);
return string.Format(
"RootFlowId: {0}, MessageName: {1}, FullName: {2}, Id: {3}, ParentId: {4}, Type: {5}, TestEvent.OuterXml: {6}{7}",
RootFlowId, MessageName, FullName, Id, ParentId, Type, Environment.NewLine, TestEvent.OuterXml);
}
}
}
}
110 changes: 95 additions & 15 deletions src/extension/EventConverter3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,24 @@ namespace NUnit.Engine.Listeners
using System;
using System.Xml;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;

internal class EventConverter3: IEventConverter
internal class EventConverter3 : IEventConverter
{
private readonly IServiceMessageFactory _serviceMessageFactory;
private readonly IHierarchy _hierarchy;
private readonly Statistics _statistics;
private readonly ITeamCityInfo _teamCityInfo;

private readonly Dictionary<string, List<EventId>> _testSuiteTestEvents =
new Dictionary<string, List<EventId>>();

private readonly Dictionary<string, XmlNode> _notStartedNUnit3Tests = new Dictionary<string, XmlNode>();
private readonly Dictionary<string, string> _suiteAssembly = new Dictionary<string, string>();

public EventConverter3(IServiceMessageFactory serviceMessageFactory, IHierarchy hierarchy, Statistics statistics, ITeamCityInfo teamCityInfo)
public EventConverter3(IServiceMessageFactory serviceMessageFactory, IHierarchy hierarchy,
Statistics statistics, ITeamCityInfo teamCityInfo)
{
if (serviceMessageFactory == null) throw new ArgumentNullException("serviceMessageFactory");
if (hierarchy == null) throw new ArgumentNullException("hierarchy");
Expand All @@ -53,13 +61,15 @@ public IEnumerable<IEnumerable<ServiceMessage>> Convert(Event testEvent)
if (testEvent.MessageName == "start-run")
{
_hierarchy.Clear();
_suiteAssembly.Clear();
_notStartedNUnit3Tests.Clear();
_testSuiteTestEvents.Clear();
yield break;
}

var id = testEvent.Id;
var parentId = testEvent.ParentId;

string rootId;
var flowId = _hierarchy.TryFindRootId(parentId, out rootId) ? rootId : id;
var testFlowId = id != flowId ? id : flowId;
Expand All @@ -69,6 +79,8 @@ public IEnumerable<IEnumerable<ServiceMessage>> Convert(Event testEvent)
rootFlowId = ".";
}

var testEventId = new EventId(_teamCityInfo, testFlowId, testEvent.FullName);

var eventId = new EventId(_teamCityInfo, flowId, testEvent.FullName);
switch (testEvent.MessageName)
{
Expand All @@ -78,41 +90,61 @@ public IEnumerable<IEnumerable<ServiceMessage>> Convert(Event testEvent)
// Root
if (parentId == string.Empty)
{
//Save assembly name
_suiteAssembly[flowId] = testEvent.Name;

// Start a flow from a root flow https://youtrack.jetbrains.com/issue/TW-56310
yield return _serviceMessageFactory.FlowStarted(flowId, rootFlowId);

_statistics.RegisterSuiteStart();
yield return _serviceMessageFactory.SuiteStarted(eventId, testEvent);
yield return _serviceMessageFactory.SuiteStarted(eventId, testEvent);
}

break;

case "test-suite":
_hierarchy.AddLink(id, parentId);
if (_suiteAssembly.ContainsKey(rootFlowId))
{
_suiteAssembly[flowId] = _suiteAssembly[rootFlowId];
}

yield return ProcessNotStartedTests(flowId, id, testEvent.TestEvent);
yield return ProcessTestSuiteProperties(flowId, id, testEvent.TestEvent);
yield return _serviceMessageFactory.TestOutputAsMessage(eventId, testEvent.TestEvent);

// Root
if (parentId == string.Empty)
{
_statistics.RegisterSuiteFinish();
yield return _serviceMessageFactory.SuiteFinished(eventId, testEvent);
yield return _serviceMessageFactory.SuiteFinished(eventId, testEvent);

// Finish a child flow from a root flow https://youtrack.jetbrains.com/issue/TW-56310
yield return _serviceMessageFactory.FlowFinished(flowId);
yield return _serviceMessageFactory.FlowFinished(flowId);
}

break;

case "start-test":
List<EventId> existingEventList;
if (_testSuiteTestEvents.TryGetValue(parentId, out existingEventList))
{
existingEventList.Add(testEventId);
}
else
{
_testSuiteTestEvents[parentId] = new List<EventId>() { testEventId };
}

_hierarchy.AddLink(id, parentId);
if (testFlowId != eventId.FlowId)
{
yield return _serviceMessageFactory.FlowStarted(testFlowId, eventId.FlowId);
}

_statistics.RegisterTestStart();
yield return _serviceMessageFactory.TestStarted(new EventId(_teamCityInfo, testFlowId, eventId.FullName));
yield return _serviceMessageFactory.TestStarted(new EventId(_teamCityInfo, testFlowId,
eventId.FullName));
break;

case "test-case":
Expand All @@ -124,11 +156,13 @@ public IEnumerable<IEnumerable<ServiceMessage>> Convert(Event testEvent)
}

_statistics.RegisterTestFinish();
yield return _serviceMessageFactory.TestFinished(new EventId(_teamCityInfo, testFlowId, testEvent.FullName), testEvent.TestEvent, testEvent.TestEvent);
yield return _serviceMessageFactory.TestFinished(testEventId, testEvent.TestEvent,
testEvent.TestEvent);

if (id != flowId && parentId != null)
{
yield return _serviceMessageFactory.FlowFinished(id);
}
}

break;

Expand All @@ -137,11 +171,55 @@ public IEnumerable<IEnumerable<ServiceMessage>> Convert(Event testEvent)
break;

case "test-output":
testFlowId = testEvent.TestId ?? rootFlowId;
yield return _serviceMessageFactory.TestOutput(new EventId(_teamCityInfo, testFlowId, testEvent.FullName), testEvent.TestEvent);
yield return _serviceMessageFactory.TestOutput(testEventId, testEvent.TestEvent);
break;
}
}
}

private IEnumerable<ServiceMessage> ProcessTestSuiteProperties(string flowId, string suiteId,
XmlNode testSuiteNode)
{
var properties = testSuiteNode.SelectNodes("properties/property");
List<EventId> testEventIds;

if (_testSuiteTestEvents.TryGetValue(suiteId, out testEventIds) && properties != null)
{
var props = new NameValueCollection();
foreach (var property in properties)
{
var propertyElement = property as XmlNode;
if (propertyElement == null)
{
continue;
}

var propertyName = propertyElement.GetAttribute("name") ?? string.Empty;
var propertyValue = propertyElement.GetAttribute("value") ?? string.Empty;

props.Add(propertyName, propertyValue);
}

if (testEventIds.Count > 0)
{
foreach (var eventId in testEventIds)
{
foreach (var name in props.AllKeys)
{
string assemblyName;
var dllName = _suiteAssembly.TryGetValue(flowId, out assemblyName) ? assemblyName : "";
var testFullName = dllName == "" ? eventId.FullName : dllName + ": " + eventId.FullName;
var attrs = new List<ServiceMessageAttr>
{
new ServiceMessageAttr(ServiceMessageAttr.Names.TestName, testFullName),
new ServiceMessageAttr(ServiceMessageAttr.Names.Name, name),
new ServiceMessageAttr(ServiceMessageAttr.Names.Value, props[name])
};
yield return new ServiceMessage(ServiceMessage.Names.TestMetadata, attrs);
}
}
}
}
}

private IEnumerable<ServiceMessage> ProcessNotStartedTests(string flowId, string id, XmlNode currentEvent)
{
Expand Down Expand Up @@ -169,18 +247,20 @@ private IEnumerable<ServiceMessage> ProcessNotStartedTests(string flowId, string
continue;
}

foreach (var message in _serviceMessageFactory.TestStarted(new EventId(_teamCityInfo, flowId, fullName)))
foreach (var message in
_serviceMessageFactory.TestStarted(new EventId(_teamCityInfo, flowId, fullName)))
{
_statistics.RegisterTestStart();
yield return message;
}

foreach (var message in _serviceMessageFactory.TestFinished(new EventId(_teamCityInfo, flowId, fullName), testEvent, currentEvent))
foreach (var message in _serviceMessageFactory.TestFinished(
new EventId(_teamCityInfo, flowId, fullName), testEvent, currentEvent))
{
_statistics.RegisterTestFinish();
yield return message;
}
}
}
}
}
}
4 changes: 2 additions & 2 deletions src/extension/EventId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ internal struct EventId
public readonly string FlowId;
public readonly string FullName;

public EventId(ITeamCityInfo tamCityInfo, string flowId, string fullName)
public EventId(ITeamCityInfo teamCityInfo, string flowId, string fullName)
{
FlowId = flowId;
// TeamCity extracts the name of assembly from the test name
Expand All @@ -21,7 +21,7 @@ public EventId(ITeamCityInfo tamCityInfo, string flowId, string fullName)
// assembly name = "abc.dll"
// test name = "text1"

FullName = fullName.Replace(":", tamCityInfo.ColonReplacement);
FullName = fullName.Replace(":", teamCityInfo.ColonReplacement);
}
}
}
2 changes: 1 addition & 1 deletion src/extension/IServiceMessageFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ internal interface IServiceMessageFactory
IEnumerable<ServiceMessage> SuiteStarted(EventId eventId, Event testEvent);

IEnumerable<ServiceMessage> SuiteFinished(EventId eventId, Event testEvent);

IEnumerable<ServiceMessage> FlowStarted(string flowId, string parentFlowId);

IEnumerable<ServiceMessage> FlowFinished(string flowId);
Expand Down
3 changes: 1 addition & 2 deletions src/extension/IServiceMessageWriter.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
namespace NUnit.Engine.Listeners
{
using System.Collections.Generic;
using System.IO;

public interface IServiceMessageWriter
{
void Write(TextWriter writer, IEnumerable<ServiceMessage> serviceMessages);
void Write(TextWriter writer, ServiceMessage serviceMessages);
}
}
29 changes: 18 additions & 11 deletions src/extension/ServiceMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,19 @@ public ServiceMessage(string name, params ServiceMessageAttr[] attributes)
{
}

public ServiceMessage(string name, IList<ServiceMessageAttr> attributes)
: this()
public ServiceMessage(string name, IList<ServiceMessageAttr> attributes) : this()
{
// ReSharper disable once UseNameofExpression
if (name == null) throw new ArgumentNullException("name");
// ReSharper disable once UseNameofExpression
if (attributes == null) throw new ArgumentNullException("attributes");

Name = name;
Value = string.Empty;
Attributes = new ReadOnlyCollection<ServiceMessageAttr>(attributes);
}

public ServiceMessage(string name, string value)
: this()
public ServiceMessage(string name, string value) : this()
{
// ReSharper disable once UseNameofExpression
if (name == null) throw new ArgumentNullException("name");
// ReSharper disable once UseNameofExpression
if (value == null) throw new ArgumentNullException("value");

Name = name;
Expand All @@ -69,6 +63,19 @@ public ServiceMessage(string name, string value)

public IEnumerable<ServiceMessageAttr> Attributes { get; private set; }

public string Dump(string prefix)
{
var attributes = "";
foreach (var serviceMessageAttr in Attributes)
{
attributes += " { " + serviceMessageAttr.Name + ": " + serviceMessageAttr.Value + " }" +
Environment.NewLine;
}

return "MSG " + prefix + ":" + Environment.NewLine + " Name: '" + Name + "', Value: '" + Value +
"', Attributes: " + Environment.NewLine + attributes;
}

[SuppressMessage("ReSharper", "InconsistentNaming")]
public static class Names
{
Expand All @@ -83,8 +90,8 @@ public static class Names
public const string TestFailed = "testFailed";
public const string TestIgnored = "testIgnored";
public const string Message = "message";
public const string PublishArtifacts = "publishArtifacts";
public const string PublishArtifacts = "publishArtifacts";
public const string TestMetadata = "testMetadata";
}
}
}
}
}
Loading