From 3f2b16b6299b7565c39e2ab69d4508946841a213 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 8 Feb 2026 07:25:40 +0000 Subject: [PATCH 1/6] Initial plan From 46471633b0a173827c2579002afb175693607cc0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 8 Feb 2026 07:27:31 +0000 Subject: [PATCH 2/6] Initial exploration - repository structure and build confirmed Co-authored-by: BenjaminMichaelis <22186029+BenjaminMichaelis@users.noreply.github.com> --- :GITHUB_ENV | 1 + 1 file changed, 1 insertion(+) create mode 100644 :GITHUB_ENV diff --git a/:GITHUB_ENV b/:GITHUB_ENV new file mode 100644 index 0000000..f06e6e8 --- /dev/null +++ b/:GITHUB_ENV @@ -0,0 +1 @@ +COPILOT_SETUP_COMPLETE=true From db11c6284a73d29ee6a84b13fe77d814d5c4bc8e Mon Sep 17 00:00:00 2001 From: Benjamin Michaelis Date: Sat, 7 Feb 2026 23:30:14 -0800 Subject: [PATCH 3/6] Delete :GITHUB_ENV --- :GITHUB_ENV | 1 - 1 file changed, 1 deletion(-) delete mode 100644 :GITHUB_ENV diff --git a/:GITHUB_ENV b/:GITHUB_ENV deleted file mode 100644 index f06e6e8..0000000 --- a/:GITHUB_ENV +++ /dev/null @@ -1 +0,0 @@ -COPILOT_SETUP_COMPLETE=true From 059a3353c43faa2e9602b9c761e4aa17d8fc2efb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 8 Feb 2026 07:33:38 +0000 Subject: [PATCH 4/6] Implement enhanced wildcard mismatch diff output Co-authored-by: BenjaminMichaelis <22186029+BenjaminMichaelis@users.noreply.github.com> --- .../EnhancedErrorMessageTests.cs | 110 ++++++ .../WildcardMatchAnalyzerTests.cs | 131 +++++++ .../ConsoleAssert.cs | 23 +- .../WildcardMatchAnalyzer.cs | 352 ++++++++++++++++++ 4 files changed, 614 insertions(+), 2 deletions(-) create mode 100644 IntelliTect.TestTools.Console.Tests/EnhancedErrorMessageTests.cs create mode 100644 IntelliTect.TestTools.Console.Tests/WildcardMatchAnalyzerTests.cs create mode 100644 IntelliTect.TestTools.Console/WildcardMatchAnalyzer.cs diff --git a/IntelliTect.TestTools.Console.Tests/EnhancedErrorMessageTests.cs b/IntelliTect.TestTools.Console.Tests/EnhancedErrorMessageTests.cs new file mode 100644 index 0000000..e6bd817 --- /dev/null +++ b/IntelliTect.TestTools.Console.Tests/EnhancedErrorMessageTests.cs @@ -0,0 +1,110 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; + +namespace IntelliTect.TestTools.Console.Tests; + +[TestClass] +public class EnhancedErrorMessageTests +{ + [TestMethod] + public void ExpectLike_WildcardMismatch_ShowsDetailedDiff() + { + // Arrange - pattern with wildcards that will NOT match + string expected = "PING *(::1) 56 data bytes\n64 bytes from *"; + + // Act & Assert + Exception exception = Assert.ThrowsExactly(() => + { + ConsoleAssert.ExpectLike(expected, () => + { + System.Console.Write("PING localhost(::1) WRONG data bytes\n64 bytes from localhost"); + }); + }); + + // Assert - Check that the error message contains the enhanced output + string errorMessage = exception.Message; + + // Should contain the line-by-line comparison header + StringAssert.Contains(errorMessage, "Line-by-line comparison"); + + // Should contain status indicators + StringAssert.Contains(errorMessage, "❌"); // Lines don't match + } + + [TestMethod] + public void ExpectLike_ExtraLines_IdentifiedAsSuch() + { + // Arrange - pattern expecting one line, but getting two + string expected = "Line 1"; + + // Act & Assert + Exception exception = Assert.ThrowsExactly(() => + { + ConsoleAssert.ExpectLike(expected, () => + { + System.Console.WriteLine("Line 1"); + System.Console.WriteLine("Line 2"); + }); + }); + + // Assert + string errorMessage = exception.Message; + // With line-by-line comparison, we should see the extra line marked + StringAssert.Contains(errorMessage, "Line 2: ❌"); + StringAssert.Contains(errorMessage, "Unexpected extra line"); + } + + [TestMethod] + public void ExpectLike_MissingLines_IdentifiedAsSuch() + { + // Arrange - pattern with wildcards expecting more lines + string expected = "Line 1\nLine *"; + + // Act & Assert + Exception exception = Assert.ThrowsExactly(() => + { + ConsoleAssert.ExpectLike(expected, () => + { + System.Console.WriteLine("Line 1"); + }); + }); + + // Assert + string errorMessage = exception.Message; + StringAssert.Contains(errorMessage, "Missing line"); + } + + [TestMethod] + public void ExecuteProcess_WildcardMismatch_ShowsDetailedDiff() + { + // This test demonstrates the improved error output for ExecuteProcess + // when wildcard matching fails. + + string expected = "This * should match"; + + Exception exception = null; + try + { + ConsoleAssert.ExecuteProcess( + expected, + "echo", + "Output that does not match", + out string _, + out _); + } + catch (Exception ex) + { + exception = ex; + } + + // Assert + Assert.IsNotNull(exception); + string errorMessage = exception.Message; + + // Should contain wildcard matching error message + StringAssert.Contains(errorMessage, "wildcard"); + + // Should contain the line-by-line comparison + StringAssert.Contains(errorMessage, "Line-by-line comparison"); + } +} diff --git a/IntelliTect.TestTools.Console.Tests/WildcardMatchAnalyzerTests.cs b/IntelliTect.TestTools.Console.Tests/WildcardMatchAnalyzerTests.cs new file mode 100644 index 0000000..f2bace3 --- /dev/null +++ b/IntelliTect.TestTools.Console.Tests/WildcardMatchAnalyzerTests.cs @@ -0,0 +1,131 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; + +namespace IntelliTect.TestTools.Console.Tests; + +[TestClass] +public class WildcardMatchAnalyzerTests +{ + [TestMethod] + public void AnalyzeMatch_SingleLineMatch_IdentifiesWildcardMatches() + { + // Arrange + string expected = "Hello * world"; + string actual = "Hello beautiful world"; + + // Act + var results = WildcardMatchAnalyzer.AnalyzeMatch(expected, actual); + + // Assert + Assert.AreEqual(1, results.Count); + Assert.IsTrue(results[0].IsMatch); + Assert.AreEqual(1, results[0].WildcardMatches.Count); + // The * matches "beautiful" (without trailing space because "world" comes next) + Assert.AreEqual("beautiful", results[0].WildcardMatches[0].MatchedText); + } + + [TestMethod] + public void AnalyzeMatch_MultipleWildcards_TracksAllMatches() + { + // Arrange + string expected = "PING *(* (::1)) * data bytes"; + string actual = "PING localhost(localhost (::1)) 56 data bytes"; + + // Act + var results = WildcardMatchAnalyzer.AnalyzeMatch(expected, actual); + + // Assert + Assert.AreEqual(1, results.Count); + Assert.IsTrue(results[0].IsMatch); + Assert.IsTrue(results[0].WildcardMatches.Count >= 2); + } + + [TestMethod] + public void AnalyzeMatch_Mismatch_IdentifiesFailure() + { + // Arrange + string expected = "Hello world"; + string actual = "Hello universe"; + + // Act + var results = WildcardMatchAnalyzer.AnalyzeMatch(expected, actual); + + // Assert + Assert.AreEqual(1, results.Count); + Assert.IsFalse(results[0].IsMatch); + } + + [TestMethod] + public void AnalyzeMatch_ExtraLinesInActual_MarkedAsUnexpected() + { + // Arrange + string expected = "Line 1\nLine 2"; + string actual = "Line 1\nLine 2\nLine 3"; + + // Act + var results = WildcardMatchAnalyzer.AnalyzeMatch(expected, actual); + + // Assert + Assert.AreEqual(3, results.Count); + Assert.IsTrue(results[0].IsMatch); + Assert.IsTrue(results[1].IsMatch); + Assert.IsFalse(results[2].IsMatch); // Extra line + Assert.IsNull(results[2].ExpectedLine); + Assert.IsNotNull(results[2].ActualLine); + } + + [TestMethod] + public void AnalyzeMatch_MissingLinesInActual_MarkedAsMissing() + { + // Arrange + string expected = "Line 1\nLine 2\nLine 3"; + string actual = "Line 1\nLine 2"; + + // Act + var results = WildcardMatchAnalyzer.AnalyzeMatch(expected, actual); + + // Assert + Assert.AreEqual(3, results.Count); + Assert.IsTrue(results[0].IsMatch); + Assert.IsTrue(results[1].IsMatch); + Assert.IsFalse(results[2].IsMatch); // Missing line + Assert.IsNotNull(results[2].ExpectedLine); + Assert.IsNull(results[2].ActualLine); + } + + [TestMethod] + public void GenerateDetailedDiff_CreatesReadableOutput() + { + // Arrange + string expected = "Hello * world\nLine *"; + string actual = "Hello beautiful world\nLine 2"; + + var results = WildcardMatchAnalyzer.AnalyzeMatch(expected, actual); + + // Act + string diff = WildcardMatchAnalyzer.GenerateDetailedDiff(results); + + // Assert + Assert.IsFalse(string.IsNullOrEmpty(diff)); + StringAssert.Contains(diff, "Line-by-line comparison"); + StringAssert.Contains(diff, "✅"); // Should contain success markers + StringAssert.Contains(diff, "Wildcard matches"); + } + + [TestMethod] + public void GenerateDetailedDiff_WithMismatch_ShowsFailure() + { + // Arrange + string expected = "Expected text"; + string actual = "Actual text"; + + var results = WildcardMatchAnalyzer.AnalyzeMatch(expected, actual); + + // Act + string diff = WildcardMatchAnalyzer.GenerateDetailedDiff(results); + + // Assert + Assert.IsFalse(string.IsNullOrEmpty(diff)); + StringAssert.Contains(diff, "❌"); // Should contain failure marker + } +} diff --git a/IntelliTect.TestTools.Console/ConsoleAssert.cs b/IntelliTect.TestTools.Console/ConsoleAssert.cs index 7d23f31..1c0aa45 100644 --- a/IntelliTect.TestTools.Console/ConsoleAssert.cs +++ b/IntelliTect.TestTools.Console/ConsoleAssert.cs @@ -468,7 +468,11 @@ private static void AssertExpectation(string expectedOutput, string output, Func bool failTest = !areEquivalentOperator(expectedOutput, output); if (failTest) { - throw new Exception(GetMessageText(expectedOutput, output, equivalentOperatorErrorMessage)); + // Check if we're using wildcard matching + bool isWildcardMatching = equivalentOperatorErrorMessage?.Contains("wildcard") == true || + equivalentOperatorErrorMessage?.Contains("like") == true; + + throw new Exception(GetMessageText(expectedOutput, output, equivalentOperatorErrorMessage, isWildcardMatching)); } } @@ -555,7 +559,7 @@ public static async Task ExecuteAsync(string givenInput, Func acti } - private static string GetMessageText(string expectedOutput, string output, string equivalentOperatorErrorMessage = null) + private static string GetMessageText(string expectedOutput, string output, string equivalentOperatorErrorMessage = null, bool isWildcardMatching = false) { string result = ""; @@ -592,6 +596,21 @@ private static string GetMessageText(string expectedOutput, string output, strin } } } + + // If wildcard matching is being used, add detailed line-by-line analysis + if (isWildcardMatching) + { + try + { + var matchResults = WildcardMatchAnalyzer.AnalyzeMatch(expectedOutput, output); + result += WildcardMatchAnalyzer.GenerateDetailedDiff(matchResults); + } + catch + { + // If analysis fails, just use the basic output + } + } + return result; } diff --git a/IntelliTect.TestTools.Console/WildcardMatchAnalyzer.cs b/IntelliTect.TestTools.Console/WildcardMatchAnalyzer.cs new file mode 100644 index 0000000..2ae3086 --- /dev/null +++ b/IntelliTect.TestTools.Console/WildcardMatchAnalyzer.cs @@ -0,0 +1,352 @@ +namespace IntelliTect.TestTools.Console; + +/// +/// Analyzes wildcard pattern matching to provide detailed diff information. +/// +internal static class WildcardMatchAnalyzer +{ + /// + /// Represents the result of matching a single line. + /// + internal class LineMatchResult + { + public bool IsMatch { get; set; } + public string ExpectedLine { get; set; } + public string ActualLine { get; set; } + public List WildcardMatches { get; set; } = new List(); + public string Status => IsMatch ? "✅" : "❌"; + } + + /// + /// Represents what a single wildcard matched. + /// + internal class WildcardMatch + { + public string Pattern { get; set; } // e.g., "*" or "?" + public string MatchedText { get; set; } + public int Position { get; set; } + } + + /// + /// Analyzes wildcard pattern matching line by line and returns detailed results. + /// + public static List AnalyzeMatch(string expectedPattern, string actualText) + { + var results = new List(); + + // Split into lines + string[] expectedLines = SplitIntoLines(expectedPattern); + string[] actualLines = SplitIntoLines(actualText); + + int maxLines = Math.Max(expectedLines.Length, actualLines.Length); + + for (int i = 0; i < maxLines; i++) + { + string expectedLine = i < expectedLines.Length ? expectedLines[i] : null; + string actualLine = i < actualLines.Length ? actualLines[i] : null; + + var lineResult = new LineMatchResult + { + ExpectedLine = expectedLine, + ActualLine = actualLine + }; + + if (expectedLine == null) + { + // Extra line in actual output + lineResult.IsMatch = false; + } + else if (actualLine == null) + { + // Missing line in actual output + lineResult.IsMatch = false; + } + else + { + // Try to match the line and capture what wildcards matched + lineResult.IsMatch = MatchLineWithWildcards(expectedLine, actualLine, lineResult.WildcardMatches); + } + + results.Add(lineResult); + } + + return results; + } + + /// + /// Generates a detailed diff message from the match results. + /// + public static string GenerateDetailedDiff(List matchResults) + { + var sb = new StringBuilder(); + sb.AppendLine(); + sb.AppendLine("Line-by-line comparison:"); + sb.AppendLine("========================"); + + for (int i = 0; i < matchResults.Count; i++) + { + var result = matchResults[i]; + sb.AppendLine(); + sb.AppendLine($"Line {i + 1}: {result.Status}"); + + if (result.ExpectedLine == null) + { + sb.AppendLine($" ⚠️ Unexpected extra line in actual output:"); + sb.AppendLine($" Actual: {EscapeForDisplay(result.ActualLine)}"); + } + else if (result.ActualLine == null) + { + sb.AppendLine($" ⚠️ Missing line in actual output:"); + sb.AppendLine($" Expected: {EscapeForDisplay(result.ExpectedLine)}"); + } + else + { + sb.AppendLine($" Expected: {EscapeForDisplay(result.ExpectedLine)}"); + sb.AppendLine($" Actual: {EscapeForDisplay(result.ActualLine)}"); + + if (result.IsMatch && result.WildcardMatches.Count > 0) + { + sb.AppendLine($" Wildcard matches:"); + foreach (var match in result.WildcardMatches) + { + sb.AppendLine($" '{match.Pattern}' matched: {EscapeForDisplay(match.MatchedText)}"); + } + } + else if (!result.IsMatch) + { + // Try to show where the mismatch occurred + string mismatchInfo = FindMismatchPosition(result.ExpectedLine, result.ActualLine); + if (!string.IsNullOrEmpty(mismatchInfo)) + { + sb.AppendLine($" {mismatchInfo}"); + } + } + } + } + + return sb.ToString(); + } + + /// + /// Tries to match a line with wildcards and captures what each wildcard matched. + /// This is a simplified implementation that tracks * and ? wildcards. + /// + private static bool MatchLineWithWildcards(string pattern, string text, List wildcardMatches) + { + try + { + var wildcardPattern = new WildcardPattern(pattern); + bool isMatch = wildcardPattern.IsMatch(text); + + if (isMatch) + { + // Extract what each wildcard matched + ExtractWildcardMatches(pattern, text, wildcardMatches); + } + + return isMatch; + } + catch + { + return false; + } + } + + /// + /// Extracts what each wildcard in the pattern matched in the text. + /// This uses a greedy approach to match wildcards. + /// + private static void ExtractWildcardMatches(string pattern, string text, List wildcardMatches) + { + int patternPos = 0; + int textPos = 0; + int wildcardIndex = 0; + + while (patternPos < pattern.Length && textPos <= text.Length) + { + char patternChar = pattern[patternPos]; + + if (patternChar == '*') + { + // Find the next non-wildcard character in the pattern + int nextPatternPos = patternPos + 1; + while (nextPatternPos < pattern.Length && (pattern[nextPatternPos] == '*' || pattern[nextPatternPos] == '?')) + { + nextPatternPos++; + } + + if (nextPatternPos >= pattern.Length) + { + // * at the end matches everything remaining + wildcardMatches.Add(new WildcardMatch + { + Pattern = "*", + MatchedText = text.Substring(textPos), + Position = wildcardIndex++ + }); + return; + } + + // Find where the next literal character appears in the text + string remainingPattern = pattern.Substring(nextPatternPos); + int nextLiteralIndex = FindNextLiteralMatch(text, textPos, remainingPattern); + + if (nextLiteralIndex == -1) + { + // Could not find a match for the remaining pattern + wildcardMatches.Add(new WildcardMatch + { + Pattern = "*", + MatchedText = text.Substring(textPos), + Position = wildcardIndex++ + }); + return; + } + + // The * matched everything from textPos to nextLiteralIndex + wildcardMatches.Add(new WildcardMatch + { + Pattern = "*", + MatchedText = text.Substring(textPos, nextLiteralIndex - textPos), + Position = wildcardIndex++ + }); + + textPos = nextLiteralIndex; + patternPos++; + } + else if (patternChar == '?') + { + // ? matches exactly one character + if (textPos < text.Length) + { + wildcardMatches.Add(new WildcardMatch + { + Pattern = "?", + MatchedText = text[textPos].ToString(), + Position = wildcardIndex++ + }); + textPos++; + } + patternPos++; + } + else if (patternChar == '[') + { + // Character class - skip to the closing ] + int closingBracket = pattern.IndexOf(']', patternPos); + if (closingBracket > patternPos && textPos < text.Length) + { + string charClass = pattern.Substring(patternPos, closingBracket - patternPos + 1); + wildcardMatches.Add(new WildcardMatch + { + Pattern = charClass, + MatchedText = text[textPos].ToString(), + Position = wildcardIndex++ + }); + textPos++; + patternPos = closingBracket + 1; + } + else + { + patternPos++; + } + } + else + { + // Literal character - must match exactly + if (textPos < text.Length && text[textPos] == patternChar) + { + textPos++; + } + patternPos++; + } + } + } + + /// + /// Finds the next position where the pattern starts matching in the text. + /// + private static int FindNextLiteralMatch(string text, int startPos, string pattern) + { + // Simple heuristic: find the first non-wildcard character in the pattern + // and search for it in the text + for (int i = 0; i < pattern.Length; i++) + { + char c = pattern[i]; + if (c != '*' && c != '?' && c != '[') + { + // Found a literal character, search for it + int index = text.IndexOf(c, startPos); + if (index >= 0) + { + return index; + } + return -1; + } + } + return -1; // Pattern has no literals + } + + /// + /// Finds the position where pattern and text first differ (for non-wildcard mismatches). + /// + private static string FindMismatchPosition(string expected, string actual) + { + int minLength = Math.Min(expected.Length, actual.Length); + + for (int i = 0; i < minLength; i++) + { + if (expected[i] != actual[i] && expected[i] != '*' && expected[i] != '?') + { + return $"Mismatch at position {i}: expected '{EscapeChar(expected[i])}' but got '{EscapeChar(actual[i])}'"; + } + } + + if (expected.Length != actual.Length) + { + return $"Length mismatch: expected {expected.Length} characters but got {actual.Length}"; + } + + return string.Empty; + } + + /// + /// Splits text into lines, preserving line ending information. + /// + private static string[] SplitIntoLines(string text) + { + if (string.IsNullOrEmpty(text)) + { + return Array.Empty(); + } + + return text.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); + } + + /// + /// Escapes a string for display, showing special characters. + /// + private static string EscapeForDisplay(string text) + { + if (text == null) return ""; + if (text == string.Empty) return ""; + + return text + .Replace("\r", "\\r") + .Replace("\n", "\\n") + .Replace("\t", "\\t"); + } + + /// + /// Escapes a single character for display. + /// + private static string EscapeChar(char c) + { + return c switch + { + '\r' => "\\r", + '\n' => "\\n", + '\t' => "\\t", + _ => c.ToString() + }; + } +} From 3eca483e8eb7dfcde4925e6b52fa0e70dbcf9afe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 8 Feb 2026 07:35:36 +0000 Subject: [PATCH 5/6] Address code review feedback: improve exception handling and add documentation Co-authored-by: BenjaminMichaelis <22186029+BenjaminMichaelis@users.noreply.github.com> --- .../EnhancedErrorMessageTests.cs | 2 +- .../ConsoleAssert.cs | 8 +++++-- .../WildcardMatchAnalyzer.cs | 24 ++++++++++++++++--- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/IntelliTect.TestTools.Console.Tests/EnhancedErrorMessageTests.cs b/IntelliTect.TestTools.Console.Tests/EnhancedErrorMessageTests.cs index e6bd817..91d083e 100644 --- a/IntelliTect.TestTools.Console.Tests/EnhancedErrorMessageTests.cs +++ b/IntelliTect.TestTools.Console.Tests/EnhancedErrorMessageTests.cs @@ -12,7 +12,7 @@ public void ExpectLike_WildcardMismatch_ShowsDetailedDiff() // Arrange - pattern with wildcards that will NOT match string expected = "PING *(::1) 56 data bytes\n64 bytes from *"; - // Act & Assert + // Act & Assert - ConsoleAssert throws System.Exception on mismatch Exception exception = Assert.ThrowsExactly(() => { ConsoleAssert.ExpectLike(expected, () => diff --git a/IntelliTect.TestTools.Console/ConsoleAssert.cs b/IntelliTect.TestTools.Console/ConsoleAssert.cs index 1c0aa45..2fee66c 100644 --- a/IntelliTect.TestTools.Console/ConsoleAssert.cs +++ b/IntelliTect.TestTools.Console/ConsoleAssert.cs @@ -605,9 +605,13 @@ private static string GetMessageText(string expectedOutput, string output, strin var matchResults = WildcardMatchAnalyzer.AnalyzeMatch(expectedOutput, output); result += WildcardMatchAnalyzer.GenerateDetailedDiff(matchResults); } - catch + catch (ArgumentException) { - // If analysis fails, just use the basic output + // Pattern analysis failed - skip detailed diff + } + catch (InvalidOperationException) + { + // Analysis encountered an unexpected state - skip detailed diff } } diff --git a/IntelliTect.TestTools.Console/WildcardMatchAnalyzer.cs b/IntelliTect.TestTools.Console/WildcardMatchAnalyzer.cs index 2ae3086..ae6516f 100644 --- a/IntelliTect.TestTools.Console/WildcardMatchAnalyzer.cs +++ b/IntelliTect.TestTools.Console/WildcardMatchAnalyzer.cs @@ -11,8 +11,17 @@ internal static class WildcardMatchAnalyzer internal class LineMatchResult { public bool IsMatch { get; set; } + + /// + /// The expected line pattern. Null if this line exists in actual output but not in expected. + /// public string ExpectedLine { get; set; } + + /// + /// The actual line text. Null if this line exists in expected output but not in actual. + /// public string ActualLine { get; set; } + public List WildcardMatches { get; set; } = new List(); public string Status => IsMatch ? "✅" : "❌"; } @@ -22,8 +31,16 @@ internal class LineMatchResult /// internal class WildcardMatch { - public string Pattern { get; set; } // e.g., "*" or "?" - public string MatchedText { get; set; } + /// + /// The wildcard pattern (e.g., "*", "?", or "[...]"). + /// + public string Pattern { get; set; } = string.Empty; + + /// + /// The text that was matched by this wildcard. + /// + public string MatchedText { get; set; } = string.Empty; + public int Position { get; set; } } @@ -146,8 +163,9 @@ private static bool MatchLineWithWildcards(string pattern, string text, List Date: Sun, 8 Feb 2026 07:38:16 +0000 Subject: [PATCH 6/6] Add clarifying comments for wildcard matching detection Co-authored-by: BenjaminMichaelis <22186029+BenjaminMichaelis@users.noreply.github.com> --- IntelliTect.TestTools.Console/ConsoleAssert.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/IntelliTect.TestTools.Console/ConsoleAssert.cs b/IntelliTect.TestTools.Console/ConsoleAssert.cs index 2fee66c..7d99de2 100644 --- a/IntelliTect.TestTools.Console/ConsoleAssert.cs +++ b/IntelliTect.TestTools.Console/ConsoleAssert.cs @@ -468,7 +468,8 @@ private static void AssertExpectation(string expectedOutput, string output, Func bool failTest = !areEquivalentOperator(expectedOutput, output); if (failTest) { - // Check if we're using wildcard matching + // Check if we're using wildcard matching by examining the error message + // Wildcard matching operations use the specific message: "The values are not like (using wildcards) each other" bool isWildcardMatching = equivalentOperatorErrorMessage?.Contains("wildcard") == true || equivalentOperatorErrorMessage?.Contains("like") == true;