diff --git a/Parser/SpecFlowUnitTestConverter.cs b/Parser/SpecFlowUnitTestConverter.cs index 973f49d19..b3eb2cf9d 100644 --- a/Parser/SpecFlowUnitTestConverter.cs +++ b/Parser/SpecFlowUnitTestConverter.cs @@ -295,7 +295,7 @@ private void GenerateScenarioOutlineTest(CodeTypeDeclaration testType, CodeMembe for (int rowIndex = 0; rowIndex < exampleSet.Table.Body.Length; rowIndex++) { - string variantName = useFirstColumnAsName ? exampleSet.Table.Body[rowIndex].Cells[0].Value.ToIdentifier() : + string variantName = useFirstColumnAsName ? exampleSet.Table.Body[rowIndex].Cells[0].Value.ToIdentifierPart() : string.Format("Variant{0}", rowIndex); GenerateScenarioOutlineTestVariant(testType, scenarioOutline, testMethodName, paramToIdentifier, exampleSetTitle, exampleSet.Table.Body[rowIndex], variantName); } diff --git a/Runtime/StringExtensions.cs b/Runtime/StringExtensions.cs index a201b6ebd..a2a4205f1 100644 --- a/Runtime/StringExtensions.cs +++ b/Runtime/StringExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; @@ -18,35 +19,39 @@ public static string Indent(this string text, string indent) public static string ToIdentifier(this string text) { - Regex firstWordCharRe = new Regex(@"(?
[^\p{Ll}\p{Lu}]+)(?[\p{Ll}\p{Lu}])"); - text = firstWordCharRe.Replace(text, match => match.Groups["pre"].Value + match.Groups["fc"].Value.ToUpper()); - - Regex punctCharRe = new Regex(@"[\n\.-]+"); - text = punctCharRe.Replace(text, "_"); + string identifier = ToIdentifierPart(text); + if (identifier.Length > 0 && char.IsDigit(identifier[0])) + identifier = "_" + identifier; - Regex nonWordCharRe = new Regex(@"[^a-zA-Z0-9_]+"); - text = nonWordCharRe.Replace(text, ""); - - if (text.Length > 0) - { - text = text.Substring(0, 1).ToUpper() + text.Substring(1); - - if (char.IsDigit(text[0])) - text = "_" + text; - } - - return text; + return identifier; } public static string ToIdentifierCamelCase(this string text) { string identifier = ToIdentifier(text); - if (text.Length > 0) + if (identifier.Length > 0) identifier = identifier.Substring(0, 1).ToLower() + identifier.Substring(1); return identifier; } + static private readonly Regex firstWordCharRe = new Regex(@"(? [^\p{Ll}\p{Lu}]+)(?[\p{Ll}\p{Lu}])"); + static private readonly Regex punctCharRe = new Regex(@"[\n\.-]+"); + + public static string ToIdentifierPart(this string text) + { + text = firstWordCharRe.Replace(text, match => match.Groups["pre"].Value + match.Groups["fc"].Value.ToUpper()); + + text = punctCharRe.Replace(text, "_"); + + text = RemoveAccentChars(text); + + if (text.Length > 0) + text = text.Substring(0, 1).ToUpper() + text.Substring(1); + + return text; + } + public static string TrimEllipse(this string text, int maxLength) { if (text == null || text.Length <= maxLength) @@ -55,5 +60,138 @@ public static string TrimEllipse(this string text, int maxLength) const string ellipse = "..."; return text.Substring(0, maxLength - ellipse.Length) + ellipse; } + + #region Accent replacements + static private Dictionary accentReplacements = new Dictionary () + { + {"\u00C0", "A"}, + {"\u00C1", "A"}, + {"\u00C2", "A"}, + {"\u00C3", "A"}, + {"\u00C4", "A"}, + {"\u00C5", "A"}, + {"\u00C6", "AE"}, + {"\u00C7", "C"}, + {"\u00C8", "E"}, + {"\u00C9", "E"}, + {"\u00CA", "E"}, + {"\u00CB", "E"}, + {"\u00CC", "I"}, + {"\u00CD", "I"}, + {"\u00CE", "I"}, + {"\u00CF", "I"}, + {"\u00D0", "D"}, + {"\u00D1", "N"}, + {"\u00D2", "O"}, + {"\u00D3", "O"}, + {"\u00D4", "O"}, + {"\u00D5", "O"}, + {"\u00D6", "O"}, + {"\u00D8", "O"}, + {"\u00D9", "U"}, + {"\u00DA", "U"}, + {"\u00DB", "U"}, + {"\u00DC", "U"}, + {"\u00DD", "Y"}, + {"\u00DF", "B"}, + {"\u00E0", "a"}, + {"\u00E1", "a"}, + {"\u00E2", "a"}, + {"\u00E3", "a"}, + {"\u00E4", "a"}, + {"\u00E5", "a"}, + {"\u00E6", "ae"}, + {"\u00E7", "c"}, + {"\u00E8", "e"}, + {"\u00E9", "e"}, + {"\u00EA", "e"}, + {"\u00EB", "e"}, + {"\u00EC", "i"}, + {"\u00ED", "i"}, + {"\u00EE", "i"}, + {"\u00EF", "i"}, + //{"\u00F0", "d"}, + {"\u00F1", "n"}, + {"\u00F2", "o"}, + {"\u00F3", "o"}, + {"\u00F4", "o"}, + {"\u00F5", "o"}, + {"\u00F6", "o"}, + {"\u00F8", "o"}, + {"\u00F9", "u"}, + {"\u00FA", "u"}, + {"\u00FB", "u"}, + {"\u00FC", "u"}, + {"\u00FD", "y"}, + {"\u00FF", "y"}, + + + {"\u0104", "A"}, + {"\u0141", "L"}, + {"\u013D", "L"}, + {"\u015A", "S"}, + {"\u0160", "S"}, + {"\u015E", "S"}, + {"\u0164", "T"}, + {"\u0179", "Z"}, + {"\u017D", "Z"}, + {"\u017B", "Z"}, + {"\u0105", "a"}, + {"\u0142", "l"}, + {"\u013E", "l"}, + {"\u015B", "s"}, + {"\u0161", "s"}, + {"\u015F", "s"}, + {"\u0165", "t"}, + {"\u017A", "z"}, + {"\u017E", "z"}, + {"\u017C", "z"}, + {"\u0154", "R"}, + {"\u0102", "A"}, + {"\u0139", "L"}, + {"\u0106", "C"}, + {"\u010C", "C"}, + {"\u0118", "E"}, + {"\u011A", "E"}, + {"\u010E", "D"}, + {"\u0110", "D"}, + {"\u0143", "N"}, + {"\u0147", "N"}, + {"\u0150", "O"}, + {"\u0158", "R"}, + {"\u016E", "U"}, + {"\u0170", "U"}, + {"\u0162", "T"}, + {"\u0155", "r"}, + {"\u0103", "a"}, + {"\u013A", "l"}, + {"\u0107", "c"}, + {"\u010D", "c"}, + {"\u0119", "e"}, + {"\u011B", "e"}, + {"\u010F", "d"}, + {"\u0111", "d"}, + {"\u0144", "n"}, + {"\u0148", "n"}, + {"\u0151", "o"}, + {"\u0159", "r"}, + {"\u016F", "u"}, + {"\u0171", "u"}, + {"\u0163", "t"}, + }; + #endregion + + static private readonly Regex accentRe = new Regex("[^a-zA-Z0-9_]"); + + private static string RemoveAccentChars(string text) + { + return accentRe.Replace(text, match => + { + string result; + if (accentReplacements.TryGetValue(match.Value, out result)) + return result; + return string.Empty; + }); + } } } \ No newline at end of file diff --git a/changelog.txt b/changelog.txt index dd4dd2ba9..f87c433c2 100644 --- a/changelog.txt +++ b/changelog.txt @@ -12,7 +12,7 @@ New features: Fixed issues: + Runtime: Remove direct dependency on nunit.framework.dll from the runtime (Issue 12) + Runtime: Binding methods with more than 4 parameters cannot be used (Issue 21) - ++ Generator: Special language characters (e.g. accented letters) are removed when generating test method names (Issue 22) 1.0.2 - 2009/10/20