/// <summary> /// Parses the error list from visual studio and collect the results from TcUnit /// </summary> /// <returns> /// null if parse failed or results are not ready /// If parse succeeds, the test results are returned /// </returns> public TcUnitTestResult ParseResults(IEnumerable <ErrorList.Error> errors, string unitTestTaskName) { TcUnitTestResult tcUnitTestResult = new TcUnitTestResult(); if (!AreTestResultsAvailable()) { return(null); } else { ErrorLogEntryType expectedErrorLogEntryType = ErrorLogEntryType.TEST_SUITE_FINISHED_RUNNING; tcUnitTestResult.AddGeneralTestResults((uint)numberOfTestSuites, (uint)numberOfTests, (uint)numberOfSuccessfulTests, (uint)numberOfFailedTests); // Temporary variables uint currentTestIdentity = 0; uint currentTestCaseInTestSuiteNumber = 0; /* Storage variables */ // Test suite string testSuiteName = ""; uint testSuiteIdentity = 0; uint testSuiteNumberOfTests = 0; uint testSuiteNumberOfFailedTests = 0; // Test case string testSuiteTestCaseName = ""; string testSuiteTestCaseClassName = ""; string testSuiteTestCaseStatus = ""; string testSuiteTestCaseFailureMessage = ""; string testSuiteTestCaseAssertType = ""; uint testSuiteTestCaseNumberOfAsserts = 0; List <TcUnitTestResult.TestCaseResult> testSuiteTestCaseResults = new List <TcUnitTestResult.TestCaseResult>(); /* Find all test suite IDs. There must be one ID for every test suite. The ID starts at 0, so * if we have 5 test suites, we should expect the IDs to be 0, 1, 2, 3, 4 */ foreach (var item in errors.Where(e => e.ErrorLevel == vsBuildErrorLevel.vsBuildErrorLevelLow)) { string tcUnitAdsMessage; // Only do further processing if message is from TcUnit if (IsTcUnitAdsMessage(item.Description, unitTestTaskName)) { tcUnitAdsMessage = RemoveEverythingButTcUnitAdsMessage(item.Description, unitTestTaskName); /* ------------------------------------- * Look for test suite finished running * ------------------------------------- */ if (tcUnitAdsMessage.Contains("Test suite ID=" + currentTestIdentity + " '")) { if (expectedErrorLogEntryType == ErrorLogEntryType.TEST_SUITE_FINISHED_RUNNING) { // Reset stored variables testSuiteName = ""; testSuiteIdentity = 0; testSuiteNumberOfTests = 0; testSuiteNumberOfFailedTests = 0; testSuiteTestCaseName = ""; testSuiteTestCaseClassName = ""; testSuiteTestCaseStatus = ""; testSuiteTestCaseFailureMessage = ""; testSuiteTestCaseAssertType = ""; testSuiteTestCaseResults.Clear(); // Parse test suite name testSuiteIdentity = currentTestIdentity; testSuiteName = tcUnitAdsMessage.Substring(tcUnitAdsMessage.LastIndexOf("Test suite ID=" + currentTestIdentity + " '") + currentTestIdentity.ToString().Length + 16); /* If last character is ', remove it */ if (String.Equals(testSuiteName[testSuiteName.Length - 1].ToString(), "'", StringComparison.InvariantCultureIgnoreCase)) { testSuiteName = testSuiteName.Remove(testSuiteName.Length - 1); } expectedErrorLogEntryType = ErrorLogEntryType.TEST_SUITE_STATISTICS; } else { log.Error("ERROR: While parsing TcUnit results, expected " + expectedErrorLogEntryType.ToString() + " but got " + ErrorLogEntryType.TEST_SUITE_FINISHED_RUNNING.ToString()); return(null); } } /* ------------------------------------- * Look for test suite statistics * ------------------------------------- */ else if (tcUnitAdsMessage.Contains("ID=" + currentTestIdentity + " number of tests=") && tcUnitAdsMessage.Contains(", number of failed tests=")) { if (expectedErrorLogEntryType == ErrorLogEntryType.TEST_SUITE_STATISTICS) { // Parse test suite results (number of tests + number of failed tests) string numberOfTestsString = Utilities.GetStringBetween(tcUnitAdsMessage, "ID=" + currentTestIdentity + " number of tests=", ", number of failed tests="); if (!uint.TryParse(numberOfTestsString, out testSuiteNumberOfTests)) { // Handle error } string numberOfFailedTestsString = tcUnitAdsMessage.Substring(tcUnitAdsMessage.LastIndexOf(", number of failed tests=") + 25); if (!uint.TryParse(numberOfFailedTestsString, out testSuiteNumberOfFailedTests)) { // Handle error } /* Now two things can happen. Either the testsuite didn't have any tests (testSuiteNumberOfTests=0) * or it had tests. If it didn't have any tests, we store the testsuite result here and go to the * next test suite. If it had tests, we continue */ if (testSuiteNumberOfTests.Equals(0)) { // Store test suite & go to next test suite TcUnitTestResult.TestSuiteResult tsResult = new TcUnitTestResult.TestSuiteResult(testSuiteName, testSuiteIdentity, testSuiteNumberOfTests, testSuiteNumberOfFailedTests); tcUnitTestResult.AddNewTestSuiteResult(tsResult); expectedErrorLogEntryType = ErrorLogEntryType.TEST_SUITE_FINISHED_RUNNING; } else { expectedErrorLogEntryType = ErrorLogEntryType.TEST_NAME; currentTestCaseInTestSuiteNumber = 1; } currentTestIdentity++; } else { log.Error("ERROR: While parsing TcUnit results, expected " + expectedErrorLogEntryType.ToString() + " but got " + ErrorLogEntryType.TEST_SUITE_STATISTICS.ToString()); return(null); } } /* ------------------------------------- * Look for test name * ------------------------------------- */ else if (tcUnitAdsMessage.Contains("Test name=")) { if (expectedErrorLogEntryType == ErrorLogEntryType.TEST_NAME && currentTestCaseInTestSuiteNumber <= testSuiteNumberOfTests) { // Parse test name string testName = tcUnitAdsMessage.Substring(tcUnitAdsMessage.LastIndexOf("Test name=") + 10); testSuiteTestCaseName = testName; currentTestCaseInTestSuiteNumber++; expectedErrorLogEntryType = ErrorLogEntryType.TEST_CLASS_NAME; } else { if (expectedErrorLogEntryType != ErrorLogEntryType.TEST_NAME) { log.Error("ERROR: While parsing TcUnit results, expected " + expectedErrorLogEntryType.ToString() + " but got " + ErrorLogEntryType.TEST_NAME.ToString()); } else { log.Error("ERROR: While parsing TcUnit results, got test case number " + currentTestCaseInTestSuiteNumber + " but expected amount is " + testSuiteNumberOfTests); } return(null); } } /* ------------------------------------- * Look for test class name * ------------------------------------- */ else if (tcUnitAdsMessage.Contains("Test class name=")) { if (expectedErrorLogEntryType == ErrorLogEntryType.TEST_CLASS_NAME) { // Parse test class name string testClassName = tcUnitAdsMessage.Substring(tcUnitAdsMessage.LastIndexOf("Test class name=") + 16); testSuiteTestCaseClassName = testClassName; expectedErrorLogEntryType = ErrorLogEntryType.TEST_STATUS_AND_NUMBER_OF_ASSERTS; } else { log.Error("ERROR: While parsing TcUnit results, expected " + expectedErrorLogEntryType.ToString() + " but got " + ErrorLogEntryType.TEST_CLASS_NAME.ToString()); return(null); } } /* ------------------------------------- * Look for test status and number of asserts * ------------------------------------- */ else if (tcUnitAdsMessage.Contains("Test status=") && tcUnitAdsMessage.Contains(", number of asserts=")) { if (expectedErrorLogEntryType == ErrorLogEntryType.TEST_STATUS_AND_NUMBER_OF_ASSERTS) { // Parse test status string testStatus = Utilities.GetStringBetween(tcUnitAdsMessage, "Test status=", ", number of asserts="); string testNumberOfAssertions = tcUnitAdsMessage.Substring(tcUnitAdsMessage.LastIndexOf(", number of asserts=") + 20); testSuiteTestCaseStatus = testStatus; if (!uint.TryParse(testNumberOfAssertions, out testSuiteTestCaseNumberOfAsserts)) { // Handle error } /* Now two things can happen. Either the test result/status is FAIL, in which case we want to read the * assertion information. If the test result/status is not FAIL, we either continue to the next test case * or the next test suite */ if (testStatus.Equals("FAIL")) { expectedErrorLogEntryType = ErrorLogEntryType.TEST_ASSERT_MESSAGE; } else { // Store test case TcUnitTestResult.TestCaseResult tcResult = new TcUnitTestResult.TestCaseResult(testSuiteTestCaseName, testSuiteTestCaseClassName, testSuiteTestCaseStatus, "", "", testSuiteTestCaseNumberOfAsserts); // Add test case result to test cases results testSuiteTestCaseResults.Add(tcResult); if (currentTestCaseInTestSuiteNumber <= testSuiteNumberOfTests) { // More tests in this test suite expectedErrorLogEntryType = ErrorLogEntryType.TEST_NAME; // Goto next test case } else { // Last test case in this test suite // Create test suite result TcUnitTestResult.TestSuiteResult tsResult = new TcUnitTestResult.TestSuiteResult(testSuiteName, testSuiteIdentity, testSuiteNumberOfTests, testSuiteNumberOfFailedTests); // Add test case results to test suite foreach (TcUnitTestResult.TestCaseResult tcResultToBeStored in testSuiteTestCaseResults) { tsResult.TestCaseResults.Add(tcResultToBeStored); } // Add test suite to final test results tcUnitTestResult.AddNewTestSuiteResult(tsResult); expectedErrorLogEntryType = ErrorLogEntryType.TEST_SUITE_FINISHED_RUNNING; } } } else { log.Error("ERROR: While parsing TcUnit results, expected " + expectedErrorLogEntryType.ToString() + " but got " + ErrorLogEntryType.TEST_STATUS_AND_NUMBER_OF_ASSERTS.ToString()); return(null); } } /* ------------------------------------- * Look for test assert message * ------------------------------------- */ else if (tcUnitAdsMessage.Contains("Test assert message=")) { if (expectedErrorLogEntryType == ErrorLogEntryType.TEST_ASSERT_MESSAGE) { // Parse test assert message string testAssertMessage = tcUnitAdsMessage.Substring(tcUnitAdsMessage.LastIndexOf("Test assert message=") + 20); testSuiteTestCaseFailureMessage = testAssertMessage; expectedErrorLogEntryType = ErrorLogEntryType.TEST_ASSERT_TYPE; } else { log.Error("ERROR: While parsing TcUnit results, expected " + expectedErrorLogEntryType.ToString() + " but got " + ErrorLogEntryType.TEST_ASSERT_MESSAGE.ToString()); return(null); } } /* ------------------------------------- * Look for test assert type * ------------------------------------- */ else if (tcUnitAdsMessage.Contains("Test assert type=")) { if (expectedErrorLogEntryType == ErrorLogEntryType.TEST_ASSERT_TYPE /* Even though we might expect a test assertion message, the test assertion might not have included one message, and thus we will * skip/not receive any TEST_ASSERTION_MESSAGE but rather instead get a TEST_ASSERT_TYPE */ || expectedErrorLogEntryType == ErrorLogEntryType.TEST_ASSERT_MESSAGE) { // Make sure to reset the assertion message to empty string if we have not received any test assert message if (expectedErrorLogEntryType == ErrorLogEntryType.TEST_ASSERT_MESSAGE) { testSuiteTestCaseFailureMessage = ""; } // Parse test assert type string testAssertType = tcUnitAdsMessage.Substring(tcUnitAdsMessage.LastIndexOf("Test assert type=") + 17); testSuiteTestCaseAssertType = testAssertType; // Store test case TcUnitTestResult.TestCaseResult tcResult = new TcUnitTestResult.TestCaseResult(testSuiteTestCaseName, testSuiteTestCaseClassName, testSuiteTestCaseStatus, testSuiteTestCaseFailureMessage, testSuiteTestCaseAssertType, testSuiteTestCaseNumberOfAsserts); // Add test case result to test cases results testSuiteTestCaseResults.Add(tcResult); if (currentTestCaseInTestSuiteNumber <= testSuiteNumberOfTests) { // More tests in this test suite expectedErrorLogEntryType = ErrorLogEntryType.TEST_NAME; // Goto next test case } else { // Last test case in this test suite // Create test suite result TcUnitTestResult.TestSuiteResult tsResult = new TcUnitTestResult.TestSuiteResult(testSuiteName, testSuiteIdentity, testSuiteNumberOfTests, testSuiteNumberOfFailedTests); // Add test case results to test suite foreach (TcUnitTestResult.TestCaseResult tcResultToBeStored in testSuiteTestCaseResults) { tsResult.TestCaseResults.Add(tcResultToBeStored); } // Add test suite to final test results tcUnitTestResult.AddNewTestSuiteResult(tsResult); expectedErrorLogEntryType = ErrorLogEntryType.TEST_SUITE_FINISHED_RUNNING; } } else { log.Error("ERROR: While parsing TcUnit results, expected " + expectedErrorLogEntryType.ToString() + " but got " + ErrorLogEntryType.TEST_ASSERT_TYPE.ToString()); return(null); } } } } log.Info("Done collecting TC results"); return(tcUnitTestResult); } }