// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageSharp.Tests { using System; using System.Collections.Concurrent; using System.Reflection; /// /// Provides instances for parametric unit tests. /// /// The pixel format of the image public abstract class TestImageProvider : ITestImageFactory where TColor : struct, IPackedPixel, IEquatable { public PixelTypes PixelType { get; private set; } = typeof(TColor).GetPixelType(); public virtual string SourceFileOrDescription => ""; /// /// Utility instance to provide informations about the test image & manage input/output /// public ImagingTestCaseUtility Utility { get; private set; } public GenericFactory Factory { get; private set; } = new GenericFactory(); public static TestImageProvider Blank( int width, int height, MethodInfo testMethod = null, PixelTypes pixelTypeOverride = PixelTypes.Undefined) => new BlankProvider(width, height).Init(testMethod, pixelTypeOverride); public static TestImageProvider File( string filePath, MethodInfo testMethod = null, PixelTypes pixelTypeOverride = PixelTypes.Undefined) { return new FileProvider(filePath).Init(testMethod, pixelTypeOverride); } public static TestImageProvider Lambda( Func, Image> func, MethodInfo testMethod = null, PixelTypes pixelTypeOverride = PixelTypes.Undefined) => new LambdaProvider(func).Init(testMethod, pixelTypeOverride); public static TestImageProvider Solid( int width, int height, byte r, byte g, byte b, byte a = 255, MethodInfo testMethod = null, PixelTypes pixelTypeOverride = PixelTypes.Undefined) { return new SolidProvider(width, height, r, g, b, a).Init(testMethod, pixelTypeOverride); } /// /// Returns an instance to the test case with the necessary traits. /// public abstract Image GetImage(); protected TestImageProvider Init(MethodInfo testMethod, PixelTypes pixelTypeOverride) { if (pixelTypeOverride != PixelTypes.Undefined) { this.PixelType = pixelTypeOverride; } if (pixelTypeOverride == PixelTypes.StandardImageClass) { this.Factory = new DefaultImageClassSpecificFactory() as GenericFactory; } this.Utility = new ImagingTestCaseUtility() { SourceFileOrDescription = this.SourceFileOrDescription, PixelTypeName = typeof(TColor).Name }; if (testMethod != null) { this.Utility.Init(testMethod); } return this; } private class BlankProvider : TestImageProvider { public BlankProvider(int width, int height) { this.Width = width; this.Height = height; } public override string SourceFileOrDescription => $"Blank{this.Width}x{this.Height}"; protected int Height { get; } protected int Width { get; } public override Image GetImage() => this.Factory.CreateImage(this.Width, this.Height); } private class FileProvider : TestImageProvider { private static ConcurrentDictionary> cache = new ConcurrentDictionary>(); private string filePath; public FileProvider(string filePath) { this.filePath = filePath; } public override string SourceFileOrDescription => this.filePath; public override Image GetImage() { var cachedImage = cache.GetOrAdd( this.filePath, fn => { var testFile = TestFile.Create(this.filePath); return this.Factory.CreateImage(testFile.Bytes); }); return new Image(cachedImage); } } private class LambdaProvider : TestImageProvider { private readonly Func, Image> creator; public LambdaProvider(Func, Image> creator) { this.creator = creator; } public override Image GetImage() => this.creator(this.Factory); } private class SolidProvider : BlankProvider { private readonly byte a; private readonly byte b; private readonly byte g; private readonly byte r; public SolidProvider(int width, int height, byte r, byte g, byte b, byte a) : base(width, height) { this.r = r; this.g = g; this.b = b; this.a = a; } public override string SourceFileOrDescription => $"Solid{this.Width}x{this.Height}_({this.r},{this.g},{this.b},{this.a})"; public override Image GetImage() { var image = base.GetImage(); TColor color = default(TColor); color.PackFromBytes(this.r, this.g, this.b, this.a); return image.Fill(color); } } } /// /// Marker /// public interface ITestImageFactory { } }