diff --git a/src/Umbraco.Core/StringExtensions.cs b/src/Umbraco.Core/StringExtensions.cs index 4847df3fc4..0b0c76f620 100644 --- a/src/Umbraco.Core/StringExtensions.cs +++ b/src/Umbraco.Core/StringExtensions.cs @@ -1084,7 +1084,7 @@ namespace Umbraco.Core var cases2 = cases.ToCleanStringType() & CleanStringType.CaseMask; return legacy != null ? legacy.LegacyConvertStringCase(phrase, cases2) - : helper.CleanString(phrase, CleanStringType.Ascii | CleanStringType.Alias | cases2); + : helper.CleanString(phrase, CleanStringType.Ascii | CleanStringType.ConvertCase | cases2); } // the new methods to clean a string (to alias, url segment...) diff --git a/src/Umbraco.Core/Strings/CleanStringType.cs b/src/Umbraco.Core/Strings/CleanStringType.cs index f681c42d4a..4c53be4cb8 100644 --- a/src/Umbraco.Core/Strings/CleanStringType.cs +++ b/src/Umbraco.Core/Strings/CleanStringType.cs @@ -14,25 +14,6 @@ namespace Umbraco.Core.Strings // note: you have 32 bits at your disposal // 0xffffffff - - // masks - - /// - /// Flag mask for casing. - /// - CaseMask = 0x3f, // 0xff - 8 possible values - - /// - /// Flag mask for encoding. - /// - CodeMask = 0x700, // 0xff00 - 8 possible values - - /// - /// Flag mask for role. - /// - RoleMask = 0x070000, // 0xff0000 - 8 possible values - - // no value /// @@ -43,6 +24,11 @@ namespace Umbraco.Core.Strings // casing values + /// + /// Flag mask for casing. + /// + CaseMask = PascalCase | CamelCase | Unchanged | LowerCase | UpperCase | UmbracoCase, + /// /// Pascal casing eg "PascalCase". /// @@ -78,6 +64,11 @@ namespace Umbraco.Core.Strings // encoding values + /// + /// Flag mask for encoding. + /// + CodeMask = Unicode | Utf8 | Ascii, + /// /// Unicode encoding. /// @@ -97,6 +88,11 @@ namespace Umbraco.Core.Strings // role values + /// + /// Flag mask for role. + /// + RoleMask = UrlSegment | Alias | FileName | ConvertCase, + /// /// Url role. /// @@ -110,6 +106,11 @@ namespace Umbraco.Core.Strings /// /// FileName role. /// - FileName = 0x040000 + FileName = 0x040000, + + /// + /// ConvertCase role. + /// + ConvertCase = 0x080000 } } diff --git a/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs b/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs index 25abba7232..92d82c9a6b 100644 --- a/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs +++ b/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs @@ -1,4 +1,8 @@ -using System; + +// debugging - define to write cleaning details & steps to console +#define WRTCONS + +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -160,6 +164,12 @@ namespace Umbraco.Core.Strings : (char.IsLetterOrDigit(c) || c == '_'), // letter, digit or underscore StringType = CleanStringType.Ascii | CleanStringType.UmbracoCase, BreakTermsOnUpper = false + }).WithConfig(CleanStringType.ConvertCase, new Config + { + PreFilter = null, + IsTerm = (c, leading) => char.IsLetterOrDigit(c) || c == '_', // letter, digit or underscore + StringType = CleanStringType.Ascii, + BreakTermsOnUpper = true }); } @@ -487,6 +497,10 @@ function validateSafeAlias(id, value, immediate, callback) {{ if (culture == null) throw new ArgumentNullException("culture"); +#if WRTCONS + Console.WriteLine("STRING TYPE {0}", stringType); +#endif + // get config var config = GetConfig(stringType, culture); stringType = config.StringTypeExtend(stringType); @@ -554,6 +568,9 @@ function validateSafeAlias(id, value, immediate, callback) {{ var state = StateBreak; caseType &= CleanStringType.CaseMask; +#if WRTCONS + Console.WriteLine("CASE {0}", caseType); +#endif // if we apply global ToUpper or ToLower to text here // then we cannot break words on uppercase chars @@ -579,13 +596,13 @@ function validateSafeAlias(id, value, immediate, callback) {{ var isPair = char.IsSurrogate(c); if (isPair) throw new NotSupportedException("Surrogate pairs are not supported."); - - //Console.WriteLine("CHAR '{0}' {1} {2} - {3} - {4}/{5} {6}", - // c, - // isTerm ? "term" : "!term", isUpper ? "upper" : "!upper", - // state, - // i, ipos, leading ? "leading" : "!leading"); - +#if WRTCONS + Console.WriteLine("CHAR '{0}' {1} {2} - {3} - {4}/{5} {6}", + c, + isTerm ? "term" : "!term", isUpper ? "upper" : "!upper", + state, + i, ipos, leading ? "leading" : "!leading"); +#endif switch (state) { // within a break @@ -692,11 +709,12 @@ function validateSafeAlias(id, value, immediate, callback) {{ CleanStringType caseType, CultureInfo culture, bool isAcronym) { var term = input.Substring(ipos, len); - //Console.WriteLine("TERM \"{0}\" {1} {2}", - // term, - // isAcronym ? "acronym" : "word", - // caseType); - +#if WRTCONS + Console.WriteLine("TERM \"{0}\" {1} {2}", + term, + isAcronym ? "acronym" : "word", + caseType); +#endif if (isAcronym) { if ((caseType == CleanStringType.CamelCase && len <= 2 && opos > 0) || diff --git a/src/Umbraco.Tests/CoreStrings/DefaultShortStringHelperTests.cs b/src/Umbraco.Tests/CoreStrings/DefaultShortStringHelperTests.cs index f8b5808681..64a432e815 100644 --- a/src/Umbraco.Tests/CoreStrings/DefaultShortStringHelperTests.cs +++ b/src/Umbraco.Tests/CoreStrings/DefaultShortStringHelperTests.cs @@ -6,8 +6,12 @@ using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; +using Moq; using NUnit.Framework; +using umbraco; using Umbraco.Core; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Strings; using Umbraco.Core.ObjectResolution; using Umbraco.Tests.TestHelpers; @@ -65,6 +69,13 @@ namespace Umbraco.Tests.CoreStrings PreFilter = WhiteQuotes, IsTerm = (c, leading) => leading ? char.IsLetter(c) : char.IsLetterOrDigit(c), StringType = CleanStringType.UmbracoCase | CleanStringType.Ascii + }) + .WithConfig(CleanStringType.ConvertCase, new DefaultShortStringHelper.Config + { + PreFilter = null, + IsTerm = (c, leading) => char.IsLetterOrDigit(c) || c == '_', // letter, digit or underscore + StringType = CleanStringType.Ascii, + BreakTermsOnUpper = true }); ShortStringHelperResolver.Reset(); @@ -98,9 +109,30 @@ namespace Umbraco.Tests.CoreStrings return s; } + [Test] + public void U4_4055_4056() + { + var settings = SettingsForTests.GenerateMockSettings(); + var contentMock = Mock.Get(settings.RequestHandler); + contentMock.Setup(x => x.CharCollection).Returns(Enumerable.Empty()); + contentMock.Setup(x => x.ConvertUrlsToAscii).Returns(false); + SettingsForTests.ConfigureSettings(settings); + + const string input = "publishedVersion"; + + Assert.AreEqual("PublishedVersion", input.ConvertCase(StringAliasCaseType.PascalCase)); // obsolete, use the one below + Assert.AreEqual("PublishedVersion", input.ToCleanString(CleanStringType.ConvertCase | CleanStringType.PascalCase | CleanStringType.Ascii)); // role, case and code + } + [Test] public void U4_4056() { + var settings = SettingsForTests.GenerateMockSettings(); + var contentMock = Mock.Get(settings.RequestHandler); + contentMock.Setup(x => x.CharCollection).Returns(Enumerable.Empty()); + contentMock.Setup(x => x.ConvertUrlsToAscii).Returns(false); + SettingsForTests.ConfigureSettings(settings); + const string input = "ÆØÅ and æøå and 中文测试 and אודות האתר and größer БбДдЖж page"; var helper = new DefaultShortStringHelper().WithDefaultConfig(); // unicode @@ -381,6 +413,12 @@ namespace Umbraco.Tests.CoreStrings [Test] public void CleanStringDefaultConfig() { + var settings = SettingsForTests.GenerateMockSettings(); + var contentMock = Mock.Get(settings.RequestHandler); + contentMock.Setup(x => x.CharCollection).Returns(Enumerable.Empty()); + contentMock.Setup(x => x.ConvertUrlsToAscii).Returns(false); + SettingsForTests.ConfigureSettings(settings); + var helper = new DefaultShortStringHelper().WithDefaultConfig(); const string input = "0123 中文测试 中文测试 léger ZÔRG (2) a?? *x";