Browse Source

TestImageProvider.FileProvider cache is now aware of decoder parameters

pull/298/head
Anton Firszov 9 years ago
parent
commit
a103cb8ec7
  1. 85
      tests/ImageSharp.Tests/TestUtilities/ImageProviders/FileProvider.cs
  2. 154
      tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs
  3. 9
      tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs

85
tests/ImageSharp.Tests/TestUtilities/ImageProviders/FileProvider.cs

@ -7,6 +7,8 @@ namespace ImageSharp.Tests
{
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Reflection;
using ImageSharp.Formats;
using ImageSharp.PixelFormats;
@ -20,11 +22,86 @@ namespace ImageSharp.Tests
{
// Need PixelTypes in the dictionary key, because result images of TestImageProvider<TPixel>.FileProvider
// are shared between PixelTypes.Color & PixelTypes.Rgba32
private class Key : Tuple<PixelTypes, string, Type>
private class Key : IEquatable<Key>
{
public Key(PixelTypes pixelType, string filePath, Type customDecoderType = null)
: base(pixelType, filePath, customDecoderType)
private Tuple<PixelTypes, string, Type> commonValues;
private Dictionary<string, object> decoderParameters;
public Key(PixelTypes pixelType, string filePath, IImageDecoder customDecoder)
{
Type customType = customDecoder?.GetType();
this.commonValues = new Tuple<PixelTypes, string, Type>(pixelType, filePath, customType);
this.decoderParameters = GetDecoderParameters(customDecoder);
}
private static Dictionary<string, object> GetDecoderParameters(IImageDecoder customDecoder)
{
Type type = customDecoder.GetType();
var data = new Dictionary<string, object>();
while (type != null && type != typeof(object))
{
PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo p in properties)
{
string key = $"{type.FullName}.{p.Name}";
object value = p.GetValue(customDecoder);
data[key] = value;
}
type = type.GetTypeInfo().BaseType;
}
return data;
}
public bool Equals(Key other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
if (!this.commonValues.Equals(other.commonValues)) return false;
if (this.decoderParameters.Count != other.decoderParameters.Count)
{
return false;
}
foreach (KeyValuePair<string, object> kv in this.decoderParameters)
{
object otherVal;
if (!other.decoderParameters.TryGetValue(kv.Key, out otherVal))
{
return false;
}
if (!object.Equals(kv.Value, otherVal))
{
return false;
}
}
return true;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return this.Equals((Key)obj);
}
public override int GetHashCode()
{
return this.commonValues.GetHashCode();
}
public static bool operator ==(Key left, Key right)
{
return Equals(left, right);
}
public static bool operator !=(Key left, Key right)
{
return !Equals(left, right);
}
}
@ -53,7 +130,7 @@ namespace ImageSharp.Tests
{
Guard.NotNull(decoder, nameof(decoder));
Key key = new Key(this.PixelType, this.FilePath, decoder.GetType());
Key key = new Key(this.PixelType, this.FilePath, decoder);
Image<TPixel> cachedImage = cache.GetOrAdd(
key,

154
tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs

@ -7,6 +7,8 @@
namespace ImageSharp.Tests
{
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using ImageSharp.Formats;
@ -61,19 +63,7 @@ namespace ImageSharp.Tests
{
Assert.Equal(expected, provider.PixelType);
}
[Theory]
[WithBlankImages(1, 1, PixelTypes.Rgba32)]
[WithFile(TestImages.Bmp.F, PixelTypes.Rgba32)]
public void PixelTypes_ColorWithDefaultImageClass_TriggersCreatingTheNonGenericDerivedImageClass<TPixel>(
TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
Image<TPixel> img = provider.GetImage();
Assert.IsType<Image<Rgba32>>(img);
}
[Theory]
[WithFile(TestImages.Bmp.Car, PixelTypes.All, 88)]
[WithFile(TestImages.Bmp.F, PixelTypes.All, 88)]
@ -92,33 +82,153 @@ namespace ImageSharp.Tests
private class TestDecoder : IImageDecoder
{
public int InvocationCount { get; private set; } = 0;
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
invocationCounts[this.callerName]++;
return new Image<TPixel>(42, 42);
}
// Couldn't make xUnit happy without this hackery:
private static ConcurrentDictionary<string, int> invocationCounts = new ConcurrentDictionary<string, int>();
private string callerName = null;
internal void InitCaller(string name)
{
this.callerName = name;
invocationCounts[name] = 0;
}
internal static int GetInvocationCount(string callerName) => invocationCounts[callerName];
private static readonly object Monitor = new object();
public static void DoTestThreadSafe(Action action)
{
lock (Monitor)
{
action();
}
}
}
[Theory]
[WithFile(TestImages.Bmp.F, PixelTypes.Rgba32)]
public void GetImage_WithCustomParameterlessDecoder_ShouldUtilizeCache<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
Assert.NotNull(provider.Utility.SourceFileOrDescription);
TestDecoder.DoTestThreadSafe(
() =>
{
string testName = nameof(this.GetImage_WithCustomParameterlessDecoder_ShouldUtilizeCache);
var decoder = new TestDecoder();
decoder.InitCaller(testName);
provider.GetImage(decoder);
Assert.Equal(1, TestDecoder.GetInvocationCount(testName));
provider.GetImage(decoder);
Assert.Equal(1, TestDecoder.GetInvocationCount(testName));
});
}
private class TestDecoderWithParameters : IImageDecoder
{
public string Param1 { get; set; }
public int Param2 { get; set; }
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
this.InvocationCount++;
invocationCounts[this.callerName]++;
return new Image<TPixel>(42, 42);
}
private static ConcurrentDictionary<string, int> invocationCounts = new ConcurrentDictionary<string, int>();
private string callerName = null;
internal void InitCaller(string name)
{
this.callerName = name;
invocationCounts[name] = 0;
}
internal static int GetInvocationCount(string callerName) => invocationCounts[callerName];
private static readonly object Monitor = new object();
public static void DoTestThreadSafe(Action action)
{
lock (Monitor)
{
action();
}
}
}
[Theory]
[WithFile(TestImages.Bmp.F, PixelTypes.Rgba32)]
public void GetImage_WithCustomParametricDecoder_ShouldUtilizeCache_WhenParametersAreEqual<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
Assert.NotNull(provider.Utility.SourceFileOrDescription);
TestDecoderWithParameters.DoTestThreadSafe(
() =>
{
string testName =
nameof(this.GetImage_WithCustomParametricDecoder_ShouldUtilizeCache_WhenParametersAreEqual);
var decoder1 = new TestDecoderWithParameters() { Param1 = "Lol", Param2 = 666 };
decoder1.InitCaller(testName);
var decoder2 = new TestDecoderWithParameters() { Param1 = "Lol", Param2 = 666 };
decoder2.InitCaller(testName);
provider.GetImage(decoder1);
Assert.Equal(1, TestDecoderWithParameters.GetInvocationCount(testName));
provider.GetImage(decoder2);
Assert.Equal(1, TestDecoderWithParameters.GetInvocationCount(testName));
});
}
[Theory]
[WithFile(TestImages.Bmp.F, PixelTypes.Rgba32)]
public void GetImage_WithCustomDecoder_ShouldUtilizeCache<TPixel>(TestImageProvider<TPixel> provider)
public void GetImage_WithCustomParametricDecoder_ShouldNotUtilizeCache_WhenParametersAreNotEqual<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
Assert.NotNull(provider.Utility.SourceFileOrDescription);
var decoder = new TestDecoder();
TestDecoderWithParameters.DoTestThreadSafe(
() =>
{
string testName =
nameof(this.GetImage_WithCustomParametricDecoder_ShouldNotUtilizeCache_WhenParametersAreNotEqual);
var decoder1 = new TestDecoderWithParameters() { Param1 = "Lol", Param2 = 42 };
decoder1.InitCaller(testName);
provider.GetImage(decoder);
Assert.Equal(1, decoder.InvocationCount);
var decoder2 = new TestDecoderWithParameters() { Param1 = "LoL", Param2 = 42 };
decoder2.InitCaller(testName);
provider.GetImage(decoder);
Assert.Equal(1, decoder.InvocationCount);
provider.GetImage(decoder1);
Assert.Equal(1, TestDecoderWithParameters.GetInvocationCount(testName));
provider.GetImage(decoder2);
Assert.Equal(2, TestDecoderWithParameters.GetInvocationCount(testName));
});
}
public static string[] AllBmpFiles => TestImages.Bmp.All;
[Theory]
@ -224,4 +334,4 @@ namespace ImageSharp.Tests
Assert.True(img.Width * img.Height > 0);
}
}
}
}

9
tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs

@ -133,15 +133,6 @@ namespace ImageSharp.Tests
AssertContainsPixelType<RgbaVector>(PixelTypes.RgbaVector, expanded);
}
[Fact]
public void Anyad()
{
PixelTypes pixelTypes = PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.RgbaVector;
PixelTypes anyad = pixelTypes & PixelTypes.Bgr565;
this.Output.WriteLine(anyad.ToString());
}
[Fact]
public void ToTypes_All()
{

Loading…
Cancel
Save