/// <summary>
        /// Asserts general test case details
        /// </summary>
        /// <param name="testCase">The test case to test</param>
        /// <param name="qualifiedName">The expected qualified name of the test case</param>
        /// <param name="sourceFile">The expected source file path of the test case or null if not available</param>
        /// <param name="lineNumber">The expected line number of the test case or -1 if not available</param>
        private void AssertTestDetails(TestCase testCase, QualifiedNameBuilder qualifiedName, string sourceFile, int lineNumber)
        {
            Assert.That(testCase.DisplayName, Is.EqualTo(qualifiedName.Peek()));
            Assert.That(testCase.FullyQualifiedName, Is.EqualTo(qualifiedName.ToString()));

            string suite = qualifiedName.Pop().ToString();

            if (!string.IsNullOrEmpty(suite))
            {
                AssertTestSuite(testCase, suite);
            }
            else
            {
                // The default 'Master Test Suite' trait value should be available
                AssertTrait(testCase, VSTestModel.TestSuiteTrait);
            }

            if (!string.IsNullOrEmpty(sourceFile))
            {
                Assert.That(testCase.CodeFilePath, Is.EqualTo(sourceFile));
            }

            if (lineNumber > -1)
            {
                Assert.That(testCase.LineNumber, Is.EqualTo(lineNumber));
            }
        }
        /// <summary>
        /// Parses a TestCase log node.
        /// </summary>
        /// <param name="node">The TestCase Xml node to parse.</param>
        /// <param name="path">The QualifiedNameBuilder which hosts the current fully qualified path.</param>
        /// <param name="collection">The TestResultCollection which will host the result.</param>
        private static void ParseTestCaseLog(XmlNode node, QualifiedNameBuilder path, TestResultCollection collection)
        {
            // Temporarily push TestCase on TestSuite name builder to acquire the fully qualified name of the TestCase
            path.Push(node.Attributes[Xml.Name].Value);

            // Acquire result record of this TestCase
            TestResult result = collection[path.ToString()];
            if (result == null)
            {
                result = new TestResult(collection);
                collection[path.ToString()] = result;
            }

            // Reset path to original value
            path.Pop();

            XmlNode testingTime = node.SelectSingleNode(Xml.TestingTime);

            if (testingTime != null)
            {
                // Boost test testing time is listed in microseconds
                result.Duration = ulong.Parse(testingTime.InnerText, CultureInfo.InvariantCulture);
            }

            ParseTestCaseLogEntries(node.ChildNodes, result);
        }
        /// <summary>
        /// Asserts general test properties
        /// </summary>
        /// <param name="tests">The enumeration of discovered tests</param>
        /// <param name="qualifiedName">The qualified test name which is to be tested</param>
        /// <param name="source">The source from which the test should have been discovered</param>
        /// <param name="info">Optional source file information related to the test under question</param>
        private void AssertVSTestCaseProperties(IEnumerable<VSTestCase> tests, QualifiedNameBuilder qualifiedName, string source, SourceFileInfo info)
        {
            VSTestCase test = tests.FirstOrDefault((_test) => (_test.FullyQualifiedName == qualifiedName.ToString()));

            Assert.That(test, Is.Not.Null);
            Assert.That(test.DisplayName, Is.EqualTo(qualifiedName.Peek()));
            Assert.That(test.Source, Is.EqualTo(source));
            Assert.That(test.ExecutorUri, Is.EqualTo(BoostTestExecutor.ExecutorUri));

            if (info != null)
            {
                Assert.That(test.CodeFilePath, Is.EqualTo(info.File));
                Assert.That(test.LineNumber, Is.EqualTo(info.LineNumber));
            }

            Assert.That(test.Traits.Count(), Is.EqualTo(1));

            Trait trait = test.Traits.First();
            Assert.That(trait.Name, Is.EqualTo(VSTestModel.TestSuiteTrait));

            string suite = qualifiedName.Pop().ToString();
            if (string.IsNullOrEmpty(suite))
            {
                suite = qualifiedName.MasterTestSuite;
            }

            Assert.That(trait.Value, Is.EqualTo(suite));
        }
        public void CorrectTestsDiscoveryForFIXTURE_TEST_CASE()
        {
            using (DummySolution solution = new DummySolution(DefaultSource, "BoostFixtureTestCase.cpp"))
            {
                #region excercise

                /** The BoostFixtureTestCase.cpp file consists of 4 test cases: BoostUnitTest1, Fixturetest_case1, Fixturetest_case1 and Fixturetest_case1,
                 * BOOST_AUTO_TEST_SUITE -> Suit1
                 *                          -->BoostUnitTest1
                 *                          -->Fixturetest_case1
                 *                          -->Fixturetest_case2
                 *                       -> Master Suite
                 *                          -->Fixturetest_case3
                 */

                IList <TestCase> testList = DiscoverTests(solution);

                #endregion excercise

                #region verify

                AssertTestDetails(testList[0], QualifiedNameBuilder.FromString("Suit1/BoostUnitTest1"));
                AssertTestDetails(testList[1], QualifiedNameBuilder.FromString("Suit1/Fixturetest_case1"));
                AssertTestDetails(testList[2], QualifiedNameBuilder.FromString("Suit1/Fixturetest_case2"));
                AssertTestDetails(testList[3], QualifiedNameBuilder.FromString("Fixturetest_case3"));

                #endregion verify
            }
        }
        public void MultilineBoostMacroDefinitions()
        {
            using (DummySolution solution = new DummySolution(DefaultSource, "BoostMultiLineDefinitions.cpp"))
            {
                IList <TestCase> testList = DiscoverTests(solution);

                AssertTestDetails(testList[0], QualifiedNameBuilder.FromString("AutoSuite/TestA"));
                AssertTestDetails(testList[1], QualifiedNameBuilder.FromString("AutoSuite/TestB"));
                AssertTestDetails(testList[2], QualifiedNameBuilder.FromString("AutoSuite/TestC"));
                AssertTestDetails(testList[3], QualifiedNameBuilder.FromString("AutoSuite/FixtureSuite/TestD"));
            }
        }
        public void BOOST_DATA_TEST_CASEDiscovery()
        {
            using (DummySolution solution = new DummySolution(DefaultSource, "BoostDataTestCase.cpp"))
            {
                IList <TestCase> testList = DiscoverTests(solution);

                Assert.That(testList.Count, Is.EqualTo(3));

                AssertTestDetails(testList[0], QualifiedNameBuilder.FromString("data_test_suite/data_1"));
                AssertTestDetails(testList[1], QualifiedNameBuilder.FromString("data_test_suite/data_2"));
                AssertTestDetails(testList[2], QualifiedNameBuilder.FromString("data_3"));
            }
        }
        /// <summary>
        /// Factory method which creates a QualifiedNameBuilder
        /// from an already existing qualified name string.
        /// </summary>
        /// <param name="masterSuite">The local name of the master test suite</param>
        /// <param name="name">The qualified name</param>
        /// <returns>A QualifiedNameBuilder from the provided string.</returns>
        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);
        }
        public void CorrectDiscoveryGenericBoostTests()
        {
            using (DummySolution solution = new DummySolution(DefaultSource, "BoostUnitTestSample.cpp"))
            {
                #region excercise

                IList <TestCase> tests = DiscoverTests(solution);

                #endregion excercise

                #region verify

                AssertTestDetails(tests.Last(), QualifiedNameBuilder.FromString("my_test<char>"), solution.SourceFileResourcePaths.First().Path, 33);

                #endregion verify
            }
        }
        /// <summary>
        /// Creates a new TestCase object.
        /// </summary>
        /// <param name="sourceExe">Name of the project executable</param>
        /// <param name="sourceInfo">.cpp file path and TestCase line number</param>
        /// <param name="suite">The suite in which testcase is present</param>
        /// <param name="testCaseName">Name of the testcase</param>
        /// <param name="isEnabled">The enabling status of the testcase</param>
        /// <returns>The created TestCase object</returns>
        public static TestCase CreateTestCase(string sourceExe, SourceFileInfo sourceInfo, QualifiedNameBuilder suite, string testCaseName, bool isEnabled = true)
        {
            suite.Push(testCaseName);

            string qualifiedName = suite.ToString();

            suite.Pop();

            var testCase = new TestCase(qualifiedName, BoostTestExecutor.ExecutorUri, sourceExe)
            {
                CodeFilePath = sourceInfo.File,
                LineNumber = sourceInfo.LineNumber,
                DisplayName = testCaseName,
            };

            GroupViaTraits(suite.ToString(), testCase, isEnabled);

            return testCase;
        }
        public void CorrectTestsDiscoveryForFIXTURE_TEST_SUITE()
        {
            using (DummySolution solution = new DummySolution(DefaultSource, "BoostFixtureTestSuite.cpp"))
            {
                #region exercise

                /** The BoostFixtureSuiteTest.cpp file consists of 3 test cases: FixtureTest1, FixtureTest2 and BoostTest,
                 * BOOST_FIXTURE_TEST_SUITE -> FixtureSuite1
                 *                             -->BoostTest1
                 *                             -->BoostTest2
                 *                          -> Master Suite
                 *                             -->BoostTest3
                 * BOOST_FIXTURE_TEST_SUITE -> FixtureSuite2
                 *                             -->Fixturetest_case1
                 *                             -->TemplatedTest<int>  (BOOST_AUTO_TEST_CASE_TEMPLATE)
                 *                             -->TemplatedTest<long> (BOOST_AUTO_TEST_CASE_TEMPLATE)
                 *                             -->TemplatedTest<char> (BOOST_AUTO_TEST_CASE_TEMPLATE)
                 */

                IList <TestCase> testList = DiscoverTests(solution);

                #endregion exercise

                #region verification

                AssertTestDetails(testList[0], QualifiedNameBuilder.FromString("FixtureSuite1/BoostTest1"));
                AssertTestDetails(testList[1], QualifiedNameBuilder.FromString("FixtureSuite1/BoostTest2"));
                AssertTestDetails(testList[2], QualifiedNameBuilder.FromString("BoostTest3"));
                AssertTestDetails(testList[3], QualifiedNameBuilder.FromString("FixtureSuite2/Fixturetest_case1"));
                AssertTestDetails(testList[4], QualifiedNameBuilder.FromString("FixtureSuite2/TemplatedTest<int>"));
                AssertTestDetails(testList[5], QualifiedNameBuilder.FromString("FixtureSuite2/TemplatedTest<long>"));
                AssertTestDetails(testList[6], QualifiedNameBuilder.FromString("FixtureSuite2/TemplatedTest<char>"));

                #endregion verification
            }
        }
        /// <summary>
        /// Given a fully qualified name of a <b>test case</b>, generates the respective test unit hierarchy.
        /// </summary>
        /// <param name="fullyQualifiedName">The fully qualified name of the <b>test case</b></param>
        /// <returns>The test case hierarchy represented by the provided fully qualified name</returns>
        /// <remarks>The parameter 'fullyQualifiedName' will be modified and emptied in due process</remarks>
        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<string> hierarchy = new Stack<string>();
            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;
        }
        /// <summary>
        /// Factory method which creates a QualifiedNameBuilder
        /// from an already existing qualified name string.
        /// </summary>
        /// <param name="masterSuite">The local name of the master test suite</param>
        /// <param name="name">The qualified name</param>
        /// <returns>A QualifiedNameBuilder from the provided string.</returns>
        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;
        }
            /// <summary>
            /// Constructor
            /// </summary>
            /// <param name="source">The source test module which contains the discovered tests</param>
            /// <param name="sink">The ITestCaseDiscoverySink which will have tests registered with</param>
            public BoostTestCaseDiscoverer(string source, ITestCaseDiscoverySink sink)
            {
                Source = source;
                Sink = sink;

                TestSuite = new QualifiedNameBuilder();
            }
 /// <summary>
 /// Asserts general test case details
 /// </summary>
 /// <param name="testCase">The test case to test</param>
 /// <param name="qualifiedName">The expected qualified name of the test case</param>
 private void AssertTestDetails(TestCase testCase, QualifiedNameBuilder qualifiedName)
 {
     AssertTestDetails(testCase, qualifiedName, null, -1);
 }
 /// <summary>
 /// Parses child TestUnit nodes.
 /// </summary>
 /// <param name="nodes">The collection of Xml nodes which are valid TestUnit nodes.</param>
 /// <param name="path">The QualifiedNameBuilder which hosts the current fully qualified path.</param>
 /// <param name="collection">The TestResultCollection which will host the result.</param>
 private static void ParseTestUnitsLog(XmlNodeList nodes, QualifiedNameBuilder path, TestResultCollection collection)
 {
     foreach (XmlNode child in nodes)
     {
         if (child.NodeType == XmlNodeType.Element)
         {
             if (child.Name == Xml.TestSuite)
             {
                 ParseTestSuiteLog(child, path, collection);
             }
             else if (child.Name == Xml.TestCase)
             {
                 ParseTestCaseLog(child, path, collection);
             }
         }
     }
 }
        /// <summary>
        /// Parses a TestSuite log node.
        /// </summary>
        /// <param name="node">The TestSuite Xml node to parse.</param>
        /// <param name="path">The QualifiedNameBuilder which hosts the current fully qualified path.</param>
        /// <param name="collection">The TestResultCollection which will host the result.</param>
        private static void ParseTestSuiteLog(XmlNode node, QualifiedNameBuilder path, TestResultCollection collection)
        {
            path.Push(node.Attributes[Xml.Name].Value);

            ParseTestUnitsLog(node.ChildNodes, path, collection);

            path.Pop();
        }
        /// <summary>
        /// Discovers Boost Test from the provided C++ source file. Notifies test discovery via the provided discoverySink.
        /// </summary>
        /// <param name="cppSourceFile">The C++ source file to scan for Boost Tests</param>
        /// <param name="source">The associated test source EXE</param>
        /// <param name="discoverySink">The discoverySink to which identified tests will be notified to</param>
        private static void DiscoverBoostTests(CppSourceFile cppSourceFile, string source, ITestCaseDiscoverySink discoverySink)
        {
            string[] code = cppSourceFile.SourceCode.TrimEnd(new[] { ' ', '\n', '\r' }).Split('\n');

            SourceFileInfo sourceInfo = new SourceFileInfo(cppSourceFile.FileName, 0);

            QualifiedNameBuilder suite = new QualifiedNameBuilder();
            // Push the equivalent of the Master Test Suite
            suite.Push(QualifiedNameBuilder.DefaultMasterTestSuiteName);

            var templateLists = new Dictionary<string, List<string>>();

            for (sourceInfo.LineNumber = 1; sourceInfo.LineNumber <= code.Length; ++sourceInfo.LineNumber)
            {
                string line = code[sourceInfo.LineNumber - 1];

                string[] splitMacro = SplitMacro(line);
                string desiredMacro = splitMacro[0].Trim();

                // serge: BOOST multiline test macros are supported now
                /*
                 * Currently the below is not able to handle BOOST UTF signatures spread over multiple lines.
                 */
                switch (desiredMacro)
                {
                    case Constants.TypedefListIdentifier:
                    case Constants.TypedefMplListIdentifier:
                    case Constants.TypedefBoostMplListIdentifier:
                        {
                            var dataTypes = new List<string>();
                            int i;

                            for (i = 1; i < splitMacro.Length - 2; ++i)
                            {
                                dataTypes.Add(splitMacro[i].Trim());
                            }

                            templateLists.Add(splitMacro[i].Trim(), dataTypes);
                            break;
                        }

                    case Constants.TestCaseTemplateIdentifier:
                        {
                            int newLineNumber = ScrollLines(sourceInfo.LineNumber, code, ref line);
                            if (sourceInfo.LineNumber != newLineNumber)
                            {
                                // recalc splitMacro
                                splitMacro = SplitMacro(line);
                                sourceInfo.LineNumber = newLineNumber;
                            }

                            string listName = splitMacro[3].Trim();
                            //third parameter is the corresponding boost::mpl::list name

                            if (templateLists.ContainsKey(listName))
                            {
                                foreach (var dataType in templateLists[listName])
                                {
                                    string testCaseName = splitMacro[1].Trim();
                                    //first parameter is the test case name
                                    string testCaseNameWithDataType = testCaseName + "<" + dataType + ">";

                                    var testCase = TestCaseUtils.CreateTestCase(source, sourceInfo, suite, testCaseNameWithDataType);

                                    TestCaseUtils.AddTestCase(testCase, discoverySink);
                                }
                            }
                            break;
                        }

                    case Constants.FixtureTestSuiteIdentifier:
                    case Constants.AutoTestSuiteIdentifier:
                        {
                            int newLineNumber = ScrollLines(sourceInfo.LineNumber, code, ref line);
                            if (sourceInfo.LineNumber != newLineNumber)
                            {
                                // recalc splitMacro
                                splitMacro = SplitMacro(line);
                                sourceInfo.LineNumber = newLineNumber;
                            }

                            suite.Push(splitMacro[1].Trim());
                            break;
                        }

                    case Constants.FixtureTestCaseIdentifier:
                    case Constants.AutoTestCaseIdentifier:
                        {
                            int newLineNumber = ScrollLines(sourceInfo.LineNumber, code, ref line);
                            if (sourceInfo.LineNumber != newLineNumber)
                            {
                                // recalc splitMacro
                                splitMacro = SplitMacro(line);
                                sourceInfo.LineNumber = newLineNumber;
                            }

                            string testCaseName = splitMacro[1].Trim();

                            var testCase = TestCaseUtils.CreateTestCase(source, sourceInfo, suite, testCaseName);

                            TestCaseUtils.AddTestCase(testCase, discoverySink);
                            break;
                        }

                    case Constants.AutoTestSuiteEndIdentifier:
                        {
                            suite.Pop();
                            break;
                        }
                    default:
                        break;
                }
            }
        }
        /// <summary>
        /// Parses a TestCase node.
        /// </summary>
        /// <param name="node">The XPathNavigator pointing to a TestCase node.</param>
        /// <param name="parent">The parent TestSuite to which TestUnits are attached to.</param>
        /// <param name="collection">The TestResultCollection which will host the result.</param>
        private static void ParseTestCaseReport(XPathNavigator node, TestSuite parent, TestResultCollection collection)
        {
            QualifiedNameBuilder fullname = new QualifiedNameBuilder(parent);
            fullname.Push(node.GetAttribute(Xml.Name, string.Empty));

            TestCase testCase = null;

            // If the test is already available, reuse it
            TestResult current = collection[fullname.ToString()];
            if (current != null)
            {
                testCase = current.Unit as TestCase;
            }

            // Else construct and add it to the appropriate parent
            if (testCase == null)
            {
                testCase = new TestCase(fullname.Peek(), parent);
            }

            TestResult result = ParseTestResult(node, testCase, collection);

            // Aggregate results. Common use-case in BOOST_DATA_TEST_CASE.
            collection[fullname.ToString()] = Aggregate(result, current);
        }
        /// <summary>
        /// Based on the parent test unit hierarchy and the provided test unit, generates a fully-qualified test case symbol name for the provided test unit.
        /// </summary>
        /// <param name="suiteNameBuilder">The parent test unit hierarchy.</param>
        /// <param name="unitName">The test unit.</param>
        /// <returns>The fully-qualified <b>test case</b> symbol name for the provided test unit.</returns>
        private static string BuildTestCaseSymbolName(QualifiedNameBuilder suiteNameBuilder, string unitName)
        {
            var fullyQualifiedName = unitName;

            string testUnitLocator = suiteNameBuilder.ToString();

            // If the test is located within a test suite, qualify accordingly
            if (!string.IsNullOrEmpty(testUnitLocator))
            { 
                fullyQualifiedName = string.Format(
                    CultureInfo.InvariantCulture,
                    "{0}::{1}",
                    testUnitLocator.Replace("/", "::"),
                    unitName
                );
            }

            var symbolName = string.Format(
                CultureInfo.InvariantCulture,
                "{0}::test_method",
                fullyQualifiedName
            );
            
            return symbolName;
        }
 /// <summary>
 /// Asserts general test case details
 /// </summary>
 /// <param name="testCase">The test case to test</param>
 /// <param name="qualifiedName">The expected qualified name of the test case</param>
 private void AssertTestDetails(TestCase testCase, QualifiedNameBuilder qualifiedName)
 {
     AssertTestDetails(testCase, qualifiedName, null, -1);
 }
        /// <summary>
        /// Searches in a list of SymbolInfo the one that identifies a Test.
        /// </summary>
        /// <param name="suiteNameBuilder">Qualified name builder.</param>
        /// <param name="unitName">The name of the unit to be searched.</param>
        /// <param name="syms">The list of the symbols.</param>
        /// <returns>A SymbolInfo if <paramref name="unitName"/> is a test method.</returns>
        private static SymbolInfo GetTestSymbol(QualifiedNameBuilder suiteNameBuilder, string unitName, IEnumerable<SymbolInfo> syms)
        {
            try
            {
                var fullyQualifiedName = unitName;

                if (!string.IsNullOrEmpty(suiteNameBuilder.ToString()))
                    fullyQualifiedName = string.Format(
                        CultureInfo.InvariantCulture,
                        "{0}::{1}",
                        suiteNameBuilder.ToString().Replace("/", "::"),
                        unitName
                    );

                var symbolName = string.Format(
                    CultureInfo.InvariantCulture,
                    "{0}::test_method",
                    fullyQualifiedName
                );

                return syms.FirstOrDefault(s => s.Name == symbolName);
            }
            catch (Exception)
            {
                throw;
            }
        }
        public void DiscoverTests(IEnumerable<string> sources, IDiscoveryContext discoveryContext, IMessageLogger logger, ITestCaseDiscoverySink discoverySink)
        {
            Code.Require(sources, "sources");
            Code.Require(discoverySink, "discoverySink");

            BoostTestAdapterSettings settings = BoostTestAdapterSettingsProvider.GetSettings(discoveryContext);
            _listContentHelper.Timeout = settings.DiscoveryTimeoutMilliseconds;

            foreach (var source in sources)
            {
                try
                {
                    var output = _listContentHelper.GetListContentOutput(source);

                    using (var dbgHelp = _listContentHelper.CreateDebugHelper(source))
                    {
                        QualifiedNameBuilder suiteNameBuilder = new QualifiedNameBuilder();
                        suiteNameBuilder.Push(QualifiedNameBuilder.DefaultMasterTestSuiteName);

                        var previousLineIndentation = -1;
                        var lines = output.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                        foreach (var l in lines)
                        {
                            var unitName = l.Trim();
                            if (unitName.EndsWith("*", StringComparison.Ordinal))
                                unitName = unitName.Substring(0, unitName.Length - 1);

                            var currentLineIndentation = l.TrimEnd().LastIndexOf(' ') + 1;

                            // pop levels from the name builder to reach the current one
                            while (currentLineIndentation <= previousLineIndentation)
                            {
                                suiteNameBuilder.Pop();
                                previousLineIndentation -= 4;
                            }

                            // Retrieve all the symbols that contains <unitname> in their name.
                            // If no symbols can be retrieved, we skip the current unitName because
                            // we cannot assume what kind of unit (test or suit) it is.
                            IEnumerable<SymbolInfo> syms;
                            if (!dbgHelp.LookupSymbol(unitName, out syms))
                                continue;

                            // Check if the unit is a Test or a Suite.
                            var testSymbol = GetTestSymbol(suiteNameBuilder, unitName, syms);
                            if (testSymbol == null)
                            {
                                // Suite
                                suiteNameBuilder.Push(unitName);

                                previousLineIndentation = currentLineIndentation;
                            }
                            else
                            {
                                // Test
                                var isEnabled = l.Contains("*");
                                var testCase = TestCaseUtils.CreateTestCase(
                                    source,
                                    new SourceFileInfo(testSymbol.FileName, testSymbol.LineNumber),
                                    suiteNameBuilder,
                                    unitName,
                                    isEnabled);
                                TestCaseUtils.AddTestCase(testCase, discoverySink);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.Error("Exception caught while discovering tests for {0} ({1} - {2})", source, ex.Message, ex.HResult);
                    Logger.Error(ex.StackTrace);
                }
            }
        }
        /// <summary>
        /// Asserts general test details for the test with the requested fully qualified name
        /// </summary>
        /// <param name="tests">The discovered test case enumeration</param>
        /// <param name="fqn">The fully qualified name of the test case to test</param>
        /// <param name="source">The expected test case source</param>
        /// <returns>The test case which has been tested</returns>
        private VSTestCase AssertTestDetails(IEnumerable<VSTestCase> tests, QualifiedNameBuilder fqn, string source)
        {
            VSTestCase vsTest = tests.FirstOrDefault(test => test.FullyQualifiedName == fqn.ToString());

            Assert.That(vsTest, Is.Not.Null);
            AssertTestDetails(vsTest, fqn, source);

            return vsTest;
        }
        /// <summary>
        /// Asserts general test case details
        /// </summary>
        /// <param name="testCase">The test case to test</param>
        /// <param name="qualifiedName">The expected qualified name of the test case</param>
        /// <param name="sourceFile">The expected source file path of the test case or null if not available</param>
        /// <param name="lineNumber">The expected line number of the test case or -1 if not available</param>
        private void AssertTestDetails(TestCase testCase, QualifiedNameBuilder qualifiedName, string sourceFile, int lineNumber)
        {
            Assert.That(testCase.DisplayName, Is.EqualTo(qualifiedName.Peek()));
            Assert.That(testCase.FullyQualifiedName, Is.EqualTo(qualifiedName.ToString()));

            string suite = qualifiedName.Pop().ToString();
            if (!string.IsNullOrEmpty(suite))
            {
                AssertTestSuite(testCase, suite);
            }
            else
            {
                // The default 'Master Test Suite' trait value should be available
                AssertTrait(testCase, VSTestModel.TestSuiteTrait);
            }

            if (!string.IsNullOrEmpty(sourceFile))
            {
                Assert.That(testCase.CodeFilePath, Is.EqualTo(sourceFile));
            }

            if (lineNumber > -1)
            {
                Assert.That(testCase.LineNumber, Is.EqualTo(lineNumber));
            }
        }
        /// <summary>
        /// Asserts general test details for the provided test case
        /// </summary>
        /// <param name="vsTest">The test case to test</param>
        /// <param name="fqn">The expected test case fully qualified name</param>
        /// <param name="source">The expected test case source</param>
        private void AssertTestDetails(VSTestCase vsTest, QualifiedNameBuilder fqn, string source)
        {
            Assert.That(vsTest, Is.Not.Null);
            Assert.That(vsTest.DisplayName, Is.EqualTo(fqn.Peek()));
            Assert.That(vsTest.ExecutorUri, Is.EqualTo(BoostTestExecutor.ExecutorUri));
            Assert.That(vsTest.Source, Is.EqualTo(source));

            string suite = fqn.Pop().ToString();
            if (string.IsNullOrEmpty(suite))
            {
                suite = QualifiedNameBuilder.DefaultMasterTestSuiteName;
            }

            Assert.That(vsTest.Traits.Where((trait) => (trait.Name == VSTestModel.TestSuiteTrait) && (trait.Value == suite)).Count(), Is.EqualTo(1));
        }
        public void DiscoverTests(IEnumerable<string> sources, IDiscoveryContext discoveryContext, IMessageLogger logger, ITestCaseDiscoverySink discoverySink)
        {
            Code.Require(sources, "sources");
            Code.Require(discoverySink, "discoverySink");

            BoostTestAdapterSettings settings = BoostTestAdapterSettingsProvider.GetSettings(discoveryContext);
            _listContentHelper.Timeout = settings.DiscoveryTimeoutMilliseconds;

            foreach (var source in sources)
            {
                try
                {
                    var output = _listContentHelper.GetListContentOutput(source);

                    using (var dbgHelp = _listContentHelper.CreateDebugHelper(source))
                    {
                        QualifiedNameBuilder suiteNameBuilder = new QualifiedNameBuilder();
                        suiteNameBuilder.Push(QualifiedNameBuilder.DefaultMasterTestSuiteName);

                        var previousLineIndentation = -1;
                        var lines = output.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                        foreach (var l in lines)
                        {
                            var isEnabled = false;

                            // Sanitize test unit name
                            var unitName = l.Trim();
                            if (unitName.EndsWith("*", StringComparison.Ordinal))
                            {
                                unitName = unitName.Substring(0, unitName.Length - 1).TrimEnd();
                                isEnabled = true;
                            }

                            // Identify indentation level
                            var currentLineIndentation = 0;
                            while (char.IsWhiteSpace(l[currentLineIndentation]))
                            {
                                ++currentLineIndentation;
                            }

                            // Pop levels from the name builder to reach the current one
                            while (currentLineIndentation <= previousLineIndentation)
                            {
                                suiteNameBuilder.Pop();
                                previousLineIndentation -= _indentation;
                            }
                            
                            // Try to locate a test case symbol for the test unit. If one is not found, assume it is a test suite.
                            var testSymbol = dbgHelp.LookupSymbol(BuildTestCaseSymbolName(suiteNameBuilder, unitName));
                            if (testSymbol == null)
                            {
                                // Suite
                                suiteNameBuilder.Push(unitName);

                                previousLineIndentation = currentLineIndentation;
                            }
                            else
                            {
                                // Test
                                var testCase = TestCaseUtils.CreateTestCase(
                                    source,
                                    new SourceFileInfo(testSymbol.FileName, testSymbol.LineNumber),
                                    suiteNameBuilder,
                                    unitName,
                                    isEnabled);
                                TestCaseUtils.AddTestCase(testCase, discoverySink);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.Error("Exception caught while discovering tests for {0} ({1} - {2})", source, ex.Message, ex.HResult);
                    Logger.Error(ex.StackTrace);
                }
            }
        }
        private static void DiscoverBoostTests(CppSourceFile cppSourceFile, string source, ITestCaseDiscoverySink discoverySink)
        {
            string[] code = cppSourceFile.SourceCode.TrimEnd(new[] { ' ', '\n', '\r' }).Split('\n');

            SourceFileInfo sourceInfo = new SourceFileInfo(cppSourceFile.FileName, 0);

            QualifiedNameBuilder suite = new QualifiedNameBuilder();
            // Push the equivalent of the Master Test Suite
            suite.Push(QualifiedNameBuilder.DefaultMasterTestSuiteName);

            var templateLists = new Dictionary<string, IEnumerable<string>>();

            for (sourceInfo.LineNumber = 1; sourceInfo.LineNumber <= code.Length; ++sourceInfo.LineNumber)
            {
                string line = code[sourceInfo.LineNumber - 1];

                string[] splitMacro = SplitMacro(line);
                string desiredMacro = splitMacro[0].Trim();

                switch (desiredMacro)
                {
                    case Constants.TypedefListIdentifier:
                    case Constants.TypedefMplListIdentifier:
                    case Constants.TypedefBoostMplListIdentifier:
                        {
                            var templateList = ParseTemplateList(splitMacro);
                            templateLists.Add(templateList.Key, templateList.Value);
                            break;
                        }

                    case Constants.TestCaseTemplateIdentifier:
                        {
                            var templateTest = ParseTemplateTestCase(splitMacro, templateLists, sourceInfo, code, ref line);

                            foreach (string testCaseDataType in templateTest.Value)
                            {
                                string testCaseNameWithDataType = templateTest.Key + '<' + testCaseDataType + '>';
                                var testCase = TestCaseUtils.CreateTestCase(source, sourceInfo, suite, testCaseNameWithDataType);
                                TestCaseUtils.AddTestCase(testCase, discoverySink);
                            }
                            break;
                        }

                    case Constants.FixtureTestSuiteIdentifier:
                    case Constants.AutoTestSuiteIdentifier:
                        {
                            string suiteName = ParseBeginTestSuite(splitMacro, sourceInfo, code, ref line);
                            suite.Push(suiteName);
                            break;
                        }

                    case Constants.FixtureTestCaseIdentifier:
                    case Constants.AutoTestCaseIdentifier:
                    case Constants.DataTestCaseIdentifier:
                        {
                            string testCaseName = ParseTestCase(splitMacro, sourceInfo, code, ref line);
                            var testCase = TestCaseUtils.CreateTestCase(source, sourceInfo, suite, testCaseName);
                            TestCaseUtils.AddTestCase(testCase, discoverySink);
                            break;
                        }

                    case Constants.FixtureDataTestCaseIdentifier:
                        {
                            string testCaseName = ParseDataTestCaseF(splitMacro, sourceInfo, code, ref line);
                            var testCase = TestCaseUtils.CreateTestCase(source, sourceInfo, suite, testCaseName);
                            TestCaseUtils.AddTestCase(testCase, discoverySink);
                            break;
                        }

                    case Constants.AutoTestSuiteEndIdentifier:
                        {
                            suite.Pop();
                            break;
                        }
                    default:
                        break;
                }
            }
        }