diff --git a/src/UnityMvvmToolkit.Core/Internal/Helpers/HashCodeHelper.cs b/src/UnityMvvmToolkit.Core/Internal/Helpers/HashCodeHelper.cs index fa75782..e072e46 100644 --- a/src/UnityMvvmToolkit.Core/Internal/Helpers/HashCodeHelper.cs +++ b/src/UnityMvvmToolkit.Core/Internal/Helpers/HashCodeHelper.cs @@ -27,12 +27,7 @@ public static int GetMemberHashCode(Type contextType, string memberName) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetPropertyConverterHashCode(IPropertyValueConverter converter, string converterName = null) { - var targetTypeHash = converter.TargetType.GetHashCode(); - var sourceTypeHash = converter.SourceType.GetHashCode(); - - return string.IsNullOrWhiteSpace(converterName) - ? CombineHashCode(targetTypeHash, sourceTypeHash) - : CombineHashCode(converterName.GetHashCode(), targetTypeHash, sourceTypeHash); + return GetPropertyWrapperConverterId(converter.TargetType, converter.SourceType, converterName); } /// diff --git a/src/UnityMvvmToolkit.Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs b/src/UnityMvvmToolkit.Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs index d1f3650..ad1a6cc 100644 --- a/src/UnityMvvmToolkit.Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs +++ b/src/UnityMvvmToolkit.Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs @@ -14,6 +14,8 @@ namespace UnityMvvmToolkit.Core.Internal.ObjectHandlers { internal sealed class ObjectWrapperHandler : IDisposable { + private static readonly int ReadOnlyPropertyHashCode = typeof(IReadOnlyProperty<>).GetHashCode(); + private readonly ValueConverterHandler _valueConverterHandler; private readonly Dictionary _commandWrappers; @@ -77,22 +79,18 @@ public TProperty GetPropertyAs(IBindingContext context, M var converterId = HashCodeHelper.GetPropertyWrapperConverterId(targetType, sourceType); - if (_wrappersByConverter.TryGetValue(converterId, out var propertyWrappers)) - { - if (propertyWrappers.Count > 0) - { - return (TProperty) propertyWrappers - .Dequeue() - .AsPropertyWrapper() - .SetProperty(property); - } - } - else + var isProperty = property is IProperty; + + var wrapperId = isProperty ? converterId : GetReadOnlyWrapperId(converterId); + + if (TryGetObjectWrapper(wrapperId, out var objectWrapper)) { - _wrappersByConverter.Add(converterId, new Queue()); + return (TProperty) objectWrapper + .AsPropertyWrapper() + .SetProperty(property); } - var wrapperType = property is IProperty + var wrapperType = isProperty ? typeof(PropertyCastWrapper<,>).MakeGenericType(sourceType, targetType) : typeof(ReadOnlyPropertyCastWrapper<,>).MakeGenericType(sourceType, targetType); @@ -115,19 +113,15 @@ public TProperty GetProperty(IBindingContext context, Bin var converterId = HashCodeHelper.GetPropertyWrapperConverterId(targetType, sourceType, bindingData.ConverterName); - if (_wrappersByConverter.TryGetValue(converterId, out var propertyWrappers)) - { - if (propertyWrappers.Count > 0) - { - return (TProperty) propertyWrappers - .Dequeue() - .AsPropertyWrapper() - .SetProperty(property); - } - } - else + var isProperty = property is IProperty; + + var wrapperId = isProperty ? converterId : GetReadOnlyWrapperId(converterId); + + if (TryGetObjectWrapper(wrapperId, out var objectWrapper)) { - _wrappersByConverter.Add(converterId, new Queue()); + return (TProperty) objectWrapper + .AsPropertyWrapper() + .SetProperty(property); } if (_valueConverterHandler.TryGetValueConverterById(converterId, out var valueConverter) == false) @@ -138,7 +132,7 @@ public TProperty GetProperty(IBindingContext context, Bin var args = new object[] { valueConverter }; - var wrapperType = property is IProperty + var wrapperType = isProperty ? typeof(PropertyConvertWrapper<,>).MakeGenericType(sourceType, targetType) : typeof(ReadOnlyPropertyConvertWrapper<,>).MakeGenericType(sourceType, targetType); @@ -177,20 +171,12 @@ public ICommandWrapper GetCommandWrapper(IBindingContext context, CommandBinding var converterId = HashCodeHelper.GetCommandWrapperConverterId(commandValueType, bindingData.ConverterName); - if (_wrappersByConverter.TryGetValue(converterId, out var commandWrappers)) + if (TryGetObjectWrapper(converterId, out var objectWrapper)) { - if (commandWrappers.Count > 0) - { - return commandWrappers - .Dequeue() - .AsCommandWrapper() - .SetCommand(commandId, command) - .RegisterParameter(bindingData.ElementId, bindingData.ParameterValue); - } - } - else - { - _wrappersByConverter.Add(converterId, new Queue()); + return objectWrapper + .AsCommandWrapper() + .SetCommand(commandId, command) + .RegisterParameter(bindingData.ElementId, bindingData.ParameterValue); } if (_valueConverterHandler.TryGetValueConverterById(converterId, out var valueConverter) == false) @@ -215,7 +201,7 @@ public void ReturnProperty(IPropertyWrapper propertyWrapper) { AssureIsNotDisposed(); - ReturnWrapper(propertyWrapper); + ReturnObjectWrapper(propertyWrapper); } public void ReturnCommandWrapper(ICommandWrapper commandWrapper, int elementId) @@ -228,7 +214,8 @@ public void ReturnCommandWrapper(ICommandWrapper commandWrapper, int elementId) } _commandWrappers.Remove(commandWrapper.CommandId); - ReturnWrapper(commandWrapper); + + ReturnObjectWrapper(commandWrapper); } public void Dispose() @@ -347,10 +334,41 @@ private void CreateParameterValueConverterInstances(int converterId, IParameterV } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ReturnWrapper(IObjectWrapper wrapper) + private bool TryGetObjectWrapper(int wrapperId, out IObjectWrapper objectWrapper) + { + if (_wrappersByConverter.TryGetValue(wrapperId, out var objectWrappers)) + { + if (objectWrappers.Count > 0) + { + objectWrapper = objectWrappers.Dequeue(); + return true; + } + } + else + { + _wrappersByConverter.Add(wrapperId, new Queue()); + } + + objectWrapper = default; + return false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ReturnObjectWrapper(IObjectWrapper wrapper) { wrapper.Reset(); - _wrappersByConverter[wrapper.ConverterId].Enqueue(wrapper); + + switch (wrapper) + { + case IProperty: + case ICommandWrapper: + _wrappersByConverter[wrapper.ConverterId].Enqueue(wrapper); + break; + + default: + _wrappersByConverter[GetReadOnlyWrapperId(wrapper.ConverterId)].Enqueue(wrapper); + break; + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -361,5 +379,11 @@ private void AssureIsNotDisposed() throw new ObjectDisposedException(nameof(ObjectWrapperHandler)); } } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int GetReadOnlyWrapperId(int wrapperConverterId) + { + return HashCodeHelper.CombineHashCode(wrapperConverterId, ReadOnlyPropertyHashCode); + } } } \ No newline at end of file diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/Helpers/HashCodeHelper.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/Helpers/HashCodeHelper.cs index fa75782..e072e46 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/Helpers/HashCodeHelper.cs +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/Helpers/HashCodeHelper.cs @@ -27,12 +27,7 @@ public static int GetMemberHashCode(Type contextType, string memberName) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetPropertyConverterHashCode(IPropertyValueConverter converter, string converterName = null) { - var targetTypeHash = converter.TargetType.GetHashCode(); - var sourceTypeHash = converter.SourceType.GetHashCode(); - - return string.IsNullOrWhiteSpace(converterName) - ? CombineHashCode(targetTypeHash, sourceTypeHash) - : CombineHashCode(converterName.GetHashCode(), targetTypeHash, sourceTypeHash); + return GetPropertyWrapperConverterId(converter.TargetType, converter.SourceType, converterName); } /// diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs index d1f3650..ad1a6cc 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs @@ -14,6 +14,8 @@ namespace UnityMvvmToolkit.Core.Internal.ObjectHandlers { internal sealed class ObjectWrapperHandler : IDisposable { + private static readonly int ReadOnlyPropertyHashCode = typeof(IReadOnlyProperty<>).GetHashCode(); + private readonly ValueConverterHandler _valueConverterHandler; private readonly Dictionary _commandWrappers; @@ -77,22 +79,18 @@ public TProperty GetPropertyAs(IBindingContext context, M var converterId = HashCodeHelper.GetPropertyWrapperConverterId(targetType, sourceType); - if (_wrappersByConverter.TryGetValue(converterId, out var propertyWrappers)) - { - if (propertyWrappers.Count > 0) - { - return (TProperty) propertyWrappers - .Dequeue() - .AsPropertyWrapper() - .SetProperty(property); - } - } - else + var isProperty = property is IProperty; + + var wrapperId = isProperty ? converterId : GetReadOnlyWrapperId(converterId); + + if (TryGetObjectWrapper(wrapperId, out var objectWrapper)) { - _wrappersByConverter.Add(converterId, new Queue()); + return (TProperty) objectWrapper + .AsPropertyWrapper() + .SetProperty(property); } - var wrapperType = property is IProperty + var wrapperType = isProperty ? typeof(PropertyCastWrapper<,>).MakeGenericType(sourceType, targetType) : typeof(ReadOnlyPropertyCastWrapper<,>).MakeGenericType(sourceType, targetType); @@ -115,19 +113,15 @@ public TProperty GetProperty(IBindingContext context, Bin var converterId = HashCodeHelper.GetPropertyWrapperConverterId(targetType, sourceType, bindingData.ConverterName); - if (_wrappersByConverter.TryGetValue(converterId, out var propertyWrappers)) - { - if (propertyWrappers.Count > 0) - { - return (TProperty) propertyWrappers - .Dequeue() - .AsPropertyWrapper() - .SetProperty(property); - } - } - else + var isProperty = property is IProperty; + + var wrapperId = isProperty ? converterId : GetReadOnlyWrapperId(converterId); + + if (TryGetObjectWrapper(wrapperId, out var objectWrapper)) { - _wrappersByConverter.Add(converterId, new Queue()); + return (TProperty) objectWrapper + .AsPropertyWrapper() + .SetProperty(property); } if (_valueConverterHandler.TryGetValueConverterById(converterId, out var valueConverter) == false) @@ -138,7 +132,7 @@ public TProperty GetProperty(IBindingContext context, Bin var args = new object[] { valueConverter }; - var wrapperType = property is IProperty + var wrapperType = isProperty ? typeof(PropertyConvertWrapper<,>).MakeGenericType(sourceType, targetType) : typeof(ReadOnlyPropertyConvertWrapper<,>).MakeGenericType(sourceType, targetType); @@ -177,20 +171,12 @@ public ICommandWrapper GetCommandWrapper(IBindingContext context, CommandBinding var converterId = HashCodeHelper.GetCommandWrapperConverterId(commandValueType, bindingData.ConverterName); - if (_wrappersByConverter.TryGetValue(converterId, out var commandWrappers)) + if (TryGetObjectWrapper(converterId, out var objectWrapper)) { - if (commandWrappers.Count > 0) - { - return commandWrappers - .Dequeue() - .AsCommandWrapper() - .SetCommand(commandId, command) - .RegisterParameter(bindingData.ElementId, bindingData.ParameterValue); - } - } - else - { - _wrappersByConverter.Add(converterId, new Queue()); + return objectWrapper + .AsCommandWrapper() + .SetCommand(commandId, command) + .RegisterParameter(bindingData.ElementId, bindingData.ParameterValue); } if (_valueConverterHandler.TryGetValueConverterById(converterId, out var valueConverter) == false) @@ -215,7 +201,7 @@ public void ReturnProperty(IPropertyWrapper propertyWrapper) { AssureIsNotDisposed(); - ReturnWrapper(propertyWrapper); + ReturnObjectWrapper(propertyWrapper); } public void ReturnCommandWrapper(ICommandWrapper commandWrapper, int elementId) @@ -228,7 +214,8 @@ public void ReturnCommandWrapper(ICommandWrapper commandWrapper, int elementId) } _commandWrappers.Remove(commandWrapper.CommandId); - ReturnWrapper(commandWrapper); + + ReturnObjectWrapper(commandWrapper); } public void Dispose() @@ -347,10 +334,41 @@ private void CreateParameterValueConverterInstances(int converterId, IParameterV } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ReturnWrapper(IObjectWrapper wrapper) + private bool TryGetObjectWrapper(int wrapperId, out IObjectWrapper objectWrapper) + { + if (_wrappersByConverter.TryGetValue(wrapperId, out var objectWrappers)) + { + if (objectWrappers.Count > 0) + { + objectWrapper = objectWrappers.Dequeue(); + return true; + } + } + else + { + _wrappersByConverter.Add(wrapperId, new Queue()); + } + + objectWrapper = default; + return false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ReturnObjectWrapper(IObjectWrapper wrapper) { wrapper.Reset(); - _wrappersByConverter[wrapper.ConverterId].Enqueue(wrapper); + + switch (wrapper) + { + case IProperty: + case ICommandWrapper: + _wrappersByConverter[wrapper.ConverterId].Enqueue(wrapper); + break; + + default: + _wrappersByConverter[GetReadOnlyWrapperId(wrapper.ConverterId)].Enqueue(wrapper); + break; + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -361,5 +379,11 @@ private void AssureIsNotDisposed() throw new ObjectDisposedException(nameof(ObjectWrapperHandler)); } } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int GetReadOnlyWrapperId(int wrapperConverterId) + { + return HashCodeHelper.CombineHashCode(wrapperConverterId, ReadOnlyPropertyHashCode); + } } } \ No newline at end of file diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/BindableListView.TItem.TCollection.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/BindableListView.TItem.TCollection.cs index 5b04477..d7d1ea2 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/BindableListView.TItem.TCollection.cs +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/BindableListView.TItem.TCollection.cs @@ -54,7 +54,7 @@ public virtual void SetBindingContext(IBindingContext context, IObjectProvider o } _itemsSourceBindingData ??= BindingItemsSourcePath.ToPropertyBindingData(); - _itemTemplate ??= objectProvider.GetCollectionItemTemplate(); + _itemTemplate ??= GetItemTemplate(objectProvider); _objectProvider = objectProvider; @@ -151,5 +151,16 @@ private void OnUnbindItem(VisualElement item, int index) UnbindItem(item, index, itemBindingContext, _objectProvider); } } + + private VisualTreeAsset GetItemTemplate(IObjectProvider objectProvider) + { +#if UNITY_2023_2_OR_NEWER + return ItemTemplate + ? ItemTemplate + : objectProvider.GetCollectionItemTemplate(); +#else + return objectProvider.GetCollectionItemTemplate(); +#endif + } } } \ No newline at end of file diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/BindableScrollView.T.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/BindableScrollView.T.cs index ac115a2..9cf0205 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/BindableScrollView.T.cs +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/BindableScrollView.T.cs @@ -62,7 +62,7 @@ public virtual void SetBindingContext(IBindingContext context, IObjectProvider o } _itemsSourceBindingData ??= BindingItemsSourcePath.ToPropertyBindingData(); - _itemTemplate ??= objectProvider.GetCollectionItemTemplate(); + _itemTemplate ??= GetItemTemplate(objectProvider); _objectProvider = objectProvider; @@ -224,5 +224,16 @@ private void OnPoolDestroyItem(VisualElement item) { item.DisposeBindableElement(_objectProvider); } + + private VisualTreeAsset GetItemTemplate(IObjectProvider objectProvider) + { +#if UNITY_2023_2_OR_NEWER + return ItemTemplate + ? ItemTemplate + : objectProvider.GetCollectionItemTemplate(); +#else + return objectProvider.GetCollectionItemTemplate(); +#endif + } } } diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableListView.TItem.TCollection.Uxml.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableListView.TItem.TCollection.Uxml.cs index 42807ec..15c538b 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableListView.TItem.TCollection.Uxml.cs +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableListView.TItem.TCollection.Uxml.cs @@ -6,23 +6,26 @@ namespace UnityMvvmToolkit.UITK.BindableUIElements partial class BindableListView { public string BindingItemsSourcePath { get; private set; } + public VisualTreeAsset ItemTemplate { get; private set; } #if UNITY_2023_2_OR_NEWER [System.Serializable] public new class UxmlSerializedData : ListView.UxmlSerializedData { - // ReSharper disable once InconsistentNaming #pragma warning disable 649 + // ReSharper disable once InconsistentNaming [UnityEngine.SerializeField] private string BindingItemsSourcePath; + // ReSharper disable once InconsistentNaming + [UnityEngine.SerializeField] private VisualTreeAsset ItemTemplate; #pragma warning restore 649 public override void Deserialize(object visualElement) { base.Deserialize(visualElement); - visualElement - .As>() - .BindingItemsSourcePath = BindingItemsSourcePath; + var bindableListView = visualElement.As>(); + bindableListView.BindingItemsSourcePath = BindingItemsSourcePath; + bindableListView.ItemTemplate = ItemTemplate; } } #else diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableScrollView.T.Uxml.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableScrollView.T.Uxml.cs index a1cdcac..03247aa 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableScrollView.T.Uxml.cs +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableScrollView.T.Uxml.cs @@ -6,23 +6,26 @@ namespace UnityMvvmToolkit.UITK.BindableUIElements partial class BindableScrollView { public string BindingItemsSourcePath { get; private set; } + public VisualTreeAsset ItemTemplate { get; private set; } #if UNITY_2023_2_OR_NEWER [System.Serializable] public new class UxmlSerializedData : ScrollView.UxmlSerializedData { - // ReSharper disable once InconsistentNaming #pragma warning disable 649 + // ReSharper disable once InconsistentNaming [UnityEngine.SerializeField] private string BindingItemsSourcePath; + // ReSharper disable once InconsistentNaming + [UnityEngine.SerializeField] private VisualTreeAsset ItemTemplate; #pragma warning restore 649 public override void Deserialize(object visualElement) { base.Deserialize(visualElement); - visualElement - .As>() - .BindingItemsSourcePath = BindingItemsSourcePath; + var bindableListView = visualElement.As>(); + bindableListView.BindingItemsSourcePath = BindingItemsSourcePath; + bindableListView.ItemTemplate = ItemTemplate; } } #else diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/package.json b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/package.json index 0fbce43..3dcdba4 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/package.json +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/package.json @@ -2,7 +2,7 @@ "name": "com.chebanovdd.unitymvvmtoolkit", "displayName": "Unity MVVM Toolkit", "author": { "name": "ChebanovDD", "url": "https://github.com/ChebanovDD" }, - "version": "1.1.8", + "version": "1.1.9", "unity": "2018.4", "description": "The Unity Mvvm Toolkit allows you to use data binding to establish a connection between the app UI and the data it displays. This is a simple and consistent way to achieve clean separation of business logic from UI.", "keywords": [ "mvvm", "binding", "ui", "toolkit" ], diff --git a/tests/UnityMvvmToolkit.Test.Integration/BindingContextObjectProviderTests.cs b/tests/UnityMvvmToolkit.Test.Integration/BindingContextObjectProviderTests.cs index aed0b21..339156c 100644 --- a/tests/UnityMvvmToolkit.Test.Integration/BindingContextObjectProviderTests.cs +++ b/tests/UnityMvvmToolkit.Test.Integration/BindingContextObjectProviderTests.cs @@ -260,6 +260,41 @@ public void RentProperty_ShouldReturnProperty_WhenConverterIsSet() countProperty.Value.Should().Be(countValue.ToString()); } + [Fact] + public void RentProperty_ShouldReturnValidPropertyWrapper() + { + // Arrange + const int countValue = 69; + + var objectProvider = new BindingContextObjectProvider(new IValueConverter[] + { + new IntToStrConverter() + }); + + var bindingContext = new MyBindingContext(intValue: countValue) + { + Count = countValue + }; + + var countPropertyBindingData = nameof(MyBindingContext.Count).ToPropertyBindingData(); + var countReadOnlyPropertyBindingData = nameof(MyBindingContext.IntReadOnlyProperty).ToPropertyBindingData(); + + // Act + var countProperty = objectProvider.RentProperty(bindingContext, countPropertyBindingData); + var countReadOnlyProperty = objectProvider.RentReadOnlyProperty(bindingContext, countReadOnlyPropertyBindingData); + + objectProvider.ReturnReadOnlyProperty(countReadOnlyProperty); + objectProvider.ReturnProperty(countProperty); + + countProperty = objectProvider.RentProperty(bindingContext, countPropertyBindingData); + countReadOnlyProperty = objectProvider.RentReadOnlyProperty(bindingContext, countReadOnlyPropertyBindingData); + + // Assert + + countProperty.Value.Should().Be(countValue.ToString()); + countReadOnlyProperty.Value.Should().Be(countValue.ToString()); + } + [Fact] public void RentProperty_ShouldConvertPropertyValue_WhenSourceAndTargetTypesMatch() { @@ -303,7 +338,7 @@ public void RentProperty_ShouldReturnReadOnlyProperty_WhenPropertyInstanceIsNotR var bindingContext = new MyBindingContext(intValue: intValue); - var intPropertyBindingData = nameof(MyBindingContext.IntReadOnlyProperty).ToPropertyBindingData(); + var intPropertyBindingData = nameof(MyBindingContext.IntFakeReadOnlyProperty).ToPropertyBindingData(); // Act IReadOnlyProperty intProperty = objectProvider.RentProperty(bindingContext, intPropertyBindingData); diff --git a/tests/UnityMvvmToolkit.Test.Integration/TestBindingContext/MyBindingContext.cs b/tests/UnityMvvmToolkit.Test.Integration/TestBindingContext/MyBindingContext.cs index ac124ca..be319a6 100644 --- a/tests/UnityMvvmToolkit.Test.Integration/TestBindingContext/MyBindingContext.cs +++ b/tests/UnityMvvmToolkit.Test.Integration/TestBindingContext/MyBindingContext.cs @@ -32,7 +32,8 @@ public MyBindingContext(string title = "Title", int intValue = default) _boolCommand = new Command(value => BoolValue = value); Title = new ReadOnlyProperty(title); - IntReadOnlyProperty = new Property(intValue); + IntReadOnlyProperty = new ReadOnlyProperty(intValue); + IntFakeReadOnlyProperty = new Property(intValue); FieldCommand = new Command(default); @@ -56,6 +57,7 @@ public int Count public IReadOnlyProperty Title { get; } public IReadOnlyProperty IntReadOnlyProperty { get; } + public IReadOnlyProperty IntFakeReadOnlyProperty { get; } public ICommand FieldCommand; public ICommand IncrementCommand { get; } diff --git a/tests/UnityMvvmToolkit.Test.Unit/ObjectWrapperHandlerTests.cs b/tests/UnityMvvmToolkit.Test.Unit/ObjectWrapperHandlerTests.cs index 35ad3ab..d3bb470 100644 --- a/tests/UnityMvvmToolkit.Test.Unit/ObjectWrapperHandlerTests.cs +++ b/tests/UnityMvvmToolkit.Test.Unit/ObjectWrapperHandlerTests.cs @@ -1,5 +1,6 @@ using FluentAssertions; using NSubstitute; +using UnityMvvmToolkit.Core; using UnityMvvmToolkit.Core.Converters.ParameterValueConverters; using UnityMvvmToolkit.Core.Converters.PropertyValueConverters; using UnityMvvmToolkit.Core.Enums; @@ -7,6 +8,7 @@ using UnityMvvmToolkit.Core.Internal.Helpers; using UnityMvvmToolkit.Core.Internal.Interfaces; using UnityMvvmToolkit.Core.Internal.ObjectHandlers; +using UnityMvvmToolkit.Core.Internal.ObjectWrappers; namespace UnityMvvmToolkit.Test.Unit; @@ -35,8 +37,9 @@ public void CreateValueConverterInstances_ShouldCreatePropertyWrapperWithConvert // Arrange var converterId = HashCodeHelper.GetPropertyWrapperConverterId(_intToStrConverter); - var propertyWrapper = Substitute.For(); - propertyWrapper.ConverterId.Returns(converterId); + var propertyWrapper = new PropertyConvertWrapper(_intToStrConverter) + .SetProperty(new Property()) + .SetConverterId(converterId); var objectWrapperHandler = new ObjectWrapperHandler(_valueConverterHandler); @@ -56,8 +59,9 @@ public void CreateValueConverterInstances_ShouldCreatePropertyWrapperWithConvert // Arrange var converterId = HashCodeHelper.GetPropertyWrapperConverterId(_intToStrConverter, _intToStrConverter.Name); - var propertyWrapper = Substitute.For(); - propertyWrapper.ConverterId.Returns(converterId); + var propertyWrapper = new PropertyConvertWrapper(_intToStrConverter) + .SetProperty(new Property()) + .SetConverterId(converterId); var objectWrapperHandler = new ObjectWrapperHandler(_valueConverterHandler); @@ -80,11 +84,13 @@ public void var converterIdByName = HashCodeHelper.GetPropertyWrapperConverterId(_intToStrConverter, _intToStrConverter.Name); - var propertyWrapperByType = Substitute.For(); - propertyWrapperByType.ConverterId.Returns(converterIdByType); + var propertyWrapperByType = new PropertyConvertWrapper(_intToStrConverter) + .SetProperty(new Property()) + .SetConverterId(converterIdByType); - var propertyWrapperByName = Substitute.For(); - propertyWrapperByName.ConverterId.Returns(converterIdByName); + var propertyWrapperByName = new PropertyConvertWrapper(_intToStrConverter) + .SetProperty(new Property()) + .SetConverterId(converterIdByName); var objectWrapperHandler = new ObjectWrapperHandler(_valueConverterHandler); @@ -108,6 +114,7 @@ public void CreateValueConverterInstances_ShouldCreateCommandWrapperWithConverte { // Arrange const int elementId = 55; + var converterId = HashCodeHelper.GetCommandWrapperConverterId(_parameterToIntConverter); var commandWrapper = Substitute.For(); @@ -130,6 +137,7 @@ public void CreateValueConverterInstances_ShouldCreateCommandWrapperWithConverte { // Arrange const int elementId = 55; + var converterId = HashCodeHelper.GetCommandWrapperConverterId(_parameterToIntConverter, _parameterToIntConverter.Name); @@ -154,6 +162,7 @@ public void { // Arrange const int elementId = 55; + var converterIdByType = HashCodeHelper.GetCommandWrapperConverterId(_parameterToIntConverter); var converterIdByName = @@ -202,8 +211,9 @@ public void ReturnProperty_ShouldResetPropertyWrapper_WhenPropertyWrapperWasRetu // Arrange var converterId = HashCodeHelper.GetPropertyWrapperConverterId(_intToStrConverter); - var propertyWrapper = Substitute.For(); - propertyWrapper.ConverterId.Returns(converterId); + PropertyWrapper propertyWrapper = new PropertyConvertWrapper(_intToStrConverter); + propertyWrapper.SetProperty(new Property(69)) + .SetConverterId(converterId); var objectWrapperHandler = new ObjectWrapperHandler(_valueConverterHandler); @@ -212,7 +222,7 @@ public void ReturnProperty_ShouldResetPropertyWrapper_WhenPropertyWrapperWasRetu objectWrapperHandler.ReturnProperty(propertyWrapper); // Assert - propertyWrapper.Received(1).Reset(); + propertyWrapper.Value.Should().Be(default); } [Fact]