/// <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));
        }
        /// <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;
        }
        /// <summary>
        /// Parse SourceFileInfo from the provided node.
        /// </summary>
        /// <param name="node">The Xml node which contains source file information.</param>
        /// <returns>A SourceFileInfo populated from the provided Xml node.</returns>
        private static SourceFileInfo ParseSourceInfo(XmlNode node)
        {
            SourceFileInfo info = null;

            XmlAttribute file = node.Attributes[Xml.File];
            if (file != null)
            {
                info = new SourceFileInfo(file.Value);
            }

            if (info != null)
            {
                XmlAttribute line = node.Attributes[Xml.Line];
                if (line != null)
                {
                    info.LineNumber = int.Parse(line.Value, CultureInfo.InvariantCulture);
                }
            }

            return info;
        }
        public void ReadXml(XmlReader reader)
        {
            base.ReadXmlAttributes(reader);

            string file = reader.GetAttribute(Xml.File);

            if (!string.IsNullOrEmpty(file))
            {
                this.Source = new SourceFileInfo(file);
                this.Source.LineNumber = int.Parse(reader.GetAttribute(Xml.Line), CultureInfo.InvariantCulture);
            }

            reader.MoveToElement();
            bool empty = reader.IsEmptyElement;
            reader.ReadStartElement(Xml.TestCase);

            if (!empty)
            {
                reader.ReadEndElement();
            }
        }
        /// <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>
 /// Constructor accepting a SourceFileInfo object
 /// </summary>
 /// <param name="source">Source file information related to this log message. May be null.</param>
 public LogEntryMemoryLeak(SourceFileInfo source)
     : base(source)
 {
 }
 /// <summary>
 /// Constructor accepting an exception detail message and a SourceFileInfo object
 /// </summary>
 /// <param name="detail">detail message of type string</param>
 /// <param name="source">Source file information related to this log message. May be null.</param>
 public LogEntryException(string detail, SourceFileInfo source)
     : base(source)
 {
     this.Detail = detail;
 }
        /// <summary>
        /// Parses the declaration of a templated test case
        /// </summary>
        /// <param name="splitMacro">The current source line split into tokens</param>
        /// <param name="definedTemplates">A collection of templated lists defined prior to this test case declaration/definition</param>
        /// <param name="sourceInfo">Source file and line information/param>
        /// <param name="code">The entire code split by line</param>
        /// <param name="line">The current source code line which is being evaluated</param>
        /// <returns>A tuple consisting of the test case name and the list of defined templated types</returns>
        private static KeyValuePair<string, IEnumerable<string>> ParseTemplateTestCase(string[] splitMacro, Dictionary<string, IEnumerable<string>> definedTemplates, SourceFileInfo sourceInfo, string[] code, ref string line)
        {
            splitMacro = ParseTestDeclaration(splitMacro, sourceInfo, code, ref line);

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

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

            IEnumerable<string> templatedDataTypes = Enumerable.Empty<string>();
            if (definedTemplates.ContainsKey(listName))
            {
                templatedDataTypes = definedTemplates[listName];
            }

            return new KeyValuePair<string, IEnumerable<string>>(testCaseName, templatedDataTypes);
        }
 /// <summary>
 /// Builds a new TestSuite. Starts a new context in which
 /// newly created TestUnits will be parented to this TestSuite.
 /// </summary>
 /// <param name="name">Test Suite Name</param>
 /// <param name="id">Test Suite Id</param>
 /// <param name="source">Test Suite source file debug information</param>
 /// <returns>this</returns>
 public TestFrameworkBuilder TestSuite(string name, int? id, SourceFileInfo source)
 {
     return this.TestSuite(name, id, source, true);
 }
 /// <summary>
 /// Builds a new TestCase.
 /// </summary>
 /// <param name="name">Test Case Name</param>
 /// <param name="id">Test Case Id</param>
 /// <param name="source">Test Case source file debug information</param>
 /// <param name="labels">Test Case labels</param>
 /// <returns>this</returns>
 public TestFrameworkBuilder TestCase(string name, int? id, SourceFileInfo source, IEnumerable<string> labels)
 {
     return this.TestCase(name, id, source, labels, true);
 }
        /// <summary>
        /// Builds a new TestCase.
        /// </summary>
        /// <param name="name">Test Case Name</param>
        /// <param name="id">Test Case Id</param>
        /// <param name="source">Test Case source file debug information</param>
        /// <param name="labels">Test Case labels</param>
        /// <returns>this</returns>
        public TestFrameworkBuilder TestCase(string name, int? id, SourceFileInfo source, IEnumerable<string> labels)
        {
            TestCase testCase = new TestCase(name, this.Parent);

            testCase.Id = id;
            testCase.Source = source;
            testCase.Labels = labels;

            return this;
        }
        /// <summary>
        /// Asserts test case details
        /// </summary>
        /// <param name="unit">The test case to test</param>
        /// <param name="id">The expected Id of the test case</param>
        /// <param name="info">The expected source file information of the test case</param>
        /// <param name="parent">The expected parent of the test case</param>
        private void AssertTestCase(TestUnit unit, int id, SourceFileInfo info, TestUnit parent)
        {
            AssertTestUnit(unit, typeof(TestCase), id, parent);

            TestCase test = ((TestCase) unit);

            Assert.That(test.Children, Is.Empty);

            SourceFileInfo unitInfo = test.Source;

            if (info == null)
            {
                Assert.That(unitInfo, Is.Null);
            }
            else
            {
                Assert.That(unitInfo.File, Is.EqualTo(info.File));
                Assert.That(unitInfo.LineNumber, Is.EqualTo(info.LineNumber));
            }
        }
 /// <summary>
 /// Parses the beginning declaration of a fixture or auto test case
 /// </summary>
 /// <param name="splitMacro">The current source line split into tokens</param>
 /// <param name="sourceInfo">Source file and line information/param>
 /// <param name="code">The entire code split by line</param>
 /// <param name="line">The current source code line which is being evaluated</param>
 /// <returns>The name of the test case</returns>
 private static string ParseTestCase(string[] splitMacro, SourceFileInfo sourceInfo, string[] code, ref string line)
 {
     splitMacro = ParseTestDeclaration(splitMacro, sourceInfo, code, ref line);
     return splitMacro[1].Trim();
 }
 /// <summary>
 /// Compares 2 SourceFileInfo for equivalence. Issues an assertion failure if leak information is not equivalent.
 /// </summary>
 /// <param name="lhs">The left-hand side SourceFileInfo instance</param>
 /// <param name="rhs">The right-hand side SourceFileInfo instance</param>
 private void AssertSourceInfoDetails(SourceFileInfo lhs, SourceFileInfo rhs)
 {
     if (lhs == null)
     {
         Assert.That(rhs, Is.Null);
     }
     else
     {
         Assert.That(lhs.File, Is.EqualTo(rhs.File));
         Assert.That(lhs.LineNumber, Is.EqualTo(rhs.LineNumber));
     }
 }
 /// <summary>
 /// Tests the provided LogEntryException's properties against the expected values
 /// </summary>
 /// <param name="entry">The LogEntryException to test</param>
 /// <param name="checkpointInfo">The expected source file information for the exception</param>
 /// <param name="checkpointMessage">The expected checkpoint message</param>
 private void AssertLogEntryExceptionDetails(LogEntryException entry, SourceFileInfo checkpointInfo,
     string checkpointMessage)
 {
     AssertSourceInfoDetails(checkpointInfo, entry.LastCheckpoint);
     Assert.That(entry.CheckpointDetail, Is.EqualTo(checkpointMessage));
 }
        /// <summary>
        /// Tests the provided LogEntry's general properties against the expected values
        /// </summary>
        /// <param name="entry">The LogEntryException to test</param>
        /// <param name="entryType">The expected log entry type</param>
        /// <param name="message">The expected log message</param>
        /// <param name="info">The expected source file information for the log entry</param>
        private void AssertLogEntryDetails(LogEntry entry, string entryType, string message, SourceFileInfo info)
        {
            Assert.That(entry.ToString(), Is.EqualTo(entryType));
            Assert.That(entry.Detail, Is.EqualTo(message));

            AssertSourceInfoDetails(entry.Source, info);
        }
 /// <summary>
 /// Constructor accepting a detail message and a SourceFileInfo object
 /// </summary>
 /// <param name="detail">detail message of type string</param>
 /// <param name="source">Source file information related to this log message. May be null.</param>
 public LogEntryWarning(string detail, SourceFileInfo source)
     : base(source)
 {
     this.Detail = detail;
 }
 /// <summary>
 /// Constructor accepting a detail message and a SourceFileInfo object
 /// </summary>
 /// <param name="detail">detail message of type string</param>
 /// <param name="source">Source file information related to this log message. May be null.</param>
 public LogEntryFatalError(string detail, SourceFileInfo source)
     : base(source)
 {
     this.Detail = detail;
 }
 /// <summary>
 /// Constructor accepting a detail message and a SourceFileInfo object
 /// </summary>
 /// <param name="detail">detail message of type string</param>
 /// <param name="source">Source file information related to this log message. May be null.</param>
 public LogEntryError(string detail, SourceFileInfo source)
     : this(detail, source, Enumerable.Empty<string>())
 {
 }
        /// <summary>
        /// Parses the <em>entire</em> test case/suite declaration
        /// </summary>
        /// <param name="splitMacro">The current source line split into tokens</param>
        /// <param name="sourceInfo">Source file and line information/param>
        /// <param name="code">The entire code split by line</param>
        /// <param name="line">The current source code line which is being evaluated</param>
        /// <returns>An array of string components which are of interest for test component evaluation</returns>
        private static string[] ParseTestDeclaration(string[] splitMacro, SourceFileInfo sourceInfo, string[] code, ref string line)
        {
            int newLineNumber = ScrollLines(sourceInfo.LineNumber, code, ref line);
            if (sourceInfo.LineNumber != newLineNumber)
            {
                // re calculate splitMacro
                splitMacro = SplitMacro(line);
                sourceInfo.LineNumber = newLineNumber;
            }

            return splitMacro;
        }
 /// <summary>
 /// Constructor accepting a SourceFileInfo
 /// </summary>
 /// <param name="source">Source file information related to this log message. May be null.</param>
 protected LogEntry(SourceFileInfo source)
     : this()
 {
     this.Source = source;
 }
 /// <summary>
 /// Constructor accepting a detail message, a SourceFileInfo object and error context frames
 /// </summary>
 /// <param name="detail">detail message of type string</param>
 /// <param name="source">Source file information related to this log message. May be null.</param>
 /// <param name="contextFrames">Error context frame information related to this error message. May be empty.</param>
 public LogEntryError(string detail, SourceFileInfo source, IEnumerable<string> contextFrames)
     : base(source)
 {
     this.Detail = detail;
     this.ContextFrames = contextFrames;
 }
 /// <summary>
 /// Builds a new TestCase.
 /// </summary>
 /// <param name="name">Test Case Name</param>
 /// <param name="id">Test Case Id</param>
 /// <param name="source">Test Case source file debug information</param>
 /// <returns>this</returns>
 public TestFrameworkBuilder TestCase(string name, int? id, SourceFileInfo source)
 {
     return this.TestCase(name, id, source, Enumerable.Empty<string>());
 }
        /// <summary>
        /// Builds a new TestCase.
        /// </summary>
        /// <param name="name">Test Case Name</param>
        /// <param name="id">Test Case Id</param>
        /// <param name="source">Test Case source file debug information</param>
        /// <returns>this</returns>
        public TestFrameworkBuilder TestCase(string name, int? id, SourceFileInfo source)
        {
            TestCase testCase = new TestCase(name, this.Parent);
            testCase.Id = id;
            testCase.Source = source;

            return this;
        }
        /// <summary>
        /// Builds a new TestCase.
        /// </summary>
        /// <param name="name">Test Case Name</param>
        /// <param name="id">Test Case Id</param>
        /// <param name="source">Test Case source file debug information</param>
        /// <param name="labels">Test Case labels</param>
        /// <param name="enabled">Test Case enabled or disabled</param>
        /// <returns>this</returns>
        public TestFrameworkBuilder TestCase(string name, int? id, SourceFileInfo source, IEnumerable<string> labels, bool enabled)
        {
            TestCase testCase = new TestCase(name, this.Parent);

            testCase.Id = id;
            testCase.Source = source;
            testCase.Labels = ((labels == null)? Enumerable.Empty<string>() : labels);
            testCase.DefaultEnabled = enabled;

            return this;
        }
 /// <summary>
 /// Verifies that both source file information are equal
 /// </summary>
 /// <param name="actual">The actual SourceFileInfo to be compared against</param>
 /// <param name="expected">The expected SourceFileInfo 'actual' should match</param>
 private static void VerifySoureFileInfo(SourceFileInfo actual, SourceFileInfo expected)
 {
     Assert.That(actual.File, Is.EqualTo(expected.File));
     Assert.That(actual.LineNumber, Is.EqualTo(expected.LineNumber));
 }
        public TestFrameworkBuilder TestSuite(string name, int? id, SourceFileInfo source, bool enabled)
        {
            TestSuite testSuite = new TestSuite(name, this.Parent);
            testSuite.Id = id;
            testSuite.Source = source;

            this.Parent = testSuite;

            testSuite.DefaultEnabled = enabled;

            return this;
        }
        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;
                }
            }
        }