diff --git a/src/NUnit.Xml.TestLogger/TestCaseNameParser.cs b/src/NUnit.Xml.TestLogger/TestCaseNameParser.cs index fcfa261..6105203 100644 --- a/src/NUnit.Xml.TestLogger/TestCaseNameParser.cs +++ b/src/NUnit.Xml.TestLogger/TestCaseNameParser.cs @@ -56,6 +56,7 @@ public static ParsedName Parse(string fullyQualifedName) var step = NameParseStep.FindMethod; var state = NameParseState.Default; + var parenthesisCount = 0; var output = new List(); @@ -71,13 +72,23 @@ public static ParsedName Parse(string fullyQualifedName) } else if (state == NameParseState.Default) { - if (thisChar == '(' || thisChar == '"' || thisChar == '\\') + if (thisChar == '(') + { + parenthesisCount--; + } + + // Backslashes allowed only inside parenthesis block + if ((thisChar == '\\') && (parenthesisCount == 0)) + { + throw new Exception("Found invalid characters"); + } + else if (thisChar == '"') { throw new Exception("Found invalid characters"); } else if (thisChar == ')') { - if (output.Count > 0) + if ((output.Count > 0) && (parenthesisCount == 0)) { throw new Exception("The closing parenthesis we detected wouldn't be the last character in the output string. This isn't acceptable because we aren't in a string"); } @@ -125,7 +136,7 @@ public static ParsedName Parse(string fullyQualifedName) { if (thisChar == ')') { - throw new Exception("Found invalid characters"); + parenthesisCount++; } if (thisChar == '(') @@ -157,6 +168,11 @@ public static ParsedName Parse(string fullyQualifedName) } } + if (parenthesisCount != 0) + { + throw new Exception($"Unbalanced count of parentheses found ({parenthesisCount})"); + } + // We are done. If we are finding type, set that variable. // Otherwise, ther was some issue, so leave the type blank. if (step == NameParseStep.FindNamespace) diff --git a/test/NUnit.Xml.TestLogger.UnitTests/TestCaseNameParserTests.cs b/test/NUnit.Xml.TestLogger.UnitTests/TestCaseNameParserTests.cs index 7308dc7..e48408e 100644 --- a/test/NUnit.Xml.TestLogger.UnitTests/TestCaseNameParserTests.cs +++ b/test/NUnit.Xml.TestLogger.UnitTests/TestCaseNameParserTests.cs @@ -30,6 +30,12 @@ public class TestCaseNameParserTests // See nunit.testlogger #66. [DataRow("z.y.x.ape.bar(a\\b)", "z.y.x", "ape", "bar(a\\b)")] + + // Test with tuple arguments + [DataRow("z.a.b((0,1))", "z", "a", "b((0,1))")] + [DataRow("z.a.b((\"arg\",1))", "z", "a", "b((\"arg\",1))")] + [DataRow("z.a.b((0,1),(2,3))", "z", "a", "b((0,1),(2,3))")] + [DataRow("z.a.b((0,(0,1)),(0,1))", "z", "a", "b((0,(0,1)),(0,1))")] public void Parse_ParsesAllParsableInputs_WithoutConsoleOutput(string testCaseName, string expectedNamespace, string expectedType, string expectedMethod) { var expected = new Tuple(expectedType, expectedMethod); @@ -94,6 +100,10 @@ public void Parse_ParsesAllParsableInputsWithoutNamespace_WithConsoleOutput(stri [DataRow("z.y.x.")] [DataRow("z.y.x.)")] [DataRow("z.y.x.\"\")")] + [DataRow("z.a.b((0,1)")] + [DataRow("z.a.b((0,1)))")] + [DataRow("z.a.b((0,(0,1))")] + [DataRow("z.a.b((0,(0,1))))")] public void Parse_FailsGracefullyOnNonParsableInputs_WithConsoleOutput(string testCaseName) { var expectedConsole = string.Format(