mirror of https://github.com/SixLabors/ImageSharp
19 changed files with 1653 additions and 46 deletions
@ -0,0 +1,242 @@ |
|||||
|
// <copyright file="FlagsHelper.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
namespace ImageSharp.Tests |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper class for flag manipulation, based on
|
||||
|
/// <see>
|
||||
|
/// <cref>http://www.codeproject.com/KB/dotnet/enum.aspx</cref>
|
||||
|
/// </see>
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="T">Must be enum type (declared using <c>enum</c> keyword)</typeparam>
|
||||
|
public class FlagsHelper<T> |
||||
|
where T : struct, IConvertible |
||||
|
{ |
||||
|
private static readonly EnumConverter Converter; |
||||
|
|
||||
|
static FlagsHelper() |
||||
|
{ |
||||
|
Type type = typeof(T); |
||||
|
string[] names = Enum.GetNames(type); |
||||
|
var values = (T[])Enum.GetValues(type); |
||||
|
|
||||
|
Converter = new FlagsEnumConverter(names, values); |
||||
|
} |
||||
|
|
||||
|
public static T[] GetSortedValues() |
||||
|
{ |
||||
|
T[] vals = (T[])Enum.GetValues(typeof(T)); |
||||
|
Array.Sort(vals); |
||||
|
return vals; |
||||
|
} |
||||
|
|
||||
|
public static T Parse(string value, bool ignoreCase = false, bool parseNumeric = true) |
||||
|
{ |
||||
|
return (T)Enum.ToObject(typeof(T), Converter.ParseInternal(value, ignoreCase, parseNumeric)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Converts enum value to string
|
||||
|
/// </summary>
|
||||
|
/// <param name="value">Enum value converted to int</param>
|
||||
|
/// <returns>If <paramref name="value"/> is defined, the enum member name; otherwise the string representation of the <paramref name="value"/>.
|
||||
|
/// If <see cref="FlagsAttribute"/> is applied, can return comma-separated list of values</returns>
|
||||
|
public static string ToString(int value) |
||||
|
{ |
||||
|
return Converter.ToStringInternal(value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Converts enum value to string
|
||||
|
/// </summary>
|
||||
|
/// <param name="value">Enum value</param>
|
||||
|
/// <returns>If <paramref name="value"/> is defined, the enum member name; otherwise the string representation of the <paramref name="value"/>.
|
||||
|
/// If <see cref="FlagsAttribute"/> is applied, can return comma-separated list of values</returns>
|
||||
|
public static string ToString(T value) |
||||
|
{ |
||||
|
return Converter.ToStringInternal(value.ToInt32(null)); |
||||
|
} |
||||
|
|
||||
|
public static bool TryParse(string value, bool ignoreCase, bool parseNumeric, out T result) |
||||
|
{ |
||||
|
int ir; |
||||
|
bool b = Converter.TryParseInternal(value, ignoreCase, parseNumeric, out ir); |
||||
|
result = (T)Enum.ToObject(typeof(T), ir); |
||||
|
return b; |
||||
|
} |
||||
|
|
||||
|
public static bool TryParse(string value, bool ignoreCase, out T result) |
||||
|
{ |
||||
|
int ir; |
||||
|
bool b = Converter.TryParseInternal(value, ignoreCase, true, out ir); |
||||
|
result = (T)Enum.ToObject(typeof(T), ir); |
||||
|
return b; |
||||
|
} |
||||
|
|
||||
|
public static bool TryParse(string value, out T result) |
||||
|
{ |
||||
|
int ir; |
||||
|
bool b = Converter.TryParseInternal(value, false, true, out ir); |
||||
|
result = (T)Enum.ToObject(typeof(T), ir); |
||||
|
return b; |
||||
|
} |
||||
|
|
||||
|
class DictionaryEnumConverter : EnumConverter |
||||
|
{ |
||||
|
protected readonly Dictionary<int, string> Dic; |
||||
|
|
||||
|
protected DictionaryEnumConverter(string[] names, T[] values) |
||||
|
{ |
||||
|
this.Dic = new Dictionary<int, string>(names.Length); |
||||
|
for (int j = 0; j < names.Length; j++) this.Dic.Add(Convert.ToInt32(values[j], null), names[j]); |
||||
|
} |
||||
|
|
||||
|
public override int ParseInternal(string value, bool ignoreCase, bool parseNumber) |
||||
|
{ |
||||
|
if (value == null) throw new ArgumentNullException(nameof(value)); |
||||
|
if (value.Length == 0) throw new ArgumentException("Value is empty", nameof(value)); |
||||
|
char f = value[0]; |
||||
|
if (parseNumber && (char.IsDigit(f) || f == '+' || f == '-')) return int.Parse(value); |
||||
|
StringComparison stringComparison = ignoreCase |
||||
|
? StringComparison.OrdinalIgnoreCase |
||||
|
: StringComparison.Ordinal; |
||||
|
foreach (KeyValuePair<int, string> pair in this.Dic) |
||||
|
{ |
||||
|
if (pair.Value.Equals(value, stringComparison)) return pair.Key; |
||||
|
} |
||||
|
|
||||
|
throw new ArgumentException("Enum value wasn't found", nameof(value)); |
||||
|
} |
||||
|
|
||||
|
public override string ToStringInternal(int value) |
||||
|
{ |
||||
|
string n; |
||||
|
return this.Dic.TryGetValue(value, out n) ? n : value.ToString(); |
||||
|
} |
||||
|
|
||||
|
public override bool TryParseInternal(string value, bool ignoreCase, bool parseNumber, out int result) |
||||
|
{ |
||||
|
result = 0; |
||||
|
if (string.IsNullOrEmpty(value)) return false; |
||||
|
char f = value[0]; |
||||
|
if (parseNumber && (char.IsDigit(f) || f == '+' || f == '-')) |
||||
|
{ |
||||
|
int i; |
||||
|
if (int.TryParse(value, out i)) |
||||
|
{ |
||||
|
result = i; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
StringComparison stringComparison = ignoreCase |
||||
|
? StringComparison.OrdinalIgnoreCase |
||||
|
: StringComparison.Ordinal; |
||||
|
foreach (KeyValuePair<int, string> pair in this.Dic) |
||||
|
{ |
||||
|
if (pair.Value.Equals(value, stringComparison)) |
||||
|
{ |
||||
|
result = pair.Key; |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
abstract class EnumConverter |
||||
|
{ |
||||
|
public abstract int ParseInternal(string value, bool ignoreCase, bool parseNumber); |
||||
|
|
||||
|
public abstract string ToStringInternal(int value); |
||||
|
|
||||
|
public abstract bool TryParseInternal(string value, bool ignoreCase, bool parseNumber, out int result); |
||||
|
} |
||||
|
|
||||
|
class FlagsEnumConverter : DictionaryEnumConverter |
||||
|
{ |
||||
|
private static readonly string[] Seps = new[] { "," }; |
||||
|
|
||||
|
private readonly uint[] values; |
||||
|
|
||||
|
public FlagsEnumConverter(string[] names, T[] values) |
||||
|
: base(names, values) |
||||
|
{ |
||||
|
this.values = new uint[values.Length]; |
||||
|
for (int i = 0; i < values.Length; i++) this.values[i] = values[i].ToUInt32(null); |
||||
|
} |
||||
|
|
||||
|
public override int ParseInternal(string value, bool ignoreCase, bool parseNumber) |
||||
|
{ |
||||
|
string[] parts = value.Split(Seps, StringSplitOptions.RemoveEmptyEntries); |
||||
|
if (parts.Length == 1) return base.ParseInternal(value, ignoreCase, parseNumber); |
||||
|
int val = 0; |
||||
|
for (int i = 0; i < parts.Length; i++) |
||||
|
{ |
||||
|
string part = parts[i]; |
||||
|
int t = base.ParseInternal(part.Trim(), ignoreCase, parseNumber); |
||||
|
val |= t; |
||||
|
} |
||||
|
|
||||
|
return val; |
||||
|
} |
||||
|
|
||||
|
public override string ToStringInternal(int value) |
||||
|
{ |
||||
|
string n; |
||||
|
if (this.Dic.TryGetValue(value, out n)) return n; |
||||
|
var sb = new StringBuilder(); |
||||
|
const string sep = ", "; |
||||
|
uint uval; |
||||
|
unchecked |
||||
|
{ |
||||
|
uval = (uint)value; |
||||
|
|
||||
|
for (int i = this.values.Length - 1; i >= 0; i--) |
||||
|
{ |
||||
|
uint v = this.values[i]; |
||||
|
if (v == 0) continue; |
||||
|
if ((v & uval) == v) |
||||
|
{ |
||||
|
uval &= ~v; |
||||
|
sb.Insert(0, sep).Insert(0, this.Dic[(int)v]); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return uval == 0 && sb.Length > sep.Length ? sb.ToString(0, sb.Length - sep.Length) : value.ToString(); |
||||
|
} |
||||
|
|
||||
|
public override bool TryParseInternal(string value, bool ignoreCase, bool parseNumber, out int result) |
||||
|
{ |
||||
|
string[] parts = value.Split(Seps, StringSplitOptions.RemoveEmptyEntries); |
||||
|
if (parts.Length == 1) return base.TryParseInternal(value, ignoreCase, parseNumber, out result); |
||||
|
int val = 0; |
||||
|
for (int i = 0; i < parts.Length; i++) |
||||
|
{ |
||||
|
string part = parts[i]; |
||||
|
int t; |
||||
|
if (!base.TryParseInternal(part.Trim(), ignoreCase, parseNumber, out t)) |
||||
|
{ |
||||
|
result = 0; |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
val |= t; |
||||
|
} |
||||
|
|
||||
|
result = val; |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
// <copyright file="GenericFactory.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.Tests |
||||
|
{ |
||||
|
using System; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Utility class to create specialized subclasses of generic classes (eg. <see cref="Image"/>)
|
||||
|
/// Used as parameter for <see cref="WithMemberFactoryAttribute"/> -based factory methods
|
||||
|
/// </summary>
|
||||
|
public class GenericFactory<TColor> |
||||
|
where TColor : struct, IPackedPixel, IEquatable<TColor> |
||||
|
{ |
||||
|
public virtual Image<TColor> CreateImage(int width, int height) |
||||
|
{ |
||||
|
return new Image<TColor>(width, height); |
||||
|
} |
||||
|
|
||||
|
public virtual Image<TColor> CreateImage(byte[] bytes) |
||||
|
{ |
||||
|
return new Image<TColor>(bytes); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class DefaultImageClassSpecificFactory : GenericFactory<Color> |
||||
|
{ |
||||
|
public override Image<Color> CreateImage(byte[] bytes) => new Image(bytes); |
||||
|
|
||||
|
public override Image<Color> CreateImage(int width, int height) => new Image(width, height); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,75 @@ |
|||||
|
// <copyright file="ImageDataAttributeBase.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
namespace ImageSharp.Tests |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Diagnostics; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
|
||||
|
using Xunit.Sdk; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Base class for Theory Data attributes which pass an instance of <see cref="TestImageProvider{TColor}"/> to the test case.
|
||||
|
/// </summary>
|
||||
|
public abstract class ImageDataAttributeBase : DataAttribute |
||||
|
{ |
||||
|
protected readonly object[] AdditionalParameters; |
||||
|
|
||||
|
protected readonly PixelTypes PixelTypes; |
||||
|
|
||||
|
protected ImageDataAttributeBase(PixelTypes pixelTypes, object[] additionalParameters) |
||||
|
{ |
||||
|
this.PixelTypes = pixelTypes; |
||||
|
this.AdditionalParameters = additionalParameters; |
||||
|
} |
||||
|
|
||||
|
public override IEnumerable<object[]> GetData(MethodInfo testMethod) |
||||
|
{ |
||||
|
var type = testMethod.GetParameters().First().ParameterType; |
||||
|
if (!typeof(ITestImageFactory).IsAssignableFrom(type)) |
||||
|
{ |
||||
|
yield return this.AdditionalParameters; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
foreach (var kv in this.PixelTypes.ExpandAllTypes()) |
||||
|
{ |
||||
|
var factoryType = typeof(TestImageProvider<>).MakeGenericType(kv.Value); |
||||
|
|
||||
|
foreach (object[] originalFacoryMethodArgs in this.GetAllFactoryMethodArgs(testMethod, factoryType)) |
||||
|
{ |
||||
|
var actualFactoryMethodArgs = new object[originalFacoryMethodArgs.Length + 2]; |
||||
|
Array.Copy(originalFacoryMethodArgs, actualFactoryMethodArgs, originalFacoryMethodArgs.Length); |
||||
|
actualFactoryMethodArgs[actualFactoryMethodArgs.Length - 2] = testMethod; |
||||
|
actualFactoryMethodArgs[actualFactoryMethodArgs.Length - 1] = kv.Key; |
||||
|
|
||||
|
var factory = factoryType.GetMethod(this.GetFactoryMethodName(testMethod)) |
||||
|
.Invoke(null, actualFactoryMethodArgs); |
||||
|
|
||||
|
object[] result = new object[this.AdditionalParameters.Length + 1]; |
||||
|
result[0] = factory; |
||||
|
Array.Copy(this.AdditionalParameters, 0, result, 1, this.AdditionalParameters.Length); |
||||
|
yield return result; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected virtual IEnumerable<object[]> GetAllFactoryMethodArgs(MethodInfo testMethod, Type factoryType) |
||||
|
{ |
||||
|
var args = this.GetFactoryMethodArgs(testMethod, factoryType); |
||||
|
return Enumerable.Repeat(args, 1); |
||||
|
} |
||||
|
|
||||
|
protected virtual object[] GetFactoryMethodArgs(MethodInfo testMethod, Type factoryType) |
||||
|
{ |
||||
|
throw new InvalidOperationException("Semi-abstract method"); |
||||
|
} |
||||
|
|
||||
|
protected abstract string GetFactoryMethodName(MethodInfo testMethod); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,115 @@ |
|||||
|
// <copyright file="ImagingTestCaseUtility.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
namespace ImageSharp.Tests |
||||
|
{ |
||||
|
using System; |
||||
|
using System.IO; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
|
||||
|
using ImageSharp.Formats; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Utility class to provide information about the test image & the test case for the test code,
|
||||
|
/// and help managing IO.
|
||||
|
/// </summary>
|
||||
|
public class ImagingTestCaseUtility |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Name of the TColor in the owner <see cref="TestImageProvider{TColor}"/>
|
||||
|
/// </summary>
|
||||
|
public string PixelTypeName { get; set; } = string.Empty; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The name of the file which is provided by <see cref="TestImageProvider{TColor}"/>
|
||||
|
/// Or a short string describing the image in the case of a non-file based image provider.
|
||||
|
/// </summary>
|
||||
|
public string SourceFileOrDescription { get; set; } = string.Empty; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// By default this is the name of the test class, but it's possible to change it
|
||||
|
/// </summary>
|
||||
|
public string TestGroupName { get; set; } = string.Empty; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The name of the test case (by default)
|
||||
|
/// </summary>
|
||||
|
public string TestName { get; set; } = string.Empty; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Root directory for output images
|
||||
|
/// </summary>
|
||||
|
public string TestOutputRoot { get; set; } = FileTestBase.TestOutputRoot; |
||||
|
|
||||
|
public string GetTestOutputDir() |
||||
|
{ |
||||
|
string testGroupName = Path.GetFileNameWithoutExtension(this.TestGroupName); |
||||
|
|
||||
|
string dir = $@"{this.TestOutputRoot}{testGroupName}"; |
||||
|
Directory.CreateDirectory(dir); |
||||
|
return dir; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the recommended file name for the output of the test
|
||||
|
/// </summary>
|
||||
|
/// <param name="extension"></param>
|
||||
|
/// <returns>The required extension</returns>
|
||||
|
public string GetTestOutputFileName(string extension = null) |
||||
|
{ |
||||
|
string fn = string.Empty; |
||||
|
|
||||
|
fn = Path.GetFileNameWithoutExtension(this.SourceFileOrDescription); |
||||
|
extension = extension ?? Path.GetExtension(this.SourceFileOrDescription); |
||||
|
extension = extension ?? ".bmp"; |
||||
|
|
||||
|
if (extension[0] != '.') |
||||
|
{ |
||||
|
extension = '.' + extension; |
||||
|
} |
||||
|
|
||||
|
if (fn != string.Empty) fn = '_' + fn; |
||||
|
|
||||
|
string pixName = this.PixelTypeName; |
||||
|
if (pixName != string.Empty) |
||||
|
{ |
||||
|
pixName = '_' + pixName; |
||||
|
} |
||||
|
|
||||
|
return $"{this.GetTestOutputDir()}/{this.TestName}{pixName}{fn}{extension}"; |
||||
|
} |
||||
|
|
||||
|
private static IImageFormat GetImageFormatByExtension(string extension) |
||||
|
{ |
||||
|
extension = extension.ToLower(); |
||||
|
return Bootstrapper.ImageFormats.First(f => f.SupportedExtensions.Contains(extension)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Encodes image by the format matching the required extension, than saves it to the recommended output file.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TColor">The pixel format of the image</typeparam>
|
||||
|
/// <param name="image">The image instance</param>
|
||||
|
/// <param name="extension">The requested extension</param>
|
||||
|
public void SaveTestOutputFile<TColor>(Image<TColor> image, string extension = null) |
||||
|
where TColor : struct, IPackedPixel, IEquatable<TColor> |
||||
|
{ |
||||
|
string path = this.GetTestOutputFileName(extension); |
||||
|
|
||||
|
var format = GetImageFormatByExtension(extension); |
||||
|
|
||||
|
using (var stream = File.OpenWrite(path)) |
||||
|
{ |
||||
|
image.Save(stream, format); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal void Init(MethodInfo method) |
||||
|
{ |
||||
|
this.TestGroupName = method.DeclaringType.Name; |
||||
|
this.TestName = method.Name; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,62 @@ |
|||||
|
// <copyright file="PixelTypes.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
namespace ImageSharp.Tests |
||||
|
{ |
||||
|
using System; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Flags that are mapped to PackedPixel types.
|
||||
|
/// They trigger the desired parametrization for <see cref="TestImageProvider{TColor}"/>.
|
||||
|
/// </summary>
|
||||
|
[Flags] |
||||
|
public enum PixelTypes : uint |
||||
|
{ |
||||
|
Undefined = 0, |
||||
|
|
||||
|
Alpha8 = 1 << 0, |
||||
|
|
||||
|
Argb = 1 << 1, |
||||
|
|
||||
|
Bgr565 = 1 << 2, |
||||
|
|
||||
|
Bgra4444 = 1 << 3, |
||||
|
|
||||
|
Byte4 = 1 << 4, |
||||
|
|
||||
|
Color = 1 << 5, |
||||
|
|
||||
|
HalfSingle = 1 << 6, |
||||
|
|
||||
|
HalfVector2 = 1 << 7, |
||||
|
|
||||
|
HalfVector4 = 1 << 8, |
||||
|
|
||||
|
NormalizedByte2 = 1 << 9, |
||||
|
|
||||
|
NormalizedByte4 = 1 << 10, |
||||
|
|
||||
|
NormalizedShort4 = 1 << 11, |
||||
|
|
||||
|
Rg32 = 1 << 12, |
||||
|
|
||||
|
Rgba1010102 = 1 << 13, |
||||
|
|
||||
|
Rgba64 = 1 << 14, |
||||
|
|
||||
|
Short2 = 1 << 15, |
||||
|
|
||||
|
Short4 = 1 << 16, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Triggers instantiating the <see cref="Image"/> subclass of <see cref="Image{TColor}"/>
|
||||
|
/// </summary>
|
||||
|
StandardImageClass = 1 << 29, |
||||
|
|
||||
|
// TODO: Add multi-flag entries by rules defined in PackedPixelConverterHelper
|
||||
|
|
||||
|
// "All" is handled as a separate, individual case instead of using bitwise OR
|
||||
|
All = 30 |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,192 @@ |
|||||
|
// <copyright file="TestImageProvider.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.Tests |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Collections.Concurrent; |
||||
|
using System.Reflection; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Provides <see cref="Image{TColor}" /> instances for parametric unit tests.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TColor">The pixel format of the image</typeparam>
|
||||
|
public abstract class TestImageProvider<TColor> : ITestImageFactory |
||||
|
where TColor : struct, IPackedPixel, IEquatable<TColor> |
||||
|
{ |
||||
|
public PixelTypes PixelType { get; private set; } = typeof(TColor).GetPixelType(); |
||||
|
|
||||
|
public virtual string SourceFileOrDescription => ""; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Utility instance to provide informations about the test image & manage input/output
|
||||
|
/// </summary>
|
||||
|
public ImagingTestCaseUtility Utility { get; private set; } |
||||
|
|
||||
|
public GenericFactory<TColor> Factory { get; private set; } = new GenericFactory<TColor>(); |
||||
|
|
||||
|
public static TestImageProvider<TColor> Blank( |
||||
|
int width, |
||||
|
int height, |
||||
|
MethodInfo testMethod = null, |
||||
|
PixelTypes pixelTypeOverride = PixelTypes.Undefined) |
||||
|
=> new BlankProvider(width, height).Init(testMethod, pixelTypeOverride); |
||||
|
|
||||
|
public static TestImageProvider<TColor> File( |
||||
|
string filePath, |
||||
|
MethodInfo testMethod = null, |
||||
|
PixelTypes pixelTypeOverride = PixelTypes.Undefined) |
||||
|
{ |
||||
|
return new FileProvider(filePath).Init(testMethod, pixelTypeOverride); |
||||
|
} |
||||
|
|
||||
|
public static TestImageProvider<TColor> Lambda( |
||||
|
Func<GenericFactory<TColor>, Image<TColor>> func, |
||||
|
MethodInfo testMethod = null, |
||||
|
PixelTypes pixelTypeOverride = PixelTypes.Undefined) |
||||
|
=> new LambdaProvider(func).Init(testMethod, pixelTypeOverride); |
||||
|
|
||||
|
public static TestImageProvider<TColor> 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); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns an <see cref="Image{TColor}"/> instance to the test case with the necessary traits.
|
||||
|
/// </summary>
|
||||
|
public abstract Image<TColor> GetImage(); |
||||
|
|
||||
|
protected TestImageProvider<TColor> Init(MethodInfo testMethod, PixelTypes pixelTypeOverride) |
||||
|
{ |
||||
|
if (pixelTypeOverride != PixelTypes.Undefined) |
||||
|
{ |
||||
|
this.PixelType = pixelTypeOverride; |
||||
|
} |
||||
|
|
||||
|
if (pixelTypeOverride == PixelTypes.StandardImageClass) |
||||
|
{ |
||||
|
this.Factory = new DefaultImageClassSpecificFactory() as GenericFactory<TColor>; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
this.Utility = new ImagingTestCaseUtility() |
||||
|
{ |
||||
|
SourceFileOrDescription = this.SourceFileOrDescription, |
||||
|
PixelTypeName = typeof(TColor).Name |
||||
|
}; |
||||
|
|
||||
|
if (testMethod != null) |
||||
|
{ |
||||
|
this.Utility.Init(testMethod); |
||||
|
} |
||||
|
|
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
private class BlankProvider : TestImageProvider<TColor> |
||||
|
{ |
||||
|
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<TColor> GetImage() => this.Factory.CreateImage(this.Width, this.Height); |
||||
|
} |
||||
|
|
||||
|
private class FileProvider : TestImageProvider<TColor> |
||||
|
{ |
||||
|
private static ConcurrentDictionary<string, Image<TColor>> cache = |
||||
|
new ConcurrentDictionary<string, Image<TColor>>(); |
||||
|
|
||||
|
private string filePath; |
||||
|
|
||||
|
public FileProvider(string filePath) |
||||
|
{ |
||||
|
this.filePath = filePath; |
||||
|
} |
||||
|
|
||||
|
public override string SourceFileOrDescription => this.filePath; |
||||
|
|
||||
|
public override Image<TColor> GetImage() |
||||
|
{ |
||||
|
var cachedImage = cache.GetOrAdd( |
||||
|
this.filePath, |
||||
|
fn => |
||||
|
{ |
||||
|
var testFile = TestFile.Create(this.filePath); |
||||
|
return this.Factory.CreateImage(testFile.Bytes); |
||||
|
}); |
||||
|
|
||||
|
return new Image<TColor>(cachedImage); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private class LambdaProvider : TestImageProvider<TColor> |
||||
|
{ |
||||
|
private readonly Func<GenericFactory<TColor>, Image<TColor>> creator; |
||||
|
|
||||
|
public LambdaProvider(Func<GenericFactory<TColor>, Image<TColor>> creator) |
||||
|
{ |
||||
|
this.creator = creator; |
||||
|
} |
||||
|
|
||||
|
public override Image<TColor> 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<TColor> GetImage() |
||||
|
{ |
||||
|
var image = base.GetImage(); |
||||
|
TColor color = default(TColor); |
||||
|
color.PackFromBytes(this.r, this.g, this.b, this.a); |
||||
|
|
||||
|
return image.Fill(color); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Marker
|
||||
|
/// </summary>
|
||||
|
public interface ITestImageFactory |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,133 @@ |
|||||
|
// <copyright file="TestUtilityExtensions.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.Tests |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Globalization; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Extension methods for TestUtilities
|
||||
|
/// </summary>
|
||||
|
public static class TestUtilityExtensions |
||||
|
{ |
||||
|
private static readonly Dictionary<Type, PixelTypes> ClrTypes2PixelTypes = new Dictionary<Type, PixelTypes>(); |
||||
|
|
||||
|
private static readonly Assembly ImageSharpAssembly = typeof(Color).GetTypeInfo().Assembly; |
||||
|
|
||||
|
private static readonly Dictionary<PixelTypes, Type> PixelTypes2ClrTypes = new Dictionary<PixelTypes, Type>(); |
||||
|
|
||||
|
private static readonly PixelTypes[] AllConcretePixelTypes = FlagsHelper<PixelTypes> |
||||
|
.GetSortedValues() |
||||
|
.Except(new [] {PixelTypes.Undefined, PixelTypes.All }) |
||||
|
.ToArray(); |
||||
|
|
||||
|
static TestUtilityExtensions() |
||||
|
{ |
||||
|
string nameSpace = typeof(Color).FullName; |
||||
|
nameSpace = nameSpace.Substring(0, nameSpace.Length - typeof(Color).Name.Length - 1); |
||||
|
foreach (PixelTypes pt in AllConcretePixelTypes.Where(pt => pt != PixelTypes.StandardImageClass)) |
||||
|
{ |
||||
|
string typeName = $"{nameSpace}.{FlagsHelper<PixelTypes>.ToString(pt)}"; |
||||
|
var t = ImageSharpAssembly.GetType(typeName); |
||||
|
if (t != null) |
||||
|
{ |
||||
|
PixelTypes2ClrTypes[pt] = t; |
||||
|
ClrTypes2PixelTypes[t] = pt; |
||||
|
} |
||||
|
} |
||||
|
PixelTypes2ClrTypes[PixelTypes.StandardImageClass] = typeof(Color); |
||||
|
} |
||||
|
|
||||
|
public static Type GetPackedType(Type pixelType) |
||||
|
{ |
||||
|
var intrfcType = |
||||
|
pixelType.GetInterfaces() |
||||
|
.Single(i => i.IsConstructedGenericType && i.GetGenericTypeDefinition() == typeof(IPackedPixel<>)); |
||||
|
|
||||
|
return intrfcType.GetGenericArguments().Single(); |
||||
|
} |
||||
|
|
||||
|
public static bool HasFlag(this PixelTypes pixelTypes, PixelTypes flag) => (pixelTypes & flag) == flag; |
||||
|
|
||||
|
public static bool IsEquivalentTo<TColor>(this Image<TColor> a, Image<TColor> b, bool compareAlpha = true) |
||||
|
where TColor : struct, IPackedPixel, IEquatable<TColor> |
||||
|
{ |
||||
|
if (a.Width != b.Width || a.Height != b.Height) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
byte[] bytesA = new byte[3]; |
||||
|
byte[] bytesB = new byte[3]; |
||||
|
|
||||
|
using (var pixA = a.Lock()) |
||||
|
{ |
||||
|
using (var pixB = b.Lock()) |
||||
|
{ |
||||
|
for (int y = 0; y < a.Height; y++) |
||||
|
{ |
||||
|
for (int x = 0; x < a.Width; x++) |
||||
|
{ |
||||
|
var ca = pixA[x, y]; |
||||
|
var cb = pixB[x, y]; |
||||
|
|
||||
|
if (compareAlpha) |
||||
|
{ |
||||
|
if (!ca.Equals(cb)) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
ca.ToBytes(bytesA, 0, ComponentOrder.XYZ); |
||||
|
cb.ToBytes(bytesB, 0, ComponentOrder.XYZ); |
||||
|
|
||||
|
if (bytesA[0] != bytesB[0] || |
||||
|
bytesA[1] != bytesB[1] || |
||||
|
bytesA[2] != bytesB[2]) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
public static string ToCsv<T>(this IEnumerable<T> items, string separator = ",") |
||||
|
{ |
||||
|
return string.Join(separator, items.Select(o => string.Format(CultureInfo.InvariantCulture, "{0}", o))); |
||||
|
} |
||||
|
|
||||
|
public static Type ToType(this PixelTypes pixelType) => PixelTypes2ClrTypes[pixelType]; |
||||
|
|
||||
|
public static PixelTypes GetPixelType(this Type colorStructClrType) => ClrTypes2PixelTypes[colorStructClrType]; |
||||
|
|
||||
|
public static IEnumerable<KeyValuePair<PixelTypes, Type>> ExpandAllTypes(this PixelTypes pixelTypes) |
||||
|
{ |
||||
|
if (pixelTypes == PixelTypes.Undefined) |
||||
|
{ |
||||
|
return Enumerable.Empty<KeyValuePair<PixelTypes, Type>>(); |
||||
|
} |
||||
|
else if (pixelTypes == PixelTypes.All) |
||||
|
{ |
||||
|
// TODO: Need to return unknown types here without forcing CLR to load all types in ImageSharp assembly
|
||||
|
return PixelTypes2ClrTypes; |
||||
|
} |
||||
|
|
||||
|
return AllConcretePixelTypes |
||||
|
.Where(pt => pixelTypes.HasFlag(pt)) |
||||
|
.Select(pt => new KeyValuePair<PixelTypes, Type>(pt, pt.ToType())); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,193 @@ |
|||||
|
// <copyright file="TestImageFactoryTests.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
// ReSharper disable InconsistentNaming
|
||||
|
|
||||
|
namespace ImageSharp.Tests |
||||
|
{ |
||||
|
using System; |
||||
|
|
||||
|
using Xunit; |
||||
|
using Xunit.Abstractions; |
||||
|
|
||||
|
public class TestImageProviderTests |
||||
|
{ |
||||
|
public TestImageProviderTests(ITestOutputHelper output) |
||||
|
{ |
||||
|
this.Output = output; |
||||
|
} |
||||
|
|
||||
|
private ITestOutputHelper Output { get; } |
||||
|
|
||||
|
[Theory] |
||||
|
[WithBlankImages(42, 666, PixelTypes.Color | PixelTypes.Argb | PixelTypes.HalfSingle, "hello")] |
||||
|
public void Use_WithEmptyImageAttribute<TColor>(TestImageProvider<TColor> provider, string message) |
||||
|
where TColor : struct, IPackedPixel, IEquatable<TColor> |
||||
|
{ |
||||
|
var img = provider.GetImage(); |
||||
|
|
||||
|
Assert.Equal(42, img.Width); |
||||
|
Assert.Equal(666, img.Height); |
||||
|
Assert.Equal("hello", message); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[WithBlankImages(42, 666, PixelTypes.All, "hello")] |
||||
|
public void Use_WithBlankImagesAttribute_WithAllPixelTypes<TColor>( |
||||
|
TestImageProvider<TColor> provider, |
||||
|
string message) |
||||
|
where TColor : struct, IPackedPixel, IEquatable<TColor> |
||||
|
{ |
||||
|
var img = provider.GetImage(); |
||||
|
|
||||
|
Assert.Equal(42, img.Width); |
||||
|
Assert.Equal(666, img.Height); |
||||
|
Assert.Equal("hello", message); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[WithBlankImages(1, 1, PixelTypes.Color, PixelTypes.Color)] |
||||
|
[WithBlankImages(1, 1, PixelTypes.Alpha8, PixelTypes.Alpha8)] |
||||
|
[WithBlankImages(1, 1, PixelTypes.StandardImageClass, PixelTypes.StandardImageClass)] |
||||
|
public void PixelType_PropertyValueIsCorrect<TColor>(TestImageProvider<TColor> provider, PixelTypes expected) |
||||
|
where TColor : struct, IPackedPixel, IEquatable<TColor> |
||||
|
{ |
||||
|
Assert.Equal(expected, provider.PixelType); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[WithBlankImages(1, 1, PixelTypes.StandardImageClass)] |
||||
|
public void PixelTypes_ColorWithDefaultImageClass_TriggersCreatingTheNonGenericDerivedImageClass<TColor>( |
||||
|
TestImageProvider<TColor> provider) |
||||
|
where TColor : struct, IPackedPixel, IEquatable<TColor> |
||||
|
{ |
||||
|
var img = provider.GetImage(); |
||||
|
|
||||
|
Assert.IsType<Image>(img); |
||||
|
} |
||||
|
|
||||
|
// TODO: @dlemstra this works only with constant strings!
|
||||
|
[Theory] |
||||
|
[WithFile(TestImages.Bmp.Car, PixelTypes.All, 88)] |
||||
|
[WithFile(TestImages.Bmp.F, PixelTypes.All, 88)] |
||||
|
public void Use_WithFileAttribute<TColor>(TestImageProvider<TColor> provider, int yo) |
||||
|
where TColor : struct, IPackedPixel, IEquatable<TColor> |
||||
|
{ |
||||
|
Assert.NotNull(provider.Utility.SourceFileOrDescription); |
||||
|
var img = provider.GetImage(); |
||||
|
Assert.True(img.Width * img.Height > 0); |
||||
|
|
||||
|
Assert.Equal(88, yo); |
||||
|
|
||||
|
string fn = provider.Utility.GetTestOutputFileName("jpg"); |
||||
|
this.Output.WriteLine(fn); |
||||
|
} |
||||
|
|
||||
|
public static string[] AllBmpFiles => TestImages.Bmp.All; |
||||
|
|
||||
|
[Theory] |
||||
|
[WithFileCollection(nameof(AllBmpFiles), PixelTypes.Color | PixelTypes.Argb)] |
||||
|
public void Use_WithFileCollection<TColor>(TestImageProvider<TColor> provider) |
||||
|
where TColor : struct, IPackedPixel, IEquatable<TColor> |
||||
|
{ |
||||
|
Assert.NotNull(provider.Utility.SourceFileOrDescription); |
||||
|
var image = provider.GetImage(); |
||||
|
provider.Utility.SaveTestOutputFile(image, "png"); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[WithSolidFilledImages(10, 20, 255, 100, 50, 200, PixelTypes.Color | PixelTypes.Argb)] |
||||
|
public void Use_WithSolidFilledImagesAttribute<TColor>(TestImageProvider<TColor> provider) |
||||
|
where TColor : struct, IPackedPixel, IEquatable<TColor> |
||||
|
{ |
||||
|
var img = provider.GetImage(); |
||||
|
Assert.Equal(img.Width, 10); |
||||
|
Assert.Equal(img.Height, 20); |
||||
|
|
||||
|
byte[] colors = new byte[4]; |
||||
|
|
||||
|
using (var pixels = img.Lock()) |
||||
|
{ |
||||
|
for (int y = 0; y < pixels.Height; y++) |
||||
|
{ |
||||
|
for (int x = 0; x < pixels.Width; x++) |
||||
|
{ |
||||
|
pixels[x, y].ToBytes(colors, 0, ComponentOrder.XYZW); |
||||
|
|
||||
|
Assert.Equal(colors[0], 255); |
||||
|
Assert.Equal(colors[1], 100); |
||||
|
Assert.Equal(colors[2], 50); |
||||
|
Assert.Equal(colors[3], 200); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Need to us <see cref="GenericFactory{TColor}"/> to create instance of <see cref="Image"/> when pixelType is StandardImageClass
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TColor"></typeparam>
|
||||
|
/// <param name="factory"></param>
|
||||
|
/// <returns></returns>
|
||||
|
public static Image<TColor> CreateTestImage<TColor>(GenericFactory<TColor> factory) |
||||
|
where TColor : struct, IPackedPixel, IEquatable<TColor> |
||||
|
{ |
||||
|
return factory.CreateImage(3, 3); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[WithMemberFactory(nameof(CreateTestImage), PixelTypes.All)] |
||||
|
public void Use_WithMemberFactoryAttribute<TColor>(TestImageProvider<TColor> provider) |
||||
|
where TColor : struct, IPackedPixel, IEquatable<TColor> |
||||
|
{ |
||||
|
var img = provider.GetImage(); |
||||
|
Assert.Equal(img.Width, 3); |
||||
|
if (provider.PixelType == PixelTypes.StandardImageClass) |
||||
|
{ |
||||
|
Assert.IsType<Image>(img); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public static readonly TheoryData<ITestImageFactory> BasicData = new TheoryData<ITestImageFactory>() |
||||
|
{ |
||||
|
TestImageProvider<Color>.Blank(10, 20), |
||||
|
TestImageProvider<HalfVector4>.Blank( |
||||
|
10, |
||||
|
20) |
||||
|
}; |
||||
|
|
||||
|
[Theory] |
||||
|
[MemberData(nameof(BasicData))] |
||||
|
public void Blank_MemberData<TColor>(TestImageProvider<TColor> provider) |
||||
|
where TColor : struct, IPackedPixel, IEquatable<TColor> |
||||
|
{ |
||||
|
var img = provider.GetImage(); |
||||
|
|
||||
|
Assert.True(img.Width * img.Height > 0); |
||||
|
} |
||||
|
|
||||
|
public static readonly TheoryData<ITestImageFactory> FileData = new TheoryData<ITestImageFactory>() |
||||
|
{ |
||||
|
TestImageProvider<Color>.File( |
||||
|
TestImages.Bmp.Car), |
||||
|
TestImageProvider<HalfVector4>.File( |
||||
|
TestImages.Bmp.F) |
||||
|
}; |
||||
|
|
||||
|
[Theory] |
||||
|
[MemberData(nameof(FileData))] |
||||
|
public void File_MemberData<TColor>(TestImageProvider<TColor> provider) |
||||
|
where TColor : struct, IPackedPixel, IEquatable<TColor> |
||||
|
{ |
||||
|
this.Output.WriteLine("SRC: " + provider.Utility.SourceFileOrDescription); |
||||
|
this.Output.WriteLine("OUT: " + provider.Utility.GetTestOutputFileName()); |
||||
|
|
||||
|
var img = provider.GetImage(); |
||||
|
|
||||
|
Assert.True(img.Width * img.Height > 0); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,147 @@ |
|||||
|
// <copyright file="FlagsHelper.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
// ReSharper disable InconsistentNaming
|
||||
|
namespace ImageSharp.Tests |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Numerics; |
||||
|
using System.Reflection; |
||||
|
|
||||
|
using Xunit; |
||||
|
using Xunit.Abstractions; |
||||
|
|
||||
|
public class TestUtilityExtensionsTests |
||||
|
{ |
||||
|
public TestUtilityExtensionsTests(ITestOutputHelper output) |
||||
|
{ |
||||
|
this.Output = output; |
||||
|
} |
||||
|
|
||||
|
private ITestOutputHelper Output { get; } |
||||
|
|
||||
|
public static Image<TColor> CreateTestImage<TColor>(GenericFactory<TColor> factory) |
||||
|
where TColor : struct, IPackedPixel, IEquatable<TColor> |
||||
|
{ |
||||
|
Image<TColor> image = factory.CreateImage(10, 10); |
||||
|
|
||||
|
using (var pixels = image.Lock()) |
||||
|
{ |
||||
|
for (int i = 0; i < 10; i++) |
||||
|
{ |
||||
|
for (int j = 0; j < 10; j++) |
||||
|
{ |
||||
|
Vector4 v = new Vector4(i, j, 0, 1); |
||||
|
v /= 10; |
||||
|
|
||||
|
TColor color = default(TColor); |
||||
|
color.PackFromVector4(v); |
||||
|
|
||||
|
pixels[i, j] = color; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return image; |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Baz() |
||||
|
{ |
||||
|
var type = typeof(Color).GetTypeInfo().Assembly.GetType("ImageSharp.Color"); |
||||
|
this.Output.WriteLine(type.ToString()); |
||||
|
|
||||
|
var fake = typeof(Color).GetTypeInfo().Assembly.GetType("ImageSharp.dsaada_DASqewrr"); |
||||
|
Assert.Null(fake); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void GetPackedType() |
||||
|
{ |
||||
|
Type shouldBeUIint32 = TestUtilityExtensions.GetPackedType(typeof(Color)); |
||||
|
|
||||
|
Assert.Equal(shouldBeUIint32, typeof(uint)); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[WithFile(TestImages.Bmp.Car, PixelTypes.Color, true)] |
||||
|
[WithFile(TestImages.Bmp.Car, PixelTypes.Color, false)] |
||||
|
public void IsEquivalentTo_WhenFalse<TColor>(TestImageProvider<TColor> provider, bool compareAlpha) |
||||
|
where TColor : struct, IPackedPixel, IEquatable<TColor> |
||||
|
{ |
||||
|
var a = provider.GetImage(); |
||||
|
var b = provider.GetImage(); |
||||
|
b = b.OilPaint(3, 2); |
||||
|
|
||||
|
Assert.False(a.IsEquivalentTo(b, compareAlpha)); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[WithMemberFactory(nameof(CreateTestImage), PixelTypes.Color | PixelTypes.Bgr565, true)] |
||||
|
[WithMemberFactory(nameof(CreateTestImage), PixelTypes.Color | PixelTypes.Bgr565, false)] |
||||
|
public void IsEquivalentTo_WhenTrue<TColor>(TestImageProvider<TColor> provider, bool compareAlpha) |
||||
|
where TColor : struct, IPackedPixel, IEquatable<TColor> |
||||
|
{ |
||||
|
var a = provider.GetImage(); |
||||
|
var b = provider.GetImage(); |
||||
|
|
||||
|
Assert.True(a.IsEquivalentTo(b, compareAlpha)); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[InlineData(PixelTypes.Color, typeof(Color))] |
||||
|
[InlineData(PixelTypes.Argb, typeof(Argb))] |
||||
|
[InlineData(PixelTypes.HalfVector4, typeof(HalfVector4))] |
||||
|
[InlineData(PixelTypes.StandardImageClass, typeof(Color))] |
||||
|
public void ToType(PixelTypes pt, Type expectedType) |
||||
|
{ |
||||
|
Assert.Equal(pt.ToType(), expectedType); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[InlineData(typeof(Color), PixelTypes.Color)] |
||||
|
[InlineData(typeof(Argb), PixelTypes.Argb)] |
||||
|
public void GetPixelType(Type clrType, PixelTypes expectedPixelType) |
||||
|
{ |
||||
|
Assert.Equal(expectedPixelType, clrType.GetPixelType()); |
||||
|
} |
||||
|
|
||||
|
private static void AssertContainsPixelType<T>( |
||||
|
PixelTypes pt, |
||||
|
IEnumerable<KeyValuePair<PixelTypes, Type>> pixelTypesExp) |
||||
|
{ |
||||
|
Assert.Contains(new KeyValuePair<PixelTypes, Type>(pt, typeof(T)), pixelTypesExp); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void ToTypes() |
||||
|
{ |
||||
|
PixelTypes pixelTypes = PixelTypes.Alpha8 | PixelTypes.Bgr565 | PixelTypes.Color | PixelTypes.HalfVector2 | PixelTypes.StandardImageClass; |
||||
|
|
||||
|
var expanded = pixelTypes.ExpandAllTypes(); |
||||
|
|
||||
|
Assert.Equal(expanded.Count(), 5); |
||||
|
|
||||
|
AssertContainsPixelType<Alpha8>(PixelTypes.Alpha8, expanded); |
||||
|
AssertContainsPixelType<Bgr565>(PixelTypes.Bgr565, expanded); |
||||
|
AssertContainsPixelType<Color>(PixelTypes.Color, expanded); |
||||
|
AssertContainsPixelType<HalfVector2>(PixelTypes.HalfVector2, expanded); |
||||
|
AssertContainsPixelType<Color>(PixelTypes.StandardImageClass, expanded); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void ToTypes_All() |
||||
|
{ |
||||
|
var expanded = PixelTypes.All.ExpandAllTypes().ToArray(); |
||||
|
|
||||
|
Assert.True(expanded.Length >= FlagsHelper<PixelTypes>.GetSortedValues().Length - 2); |
||||
|
AssertContainsPixelType<Color>(PixelTypes.Color, expanded); |
||||
|
AssertContainsPixelType<Color>(PixelTypes.StandardImageClass, expanded); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,38 @@ |
|||||
|
// <copyright file="WithBlankImagesAttribute.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.Tests |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Reflection; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Triggers passing <see cref="TestImageProvider{TColor}"/> instances which produce a blank image of size width * height.
|
||||
|
/// One <see cref="TestImageProvider{TColor}"/> instance will be passed for each the pixel format defined by the pixelTypes parameter
|
||||
|
/// </summary>
|
||||
|
public class WithBlankImagesAttribute : ImageDataAttributeBase |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Triggers passing an <see cref="TestImageProvider{TColor}"/> that produces a blank image of size width * height
|
||||
|
/// </summary>
|
||||
|
/// <param name="width">The required width</param>
|
||||
|
/// <param name="height">The required height</param>
|
||||
|
/// <param name="pixelTypes">The requested parameter</param>
|
||||
|
/// <param name="additionalParameters">Additional theory parameter values</param>
|
||||
|
public WithBlankImagesAttribute(int width, int height, PixelTypes pixelTypes, params object[] additionalParameters) |
||||
|
: base(pixelTypes, additionalParameters) |
||||
|
{ |
||||
|
this.Width = width; |
||||
|
this.Height = height; |
||||
|
} |
||||
|
|
||||
|
public int Width { get; } |
||||
|
public int Height { get; } |
||||
|
|
||||
|
protected override string GetFactoryMethodName(MethodInfo testMethod) => "Blank"; |
||||
|
|
||||
|
protected override object[] GetFactoryMethodArgs(MethodInfo testMethod, Type factoryType) => new object[] { this.Width, this.Height }; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
// <copyright file="WithFileAttribute.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.Tests |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Reflection; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Triggers passing <see cref="TestImageProvider{TColor}"/> instances which read an image from the given file
|
||||
|
/// One <see cref="TestImageProvider{TColor}"/> instance will be passed for each the pixel format defined by the pixelTypes parameter
|
||||
|
/// </summary>
|
||||
|
public class WithFileAttribute : ImageDataAttributeBase |
||||
|
{ |
||||
|
private readonly string fileName; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Triggers passing <see cref="TestImageProvider{TColor}"/> instances which read an image from the given file
|
||||
|
/// One <see cref="TestImageProvider{TColor}"/> instance will be passed for each the pixel format defined by the pixelTypes parameter
|
||||
|
/// </summary>
|
||||
|
/// <param name="fileName">The name of the file</param>
|
||||
|
/// <param name="pixelTypes">The requested pixel types</param>
|
||||
|
/// <param name="additionalParameters">Additional theory parameter values</param>
|
||||
|
public WithFileAttribute(string fileName, PixelTypes pixelTypes, params object[] additionalParameters) |
||||
|
: base(pixelTypes, additionalParameters) |
||||
|
{ |
||||
|
this.fileName = fileName; |
||||
|
} |
||||
|
|
||||
|
protected override object[] GetFactoryMethodArgs(MethodInfo testMethod, Type factoryType) => new object[] { this.fileName }; |
||||
|
|
||||
|
protected override string GetFactoryMethodName(MethodInfo testMethod) => "File"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,86 @@ |
|||||
|
// <copyright file="WithFileCollectionAttribute.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
namespace ImageSharp.Tests |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Triggers passing <see cref="TestImageProvider{TColor}"/> instances which read an image for each file being enumerated by the (static) test class field/property defined by enumeratorMemberName
|
||||
|
/// <see cref="TestImageProvider{TColor}"/> instances will be passed for each the pixel format defined by the pixelTypes parameter
|
||||
|
/// </summary>
|
||||
|
public class WithFileCollectionAttribute : ImageDataAttributeBase |
||||
|
{ |
||||
|
private readonly string enumeratorMemberName; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Triggers passing <see cref="TestImageProvider{TColor}"/> instances which read an image for each file being enumerated by the (static) test class field/property defined by enumeratorMemberName
|
||||
|
/// <see cref="TestImageProvider{TColor}"/> instances will be passed for each the pixel format defined by the pixelTypes parameter
|
||||
|
/// </summary>
|
||||
|
/// <param name="enumeratorMemberName">The name of the static test class field/property enumerating the files</param>
|
||||
|
/// <param name="pixelTypes">The requested pixel types</param>
|
||||
|
/// <param name="additionalParameters">Additional theory parameter values</param>
|
||||
|
public WithFileCollectionAttribute( |
||||
|
string enumeratorMemberName, |
||||
|
PixelTypes pixelTypes, |
||||
|
params object[] additionalParameters) |
||||
|
: base(pixelTypes, additionalParameters) |
||||
|
{ |
||||
|
this.enumeratorMemberName = enumeratorMemberName; |
||||
|
} |
||||
|
|
||||
|
protected override IEnumerable<object[]> GetAllFactoryMethodArgs(MethodInfo testMethod, Type factoryType) |
||||
|
{ |
||||
|
var accessor = this.GetPropertyAccessor(testMethod.DeclaringType); |
||||
|
|
||||
|
accessor = accessor ?? this.GetFieldAccessor(testMethod.DeclaringType); |
||||
|
|
||||
|
IEnumerable<string> files = (IEnumerable<string>)accessor(); |
||||
|
return files.Select(f => new object[] { f }); |
||||
|
} |
||||
|
|
||||
|
protected override string GetFactoryMethodName(MethodInfo testMethod) => "File"; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Based on MemberData implementation
|
||||
|
/// </summary>
|
||||
|
private Func<object> GetFieldAccessor(Type type) |
||||
|
{ |
||||
|
FieldInfo fieldInfo = null; |
||||
|
for (var reflectionType = type; |
||||
|
reflectionType != null; |
||||
|
reflectionType = reflectionType.GetTypeInfo().BaseType) |
||||
|
{ |
||||
|
fieldInfo = reflectionType.GetRuntimeField(this.enumeratorMemberName); |
||||
|
if (fieldInfo != null) break; |
||||
|
} |
||||
|
|
||||
|
if (fieldInfo == null || !fieldInfo.IsStatic) return null; |
||||
|
|
||||
|
return () => fieldInfo.GetValue(null); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Based on MemberData implementation
|
||||
|
/// </summary>
|
||||
|
private Func<object> GetPropertyAccessor(Type type) |
||||
|
{ |
||||
|
PropertyInfo propInfo = null; |
||||
|
for (var reflectionType = type; |
||||
|
reflectionType != null; |
||||
|
reflectionType = reflectionType.GetTypeInfo().BaseType) |
||||
|
{ |
||||
|
propInfo = reflectionType.GetRuntimeProperty(this.enumeratorMemberName); |
||||
|
if (propInfo != null) break; |
||||
|
} |
||||
|
|
||||
|
if (propInfo == null || propInfo.GetMethod == null || !propInfo.GetMethod.IsStatic) return null; |
||||
|
|
||||
|
return () => propInfo.GetValue(null, null); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,54 @@ |
|||||
|
// <copyright file="WithMemberFactoryAttribute.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.Tests |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Triggers passing <see cref="TestImageProvider{TColor}"/> instances which return the image produced by the given test class member method
|
||||
|
/// <see cref="TestImageProvider{TColor}"/> instances will be passed for each the pixel format defined by the pixelTypes parameter
|
||||
|
/// The parameter of the factory method must be a <see cref="GenericFactory{TColor}"/> instance
|
||||
|
/// </summary>
|
||||
|
public class WithMemberFactoryAttribute : ImageDataAttributeBase |
||||
|
{ |
||||
|
private readonly string memberMethodName; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Triggers passing <see cref="TestImageProvider{TColor}"/> instances which return the image produced by the given test class member method
|
||||
|
/// <see cref="TestImageProvider{TColor}"/> instances will be passed for each the pixel format defined by the pixelTypes parameter
|
||||
|
/// </summary>
|
||||
|
/// <param name="memberMethodName">The name of the static test class which returns the image</param>
|
||||
|
/// <param name="pixelTypes">The requested pixel types</param>
|
||||
|
/// <param name="additionalParameters">Additional theory parameter values</param>
|
||||
|
public WithMemberFactoryAttribute(string memberMethodName, PixelTypes pixelTypes, params object[] additionalParameters) |
||||
|
: base(pixelTypes, additionalParameters) |
||||
|
{ |
||||
|
this.memberMethodName = memberMethodName; |
||||
|
} |
||||
|
|
||||
|
protected override object[] GetFactoryMethodArgs(MethodInfo testMethod, Type factoryType) |
||||
|
{ |
||||
|
var m = testMethod.DeclaringType.GetMethod(this.memberMethodName); |
||||
|
|
||||
|
var args = factoryType.GetGenericArguments(); |
||||
|
var colorType = args.Single(); |
||||
|
|
||||
|
var imgType = typeof(Image<>).MakeGenericType(colorType); |
||||
|
var genericFactoryType = (typeof(GenericFactory<>)).MakeGenericType(colorType); |
||||
|
|
||||
|
var funcType = typeof(Func<,>).MakeGenericType(genericFactoryType, imgType); |
||||
|
|
||||
|
var genericMethod = m.MakeGenericMethod(args); |
||||
|
|
||||
|
var d = genericMethod.CreateDelegate(funcType); |
||||
|
return new object[] { d }; |
||||
|
} |
||||
|
|
||||
|
protected override string GetFactoryMethodName(MethodInfo testMethod) => "Lambda"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,93 @@ |
|||||
|
// <copyright file="WithSolidFilledImagesAttribute.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
namespace ImageSharp.Tests |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Reflection; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Triggers passing <see cref="TestImageProvider{TColor}"/> instances which produce an image of size width * height filled with the requested color.
|
||||
|
/// One <see cref="TestImageProvider{TColor}"/> instance will be passed for each the pixel format defined by the pixelTypes parameter
|
||||
|
/// </summary>
|
||||
|
public class WithSolidFilledImagesAttribute : WithBlankImagesAttribute |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Triggers passing <see cref="TestImageProvider{TColor}"/> instances which produce an image of size width * height filled with the requested color.
|
||||
|
/// One <see cref="TestImageProvider{TColor}"/> instance will be passed for each the pixel format defined by the pixelTypes parameter
|
||||
|
/// </summary>
|
||||
|
/// <param name="width">The width of the requested image</param>
|
||||
|
/// <param name="height">The height of the requested image</param>
|
||||
|
/// <param name="r">Red</param>
|
||||
|
/// <param name="g">Green</param>
|
||||
|
/// <param name="b">Blue</param>
|
||||
|
/// <param name="pixelTypes">The requested pixel types</param>
|
||||
|
/// <param name="additionalParameters">Additional theory parameter values</param>
|
||||
|
public WithSolidFilledImagesAttribute( |
||||
|
int width, |
||||
|
int height, |
||||
|
byte r, |
||||
|
byte g, |
||||
|
byte b, |
||||
|
PixelTypes pixelTypes, |
||||
|
params object[] additionalParameters) |
||||
|
: this(width, height, r, g, b, 255, pixelTypes, additionalParameters) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Triggers passing <see cref="TestImageProvider{TColor}"/> instances which produce an image of size width * height filled with the requested color.
|
||||
|
/// One <see cref="TestImageProvider{TColor}"/> instance will be passed for each the pixel format defined by the pixelTypes parameter
|
||||
|
/// </summary>
|
||||
|
/// <param name="width">The width of the requested image</param>
|
||||
|
/// <param name="height">The height of the requested image</param>
|
||||
|
/// <param name="r">Red</param>
|
||||
|
/// <param name="g">Green</param>
|
||||
|
/// <param name="b">Blue</param>
|
||||
|
/// /// <param name="a">Alpha</param>
|
||||
|
/// <param name="pixelTypes">The requested pixel types</param>
|
||||
|
/// <param name="additionalParameters">Additional theory parameter values</param>
|
||||
|
public WithSolidFilledImagesAttribute( |
||||
|
int width, |
||||
|
int height, |
||||
|
byte r, |
||||
|
byte g, |
||||
|
byte b, |
||||
|
byte a, |
||||
|
PixelTypes pixelTypes, |
||||
|
params object[] additionalParameters) |
||||
|
: base(width, height, pixelTypes, additionalParameters) |
||||
|
{ |
||||
|
this.R = r; |
||||
|
this.G = g; |
||||
|
this.B = b; |
||||
|
this.A = a; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Red
|
||||
|
/// </summary>
|
||||
|
public byte R { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Green
|
||||
|
/// </summary>
|
||||
|
public byte G { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Blue
|
||||
|
/// </summary>
|
||||
|
public byte B { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Alpha
|
||||
|
/// </summary>
|
||||
|
public byte A { get; } |
||||
|
|
||||
|
protected override object[] GetFactoryMethodArgs(MethodInfo testMethod, Type factoryType) |
||||
|
=> new object[] { this.Width, this.Height, this.R, this.G, this.B, this.A }; |
||||
|
|
||||
|
protected override string GetFactoryMethodName(MethodInfo testMethod) => "Solid"; |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue