DesignerSupportTests.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Net;
  7. using System.Net.Sockets;
  8. using System.Runtime.InteropServices;
  9. using System.Text;
  10. using System.Threading;
  11. using System.Threading.Tasks;
  12. using Avalonia.Remote.Protocol;
  13. using Avalonia.Remote.Protocol.Designer;
  14. using Avalonia.Remote.Protocol.Viewport;
  15. using Xunit;
  16. using Xunit.Extensions;
  17. namespace Avalonia.DesignerSupport.Tests
  18. {
  19. public class DesignerSupportTests
  20. {
  21. private const string DesignerAppPath = "../../../../../src/tools/Avalonia.Designer.HostApp/bin/$BUILD/netstandard2.0/Avalonia.Designer.HostApp.dll";
  22. private readonly Xunit.Abstractions.ITestOutputHelper outputHelper;
  23. public DesignerSupportTests(Xunit.Abstractions.ITestOutputHelper outputHelper)
  24. {
  25. this.outputHelper = outputHelper;
  26. }
  27. [SkippableTheory,
  28. InlineData(
  29. @"..\..\..\..\..\tests/Avalonia.DesignerSupport.TestApp/bin/$BUILD/net6.0/",
  30. "Avalonia.DesignerSupport.TestApp",
  31. "Avalonia.DesignerSupport.TestApp.dll",
  32. @"..\..\..\..\..\tests\Avalonia.DesignerSupport.TestApp\MainWindow.xaml",
  33. "win32"),
  34. InlineData(
  35. @"..\..\..\..\..\samples\ControlCatalog.NetCore\bin\$BUILD\net6.0\",
  36. "ControlCatalog.NetCore",
  37. "ControlCatalog.dll",
  38. @"..\..\..\..\..\samples\ControlCatalog\MainWindow.xaml",
  39. "win32"),
  40. InlineData(
  41. @"..\..\..\..\..\tests/Avalonia.DesignerSupport.TestApp/bin/$BUILD/net6.0/",
  42. "Avalonia.DesignerSupport.TestApp",
  43. "Avalonia.DesignerSupport.TestApp.dll",
  44. @"..\..\..\..\..\tests\Avalonia.DesignerSupport.TestApp\MainWindow.xaml",
  45. "avalonia-remote"),
  46. InlineData(
  47. @"..\..\..\..\..\samples\ControlCatalog.NetCore\bin\$BUILD\net6.0\",
  48. "ControlCatalog.NetCore",
  49. "ControlCatalog.dll",
  50. @"..\..\..\..\..\samples\ControlCatalog\MainWindow.xaml",
  51. "avalonia-remote")]
  52. public async Task Designer_In_Win32_Mode_Should_Provide_Valid_Hwnd(
  53. string outputDir,
  54. string executableName,
  55. string assemblyName,
  56. string xamlFile,
  57. string method)
  58. {
  59. outputDir = Path.GetFullPath(outputDir.Replace('\\', Path.DirectorySeparatorChar));
  60. xamlFile = Path.GetFullPath(xamlFile.Replace('\\', Path.DirectorySeparatorChar));
  61. if (method == "win32")
  62. Skip.IfNot(RuntimeInformation.IsOSPlatform(OSPlatform.Windows));
  63. var xaml = File.ReadAllText(xamlFile);
  64. string buildType;
  65. #if DEBUG
  66. buildType = "Debug";
  67. #else
  68. buildType = "Release";
  69. #endif
  70. outputDir = outputDir.Replace("$BUILD", buildType);
  71. var sessionId = Guid.NewGuid();
  72. long handle = 0;
  73. bool success = false;
  74. string error = null;
  75. var resultMessageReceivedToken = new CancellationTokenSource();
  76. var tcpListener = new TcpListener(IPAddress.Loopback, 0);
  77. tcpListener.Start();
  78. var port = ((IPEndPoint)tcpListener.LocalEndpoint).Port;
  79. tcpListener.Stop();
  80. var transport = new BsonTcpTransport();
  81. transport.Listen(IPAddress.Loopback, port, conn =>
  82. {
  83. conn.OnMessage += async (_, msg) =>
  84. {
  85. if (msg is StartDesignerSessionMessage start)
  86. {
  87. Assert.Equal(sessionId, Guid.Parse(start.SessionId));
  88. if (method == "avalonia-remote")
  89. {
  90. await conn.Send(new ClientSupportedPixelFormatsMessage
  91. {
  92. Formats = new[] { PixelFormat.Rgba8888 }
  93. });
  94. await conn.Send(new ClientViewportAllocatedMessage
  95. {
  96. DpiX = 96, DpiY = 96, Width = 1024, Height = 768
  97. });
  98. }
  99. await conn.Send(new UpdateXamlMessage
  100. {
  101. AssemblyPath = Path.Combine(outputDir, assemblyName),
  102. Xaml = xaml
  103. });
  104. }
  105. else if (msg is UpdateXamlResultMessage result)
  106. {
  107. if (result.Error != null)
  108. {
  109. error = result.Error;
  110. outputHelper.WriteLine(result.Error);
  111. }
  112. else
  113. success = true;
  114. if (method == "win32")
  115. handle = result.Handle != null ? long.Parse(result.Handle) : 0;
  116. resultMessageReceivedToken.Cancel();
  117. conn.Dispose();
  118. }
  119. };
  120. });
  121. var cmdline =
  122. $"exec --runtimeconfig \"{outputDir}{executableName}.runtimeconfig.json\" --depsfile \"{outputDir}{executableName}.deps.json\" "
  123. + $" \"{DesignerAppPath.Replace("$BUILD", buildType)}\" "
  124. + $"--transport tcp-bson://127.0.0.1:{port}/ --session-id {sessionId} --method {method} \"{outputDir}{executableName}.dll\"";
  125. using (var proc = new Process
  126. {
  127. StartInfo = new ProcessStartInfo("dotnet", cmdline)
  128. {
  129. UseShellExecute = false,
  130. RedirectStandardOutput = true,
  131. RedirectStandardError = true,
  132. CreateNoWindow = true,
  133. WorkingDirectory = outputDir,
  134. },
  135. EnableRaisingEvents = true
  136. })
  137. {
  138. proc.Start();
  139. var cancelled = false;
  140. try
  141. {
  142. await Task.Delay(10000, resultMessageReceivedToken.Token);
  143. }
  144. catch (TaskCanceledException)
  145. {
  146. cancelled = true;
  147. }
  148. try
  149. {
  150. proc.Kill();
  151. }
  152. catch
  153. {
  154. //
  155. }
  156. proc.WaitForExit();
  157. var stdout = proc.StandardOutput.ReadToEnd();
  158. var stderr = proc.StandardError.ReadToEnd();
  159. Assert.True(cancelled,
  160. $"Message Not Received.\n" + proc.StandardOutput.ReadToEnd() + "\n" +
  161. stderr + "\n" + stdout);
  162. Assert.True(success, error);
  163. if (method == "win32")
  164. Assert.NotEqual(0, handle);
  165. }
  166. }
  167. }
  168. }