Add default property value converters for all value types (#14869)
* Add default property value converters for all value types * Clean up some left-over stuff
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that this is a default value type property value converter (shipped with Umbraco).
|
||||
/// This attribute is for internal use only. It should never be applied to custom value converters.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
|
||||
public class DefaultValueTypePropertyValueConverterAttribute : DefaultPropertyValueConverterAttribute
|
||||
{
|
||||
}
|
||||
@@ -44,5 +44,15 @@ public class PropertyValueConverterCollection : BuilderCollectionBase<IPropertyV
|
||||
=> DefaultConverters.ContainsKey(converter);
|
||||
|
||||
internal bool Shadows(IPropertyValueConverter shadowing, IPropertyValueConverter shadowed)
|
||||
=> DefaultConverters.TryGetValue(shadowing, out Type[]? types) && types.Contains(shadowed.GetType());
|
||||
{
|
||||
Type shadowedType = shadowed.GetType();
|
||||
|
||||
// any value converter built specifically to convert purely value type bound properties can always be shadowed
|
||||
if (shadowedType.GetCustomAttribute<DefaultValueTypePropertyValueConverterAttribute>(false) is not null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return DefaultConverters.TryGetValue(shadowing, out Type[]? types) && types.Contains(shadowedType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
[DefaultValueTypePropertyValueConverter]
|
||||
public class BigintValueTypeConverter : ValueTypePropertyValueConverterBase
|
||||
{
|
||||
protected override string[] SupportedValueTypes => new[] { ValueTypes.Bigint };
|
||||
|
||||
public BigintValueTypeConverter(PropertyEditorCollection propertyEditors)
|
||||
: base(propertyEditors)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof(long);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object? ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object? source, bool preview)
|
||||
=> source.TryConvertTo<long>().Result;
|
||||
}
|
||||
@@ -17,26 +17,7 @@ public class DatePickerValueConverter : PropertyValueConverterBase
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object? source, bool preview)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
return DateTime.MinValue;
|
||||
}
|
||||
|
||||
// in XML a DateTime is: string - format "yyyy-MM-ddTHH:mm:ss"
|
||||
// Actually, not always sometimes it is formatted in UTC style with 'Z' suffixed on the end but that is due to this bug:
|
||||
// http://issues.umbraco.org/issue/U4-4145, http://issues.umbraco.org/issue/U4-3894
|
||||
// We should just be using TryConvertTo instead.
|
||||
if (source is string sourceString)
|
||||
{
|
||||
Attempt<DateTime> attempt = sourceString.TryConvertTo<DateTime>();
|
||||
return attempt.Success == false ? DateTime.MinValue : attempt.Result;
|
||||
}
|
||||
|
||||
// in the database a DateTime is: DateTime
|
||||
// default value is: DateTime.MinValue
|
||||
return source is DateTime ? source : DateTime.MinValue;
|
||||
}
|
||||
=> ParseDateTimeValue(source);
|
||||
|
||||
// default ConvertSourceToObject just returns source ie a DateTime value
|
||||
[Obsolete("The current implementation of XPath is suboptimal and will be removed entirely in a future version. Scheduled for removal in v14")]
|
||||
@@ -55,4 +36,26 @@ public class DatePickerValueConverter : PropertyValueConverterBase
|
||||
|
||||
return XmlConvert.ToString((DateTime)inter, XmlDateTimeSerializationMode.Unspecified);
|
||||
}
|
||||
|
||||
internal static DateTime ParseDateTimeValue(object? source)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
return DateTime.MinValue;
|
||||
}
|
||||
|
||||
// in XML a DateTime is: string - format "yyyy-MM-ddTHH:mm:ss"
|
||||
// Actually, not always sometimes it is formatted in UTC style with 'Z' suffixed on the end but that is due to this bug:
|
||||
// http://issues.umbraco.org/issue/U4-4145, http://issues.umbraco.org/issue/U4-3894
|
||||
// We should just be using TryConvertTo instead.
|
||||
if (source is string sourceString)
|
||||
{
|
||||
Attempt<DateTime> attempt = sourceString.TryConvertTo<DateTime>();
|
||||
return attempt.Success == false ? DateTime.MinValue : attempt.Result;
|
||||
}
|
||||
|
||||
// in the database a DateTime is: DateTime
|
||||
// default value is: DateTime.MinValue
|
||||
return source is DateTime dateTimeValue ? dateTimeValue : DateTime.MinValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
[DefaultValueTypePropertyValueConverter]
|
||||
public class DateTimeValueTypeConverter : ValueTypePropertyValueConverterBase
|
||||
{
|
||||
protected override string[] SupportedValueTypes => new[] { ValueTypes.Date, ValueTypes.DateTime };
|
||||
|
||||
public DateTimeValueTypeConverter(PropertyEditorCollection propertyEditors)
|
||||
: base(propertyEditors)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof(DateTime);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object? ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object? source, bool preview)
|
||||
=> DatePickerValueConverter.ParseDateTimeValue(source); // reuse the value conversion from the default "Umbraco.DateTime" value converter
|
||||
}
|
||||
@@ -16,6 +16,9 @@ public class DecimalValueConverter : PropertyValueConverterBase
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object? source, bool preview)
|
||||
=> ParseDecimalValue(source);
|
||||
|
||||
internal static decimal ParseDecimalValue(object? source)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
@@ -23,9 +26,9 @@ public class DecimalValueConverter : PropertyValueConverterBase
|
||||
}
|
||||
|
||||
// is it already a decimal?
|
||||
if (source is decimal)
|
||||
if (source is decimal sourceDecimal)
|
||||
{
|
||||
return source;
|
||||
return sourceDecimal;
|
||||
}
|
||||
|
||||
// is it a double?
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
[DefaultValueTypePropertyValueConverter]
|
||||
public class DecimalValueTypeConverter : ValueTypePropertyValueConverterBase
|
||||
{
|
||||
protected override string[] SupportedValueTypes => new[] { ValueTypes.Decimal };
|
||||
|
||||
public DecimalValueTypeConverter(PropertyEditorCollection propertyEditors)
|
||||
: base(propertyEditors)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof(decimal);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object? ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object? source, bool preview)
|
||||
=> DecimalValueConverter.ParseDecimalValue(source); // reuse the value conversion from the default "Umbraco.Decimal" value converter
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
[DefaultValueTypePropertyValueConverter]
|
||||
public class IntegerValueTypeConverter : ValueTypePropertyValueConverterBase
|
||||
{
|
||||
protected override string[] SupportedValueTypes => new[] { ValueTypes.Integer };
|
||||
|
||||
public IntegerValueTypeConverter(PropertyEditorCollection propertyEditors)
|
||||
: base(propertyEditors)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof(int);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object? ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object? source, bool preview)
|
||||
=> source.TryConvertTo<int>().Result;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
[DefaultValueTypePropertyValueConverter]
|
||||
public class TextStringValueTypeConverter : ValueTypePropertyValueConverterBase
|
||||
{
|
||||
protected override string[] SupportedValueTypes => new[] { ValueTypes.Text, ValueTypes.String };
|
||||
|
||||
public TextStringValueTypeConverter(PropertyEditorCollection propertyEditors)
|
||||
: base(propertyEditors)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof(string);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object? ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object? source, bool preview)
|
||||
=> source as string;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
[DefaultValueTypePropertyValueConverter]
|
||||
public class TimeValueTypeConverter : ValueTypePropertyValueConverterBase
|
||||
{
|
||||
protected override string[] SupportedValueTypes => new[] { ValueTypes.Time };
|
||||
|
||||
public TimeValueTypeConverter(PropertyEditorCollection propertyEditors)
|
||||
: base(propertyEditors)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof(TimeSpan);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object? ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object? source, bool preview)
|
||||
=> source is DateTime dateTimeValue ? dateTimeValue.ToUniversalTime().TimeOfDay : null;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
public abstract class ValueTypePropertyValueConverterBase : PropertyValueConverterBase
|
||||
{
|
||||
private readonly PropertyEditorCollection _propertyEditors;
|
||||
|
||||
protected abstract string[] SupportedValueTypes { get; }
|
||||
|
||||
protected ValueTypePropertyValueConverterBase(PropertyEditorCollection propertyEditors)
|
||||
=> _propertyEditors = propertyEditors;
|
||||
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> _propertyEditors.TryGet(propertyType.EditorAlias, out IDataEditor? editor)
|
||||
&& SupportedValueTypes.InvariantContains(editor.GetValueEditor().ValueType);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.PropertyEditors.DeliveryApi;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
[DefaultValueTypePropertyValueConverter]
|
||||
public class XmlValueTypeConverter : ValueTypePropertyValueConverterBase, IDeliveryApiPropertyValueConverter
|
||||
{
|
||||
protected override string[] SupportedValueTypes => new[] { ValueTypes.Xml };
|
||||
|
||||
public XmlValueTypeConverter(PropertyEditorCollection propertyEditors)
|
||||
: base(propertyEditors)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof(XDocument);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object? ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object? source, bool preview)
|
||||
{
|
||||
if (source is not string stringValue)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return XDocument.Parse(stringValue);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public PropertyCacheLevel GetDeliveryApiPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> GetPropertyCacheLevel(propertyType);
|
||||
|
||||
public Type GetDeliveryApiPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof(string);
|
||||
|
||||
// System.Text.Json does not appreciate serializing XDocument because of parent/child node references. Let's settle for outputting the raw XML as a string, then.
|
||||
public object? ConvertIntermediateToDeliveryApiObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object? inter, bool preview, bool expanding)
|
||||
=> inter is XDocument xDocumentValue
|
||||
? xDocumentValue.ToString(SaveOptions.DisableFormatting)
|
||||
: null;
|
||||
}
|
||||
@@ -1,11 +1,7 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
@@ -116,18 +112,12 @@ public class PropertyEditorValueConverterTests
|
||||
}
|
||||
|
||||
[TestCase("1", 1)]
|
||||
[TestCase("1", 1)]
|
||||
[TestCase("0", 0)]
|
||||
[TestCase("0", 0)]
|
||||
[TestCase(null, 0)]
|
||||
[TestCase(null, 0)]
|
||||
[TestCase("-1", -1)]
|
||||
[TestCase("-1", -1)]
|
||||
[TestCase("1.65", 1.65)]
|
||||
[TestCase("1.65", 1.65)]
|
||||
[TestCase("-1.65", -1.65)]
|
||||
[TestCase("-1.65", -1.65)]
|
||||
public void CanConvertDecimalAliasPropertyEditor(object value, double expected)
|
||||
public void CanConvertDecimalAliasPropertyEditor(object value, decimal expected)
|
||||
{
|
||||
var converter = new DecimalValueConverter();
|
||||
var inter = converter.ConvertSourceToIntermediate(null, null, value, false);
|
||||
@@ -136,18 +126,19 @@ public class PropertyEditorValueConverterTests
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanConvertManifestBasedPropertyWithValueTypeJson()
|
||||
[TestCase("100", 100)]
|
||||
[TestCase("0", 0)]
|
||||
[TestCase(null, 0)]
|
||||
[TestCase("-100", -100)]
|
||||
[TestCase("1.65", 2)]
|
||||
[TestCase("-1.65", -2)]
|
||||
[TestCase("something something", 0)]
|
||||
public void CanConvertIntegerAliasPropertyEditor(object value, int expected)
|
||||
{
|
||||
var valueEditor = Mock.Of<IDataValueEditor>(x => x.ValueType == ValueTypes.Json);
|
||||
var dataEditor = Mock.Of<IDataEditor>(x => x.GetValueEditor() == valueEditor);
|
||||
var propertyEditors = new PropertyEditorCollection(new DataEditorCollection(() => new[] { dataEditor }));
|
||||
var propertyType = Mock.Of<IPublishedPropertyType>(x => x.EditorAlias == "My.Custom.Json");
|
||||
var converter = new IntegerValueConverter();
|
||||
var inter = converter.ConvertSourceToIntermediate(null, null, value, false);
|
||||
var result = converter.ConvertIntermediateToObject(null, null, PropertyCacheLevel.Unknown, inter, false);
|
||||
|
||||
var valueConverter = new JsonValueConverter(propertyEditors, Mock.Of<ILogger<JsonValueConverter>>());
|
||||
var inter = valueConverter.ConvertSourceToIntermediate(Mock.Of<IPublishedElement>(), propertyType, "{\"message\": \"Hello, JSON\"}", false);
|
||||
var result = valueConverter.ConvertIntermediateToObject(Mock.Of<IPublishedElement>(), propertyType, PropertyCacheLevel.Element, inter, false) as JObject;
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual("Hello, JSON", result["message"]!.Value<string>());
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors;
|
||||
|
||||
[TestFixture]
|
||||
public class PropertyEditorValueTypeConverterTests
|
||||
{
|
||||
[TestCase("2023-09-26 13:14:15", true)]
|
||||
[TestCase("2023-09-26T13:14:15", true)]
|
||||
[TestCase("2023-09-26T00:00:00", true)]
|
||||
[TestCase("2023-09-26", true)]
|
||||
[TestCase("", false)]
|
||||
[TestCase("Hello, world!", false)]
|
||||
[TestCase(123456, false)]
|
||||
[TestCase(null, false)]
|
||||
public void CanConvertDateValueTypePropertyEditor(object? date, bool expectedSuccess)
|
||||
{
|
||||
var expectedResult = expectedSuccess ? DateTime.Parse((date as string)!) : DateTime.MinValue;
|
||||
var supportedValueTypes = new[] { ValueTypes.DateTime, ValueTypes.Date };
|
||||
foreach (var valueType in supportedValueTypes)
|
||||
{
|
||||
var converter = new DateTimeValueTypeConverter(ValueTypePropertyEditorCollection(valueType));
|
||||
var propertyType = PropertyType();
|
||||
|
||||
Assert.IsTrue(converter.IsConverter(propertyType));
|
||||
|
||||
var result = converter.ConvertSourceToIntermediate(null, propertyType, date, false);
|
||||
|
||||
Assert.AreEqual(expectedResult, result);
|
||||
}
|
||||
}
|
||||
|
||||
[TestCase("1", 1)]
|
||||
[TestCase("0", 0)]
|
||||
[TestCase(null, 0)]
|
||||
[TestCase("", 0)]
|
||||
[TestCase("Hello, world!", 0)]
|
||||
[TestCase("-1", -1)]
|
||||
[TestCase("1.65", 1.65)]
|
||||
[TestCase("-1.65", -1.65)]
|
||||
public void CanConvertDecimalValueTypePropertyEditor(object value, decimal expected)
|
||||
{
|
||||
var propertyEditors = ValueTypePropertyEditorCollection(ValueTypes.Decimal);
|
||||
var propertyType = PropertyType();
|
||||
|
||||
var converter = new DecimalValueTypeConverter(propertyEditors);
|
||||
var inter = converter.ConvertSourceToIntermediate(Mock.Of<IPublishedElement>(), propertyType, value, false);
|
||||
|
||||
Assert.IsTrue(converter.IsConverter(propertyType));
|
||||
|
||||
var result = converter.ConvertIntermediateToObject(Mock.Of<IPublishedElement>(), propertyType, PropertyCacheLevel.Element, inter, false);
|
||||
Assert.IsTrue(result is decimal);
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
|
||||
[TestCase("100", 100)]
|
||||
[TestCase("0", 0)]
|
||||
[TestCase(null, 0)]
|
||||
[TestCase("", 0)]
|
||||
[TestCase("Hello, world!", 0)]
|
||||
[TestCase("-100", -100)]
|
||||
[TestCase("1.65", 2)]
|
||||
[TestCase("-1.65", -2)]
|
||||
public void CanConvertIntegerValueTypePropertyEditor(object value, int expected)
|
||||
{
|
||||
var propertyEditors = ValueTypePropertyEditorCollection(ValueTypes.Integer);
|
||||
var propertyType = PropertyType();
|
||||
|
||||
var converter = new IntegerValueTypeConverter(propertyEditors);
|
||||
var inter = converter.ConvertSourceToIntermediate(Mock.Of<IPublishedElement>(), propertyType, value, false);
|
||||
|
||||
Assert.IsTrue(converter.IsConverter(propertyType));
|
||||
|
||||
var result = converter.ConvertIntermediateToObject(Mock.Of<IPublishedElement>(), propertyType, PropertyCacheLevel.Element, inter, false);
|
||||
Assert.IsTrue(result is int);
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
|
||||
[TestCase("100", 100)]
|
||||
[TestCase("0", 0)]
|
||||
[TestCase(null, 0)]
|
||||
[TestCase("", 0)]
|
||||
[TestCase("Hello, world!", 0)]
|
||||
[TestCase("-100", -100)]
|
||||
[TestCase("1.65", 2)]
|
||||
[TestCase("-1.65", -2)]
|
||||
public void CanConvertBigintValueTypePropertyEditor(object value, long expected)
|
||||
{
|
||||
var propertyEditors = ValueTypePropertyEditorCollection(ValueTypes.Bigint);
|
||||
var propertyType = PropertyType();
|
||||
|
||||
var converter = new BigintValueTypeConverter(propertyEditors);
|
||||
var inter = converter.ConvertSourceToIntermediate(Mock.Of<IPublishedElement>(), propertyType, value, false);
|
||||
|
||||
Assert.IsTrue(converter.IsConverter(propertyType));
|
||||
|
||||
var result = converter.ConvertIntermediateToObject(Mock.Of<IPublishedElement>(), propertyType, PropertyCacheLevel.Element, inter, false);
|
||||
Assert.IsTrue(result is long);
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
|
||||
[TestCase("100", "100")]
|
||||
[TestCase("0", "0")]
|
||||
[TestCase(null, null)]
|
||||
[TestCase("", "")]
|
||||
[TestCase("Hello, world!", "Hello, world!")]
|
||||
[TestCase(-100, null)]
|
||||
[TestCase(1.65, null)]
|
||||
public void CanConvertTextAndStringValueTypePropertyEditor(object? value, string? expected)
|
||||
{
|
||||
var scenarios = new[] { ValueTypes.Text, ValueTypes.String };
|
||||
foreach (var scenario in scenarios)
|
||||
{
|
||||
var propertyEditors = ValueTypePropertyEditorCollection(scenario);
|
||||
var propertyType = PropertyType();
|
||||
|
||||
var converter = new TextStringValueTypeConverter(propertyEditors);
|
||||
var inter = converter.ConvertSourceToIntermediate(Mock.Of<IPublishedElement>(), propertyType, value, false);
|
||||
|
||||
Assert.IsTrue(converter.IsConverter(propertyType));
|
||||
|
||||
var result = converter.ConvertIntermediateToObject(Mock.Of<IPublishedElement>(), propertyType, PropertyCacheLevel.Element, inter, false);
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
}
|
||||
|
||||
[TestCase("2023-01-01T03:04:00Z","03:04:00")]
|
||||
[TestCase("2023-01-01T13:14:00Z", "13:14:00")]
|
||||
[TestCase("2023-01-01T13:14:15Z", "13:14:15")]
|
||||
[TestCase("2023-01-01T13:14:15.678Z", "13:14:15.678")]
|
||||
[TestCase("", null)]
|
||||
[TestCase("Hello, world!", null)]
|
||||
[TestCase(123456, null)]
|
||||
[TestCase(null, null)]
|
||||
public void CanConvertTimeValueTypePropertyEditor(object? value, object? expectedTime)
|
||||
{
|
||||
var sourceValue = expectedTime is not null ? DateTime.Parse((value as string)!) : value;
|
||||
TimeSpan? expectedResult = expectedTime is not null ? TimeSpan.Parse((expectedTime as string)!) : null;
|
||||
var propertyEditors = ValueTypePropertyEditorCollection(ValueTypes.Time);
|
||||
var converter = new TimeValueTypeConverter(propertyEditors);
|
||||
var propertyType = PropertyType();
|
||||
|
||||
Assert.IsTrue(converter.IsConverter(propertyType));
|
||||
|
||||
var result = converter.ConvertSourceToIntermediate(null, propertyType, sourceValue, false);
|
||||
Assert.AreEqual(expectedResult, result);
|
||||
}
|
||||
|
||||
[TestCase("<root>test</root>", true)]
|
||||
[TestCase("<root><child>child 1</child><child>child 2</child></root>", true)]
|
||||
[TestCase("<root><child>malformed XML<child><root>", false)]
|
||||
[TestCase("", false)]
|
||||
[TestCase("Hello, world!", false)]
|
||||
[TestCase(123456, false)]
|
||||
[TestCase(null, false)]
|
||||
public void CanConvertXmlValueTypePropertyEditor(object? value, bool expectsSuccess)
|
||||
{
|
||||
var propertyEditors = ValueTypePropertyEditorCollection(ValueTypes.Xml);
|
||||
var converter = new XmlValueTypeConverter(propertyEditors);
|
||||
var propertyType = PropertyType();
|
||||
|
||||
Assert.IsTrue(converter.IsConverter(propertyType));
|
||||
|
||||
var result = converter.ConvertSourceToIntermediate(null, propertyType, value, false) as XDocument;
|
||||
if (expectsSuccess)
|
||||
{
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(value, result.ToString(SaveOptions.DisableFormatting));
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.IsNull(result);
|
||||
}
|
||||
}
|
||||
|
||||
[TestCase("{\"message\":\"Hello, JSON\"}", true)]
|
||||
[TestCase("{\"nested\":{\"message\":\"Hello, Nested\"}}", true)]
|
||||
[TestCase("{\"nested\":{\"invalid JSON", false)]
|
||||
[TestCase("", false)]
|
||||
[TestCase("Hello, world!", false)]
|
||||
[TestCase(123456, false)]
|
||||
[TestCase(null, false)]
|
||||
public void CanConvertJsonValueTypePropertyEditor(object? source, bool expectsSuccess)
|
||||
{
|
||||
var propertyEditors = ValueTypePropertyEditorCollection(ValueTypes.Json);
|
||||
var converter = new JsonValueConverter(propertyEditors, Mock.Of<ILogger<JsonValueConverter>>());
|
||||
var propertyType = PropertyType();
|
||||
|
||||
Assert.IsTrue(converter.IsConverter(propertyType));
|
||||
|
||||
var result = converter.ConvertSourceToIntermediate(null, propertyType, source, false) as JToken;
|
||||
if (expectsSuccess)
|
||||
{
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(source, result.ToString(Formatting.None));
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.IsNull(result);
|
||||
}
|
||||
}
|
||||
|
||||
private static PropertyEditorCollection ValueTypePropertyEditorCollection(string valueType)
|
||||
{
|
||||
var valueEditor = Mock.Of<IDataValueEditor>(x => x.ValueType == valueType);
|
||||
var dataEditor = Mock.Of<IDataEditor>(x => x.GetValueEditor() == valueEditor && x.Alias == "My.Custom.Alias" && x.Type == EditorType.PropertyValue);
|
||||
var propertyEditors = new PropertyEditorCollection(new DataEditorCollection(() => new[] { dataEditor }));
|
||||
return propertyEditors;
|
||||
}
|
||||
|
||||
private static IPublishedPropertyType PropertyType() => Mock.Of<IPublishedPropertyType>(x => x.EditorAlias == "My.Custom.Alias");
|
||||
}
|
||||
Reference in New Issue
Block a user