DesignerSupportTests.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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/net8.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\net8.0\",
  36. "ControlCatalog.NetCore",
  37. "ControlCatalog.dll",
  38. @"..\..\..\..\..\samples\ControlCatalog\MainWindow.xaml",
  39. "win32"),
  40. InlineData(
  41. @"..\..\..\..\..\tests/Avalonia.DesignerSupport.TestApp/bin/$BUILD/net8.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\net8.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 assemblyPath = Path.Combine(outputDir, assemblyName);
  72. Assert.True(File.Exists(assemblyPath), "File.Exists(assemblyPath)");
  73. var sessionId = Guid.NewGuid();
  74. long handle = 0;
  75. bool success = false;
  76. string error = null;
  77. var resultMessageReceivedToken = new CancellationTokenSource();
  78. var tcpListener = new TcpListener(IPAddress.Loopback, 0);
  79. tcpListener.Start();
  80. var port = ((IPEndPoint)tcpListener.LocalEndpoint).Port;
  81. tcpListener.Stop();
  82. var transport = new BsonTcpTransport();
  83. transport.Listen(IPAddress.Loopback, port, conn =>
  84. {
  85. conn.OnMessage += async (_, msg) =>
  86. {
  87. if (msg is StartDesignerSessionMessage start)
  88. {
  89. Assert.Equal(sessionId, Guid.Parse(start.SessionId));
  90. if (method == "avalonia-remote")
  91. {
  92. await conn.Send(new ClientSupportedPixelFormatsMessage
  93. {
  94. Formats = new[] { PixelFormat.Rgba8888 }
  95. });
  96. await conn.Send(new ClientViewportAllocatedMessage
  97. {
  98. DpiX = 96, DpiY = 96, Width = 1024, Height = 768
  99. });
  100. }
  101. await conn.Send(new UpdateXamlMessage
  102. {
  103. AssemblyPath = assemblyPath,
  104. Xaml = xaml
  105. });
  106. }
  107. else if (msg is UpdateXamlResultMessage result)
  108. {
  109. if (result.Error != null)
  110. {
  111. error = result.Error;
  112. outputHelper.WriteLine(result.Error);
  113. }
  114. else
  115. success = true;
  116. if (method == "win32")
  117. handle = result.Handle != null ? long.Parse(result.Handle) : 0;
  118. resultMessageReceivedToken.Cancel();
  119. conn.Dispose();
  120. }
  121. };
  122. });
  123. var cmdline =
  124. $"exec --runtimeconfig \"{outputDir}{executableName}.runtimeconfig.json\" --depsfile \"{outputDir}{executableName}.deps.json\" "
  125. + $" \"{DesignerAppPath.Replace("$BUILD", buildType)}\" "
  126. + $"--transport tcp-bson://127.0.0.1:{port}/ --session-id {sessionId} --method {method} \"{outputDir}{executableName}.dll\"";
  127. using (var proc = new Process
  128. {
  129. StartInfo = new ProcessStartInfo("dotnet", cmdline)
  130. {
  131. UseShellExecute = false,
  132. RedirectStandardOutput = true,
  133. RedirectStandardError = true,
  134. CreateNoWindow = true,
  135. WorkingDirectory = outputDir,
  136. },
  137. EnableRaisingEvents = true
  138. })
  139. {
  140. proc.Start();
  141. var cancelled = false;
  142. try
  143. {
  144. await Task.Delay(10000, resultMessageReceivedToken.Token);
  145. }
  146. catch (TaskCanceledException)
  147. {
  148. cancelled = true;
  149. }
  150. try
  151. {
  152. proc.Kill();
  153. }
  154. catch
  155. {
  156. //
  157. }
  158. proc.WaitForExit();
  159. var stdout = proc.StandardOutput.ReadToEnd();
  160. var stderr = proc.StandardError.ReadToEnd();
  161. Assert.True(cancelled,
  162. $"Message Not Received.\n" + proc.StandardOutput.ReadToEnd() + "\n" +
  163. stderr + "\n" + stdout);
  164. Assert.True(success, error);
  165. if (method == "win32")
  166. Assert.NotEqual(0, handle);
  167. }
  168. }
  169. }
  170. }