From 661838897337d8c2f041cd68d6dd55d7ece9b218 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 8 Feb 2018 12:10:57 +0100 Subject: [PATCH 1/7] Fix for not being able to save decimal value --- src/Umbraco.Core/ObjectExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs index ccd379f7d2..0f5d344a00 100644 --- a/src/Umbraco.Core/ObjectExtensions.cs +++ b/src/Umbraco.Core/ObjectExtensions.cs @@ -212,7 +212,7 @@ namespace Umbraco.Core var convertible2 = input as IConvertible; if (convertible2 != null) { - return Attempt.Succeed(Convert.ChangeType(convertible2, target)); + return Attempt.Succeed(Convert.ChangeType(convertible2, Nullable.GetUnderlyingType(target) ?? target)); } } catch (Exception e) From 84265a9716bbca27e09af83849500070802223e8 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 8 Feb 2018 12:18:51 +0100 Subject: [PATCH 2/7] Fix checkbox in nested content --- src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs b/src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs index 66a316fd0f..224dcfa67b 100644 --- a/src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Linq; using System.Xml.Linq; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Umbraco.Core.Logging; using Umbraco.Core.Manifest; using Umbraco.Core.Models; @@ -248,7 +248,7 @@ namespace Umbraco.Core.PropertyEditors return null; } - var result = TryConvertValueToCrlType(editorValue.Value); + var result = TryConvertValueToCrlType((editorValue.Value != null && editorValue.Value.GetType() == typeof(JValue)) ? editorValue.Value.ToString() : editorValue.Value); if (result.Success == false) { LogHelper.Warn("The value " + editorValue.Value + " cannot be converted to the type " + GetDatabaseType()); @@ -391,4 +391,4 @@ namespace Umbraco.Core.PropertyEditors } } } -} \ No newline at end of file +} From 151c35bc4754fc8450ee7f62a413d0a0ddf74e6e Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 8 Feb 2018 13:15:43 +0100 Subject: [PATCH 3/7] Moving check to TryToConvertValueToCrlType --- src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs b/src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs index 224dcfa67b..28adeb7663 100644 --- a/src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs @@ -176,6 +176,12 @@ namespace Umbraco.Core.PropertyEditors /// internal Attempt TryConvertValueToCrlType(object value) { + var jv = value as JValue; + if (jv != null) + { + value = value.ToString(); + } + //this is a custom check to avoid any errors, if it's a string and it's empty just make it null var s = value as string; if (s != null) @@ -248,7 +254,7 @@ namespace Umbraco.Core.PropertyEditors return null; } - var result = TryConvertValueToCrlType((editorValue.Value != null && editorValue.Value.GetType() == typeof(JValue)) ? editorValue.Value.ToString() : editorValue.Value); + var result = TryConvertValueToCrlType(editorValue.Value); if (result.Success == false) { LogHelper.Warn("The value " + editorValue.Value + " cannot be converted to the type " + GetDatabaseType()); From 4423571eaa913bb18626325b9ce760d58e075661 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 8 Feb 2018 16:21:09 +0100 Subject: [PATCH 4/7] Added ConvertToNullableDecimalTest and check that fixes the decimal save issue --- src/Umbraco.Core/ObjectExtensions.cs | 7 ++++- src/Umbraco.Tests/TryConvertToTests.cs | 36 ++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs index 0f5d344a00..24c74e2887 100644 --- a/src/Umbraco.Core/ObjectExtensions.cs +++ b/src/Umbraco.Core/ObjectExtensions.cs @@ -156,6 +156,11 @@ namespace Umbraco.Core if (inner.Success) { input = inner.Result; // Now fall on through... + + if (input is decimal) + { + target = underlying; + } } else { @@ -212,7 +217,7 @@ namespace Umbraco.Core var convertible2 = input as IConvertible; if (convertible2 != null) { - return Attempt.Succeed(Convert.ChangeType(convertible2, Nullable.GetUnderlyingType(target) ?? target)); + return Attempt.Succeed(Convert.ChangeType(convertible2, target)); } } catch (Exception e) diff --git a/src/Umbraco.Tests/TryConvertToTests.cs b/src/Umbraco.Tests/TryConvertToTests.cs index 7116d98038..ee9fd0870b 100644 --- a/src/Umbraco.Tests/TryConvertToTests.cs +++ b/src/Umbraco.Tests/TryConvertToTests.cs @@ -94,6 +94,42 @@ namespace Umbraco.Tests Assert.AreEqual(100m, conv.Result); } + [Test] + public void ConvertToNullableDecimalTest() + { + var conv = "100".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100m, conv.Result); + + conv = "100.000".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100m, conv.Result); + + conv = "100,000".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100m, conv.Result); + + conv = "100.001".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100.001m, conv.Result); + + conv = 100m.TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100m, conv.Result); + + conv = 100.000m.TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100m, conv.Result); + + conv = 100.001m.TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100.001m, conv.Result); + + conv = 100.TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100m, conv.Result); + } + [Test] public void ConvertToDateTimeTest() { From 17b59cc20fd69f8ea207856116b2ec5ceb2f3684 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 9 Feb 2018 10:02:51 +1100 Subject: [PATCH 5/7] Updates the ObjectExtensions TryConvertTo code and moved all unit tests to ObjectExtensionsTests which now all pass --- src/Umbraco.Core/ObjectExtensions.cs | 22 +-- src/Umbraco.Tests/ObjectExtensionsTests.cs | 160 +++++++++++++++++++-- src/Umbraco.Tests/TryConvertToTests.cs | 141 ------------------ src/Umbraco.Tests/Umbraco.Tests.csproj | 1 - 4 files changed, 164 insertions(+), 160 deletions(-) delete mode 100644 src/Umbraco.Tests/TryConvertToTests.cs diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs index 24c74e2887..7185a19853 100644 --- a/src/Umbraco.Core/ObjectExtensions.cs +++ b/src/Umbraco.Core/ObjectExtensions.cs @@ -143,6 +143,7 @@ namespace Umbraco.Core var inputString = input as string; if (inputString != null) { + //TODO: Why the check against only bool/date when a string is null/empty? In what scenario can we convert to another type when the string is null or empty other than just being null? if (string.IsNullOrEmpty(inputString) && (underlying == typeof(DateTime) || underlying == typeof(bool))) { return Attempt.Succeed(null); @@ -156,11 +157,6 @@ namespace Umbraco.Core if (inner.Success) { input = inner.Result; // Now fall on through... - - if (input is decimal) - { - target = underlying; - } } else { @@ -213,11 +209,19 @@ namespace Umbraco.Core return Attempt.Succeed(outputConverter.ConvertFrom(input)); } + if (target.IsGenericType && GetCachedGenericNullableType(target) != null) + { + // cannot Convert.ChangeType as that does not work with nullable + // input has already been converted to the underlying type - just + // return input, there's an implicit conversion from T to T? anyways + return Attempt.Succeed(input); + } + // Re-check convertables since we altered the input through recursion var convertible2 = input as IConvertible; if (convertible2 != null) { - return Attempt.Succeed(Convert.ChangeType(convertible2, target)); + return Attempt.Succeed(Convert.ChangeType(convertible2, Nullable.GetUnderlyingType(target) ?? target)); } } catch (Exception e) @@ -750,9 +754,9 @@ namespace Umbraco.Core if (AssignableTypeCache.TryGetValue(key, out canConvert)) { return canConvert; - } - - // "object is" is faster than "Type.IsAssignableFrom. + } + + // "object is" is faster than "Type.IsAssignableFrom. // We can use it to very quickly determine whether true/false if (input is IConvertible && target.IsAssignableFrom(source)) { diff --git a/src/Umbraco.Tests/ObjectExtensionsTests.cs b/src/Umbraco.Tests/ObjectExtensionsTests.cs index a2d27b4181..b3b27e30a7 100644 --- a/src/Umbraco.Tests/ObjectExtensionsTests.cs +++ b/src/Umbraco.Tests/ObjectExtensionsTests.cs @@ -6,6 +6,10 @@ using System.Threading; using System.Web.UI.WebControls; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.ObjectResolution; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Strings; +using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests { @@ -155,7 +159,7 @@ namespace Umbraco.Tests Assert.AreEqual("Hello world", result.Result); } - [Test] + [Test] public virtual void CanConvertObjectToSameObject() { var obj = new MyTestObject(); @@ -164,7 +168,142 @@ namespace Umbraco.Tests Assert.AreEqual(obj, result.Result); } - private CultureInfo savedCulture; + [Test] + public void ConvertToIntegerTest() + { + var conv = "100".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100, conv.Result); + + conv = "100.000".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100, conv.Result); + + conv = "100,000".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100, conv.Result); + + // oops + conv = "100.001".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100, conv.Result); + + conv = 100m.TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100, conv.Result); + + conv = 100.000m.TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100, conv.Result); + + // oops + conv = 100.001m.TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100, conv.Result); + } + + [Test] + public void ConvertToDecimalTest() + { + var conv = "100".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100m, conv.Result); + + conv = "100.000".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100m, conv.Result); + + conv = "100,000".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100m, conv.Result); + + conv = "100.001".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100.001m, conv.Result); + + conv = 100m.TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100m, conv.Result); + + conv = 100.000m.TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100m, conv.Result); + + conv = 100.001m.TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100.001m, conv.Result); + + conv = 100.TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100m, conv.Result); + } + + [Test] + public void ConvertToNullableDecimalTest() + { + var conv = "100".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100m, conv.Result); + + conv = "100.000".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100m, conv.Result); + + conv = "100,000".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100m, conv.Result); + + conv = "100.001".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100.001m, conv.Result); + + conv = 100m.TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100m, conv.Result); + + conv = 100.000m.TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100m, conv.Result); + + conv = 100.001m.TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100.001m, conv.Result); + + conv = 100.TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(100m, conv.Result); + } + + [Test] + public void ConvertToDateTimeTest() + { + var conv = "2016-06-07".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(new DateTime(2016, 6, 7), conv.Result); + } + + [Test] + public void ConvertToNullableDateTimeTest() + { + var conv = "2016-06-07".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(new DateTime(2016, 6, 7), conv.Result); + } + + [Test] + public void Value_Editor_Can_Convert_Decimal_To_Decimal_Clr_Type() + { + var valueEditor = new PropertyValueEditor + { + ValueType = PropertyEditorValueTypes.Decimal + }; + + var result = valueEditor.TryConvertValueToCrlType(12.34d); + Assert.IsTrue(result.Success); + Assert.AreEqual(12.34d, result.Result); + } + + private CultureInfo _savedCulture; /// /// Run once before each test in derived test fixtures. @@ -172,10 +311,13 @@ namespace Umbraco.Tests [SetUp] public void TestSetup() { - savedCulture = Thread.CurrentThread.CurrentCulture; + _savedCulture = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = new CultureInfo("en-GB"); // make sure the dates parse correctly - return; - } + + var settings = SettingsForTests.GetDefault(); + ShortStringHelperResolver.Current = new ShortStringHelperResolver(new DefaultShortStringHelper(settings).WithDefaultConfig()); + Resolution.Freeze(); + } /// /// Run once after each test in derived test fixtures. @@ -183,9 +325,9 @@ namespace Umbraco.Tests [TearDown] public void TestTearDown() { - Thread.CurrentThread.CurrentCulture = savedCulture; - return; - } + Thread.CurrentThread.CurrentCulture = _savedCulture; + ShortStringHelperResolver.Reset(); + } private class MyTestObject { @@ -195,4 +337,4 @@ namespace Umbraco.Tests } } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Tests/TryConvertToTests.cs b/src/Umbraco.Tests/TryConvertToTests.cs deleted file mode 100644 index ee9fd0870b..0000000000 --- a/src/Umbraco.Tests/TryConvertToTests.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.ObjectResolution; -using Umbraco.Core.Strings; -using Umbraco.Tests.TestHelpers; - -namespace Umbraco.Tests -{ - [TestFixture] - public class TryConvertToTests - { - [SetUp] - public void SetUp() - { - var settings = SettingsForTests.GetDefault(); - ShortStringHelperResolver.Current = new ShortStringHelperResolver(new DefaultShortStringHelper(settings).WithDefaultConfig()); - Resolution.Freeze(); - } - - [TearDown] - public void TearDown() - { - ShortStringHelperResolver.Reset(); - } - - [Test] - public void ConvertToIntegerTest() - { - var conv = "100".TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100, conv.Result); - - conv = "100.000".TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100, conv.Result); - - conv = "100,000".TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100, conv.Result); - - // oops - conv = "100.001".TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100, conv.Result); - - conv = 100m.TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100, conv.Result); - - conv = 100.000m.TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100, conv.Result); - - // oops - conv = 100.001m.TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100, conv.Result); - } - - [Test] - public void ConvertToDecimalTest() - { - var conv = "100".TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100m, conv.Result); - - conv = "100.000".TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100m, conv.Result); - - conv = "100,000".TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100m, conv.Result); - - conv = "100.001".TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100.001m, conv.Result); - - conv = 100m.TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100m, conv.Result); - - conv = 100.000m.TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100m, conv.Result); - - conv = 100.001m.TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100.001m, conv.Result); - - conv = 100.TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100m, conv.Result); - } - - [Test] - public void ConvertToNullableDecimalTest() - { - var conv = "100".TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100m, conv.Result); - - conv = "100.000".TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100m, conv.Result); - - conv = "100,000".TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100m, conv.Result); - - conv = "100.001".TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100.001m, conv.Result); - - conv = 100m.TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100m, conv.Result); - - conv = 100.000m.TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100m, conv.Result); - - conv = 100.001m.TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100.001m, conv.Result); - - conv = 100.TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(100m, conv.Result); - } - - [Test] - public void ConvertToDateTimeTest() - { - var conv = "2016-06-07".TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(new DateTime(2016, 6, 7), conv.Result); - } - } -} diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 2811ef715f..2e7b1b5e42 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -231,7 +231,6 @@ - From d29b7311faa3c812e081b4a67d2f511a83ccd5ea Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 9 Feb 2018 10:08:25 +1100 Subject: [PATCH 6/7] reverts the convertible2 back to what it was before --- src/Umbraco.Core/ObjectExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs index 7185a19853..185a75fac9 100644 --- a/src/Umbraco.Core/ObjectExtensions.cs +++ b/src/Umbraco.Core/ObjectExtensions.cs @@ -221,7 +221,7 @@ namespace Umbraco.Core var convertible2 = input as IConvertible; if (convertible2 != null) { - return Attempt.Succeed(Convert.ChangeType(convertible2, Nullable.GetUnderlyingType(target) ?? target)); + return Attempt.Succeed(Convert.ChangeType(convertible2, target)); } } catch (Exception e) From c63156fcd808047dd15efe874015889f8710d5ab Mon Sep 17 00:00:00 2001 From: Sebastiaan Jansssen Date: Fri, 9 Feb 2018 09:46:05 +0100 Subject: [PATCH 7/7] Bump version to 7.7.11 (cherry picked from commit 0c25c36af04bd633f2ad1808bbce24308714cd79) --- src/SolutionInfo.cs | 4 ++-- src/Umbraco.Core/Configuration/UmbracoVersion.cs | 2 +- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index 2f9911bfbe..335d5fb8b8 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -11,5 +11,5 @@ using System.Resources; [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("7.7.10")] -[assembly: AssemblyInformationalVersion("7.7.10")] \ No newline at end of file +[assembly: AssemblyFileVersion("7.7.11")] +[assembly: AssemblyInformationalVersion("7.7.11")] \ No newline at end of file diff --git a/src/Umbraco.Core/Configuration/UmbracoVersion.cs b/src/Umbraco.Core/Configuration/UmbracoVersion.cs index f4a6dd9377..7542e77002 100644 --- a/src/Umbraco.Core/Configuration/UmbracoVersion.cs +++ b/src/Umbraco.Core/Configuration/UmbracoVersion.cs @@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration { public class UmbracoVersion { - private static readonly Version Version = new Version("7.7.10"); + private static readonly Version Version = new Version("7.7.11"); /// /// Gets the current version of Umbraco. diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 7e215fca26..e0c7fcec6a 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -1023,9 +1023,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\" True True - 7710 + 7711 / - http://localhost:7710 + http://localhost:7711 False False