diff --git a/BoostTestAdapter/Boost/Results/BoostStandardOutput.cs b/BoostTestAdapter/Boost/Results/BoostStandardOutput.cs
index 600bf4c..e8f1d2c 100644
--- a/BoostTestAdapter/Boost/Results/BoostStandardOutput.cs
+++ b/BoostTestAdapter/Boost/Results/BoostStandardOutput.cs
@@ -1,41 +1,41 @@
-// (C) Copyright ETAS 2015.
-// Distributed under the Boost Software License, Version 1.0.
-// (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-using System.Collections.Generic;
+// (C) Copyright ETAS 2015.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+using System.Collections.Generic;
using BoostTestAdapter.Boost.Results.LogEntryTypes;
-namespace BoostTestAdapter.Boost.Results
-{
- ///
- /// Standard Output as emitted by Boost Test executables
- ///
- public class BoostStandardOutput : BoostConsoleOutputBase
- {
- #region Constructors
-
- ///
- /// Constructor accepting a path to the external file
- ///
- /// The destination result collection. Possibly used for result aggregation.
- public BoostStandardOutput(IDictionary target)
- : base(target)
- {
- }
-
- #endregion Constructors
-
- #region BoostConsoleOutputBase
-
- protected override LogEntry CreateLogEntry(string message)
- {
- return new LogEntryStandardOutputMessage()
- {
- Detail = message
- };
- }
-
- #endregion BoostConsoleOutputBase
- }
+namespace BoostTestAdapter.Boost.Results
+{
+ ///
+ /// Standard Output as emitted by Boost Test executables
+ ///
+ public class BoostStandardOutput : BoostConsoleOutputBase
+ {
+ #region Constructors
+
+ ///
+ /// Constructor accepting a path to the external file
+ ///
+ /// The destination result collection. Possibly used for result aggregation.
+ public BoostStandardOutput(IDictionary target)
+ : base(target)
+ {
+ }
+
+ #endregion Constructors
+
+ #region BoostConsoleOutputBase
+
+ protected override LogEntry CreateLogEntry(string message)
+ {
+ return new LogEntryStandardOutputMessage()
+ {
+ Detail = message
+ };
+ }
+
+ #endregion BoostConsoleOutputBase
+ }
}
\ No newline at end of file
diff --git a/BoostTestAdapter/Boost/Test/TestFrameworkDOTDeserialiser.cs b/BoostTestAdapter/Boost/Test/TestFrameworkDOTDeserialiser.cs
index 94eff63..ec8a92e 100644
--- a/BoostTestAdapter/Boost/Test/TestFrameworkDOTDeserialiser.cs
+++ b/BoostTestAdapter/Boost/Test/TestFrameworkDOTDeserialiser.cs
@@ -1,545 +1,506 @@
-// (C) Copyright ETAS 2015.
-// Distributed under the Boost Software License, Version 1.0.
-// (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-using System;
-using System.IO;
-using System.Linq;
-using System.Globalization;
-using System.Collections.Generic;
-
-using Antlr.DOT;
-using Antlr4.Runtime.Tree;
-using Antlr4.Runtime.Misc;
-
-using BoostTestAdapter.Utility;
-
-namespace BoostTestAdapter.Boost.Test
-{
- ///
- /// A Test Framework deserialiser which generates a
- /// Test Framework instance from a Boost Test DOT representation.
- ///
- public class TestFrameworkDOTDeserialiser
- {
- ///
- /// Constructor
- ///
- /// The test module source file path
- public TestFrameworkDOTDeserialiser(string source)
- {
- this.Source = source;
- }
-
- ///
- /// The test module source file path
- ///
- public string Source { get; private set; }
-
- ///
- /// Parses the stream containing a Boost Test DOT representation of a Test Framework
- ///
- /// The stream consisting of a DOT representation
- /// The deserialised Test Framework
- public TestFramework Deserialise(Stream stream)
- {
- return Deserialise(stream, null);
- }
-
- ///
- /// Parses the stream containing a Boost Test DOT representation of a Test Framework. Notifies the
- /// provided visitor (during parsing) of any identified test units.
- ///
- /// The stream consisting of a DOT representation
- /// The visitor which will be notified during parsing
- /// The deserialised Test Framework
- ///
- /// The visitor will not necessarily be notified in a top-down fashion. To ensure top-down
- /// visitation, wait for the result and visit the master test suite.
- ///
- public TestFramework Deserialise(Stream stream, ITestVisitor visitor)
- {
- BoostTestFrameworkVisitor dotVisitor = new BoostTestFrameworkVisitor(this, visitor);
- return DOT.Parse(stream, dotVisitor);
- }
-
- ///
- /// Implementation of DOTBaseVisitor which creates/populates a
- /// TestFramework instance from a DOT abstract syntax tree.
- ///
- private class BoostTestFrameworkVisitor : DOTBaseVisitor
- {
- ///
- /// Constructor
- ///
- /// The parent TestFrameworkDOTDeserialiser instance
- public BoostTestFrameworkVisitor(TestFrameworkDOTDeserialiser parent, ITestVisitor visitor)
- {
- this.Parent = parent;
- this.Visitor = visitor;
-
- this.Framework = null;
- this.Context = null;
- }
-
- ///
- /// The parent TestFrameworkDOTDeserialiser instance
- ///
- public TestFrameworkDOTDeserialiser Parent { get; private set; }
-
- ///
- /// An ITestVisitor which is to be notified once a test unit has been fully defined
- ///
- public ITestVisitor Visitor { get; private set; }
-
- ///
- /// The generated Test Framework
- ///
- public TestFramework Framework { get; private set; }
-
- ///
- /// Context class used to aggregate information during parsing
- ///
- private class DOTContext
- {
- ///
- /// Default Constructor
- ///
- public DOTContext()
- {
- this.TestUnits = new Stack();
- }
-
- ///
- /// The current parent test suite which will host child test cases
- ///
- public TestSuite ParentSuite { get; set; }
-
- ///
- /// The master test suite
- ///
- public TestSuite MasterTestSuite { get; set; }
-
- ///
- /// In-progress test unit information which is currently being parsed
- ///
- public Stack TestUnits { get; private set; }
- }
-
- ///
- /// The current deserialisation context
- ///
- private DOTContext Context { get; set; }
-
- #region DOTBaseVisitor
-
- public override TestFramework VisitGraph([NotNull] DOTParser.GraphContext context)
- {
- this.Context = new DOTContext();
- this.Framework = null;
-
- // Visit children
- this.Framework = base.VisitGraph(context);
-
- this.Framework = new TestFramework(this.Parent.Source, this.Context.MasterTestSuite);
- this.Context = null;
-
- return this.Framework;
- }
-
- public override TestFramework VisitSubgraph([NotNull] DOTParser.SubgraphContext context)
- {
- TestUnitInfo info = this.Context.TestUnits.Peek();
-
- TestSuite suite = CreateTestSuite(info, this.Context.ParentSuite);
- this.Context.ParentSuite = suite;
-
- if (this.Context.MasterTestSuite == null)
- {
- this.Context.MasterTestSuite = suite;
- }
-
- // Visit Children
- this.Framework = base.VisitSubgraph(context);
-
- // Register any child test cases
- while (info != this.Context.TestUnits.Peek())
- {
- TestCase test = CreateTestCase(this.Context.TestUnits.Pop(), this.Context.ParentSuite);
- Visit(test);
- }
-
- // NOTE Suite is visited after children since it is at this point that we
- // can guarantee that the suite is fully formed
- Visit(suite);
-
- this.Context.TestUnits.Pop();
- this.Context.ParentSuite = (TestSuite)suite.Parent;
-
- return this.Framework;
- }
-
- public override TestFramework VisitNode_stmt([NotNull] DOTParser.Node_stmtContext context)
- {
- TestUnitInfo info = new TestUnitInfo(context.node_id().GetText());
-
- foreach (var attribute in GetKeyValuePairs(context.attr_list()))
- {
- switch (attribute.Key)
- {
- case "color":
- {
- // 'green' implies that the test is explicitly enabled by default
- // 'yellow' implies that it is enabled, but *may* be disabled
- info.DefaultEnabled = (attribute.Value == "green");
- break;
- }
-
- case "label":
- {
- // Parse BOOST Test specific content
- info.Parse(attribute.Value.Trim('"'));
- break;
- }
- }
- };
-
- this.Context.TestUnits.Push(info);
-
- return base.VisitNode_stmt(context);
- }
-
- public override TestFramework VisitEdge_stmt([NotNull] DOTParser.Edge_stmtContext context)
- {
- TestUnitInfo info = this.Context.TestUnits.Peek();
-
- if (info != null)
- {
- var lhs = context.node_id();
- var rhs = lhs;
-
- var edgeRhs = context.edgeRHS();
-
- // NOTE Boost Test DOT output only define one edge per edge statement
- if (edgeRhs.edgeop().Length == 1)
- {
- var edgeop = edgeRhs.edgeop()[0];
- // Ensure that a directed edge '->' token is used
- if (edgeop.GetToken(DOTLexer.T__7, 0) != null)
- {
- rhs = edgeRhs.node_id()[0];
- }
- }
-
- if ((lhs != rhs) && (rhs != null))
- {
- // Identify whether this edge is a constraining edge (i.e. an actual graph edge) or a non-constraining edge
- bool constraint = !GetKeyValuePairs(context.attr_list()).Any((attribute) => (attribute.Key == "constraint") && (attribute.Value == "false"));
-
- // This implies a test dependency
- if ((lhs.GetText() == info.id) && !constraint)
- {
- info.Dependencies.Add(rhs.GetText());
- }
- // This implies a test unit relationship
- else if (rhs.GetText() == info.id)
- {
- info.Parents.Add(lhs.GetText());
- }
- }
- }
-
- return base.VisitEdge_stmt(context);
- }
-
- #endregion DOTBaseVisitor
-
- ///
- /// Iterates over all key-value pair attributes contained within the provided attr_list
- ///
- /// The attr_list to iterate
- /// An enumeration of all key-value pairs present in the provided attr_list
- private static IEnumerable> GetKeyValuePairs(DOTParser.Attr_listContext attr_list)
- {
- // NOTE Refer to DOT grammar; an 'attr_list' is composed of an 'a_list', which is composed of multiple 'id's
-
- if (attr_list != null)
- {
- var a_lists = attr_list.a_list();
- if (a_lists != null)
- {
- for (int i = 0; i < a_lists.Length; ++i)
- {
- var a_list = a_lists[i];
-
- int id = 0;
- int idCount = a_list.id().Length;
-
- // Try to identify the id() list as a list of 'id' = 'id' tuples
-
- while (id < idCount)
- {
- var lhs = a_list.id()[id];
-
- // Reference: Antlr4 C# Runtime [ParserRuleContext.GetTokens(int)]
- var sibling = a_list.GetChild(a_list.children.IndexOf(lhs) + 1) as ITerminalNode;
-
- // Identify if the a_list contains a key/value pair separated by the '=' token
- if ((sibling != null) && (sibling.Symbol.Type == DOTLexer.T__3))
- {
- yield return new KeyValuePair(lhs.GetText(), a_list.id()[id + 1].GetText());
- id += 2;
- }
- // Else provide the identifier a single item
- else
- {
- yield return new KeyValuePair(lhs.GetText(), null);
- ++id;
- }
- }
- }
- }
- }
- }
-
- ///
- /// Creates a TestSuite instance from the provided TestUnitInfo structure
- ///
- /// The currently accumulated test unit information
- /// The parent test suite of this test unit
- /// A TestSuite based on the provided information
- private static TestSuite CreateTestSuite(TestUnitInfo info, TestSuite parent)
- {
- return PopulateTestUnit(info, new TestSuite(info.Name, parent));
- }
-
- ///
- /// Creates a TestCase instance from the provided TestUnitInfo structure
- ///
- /// The currently accumulated test unit information
- /// The parent test suite of this test unit
- /// A TestCase based on the provided information
- private static TestCase CreateTestCase(TestUnitInfo info, TestSuite parent)
- {
- return PopulateTestUnit(info, new TestCase(info.Name, parent));
- }
-
- ///
- /// Populates the provided TestUnit with the test unit information
- ///
- /// A TestUnit derived type
- /// The currently accumulated test unit information
- /// The test unit instance which is to be populated
- /// unit
- private static T PopulateTestUnit(TestUnitInfo info, T unit) where T : TestUnit
- {
- if ((!string.IsNullOrEmpty(info.id)) && (info.id.Length > 2))
- {
- // Remove the 'tu' prefix from the test unit string ID
-
- int id = 0;
- if (int.TryParse(info.id.Substring(2), NumberStyles.Integer, CultureInfo.InvariantCulture, out id))
- {
- unit.Id = id;
- }
- }
-
- unit.Source = info.SourceInfo;
- unit.Labels = info.Labels;
-
- unit.DefaultEnabled = info.DefaultEnabled;
-
- // Default Enabled
- // Timeout
- // Expected Failures
- // Dependencies
-
- return unit;
- }
-
- ///
- /// Allows the registered ITestVisitor to visit the completed TestUnit definition
- ///
- /// The test unit to visit
- void Visit(TestUnit unit)
- {
- if (this.Visitor != null)
- {
- unit.Apply(this.Visitor);
- }
- }
-
- ///
- /// Aggregation of test unit information contained within a Boost Test DOT serialisation
- ///
- private class TestUnitInfo
- {
- ///
- /// Constructor
- ///
- /// Test Unit ID (e.g. tu1)
- public TestUnitInfo(string id)
- {
- this.id = id;
-
- this.Name = string.Empty;
- this.SourceInfo = null;
- this.Timeout = 0;
- this.ExpectedFailures = 0;
- this.Labels = Enumerable.Empty();
-
- this.Parents = new List();
- this.Dependencies = new List();
-
- this.DefaultEnabled = true;
- }
-
- ///
- /// Test Unit ID (e.g. tu1)
- ///
- public string id { get; private set; }
-
- ///
- /// Test Unit Name
- ///
- public string Name { get; set; }
-
- ///
- /// Source information
- ///
- public SourceFileInfo SourceInfo { get; set; }
-
- ///
- /// Test timeout
- ///
- public uint Timeout { get; set; }
-
- ///
- /// Test expected failure count
- ///
- public uint ExpectedFailures { get; set; }
-
- ///
- /// Test labels
- ///
- public IEnumerable Labels { get; set; }
-
- ///
- /// Test unit children
- ///
- public List Parents { get; set; }
-
- ///
- /// Test unit dependencies
- ///
- public List Dependencies { get; set; }
-
- ///
- /// Flag which is raised when the test is explicitly set to true
- ///
- public bool DefaultEnabled { get; set; }
-
- ///
- /// Parses test unit information from the provided string
- ///
- /// The string to parse
- /// Test unit information contained within value
- ///
- public TestUnitInfo Parse(string value)
- {
- TestUnitInfo info = new TestUnitInfo(this.id);
- info.DefaultEnabled = this.DefaultEnabled;
- string[] properties = value.Split('|');
-
- if (properties.Length > 0)
- {
- info.Name = properties[0];
- }
- if (properties.Length > 1)
- {
- info.SourceInfo = SourceFileInfo.Parse(properties[1]);
- }
- if (properties.Length > 2)
- {
- foreach (var attribute in ParseKeyValuePairs(properties.Skip(2)))
- {
- ParseNamedAttribute(info, attribute);
- }
- }
-
- // Replace the contents of 'this' with that of 'info'
- Set(info);
-
- return this;
- }
-
- ///
- /// Sets the current instance properties to the one provided
- ///
- ///
- private void Set(TestUnitInfo value)
- {
- this.id = value.id;
- this.Name = value.Name;
- this.SourceInfo = value.SourceInfo;
- this.DefaultEnabled = value.DefaultEnabled;
- this.Timeout = value.Timeout;
- this.ExpectedFailures = value.ExpectedFailures;
- this.Labels = value.Labels;
- this.Parents = value.Parents;
- this.Dependencies = value.Dependencies;
- }
-
- ///
- /// Parses a Boost Test DOT named attribute label
- ///
- /// The test unit information structure which to populate
- /// The attribute to parse
- private static void ParseNamedAttribute(TestUnitInfo info, KeyValuePair attribute)
- {
- switch (attribute.Key)
- {
- case "timeout":
- {
- info.Timeout = uint.Parse(attribute.Value, CultureInfo.InvariantCulture);
- break;
- }
- case "expected failures":
- {
- info.ExpectedFailures = uint.Parse(attribute.Value, CultureInfo.InvariantCulture);
- break;
- }
- case "labels":
- {
- var labels = attribute.Value.Split(new[] { " @" }, StringSplitOptions.RemoveEmptyEntries);
- if (labels.Length > 0)
- {
- info.Labels = labels;
- }
- break;
- }
- }
- }
-
- ///
- /// Parses the Boost Test DOT label attributes for any key-value pairs
- ///
- /// The values/attributes to parse
- /// An enumeration of successfully parsed key-value pairs
- private static IEnumerable> ParseKeyValuePairs(IEnumerable values)
- {
- foreach (string value in values)
- {
- // NOTE 'timeout' and 'expected failures' use '=' as a separator, 'labels' use ':'
- string[] keyValue = value.Split(new[] { '=', ':' }, 2, StringSplitOptions.RemoveEmptyEntries);
- if (keyValue.Length == 2)
- {
- yield return new KeyValuePair(keyValue[0], keyValue[1]);
- }
- }
- }
- }
- }
- }
+// (C) Copyright ETAS 2015.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Globalization;
+using System.Collections.Generic;
+
+using Antlr.DOT;
+using Antlr4.Runtime.Tree;
+using Antlr4.Runtime.Misc;
+
+using BoostTestAdapter.Utility;
+
+namespace BoostTestAdapter.Boost.Test
+{
+ ///
+ /// A Test Framework deserialiser which generates a
+ /// Test Framework instance from a Boost Test DOT representation.
+ ///
+ public class TestFrameworkDOTDeserialiser
+ {
+ ///
+ /// Constructor
+ ///
+ /// The test module source file path
+ public TestFrameworkDOTDeserialiser(string source)
+ {
+ this.Source = source;
+ }
+
+ ///
+ /// The test module source file path
+ ///
+ public string Source { get; private set; }
+
+ ///
+ /// Parses the stream containing a Boost Test DOT representation of a Test Framework
+ ///
+ /// The stream consisting of a DOT representation
+ /// The deserialised Test Framework
+ public TestFramework Deserialise(Stream stream)
+ {
+ BoostTestFrameworkVisitor dotVisitor = new BoostTestFrameworkVisitor(this);
+ return DOT.Parse(stream, dotVisitor);
+ }
+
+ ///
+ /// Implementation of DOTBaseVisitor which creates/populates a
+ /// TestFramework instance from a DOT abstract syntax tree.
+ ///
+ private class BoostTestFrameworkVisitor : DOTBaseVisitor
+ {
+ ///
+ /// Constructor
+ ///
+ /// The parent TestFrameworkDOTDeserialiser instance
+ public BoostTestFrameworkVisitor(TestFrameworkDOTDeserialiser parent)
+ {
+ this.Parent = parent;
+
+ this.Framework = null;
+ this.Context = null;
+ }
+
+ ///
+ /// The parent TestFrameworkDOTDeserialiser instance
+ ///
+ public TestFrameworkDOTDeserialiser Parent { get; private set; }
+
+ ///
+ /// The generated Test Framework
+ ///
+ public TestFramework Framework { get; private set; }
+
+ ///
+ /// Context class used to aggregate information during parsing
+ ///
+ private class DOTContext
+ {
+ ///
+ /// Default Constructor
+ ///
+ public DOTContext()
+ {
+ this.TestUnits = new Stack();
+ }
+
+ ///
+ /// The current parent test suite which will host child test cases
+ ///
+ public TestSuite ParentSuite { get; set; }
+
+ ///
+ /// The master test suite
+ ///
+ public TestSuite MasterTestSuite { get; set; }
+
+ ///
+ /// In-progress test unit information which is currently being parsed
+ ///
+ public Stack TestUnits { get; private set; }
+ }
+
+ ///
+ /// The current deserialisation context
+ ///
+ private DOTContext Context { get; set; }
+
+ #region DOTBaseVisitor
+
+ public override TestFramework VisitGraph([NotNull] DOTParser.GraphContext context)
+ {
+ this.Context = new DOTContext();
+ this.Framework = null;
+
+ // Visit children
+ this.Framework = base.VisitGraph(context);
+
+ this.Framework = new TestFramework(this.Parent.Source, this.Context.MasterTestSuite);
+ this.Context = null;
+
+ return this.Framework;
+ }
+
+ public override TestFramework VisitSubgraph([NotNull] DOTParser.SubgraphContext context)
+ {
+ TestUnitInfo info = this.Context.TestUnits.Peek();
+
+ TestSuite suite = CreateTestSuite(info, this.Context.ParentSuite);
+ this.Context.ParentSuite = suite;
+
+ if (this.Context.MasterTestSuite == null)
+ {
+ this.Context.MasterTestSuite = suite;
+ }
+
+ // Visit Children
+ this.Framework = base.VisitSubgraph(context);
+
+ // Register any child test cases
+ while (info != this.Context.TestUnits.Peek())
+ {
+ CreateTestCase(this.Context.TestUnits.Pop(), this.Context.ParentSuite);
+ }
+
+ this.Context.TestUnits.Pop();
+ this.Context.ParentSuite = (TestSuite)suite.Parent;
+
+ return this.Framework;
+ }
+
+ public override TestFramework VisitNode_stmt([NotNull] DOTParser.Node_stmtContext context)
+ {
+ TestUnitInfo info = new TestUnitInfo(context.node_id().GetText());
+
+ foreach (var attribute in GetKeyValuePairs(context.attr_list()))
+ {
+ switch (attribute.Key)
+ {
+ case "color":
+ {
+ // 'green' implies that the test is explicitly enabled by default
+ // 'yellow' implies that it is enabled, but *may* be disabled
+ info.DefaultEnabled = (attribute.Value == "green");
+ break;
+ }
+
+ case "label":
+ {
+ // Parse BOOST Test specific content
+ info.Parse(attribute.Value.Trim('"'));
+ break;
+ }
+ }
+ };
+
+ this.Context.TestUnits.Push(info);
+
+ return base.VisitNode_stmt(context);
+ }
+
+ public override TestFramework VisitEdge_stmt([NotNull] DOTParser.Edge_stmtContext context)
+ {
+ TestUnitInfo info = this.Context.TestUnits.Peek();
+
+ if (info != null)
+ {
+ var lhs = context.node_id();
+ var rhs = lhs;
+
+ var edgeRhs = context.edgeRHS();
+
+ // NOTE Boost Test DOT output only define one edge per edge statement
+ if (edgeRhs.edgeop().Length == 1)
+ {
+ var edgeop = edgeRhs.edgeop()[0];
+ // Ensure that a directed edge '->' token is used
+ if (edgeop.GetToken(DOTLexer.T__7, 0) != null)
+ {
+ rhs = edgeRhs.node_id()[0];
+ }
+ }
+
+ if ((lhs != rhs) && (rhs != null))
+ {
+ // Identify whether this edge is a constraining edge (i.e. an actual graph edge) or a non-constraining edge
+ bool constraint = !GetKeyValuePairs(context.attr_list()).Any((attribute) => (attribute.Key == "constraint") && (attribute.Value == "false"));
+
+ // This implies a test dependency
+ if ((lhs.GetText() == info.id) && !constraint)
+ {
+ info.Dependencies.Add(rhs.GetText());
+ }
+ // This implies a test unit relationship
+ else if (rhs.GetText() == info.id)
+ {
+ info.Parents.Add(lhs.GetText());
+ }
+ }
+ }
+
+ return base.VisitEdge_stmt(context);
+ }
+
+ #endregion DOTBaseVisitor
+
+ ///
+ /// Iterates over all key-value pair attributes contained within the provided attr_list
+ ///
+ /// The attr_list to iterate
+ /// An enumeration of all key-value pairs present in the provided attr_list
+ private static IEnumerable> GetKeyValuePairs(DOTParser.Attr_listContext attr_list)
+ {
+ // NOTE Refer to DOT grammar; an 'attr_list' is composed of an 'a_list', which is composed of multiple 'id's
+
+ if (attr_list != null)
+ {
+ var a_lists = attr_list.a_list();
+ if (a_lists != null)
+ {
+ for (int i = 0; i < a_lists.Length; ++i)
+ {
+ var a_list = a_lists[i];
+
+ int id = 0;
+ int idCount = a_list.id().Length;
+
+ // Try to identify the id() list as a list of 'id' = 'id' tuples
+
+ while (id < idCount)
+ {
+ var lhs = a_list.id()[id];
+
+ // Reference: Antlr4 C# Runtime [ParserRuleContext.GetTokens(int)]
+ var sibling = a_list.GetChild(a_list.children.IndexOf(lhs) + 1) as ITerminalNode;
+
+ // Identify if the a_list contains a key/value pair separated by the '=' token
+ if ((sibling != null) && (sibling.Symbol.Type == DOTLexer.T__3))
+ {
+ yield return new KeyValuePair(lhs.GetText(), a_list.id()[id + 1].GetText());
+ id += 2;
+ }
+ // Else provide the identifier a single item
+ else
+ {
+ yield return new KeyValuePair(lhs.GetText(), null);
+ ++id;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// Creates a TestSuite instance from the provided TestUnitInfo structure
+ ///
+ /// The currently accumulated test unit information
+ /// The parent test suite of this test unit
+ /// A TestSuite based on the provided information
+ private static TestSuite CreateTestSuite(TestUnitInfo info, TestSuite parent)
+ {
+ return PopulateTestUnit(info, new TestSuite(info.Name, parent));
+ }
+
+ ///
+ /// Creates a TestCase instance from the provided TestUnitInfo structure
+ ///
+ /// The currently accumulated test unit information
+ /// The parent test suite of this test unit
+ /// A TestCase based on the provided information
+ private static TestCase CreateTestCase(TestUnitInfo info, TestSuite parent)
+ {
+ return PopulateTestUnit(info, new TestCase(info.Name, parent));
+ }
+
+ ///
+ /// Populates the provided TestUnit with the test unit information
+ ///
+ /// A TestUnit derived type
+ /// The currently accumulated test unit information
+ /// The test unit instance which is to be populated
+ /// unit
+ private static T PopulateTestUnit(TestUnitInfo info, T unit) where T : TestUnit
+ {
+ if ((!string.IsNullOrEmpty(info.id)) && (info.id.Length > 2))
+ {
+ // Remove the 'tu' prefix from the test unit string ID
+
+ int id = 0;
+ if (int.TryParse(info.id.Substring(2), NumberStyles.Integer, CultureInfo.InvariantCulture, out id))
+ {
+ unit.Id = id;
+ }
+ }
+
+ unit.Source = info.SourceInfo;
+ unit.Labels = info.Labels;
+
+ unit.DefaultEnabled = info.DefaultEnabled;
+
+ // Default Enabled
+ // Timeout
+ // Expected Failures
+ // Dependencies
+
+ return unit;
+ }
+
+ ///
+ /// Aggregation of test unit information contained within a Boost Test DOT serialisation
+ ///
+ private class TestUnitInfo
+ {
+ ///
+ /// Constructor
+ ///
+ /// Test Unit ID (e.g. tu1)
+ public TestUnitInfo(string id)
+ {
+ this.id = id;
+
+ this.Name = string.Empty;
+ this.SourceInfo = null;
+ this.Timeout = 0;
+ this.ExpectedFailures = 0;
+ this.Labels = Enumerable.Empty();
+
+ this.Parents = new List();
+ this.Dependencies = new List();
+
+ this.DefaultEnabled = true;
+ }
+
+ ///
+ /// Test Unit ID (e.g. tu1)
+ ///
+ public string id { get; private set; }
+
+ ///
+ /// Test Unit Name
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Source information
+ ///
+ public SourceFileInfo SourceInfo { get; set; }
+
+ ///
+ /// Test timeout
+ ///
+ public uint Timeout { get; set; }
+
+ ///
+ /// Test expected failure count
+ ///
+ public uint ExpectedFailures { get; set; }
+
+ ///
+ /// Test labels
+ ///
+ public IEnumerable Labels { get; set; }
+
+ ///
+ /// Test unit children
+ ///
+ public List Parents { get; set; }
+
+ ///
+ /// Test unit dependencies
+ ///
+ public List Dependencies { get; set; }
+
+ ///
+ /// Flag which is raised when the test is explicitly set to true
+ ///
+ public bool DefaultEnabled { get; set; }
+
+ ///
+ /// Parses test unit information from the provided string
+ ///
+ /// The string to parse
+ /// Test unit information contained within value
+ ///
+ public TestUnitInfo Parse(string value)
+ {
+ TestUnitInfo info = new TestUnitInfo(this.id);
+ info.DefaultEnabled = this.DefaultEnabled;
+ string[] properties = value.Split('|');
+
+ if (properties.Length > 0)
+ {
+ info.Name = properties[0];
+ }
+ if (properties.Length > 1)
+ {
+ info.SourceInfo = SourceFileInfo.Parse(properties[1]);
+ }
+ if (properties.Length > 2)
+ {
+ foreach (var attribute in ParseKeyValuePairs(properties.Skip(2)))
+ {
+ ParseNamedAttribute(info, attribute);
+ }
+ }
+
+ // Replace the contents of 'this' with that of 'info'
+ Set(info);
+
+ return this;
+ }
+
+ ///
+ /// Sets the current instance properties to the one provided
+ ///
+ ///
+ private void Set(TestUnitInfo value)
+ {
+ this.id = value.id;
+ this.Name = value.Name;
+ this.SourceInfo = value.SourceInfo;
+ this.DefaultEnabled = value.DefaultEnabled;
+ this.Timeout = value.Timeout;
+ this.ExpectedFailures = value.ExpectedFailures;
+ this.Labels = value.Labels;
+ this.Parents = value.Parents;
+ this.Dependencies = value.Dependencies;
+ }
+
+ ///
+ /// Parses a Boost Test DOT named attribute label
+ ///
+ /// The test unit information structure which to populate
+ /// The attribute to parse
+ private static void ParseNamedAttribute(TestUnitInfo info, KeyValuePair attribute)
+ {
+ switch (attribute.Key)
+ {
+ case "timeout":
+ {
+ info.Timeout = uint.Parse(attribute.Value, CultureInfo.InvariantCulture);
+ break;
+ }
+ case "expected failures":
+ {
+ info.ExpectedFailures = uint.Parse(attribute.Value, CultureInfo.InvariantCulture);
+ break;
+ }
+ case "labels":
+ {
+ var labels = attribute.Value.Split(new[] { " @" }, StringSplitOptions.RemoveEmptyEntries);
+ if (labels.Length > 0)
+ {
+ info.Labels = labels;
+ }
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Parses the Boost Test DOT label attributes for any key-value pairs
+ ///
+ /// The values/attributes to parse
+ /// An enumeration of successfully parsed key-value pairs
+ private static IEnumerable> ParseKeyValuePairs(IEnumerable values)
+ {
+ foreach (string value in values)
+ {
+ // NOTE 'timeout' and 'expected failures' use '=' as a separator, 'labels' use ':'
+ string[] keyValue = value.Split(new[] { '=', ':' }, 2, StringSplitOptions.RemoveEmptyEntries);
+ if (keyValue.Length == 2)
+ {
+ yield return new KeyValuePair(keyValue[0], keyValue[1]);
+ }
+ }
+ }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/BoostTestAdapter/Boost/Test/TestUnit.cs b/BoostTestAdapter/Boost/Test/TestUnit.cs
index b09927f..6194773 100644
--- a/BoostTestAdapter/Boost/Test/TestUnit.cs
+++ b/BoostTestAdapter/Boost/Test/TestUnit.cs
@@ -1,192 +1,189 @@
-// (C) Copyright ETAS 2015.
-// Distributed under the Boost Software License, Version 1.0.
-// (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Xml;
-using BoostTestAdapter.Utility;
-
-namespace BoostTestAdapter.Boost.Test
-{
- ///
- /// Base class for Boost Test test components. Follows the composite design pattern.
- ///
- public abstract class TestUnit : ITestVisitable
- {
- #region Constructors
-
- ///
- /// Constructor
- ///
- /// Test Unit (local) name.
- /// Parent/Owner Test Unit of this instance.
- protected TestUnit(string name, TestUnit parent)
- {
- this.Id = null;
- this.Name = name;
- this.Parent = parent;
- this.Labels = Enumerable.Empty();
-
- this.DefaultEnabled = true;
-
- if (parent != null)
- {
- parent.AddChild(this);
- }
- }
-
- #endregion Constructors
-
- #region Properties
-
- ///
- /// Test Unit Id. Optional.
- ///
- public int? Id { get; set; }
-
- ///
- /// Test Unit (local) Name.
- ///
- public string Name { get; private set; }
-
- ///
- /// Parent/Owner Test Unit of this instance.
- ///
- public TestUnit Parent { get; private set; }
-
- ///
- /// Child Test Units of this instance.
- ///
- public virtual IEnumerable Children
- {
- get
- {
- return Enumerable.Empty();
- }
- }
-
- ///
- /// Optional source file information related to this test unit.
- ///
- public SourceFileInfo Source { get; set; }
-
- ///
- /// Identifies any label associations with this test unit
- ///
- public IEnumerable Labels { get; set; }
-
-
-
- ///
- /// Cached version of the fully qualified name builder
- ///
- private QualifiedNameBuilder _fullyQualifiedName = null;
-
- ///
- /// Internal property which provides a cached QualifiedNameBuilder to represent the fully qualified name
- ///
- private QualifiedNameBuilder FullyQualifiedNameBuilder
- {
- get
- {
- if (this._fullyQualifiedName == null)
- {
- _fullyQualifiedName = (Parent == null) ? new QualifiedNameBuilder() : Parent.FullyQualifiedNameBuilder.Clone();
- _fullyQualifiedName.Push(this);
- }
-
- return _fullyQualifiedName;
- }
- }
-
- ///
- /// Identifies the fully qualified name of this TestUnit
- ///
- public string FullyQualifiedName
- {
- get
- {
- return FullyQualifiedNameBuilder.ToString();
- }
- }
-
- ///
- /// Identifies whether the test is explicitly disabled by setting this value to false
- ///
-
- public bool DefaultEnabled { get; set; }
-
- #endregion Properties
-
- ///
- /// Adds a child to this TestUnit
- ///
- /// The unit to add as a child
- public virtual void AddChild(TestUnit unit)
- {
- throw new InvalidOperationException();
- }
-
- #region ITestVisitable
-
- public abstract void Apply(ITestVisitor visitor);
-
- #endregion ITestVisitable
-
- #region Utility
-
- ///
- /// Given a fully qualified name of a test case, generates the respective test unit hierarchy.
- ///
- /// The fully qualified name of the test case
- /// The test case hierarcy represented by the provided fully qualified name
- public static TestCase FromFullyQualifiedName(string fullyQualifiedName)
- {
- return FromFullyQualifiedName(QualifiedNameBuilder.FromString(fullyQualifiedName));
- }
-
- ///
- /// Given a fully qualified name of a test case, generates the respective test unit hierarchy.
- ///
- /// The fully qualified name of the test case
- /// The test case hierarchy represented by the provided fully qualified name
- /// The parameter 'fullyQualifiedName' will be modified and emptied in due process
- private static TestCase FromFullyQualifiedName(QualifiedNameBuilder fullyQualifiedName)
- {
- // Reverse the fully qualified name stack i.e. Master Test Suite should be first element and Test Case should be last element
- Stack hierarchy = new Stack();
- while (fullyQualifiedName.Peek() != null)
- {
- hierarchy.Push(fullyQualifiedName.Peek());
- fullyQualifiedName.Pop();
- }
-
- TestSuite parent = null;
-
- // Treat each entry (except for the last) as a test suite
- while (hierarchy.Count > 1)
- {
- parent = new TestSuite(hierarchy.Peek(), parent);
- hierarchy.Pop();
- }
-
- // Treat the last entry as a test case
- return (hierarchy.Count == 1) ? new TestCase(hierarchy.Peek(), parent) : null;
- }
-
- #endregion Utility
-
- #region object overrides
-
- public override string ToString()
- {
- return this.FullyQualifiedName;
- }
-
- #endregion object overrides
- }
+// (C) Copyright ETAS 2015.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Xml;
+using BoostTestAdapter.Utility;
+
+namespace BoostTestAdapter.Boost.Test
+{
+ ///
+ /// Base class for Boost Test test components. Follows the composite design pattern.
+ ///
+ public abstract class TestUnit : ITestVisitable
+ {
+ #region Constructors
+
+ ///
+ /// Constructor
+ ///
+ /// Test Unit (local) name.
+ /// Parent/Owner Test Unit of this instance.
+ protected TestUnit(string name, TestUnit parent)
+ {
+ this.Id = null;
+ this.Name = name;
+ this.Parent = parent;
+ this.Labels = Enumerable.Empty();
+
+ this.DefaultEnabled = true;
+
+ if (parent != null)
+ {
+ parent.AddChild(this);
+ }
+ }
+
+ #endregion Constructors
+
+ #region Properties
+
+ ///
+ /// Test Unit Id. Optional.
+ ///
+ public int? Id { get; set; }
+
+ ///
+ /// Test Unit (local) Name.
+ ///
+ public string Name { get; private set; }
+
+ ///
+ /// Parent/Owner Test Unit of this instance.
+ ///
+ public TestUnit Parent { get; private set; }
+
+ ///
+ /// Child Test Units of this instance.
+ ///
+ public virtual IEnumerable Children
+ {
+ get
+ {
+ return Enumerable.Empty();
+ }
+ }
+
+ ///
+ /// Optional source file information related to this test unit.
+ ///
+ public SourceFileInfo Source { get; set; }
+
+ ///
+ /// Identifies any label associations with this test unit
+ ///
+ public IEnumerable Labels { get; set; }
+
+ ///
+ /// Cached version of the fully qualified name builder
+ ///
+ private QualifiedNameBuilder _fullyQualifiedName = null;
+
+ ///
+ /// Internal property which provides a cached QualifiedNameBuilder to represent the fully qualified name
+ ///
+ private QualifiedNameBuilder FullyQualifiedNameBuilder
+ {
+ get
+ {
+ if (this._fullyQualifiedName == null)
+ {
+ _fullyQualifiedName = (Parent == null) ? new QualifiedNameBuilder() : Parent.FullyQualifiedNameBuilder.Clone();
+ _fullyQualifiedName.Push(this);
+ }
+
+ return _fullyQualifiedName;
+ }
+ }
+
+ ///
+ /// Identifies the fully qualified name of this TestUnit
+ ///
+ public string FullyQualifiedName
+ {
+ get
+ {
+ return FullyQualifiedNameBuilder.ToString();
+ }
+ }
+
+ ///
+ /// Identifies whether the test is explicitly disabled by setting this value to false
+ ///
+ public bool DefaultEnabled { get; set; }
+
+ #endregion Properties
+
+ ///
+ /// Adds a child to this TestUnit
+ ///
+ /// The unit to add as a child
+ public virtual void AddChild(TestUnit unit)
+ {
+ throw new InvalidOperationException();
+ }
+
+ #region ITestVisitable
+
+ public abstract void Apply(ITestVisitor visitor);
+
+ #endregion ITestVisitable
+
+ #region Utility
+
+ ///
+ /// Given a fully qualified name of a test case, generates the respective test unit hierarchy.
+ ///
+ /// The fully qualified name of the test case
+ /// The test case hierarcy represented by the provided fully qualified name
+ public static TestCase FromFullyQualifiedName(string fullyQualifiedName)
+ {
+ return FromFullyQualifiedName(QualifiedNameBuilder.FromString(fullyQualifiedName));
+ }
+
+ ///
+ /// Given a fully qualified name of a test case, generates the respective test unit hierarchy.
+ ///
+ /// The fully qualified name of the test case
+ /// The test case hierarchy represented by the provided fully qualified name
+ /// The parameter 'fullyQualifiedName' will be modified and emptied in due process
+ private static TestCase FromFullyQualifiedName(QualifiedNameBuilder fullyQualifiedName)
+ {
+ // Reverse the fully qualified name stack i.e. Master Test Suite should be first element and Test Case should be last element
+ Stack hierarchy = new Stack();
+ while (fullyQualifiedName.Peek() != null)
+ {
+ hierarchy.Push(fullyQualifiedName.Peek());
+ fullyQualifiedName.Pop();
+ }
+
+ TestSuite parent = null;
+
+ // Treat each entry (except for the last) as a test suite
+ while (hierarchy.Count > 1)
+ {
+ parent = new TestSuite(hierarchy.Peek(), parent);
+ hierarchy.Pop();
+ }
+
+ // Treat the last entry as a test case
+ return (hierarchy.Count == 1) ? new TestCase(hierarchy.Peek(), parent) : null;
+ }
+
+ #endregion Utility
+
+ #region object overrides
+
+ public override string ToString()
+ {
+ return this.FullyQualifiedName;
+ }
+
+ #endregion object overrides
+ }
}
\ No newline at end of file
diff --git a/BoostTestAdapter/BoostTestAdapter.csproj b/BoostTestAdapter/BoostTestAdapter.csproj
index f2ac959..c003063 100644
--- a/BoostTestAdapter/BoostTestAdapter.csproj
+++ b/BoostTestAdapter/BoostTestAdapter.csproj
@@ -125,6 +125,7 @@
+
@@ -152,7 +153,7 @@
-
+
diff --git a/BoostTestAdapter/BoostTestDiscoverer.cs b/BoostTestAdapter/BoostTestDiscoverer.cs
index 52c71c9..e34e56a 100644
--- a/BoostTestAdapter/BoostTestDiscoverer.cs
+++ b/BoostTestAdapter/BoostTestDiscoverer.cs
@@ -1,129 +1,129 @@
-// (C) Copyright ETAS 2015.
-// Distributed under the Boost Software License, Version 1.0.
-// (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using BoostTestAdapter.Settings;
-using Microsoft.VisualStudio.TestPlatform.ObjectModel;
-using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
-using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
-using BoostTestAdapter.Utility;
-
-namespace BoostTestAdapter
-{
- [FileExtension(DllExtension)]
- [FileExtension(ExeExtension)]
- [DefaultExecutorUri(BoostTestExecutor.ExecutorUriString)]
- public class BoostTestDiscoverer : ITestDiscoverer
- {
- #region Constants
-
- public const string DllExtension = ".dll";
- public const string ExeExtension = ".exe";
-
- #endregion Constants
-
- #region Constructors
-
- ///
- /// Default constructor. The default IBoostTestDiscovererFactory implementation is provided.
- ///
- public BoostTestDiscoverer()
- :this(new BoostTestDiscovererFactory())
- {
- }
-
- ///
- /// Constructor.
- ///
- /// A custom IBoostTestDiscovererFactory implementation.
- public BoostTestDiscoverer(IBoostTestDiscovererFactory boostTestDiscovererFactory)
- {
- _boostTestDiscovererFactory = boostTestDiscovererFactory;
- }
-
- #endregion
-
-
- #region Members
-
- private readonly IBoostTestDiscovererFactory _boostTestDiscovererFactory;
-
- #endregion
-
-
- #region ITestDiscoverer
-
- ///
- /// Method called by Visual Studio (discovered via reflection) for test enumeration
- ///
- /// path, target name and target extensions to discover
- /// discovery context settings
- ///
- /// Unit test framework Sink
- /// Entry point of the discovery procedure
- public void DiscoverTests(IEnumerable sources, IDiscoveryContext discoveryContext, IMessageLogger logger, ITestCaseDiscoverySink discoverySink)
- {
-#if DEBUG && LAUNCH_DEBUGGER
- System.Diagnostics.Debugger.Launch();
-#endif
-
- if (sources == null)
- return;
-
- Logger.Initialize(logger);
-
- DiscoverTests(sources, discoveryContext, discoverySink);
-
- Logger.Shutdown();
- }
-
- #endregion ITestDiscoverer
-
- ///
- /// Method called by BoostTestExecutor for test enumeration
- ///
- /// path, target name and target extensions to discover
- /// discovery context settings
- /// Unit test framework Sink
- /// This method assumes that the Logger singleton is maintained by the caller.
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
- public void DiscoverTests(IEnumerable sources, IDiscoveryContext discoveryContext, ITestCaseDiscoverySink discoverySink)
- {
- if (sources == null)
- return;
-
- BoostTestAdapterSettings settings = BoostTestAdapterSettingsProvider.GetSettings(discoveryContext);
-
- try
- {
- // Filter out any sources which are not of interest
- if (!TestSourceFilter.IsNullOrEmpty(settings.Filters))
- {
- sources = sources.Where(settings.Filters.ShouldInclude);
- }
-
- var results = _boostTestDiscovererFactory.GetDiscoverers(sources.ToList(), settings);
- if (results == null)
- return;
-
- // Test discovery
- foreach (var discoverer in results)
- {
- if (discoverer.Sources.Count > 0)
- {
- Logger.Info("Discovering ({0}): -> [{1}]", discoverer.Discoverer.GetType().Name, string.Join(", ", discoverer.Sources));
- discoverer.Discoverer.DiscoverTests(discoverer.Sources, discoveryContext, discoverySink);
- }
- }
- }
- catch (Exception ex)
- {
- Logger.Exception(ex, "Exception caught while discovering tests: {0} ({1})", ex.Message, ex.HResult);
- }
- }
- }
-}
+// (C) Copyright ETAS 2015.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using BoostTestAdapter.Settings;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
+using BoostTestAdapter.Utility;
+
+namespace BoostTestAdapter
+{
+ [FileExtension(DllExtension)]
+ [FileExtension(ExeExtension)]
+ [DefaultExecutorUri(BoostTestExecutor.ExecutorUriString)]
+ public class BoostTestDiscoverer : ITestDiscoverer
+ {
+ #region Constants
+
+ public const string DllExtension = ".dll";
+ public const string ExeExtension = ".exe";
+
+ #endregion Constants
+
+ #region Constructors
+
+ ///
+ /// Default constructor. The default IBoostTestDiscovererFactory implementation is provided.
+ ///
+ public BoostTestDiscoverer()
+ :this(new BoostTestDiscovererFactory())
+ {
+ }
+
+ ///
+ /// Constructor.
+ ///
+ /// A custom IBoostTestDiscovererFactory implementation.
+ public BoostTestDiscoverer(IBoostTestDiscovererFactory boostTestDiscovererFactory)
+ {
+ _boostTestDiscovererFactory = boostTestDiscovererFactory;
+ }
+
+ #endregion
+
+
+ #region Members
+
+ private readonly IBoostTestDiscovererFactory _boostTestDiscovererFactory;
+
+ #endregion
+
+
+ #region ITestDiscoverer
+
+ ///
+ /// Method called by Visual Studio (discovered via reflection) for test enumeration
+ ///
+ /// path, target name and target extensions to discover
+ /// discovery context settings
+ ///
+ /// Unit test framework Sink
+ /// Entry point of the discovery procedure
+ public void DiscoverTests(IEnumerable sources, IDiscoveryContext discoveryContext, IMessageLogger logger, ITestCaseDiscoverySink discoverySink)
+ {
+#if DEBUG && LAUNCH_DEBUGGER
+ System.Diagnostics.Debugger.Launch();
+#endif
+
+ if (sources == null)
+ return;
+
+ Logger.Initialize(logger);
+
+ DiscoverTests(sources, discoveryContext, discoverySink);
+
+ Logger.Shutdown();
+ }
+
+ #endregion ITestDiscoverer
+
+ ///
+ /// Method called by BoostTestExecutor for test enumeration
+ ///
+ /// path, target name and target extensions to discover
+ /// discovery context settings
+ /// Unit test framework Sink
+ /// This method assumes that the Logger singleton is maintained by the caller.
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
+ public void DiscoverTests(IEnumerable sources, IDiscoveryContext discoveryContext, ITestCaseDiscoverySink discoverySink)
+ {
+ if (sources == null)
+ return;
+
+ BoostTestAdapterSettings settings = BoostTestAdapterSettingsProvider.GetSettings(discoveryContext);
+
+ try
+ {
+ // Filter out any sources which are not of interest
+ if (!TestSourceFilter.IsNullOrEmpty(settings.Filters))
+ {
+ sources = sources.Where(settings.Filters.ShouldInclude);
+ }
+
+ var results = _boostTestDiscovererFactory.GetDiscoverers(sources.ToList(), settings);
+ if (results == null)
+ return;
+
+ // Test discovery
+ foreach (var discoverer in results)
+ {
+ if (discoverer.Sources.Count > 0)
+ {
+ Logger.Info("Discovering ({0}): -> [{1}]", discoverer.Discoverer.GetType().Name, string.Join(", ", discoverer.Sources));
+ discoverer.Discoverer.DiscoverTests(discoverer.Sources, discoveryContext, discoverySink);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.Exception(ex, "Exception caught while discovering tests: {0} ({1})", ex.Message, ex.HResult);
+ }
+ }
+ }
+}
diff --git a/BoostTestAdapter/Discoverers/ListContentDiscoverer.cs b/BoostTestAdapter/Discoverers/ListContentDiscoverer.cs
index 35c60fb..ed26cc4 100644
--- a/BoostTestAdapter/Discoverers/ListContentDiscoverer.cs
+++ b/BoostTestAdapter/Discoverers/ListContentDiscoverer.cs
@@ -88,7 +88,7 @@ public void DiscoverTests(IEnumerable sources, IDiscoveryContext discove
if (vs != null)
{
Logger.Debug("Connected to Visual Studio {0} instance", vs.Version);
- }
+ }
args.SetWorkingEnvironment(source, settings, vs);
}
@@ -122,12 +122,11 @@ public void DiscoverTests(IEnumerable sources, IDiscoveryContext discove
using (FileStream stream = File.OpenRead(args.StandardErrorFile))
{
TestFrameworkDOTDeserialiser deserialiser = new TestFrameworkDOTDeserialiser(source);
-
- // Pass in a visitor to avoid a 2-pass loop in order to notify test cases to VS
- //
- // NOTE Due to deserialisation, make sure that only test cases are visited. Test
- // suites may be visited after their child test cases are visited.
- deserialiser.Deserialise(stream, new VSDiscoveryVisitorTestsOnly(source, discoverySink));
+ TestFramework framework = deserialiser.Deserialise(stream);
+ if ((framework != null) && (framework.MasterTestSuite != null))
+ {
+ framework.MasterTestSuite.Apply(new VSDiscoveryVisitor(source, discoverySink));
+ }
}
}
}
@@ -139,27 +138,5 @@ public void DiscoverTests(IEnumerable sources, IDiscoveryContext discove
}
#endregion IBoostTestDiscoverer
-
- ///
- /// A specification of VSDiscoveryVisitor which limits visitation to tests only.
- /// Allows for optimal visitation during DOT deserialisation.
- ///
- private class VSDiscoveryVisitorTestsOnly : VSDiscoveryVisitor
- {
- public VSDiscoveryVisitorTestsOnly(string source, ITestCaseDiscoverySink sink)
- : base(source, sink)
- {
- }
-
- protected override bool ShouldVisit(TestSuite suite)
- {
- return false;
- }
-
- protected override bool ShouldVisit(TestCase test)
- {
- return true;
- }
- }
}
}
diff --git a/BoostTestAdapter/Discoverers/VSDiscoveryVisitor.cs b/BoostTestAdapter/Discoverers/VSDiscoveryVisitor.cs
index b04e60b..4f7891a 100644
--- a/BoostTestAdapter/Discoverers/VSDiscoveryVisitor.cs
+++ b/BoostTestAdapter/Discoverers/VSDiscoveryVisitor.cs
@@ -1,185 +1,185 @@
-// (C) Copyright ETAS 2015.
-// Distributed under the Boost Software License, Version 1.0.
-// (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-using System.Diagnostics;
-
-using BoostTestAdapter.Boost.Test;
-
-using BoostTestAdapter.Utility;
-using BoostTestAdapter.Utility.VisualStudio;
-
-using Microsoft.VisualStudio.TestPlatform.ObjectModel;
-using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
-
-using TestCase = BoostTestAdapter.Boost.Test.TestCase;
-using VSTestCase = Microsoft.VisualStudio.TestPlatform.ObjectModel.TestCase;
-using System.IO;
-
-namespace BoostTestAdapter.Discoverers
-{
- ///
- /// ITestVisitor implementation. Visits TestCases and registers them
- /// with the supplied ITestCaseDiscoverySink.
- ///
- public class VSDiscoveryVisitor : ITestVisitor
- {
- ///
- /// Constructor
- ///
- /// The source test module which contains the discovered tests
- /// The ITestCaseDiscoverySink which will have tests registered with
- public VSDiscoveryVisitor(string source, ITestCaseDiscoverySink sink)
- {
- this.Source = source;
- this.DiscoverySink = sink;
- this.OutputLog = true;
- }
-
- ///
- /// The test module source file path
- ///
- public string Source { get; private set; }
-
- ///
- /// Whether the module should output to the logger regarding relative paths
- ///
- public bool OutputLog { get; private set; }
-
- ///
- /// The Visual Studio DiscoverySink which is used to notify test discovery
- ///
- public ITestCaseDiscoverySink DiscoverySink { get; private set; }
-
- #region ITestVisitor
-
- public void Visit(TestSuite testSuite)
- {
- Code.Require(testSuite, "testSuite");
-
- if (ShouldVisit(testSuite))
- {
- foreach (TestUnit child in testSuite.Children)
- {
- child.Apply(this);
- }
- }
- }
-
- public void Visit(TestCase testCase)
- {
- Code.Require(testCase, "testCase");
-
- if (ShouldVisit(testCase))
- {
- VSTestCase test = GenerateTestCase(testCase);
-
- // Send to discovery sink
- if (null != this.DiscoverySink)
- {
- Logger.Info("Found test: {0}", test.FullyQualifiedName);
- this.DiscoverySink.SendTestCase(test);
- }
- }
- }
-
- #endregion ITestVisitor
-
- ///
- /// Generates a Visual Studio equivalent test case structure.
- ///
- /// The Boost.Test.TestCase to convert.
- /// An equivalent Visual Studio TestCase structure to the one provided.
-
- private VSTestCase GenerateTestCase(TestCase testCase)
- {
- VSTestCase test = new VSTestCase(
- testCase.FullyQualifiedName,
- BoostTestExecutor.ExecutorUri,
- this.Source
- );
-
- test.DisplayName = testCase.Name;
-
- if (testCase.Source != null)
- {
- // NOTE As of Boost 1.61, this warning might be triggered when BOOST_DATA_TEST_CASEs are used due to irregular DOT output
- if (!Path.IsPathRooted(testCase.Source.File) && this.OutputLog)
- {
- Logger.Info("Relative Paths are being used. Please note that test navigation from the Test Explorer window will not be available. To enable such functionality, the Use Full Paths setting under C++ -> Advanced in the project's Property Page must be set to Yes (/FC).");
- this.OutputLog = false;
- }
-
- test.CodeFilePath = testCase.Source.File;
- test.LineNumber = testCase.Source.LineNumber;
- }
-
- // Register the test suite as a trait
- test.Traits.Add(new Trait(VSTestModel.TestSuiteTrait, GetParentFullyQualifiedName(testCase)));
-
- // Register enabled and disabled as traits
- test.Traits.Add(new Trait(VSTestModel.StatusTrait, (testCase.DefaultEnabled ? VSTestModel.TestEnabled : VSTestModel.TestDisabled)));
-
- TestUnit unit = testCase;
- while (unit != null)
- {
- foreach (string label in unit.Labels)
- {
- // Register each and every label as an individual trait
- test.Traits.Add(new Trait(label, string.Empty));
- }
-
- // Test cases inherit the labels of parent test units
- // Reference: http://www.boost.org/doc/libs/1_60_0/libs/test/doc/html/boost_test/tests_organization/tests_grouping.html
- unit = unit.Parent;
- }
-
- return test;
- }
-
- ///
- /// States whether the provided test suite should be visited
- ///
- /// The test suite under consideration
- /// true if the provided TestSuite should be visited; false otherwise
- protected virtual bool ShouldVisit(TestSuite suite)
- {
- return true;
- }
-
- ///
- /// States whether the provided test case should be visited
- ///
- /// The test case under consideration
- /// true if the provided TestCase should be visited; false otherwise
- protected virtual bool ShouldVisit(TestCase test)
- {
- return true;
- }
-
- ///
- /// Provides the fully qualified name of the parent TestUnit of the provided TestCase
- ///
- /// The TestCase whose parent TestUnit is to be queried
- /// The fully qualified name of the parent TestUnit
- private static string GetParentFullyQualifiedName(TestCase test)
- {
- Code.Require(test, "test");
-
- TestUnit parent = test.Parent;
-
- // A test case must have a parent, at the very least, the master test suite should be the parent of a test case
- Debug.Assert(parent != null);
-
- // Since the master test suite name is not included in the fully qualified name, identify
- // this edge case and explicitly return the master test suite name in such cases.
- if (parent.Parent == null)
- {
- return string.IsNullOrEmpty(parent.Name) ? QualifiedNameBuilder.DefaultMasterTestSuiteName : parent.Name;
- }
-
- return parent.FullyQualifiedName;
- }
- }
-}
+// (C) Copyright ETAS 2015.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+using System.IO;
+using System.Diagnostics;
+
+using BoostTestAdapter.Boost.Test;
+
+using BoostTestAdapter.Utility;
+using BoostTestAdapter.Utility.VisualStudio;
+
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
+
+using TestCase = BoostTestAdapter.Boost.Test.TestCase;
+using VSTestCase = Microsoft.VisualStudio.TestPlatform.ObjectModel.TestCase;
+
+namespace BoostTestAdapter.Discoverers
+{
+ ///
+ /// ITestVisitor implementation. Visits TestCases and registers them
+ /// with the supplied ITestCaseDiscoverySink.
+ ///
+ public class VSDiscoveryVisitor : ITestVisitor
+ {
+ ///
+ /// Constructor
+ ///
+ /// The source test module which contains the discovered tests
+ /// The ITestCaseDiscoverySink which will have tests registered with
+ public VSDiscoveryVisitor(string source, ITestCaseDiscoverySink sink)
+ {
+ Code.Require(sink, "sink");
+
+ this.Source = source;
+ this.DiscoverySink = sink;
+ this.OutputLog = true;
+ }
+
+ ///
+ /// The test module source file path
+ ///
+ public string Source { get; private set; }
+
+ ///
+ /// Whether the module should output to the logger regarding relative paths
+ ///
+ private bool OutputLog { get; set; }
+
+ ///
+ /// The Visual Studio DiscoverySink which is used to notify test discovery
+ ///
+ public ITestCaseDiscoverySink DiscoverySink { get; private set; }
+
+ #region ITestVisitor
+
+ public void Visit(TestSuite testSuite)
+ {
+ Code.Require(testSuite, "testSuite");
+
+ if (BoostDataTestCaseVerifier.IsBoostDataTestCase(testSuite))
+ {
+ foreach (TestUnit child in testSuite.Children)
+ {
+ // NOTE Since we have asserted that the suite is a BOOST_DATA_TEST_CASE,
+ // all child instances are to be of type TestCase
+
+ var displayName = testSuite.Name + '/' + child.Name;
+ Visit((TestCase)child, displayName);
+ }
+ }
+ else
+ {
+ foreach (TestUnit child in testSuite.Children)
+ {
+ child.Apply(this);
+ }
+ }
+ }
+
+ public void Visit(TestCase testCase)
+ {
+ Code.Require(testCase, "testCase");
+
+ Visit(testCase, testCase.Name);
+ }
+
+ #endregion ITestVisitor
+
+ ///
+ /// Visits the provided TestCase
+ ///
+ /// The TestCase which is to be visited
+ /// The test case display name to use (overrides the test case name)
+ private void Visit(TestCase testCase, string displayName)
+ {
+ Code.Require(testCase, "testCase");
+
+ VSTestCase test = GenerateTestCase(testCase);
+ test.DisplayName = string.IsNullOrEmpty(displayName) ? test.DisplayName : displayName;
+
+ // Send to discovery sink
+ Logger.Info("Found test: {0}", test.FullyQualifiedName);
+ this.DiscoverySink.SendTestCase(test);
+ }
+
+ ///
+ /// Generates a Visual Studio equivalent test case structure.
+ ///
+ /// The Boost.Test.TestCase to convert.
+ /// An equivalent Visual Studio TestCase structure to the one provided.
+
+ private VSTestCase GenerateTestCase(TestCase testCase)
+ {
+ VSTestCase test = new VSTestCase(
+ testCase.FullyQualifiedName,
+ BoostTestExecutor.ExecutorUri,
+ this.Source
+ );
+
+ test.DisplayName = testCase.Name;
+
+ if (testCase.Source != null)
+ {
+ // NOTE As of Boost 1.61, this warning might be triggered when BOOST_DATA_TEST_CASEs are used due to irregular DOT output
+ if (!Path.IsPathRooted(testCase.Source.File) && this.OutputLog)
+ {
+ Logger.Info("Relative Paths are being used. Please note that test navigation from the Test Explorer window will not be available. To enable such functionality, the Use Full Paths setting under C++ -> Advanced in the project's Property Page must be set to Yes (/FC).");
+ this.OutputLog = false;
+ }
+
+ test.CodeFilePath = testCase.Source.File;
+ test.LineNumber = testCase.Source.LineNumber;
+ }
+
+ // Register the test suite as a trait
+ test.Traits.Add(new Trait(VSTestModel.TestSuiteTrait, GetParentFullyQualifiedName(testCase)));
+
+ // Register enabled and disabled as traits
+ test.Traits.Add(new Trait(VSTestModel.StatusTrait, (testCase.DefaultEnabled ? VSTestModel.TestEnabled : VSTestModel.TestDisabled)));
+
+ TestUnit unit = testCase;
+ while (unit != null)
+ {
+ foreach (string label in unit.Labels)
+ {
+ // Register each and every label as an individual trait
+ test.Traits.Add(new Trait(label, string.Empty));
+ }
+
+ // Test cases inherit the labels of parent test units
+ // Reference: http://www.boost.org/doc/libs/1_60_0/libs/test/doc/html/boost_test/tests_organization/tests_grouping.html
+ unit = unit.Parent;
+ }
+
+ return test;
+ }
+
+ ///
+ /// Provides the fully qualified name of the parent TestUnit of the provided TestCase
+ ///
+ /// The TestCase whose parent TestUnit is to be queried
+ /// The fully qualified name of the parent TestUnit
+ private static string GetParentFullyQualifiedName(TestCase test)
+ {
+ Code.Require(test, "test");
+
+ TestUnit parent = test.Parent;
+
+ // A test case must have a parent, at the very least, the master test suite should be the parent of a test case
+ Debug.Assert(parent != null);
+
+ // Since the master test suite name is not included in the fully qualified name, identify
+ // this edge case and explicitly return the master test suite name in such cases.
+ if (parent.Parent == null)
+ {
+ return string.IsNullOrEmpty(parent.Name) ? QualifiedNameBuilder.DefaultMasterTestSuiteName : parent.Name;
+ }
+
+ return parent.FullyQualifiedName;
+ }
+ }
+}
diff --git a/BoostTestAdapter/Settings/BoostTestAdapterSettings.cs b/BoostTestAdapter/Settings/BoostTestAdapterSettings.cs
index 4e6f0cf..50976cd 100644
--- a/BoostTestAdapter/Settings/BoostTestAdapterSettings.cs
+++ b/BoostTestAdapter/Settings/BoostTestAdapterSettings.cs
@@ -210,6 +210,7 @@ public bool UseBoost162Workaround
///
/// Determines a delay represented in milliseconds which will be forced after the execution of each test batch.
///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "PostTest")]
[DefaultValue(0)]
public int PostTestDelay { get; set; }
diff --git a/BoostTestAdapter/TestBatch/TestSuiteTestBatchStrategy.cs b/BoostTestAdapter/TestBatch/TestSuiteTestBatchStrategy.cs
index de15ee0..ca0f1be 100644
--- a/BoostTestAdapter/TestBatch/TestSuiteTestBatchStrategy.cs
+++ b/BoostTestAdapter/TestBatch/TestSuiteTestBatchStrategy.cs
@@ -1,64 +1,63 @@
-// (C) Copyright ETAS 2015.
-// Distributed under the Boost Software License, Version 1.0.
-// (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-using System.Collections.Generic;
-using System.Linq;
-using BoostTestAdapter.Boost.Runner;
-using BoostTestAdapter.Settings;
-using BoostTestAdapter.Utility;
-using BoostTestAdapter.Utility.VisualStudio;
-
-using VSTestCase = Microsoft.VisualStudio.TestPlatform.ObjectModel.TestCase;
-
-namespace BoostTestAdapter.TestBatch
-{
- ///
- /// An ITestBatchingStrategy which allocates a test run for test suites. All tests
- /// contained within the same test suite are executed in one test run.
- ///
- public class TestSuiteTestBatchStrategy : TestBatchStrategy
- {
- public TestSuiteTestBatchStrategy(IBoostTestRunnerFactory testRunnerFactory, BoostTestAdapterSettings settings, CommandLineArgsBuilder argsBuilder) :
- base(testRunnerFactory, settings, argsBuilder)
- {
- }
-
- #region TestBatchStrategy
-
- public override IEnumerable BatchTests(IEnumerable tests)
- {
- BoostTestRunnerSettings adaptedSettings = this.Settings.TestRunnerSettings.Clone();
- adaptedSettings.Timeout = -1;
-
- // Group by source
- IEnumerable> sources = tests.GroupBy(test => test.Source);
- foreach (IGrouping source in sources)
- {
- IBoostTestRunner runner = GetTestRunner(source.Key);
- if (runner == null)
- {
- continue;
- }
-
- // Group by test suite
- var suiteGroups = source.GroupBy(test => test.Traits.First(trait => (trait.Name == VSTestModel.TestSuiteTrait)).Value);
- foreach (var suiteGroup in suiteGroups)
- {
- BoostTestRunnerCommandLineArgs args = BuildCommandLineArgs(source.Key);
- foreach (VSTestCase test in suiteGroup)
- {
- // List all tests by display name
- // but ensure that the first test is fully qualified so that remaining tests are taken relative to this test suite
- args.Tests.Add((args.Tests.Count == 0) ? test.FullyQualifiedName : test.DisplayName);
- }
-
- yield return new TestRun(runner, suiteGroup, args, adaptedSettings);
- }
- }
- }
-
- #endregion TestBatchStrategy
- }
+// (C) Copyright ETAS 2015.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+using System.Collections.Generic;
+using System.Linq;
+using BoostTestAdapter.Boost.Runner;
+using BoostTestAdapter.Settings;
+using BoostTestAdapter.Utility;
+using BoostTestAdapter.Utility.VisualStudio;
+
+using VSTestCase = Microsoft.VisualStudio.TestPlatform.ObjectModel.TestCase;
+
+namespace BoostTestAdapter.TestBatch
+{
+ ///
+ /// An ITestBatchingStrategy which allocates a test run for test suites. All tests
+ /// contained within the same test suite are executed in one test run.
+ ///
+ public class TestSuiteTestBatchStrategy : TestBatchStrategy
+ {
+ public TestSuiteTestBatchStrategy(IBoostTestRunnerFactory testRunnerFactory, BoostTestAdapterSettings settings, CommandLineArgsBuilder argsBuilder) :
+ base(testRunnerFactory, settings, argsBuilder)
+ {
+ }
+
+ #region TestBatchStrategy
+
+ public override IEnumerable BatchTests(IEnumerable tests)
+ {
+ BoostTestRunnerSettings adaptedSettings = this.Settings.TestRunnerSettings.Clone();
+ adaptedSettings.Timeout = -1;
+
+ // Group by source
+ IEnumerable> sources = tests.GroupBy(test => test.Source);
+ foreach (IGrouping source in sources)
+ {
+ IBoostTestRunner runner = GetTestRunner(source.Key);
+ if (runner == null)
+ {
+ continue;
+ }
+
+ // Group by test suite
+ var suiteGroups = source.GroupBy(test => test.Traits.First(trait => (trait.Name == VSTestModel.TestSuiteTrait)).Value);
+ foreach (var suiteGroup in suiteGroups)
+ {
+ BoostTestRunnerCommandLineArgs args = BuildCommandLineArgs(source.Key);
+ foreach (VSTestCase test in suiteGroup)
+ {
+ // List all tests by name but ensure that the first test is fully qualified so that remaining tests are taken relative to this test suite
+ args.Tests.Add((args.Tests.Count == 0) ? test.FullyQualifiedName : QualifiedNameBuilder.FromString(test.FullyQualifiedName).Peek());
+ }
+
+ yield return new TestRun(runner, suiteGroup, args, adaptedSettings);
+ }
+ }
+ }
+
+ #endregion TestBatchStrategy
+ }
}
\ No newline at end of file
diff --git a/BoostTestAdapter/Utility/BoostDataTestCaseVerifier.cs b/BoostTestAdapter/Utility/BoostDataTestCaseVerifier.cs
new file mode 100644
index 0000000..a63ba7d
--- /dev/null
+++ b/BoostTestAdapter/Utility/BoostDataTestCaseVerifier.cs
@@ -0,0 +1,95 @@
+// (C) Copyright ETAS 2015.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+using System.Text.RegularExpressions;
+
+using BoostTestAdapter.Boost.Test;
+
+namespace BoostTestAdapter.Utility
+{
+ ///
+ /// Utility class which determines if a test suite is, in fact, a BOOST_DATA_TEST_CASE
+ ///
+ public class BoostDataTestCaseVerifier : ITestVisitor
+ {
+ ///
+ /// The test case name pattern used for BOOST_DATA_TEST_CASE instances
+ ///
+ private static readonly Regex _dataTestCaseNamePattern = new Regex(@"^_\d+$");
+
+ ///
+ /// Constructor
+ ///
+ /// The test suite which is to be determined if it is a BOOST_DATA_TEST_CASE
+ private BoostDataTestCaseVerifier(TestSuite testSuite)
+ {
+ this.RootTestSuite = testSuite;
+ this.DataTestCase = true;
+ }
+
+ ///
+ /// The root test suite which is to be determined if it is a BOOST_DATA_TEST_CASE
+ ///
+ public TestSuite RootTestSuite { get; set; }
+
+ ///
+ /// Flag identifying if RootTestSuite is a BOOST_DATA_TEST_CASE
+ ///
+ public bool DataTestCase { get; set; }
+
+ #region ITestVisitor
+
+ public void Visit(TestSuite testSuite)
+ {
+ Code.Require(testSuite, "testSuite");
+
+ // A BOOST_DATA_TEST_CASE should only have child test cases
+ // Any child test suite implies that the suite is not a BOOST_DATA_TEST_CASE
+ DataTestCase = ((testSuite == RootTestSuite) && (testSuite.Source != null));
+
+ if (DataTestCase)
+ {
+ foreach (var child in testSuite.Children)
+ {
+ child.Apply(this);
+
+ if (!DataTestCase)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ public void Visit(TestCase testCase)
+ {
+ Code.Require(testCase, "testCase");
+
+ // A BOOST_DATA_TEST_CASE test has the following properties:
+ // - It's name is of the format '_[number]' (where [number] increments per test case)
+ // - It has the same line number as all other data test case instance
+ // - It has the same source file reference as all other data test case instances
+ DataTestCase = (
+ (testCase.Source.LineNumber == RootTestSuite.Source.LineNumber) &&
+ (testCase.Source.File == RootTestSuite.Source.File) &&
+ _dataTestCaseNamePattern.IsMatch(testCase.Name)
+ );
+ }
+
+ #endregion
+
+ ///
+ /// Determines if the provided test suite is, in fact, a BOOST_DATA_TEST_CASE
+ ///
+ /// The test suite which is to be determined if it is a BOOST_DATA_TEST_CASE
+ /// true if the provided test suite is a BOOST_DATA_TEST_CASE; false otherwise
+ public static bool IsBoostDataTestCase(TestSuite testSuite)
+ {
+ var verifier = new BoostDataTestCaseVerifier(testSuite);
+ testSuite.Apply(verifier);
+ return verifier.DataTestCase;
+ }
+ }
+}
diff --git a/BoostTestAdapter/Utility/QualifiedNameBuilder.cs b/BoostTestAdapter/Utility/QualifiedNameBuilder.cs
index dd8b06d..05f2647 100644
--- a/BoostTestAdapter/Utility/QualifiedNameBuilder.cs
+++ b/BoostTestAdapter/Utility/QualifiedNameBuilder.cs
@@ -1,224 +1,219 @@
-// (C) Copyright ETAS 2015.
-// Distributed under the Boost Software License, Version 1.0.
-// (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using BoostTestAdapter.Boost.Test;
-
-namespace BoostTestAdapter.Utility
-{
- ///
- /// Builds qualified names for Boost Test Test Units.
- ///
- public class QualifiedNameBuilder : ICloneable
- {
- #region Constants
-
- private const string Separator = "/";
-
- #endregion Constants
-
- #region Constructors
-
- ///
- /// Default constructor.
- ///
- public QualifiedNameBuilder()
- : this(new List())
- {
- }
-
- ///
- /// Internal constructor.
- ///
- /// The initial fully qualified path
- private QualifiedNameBuilder(List path)
- {
- this.Path = path;
- }
-
- ///
- /// Constructor. Initializes this qualified name based on the provided TestUnit.
- ///
- /// The TestUnit from which this qualified name is to be initialized.
- public QualifiedNameBuilder(TestUnit root) :
- this()
- {
- Initialize(root);
- }
-
- #endregion Constructors
-
- #region Helper Methods
-
- ///
- /// Helper function which aids in the implementation of QualifiedNameBuilder(TestUnit) constructor
- ///
- /// The test unit which is to be listed
- private void Initialize(TestUnit root)
- {
- if (root == null)
- {
- return;
- }
-
- Initialize(root.Parent);
-
- this.Push(root);
- }
-
- #endregion Helper Methods
-
- #region Properties
-
- ///
- /// The Master Test Suite local name.
- ///
- public string MasterTestSuite
- {
- get { return this.Path.FirstOrDefault(); }
- }
-
- ///
- /// Stack which contains the entries for this qualified name.
- ///
- private List Path { get; set; }
-
- ///
- /// The depth of this fully qualified name.
- /// A depth of 0 implies an empty object.
- ///
- public int Level { get { return this.Path.Count; } }
-
- #endregion Properties
-
- #region Constant Properties
-
- ///
- /// Identifies the standard depth level at which the MasterTestSuite is located.
- ///
- public static uint MasterTestSuiteLevel { get { return 1; } }
-
- ///
- /// Identifies the default MasterTestSuite test suite name.
- ///
- public static string DefaultMasterTestSuiteName { get { return "Master Test Suite"; } }
-
- #endregion Constant Properties
-
- ///
- /// Pushes the test unit on this structure.
- ///
- /// The test unit to push
- /// this
- public QualifiedNameBuilder Push(TestUnit unit)
- {
- Utility.Code.Require(unit, "unit");
-
- return this.Push(unit.Name);
- }
-
- ///
- /// Pushes the (local) name of a test unit on this structure.
- ///
- /// The test unit (local) name to push
- /// this
- public QualifiedNameBuilder Push(string name)
- {
- this.Path.Add(name);
-
- return this;
- }
-
- ///
- /// Peeks at the last (local) name pushed on this builder.
- ///
- /// The last (local) name pushed on this builder.
- public string Peek()
- {
- return (this.Path.Count > 0) ? this.Path[this.Path.Count - 1] : null;
- }
-
- ///
- /// Pops the last test unit from this instance.
- ///
- /// this
- public QualifiedNameBuilder Pop()
- {
- if (this.Path.Count > 0)
- {
- this.Path.RemoveAt(this.Path.Count - 1);
- }
-
- return this;
- }
-
- #region object overrides
-
- ///
- /// Provides a string representation of this fully qualified name as expected by Boost Test standards.
- ///
- /// A string representation of this fully qualified name as expected by Boost Test standards.
- public override string ToString()
- {
- // Skip the Master Test Suite. Master Test Suite is omitted in qualified name.
- return string.Join(Separator, this.Path.Skip(1));
- }
-
- #endregion object overrides
-
- ///
- /// Factory method which creates a QualifiedNameBuilder
- /// from an already existing qualified name string.
- ///
- /// The qualified name
- /// A QualifiedNameBuilder from the provided string.
- public static QualifiedNameBuilder FromString(string name)
- {
- // Assume Master Test Suite name
- return FromString(DefaultMasterTestSuiteName, name);
- }
-
- ///
- /// Factory method which creates a QualifiedNameBuilder
- /// from an already existing qualified name string.
- ///
- /// The local name of the master test suite
- /// The qualified name
- /// A QualifiedNameBuilder from the provided string.
- public static QualifiedNameBuilder FromString(string masterSuite, string name)
- {
- Utility.Code.Require(masterSuite, "masterSuite");
- Utility.Code.Require(name, "name");
-
- QualifiedNameBuilder builder = new QualifiedNameBuilder();
-
- builder.Push(masterSuite);
-
- foreach (string part in name.Split(new string[] { Separator }, StringSplitOptions.RemoveEmptyEntries))
- {
- builder.Push(part);
- }
-
- return builder;
- }
-
- #region ICloneable
-
- object ICloneable.Clone()
- {
- return this.Clone();
- }
-
- public QualifiedNameBuilder Clone()
- {
- // NOTE Make an explicit copy of the path
- return new QualifiedNameBuilder(new List(this.Path));
- }
-
- #endregion ICloneable
- }
+// (C) Copyright ETAS 2015.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using BoostTestAdapter.Boost.Test;
+
+namespace BoostTestAdapter.Utility
+{
+ ///
+ /// Builds qualified names for Boost Test Test Units.
+ ///
+ public class QualifiedNameBuilder : ICloneable
+ {
+ #region Constants
+
+ private const string Separator = "/";
+
+ #endregion Constants
+
+ #region Constructors
+
+ ///
+ /// Default constructor.
+ ///
+ public QualifiedNameBuilder()
+ : this(new List())
+ {
+ }
+
+ ///
+ /// Internal constructor.
+ ///
+ /// The initial fully qualified path
+ private QualifiedNameBuilder(List path)
+ {
+ this.Path = path;
+ }
+
+ ///
+ /// Constructor. Initializes this qualified name based on the provided TestUnit.
+ ///
+ /// The TestUnit from which this qualified name is to be initialized.
+ public QualifiedNameBuilder(TestUnit root) :
+ this()
+ {
+ Initialize(root);
+ }
+
+ #endregion Constructors
+
+ #region Helper Methods
+
+ ///
+ /// Helper function which aids in the implementation of QualifiedNameBuilder(TestUnit) constructor
+ ///
+ /// The test unit which is to be listed
+ private void Initialize(TestUnit root)
+ {
+ if (root == null)
+ {
+ return;
+ }
+
+ Initialize(root.Parent);
+
+ this.Push(root);
+ }
+
+ #endregion Helper Methods
+
+ #region Properties
+
+ ///
+ /// The Master Test Suite local name.
+ ///
+ public string MasterTestSuite
+ {
+ get { return this.Path.FirstOrDefault(); }
+ }
+
+ ///
+ /// Stack which contains the entries for this qualified name.
+ ///
+ private List Path { get; set; }
+
+ ///
+ /// The depth of this fully qualified name.
+ /// A depth of 0 implies an empty object.
+ ///
+ public int Level { get { return this.Path.Count; } }
+
+ #endregion Properties
+
+ #region Constant Properties
+
+ ///
+ /// Identifies the default MasterTestSuite test suite name.
+ ///
+ public static string DefaultMasterTestSuiteName { get { return "Master Test Suite"; } }
+
+ #endregion Constant Properties
+
+ ///
+ /// Pushes the test unit on this structure.
+ ///
+ /// The test unit to push
+ /// this
+ public QualifiedNameBuilder Push(TestUnit unit)
+ {
+ Utility.Code.Require(unit, "unit");
+
+ return this.Push(unit.Name);
+ }
+
+ ///
+ /// Pushes the (local) name of a test unit on this structure.
+ ///
+ /// The test unit (local) name to push
+ /// this
+ public QualifiedNameBuilder Push(string name)
+ {
+ this.Path.Add(name);
+
+ return this;
+ }
+
+ ///
+ /// Peeks at the last (local) name pushed on this builder.
+ ///
+ /// The last (local) name pushed on this builder.
+ public string Peek()
+ {
+ return (this.Path.Count > 0) ? this.Path[this.Path.Count - 1] : null;
+ }
+
+ ///
+ /// Pops the last test unit from this instance.
+ ///
+ /// this
+ public QualifiedNameBuilder Pop()
+ {
+ if (this.Path.Count > 0)
+ {
+ this.Path.RemoveAt(this.Path.Count - 1);
+ }
+
+ return this;
+ }
+
+ #region object overrides
+
+ ///
+ /// Provides a string representation of this fully qualified name as expected by Boost Test standards.
+ ///
+ /// A string representation of this fully qualified name as expected by Boost Test standards.
+ public override string ToString()
+ {
+ // Skip the Master Test Suite. Master Test Suite is omitted in qualified name.
+ return string.Join(Separator, this.Path.Skip(1));
+ }
+
+ #endregion object overrides
+
+ ///
+ /// Factory method which creates a QualifiedNameBuilder
+ /// from an already existing qualified name string.
+ ///
+ /// The qualified name
+ /// A QualifiedNameBuilder from the provided string.
+ public static QualifiedNameBuilder FromString(string name)
+ {
+ // Assume Master Test Suite name
+ return FromString(DefaultMasterTestSuiteName, name);
+ }
+
+ ///
+ /// Factory method which creates a QualifiedNameBuilder
+ /// from an already existing qualified name string.
+ ///
+ /// The local name of the master test suite
+ /// The qualified name
+ /// A QualifiedNameBuilder from the provided string.
+ public static QualifiedNameBuilder FromString(string masterSuite, string name)
+ {
+ Utility.Code.Require(masterSuite, "masterSuite");
+ Utility.Code.Require(name, "name");
+
+ QualifiedNameBuilder builder = new QualifiedNameBuilder();
+
+ builder.Push(masterSuite);
+
+ foreach (string part in name.Split(new string[] { Separator }, StringSplitOptions.RemoveEmptyEntries))
+ {
+ builder.Push(part);
+ }
+
+ return builder;
+ }
+
+ #region ICloneable
+
+ object ICloneable.Clone()
+ {
+ return this.Clone();
+ }
+
+ public QualifiedNameBuilder Clone()
+ {
+ // NOTE Make an explicit copy of the path
+ return new QualifiedNameBuilder(new List(this.Path));
+ }
+
+ #endregion ICloneable
+ }
}
\ No newline at end of file
diff --git a/BoostTestAdapter/Utility/VisualStudio/DefaultDiscoverySink.cs b/BoostTestAdapter/Utility/VisualStudio/DefaultTestCaseDiscoverySink.cs
similarity index 96%
rename from BoostTestAdapter/Utility/VisualStudio/DefaultDiscoverySink.cs
rename to BoostTestAdapter/Utility/VisualStudio/DefaultTestCaseDiscoverySink.cs
index 8410142..f0562e1 100644
--- a/BoostTestAdapter/Utility/VisualStudio/DefaultDiscoverySink.cs
+++ b/BoostTestAdapter/Utility/VisualStudio/DefaultTestCaseDiscoverySink.cs
@@ -1,66 +1,66 @@
-// (C) Copyright ETAS 2015.
-// Distributed under the Boost Software License, Version 1.0.
-// (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-using System.Collections.Generic;
-using Microsoft.VisualStudio.TestPlatform.ObjectModel;
-using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
-
-namespace BoostTestAdapter.Utility.VisualStudio
-{
- ///
- /// An ITestCaseDiscoverySink implementation. Aggregates all tests
- /// within an internal collection which is publicly accessible.
- ///
- public class DefaultTestCaseDiscoverySink : ITestCaseDiscoverySink
- {
- private ICollection _tests = new HashSet(new TestCaseComparer());
-
- ///
- /// The collection of discovered TestCases
- ///
- public IEnumerable Tests
- {
- get
- {
- return _tests;
- }
- }
-
- #region ITestCaseDiscoverySink
-
- public void SendTestCase(TestCase discoveredTest)
- {
- this._tests.Add(discoveredTest);
- }
-
- #endregion ITestCaseDiscoverySink
- }
-
- ///
- /// TestCase equality comparer which defines equality based on the TestCase's
- /// Fully Qualified Name.
- ///
- public class TestCaseComparer : IEqualityComparer
- {
- #region IEqualityComparer
-
- public bool Equals(TestCase x, TestCase y)
- {
- Utility.Code.Require(x, "x");
- Utility.Code.Require(y, "y");
-
- return (x.FullyQualifiedName == y.FullyQualifiedName) && (x.Source == y.Source);
- }
-
- public int GetHashCode(TestCase obj)
- {
- Utility.Code.Require(obj, "obj");
-
- return obj.FullyQualifiedName.GetHashCode() ^ obj.Source.GetHashCode();
- }
-
- #endregion IEqualityComparer
- }
+// (C) Copyright ETAS 2015.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+using System.Collections.Generic;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
+
+namespace BoostTestAdapter.Utility.VisualStudio
+{
+ ///
+ /// An ITestCaseDiscoverySink implementation. Aggregates all tests
+ /// within an internal collection which is publicly accessible.
+ ///
+ public class DefaultTestCaseDiscoverySink : ITestCaseDiscoverySink
+ {
+ private ICollection _tests = new HashSet(new TestCaseComparer());
+
+ ///
+ /// The collection of discovered TestCases
+ ///
+ public IEnumerable Tests
+ {
+ get
+ {
+ return _tests;
+ }
+ }
+
+ #region ITestCaseDiscoverySink
+
+ public void SendTestCase(TestCase discoveredTest)
+ {
+ this._tests.Add(discoveredTest);
+ }
+
+ #endregion ITestCaseDiscoverySink
+ }
+
+ ///
+ /// TestCase equality comparer which defines equality based on the TestCase's
+ /// Fully Qualified Name.
+ ///
+ public class TestCaseComparer : IEqualityComparer
+ {
+ #region IEqualityComparer
+
+ public bool Equals(TestCase x, TestCase y)
+ {
+ Utility.Code.Require(x, "x");
+ Utility.Code.Require(y, "y");
+
+ return (x.FullyQualifiedName == y.FullyQualifiedName) && (x.Source == y.Source);
+ }
+
+ public int GetHashCode(TestCase obj)
+ {
+ Utility.Code.Require(obj, "obj");
+
+ return obj.FullyQualifiedName.GetHashCode() ^ obj.Source.GetHashCode();
+ }
+
+ #endregion IEqualityComparer
+ }
}
\ No newline at end of file
diff --git a/BoostTestAdapterNunit/BoostDataTestCaseVerifierTest.cs b/BoostTestAdapterNunit/BoostDataTestCaseVerifierTest.cs
new file mode 100644
index 0000000..96cd91f
--- /dev/null
+++ b/BoostTestAdapterNunit/BoostDataTestCaseVerifierTest.cs
@@ -0,0 +1,139 @@
+// (C) Copyright ETAS 2015.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+using NUnit.Framework;
+
+using BoostTestAdapter.Boost.Test;
+using BoostTestAdapter.Utility;
+
+using BoostTestAdapterNunit.Utility;
+
+namespace BoostTestAdapterNunit
+{
+ [TestFixture]
+ internal class BoostDataTestCaseVerifierTest
+ {
+ private const string _sourceFile = @"c:\test.cpp";
+
+ ///
+ /// Creates a 'default' TestFrameworkBuilder instance for this TestFixture
+ ///
+ /// A 'default' TestFrameworkBuilder instance
+ private static TestFrameworkBuilder CreateFrameworkBuilder()
+ {
+ return new TestFrameworkBuilder("test.exe", "MyTest", 1);
+ }
+
+ ///
+ /// Locates the test suite with the provided fully qualified name
+ ///
+ /// The framework from which to locate the test suite
+ /// The test suite's fully qualified name
+ /// The test suite which was located or null if it was not found
+ private static TestSuite LocateSuite(TestFramework framework, string fullyQualifiedName)
+ {
+ var suite = BoostTestLocator.Locate(framework, fullyQualifiedName);
+
+ Assert.That(suite, Is.Not.Null);
+ Assert.That(suite, Is.TypeOf());
+
+ return (TestSuite) suite;
+ }
+
+ ///
+ /// Verifies if the test suite with the specified fully qualified name is a BOOST_DATA_TEST_CASE
+ ///
+ /// The framework from which to locate the test suite
+ /// The test suite's fully qualified name
+ /// true if the test suite is a BOOST_DATA_TEST_CASE; false otherwise
+ private static bool IsBoostDataTestCase(TestFramework framework, string fullyQualifiedName)
+ {
+ var suite = LocateSuite(framework, fullyQualifiedName);
+ return (suite != null) && (BoostDataTestCaseVerifier.IsBoostDataTestCase(suite));
+ }
+
+ ///
+ /// Assert that: A valid BOOST_DATA_TEST_CASE can be identified as such
+ ///
+ [Test]
+ public void ValidBoostDataTestCase()
+ {
+ TestFramework framework = CreateFrameworkBuilder().
+ TestSuite("DataTestCase", 2, new SourceFileInfo(_sourceFile, 10)).
+ TestCase("_0", 65536, new SourceFileInfo(_sourceFile, 10)).
+ TestCase("_1", 65537, new SourceFileInfo(_sourceFile, 10)).
+ TestCase("_2", 65538, new SourceFileInfo(_sourceFile, 10)).
+ TestCase("_3", 65539, new SourceFileInfo(_sourceFile, 10)).
+ EndSuite().
+ Build();
+
+ bool result = IsBoostDataTestCase(framework, "DataTestCase");
+ Assert.That(result, Is.True);
+ }
+
+ ///
+ /// Assert that: A test suite containing tests with a pattern similar to BOOST_DATA_TEST_CASE is not identified
+ /// as a data test case instance if the line numbers differ from the parent test suite instance
+ ///
+ [Test]
+ public void FakeBoostDataTestCase()
+ {
+ TestFramework framework = CreateFrameworkBuilder().
+ TestSuite("BoostUnitTest", 2, new SourceFileInfo(_sourceFile, 10)).
+ TestCase("_0", 65536, new SourceFileInfo(_sourceFile, 13)).
+ TestCase("_1", 65537, new SourceFileInfo(_sourceFile, 23)).
+ TestCase("_2", 65538, new SourceFileInfo(_sourceFile, 33)).
+ TestCase("_3", 65539, new SourceFileInfo(_sourceFile, 43)).
+ EndSuite().
+ Build();
+
+ bool result = IsBoostDataTestCase(framework, "BoostUnitTest");
+ Assert.That(result, Is.False);
+ }
+
+ ///
+ /// Assert that: A regular test suite containing test suites and test cases is not identified as a
+ /// BOOST_DATA_TEST_CASE
+ ///
+ [Test]
+ public void RegularTestSuite()
+ {
+ TestFramework framework = CreateFrameworkBuilder().
+ TestSuite("Suite1", 2, new SourceFileInfo(_sourceFile, 10)).
+ TestSuite("Suite2", 3, new SourceFileInfo(_sourceFile, 15)).
+ TestCase("Test1", 65536, new SourceFileInfo(_sourceFile, 23)).
+ EndSuite().
+ EndSuite().
+ Build();
+
+ {
+ bool result = IsBoostDataTestCase(framework, "Suite1");
+ Assert.That(result, Is.False);
+ }
+
+ {
+ bool result = IsBoostDataTestCase(framework, "Suite1/Suite2");
+ Assert.That(result, Is.False);
+ }
+ }
+
+ ///
+ /// Assert that: A regular test suite containing solely test cases is not identified as a
+ /// BOOST_DATA_TEST_CASE
+ ///
+ [Test]
+ public void RegularTestCase()
+ {
+ TestFramework framework = CreateFrameworkBuilder().
+ TestSuite("Suite1", 2, new SourceFileInfo(_sourceFile, 10)).
+ TestCase("Test1", 65536, new SourceFileInfo(_sourceFile, 23)).
+ EndSuite().
+ Build();
+
+ bool result = IsBoostDataTestCase(framework, "Suite1");
+ Assert.That(result, Is.False);
+ }
+ }
+}
diff --git a/BoostTestAdapterNunit/BoostTestAdapterNunit.csproj b/BoostTestAdapterNunit/BoostTestAdapterNunit.csproj
index 0f13538..16808bb 100644
--- a/BoostTestAdapterNunit/BoostTestAdapterNunit.csproj
+++ b/BoostTestAdapterNunit/BoostTestAdapterNunit.csproj
@@ -1,182 +1,186 @@
-
-
-
-
- Debug
- AnyCPU
- {FE58A67C-D313-46FD-B8F3-F80383EE5FD1}
- Library
- Properties
- BoostTestAdapterNunit
- BoostTestAdapterNunit
- v4.5
- 512
-
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
- true
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
- $(MSBuildProgramFiles32)
-
- $(ProgramFiles%28x86%29)
+
+
+
+
+ Debug
+ AnyCPU
+ {FE58A67C-D313-46FD-B8F3-F80383EE5FD1}
+ Library
+ Properties
+ BoostTestAdapterNunit
+ BoostTestAdapterNunit
+ v4.5
+ 512
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ true
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ $(MSBuildProgramFiles32)
+
+ $(ProgramFiles%28x86%29)
- $(ProgramFiles) (x86)
-
- $(ProgramFiles)
-
-
-
- ..\Antlr.DOT\lib\Antlr4.Runtime.dll
-
-
- ..\packages\FakeItEasy.1.13.1\lib\net40\FakeItEasy.dll
-
-
- False
- $(ProgramFiles32)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TestWindow\Microsoft.VisualStudio.TestPlatform.ObjectModel.dll
-
-
- ..\packages\NUnit.2.6.4\lib\nunit.framework.dll
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {488ae1ce-107d-4f5b-9f1f-ed7905d5ce75}
- Antlr.DOT
-
-
- {bc4b3bed-9241-4dd6-8070-a9b66dfc08c1}
- BoostTestAdapter
-
-
- {62347cc7-c839-413d-a7ce-598409f6f15b}
- VisualStudioAdapter
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NB this trick (Adding a literal " (x86)" to the 64 bit Program Files path) may or may not work on all versions/locales of Windows -->
+ $(ProgramFiles) (x86)
+
+ $(ProgramFiles)
+
+
+
+ ..\Antlr.DOT\lib\Antlr4.Runtime.dll
+
+
+ ..\packages\FakeItEasy.1.13.1\lib\net40\FakeItEasy.dll
+
+
+ False
+ $(ProgramFiles32)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TestWindow\Microsoft.VisualStudio.TestPlatform.ObjectModel.dll
+
+
+ ..\packages\NUnit.2.6.4\lib\nunit.framework.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {488ae1ce-107d-4f5b-9f1f-ed7905d5ce75}
+ Antlr.DOT
+
+
+ {bc4b3bed-9241-4dd6-8070-a9b66dfc08c1}
+ BoostTestAdapter
+
+
+ {62347cc7-c839-413d-a7ce-598409f6f15b}
+ VisualStudioAdapter
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -->
\ No newline at end of file
diff --git a/BoostTestAdapterNunit/BoostTestExecutorTest.cs b/BoostTestAdapterNunit/BoostTestExecutorTest.cs
index 237630b..6d5ec92 100644
--- a/BoostTestAdapterNunit/BoostTestExecutorTest.cs
+++ b/BoostTestAdapterNunit/BoostTestExecutorTest.cs
@@ -466,7 +466,11 @@ private VSTestCase CreateTestCase(string fullyQualifiedName, string source)
{
VSTestCase test = new VSTestCase(fullyQualifiedName, BoostTestExecutor.ExecutorUri, source);
- test.Traits.Add(VSTestModel.TestSuiteTrait, QualifiedNameBuilder.FromString(fullyQualifiedName).Pop().ToString());
+ var fullyQualifiedNameBuilder = QualifiedNameBuilder.FromString(fullyQualifiedName);
+
+ test.DisplayName = fullyQualifiedNameBuilder.Peek();
+
+ test.Traits.Add(VSTestModel.TestSuiteTrait, fullyQualifiedNameBuilder.Pop().ToString());
test.Traits.Add(VSTestModel.StatusTrait, VSTestModel.TestEnabled);
return test;
@@ -972,7 +976,7 @@ public void TestTestSuiteBatchedRuns()
List>> expectedBatches = new List>>
{
- new KeyValuePair>(DefaultSource, new List {"A/Test1", "A/Test2"}),
+ new KeyValuePair>(DefaultSource, new List {"A/Test1", "Test2"}),
new KeyValuePair>(DefaultSource, new List {"B/Test1"}),
new KeyValuePair>(otherSource, new List {"A/Test1"})
};
diff --git a/BoostTestAdapterNunit/BoostTestTest.cs b/BoostTestAdapterNunit/BoostTestTest.cs
index cecf636..389287e 100644
--- a/BoostTestAdapterNunit/BoostTestTest.cs
+++ b/BoostTestAdapterNunit/BoostTestTest.cs
@@ -4,14 +4,11 @@
// http://www.boost.org/LICENSE_1_0.txt)
using System;
-using System.IO;
-using System.Xml;
-using System.Xml.Serialization;
using BoostTestAdapter.Boost.Test;
using BoostTestAdapter.Utility;
-using BoostTestAdapterNunit.Utility;
using NUnit.Framework;
-
+using BoostTestAdapterNunit.Utility;
+
namespace BoostTestAdapterNunit
{
[TestFixture]
@@ -25,57 +22,7 @@ class BoostTestTest
private const string Source = @"C:\tests.dll";
#endregion Test Data
-
- #region Helper Classes
- ///
- /// ITestVisitor implementation which looks up test units based on their qualified name.
- ///
- private class TestUnitLookup : ITestVisitor
- {
- public TestUnitLookup(string fullyQualifiedName)
- {
- this.FullyQualifiedName = fullyQualifiedName;
- }
-
- public string FullyQualifiedName { get; private set; }
- public TestUnit Unit { get; private set; }
-
- public void Visit(TestCase testCase)
- {
- Check(testCase);
- }
-
- public void Visit(TestSuite testSuite)
- {
- if (!Check(testSuite))
- {
- foreach (TestUnit child in testSuite.Children)
- {
- child.Apply(this);
- if (this.Unit != null)
- {
- break;
- }
- }
- }
- }
-
- private bool Check(TestUnit unit)
- {
- bool match = (unit.FullyQualifiedName == this.FullyQualifiedName);
-
- if (match)
- {
- this.Unit = unit;
- }
-
- return match;
- }
- }
-
- #endregion Helper Classes
-
#region Helper Methods
///
@@ -86,9 +33,7 @@ private bool Check(TestUnit unit)
/// The test unit with the requested fully qualified name or null if it cannot be found
private TestUnit Lookup(TestUnit root, string fullyQualifiedName)
{
- TestUnitLookup lookup = new TestUnitLookup(fullyQualifiedName);
- root.Apply(lookup);
- return lookup.Unit;
+ return BoostTestLocator.Locate(root, fullyQualifiedName);
}
///
diff --git a/BoostTestAdapterNunit/DOTDeserialisationTest.cs b/BoostTestAdapterNunit/DOTDeserialisationTest.cs
index 86adc6f..b429ae6 100644
--- a/BoostTestAdapterNunit/DOTDeserialisationTest.cs
+++ b/BoostTestAdapterNunit/DOTDeserialisationTest.cs
@@ -1,160 +1,177 @@
-// (C) Copyright ETAS 2015.
-// Distributed under the Boost Software License, Version 1.0.
-// (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-using BoostTestAdapter.Utility;
-using BoostTestAdapter.Boost.Test;
-
-using BoostTestAdapterNunit.Utility;
-
-using NUnit.Framework;
-
-namespace BoostTestAdapterNunit
-{
- [TestFixture]
- public class DOTDeserialisationTest
- {
- #region Test Data
-
- ///
- /// Default source identifier for test purposes
- ///
- private static string Source
- {
- get
- {
- return "source.exe";
- }
- }
-
- #endregion Test Data
-
- #region Helper Methods
-
- ///
- /// Compares a test framework deserialised from the provided embedded resource against the expected one
- ///
- /// Path to an embedded resource which is to be treated as input for TestFramework deserialisation
- /// The TestFramework which the deserialised version should be compared against
- private void Compare(string resource, TestFramework expected)
- {
- using (var stream = TestHelper.LoadEmbeddedResource(resource))
- {
- TestFrameworkDOTDeserialiser parser = new TestFrameworkDOTDeserialiser(Source);
- TestFramework framework = parser.Deserialise(stream);
-
- FrameworkEqualityVisitor.IsEqualTo(framework, expected, false);
- }
- }
-
- #endregion Helper Methods
-
- ///
- /// Deserialisation of (relatively large) Boost Test DOT content containing most features
- ///
- /// Test aims:
- /// - Ensure that a TestFramework can be deserialised correctly from DOT content
- ///
- [Test]
- public void DeserialiseDOT()
- {
- TestFramework expected = new TestFrameworkBuilder(Source, "sample", 1, false).
- TestSuite("suite_1", 2, new SourceFileInfo(@"d:\sample.boostunittest\file_1.cpp", 6), false).
- TestSuite("suite_2", 3, new SourceFileInfo(@"d:\sample.boostunittest\file_1.cpp", 8), false).
- TestCase("test_3", 65536, new SourceFileInfo(@"d:\sample.boostunittest\file_1.cpp", 14), null, false).
- TestCase("test_4", 65537, new SourceFileInfo(@"d:\sample.boostunittest\file_1.cpp", 44), null, false).
- TestCase("test_5", 65538, new SourceFileInfo(@"d:\sample.boostunittest\file_1.cpp", 62), null, false).
- EndSuite().
- TestSuite("suite_6", 4, new SourceFileInfo(@"d:\sample.boostunittest\file_2.cpp", 19), false).
- TestCase("test_7", 65539, new SourceFileInfo(@"d:\sample.boostunittest\file_2.cpp", 24), null, false).
- TestCase("test_8", 65540, new SourceFileInfo(@"d:\sample.boostunittest\file_2.cpp", 40), null, false).
- TestCase("test_9", 65541, new SourceFileInfo(@"d:\sample.boostunittest\file_2.cpp", 90), null, false).
- TestCase("test_10", 65542, new SourceFileInfo(@"d:\sample.boostunittest\file_2.cpp", 105), null, false).
- TestCase("test_11", 65543, new SourceFileInfo(@"d:\sample.boostunittest\file_2.cpp", 121), null, false).
- TestCase("test_12", 65544, new SourceFileInfo(@"d:\sample.boostunittest\file_2.cpp", 134), null, false).
- TestCase("test_13", 65545, new SourceFileInfo(@"d:\sample.boostunittest\file_2.cpp", 310), null, false).
- EndSuite().
- TestSuite("suite_14", 5, new SourceFileInfo(@"d:\sample.boostunittest\file_3.cpp", 20), false).
- TestCase("test_15", 65546, new SourceFileInfo(@"d:\sample.boostunittest\file_3.cpp", 27), null, false).
- TestCase("test_16", 65547, new SourceFileInfo(@"d:\sample.boostunittest\file_3.cpp", 49), null, false).
- TestCase("test_17", 65548, new SourceFileInfo(@"d:\sample.boostunittest\file_3.cpp", 59), null, false).
- TestCase("test_18", 65549, new SourceFileInfo(@"d:\sample.boostunittest\file_3.cpp", 88), null, false).
- EndSuite().
- TestSuite("suite_19", 6, new SourceFileInfo(@"d:\sample.boostunittest\file_4.cpp", 7), false).
- TestCase("test_20", 65550, new SourceFileInfo(@"d:\sample.boostunittest\file_4.cpp", 12), null, false).
- EndSuite().
- TestSuite("suite_21", 7, new SourceFileInfo(@"d:\sample.boostunittest\file_5.cpp", 8), false).
- TestCase("test_22", 65551, new SourceFileInfo(@"d:\sample.boostunittest\file_5.cpp", 14), null, false).
- EndSuite().
- TestSuite("suite_23", 8, new SourceFileInfo(@"d:\sample.boostunittest\file_6.cpp", 13), false).
- TestCase("test_24", 65552, new SourceFileInfo(@"d:\sample.boostunittest\file_6.cpp", 18), null, false).
- TestCase("test_25", 65553, new SourceFileInfo(@"d:\sample.boostunittest\file_6.cpp", 28), null, false).
- TestCase("test_26", 65554, new SourceFileInfo(@"d:\sample.boostunittest\file_6.cpp", 38), null, false).
- TestCase("test_27", 65555, new SourceFileInfo(@"d:\sample.boostunittest\file_6.cpp", 48), null, false).
- TestCase("test_28", 65556, new SourceFileInfo(@"d:\sample.boostunittest\file_6.cpp", 59), null, false).
- TestCase("test_29", 65557, new SourceFileInfo(@"d:\sample.boostunittest\file_6.cpp", 70), null, false).
- EndSuite().
- TestSuite("suite_30", 9, new SourceFileInfo(@"d:\sample.boostunittest\file_7.cpp", 8), false).
- TestCase("test_31", 65558, new SourceFileInfo(@"d:\sample.boostunittest\file_7.cpp", 14), new[] { "hello", "world", "labels" }, false).
- EndSuite().
- EndSuite().
- Build();
-
- Compare("BoostTestAdapterNunit.Resources.ListContentDOT.sample.list.content.gv", expected);
- }
-
- ///
- /// Deserialisation of Boost Test DOT content consisting of the following scenario:
- ///
- /// - Master Test Suite
- /// -- Test Case
- /// -- Test Suite
- /// --- Test Case
- /// -- Test Case
- ///
- /// Test aims:
- /// - Ensure that a TestFramework can be deserialised correctly from DOT content
- ///
- [Test]
- public void TestSuiteWithChildTestsAndSuites()
- {
- TestFramework expected = new TestFrameworkBuilder(Source, "MyTest", 1, false).
- TestCase("Test", 65536, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 30),null, false).
- TestSuite("Suite", 2, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 35), false).
- TestCase("Test", 65537, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 37), null, false).
- EndSuite().
- TestCase("TestB", 65538, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 44), null, false).
- Build();
-
- Compare("BoostTestAdapterNunit.Resources.ListContentDOT.sample.3.list.content.gv", expected);
- }
-
-
- ///
- /// Deserialisation of Boost Test DOT content consisting of test cases which are
- /// explicitly enabled or disabled using boost decorators
- ///
- /// Test aims:
- /// - Ensure that the decorators are correctly read and grouping is done correctly
- ///
- [Test]
- public void TestsWithDecorators()
- {
- TestFramework expected = new TestFrameworkBuilder(Source, "Sample", 1).
- TestSuite("Suite1", 2, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 11)).
- TestCase("MyBoost_Test1", 65536, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 12)).
- TestCase("MyBoost_Test2", 65537, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 16), null, false).
- TestCase("MyBoost_Test3", 65538, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 20)).
- TestCase("MyBoost_Test4", 65539, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 24), null, false).
- EndSuite().
- TestCase("MyBoost_Test5", 65540, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 30)).
- TestCase("MyBoost_Test6", 65541, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 34), null, false).
- TestCase("MyBoost_Test7", 65542, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 38)).
- TestCase("MyBoost_Test8", 65543, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 42), null, false).
- Build();
-
- Compare("BoostTestAdapterNunit.Resources.ListContentDOT.test_list_content.gv", expected);
- }
- }
+// (C) Copyright ETAS 2015.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+using BoostTestAdapter.Utility;
+using BoostTestAdapter.Boost.Test;
+
+using BoostTestAdapterNunit.Utility;
+
+using NUnit.Framework;
+
+namespace BoostTestAdapterNunit
+{
+ [TestFixture]
+ public class DOTDeserialisationTest
+ {
+ #region Test Data
+
+ ///
+ /// Default source identifier for test purposes
+ ///
+ private static string Source
+ {
+ get
+ {
+ return "source.exe";
+ }
+ }
+
+ #endregion Test Data
+
+ #region Helper Methods
+
+ ///
+ /// Compares a test framework deserialised from the provided embedded resource against the expected one
+ ///
+ /// Path to an embedded resource which is to be treated as input for TestFramework deserialisation
+ /// The TestFramework which the deserialised version should be compared against
+ private void Compare(string resource, TestFramework expected)
+ {
+ using (var stream = TestHelper.LoadEmbeddedResource(resource))
+ {
+ TestFrameworkDOTDeserialiser parser = new TestFrameworkDOTDeserialiser(Source);
+ TestFramework framework = parser.Deserialise(stream);
+
+ FrameworkEqualityVisitor.IsEqualTo(framework, expected, false);
+ }
+ }
+
+ #endregion Helper Methods
+
+ ///
+ /// Deserialisation of (relatively large) Boost Test DOT content containing most features
+ ///
+ /// Test aims:
+ /// - Ensure that a TestFramework can be deserialised correctly from DOT content
+ ///
+ [Test]
+ public void DeserialiseDOT()
+ {
+ TestFramework expected = new TestFrameworkBuilder(Source, "sample", 1, false).
+ TestSuite("suite_1", 2, new SourceFileInfo(@"d:\sample.boostunittest\file_1.cpp", 6), false).
+ TestSuite("suite_2", 3, new SourceFileInfo(@"d:\sample.boostunittest\file_1.cpp", 8), false).
+ TestCase("test_3", 65536, new SourceFileInfo(@"d:\sample.boostunittest\file_1.cpp", 14), null, false).
+ TestCase("test_4", 65537, new SourceFileInfo(@"d:\sample.boostunittest\file_1.cpp", 44), null, false).
+ TestCase("test_5", 65538, new SourceFileInfo(@"d:\sample.boostunittest\file_1.cpp", 62), null, false).
+ EndSuite().
+ TestSuite("suite_6", 4, new SourceFileInfo(@"d:\sample.boostunittest\file_2.cpp", 19), false).
+ TestCase("test_7", 65539, new SourceFileInfo(@"d:\sample.boostunittest\file_2.cpp", 24), null, false).
+ TestCase("test_8", 65540, new SourceFileInfo(@"d:\sample.boostunittest\file_2.cpp", 40), null, false).
+ TestCase("test_9", 65541, new SourceFileInfo(@"d:\sample.boostunittest\file_2.cpp", 90), null, false).
+ TestCase("test_10", 65542, new SourceFileInfo(@"d:\sample.boostunittest\file_2.cpp", 105), null, false).
+ TestCase("test_11", 65543, new SourceFileInfo(@"d:\sample.boostunittest\file_2.cpp", 121), null, false).
+ TestCase("test_12", 65544, new SourceFileInfo(@"d:\sample.boostunittest\file_2.cpp", 134), null, false).
+ TestCase("test_13", 65545, new SourceFileInfo(@"d:\sample.boostunittest\file_2.cpp", 310), null, false).
+ EndSuite().
+ TestSuite("suite_14", 5, new SourceFileInfo(@"d:\sample.boostunittest\file_3.cpp", 20), false).
+ TestCase("test_15", 65546, new SourceFileInfo(@"d:\sample.boostunittest\file_3.cpp", 27), null, false).
+ TestCase("test_16", 65547, new SourceFileInfo(@"d:\sample.boostunittest\file_3.cpp", 49), null, false).
+ TestCase("test_17", 65548, new SourceFileInfo(@"d:\sample.boostunittest\file_3.cpp", 59), null, false).
+ TestCase("test_18", 65549, new SourceFileInfo(@"d:\sample.boostunittest\file_3.cpp", 88), null, false).
+ EndSuite().
+ TestSuite("suite_19", 6, new SourceFileInfo(@"d:\sample.boostunittest\file_4.cpp", 7), false).
+ TestCase("test_20", 65550, new SourceFileInfo(@"d:\sample.boostunittest\file_4.cpp", 12), null, false).
+ EndSuite().
+ TestSuite("suite_21", 7, new SourceFileInfo(@"d:\sample.boostunittest\file_5.cpp", 8), false).
+ TestCase("test_22", 65551, new SourceFileInfo(@"d:\sample.boostunittest\file_5.cpp", 14), null, false).
+ EndSuite().
+ TestSuite("suite_23", 8, new SourceFileInfo(@"d:\sample.boostunittest\file_6.cpp", 13), false).
+ TestCase("test_24", 65552, new SourceFileInfo(@"d:\sample.boostunittest\file_6.cpp", 18), null, false).
+ TestCase("test_25", 65553, new SourceFileInfo(@"d:\sample.boostunittest\file_6.cpp", 28), null, false).
+ TestCase("test_26", 65554, new SourceFileInfo(@"d:\sample.boostunittest\file_6.cpp", 38), null, false).
+ TestCase("test_27", 65555, new SourceFileInfo(@"d:\sample.boostunittest\file_6.cpp", 48), null, false).
+ TestCase("test_28", 65556, new SourceFileInfo(@"d:\sample.boostunittest\file_6.cpp", 59), null, false).
+ TestCase("test_29", 65557, new SourceFileInfo(@"d:\sample.boostunittest\file_6.cpp", 70), null, false).
+ EndSuite().
+ TestSuite("suite_30", 9, new SourceFileInfo(@"d:\sample.boostunittest\file_7.cpp", 8), false).
+ TestCase("test_31", 65558, new SourceFileInfo(@"d:\sample.boostunittest\file_7.cpp", 14), new[] { "hello", "world", "labels" }, false).
+ EndSuite().
+ EndSuite().
+ Build();
+
+ Compare("BoostTestAdapterNunit.Resources.ListContentDOT.sample.list.content.gv", expected);
+ }
+
+ ///
+ /// Deserialisation of Boost Test DOT content consisting of the following scenario:
+ ///
+ /// - Master Test Suite
+ /// -- Test Case
+ /// -- Test Suite
+ /// --- Test Case
+ /// -- Test Case
+ ///
+ /// Test aims:
+ /// - Ensure that a TestFramework can be deserialised correctly from DOT content
+ ///
+ [Test]
+ public void TestSuiteWithChildTestsAndSuites()
+ {
+ TestFramework expected = new TestFrameworkBuilder(Source, "MyTest", 1, false).
+ TestCase("Test", 65536, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 30),null, false).
+ TestSuite("Suite", 2, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 35), false).
+ TestCase("Test", 65537, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 37), null, false).
+ EndSuite().
+ TestCase("TestB", 65538, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 44), null, false).
+ Build();
+
+ Compare("BoostTestAdapterNunit.Resources.ListContentDOT.sample.3.list.content.gv", expected);
+ }
+
+ ///
+ /// Deserialisation of Boost Test DOT content consisting of test cases which are
+ /// explicitly enabled or disabled using boost decorators
+ ///
+ /// Test aims:
+ /// - Ensure that the decorators are correctly read and grouping is done correctly
+ ///
+ [Test]
+ public void TestsWithDecorators()
+ {
+ TestFramework expected = new TestFrameworkBuilder(Source, "Sample", 1).
+ TestSuite("Suite1", 2, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 11)).
+ TestCase("MyBoost_Test1", 65536, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 12)).
+ TestCase("MyBoost_Test2", 65537, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 16), null, false).
+ TestCase("MyBoost_Test3", 65538, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 20)).
+ TestCase("MyBoost_Test4", 65539, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 24), null, false).
+ EndSuite().
+ TestCase("MyBoost_Test5", 65540, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 30)).
+ TestCase("MyBoost_Test6", 65541, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 34), null, false).
+ TestCase("MyBoost_Test7", 65542, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 38)).
+ TestCase("MyBoost_Test8", 65543, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 42), null, false).
+ Build();
+
+ Compare("BoostTestAdapterNunit.Resources.ListContentDOT.test_list_content.gv", expected);
+ }
+
+ ///
+ /// Assert that: It is possible to deserialize --list_content=DOT output consisting of a BOOST_DATA_TEST_CASE
+ ///
+ [Test]
+ public void DeserializeBoostDataTestCase()
+ {
+ TestFramework expected = new TestFrameworkBuilder(Source, "DataTestCaseExample", 1).
+ TestSuite("BoostUnitTest", 2, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 10)).
+ TestCase("_0", 65536, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 10)).
+ TestCase("_1", 65537, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 10)).
+ TestCase("_2", 65538, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 10)).
+ TestCase("_3", 65539, new SourceFileInfo(@"c:\boostunittest\boostunittestsample.cpp", 10)).
+ EndSuite().
+ Build();
+
+ Compare("BoostTestAdapterNunit.Resources.ListContentDOT.boost_data_test_case.gv", expected);
+ }
+ }
}
\ No newline at end of file
diff --git a/BoostTestAdapterNunit/Resources/ListContentDOT/boost_data_test_case.gv b/BoostTestAdapterNunit/Resources/ListContentDOT/boost_data_test_case.gv
new file mode 100644
index 0000000..1a8a681
--- /dev/null
+++ b/BoostTestAdapterNunit/Resources/ListContentDOT/boost_data_test_case.gv
@@ -0,0 +1,17 @@
+digraph G {rankdir=LR;
+tu1[shape=ellipse,peripheries=2,fontname=Helvetica,color=green,label="DataTestCaseExample"];
+{
+tu2[shape=Mrecord,fontname=Helvetica,color=green,label="BoostUnitTest|c:\boostunittest\boostunittestsample.cpp(10)"];
+tu1 -> tu2;
+{
+tu65536[shape=Mrecord,fontname=Helvetica,color=green,label="_0|c:\boostunittest\boostunittestsample.cpp(10)"];
+tu2 -> tu65536;
+tu65537[shape=Mrecord,fontname=Helvetica,color=green,label="_1|c:\boostunittest\boostunittestsample.cpp(10)"];
+tu2 -> tu65537;
+tu65538[shape=Mrecord,fontname=Helvetica,color=green,label="_2|c:\boostunittest\boostunittestsample.cpp(10)"];
+tu2 -> tu65538;
+tu65539[shape=Mrecord,fontname=Helvetica,color=green,label="_3|c:\boostunittest\boostunittestsample.cpp(10)"];
+tu2 -> tu65539;
+}
+}
+}
diff --git a/BoostTestAdapterNunit/Utility/BoostTestLocator.cs b/BoostTestAdapterNunit/Utility/BoostTestLocator.cs
new file mode 100644
index 0000000..dcc0a9b
--- /dev/null
+++ b/BoostTestAdapterNunit/Utility/BoostTestLocator.cs
@@ -0,0 +1,105 @@
+// (C) Copyright ETAS 2015.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+using BoostTestAdapter.Boost.Test;
+
+namespace BoostTestAdapterNunit.Utility
+{
+ ///
+ /// ITestVisitor implementation which looks up test units based on their qualified name.
+ ///
+ public class BoostTestLocator : ITestVisitor
+ {
+ ///
+ /// Constructor
+ ///
+ /// The test unit's fully qualified name to locate
+ private BoostTestLocator(string fullyQualifiedName)
+ {
+ this.FullyQualifiedName = fullyQualifiedName;
+ }
+
+ ///
+ /// The fully qualified name of the test unit to locate
+ ///
+ public string FullyQualifiedName { get; private set; }
+
+ ///
+ /// The resultant test unit
+ ///
+ public TestUnit Unit { get; private set; }
+
+ #region ITestVisitor
+
+ public void Visit(TestCase testCase)
+ {
+ Check(testCase);
+ }
+
+ public void Visit(TestSuite testSuite)
+ {
+ if (!Check(testSuite))
+ {
+ foreach (TestUnit child in testSuite.Children)
+ {
+ child.Apply(this);
+
+ if (this.Unit != null)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ #endregion
+
+ ///
+ /// Checks if the provided test unit is the one which was requested for location
+ ///
+ /// The test unit to test
+ /// true if the provided test unit was the one requested for location; false otherwise
+ private bool Check(TestUnit unit)
+ {
+ bool match = (unit.FullyQualifiedName == this.FullyQualifiedName);
+
+ if (match)
+ {
+ this.Unit = unit;
+ }
+
+ return match;
+ }
+
+ ///
+ /// Locates the test unit with the specified fully qualified name from the provided test framework
+ ///
+ /// The framework from which to locate the test unit
+ /// The test unit's fully qualified name to locate
+ /// The located test unit or null if it was not found
+ public static TestUnit Locate(TestFramework root, string fullyQualifiedName)
+ {
+ return Locate(root?.MasterTestSuite, fullyQualifiedName);
+ }
+
+ ///
+ /// Locates the test unit with the specified fully qualified name from the provided root
+ ///
+ /// The root test unit from which to locate the test unit
+ /// The test unit's fully qualified name to locate
+ /// The located test unit or null if it was not found
+ public static TestUnit Locate(TestUnit root, string fullyQualifiedName)
+ {
+ if (root == null)
+ {
+ return null;
+ }
+
+ var locator = new BoostTestLocator(fullyQualifiedName);
+ root.Apply(locator);
+ return locator.Unit;
+ }
+ }
+}
diff --git a/BoostTestAdapterNunit/VSDiscoveryVisitorTest.cs b/BoostTestAdapterNunit/VSDiscoveryVisitorTest.cs
new file mode 100644
index 0000000..4b4ae0f
--- /dev/null
+++ b/BoostTestAdapterNunit/VSDiscoveryVisitorTest.cs
@@ -0,0 +1,137 @@
+// (C) Copyright ETAS 2015.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+using System;
+using NUnit.Framework;
+
+using System.Linq;
+using System.Collections.Generic;
+
+using BoostTestAdapter;
+using BoostTestAdapter.Boost.Test;
+using BoostTestAdapter.Discoverers;
+using BoostTestAdapter.Utility;
+using BoostTestAdapter.Utility.VisualStudio;
+
+using BoostTestCase = BoostTestAdapter.Boost.Test.TestCase;
+using VSTestCase = Microsoft.VisualStudio.TestPlatform.ObjectModel.TestCase;
+
+using BoostTestAdapterNunit.Utility;
+
+namespace BoostTestAdapterNunit
+{
+ [TestFixture]
+ internal class VSDiscoveryVisitorTest
+ {
+ ///
+ /// Default test source file
+ ///
+ private const string _sourceFile = @"c:\test.cpp";
+
+ ///
+ /// Creates a 'default' TestFrameworkBuilder instance for this TestFixture
+ ///
+ /// A 'default' TestFrameworkBuilder instance
+ private static TestFrameworkBuilder CreateFrameworkBuilder()
+ {
+ return new TestFrameworkBuilder("test.exe", "MyTest", 1);
+ }
+
+ ///
+ /// Discovers all tests cases enumerated within the provided framework
+ ///
+ /// The framework to discover tests from
+ /// An enumeration of all the discovered tests
+ private static IEnumerable Discover(TestFramework framework)
+ {
+ var sink = new DefaultTestCaseDiscoverySink();
+ var visitor = new VSDiscoveryVisitor(framework.Source, sink);
+ framework.MasterTestSuite.Apply(visitor);
+ return sink.Tests;
+ }
+
+ ///
+ /// Locates the test case with the provided fully qualified name from the provided framework
+ ///
+ /// The framework to locate the test case from
+ /// The test case fully qualified name to locate
+ /// The located TestCase instance or null if it is not found
+ private static BoostTestCase LocateTestCase(TestFramework framework, string fullyQualifiedName)
+ {
+ var unit = BoostTestLocator.Locate(framework, fullyQualifiedName);
+ return unit as BoostTestCase;
+ }
+
+ ///
+ /// Asserts 'common' test case details between the test case encoded in the framework and the respective Visual Studio test case
+ ///
+ /// The Visual Studio TestCase instance to verify
+ /// The framework to locate the test case from
+ /// The test case fully qualified name to locate
+ private static void AssertCommonTestCaseDetails(VSTestCase test, TestFramework framework, string fullyQualifiedName)
+ {
+ Assert.That(framework, Is.Not.Null);
+
+ var expected = LocateTestCase(framework, fullyQualifiedName);
+
+ Assert.That(expected, Is.Not.Null);
+
+ AssertCommonTestCaseDetails(test, expected, framework.Source);
+ }
+
+ ///
+ /// Asserts 'common' test case details between the Boost test case and the respective Visual Studio test case
+ ///
+ /// The Visual Studio TestCase instance to verify
+ /// The Boost TestCase to which test should match to
+ /// The source from which the Boost Test case was discovered from
+ private static void AssertCommonTestCaseDetails(VSTestCase test, BoostTestCase expected, string source)
+ {
+ Assert.That(expected, Is.Not.Null);
+ Assert.That(test, Is.Not.Null);
+
+ Assert.That(test.Source, Is.EqualTo(source));
+ Assert.That(test.ExecutorUri, Is.EqualTo(new Uri(BoostTestExecutor.ExecutorUriString)));
+ Assert.That(test.FullyQualifiedName, Is.EqualTo(expected.FullyQualifiedName));
+
+ if (expected.Source != null)
+ {
+ Assert.That(test.CodeFilePath, Is.EqualTo(expected.Source.File));
+ Assert.That(test.LineNumber, Is.EqualTo(expected.Source.LineNumber));
+ }
+ }
+
+ ///
+ /// Assert that: Test display names for BOOST_DATA_TEST_CASE instances are different
+ /// than the names determined by the Boost.Test framework
+ ///
+ [Test]
+ public void BoostDataTestCase()
+ {
+ TestFramework framework = CreateFrameworkBuilder().
+ TestSuite("DataTestCase", 2, new SourceFileInfo(_sourceFile, 10)).
+ TestCase("_0", 65536, new SourceFileInfo(_sourceFile, 10)).
+ TestCase("_1", 65537, new SourceFileInfo(_sourceFile, 10)).
+ TestCase("_2", 65538, new SourceFileInfo(_sourceFile, 10)).
+ TestCase("_3", 65539, new SourceFileInfo(_sourceFile, 10)).
+ EndSuite().
+ Build();
+
+ var tests = Discover(framework).OrderBy(test => test.FullyQualifiedName).ToList();
+
+ Assert.That(tests.Count, Is.EqualTo(4));
+
+ AssertCommonTestCaseDetails(tests[0], framework, "DataTestCase/_0");
+ AssertCommonTestCaseDetails(tests[1], framework, "DataTestCase/_1");
+ AssertCommonTestCaseDetails(tests[2], framework, "DataTestCase/_2");
+ AssertCommonTestCaseDetails(tests[3], framework, "DataTestCase/_3");
+
+ Assert.That(tests[0].DisplayName, Is.Not.EqualTo(LocateTestCase(framework, "DataTestCase/_0").Name));
+ Assert.That(tests[1].DisplayName, Is.Not.EqualTo(LocateTestCase(framework, "DataTestCase/_1").Name));
+ Assert.That(tests[2].DisplayName, Is.Not.EqualTo(LocateTestCase(framework, "DataTestCase/_2").Name));
+ Assert.That(tests[3].DisplayName, Is.Not.EqualTo(LocateTestCase(framework, "DataTestCase/_3").Name));
+ }
+ }
+}