diff options
author | Bertrand Le Roy <beleroy@microsoft.com> | 2018-01-30 00:12:35 +0300 |
---|---|---|
committer | Bertrand Le Roy <beleroy@microsoft.com> | 2018-01-30 00:12:35 +0300 |
commit | 5a4160fd06f403b31b340fa602a673992d72caf5 (patch) | |
tree | b4900417466229eda4d875dd6b7d269008e6da52 | |
parent | 0fcb722f7478ffd344821a9464b80c69a9a96ba4 (diff) |
New resource provider interfaces and mock implementationbleroy-resources
9 files changed, 265 insertions, 27 deletions
diff --git a/Xamarin.PropertyEditing.Tests/MockResourceProvider.cs b/Xamarin.PropertyEditing.Tests/MockResourceProvider.cs new file mode 100644 index 0000000..c14c9f3 --- /dev/null +++ b/Xamarin.PropertyEditing.Tests/MockResourceProvider.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Xamarin.PropertyEditing.Tests +{ + public class MockResourceProvider : IResourceProvider + { + public MockResourceProvider(IEnumerable<ResourceSource> sources, IEnumerable<Resource> resources) + { + if (sources == null) { + throw new System.ArgumentNullException (nameof (sources)); + } + if (resources == null) { + throw new System.ArgumentNullException (nameof (resources)); + } + + this.sources = sources.ToArray (); + this.resources = resources.ToList (); + } + + public async Task<Resource> CreateResourceAsync<T> (ResourceSource source, string name, T value) + { + if (source == null) { + throw new System.ArgumentNullException (nameof (source)); + } + + var newResource = new Resource<T> (source, name, value); + this.resources.Add (newResource); + return await Task.FromResult<Resource>(newResource); + } + + public async Task<IReadOnlyList<Resource>> GetResourcesAsync (object target, IPropertyInfo property, CancellationToken cancelToken) + => await Task.FromResult ((IReadOnlyList<Resource>)(this.resources + .Where (r => property.Type.IsAssignableFrom (r.RepresentationType)) + .ToArray ())); + + public async Task<IReadOnlyList<ResourceSource>> GetResourceSourcesAsync (object target, IPropertyInfo property) + => await Task.FromResult(this.sources); + + IReadOnlyList<ResourceSource> sources; + IList<Resource> resources; + } +} diff --git a/Xamarin.PropertyEditing.Tests/MockResourceProviderTests.cs b/Xamarin.PropertyEditing.Tests/MockResourceProviderTests.cs new file mode 100644 index 0000000..8885504 --- /dev/null +++ b/Xamarin.PropertyEditing.Tests/MockResourceProviderTests.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; +using Xamarin.PropertyEditing.Tests.MockPropertyInfo; + +namespace Xamarin.PropertyEditing.Tests +{ + [TestFixture] + public class MockResourceProviderTests + { + [Test] + public async Task GetResourcesByPropertyType() + { + var source = new ResourceSource ("Source", true); + + var stringResource1 = new Resource<string> (source, "StringResource1", "One"); + var stringResource2 = new Resource<string> (source, "StringResource2", "Two"); + var intResource = new Resource<int> (source, "IntResource1", 1); + + var resourceProvider = new MockResourceProvider ( + new ResourceSource[] { source }, + new Resource[] { stringResource1, intResource, stringResource2 }); + + IReadOnlyList<Resource> strings = await resourceProvider.GetResourcesAsync (null, new MockPropertyInfo<string> ("StringProperty"), new CancellationToken()); + IReadOnlyList<Resource> ints = await resourceProvider.GetResourcesAsync (null, new MockPropertyInfo<int> ("IntProperty"), new CancellationToken ()); + + Assert.That (strings, Is.EquivalentTo (new[] { stringResource1, stringResource2 })); + Assert.That (ints, Is.EquivalentTo (new[] { intResource })); + } + + [Test] + public async Task GetResourcesByBaseType () + { + var source = new ResourceSource ("Source", true); + + var resourceA = new Resource<A> (source, "ResourceA", new A()); + var resourceB = new Resource<B> (source, "ResourceB", new B()); + + var resourceProvider = new MockResourceProvider ( + new ResourceSource[] { source }, + new Resource[] { resourceA, resourceB }); + + IReadOnlyList<Resource> resources = await resourceProvider.GetResourcesAsync (null, new MockPropertyInfo<A> ("AProperty"), new CancellationToken ()); + + Assert.That (resources, Is.EquivalentTo (new IResource<A>[] { resourceA, resourceB })); + } + + [Test] + public async Task CreateResourceAddsNewResources() + { + var source = new ResourceSource ("Source", true); + + var stringResource1 = new Resource<string> (source, "StringResource1", "One"); + + var resourceProvider = new MockResourceProvider ( + new ResourceSource[] { source }, + new Resource[] { stringResource1 }); + + var addedResource = await resourceProvider.CreateResourceAsync (source, "StringResource2", "Two") as Resource<string>; + + IReadOnlyList<Resource> strings = await resourceProvider.GetResourcesAsync (null, new MockPropertyInfo<string> ("StringProperty"), new CancellationToken ()); + + Assert.That (addedResource, Is.Not.Null); + Assert.That (addedResource.Name, Is.EqualTo ("StringResource2")); + Assert.That (addedResource.Value, Is.EqualTo ("Two")); + Assert.That (addedResource.Source, Is.EqualTo (source)); + Assert.That (strings, Is.EquivalentTo (new[] { stringResource1, addedResource })); + } + + [Test] + public async Task GetResourceSources() + { + var source1 = new ResourceSource ("Source1", true); + var source2 = new ResourceSource ("Source2", true); + + var resourceProvider = new MockResourceProvider ( + new ResourceSource[] { source1, source2 }, + new Resource[] { }); + + var sources = await resourceProvider.GetResourceSourcesAsync (null, null); + + Assert.That (sources, Is.EquivalentTo (new ResourceSource[] { source1, source2 })); + } + + private class A { } + private class B : A { } + } +} diff --git a/Xamarin.PropertyEditing.Tests/PropertyViewModelTests.cs b/Xamarin.PropertyEditing.Tests/PropertyViewModelTests.cs index 53191cc..bb62895 100644 --- a/Xamarin.PropertyEditing.Tests/PropertyViewModelTests.cs +++ b/Xamarin.PropertyEditing.Tests/PropertyViewModelTests.cs @@ -222,7 +222,7 @@ namespace Xamarin.PropertyEditing.Tests var resource = new Resource ("name"); var resourcesMock = new Mock<IResourceProvider> (); - resourcesMock.Setup (rp => rp.GetResourcesAsync (mockProperty.Object, It.IsAny<CancellationToken> ())).ReturnsAsync (new[] { resource }); + resourcesMock.Setup (rp => rp.GetResourcesAsync (null, mockProperty.Object, It.IsAny<CancellationToken> ())).ReturnsAsync (new[] { resource }); var vm = GetViewModel (mockProperty.Object, new[] { new Mock<IObjectEditor> ().Object }); vm.ResourceProvider = resourcesMock.Object; @@ -240,7 +240,7 @@ namespace Xamarin.PropertyEditing.Tests var resource = new Resource ("name"); var resourcesMock = new Mock<IResourceProvider> (); - resourcesMock.Setup (rp => rp.GetResourcesAsync (mockProperty.Object, It.IsAny<CancellationToken> ())).ReturnsAsync (new[] { resource }); + resourcesMock.Setup (rp => rp.GetResourcesAsync (null, mockProperty.Object, It.IsAny<CancellationToken> ())).ReturnsAsync (new[] { resource }); var vm = GetViewModel (mockProperty.Object, new[] { new Mock<IObjectEditor> ().Object }); vm.ResourceProvider = resourcesMock.Object; @@ -258,7 +258,7 @@ namespace Xamarin.PropertyEditing.Tests var resource = new Resource ("name"); var resourcesMock = new Mock<IResourceProvider> (); - resourcesMock.Setup (rp => rp.GetResourcesAsync (mockProperty.Object, It.IsAny<CancellationToken> ())).ReturnsAsync (new[] { resource }); + resourcesMock.Setup (rp => rp.GetResourcesAsync (null, mockProperty.Object, It.IsAny<CancellationToken> ())).ReturnsAsync (new[] { resource }); var vm = GetViewModel (mockProperty.Object, new[] { new Mock<IObjectEditor> ().Object }); vm.ResourceProvider = resourcesMock.Object; @@ -277,7 +277,7 @@ namespace Xamarin.PropertyEditing.Tests var value = GetNonDefaultRandomTestValue (); var resourcesMock = new Mock<IResourceProvider> (); - resourcesMock.Setup (rp => rp.GetResourcesAsync (mockProperty.Object, It.IsAny<CancellationToken> ())).ReturnsAsync (new[] { resource }); + resourcesMock.Setup (rp => rp.GetResourcesAsync (null, mockProperty.Object, It.IsAny<CancellationToken> ())).ReturnsAsync (new[] { resource }); var editor = new MockObjectEditor (mockProperty.Object); editor.ValueEvaluator = (info, o) => { @@ -303,7 +303,7 @@ namespace Xamarin.PropertyEditing.Tests var resource = new Resource ("name"); var resourcesMock = new Mock<IResourceProvider> (); - resourcesMock.Setup (rp => rp.GetResourcesAsync (mockProperty.Object, It.IsAny<CancellationToken> ())).ReturnsAsync (new[] { resource }); + resourcesMock.Setup (rp => rp.GetResourcesAsync (null, mockProperty.Object, It.IsAny<CancellationToken> ())).ReturnsAsync (new[] { resource }); var vm = GetViewModel (mockProperty.Object, new[] { new Mock<IObjectEditor> ().Object }); Assume.That (vm.ResourceProvider, Is.Null); @@ -323,7 +323,7 @@ namespace Xamarin.PropertyEditing.Tests var resource = new Resource ("name"); var resourcesMock = new Mock<IResourceProvider> (); - resourcesMock.Setup (rp => rp.GetResourcesAsync (mockProperty.Object, It.IsAny<CancellationToken> ())).ReturnsAsync (new[] { resource }); + resourcesMock.Setup (rp => rp.GetResourcesAsync (null, mockProperty.Object, It.IsAny<CancellationToken> ())).ReturnsAsync (new[] { resource }); var editor = new MockObjectEditor (mockProperty.Object); await editor.SetValueAsync (mockProperty.Object, new ValueInfo<TValue> { diff --git a/Xamarin.PropertyEditing.Tests/Xamarin.PropertyEditing.Tests.csproj b/Xamarin.PropertyEditing.Tests/Xamarin.PropertyEditing.Tests.csproj index 6f980c0..56f6e78 100644 --- a/Xamarin.PropertyEditing.Tests/Xamarin.PropertyEditing.Tests.csproj +++ b/Xamarin.PropertyEditing.Tests/Xamarin.PropertyEditing.Tests.csproj @@ -61,6 +61,8 @@ <Compile Include="BoolViewModelTests.cs" /> <Compile Include="BrushPropertyViewModelTests.cs" /> <Compile Include="BytePropertyViewModelTests.cs" /> + <Compile Include="MockResourceProvider.cs" /> + <Compile Include="MockResourceProviderTests.cs" /> <Compile Include="SimpleCollectionViewTests.cs" /> <Compile Include="CommonColorTests.cs" /> <Compile Include="Helpers.cs" /> diff --git a/Xamarin.PropertyEditing/IResourceProvider.cs b/Xamarin.PropertyEditing/IResourceProvider.cs index 71a8d48..56a9d22 100644 --- a/Xamarin.PropertyEditing/IResourceProvider.cs +++ b/Xamarin.PropertyEditing/IResourceProvider.cs @@ -1,32 +1,31 @@ -using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace Xamarin.PropertyEditing { - public class Resource - { - public Resource (string name) - { - if (name == null) - throw new ArgumentNullException (nameof (name)); - - Name = name; - } - - public string Name - { - get; - } - } - public interface IResourceProvider { /// <summary> - /// Gets the resources available to the given <paramref name="property"/>. + /// Gets the resources available to the given <paramref name="target"/> and <paramref name="property"/>. /// </summary> - /// <exception cref="ArgumentNullException"><paramref name="property"/> is <c>null</c>.</exception> - Task<IReadOnlyList<Resource>> GetResourcesAsync (IPropertyInfo property, CancellationToken cancelToken); + /// <exception cref="ArgumentNullException"><paramref name="property"/> or <paramref name="target"/> is <c>null</c>.</exception> + /// <remarks> + /// <para> + /// Returned resources can either be of base class <see cref="Resource"/> or, whenever possible, of <see cref="Resource{T}"/> + /// including their relative representative value. This mean things like dynamic resources should, if possible, do a lookup + /// of its value relative to the <paramref name="target" /> and provide that value. + /// </para> + /// </remarks> + Task<IReadOnlyList<Resource>> GetResourcesAsync (object target, IPropertyInfo property, CancellationToken cancelToken); + + /// <summary> + /// Gets resource sources relative to the provided <paramref name="target"/>. + /// </summary> + Task<IReadOnlyList<ResourceSource>> GetResourceSourcesAsync (object target, IPropertyInfo property); + + /// <typeparam name="T">The representation type.</typeparam> + /// <param name="value">The value of the resource in it's representative form.</param> + Task<Resource> CreateResourceAsync<T> (ResourceSource source, string name, T value); } }
\ No newline at end of file diff --git a/Xamarin.PropertyEditing/Resource.cs b/Xamarin.PropertyEditing/Resource.cs new file mode 100644 index 0000000..bf6a1db --- /dev/null +++ b/Xamarin.PropertyEditing/Resource.cs @@ -0,0 +1,71 @@ +using System; + +namespace Xamarin.PropertyEditing +{ + public interface IResource + { + string Name { get; } + Type RepresentationType { get; } + ResourceSource Source { get; } + } + + public interface IResource<out T> + { + T Value { get; } + } + + public class Resource<T> + : Resource, IResource<T> + { + public Resource (ResourceSource source, string name, T value) + : base (source, name) + { + Value = value; + } + + public T Value + { + get; + } + + public override Type RepresentationType => typeof (T); + + public override string ToString () => $"{base.ToString ()}: {Value.ToString ()}"; + } + + public class Resource : IResource + { + public Resource (string name) + { + if (name == null) + throw new ArgumentNullException (nameof (name)); + + Name = name; + } + + public Resource (ResourceSource source, string name) + : this (name) + { + Source = source; + } + + /// <summary> + /// Gets the source for this resource. + /// </summary> + /// <remarks>This may be <c>null</c> when the resource is a dynamic reference that is unlocatable.</remarks> + public ResourceSource Source + { + get; + } + + /// <remarks>This may be <c>null</c> when the resource is a dynamic reference that is unlocatable.</remarks> + public virtual Type RepresentationType => null; + + public string Name + { + get; + } + + public override string ToString () => $"{Source.Name} - {Name}"; + } +}
\ No newline at end of file diff --git a/Xamarin.PropertyEditing/ResourceSource.cs b/Xamarin.PropertyEditing/ResourceSource.cs new file mode 100644 index 0000000..1ed5dcc --- /dev/null +++ b/Xamarin.PropertyEditing/ResourceSource.cs @@ -0,0 +1,29 @@ +using System; + +namespace Xamarin.PropertyEditing +{ + public class ResourceSource + { + public ResourceSource (string name, bool isLocal) + { + if (name == null) + throw new ArgumentNullException (nameof (name)); + + Name = name; + IsLocal = isLocal; + } + + public string Name + { + get; + } + + /// <summary> + /// Gets whether the source is local/relative to a target object. + /// </summary> + public bool IsLocal + { + get; + } + } +}
\ No newline at end of file diff --git a/Xamarin.PropertyEditing/ViewModels/PropertyViewModel.cs b/Xamarin.PropertyEditing/ViewModels/PropertyViewModel.cs index 5fdf85d..92a10ba 100644 --- a/Xamarin.PropertyEditing/ViewModels/PropertyViewModel.cs +++ b/Xamarin.PropertyEditing/ViewModels/PropertyViewModel.cs @@ -188,7 +188,8 @@ namespace Xamarin.PropertyEditing.ViewModels return; try { - IReadOnlyList<Resource> gottenResources = await provider.GetResourcesAsync (Property, cancelToken); + var target = Editors?.FirstOrDefault ()?.Target; + IReadOnlyList<Resource> gottenResources = await provider.GetResourcesAsync (target, Property, cancelToken); if (cancelToken.IsCancellationRequested) return; diff --git a/Xamarin.PropertyEditing/Xamarin.PropertyEditing.csproj b/Xamarin.PropertyEditing/Xamarin.PropertyEditing.csproj index ab7a4c7..4ce1d62 100644 --- a/Xamarin.PropertyEditing/Xamarin.PropertyEditing.csproj +++ b/Xamarin.PropertyEditing/Xamarin.PropertyEditing.csproj @@ -75,6 +75,7 @@ <Compile Include="IObjectEditor.cs" /> <Compile Include="IHavePredefinedValues.cs" /> <Compile Include="IPropertyInfo.cs" /> + <Compile Include="Resource.cs" /> <Compile Include="IResourceProvider.cs" /> <Compile Include="ISelfConstrainedPropertyInfo.cs" /> <Compile Include="ITypeInfo.cs" /> @@ -94,6 +95,7 @@ <Compile Include="Reflection\ReflectionEventInfo.cs" /> <Compile Include="Reflection\ReflectionObjectEditor.cs" /> <Compile Include="Reflection\ReflectionPropertyInfo.cs" /> + <Compile Include="ResourceSource.cs" /> <Compile Include="TargetPlatform.cs" /> <Compile Include="ValueInfo.cs" /> <Compile Include="ValueSource.cs" /> |