diff options
Diffstat (limited to 'Xamarin.PropertyEditing.Tests')
13 files changed, 1013 insertions, 19 deletions
diff --git a/Xamarin.PropertyEditing.Tests/AddValueConverterViewModelTests.cs b/Xamarin.PropertyEditing.Tests/AddValueConverterViewModelTests.cs index 61be5c5..c323cc2 100644 --- a/Xamarin.PropertyEditing.Tests/AddValueConverterViewModelTests.cs +++ b/Xamarin.PropertyEditing.Tests/AddValueConverterViewModelTests.cs @@ -1,12 +1,9 @@ -using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; using Moq; using NUnit.Framework; -using NUnit.Framework.Internal; using Xamarin.PropertyEditing.ViewModels; namespace Xamarin.PropertyEditing.Tests diff --git a/Xamarin.PropertyEditing.Tests/CreateBindingViewModelTests.cs b/Xamarin.PropertyEditing.Tests/CreateBindingViewModelTests.cs new file mode 100644 index 0000000..2cf707b --- /dev/null +++ b/Xamarin.PropertyEditing.Tests/CreateBindingViewModelTests.cs @@ -0,0 +1,709 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Moq; +using NUnit.Framework; +using Xamarin.PropertyEditing.Drawing; +using Xamarin.PropertyEditing.Reflection; +using Xamarin.PropertyEditing.Tests.MockControls; +using Xamarin.PropertyEditing.ViewModels; + +namespace Xamarin.PropertyEditing.Tests +{ + [TestFixture] + internal class CreateBindingViewModelTests + { + [SetUp] + public void Setup () + { + AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException; + this.syncContext = new AsyncSynchronizationContext (); + SynchronizationContext.SetSynchronizationContext (this.syncContext); + } + + private Exception unhandled; + + private void CurrentDomainOnUnhandledException (object sender, UnhandledExceptionEventArgs e) + { + this.unhandled = e.ExceptionObject as Exception; + } + + [TearDown] + public void TearDown () + { + this.syncContext.WaitForPendingOperationsToComplete (); + SynchronizationContext.SetSynchronizationContext (null); + + AppDomain.CurrentDomain.UnhandledException -= CurrentDomainOnUnhandledException; + + if (this.unhandled != null) { + var ex = this.unhandled; + this.unhandled = null; + Assert.Fail ("Unhandled exception: {0}", ex); + } + } + + [Test] + public void PropertyDisplayType () + { + var target = new object(); + + const string propName = "propertyName"; + var property = GetBasicProperty (propName); + + var editor = new Mock<IObjectEditor> (); + editor.SetupGet (e => e.Properties).Returns (new[] { property.Object }); + editor.SetupGet (e => e.Target).Returns (target); + editor.SetupGet (e => e.TargetType).Returns (typeof(object).ToTypeInfo ()); + + var editorProvider = new MockEditorProvider (editor.Object); + + var bpmock = new Mock<IBindingProvider> (); + + var vm = new CreateBindingViewModel (new TargetPlatform (editorProvider, bpmock.Object), editor.Object, property.Object); + Assert.That (vm.PropertyDisplay, Contains.Substring ("Object")); + Assert.That (vm.PropertyDisplay, Contains.Substring (propName)); + } + + [Test] + public void PropertyDisplayNameable () + { + var target = new object (); + const string propName = "propertyName"; + var property = GetBasicProperty (propName); + var editor = GetBasicEditor (target, property.Object); + + const string objName = "objName"; + var nameable = editor.As<INameableObject> (); + nameable.Setup (n => n.GetNameAsync ()).ReturnsAsync (objName); + + var editorProvider = new MockEditorProvider (editor.Object); + + var bpmock = new Mock<IBindingProvider> (); + + var vm = new CreateBindingViewModel (new TargetPlatform (editorProvider, bpmock.Object), editor.Object, property.Object); + Assert.That (vm.PropertyDisplay, Does.Not.Contains ("Object")); + Assert.That (vm.PropertyDisplay, Contains.Substring (objName)); + Assert.That (vm.PropertyDisplay, Contains.Substring (propName)); + } + + [Test] + public async Task BindingSources () + { + var target = new object (); + var property = GetBasicProperty (); + var editor = GetBasicEditor (target, property.Object); + + var editorProvider = new MockEditorProvider (editor.Object); + + var sources = new[] { + new BindingSource ("Short Description", BindingSourceType.Object, "Short Description"), + new BindingSource ("Long Description", BindingSourceType.Object, "Long Description"), + }; + + var bpmock = new Mock<IBindingProvider> (); + bpmock.Setup (bp => bp.GetBindingSourcesAsync (target, property.Object)).ReturnsAsync (sources); + bpmock.Setup (bp => bp.GetRootElementsAsync (sources[0], target)).ReturnsAsync (new[] { new object (), new object () }); + bpmock.Setup (bp => bp.GetRootElementsAsync (sources[1], target)).ReturnsAsync (new[] { new object () }); + bpmock.Setup (bp => bp.GetValueConverterResourcesAsync (It.IsAny<object> ())).ReturnsAsync (new Resource[0]); + + var vm = new CreateBindingViewModel (new TargetPlatform (editorProvider, bpmock.Object), editor.Object, property.Object); + + Assert.That (vm.BindingSources, Is.Not.Null); + + var requested = await vm.BindingSources.Task; + CollectionAssert.AreEqual (sources, requested); + + Assert.That (vm.SelectedBindingSource, Is.EqualTo (sources[0])); + } + + [Test] + public async Task BindingSourceObjectRoots () + { + var target = new object (); + var property = GetBasicProperty (); + var editor = GetBasicEditor (target, property.Object); + + var editorProvider = new MockEditorProvider (editor.Object); + + var sources = new[] { + new BindingSource ("Short Description", BindingSourceType.Object, "Short Description"), + new BindingSource ("Long Description", BindingSourceType.Object, "Long Description"), + }; + + var shortRoots = new[] { new object (), new object () }; + + var bpmock = new Mock<IBindingProvider> (); + bpmock.Setup (bp => bp.GetBindingSourcesAsync (target, property.Object)).ReturnsAsync (sources); + bpmock.Setup (bp => bp.GetRootElementsAsync (sources[0], target)).ReturnsAsync (shortRoots); + bpmock.Setup (bp => bp.GetRootElementsAsync (sources[1], target)).ReturnsAsync (new[] { new object () }); + bpmock.Setup (bp => bp.GetValueConverterResourcesAsync (It.IsAny<object> ())).ReturnsAsync (new Resource[0]); + + var vm = new CreateBindingViewModel (new TargetPlatform (editorProvider, bpmock.Object), editor.Object, property.Object); + await vm.BindingSources.Task; + Assume.That (vm.SelectedBindingSource, Is.EqualTo (sources[0])); + + bpmock.Verify (bp => bp.GetRootElementsAsync (sources[0], target)); + IReadOnlyList<ObjectTreeElement> roots = await vm.ObjectElementRoots.Task; + Assert.That (roots.Count, Is.EqualTo (2), "Unexpected number of roots"); + CollectionAssert.AreEqual (roots.Select (r => r.Editor.Target), shortRoots); + } + + [Test] + [Description ("If the source has a description, we're on object type source and it's the only one, use a long description")] + public async Task ShowLongDescription () + { + var sources = new[] { + new BindingSource ("Short Description", BindingSourceType.Object, "Short Description"), + new BindingSource ("Long Description", BindingSourceType.SingleObject, "Long Description"), + }; + var vm = CreateBasicViewModel (sources: sources); + await vm.BindingSources.Task; + + Assume.That (vm.SelectedBindingSource, Is.EqualTo (sources[0])); + Assume.That (vm.ShowObjectSelector, Is.True, "Object selector should be showing"); + Assert.That (vm.ShowLongDescription, Is.False); + + vm.SelectedBindingSource = sources[1]; + await vm.ObjectElementRoots.Task; + Assert.That (vm.ShowLongDescription, Is.True); + Assert.That (vm.ShowObjectSelector, Is.False); + } + + [Test] + public async Task ValueConverters () + { + var target = new object (); + + var property = GetBasicProperty (); + var editor = GetBasicEditor (target, property.Object); + + const string objName = "objName"; + var nameable = editor.As<INameableObject> (); + nameable.Setup (n => n.GetNameAsync ()).ReturnsAsync (objName); + + var editorProvider = new MockEditorProvider (editor.Object); + + var sources = new[] { + new BindingSource ("Short Description", BindingSourceType.Object, "Short Description"), + new BindingSource ("Long Description", BindingSourceType.Object, "Long Description"), + }; + + var visi = new Resource ("BooleanToVisibilityConverter"); + + var bpmock = new Mock<IBindingProvider> (); + bpmock.Setup (bp => bp.GetBindingSourcesAsync (target, property.Object)).ReturnsAsync (sources); + bpmock.Setup (bp => bp.GetRootElementsAsync (sources[0], target)).ReturnsAsync (new[] { new object (), new object () }); + bpmock.Setup (bp => bp.GetRootElementsAsync (sources[1], target)).ReturnsAsync (new[] { new object () }); + bpmock.Setup (bp => bp.GetValueConverterResourcesAsync (It.IsAny<object> ())).ReturnsAsync (new [] { visi }); + + var vm = new CreateBindingViewModel (new TargetPlatform (editorProvider, bpmock.Object), editor.Object, property.Object); + Assert.That (vm.ValueConverters, Is.Not.Null); + + await vm.ValueConverters.Task; + Assert.That (vm.ValueConverters.Value, Contains.Item (visi)); + Assert.That (vm.ValueConverters.Value.Count, Is.EqualTo (3)); // visi, No Converter, Request Converter + } + + [Test] + public async Task RequestValueConverter () + { + var target = new object(); + + var vm = CreateBasicViewModel (target: target); + Assume.That (vm.ValueConverters, Is.Not.Null); + + await vm.ValueConverters.Task; + + Assume.That (vm.SelectedValueConverter, Is.EqualTo (vm.ValueConverters.Value[0])); + Assume.That (vm.ValueConverters.Value.Count, Is.EqualTo (2)); + + const string name = "NewConverter"; + bool requested = false; + vm.CreateValueConverterRequested += (o, e) => { + e.ConverterType = typeof(object).ToTypeInfo (); + e.Name = name; + e.Source = MockResourceProvider.ApplicationResourcesSource; + requested = true; + }; + + Assume.That (vm.ValueConverters.Value, Is.InstanceOf (typeof(INotifyCollectionChanged))); + + object newItem = null; + ((INotifyCollectionChanged) vm.ValueConverters.Value).CollectionChanged += (o, e) => { + if (e.Action == NotifyCollectionChangedAction.Add && e.NewItems.Count == 1) { + newItem = e.NewItems[0]; + Assert.That (e.NewStartingIndex, Is.EqualTo (1), "New converter was not added below none and above request"); + } + }; + + int selectedChanged = 0; + vm.PropertyChanged += (o, e) => { + if (e.PropertyName == nameof(CreateBindingViewModel.SelectedValueConverter)) + selectedChanged++; + }; + + vm.SelectedValueConverter = vm.ValueConverters.Value[1]; + + Assert.That (requested, Is.True); + Assert.That (selectedChanged, Is.EqualTo (2), "SelectedValueConverter did not fire INPC for request and result changes"); + Assert.That (newItem, Is.Not.Null); + Assert.That (vm.SelectedValueConverter, Is.EqualTo (newItem)); + } + + [Test] + public async Task RequestValueConverterCanceled () + { + var vm = CreateBasicViewModel (); + Assume.That (vm.ValueConverters, Is.Not.Null); + + await vm.ValueConverters.Task; + + Assume.That (vm.SelectedValueConverter, Is.EqualTo (vm.ValueConverters.Value[0])); + Assume.That (vm.ValueConverters.Value.Count, Is.EqualTo (2)); + + bool requested = false; + vm.CreateValueConverterRequested += (o, e) => { + requested = true; + }; + + vm.SelectedValueConverter = vm.ValueConverters.Value[1]; + + Assert.That (requested, Is.True); + Assert.That (vm.SelectedValueConverter, Is.EqualTo (vm.ValueConverters.Value[0]), + "SelectedValueConverter wasn't set back to No Converter after canceled request"); + } + + [Test] + public async Task PropertyRoot () + { + var target = new object (); + + var property = new Mock<IPropertyInfo> (); + property.SetupGet (p => p.ValueSources).Returns (ValueSources.Local | ValueSources.Binding); + property.SetupGet (p => p.Type).Returns (typeof (object)); + property.SetupGet (p => p.Name).Returns ("name"); + property.SetupGet (p => p.RealType).Returns (typeof (object).ToTypeInfo ()); + property.SetupGet (p => p.CanWrite).Returns (true); + + var editor = GetBasicEditor (target, property.Object); + + var controlTarget = new MockWpfControl (); + var controlEditor = new MockObjectEditor (controlTarget); + var provider = new MockEditorProvider (controlEditor); + + var source = new BindingSource ("Control", BindingSourceType.Object); + var bpmock = new Mock<IBindingProvider> (); + bpmock.Setup (bp => bp.GetBindingSourcesAsync (target, property.Object)).ReturnsAsync (new[] { source }); + bpmock.Setup (bp => bp.GetRootElementsAsync (source, target)).ReturnsAsync (new[] { controlTarget }); + bpmock.Setup (bp => bp.GetValueConverterResourcesAsync (It.IsAny<object> ())).ReturnsAsync (new Resource[0]); + + var vm = new CreateBindingViewModel (new TargetPlatform (provider, bpmock.Object), editor.Object, property.Object); + Assume.That (vm.SelectedBindingSource, Is.EqualTo (source)); + + Assert.That (vm.PropertyRoot, Is.Not.Null); + await vm.PropertyRoot.Task; + + var targetType = typeof(MockWpfControl).ToTypeInfo (); + Assert.That (vm.PropertyRoot.Value.TargetType, Is.EqualTo (targetType)); + CollectionAssert.AreEqual (controlEditor.Properties, vm.PropertyRoot.Value.Children.Select (te => te.Property)); + } + + [Test] + public async Task PropertyRootChildren () + { + var target = new object(); + + var property = new Mock<IPropertyInfo> (); + property.SetupGet (p => p.ValueSources).Returns (ValueSources.Local | ValueSources.Binding); + property.SetupGet (p => p.Type).Returns (typeof (object)); + property.SetupGet (p => p.Name).Returns ("name"); + property.SetupGet (p => p.RealType).Returns (typeof (object).ToTypeInfo ()); + property.SetupGet (p => p.CanWrite).Returns (true); + + var editor = GetBasicEditor (target, property.Object); + + var controlTarget = new MockWpfControl(); + var controlEditor = new MockObjectEditor (controlTarget); + var provider = new MockEditorProvider (controlEditor); + + var source = new BindingSource ("Control", BindingSourceType.Object); + var bpmock = new Mock<IBindingProvider> (); + bpmock.Setup (bp => bp.GetBindingSourcesAsync (target, property.Object)).ReturnsAsync (new[] { source }); + bpmock.Setup (bp => bp.GetRootElementsAsync (source, target)).ReturnsAsync (new[] { controlTarget }); + bpmock.Setup (bp => bp.GetValueConverterResourcesAsync (It.IsAny<object> ())).ReturnsAsync (new Resource[0]); + + var vm = new CreateBindingViewModel (new TargetPlatform (provider, bpmock.Object), editor.Object, property.Object); + Assume.That (vm.SelectedBindingSource, Is.EqualTo (source)); + Assume.That (vm.PropertyRoot, Is.Not.Null); + await vm.PropertyRoot.Task; + + var childrenProperty = controlEditor.Properties.First (p => p.Type == typeof(CommonThickness)); + var element = vm.PropertyRoot.Value.Children.First (p => Equals (p.Property, childrenProperty)); + + Assert.That (element.Children, Is.Not.Null); + + await element.Children.Task; + var expected = await provider.GetPropertiesForTypeAsync (typeof(CommonThickness).ToTypeInfo ()); + CollectionAssert.AreEqual (expected, element.Children.Value.Select (te => te.Property)); + } + + [Test] + public async Task Path () + { + var target = new object (); + + var property = new Mock<IPropertyInfo> (); + property.SetupGet (p => p.ValueSources).Returns (ValueSources.Local | ValueSources.Binding); + property.SetupGet (p => p.Type).Returns (typeof (object)); + property.SetupGet (p => p.Name).Returns ("name"); + property.SetupGet (p => p.RealType).Returns (typeof (object).ToTypeInfo ()); + property.SetupGet (p => p.CanWrite).Returns (true); + + var editor = GetBasicEditor (target, property.Object); + + var controlTarget = new MockWpfControl (); + var controlEditor = new MockObjectEditor (controlTarget); + var provider = new MockEditorProvider (controlEditor); + + var source = new BindingSource ("Control", BindingSourceType.Object); + var bpmock = new Mock<IBindingProvider> (); + bpmock.Setup (bp => bp.GetBindingSourcesAsync (target, property.Object)).ReturnsAsync (new[] { source }); + bpmock.Setup (bp => bp.GetRootElementsAsync (source, target)).ReturnsAsync (new[] { controlTarget }); + bpmock.Setup (bp => bp.GetValueConverterResourcesAsync (It.IsAny<object> ())).ReturnsAsync (new Resource[0]); + + var vm = new CreateBindingViewModel (new TargetPlatform (provider, bpmock.Object), editor.Object, property.Object); + Assume.That (vm.SelectedBindingSource, Is.EqualTo (source)); + Assume.That (vm.PropertyRoot, Is.Not.Null); + await vm.PropertyRoot.Task; + + var element = vm.PropertyRoot.Value.Children.First (p => p.Property.Type == typeof(CommonThickness)); + await element.Children.Task; + var sub = element.Children.Value.First (); + vm.SelectedPropertyElement = sub; + + Assert.That (vm.Path, Is.EqualTo ($"{element.Property.Name}.{sub.Property.Name}")); + } + + [Test] + public async Task SelectedBindingSource () + { + BindingSource[] sources = new[] { + new BindingSource ("First", BindingSourceType.Object), + new BindingSource ("Second", BindingSourceType.Resource), + new BindingSource ("Third", BindingSourceType.Type), + }; + + var vm = CreateBasicViewModel (sources); + + while (vm.SelectedObjects.Count == 0) { + await Task.Delay (1); + } + + var binding = (MockBinding)vm.SelectedObjects.First (); + + Assert.That (vm.SelectedBindingSource, Is.EqualTo (sources[0])); + Assert.That (binding.Source, Is.EqualTo (sources[0]), "Backing binding object property didn't update"); + + bool propertyChanged = false, objectRootsChanged = false, resourceRootsChanged = false, typeRootsChanged = false; + vm.PropertyChanged += (o, e) => { + if (e.PropertyName == nameof(CreateBindingViewModel.SelectedBindingSource)) + propertyChanged = true; + else if (e.PropertyName == nameof(CreateBindingViewModel.ObjectElementRoots)) + objectRootsChanged = true; + else if (e.PropertyName == nameof(CreateBindingViewModel.SourceResources)) + resourceRootsChanged = true; + else if (e.PropertyName == nameof(CreateBindingViewModel.TypeSelector)) + typeRootsChanged = true; + }; + + vm.SelectedBindingSource = sources[1]; + Assert.That (propertyChanged, Is.True, "INPC did not fire for SelectedBindingSource"); + Assert.That (binding.Source, Is.EqualTo (sources[1]), "Backing binding object property didn't update"); + Assert.That (resourceRootsChanged, Is.True, "SourceResources did not update when selected"); + Assert.That (vm.SourceResources, Is.Not.Null); + Assert.That (objectRootsChanged, Is.False); + Assert.That (typeRootsChanged, Is.False); + + propertyChanged = objectRootsChanged = resourceRootsChanged = typeRootsChanged = false; + vm.SelectedBindingSource = sources[2]; + Assert.That (propertyChanged, Is.True, "INPC did not fire for SelectedBindingSource"); + Assert.That (binding.Source, Is.EqualTo (sources[2]), "Backing binding object property didn't update"); + Assert.That (resourceRootsChanged, Is.False); + Assert.That (objectRootsChanged, Is.False); + Assert.That (typeRootsChanged, Is.True, "TypeSelector didn't update when selected"); + Assert.That (vm.TypeSelector, Is.Not.Null); + + propertyChanged = objectRootsChanged = resourceRootsChanged = typeRootsChanged = false; + vm.SelectedBindingSource = sources[0]; + Assert.That (propertyChanged, Is.True, "INPC did not fire for SelectedBindingSource"); + Assert.That (binding.Source, Is.EqualTo (sources[0]), "Backing binding object property didn't update"); + Assert.That (resourceRootsChanged, Is.False); + Assert.That (objectRootsChanged, Is.True, "ObjectElementRoots didn't update when selected"); + Assert.That (vm.ObjectElementRoots, Is.Not.Null); + Assert.That (typeRootsChanged, Is.False); + } + + [Test] + public async Task ShowSourceParameterSelectors () + { + BindingSource[] sources = new[] { + new BindingSource ("First", BindingSourceType.Object), + new BindingSource ("Second", BindingSourceType.Resource), + new BindingSource ("Third", BindingSourceType.Type), + }; + + var vm = CreateBasicViewModel (sources); + + while (vm.SelectedObjects.Count == 0) { + await Task.Delay (1); + } + + Assume.That (vm.SelectedBindingSource, Is.EqualTo (sources[0])); + + bool objectChanged = false, resourceChanged = false, typeChanged = false; + vm.PropertyChanged += (o, e) => { + if (e.PropertyName == nameof (CreateBindingViewModel.ShowObjectSelector)) + objectChanged = true; + else if (e.PropertyName == nameof (CreateBindingViewModel.ShowResourceSelector)) + resourceChanged = true; + else if (e.PropertyName == nameof (CreateBindingViewModel.ShowTypeSelector)) + typeChanged = true; + }; + + vm.SelectedBindingSource = sources[1]; + Assert.That (resourceChanged, Is.True); + Assert.That (vm.ShowResourceSelector, Is.True); + Assert.That (objectChanged, Is.True, "Did not signal old selector changed"); + Assert.That (vm.ShowObjectSelector, Is.False); + Assert.That (vm.ShowTypeSelector, Is.False); + + objectChanged = resourceChanged = typeChanged = false; + vm.SelectedBindingSource = sources[2]; + Assert.That (resourceChanged, Is.True); + Assert.That (vm.ShowResourceSelector, Is.False); + Assert.That (objectChanged, Is.True, "Did not signal old selector changed"); + Assert.That (vm.ShowObjectSelector, Is.False); + Assert.That (vm.ShowTypeSelector, Is.True); + + objectChanged = resourceChanged = typeChanged = false; + vm.SelectedBindingSource = sources[0]; + Assert.That (vm.ShowResourceSelector, Is.False); + Assert.That (objectChanged, Is.True); + Assert.That (vm.ShowObjectSelector, Is.True); + Assert.That (typeChanged, Is.True, "Did not signal old selector changed"); + Assert.That (vm.ShowTypeSelector, Is.False); + } + + [Test] + public async Task ResourceRoots () + { + object target = new object(); + var property = GetBasicProperty (); + var editor = GetBasicEditor (target, property.Object); + var resources = new MockResourceProvider (); + var bindings = GetBasicBindingProvider (target, property.Object); + var source = new BindingSource ("Resources", BindingSourceType.Resource); + bindings.Setup (bp => bp.GetBindingSourcesAsync (target, property.Object)).ReturnsAsync (new[] { source }); + bindings.Setup (bp => bp.GetResourcesAsync (source, target)) + .Returns<BindingSource,object> (async (bs, t) => { + var rs = await resources.GetResourcesAsync (target, CancellationToken.None); + return rs.ToLookup (r => r.Source); + }); + + var vm = new CreateBindingViewModel ( + new TargetPlatform (new MockEditorProvider (editor.Object), resources, bindings.Object), editor.Object, + property.Object); + + Assume.That (vm.SelectedBindingSource, Is.EqualTo (source)); + + Assert.That (vm.SourceResources, Is.Not.Null); + await vm.SourceResources.Task; + Assert.That (vm.SourceResources.Value.First().Key, Is.EqualTo (DefaultResourceSources[0])); + } + + [Test] + public async Task ResourceProperties () + { + object target = new object (); + var property = GetBasicProperty (); + var editor = GetBasicEditor (target, property.Object); + var resources = new MockResourceProvider (); + var source = new BindingSource ("Resources", BindingSourceType.Resource); + var bindings = GetBasicBindingProvider (target, property.Object, sources: new [] { source }); + bindings.Setup (bp => bp.GetResourcesAsync (source, target)) + .Returns<BindingSource, object> (async (bs, t) => { + var rs = await resources.GetResourcesAsync (target, CancellationToken.None); + return rs.ToLookup (r => r.Source); + }); + + var vm = new CreateBindingViewModel ( + new TargetPlatform (new MockEditorProvider (editor.Object), resources, bindings.Object), editor.Object, + property.Object); + + Assume.That (vm.SelectedBindingSource, Is.EqualTo (source)); + Assume.That (vm.SourceResources, Is.Not.Null); + await vm.SourceResources.Task; + + while (vm.SelectedObjects.Count == 0) { + await Task.Delay (1); + } + + var binding = (MockBinding)vm.SelectedObjects.First(); + vm.SelectedResource = vm.SourceResources.Value.First ().OfType<Resource<CommonSolidBrush>>().First (); + Assert.That (binding.SourceParameter, Is.EqualTo (vm.SelectedResource)); + Assume.That (vm.PropertyRoot, Is.Not.Null); + await vm.PropertyRoot.Task; + + Assert.That (vm.PropertyRoot.Value.TargetType, Is.EqualTo (typeof(CommonSolidBrush).ToTypeInfo ())); + CollectionAssert.AreEqual (ReflectionEditorProvider.GetPropertiesForType (typeof(CommonSolidBrush)), + vm.PropertyRoot.Value.Children.Select (pe => pe.Property)); + } + + [Test] + public async Task Types () + { + object target = new object (); + var property = GetBasicProperty (); + var editor = GetBasicEditor (target, property.Object); + var resources = new MockResourceProvider (); + var source = new BindingSource ("Resources", BindingSourceType.Type); + + var type = typeof(MockSampleControl).ToTypeInfo (); + var bindings = GetBasicBindingProvider (target, property.Object, sources: new[] { source }); + bindings.Setup (bp => bp.GetSourceTypesAsync (source, target)) + .ReturnsAsync (new AssignableTypesResult (new[] { type })); + + var provider = new MockEditorProvider (editor.Object); + var vm = new CreateBindingViewModel (new TargetPlatform (provider, resources, bindings.Object), editor.Object, property.Object); + + Assume.That (vm.SelectedBindingSource, Is.EqualTo (source)); + Assume.That (vm.TypeSelector, Is.Not.Null); + + while (vm.SelectedObjects.Count == 0 && vm.TypeSelector.IsLoading) { + await Task.Delay (1); + } + + var binding = (MockBinding) vm.SelectedObjects.First (); + + Assert.That (vm.TypeSelector.SelectedType, Is.Null); + + bool propertyChanged = false; + vm.PropertyChanged += (o, e) => { + if (e.PropertyName == nameof(CreateBindingViewModel.PropertyRoot)) + propertyChanged = true; + }; + + vm.TypeSelector.SelectedType = type; + Assert.That (propertyChanged, Is.True, "INPC didn't change for PropertyRoot on selected source param"); + Assert.That (vm.PropertyRoot, Is.Not.Null); + Assert.That (binding.SourceParameter, Is.EqualTo (type)); + + await vm.PropertyRoot.Task; + CollectionAssert.AreEqual (provider.GetPropertiesForTypeAsync (type).Result, + vm.PropertyRoot.Value.Children.Select (pe => pe.Property)); + } + + [Test] + public async Task ExtraProperties () + { + var provider = new MockEditorProvider(); + var vm = CreateBasicViewModel (); + + var editors = (IList<IObjectEditor>)typeof(CreateBindingViewModel).GetProperty ("ObjectEditors", BindingFlags.NonPublic | BindingFlags.Instance) + .GetValue (vm); // Shortcut + var editor = editors[0]; + + IEnumerable<IPropertyInfo> properties = (await provider.GetPropertiesForTypeAsync (typeof(MockBinding).ToTypeInfo ())); + CollectionAssert.AreEqual (properties, vm.Properties.Cast<PropertyViewModel> ().Select (pvm => pvm.Property)); + + properties = properties.Where (p => !editor.KnownProperties.ContainsKey (p)); + CollectionAssert.AreEqual (properties.Where (p => p.Type == typeof(bool)), + vm.FlagsProperties.Cast<PropertyViewModel> ().Select (pvm => pvm.Property)); + CollectionAssert.AreEqual (properties.Where (p => p.Type != typeof (bool)), + vm.BindingProperties.Cast<PropertyViewModel> ().Select (pvm => pvm.Property)); + } + + private AsyncSynchronizationContext syncContext; + private static readonly ResourceSource[] DefaultResourceSources = new[] { MockResourceProvider.SystemResourcesSource, MockResourceProvider.ApplicationResourcesSource }; + + private Mock<IPropertyInfo> GetBasicProperty (string name = "propertyName") + { + var property = new Mock<IPropertyInfo> (); + property.SetupGet (p => p.ValueSources).Returns (ValueSources.Local | ValueSources.Binding); + property.SetupGet (p => p.Type).Returns (typeof (string)); + property.SetupGet (p => p.Name).Returns (name); + property.SetupGet (p => p.RealType).Returns (typeof (string).ToTypeInfo ()); + property.SetupGet (p => p.CanWrite).Returns (true); + + return property; + } + + private Mock<IObjectEditor> GetBasicEditor (object target, IPropertyInfo property) + { + var editor = new Mock<IObjectEditor> (); + editor.SetupGet (e => e.Properties).Returns (new[] { property }); + editor.SetupGet (e => e.Target).Returns (target); + editor.SetupGet (e => e.TargetType).Returns (typeof (object).ToTypeInfo ()); + + return editor; + } + + private Mock<IResourceProvider> GetBasicResourceProvider (object target, ResourceSource[] sources = null) + { + sources = sources ?? DefaultResourceSources; + + var resources = new Mock<IResourceProvider> (); + resources.Setup (r => r.GetResourceSourcesAsync (target)).ReturnsAsync (sources); + resources.Setup (r => r.CreateResourceAsync (It.IsAny<ResourceSource> (), It.IsAny<string> (), It.IsAny<object> ())) + .ReturnsAsync ((Func<ResourceSource, string, object, Resource>) ((s, n, v) => new Resource (s, n))); + return resources; + } + + private Mock<IBindingProvider> GetBasicBindingProvider (object target, IPropertyInfo property, BindingSource[] sources = null) + { + var bpmock = new Mock<IBindingProvider> (); + + if (sources == null) { + sources = new[] { + new BindingSource ("Short Description", BindingSourceType.Object, "Short Description"), + new BindingSource ("Long Description", BindingSourceType.SingleObject, "Long Description"), + }; + + bpmock.Setup (bp => bp.GetRootElementsAsync (sources[0], target)).ReturnsAsync (new[] { new object (), new object () }); + bpmock.Setup (bp => bp.GetRootElementsAsync (sources[1], target)).ReturnsAsync (new[] { new object () }); + } else { + for (int i = 0; i < sources.Length; i++) { + int index = i; + if (sources[i].Type == BindingSourceType.SingleObject) + bpmock.Setup (bp => bp.GetRootElementsAsync (sources[index], target)).ReturnsAsync (new[] { new object () }); + else + bpmock.Setup (bp => bp.GetRootElementsAsync (sources[index], target)).ReturnsAsync (new[] { new object (), new object() }); + } + } + + bpmock.Setup (bp => bp.GetBindingSourcesAsync (target, property)).ReturnsAsync (sources); + bpmock.Setup (bp => bp.GetValueConverterResourcesAsync (It.IsAny<object> ())).ReturnsAsync (new Resource[0]); + return bpmock; + } + + private CreateBindingViewModel CreateBasicViewModel (BindingSource[] sources = null, object target = null) + { + target = target ?? new object (); + Mock<IPropertyInfo> property = GetBasicProperty (); + Mock<IObjectEditor> editor = GetBasicEditor (target, property.Object); + + var editorProvider = new MockEditorProvider (editor.Object); + Mock<IResourceProvider> resourceProvider = GetBasicResourceProvider (target); + Mock<IBindingProvider> bpmock = GetBasicBindingProvider (target, property.Object, sources); + + return new CreateBindingViewModel (new TargetPlatform (editorProvider, resourceProvider.Object, bpmock.Object), editor.Object, property.Object); + } + } +}
\ No newline at end of file diff --git a/Xamarin.PropertyEditing.Tests/CreateResourceViewModelTests.cs b/Xamarin.PropertyEditing.Tests/CreateResourceViewModelTests.cs index c3c4192..fd70270 100644 --- a/Xamarin.PropertyEditing.Tests/CreateResourceViewModelTests.cs +++ b/Xamarin.PropertyEditing.Tests/CreateResourceViewModelTests.cs @@ -1,9 +1,6 @@ using System; using System.Collections.Generic; -<<<<<<< HEAD using System.Linq; -======= ->>>>>>> [Core/Win] Create resource core/window using System.Threading; using System.Threading.Tasks; using Moq; diff --git a/Xamarin.PropertyEditing.Tests/MockBindingEditor.cs b/Xamarin.PropertyEditing.Tests/MockBindingEditor.cs new file mode 100644 index 0000000..45ab099 --- /dev/null +++ b/Xamarin.PropertyEditing.Tests/MockBindingEditor.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Xamarin.PropertyEditing.Reflection; + +namespace Xamarin.PropertyEditing.Tests +{ + internal class MockBindingEditor + : IObjectEditor + { + public MockBindingEditor (MockBinding binding) + { + Target = binding; + this.editor = new ReflectionObjectEditor (binding); + this.editor.PropertyChanged += (sender, args) => { + PropertyChanged?.Invoke (this, args); + }; + + KnownProperties = new Dictionary<IPropertyInfo, KnownProperty> { + { this.editor.Properties.Single (pi => pi.Name == nameof(MockBinding.Source)), PropertyBinding.SourceProperty }, + { this.editor.Properties.Single (pi => pi.Name == nameof(MockBinding.SourceParameter)), PropertyBinding.SourceParameterProperty }, + { this.editor.Properties.Single (pi => pi.Name == nameof(MockBinding.Path)), PropertyBinding.PathProperty }, + { this.editor.Properties.Single (pi => pi.Name == nameof(MockBinding.Converter)), PropertyBinding.ConverterProperty }, + { this.editor.Properties.Single (pi => pi.Name == nameof(MockBinding.TypeLevel)), PropertyBinding.TypeLevelProperty } + }; + } + + public event EventHandler<EditorPropertyChangedEventArgs> PropertyChanged; + + public object Target + { + get; + } + + public ITypeInfo TargetType => this.editor.TargetType; + + public IReadOnlyCollection<IPropertyInfo> Properties => this.editor.Properties; + + public IReadOnlyDictionary<IPropertyInfo, KnownProperty> KnownProperties + { + get; + } + + public IObjectEditor Parent => null; + + public IReadOnlyList<IObjectEditor> DirectChildren => null; + + public Task<AssignableTypesResult> GetAssignableTypesAsync (IPropertyInfo property, bool childTypes) + { + return this.editor.GetAssignableTypesAsync (property, childTypes); + } + + public Task SetValueAsync<T> (IPropertyInfo property, ValueInfo<T> value, PropertyVariation variation = null) + { + return this.editor.SetValueAsync (property, value, variation); + } + + public Task<ValueInfo<T>> GetValueAsync<T> (IPropertyInfo property, PropertyVariation variation = null) + { + return this.editor.GetValueAsync<T> (property, variation); + } + + private readonly ReflectionObjectEditor editor; + } +}
\ No newline at end of file diff --git a/Xamarin.PropertyEditing.Tests/MockBindingProvider.cs b/Xamarin.PropertyEditing.Tests/MockBindingProvider.cs new file mode 100644 index 0000000..8077ed4 --- /dev/null +++ b/Xamarin.PropertyEditing.Tests/MockBindingProvider.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Xamarin.PropertyEditing.Reflection; +using Xamarin.PropertyEditing.Tests.MockControls; + +namespace Xamarin.PropertyEditing.Tests +{ + public class MockBindingProvider + : IBindingProvider + { + public Task<IReadOnlyList<BindingSource>> GetBindingSourcesAsync (object target, IPropertyInfo property) + { + return Task.FromResult<IReadOnlyList<BindingSource>> (new[] { + new BindingSourceInstance (RelativeSelf, $"Bind [{target.GetType().Name}] to itself."), + StaticResource, + Ancestor + }); + } + + public Task<AssignableTypesResult> GetSourceTypesAsync (BindingSource source, object target) + { + return ReflectionObjectEditor.GetAssignableTypes (typeof(MockControl).ToTypeInfo (), childTypes: false); + } + + public Task<IReadOnlyList<object>> GetRootElementsAsync (BindingSource source, object target) + { + if (source == null) + throw new ArgumentNullException (nameof(source)); + if (source.Type != BindingSourceType.Object && source.Type != BindingSourceType.SingleObject) + throw new ArgumentException ("source.Type was not Object", nameof(source)); + + if (source is BindingSourceInstance instance) + source = instance.Original; + + if (source == RelativeSelf) + return Task.FromResult<IReadOnlyList<object>> (new [] { target }); + if (source == StaticResource) + return MockResourceProvider.GetResourceSourcesAsync (target).ContinueWith (t => (IReadOnlyList<object>) t.Result); + + throw new NotImplementedException(); + } + + public async Task<ILookup<ResourceSource, Resource>> GetResourcesAsync (BindingSource source, object target) + { + var results = await this.resources.GetResourcesAsync (target, CancellationToken.None).ConfigureAwait (false); + return results.ToLookup (r => r.Source); + } + + public Task<IReadOnlyList<Resource>> GetValueConverterResourcesAsync (object target) + { + return Task.FromResult<IReadOnlyList<Resource>> (Array.Empty<Resource> ()); + } + + private readonly MockResourceProvider resources = new MockResourceProvider(); + + private static readonly BindingSource Ancestor = new BindingSource ("RelativeSource FindAncestor", BindingSourceType.Type); + private static readonly BindingSource RelativeSelf = new BindingSource ("RelativeSource Self", BindingSourceType.SingleObject); + private static readonly BindingSource StaticResource = new BindingSource ("StaticResource", BindingSourceType.Resource); + + private class BindingSourceInstance + : BindingSource + { + public BindingSourceInstance (BindingSource original, string description) + : base (original.Name, original.Type, description) + { + Original = original; + } + + public BindingSource Original + { + get; + } + } + } + + public class MockBinding + { + public string Path + { + get; + set; + } + + public BindingSource Source + { + get; + set; + } + + public object SourceParameter + { + get; + set; + } + + public Resource Converter + { + get; + set; + } + + public string StringFormat + { + get; + set; + } + + public bool IsAsync + { + get; + set; + } + + public int TypeLevel + { + get; + set; + } + } +}
\ No newline at end of file diff --git a/Xamarin.PropertyEditing.Tests/MockControls/MockControl.cs b/Xamarin.PropertyEditing.Tests/MockControls/MockControl.cs index dbc30a6..b7685ba 100644 --- a/Xamarin.PropertyEditing.Tests/MockControls/MockControl.cs +++ b/Xamarin.PropertyEditing.Tests/MockControls/MockControl.cs @@ -14,7 +14,7 @@ namespace Xamarin.PropertyEditing.Tests.MockControls public void AddProperty<T> (string name, string category = null, bool canWrite = true, bool flag = false, IEnumerable<Type> converterTypes = null, - string description = null, ValueSources valueSources = ValueSources.Local | ValueSources.Default) + string description = null, ValueSources valueSources = ValueSources.Local | ValueSources.Default | ValueSources.Binding) { IPropertyInfo propertyInfo; if (typeof(T).IsEnum) { diff --git a/Xamarin.PropertyEditing.Tests/MockControls/MockResourceProvider.cs b/Xamarin.PropertyEditing.Tests/MockControls/MockResourceProvider.cs index cadded8..8d5e458 100644 --- a/Xamarin.PropertyEditing.Tests/MockControls/MockResourceProvider.cs +++ b/Xamarin.PropertyEditing.Tests/MockControls/MockResourceProvider.cs @@ -45,6 +45,13 @@ namespace Xamarin.PropertyEditing.Tests return Task.FromResult<Resource> (r); } + public Task<IReadOnlyList<Resource>> GetResourcesAsync (object target, CancellationToken cancelToken) + { + return Task.FromResult<IReadOnlyList<Resource>> (this.resources.SelectMany (g => g) + .Where (r => !(r.Source is ObjectResourceSource ors) || ReferenceEquals (target, ors.Target)) + .ToList ()); + } + public Task<IReadOnlyList<Resource>> GetResourcesAsync (object target, IPropertyInfo property, CancellationToken cancelToken) { return Task.FromResult<IReadOnlyList<Resource>> (this.resources.SelectMany (g => g) @@ -52,8 +59,18 @@ namespace Xamarin.PropertyEditing.Tests .ToList()); } + Task<IReadOnlyList<ResourceSource>> IResourceProvider.GetResourceSourcesAsync (object target) + { + return MockResourceProvider.GetResourceSourcesAsync (target); + } + public Task<IReadOnlyList<ResourceSource>> GetResourceSourcesAsync (object target, IPropertyInfo property) { + return GetResourceSourcesAsync (target); + } + + public static Task<IReadOnlyList<ResourceSource>> GetResourceSourcesAsync (object target) + { return Task.FromResult<IReadOnlyList<ResourceSource>> (new[] { SystemResourcesSource, ApplicationResourcesSource, Resources, Window, new ObjectResourceSource (target, target.GetType ().Name, ResourceSourceType.Document) }); } @@ -118,6 +135,15 @@ namespace Xamarin.PropertyEditing.Tests new Resource<CommonSolidBrush> (SystemResourcesSource, "ControlTextBrush", new CommonSolidBrush (0, 0, 0)), new Resource<CommonSolidBrush> (SystemResourcesSource, "HighlightBrush", new CommonSolidBrush (51, 153, 255)), new Resource<CommonSolidBrush> (SystemResourcesSource, "TransparentBrush", new CommonSolidBrush (0, 0, 0, 0)), + new Resource<CommonSolidBrush> (SystemResourcesSource, "ATextBrush", new CommonSolidBrush (0, 0, 0)), + new Resource<CommonSolidBrush> (SystemResourcesSource, "ATransparentBrush", new CommonSolidBrush (51, 153, 255)), + new Resource<CommonSolidBrush> (SystemResourcesSource, "AHighlightBrush", new CommonSolidBrush (0, 0, 0, 0)), + new Resource<CommonSolidBrush> (SystemResourcesSource, "BTextBrush", new CommonSolidBrush (0, 0, 0)), + new Resource<CommonSolidBrush> (SystemResourcesSource, "BHighlightBrush", new CommonSolidBrush (51, 153, 255)), + new Resource<CommonSolidBrush> (SystemResourcesSource, "BTransparentBrush", new CommonSolidBrush (0, 0, 0, 0)), + new Resource<CommonSolidBrush> (SystemResourcesSource, "CTextBrush", new CommonSolidBrush (0, 0, 0)), + new Resource<CommonSolidBrush> (SystemResourcesSource, "CHighlightBrush", new CommonSolidBrush (51, 153, 255)), + new Resource<CommonSolidBrush> (SystemResourcesSource, "CTransparentBrush", new CommonSolidBrush (0, 0, 0, 0)), new Resource<CommonColor> (SystemResourcesSource, "ControlTextColor", new CommonColor (0, 0, 0)), new Resource<CommonColor> (SystemResourcesSource, "HighlightColor", new CommonColor (51, 153, 255)) }, diff --git a/Xamarin.PropertyEditing.Tests/MockControls/MockSampleControl.cs b/Xamarin.PropertyEditing.Tests/MockControls/MockSampleControl.cs index 1f41595..3d8acde 100644 --- a/Xamarin.PropertyEditing.Tests/MockControls/MockSampleControl.cs +++ b/Xamarin.PropertyEditing.Tests/MockControls/MockSampleControl.cs @@ -8,12 +8,12 @@ namespace Xamarin.PropertyEditing.Tests.MockControls { public MockSampleControl() { - AddProperty<bool> ("Boolean", ReadWrite); + AddProperty<bool> ("Boolean", ReadWrite, valueSources: ValueSources.Local | ValueSources.Resource | ValueSources.Binding); AddProperty<bool> ("UnsetBoolean", ReadWrite, valueSources: ValueSources.Local); AddProperty<int> ("Integer", ReadWrite); AddProperty<int> ("UnsetInteger", ReadWrite, valueSources: ValueSources.Local); AddProperty<float> ("FloatingPoint", ReadWrite); - AddProperty<string> ("String", ReadWrite); + AddProperty<string> ("String", ReadWrite, valueSources: ValueSources.Local | ValueSources.Resource | ValueSources.Binding); AddProperty<Enumeration> ("Enumeration", ReadWrite); AddProperty<FlagsNoValues> ("FlagsNoValues", ReadWrite, canWrite: true, flag: true); AddProperty<FlagsWithValues> ("FlagsWithValues", ReadWrite, canWrite: true, flag: true); diff --git a/Xamarin.PropertyEditing.Tests/MockEditorProvider.cs b/Xamarin.PropertyEditing.Tests/MockEditorProvider.cs index e2ca470..2225bca 100644 --- a/Xamarin.PropertyEditing.Tests/MockEditorProvider.cs +++ b/Xamarin.PropertyEditing.Tests/MockEditorProvider.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using Xamarin.PropertyEditing.Common; +using Xamarin.PropertyEditing.Drawing; using Xamarin.PropertyEditing.Reflection; using Xamarin.PropertyEditing.Tests.MockControls; @@ -11,6 +13,26 @@ namespace Xamarin.PropertyEditing.Tests { public static readonly TargetPlatform MockPlatform = new TargetPlatform (new MockEditorProvider ()); + public MockEditorProvider () + { + } + + public MockEditorProvider (IObjectEditor editor) + { + this.editorCache.Add (editor.Target, editor); + } + + public IReadOnlyDictionary<Type, ITypeInfo> KnownTypes + { + get; + } = new Dictionary<Type, ITypeInfo> { + { typeof(PropertyBinding), typeof(MockBinding).ToTypeInfo() }, + { typeof(CommonValueConverter), typeof(MockValueConverter).ToTypeInfo() }, + { typeof(CommonBrush), typeof(CommonBrush).ToTypeInfo() }, + { typeof(CommonSolidBrush), typeof(CommonSolidBrush).ToTypeInfo() }, + { typeof(CommonColor), typeof(CommonColor).ToTypeInfo() } + }; + public Task<IObjectEditor> GetObjectEditorAsync (object item) { if (this.editorCache.TryGetValue (item, out IObjectEditor cachedEditor)) { @@ -23,9 +45,25 @@ namespace Xamarin.PropertyEditing.Tests public async Task<IReadOnlyCollection<IPropertyInfo>> GetPropertiesForTypeAsync (ITypeInfo type) { - object obj = await CreateObjectAsync (type).ConfigureAwait (false); - IObjectEditor editor = ChooseEditor (obj); - return editor.Properties; + Type realType = ReflectionEditorProvider.GetRealType (type); + if (realType == null) + return Array.Empty<IPropertyInfo> (); + + if (typeof(MockControl).IsAssignableFrom (realType)) { + object item = await CreateObjectAsync (type); + IObjectEditor editor = ChooseEditor (item); + return editor.Properties; + } + + return ReflectionEditorProvider.GetPropertiesForType (realType); + } + + public Task<AssignableTypesResult> GetAssignableTypesAsync (ITypeInfo type, bool childTypes) + { + if (type == KnownTypes[typeof(CommonValueConverter)]) + return Task.FromResult (new AssignableTypesResult (new[] { type })); + + return ReflectionObjectEditor.GetAssignableTypes (type, childTypes); } IObjectEditor ChooseEditor (object item) @@ -35,6 +73,8 @@ namespace Xamarin.PropertyEditing.Tests return new MockObjectEditor (msc); case MockControl mc: return new MockNameableEditor (mc); + case MockBinding mb: + return new MockBindingEditor (mb); default: return new ReflectionObjectEditor (item); } diff --git a/Xamarin.PropertyEditing.Tests/MockObjectEditor.cs b/Xamarin.PropertyEditing.Tests/MockObjectEditor.cs index aa193df..8da782c 100644 --- a/Xamarin.PropertyEditing.Tests/MockObjectEditor.cs +++ b/Xamarin.PropertyEditing.Tests/MockObjectEditor.cs @@ -144,12 +144,14 @@ namespace Xamarin.PropertyEditing.Tests public Task<AssignableTypesResult> GetAssignableTypesAsync (IPropertyInfo property, bool childTypes) { - if (this.assignableTypes == null) { - return ReflectionObjectEditor.GetAssignableTypes (property, childTypes); - } else if (!this.assignableTypes.TryGetValue (property, out IReadOnlyList<ITypeInfo> types)) - return Task.FromResult (new AssignableTypesResult (Enumerable.Empty<ITypeInfo> ().ToArray ())); - else - return Task.FromResult (new AssignableTypesResult (types)); + if (this.assignableTypes != null) { + if (!this.assignableTypes.TryGetValue (property, out IReadOnlyList<ITypeInfo> types)) + return Task.FromResult (new AssignableTypesResult (Enumerable.Empty<ITypeInfo> ().ToArray ())); + else + return Task.FromResult (new AssignableTypesResult (types)); + } + + return ReflectionObjectEditor.GetAssignableTypes (property.RealType, childTypes); } #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously @@ -310,6 +312,25 @@ namespace Xamarin.PropertyEditing.Tests Value = default(T) }; } + + public Task<ITypeInfo> GetValueTypeAsync (IPropertyInfo property, PropertyVariation variation = null) + { + if (variation != null) + throw new NotImplementedException(); + + Type type = property.Type; + if (this.values.TryGetValue (property, out object value)) { + Type valueType = value.GetType (); + if (valueType.IsConstructedGenericType && valueType.GetGenericTypeDefinition () == typeof(ValueInfo<>)) { + value = valueType.GetProperty ("Value").GetValue (value); + type = value.GetType (); + } else + type = valueType; + } + + var asm = new AssemblyInfo (type.Assembly.FullName, true); + return Task.FromResult<ITypeInfo> (new TypeInfo (asm, type.Namespace, type.Name)); + } #pragma warning restore CS1998 internal readonly IDictionary<IPropertyInfo, object> values = new Dictionary<IPropertyInfo, object> (); diff --git a/Xamarin.PropertyEditing.Tests/MockValueConverter.cs b/Xamarin.PropertyEditing.Tests/MockValueConverter.cs new file mode 100644 index 0000000..65d2bf9 --- /dev/null +++ b/Xamarin.PropertyEditing.Tests/MockValueConverter.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Xamarin.PropertyEditing.Tests +{ + internal class MockValueConverter + { + } +}
\ No newline at end of file diff --git a/Xamarin.PropertyEditing.Tests/PropertiesViewModelTests.cs b/Xamarin.PropertyEditing.Tests/PropertiesViewModelTests.cs index 713b3eb..8bd7ae2 100644 --- a/Xamarin.PropertyEditing.Tests/PropertiesViewModelTests.cs +++ b/Xamarin.PropertyEditing.Tests/PropertiesViewModelTests.cs @@ -674,7 +674,6 @@ namespace Xamarin.PropertyEditing.Tests Assert.That (property.Editors.Count, Is.EqualTo (1)); } - [Test] public void PropertiesListItemRemoved () { diff --git a/Xamarin.PropertyEditing.Tests/Xamarin.PropertyEditing.Tests.csproj b/Xamarin.PropertyEditing.Tests/Xamarin.PropertyEditing.Tests.csproj index ddcdd7d..ba02175 100644 --- a/Xamarin.PropertyEditing.Tests/Xamarin.PropertyEditing.Tests.csproj +++ b/Xamarin.PropertyEditing.Tests/Xamarin.PropertyEditing.Tests.csproj @@ -65,11 +65,15 @@ <Compile Include="BrushPropertyViewModelTests.cs" /> <Compile Include="BytePropertyViewModelTests.cs" /> <Compile Include="CollectionPropertyViewModelTests.cs" /> + <Compile Include="CreateBindingViewModelTests.cs" /> <Compile Include="CreateResourceViewModelTests.cs" /> <Compile Include="MaterialDesignColorViewModelTests.cs" /> <Compile Include="CombinablePredefinedViewModelTests.cs" /> + <Compile Include="MockBindingEditor.cs" /> + <Compile Include="MockBindingProvider.cs" /> <Compile Include="MockControls\MockResourceProvider.cs" /> <Compile Include="MockPropertyInfo\MockBrushPropertyInfo.cs" /> + <Compile Include="MockValueConverter.cs" /> <Compile Include="NumericTests.cs" /> <Compile Include="NumericViewModelTests.cs" /> <Compile Include="ResourceSelectorViewModelTests.cs" /> |