TestBase.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // Copyright (c) The Avalonia Project. All rights reserved.
  2. // Licensed under the MIT license. See licence.md file in the project root for full license information.
  3. using System.IO;
  4. using System.Runtime.CompilerServices;
  5. using ImageMagick;
  6. using Avalonia.Controls;
  7. using Avalonia.Media.Imaging;
  8. using Avalonia.Rendering;
  9. using Xunit;
  10. using Avalonia.Platform;
  11. using System.Threading.Tasks;
  12. using System;
  13. using System.Threading;
  14. #if AVALONIA_CAIRO
  15. using Avalonia.Cairo;
  16. #elif AVALONIA_SKIA
  17. using Avalonia.Skia;
  18. #else
  19. using Avalonia.Direct2D1;
  20. #endif
  21. #if AVALONIA_CAIRO
  22. namespace Avalonia.Cairo.RenderTests
  23. #elif AVALONIA_SKIA
  24. namespace Avalonia.Skia.RenderTests
  25. #else
  26. namespace Avalonia.Direct2D1.RenderTests
  27. #endif
  28. {
  29. public class TestBase
  30. {
  31. private static readonly TestThreadingInterface threadingInterface =
  32. new TestThreadingInterface();
  33. static TestBase()
  34. {
  35. #if AVALONIA_CAIRO
  36. CairoPlatform.Initialize();
  37. #elif AVALONIA_SKIA
  38. SkiaPlatform.Initialize();
  39. #else
  40. Direct2D1Platform.Initialize();
  41. #endif
  42. AvaloniaLocator.CurrentMutable
  43. .Bind<IPlatformThreadingInterface>()
  44. .ToConstant(threadingInterface);
  45. }
  46. public TestBase(string outputPath)
  47. {
  48. #if AVALONIA_CAIRO
  49. string testFiles = Path.GetFullPath(@"..\..\tests\TestFiles\Cairo");
  50. #elif AVALONIA_SKIA
  51. string testFiles = Path.GetFullPath(@"..\..\tests\TestFiles\Skia");
  52. #else
  53. string testFiles = Path.GetFullPath(@"..\..\tests\TestFiles\Direct2D1");
  54. #endif
  55. OutputPath = Path.Combine(testFiles, outputPath);
  56. threadingInterface.MainThread = Thread.CurrentThread;
  57. }
  58. public string OutputPath
  59. {
  60. get;
  61. }
  62. protected async Task RenderToFile(Control target, [CallerMemberName] string testName = "")
  63. {
  64. if (!Directory.Exists(OutputPath))
  65. {
  66. Directory.CreateDirectory(OutputPath);
  67. }
  68. var immediatePath = Path.Combine(OutputPath, testName + ".immediate.out.png");
  69. var deferredPath = Path.Combine(OutputPath, testName + ".deferred.out.png");
  70. var factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
  71. using (RenderTargetBitmap bitmap = new RenderTargetBitmap(
  72. (int)target.Width,
  73. (int)target.Height))
  74. {
  75. Size size = new Size(target.Width, target.Height);
  76. target.Measure(size);
  77. target.Arrange(new Rect(size));
  78. bitmap.Render(target);
  79. bitmap.Save(immediatePath);
  80. }
  81. using (var rtb = factory.CreateRenderTargetBitmap((int)target.Width, (int)target.Height, 96, 96))
  82. using (var renderer = new DeferredRenderer(target, rtb))
  83. {
  84. Size size = new Size(target.Width, target.Height);
  85. target.Measure(size);
  86. target.Arrange(new Rect(size));
  87. renderer.UnitTestUpdateScene();
  88. // Do the deferred render on a background thread to expose any threading errors in
  89. // the deferred rendering path.
  90. await Task.Run((Action)renderer.UnitTestRender);
  91. rtb.Save(deferredPath);
  92. }
  93. }
  94. protected void CompareImages([CallerMemberName] string testName = "")
  95. {
  96. var expectedPath = Path.Combine(OutputPath, testName + ".expected.png");
  97. var immediatePath = Path.Combine(OutputPath, testName + ".immediate.out.png");
  98. var deferredPath = Path.Combine(OutputPath, testName + ".deferred.out.png");
  99. using (var expected = new MagickImage(expectedPath))
  100. using (var immediate = new MagickImage(immediatePath))
  101. using (var deferred = new MagickImage(deferredPath))
  102. {
  103. double immediateError = expected.Compare(immediate, ErrorMetric.RootMeanSquared);
  104. double deferredError = expected.Compare(deferred, ErrorMetric.RootMeanSquared);
  105. if (immediateError > 0.022)
  106. {
  107. Assert.True(false, immediatePath + ": Error = " + immediateError);
  108. }
  109. if (deferredError > 0.022)
  110. {
  111. Assert.True(false, deferredPath + ": Error = " + deferredError);
  112. }
  113. }
  114. }
  115. private class TestThreadingInterface : IPlatformThreadingInterface
  116. {
  117. public bool CurrentThreadIsLoopThread => MainThread.ManagedThreadId == Thread.CurrentThread.ManagedThreadId;
  118. public Thread MainThread { get; set; }
  119. public event Action Signaled;
  120. public void RunLoop(CancellationToken cancellationToken)
  121. {
  122. throw new NotImplementedException();
  123. }
  124. public void Signal()
  125. {
  126. throw new NotImplementedException();
  127. }
  128. public IDisposable StartTimer(TimeSpan interval, Action tick)
  129. {
  130. throw new NotImplementedException();
  131. }
  132. }
  133. }
  134. }