Beispiel #1
0
        public void ConvertMemoryLeakToVSTestResult()
        {
            LogEntryMemoryLeak leak = new LogEntryMemoryLeak();

            leak.LeakLineNumber             = 32;
            leak.LeakMemoryAllocationNumber = 836;
            leak.LeakLeakedDataContents     = " Data: <`-  Leak...     > 60 2D BD 00 4C 65 61 6B 2E 2E 2E 00 CD CD CD CD ";

            leak.LeakSourceFilePath = @"C:\boostunittestsample.cpp";
            leak.LeakSourceFileName = "boostunittestsample.cpp";

            BoostTestResult testCaseResult = new BoostTestResultBuilder().
                                             For(this.TestCase).
                                             Passed().
                                             Duration(1000).
                                             Log(leak).
                                             Build();

            VSTestResult result = testCaseResult.AsVSTestResult(this.TestCase);

            AssertVSTestModelProperties(result);

            Assert.That(result.Outcome, Is.EqualTo(TestOutcome.Passed));
            Assert.That(result.Duration, Is.EqualTo(Microseconds(1000)));

            Assert.That(result.Messages.Count, Is.EqualTo(1));

            TestResultMessage message = result.Messages.First();

            Assert.That(message.Category, Is.EqualTo(TestResultMessage.StandardErrorCategory));
        }
        /// <summary>
        /// Formats a LogEntryMemoryLeak to append to test result string
        /// </summary>
        /// <param name="memoryLeak">The memory leak to format</param>
        /// <param name="sb">The StringBuilder which will host the output</param>
        /// <returns>sb</returns>
        private static StringBuilder FormatMemoryLeak(LogEntryMemoryLeak memoryLeak, StringBuilder sb)
        {
            if ((memoryLeak.LeakSourceFilePath != null) && (memoryLeak.LeakSourceFileName != null))
            {
                sb.Append("source file path leak detected at :").
                Append(memoryLeak.LeakSourceFilePath).
                Append(memoryLeak.LeakSourceFileName);
            }

            if (memoryLeak.LeakLineNumber != null)
            {
                sb.Append(", ").
                Append("Line number: ").
                Append(memoryLeak.LeakLineNumber);
            }

            sb.Append(", ").
            Append("Memory allocation number: ").
            Append(memoryLeak.LeakMemoryAllocationNumber);

            sb.Append(", ").
            Append("Leak size: ").
            Append(memoryLeak.LeakSizeInBytes).
            Append(" byte");

            if (memoryLeak.LeakSizeInBytes > 0)
            {
                sb.Append('s');
            }

            sb.Append(Environment.NewLine).
            Append(memoryLeak.LeakLeakedDataContents);

            return(sb);
        }
        private static string GetTestResultMessageText(TestUnit unit, LogEntry entry)
        {
            Code.Require(unit, "unit");
            Code.Require(entry, "entry");

            if ((entry is LogEntryStandardOutputMessage) || (entry is LogEntryStandardErrorMessage))
            {
                return(entry.Detail.TrimEnd() + Environment.NewLine);
            }

            StringBuilder sb = new StringBuilder();

            if (entry.Source != null)
            {
                AppendSourceInfo(entry.Source, sb);
            }

            sb.Append(entry.ToString().ToLowerInvariant()).
            Append(" in \"").
            Append(unit.Name).
            Append("\"");

            LogEntryMemoryLeak memoryLeak = entry as LogEntryMemoryLeak;

            if (memoryLeak == null)
            {
                sb.Append(": ").Append(entry.Detail.TrimEnd());
            }

            LogEntryException exception = entry as LogEntryException;

            if (exception != null)
            {
                FormatException(exception, sb);
            }

            LogEntryError error = entry as LogEntryError;

            if (error != null)
            {
                FormatError(error, sb);
            }

            if (memoryLeak != null)
            {
                FormatMemoryLeak(memoryLeak, sb);
            }

            // Append NewLine so that log entries are listed one per line
            return(sb.Append(Environment.NewLine).ToString());
        }
        /// <summary>
        /// Registers the provided memory leak string representation within the test collection
        /// </summary>
        /// <param name="leakInformation">The full memory leak information</param>
        /// <param name="collection">The test collection in which to place memory leak entries</param>
        private void RegisterMemoryLeak(string leakInformation, IDictionary <string, TestResult> collection)
        {
            foreach (var entry in collection)
            {
                var result = entry.Value;

                if (this.FailTestOnMemoryLeak)
                {
                    result.Result = TestResultType.Failed;
                }

                Regex regexLeakInformation = new Regex(@"(?:([\\:\w\rA-z.]*?)([\w\d.]*)\((\d{1,})\)\s:\s)?\{(\d{1,})\}[\w\s\d]*,\s(\d{1,})[\s\w.]*\n(.*?)(?=$|(?:[\\\w.:]*\(\d{1,}\)\s:\s)?\{\d{1,}\d)", RegexOptions.IgnoreCase | RegexOptions.Singleline);   //the old one wasRegex regexLeakInformation = new Regex(@"^(.*\\)(.*?)\((\d{1,})\).*?{(\d{1,})}.*?(\d{1,})\sbyte", RegexOptions.IgnoreCase | RegexOptions.Multiline);

                /*
                 *
                 * The same regex works for when the complete file path along with the line number are reported in the console output such as in the below sample output
                 *
                 * d:\hwa\dev\svn\boostunittestadapterdev\branches\tempbugfixing\sample\boostunittest\boostunittest2\adapterbugs.cpp(58) : {869} normal block at 0x00A88A58, 4 bytes long.
                 *  Data: <    > CD CD CD CD
                 * d:\hwa\dev\svn\boostunittestadapterdev\branches\tempbugfixing\sample\boostunittest\boostunittest2\adapterbugs.cpp(55) : {868} normal block at 0x00A88788, 4 bytes long.
                 *  Data: <    > F5 01 00 00
                 *
                 * and also when this information is not reported such as in the below sample output
                 *
                 * {869} normal block at 0x005E8998, 4 bytes long.
                 * Data: <    > CD CD CD CD
                 * {868} normal block at 0x005E8848, 4 bytes long.
                 * Data: <    > F5 01 00 00
                 *
                 */

                #region regexLeakInformation

                // (?:([\\:\w\rA-z.]*?)([\w\d.]*)\((\d{1,})\)\s:\s)?\{(\d{1,})\}[\w\s\d]*,\s(\d{1,})[\s\w.]*\n(.*?)(?=$|(?:[\\\w.:]*\(\d{1,}\)\s:\s)?\{\d{1,}\d)
                //
                // Options: Case insensitive; Exact spacing; Dot matches line breaks; ^$ don't match at line breaks; Numbered capture
                //
                // Match the regular expression below «(?:([\\:\w\rA-z.]*?)([\w\d.]*)\((\d{1,})\)\s:\s)?»
                //    Between zero and one times, as many times as possible, giving back as needed (greedy) «?»
                //    Match the regex below and capture its match into backreference number 1 «([\\:\w\rA-z.]*?)»
                //       Match a single character present in the list below «[\\:\w\rA-z.]*?»
                //          Between zero and unlimited times, as few times as possible, expanding as needed (lazy) «*?»
                //          The backslash character «\\»
                //          The literal character “:” «:»
                //          A “word character” (Unicode; any letter or ideograph, digit, connector punctuation) «\w»
                //          The carriage return character «\r»
                //          A character in the range between “A” and “z” (case insensitive) «A-z»
                //          The literal character “.” «.»
                //    Match the regex below and capture its match into backreference number 2 «([\w\d.]*)»
                //       Match a single character present in the list below «[\w\d.]*»
                //          Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
                //          A “word character” (Unicode; any letter or ideograph, digit, connector punctuation) «\w»
                //          A “digit” (0–9 in any Unicode script) «\d»
                //          The literal character “.” «.»
                //    Match the character “(” literally «\(»
                //    Match the regex below and capture its match into backreference number 3 «(\d{1,})»
                //       Match a single character that is a “digit” (0–9 in any Unicode script) «\d{1,}»
                //          Between one and unlimited times, as many times as possible, giving back as needed (greedy) «{1,}»
                //    Match the character “)” literally «\)»
                //    Match a single character that is a “whitespace character” (any Unicode separator, tab, line feed, carriage return, vertical tab, form feed, next line) «\s»
                //    Match the character “:” literally «:»
                //    Match a single character that is a “whitespace character” (any Unicode separator, tab, line feed, carriage return, vertical tab, form feed, next line) «\s»
                // Match the character “{” literally «\{»
                // Match the regex below and capture its match into backreference number 4 «(\d{1,})»
                //    Match a single character that is a “digit” (0–9 in any Unicode script) «\d{1,}»
                //       Between one and unlimited times, as many times as possible, giving back as needed (greedy) «{1,}»
                // Match the character “}” literally «\}»
                // Match a single character present in the list below «[\w\s\d]*»
                //    Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
                //    A “word character” (Unicode; any letter or ideograph, digit, connector punctuation) «\w»
                //    A “whitespace character” (any Unicode separator, tab, line feed, carriage return, vertical tab, form feed, next line) «\s»
                //    A “digit” (0–9 in any Unicode script) «\d»
                // Match the character “,” literally «,»
                // Match a single character that is a “whitespace character” (any Unicode separator, tab, line feed, carriage return, vertical tab, form feed, next line) «\s»
                // Match the regex below and capture its match into backreference number 5 «(\d{1,})»
                //    Match a single character that is a “digit” (0–9 in any Unicode script) «\d{1,}»
                //       Between one and unlimited times, as many times as possible, giving back as needed (greedy) «{1,}»
                // Match a single character present in the list below «[\s\w.]*»
                //    Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
                //    A “whitespace character” (any Unicode separator, tab, line feed, carriage return, vertical tab, form feed, next line) «\s»
                //    A “word character” (Unicode; any letter or ideograph, digit, connector punctuation) «\w»
                //    The literal character “.” «.»
                // Match the line feed character «\n»
                // Match the regex below and capture its match into backreference number 6 «(.*?)»
                //    Match any single character «.*?»
                //       Between zero and unlimited times, as few times as possible, expanding as needed (lazy) «*?»
                // Assert that the regex below can be matched, starting at this position (positive lookahead) «(?=$|(?:[\\\w.:]*\(\d{1,}\)\s:\s)?\{\d{1,}\d)»
                //    Match this alternative (attempting the next alternative only if this one fails) «$»
                //       Assert position at the end of the string, or before the line break at the end of the string, if any (line feed) «$»
                //    Or match this alternative (the entire group fails if this one fails to match) «(?:[\\\w.:]*\(\d{1,}\)\s:\s)?\{\d{1,}\d»
                //       Match the regular expression below «(?:[\\\w.:]*\(\d{1,}\)\s:\s)?»
                //          Between zero and one times, as many times as possible, giving back as needed (greedy) «?»
                //          Match a single character present in the list below «[\\\w.:]*»
                //             Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
                //             The backslash character «\\»
                //             A “word character” (Unicode; any letter or ideograph, digit, connector punctuation) «\w»
                //             A single character from the list “.:” «.:»
                //          Match the character “(” literally «\(»
                //          Match a single character that is a “digit” (0–9 in any Unicode script) «\d{1,}»
                //             Between one and unlimited times, as many times as possible, giving back as needed (greedy) «{1,}»
                //          Match the character “)” literally «\)»
                //          Match a single character that is a “whitespace character” (any Unicode separator, tab, line feed, carriage return, vertical tab, form feed, next line) «\s»
                //          Match the character “:” literally «:»
                //          Match a single character that is a “whitespace character” (any Unicode separator, tab, line feed, carriage return, vertical tab, form feed, next line) «\s»
                //       Match the character “{” literally «\{»
                //       Match a single character that is a “digit” (0–9 in any Unicode script) «\d{1,}»
                //          Between one and unlimited times, as many times as possible, giving back as needed (greedy) «{1,}»
                //       Match a single character that is a “digit” (0–9 in any Unicode script) «\d»

                #endregion regexLeakInformation

                Match matchLeakInformation = regexLeakInformation.Match(leakInformation);
                while (matchLeakInformation.Success)
                {
                    LogEntryMemoryLeak leak = new LogEntryMemoryLeak();

                    result.LogEntries.Add(leak);

                    //Capturing group 1,2 and 3 will have the 'Success' property false in case the C++ new operator has not been replaced via the macro

                    // Temporary variable used to try and parse unsigned integer values;
                    uint value = 0;

                    if (matchLeakInformation.Groups[1].Success && matchLeakInformation.Groups[2].Success && matchLeakInformation.Groups[3].Success)
                    {
                        // Group 1 => Directory
                        // Group 2 => Source File Name

                        leak.Source = new SourceFileInfo(matchLeakInformation.Groups[1].Value + matchLeakInformation.Groups[2].Value);

                        if (uint.TryParse(matchLeakInformation.Groups[3].Value, out value))
                        {
                            leak.Source.LineNumber = (int)value;
                        }
                    }

                    if (uint.TryParse(matchLeakInformation.Groups[4].Value, out value))
                    {
                        leak.LeakMemoryAllocationNumber = value;
                    }

                    if (uint.TryParse(matchLeakInformation.Groups[5].Value, out value))
                    {
                        leak.LeakSizeInBytes = value;
                    }

                    leak.LeakLeakedDataContents = matchLeakInformation.Groups[6].Value;

                    matchLeakInformation = matchLeakInformation.NextMatch();
                }
            }
        }