/// <summary> /// Event handler gets called the a debug message from the device arrives the nanoFramework debugger /// </summary> /// <param name="message">The debug message</param> private void OnDebugMessage(object sender, SerialDataReceivedEventArgs e) { string className = null; UnitTestResult result = null; string received = _serialPort.ReadExisting(); _output.Append(received); Console.Write(received); if (!_output.ToString().Contains("Tests finished")) { return; } foreach (string message in _output.ToString().Split(Environment.NewLine.ToCharArray())) { foreach (KeyValuePair <MessageParsing, string> entry in _regexParsing) { result = null; // test the message with all possible regex Match match = Regex.Match(message, entry.Value); if (match.Success) { // what have we found? switch (entry.Key) { // Tests started: => get the ticks per milliseconds case MessageParsing.Started: TicksPerMillisecond = decimal.Parse(match.Groups["ticksPerMillisecond"].ToString()); // activate the current results _currentResult = _results.Where(allResults => allResults.TestAssemblyName == match.Groups["assemblyName"].ToString()).Single(); _currentResult.TimeStamp = DateTime.Now.ToString(new System.Globalization.CultureInfo("en-US")); break; // One test passed: Create the UnitTestResult case MessageParsing.Passed: className = match.Groups["fullClassName"].ToString(); result = new UnitTestResult(match.Groups["methodName"].ToString(), UnitTestStatus.Passed, decimal.Parse(match.Groups["elapsedTicks"].ToString()) / TicksPerMillisecond, null); break; // One test failed: Create the UnitTestResult case MessageParsing.Failed: className = match.Groups["fullClassName"].ToString(); result = new UnitTestResult(match.Groups["methodName"].ToString(), UnitTestStatus.Failed, 0, match.Groups["errorMessage"].ToString()); break; // All tests finished: one more assembly has finished the tests; done? case MessageParsing.Finished: _currentResult = null; _testedAssemblyCount++; // all assemblies tested? => detach the event handler and release the semaphore if (_testedAssemblyCount == _results.Count) { if (_serialPort != null) { _serialPort.DataReceived -= OnDebugMessage; _serialPort.Close(); } _waitForFinished.Release(); } break; } break; } } // UnitTestResult created? if (result != null) { // find the class results UnitTestClassResult classResult = _currentResult.ClassResults.Where(entry => entry.TestClassName == className).FirstOrDefault(); // something went wrong if we don't find the test class in the results; maybe the pe-file doesn't match the corresponding dll/exe file if (classResult == null) { throw new ArgumentException($"TestClass {className} not found in the test results"); } // remove the placeholder result and add the current result classResult.MethodResults.RemoveAll(entry => entry.TestMethodName == result.TestMethodName); classResult.MethodResults.Add(result); if (result.TestStatus == UnitTestStatus.Failed) { classResult.ClassStatus = UnitTestStatus.Failed; _currentResult.AssemblyStatus = UnitTestStatus.Failed; } // cumulate the execution time to the class and the assembly classResult.ExecutionDurationMilliseconds += result.ExecutionDurationMilliseconds; _currentResult.ExecutionDurationMilliseconds += result.ExecutionDurationMilliseconds; } } }
/// <summary> /// Event handler gets called when data was received via serial port /// </summary> private void ProcessNextMessageLines() { string className = null; UnitTestResult result = null; string ignoreMessage = null; int i; while ((i = _output.ToString().IndexOfAny(Environment.NewLine.ToCharArray())) >= 0) { if (i == 0) { _output.Remove(0, 1); continue; } string message = _output.ToString().Substring(0, i); foreach (var entry in _regexParsing) { result = null; // test the message with all possible regex var match = Regex.Match(message, entry.Value); if (match.Success) { // what have we found? switch (entry.Key) { // Tests started: => get the ticks per milliseconds case MessageParsing.Started: _ticksPerMillisecond = decimal.Parse(match.Groups["ticksPerMillisecond"].ToString()); // activate the current results _currentResult = _results.Where(allResults => allResults.TestAssemblyName == match.Groups["assemblyName"].ToString()).Single(); _currentResult.TimeStamp = DateTime.Now.ToString(new CultureInfo("en-US")); break; // One test passed: Create the UnitTestResult case MessageParsing.Passed: className = match.Groups["fullClassName"].ToString(); result = new UnitTestResult(match.Groups["methodName"].ToString(), UnitTestStatus.Passed, decimal.Parse(match.Groups["elapsedTicks"].ToString()) / _ticksPerMillisecond, null); break; // One test failed: Create the UnitTestResult case MessageParsing.Failed: className = match.Groups["fullClassName"].ToString(); result = new UnitTestResult(match.Groups["methodName"].ToString(), UnitTestStatus.Failed, 0, match.Groups["errorMessage"].ToString()); break; // The whole test class has the ignore attribute case MessageParsing.IgnoredClass: className = match.Groups["fullClassName"].ToString(); ignoreMessage = match.Groups["ignoreMessage"].ToString(); break; // One test method has the ignore attribute case MessageParsing.IgnoredMethod: className = match.Groups["fullClassName"].ToString(); result = new UnitTestResult(match.Groups["methodName"].ToString(), UnitTestStatus.Ignored, 0, match.Groups["ignoreMessage"].ToString()); break; // All tests finished: one more assembly has finished the tests; done? case MessageParsing.Finished: _currentResult = null; _testedAssemblyCount++; // all assemblies tested? => detach the event handler and release the semaphore if (_testedAssemblyCount == _results.Count) { if (_serialPort != null) { _serialPort.DataReceived -= OnDataReceived; _serialPort.Close(); } _waitForFinished.Release(); } break; } break; } } // UnitTestResult created? if (result != null) { // find the class results var classResult = _currentResult.ClassResults.FirstOrDefault(entry => entry.TestClassName == className); // something went wrong if we don't find the test class in the results; maybe the pe-file doesn't match the corresponding dll/exe file if (classResult == null) { throw new ArgumentException($"TestClass {className} not found in the test results"); } // remove the placeholder result and add the current result classResult.MethodResults.RemoveAll(entry => entry.TestMethodName == result.TestMethodName); classResult.MethodResults.Add(result); if (result.TestStatus == UnitTestStatus.Failed) { classResult.ClassStatus = UnitTestStatus.Failed; _currentResult.AssemblyStatus = UnitTestStatus.Failed; } else { if (classResult.ClassStatus != UnitTestStatus.Failed) { classResult.ClassStatus = UnitTestStatus.Passed; } if (_currentResult.AssemblyStatus != UnitTestStatus.Failed) { _currentResult.AssemblyStatus = UnitTestStatus.Passed; } } // cumulate the execution time to the class and the assembly classResult.ExecutionDurationMilliseconds += result.ExecutionDurationMilliseconds; _currentResult.ExecutionDurationMilliseconds += result.ExecutionDurationMilliseconds; } // whole class ignored? if (ignoreMessage != null) { // find the class results var classResult = _currentResult.ClassResults.FirstOrDefault(entry => entry.TestClassName == className); // something went wrong if we don't find the test class in the results; maybe the pe-file doesn't match the corresponding dll/exe file if (classResult == null) { throw new ArgumentException($"TestClass {className} not found in the test results"); } classResult.ClassStatus = UnitTestStatus.Ignored; foreach (UnitTestResult entry in classResult.MethodResults) { entry.TestStatus = UnitTestStatus.Ignored; entry.Message = ignoreMessage; } } _output.Remove(0, i + 1); } }