xwt/Testing/Tests/ReferenceImageManager.cs

207 строки
6.5 KiB
C#

//
// ReferenceImageManager.cs
//
// Author:
// Lluis Sanchez <lluis@xamarin.com>
//
// Copyright (c) 2013 Xamarin Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using Xwt.Drawing;
using System.Collections.Generic;
using System.IO;
using NUnit.Framework;
namespace Xwt
{
public class ReferenceImageManager
{
internal static string ProjectReferenceImageDir;
public static string ProjectCustomReferenceImageDir;
public static bool RecheckAll;
internal static string FailedImageCacheDir;
public static List<FailedImageInfo> ImageFailures = new List<FailedImageInfo> ();
static ReferenceImageManager ()
{
}
public static void Init (string projectName)
{
var baseDir = Path.GetDirectoryName (typeof(ReferenceImageManager).Assembly.Location);
while (Path.GetFileName (baseDir) != "Testing")
baseDir = Path.GetDirectoryName (baseDir);
ProjectReferenceImageDir = Path.Combine (baseDir, "Tests", "ReferenceImages");
ProjectCustomReferenceImageDir = Path.Combine (baseDir, projectName, "ReferenceImages");
FailedImageCacheDir = Path.Combine (baseDir, "bin", projectName, "FailedImageCache");
}
public static Image LoadReferenceImage (string name)
{
var f = Path.Combine (ProjectReferenceImageDir, name);
if (File.Exists (f))
return Image.FromFile (f);
else
return null;
}
public static Image LoadCustomReferenceImage (string name)
{
var file = Path.Combine (ProjectCustomReferenceImageDir, name);
if (File.Exists (file))
return Image.FromFile (file);
else
return null;
}
public static void ShowImageVerifier ()
{
if (ImageFailures.Count > 0) {
var dlg = new ReferenceImageVerifierDialog ();
dlg.Run ();
}
}
static Image TryLoadImage (System.Reflection.Assembly asm, string name)
{
try {
if (asm.GetManifestResourceInfo (name) != null)
return Image.FromResource (asm, name);
}
catch {
}
try {
if (asm.GetManifestResourceInfo ("WpfTestRunner.ReferenceImages." + name) != null)
return Image.FromResource (asm, "WpfTestRunner.ReferenceImages." + name);
}
catch {
}
return null;
}
public static void CheckImage (string refImageName, Image im)
{
BitmapImage img = im as BitmapImage ?? im.ToBitmap ();
Image coreRefImage = LoadReferenceImage (refImageName);
Image refImage = !RecheckAll ? LoadCustomReferenceImage (refImageName) : null;
if (refImage == null)
refImage = coreRefImage;
if (refImage == null) {
ImageFailures.Add (new FailedImageInfo () {
TestImage = img.WithSize (img.PixelWidth, img.PixelHeight),
ReferenceImage = img.WithSize (img.PixelWidth, img.PixelHeight),
Name = refImageName,
TargetDir = ProjectReferenceImageDir
});
return;
}
var diff = DiffImages (img, refImage);
if (diff != null && refImage != coreRefImage) {
// Maybe the original image has changed
refImage = coreRefImage;
diff = DiffImages (img, refImage);
}
if (diff != null) {
bool knownFailure = false;
var failedImageFile = Path.Combine (FailedImageCacheDir, refImageName);
if (File.Exists (failedImageFile)) {
var failedImage = Image.FromFile (Path.Combine (FailedImageCacheDir, refImageName));
if (DiffImages (img, failedImage) == null)
knownFailure = true;
}
if (!knownFailure) {
ImageFailures.Add (new FailedImageInfo () {
TestImage = img.WithSize (img.PixelWidth, img.PixelHeight),
ReferenceImage = refImage.WithSize (img.PixelWidth, img.PixelHeight),
DiffImage = diff,
Name = refImageName,
TargetDir = ProjectCustomReferenceImageDir
});
}
Assert.Fail ("Image " + refImageName + " doesn't match");
}
}
public static Image DiffImages (Image img1, Image img2)
{
bool foundDifference = false;
var bmp1 = (img1 as BitmapImage) ?? img1.ToBitmap ();
var bmp2 = (img2 as BitmapImage) ?? img2.ToBitmap ();
var res = new ImageBuilder ((int)Math.Min (bmp1.PixelWidth, bmp2.PixelWidth), (int) Math.Min (bmp1.PixelHeight, bmp2.PixelHeight));
var bmpr = res.ToBitmap ();
res.Dispose ();
for (int y=0; y<bmp1.PixelHeight && y < bmp2.PixelHeight; y++) {
for (int x=0; x<bmp1.PixelWidth && x<bmp2.PixelWidth; x++) {
var p1 = bmp1.GetPixel (x, y);
var p2 = bmp2.GetPixel (x, y);
var col = Colors.White;
if (p1 != p2) {
foundDifference = true;
var r = Math.Pow (p1.Red - p2.Red, 2) + Math.Pow (p1.Green - p2.Green, 2) + Math.Pow (p1.Blue - p2.Blue, 2) + Math.Pow (p1.Alpha - p2.Alpha, 2);
if (r < 0.01)
col = new Color (0.9, 0.9, 0.9);
else if (r < 0.1)
col = new Color (0.7, 0.7, 0.7);
else
col = Colors.Red;
}
bmpr.SetPixel (x, y, col);
}
}
if (foundDifference)
return bmpr;
else
return null;
}
}
public class FailedImageInfo
{
public Image TestImage { get; set; }
public Image ReferenceImage { get; set; }
public Image DiffImage { get; set; }
public string Name { get; set; }
public string TargetDir { get; set; }
public void Validate ()
{
if (!Directory.Exists (TargetDir))
Directory.CreateDirectory (TargetDir);
TestImage.Save (Path.Combine (TargetDir, Name), ImageFileType.Png);
}
public void Fail ()
{
if (!Directory.Exists (ReferenceImageManager.FailedImageCacheDir))
Directory.CreateDirectory (ReferenceImageManager.FailedImageCacheDir);
TestImage.Save (Path.Combine (ReferenceImageManager.FailedImageCacheDir, Name), ImageFileType.Png);
}
}
}