2
0

ExampleTests.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. #nullable enable
  2. using System.Diagnostics.CodeAnalysis;
  3. using Terminal.Gui.Examples;
  4. using Xunit.Abstractions;
  5. namespace ApplicationTests.Examples;
  6. /// <summary>
  7. /// Tests for the example discovery and execution infrastructure.
  8. /// </summary>
  9. public class ExampleTests
  10. {
  11. private readonly ITestOutputHelper _output;
  12. public ExampleTests (ITestOutputHelper output)
  13. {
  14. _output = output;
  15. }
  16. /// <summary>
  17. /// Discovers all examples by looking for assemblies with ExampleMetadata attributes.
  18. /// </summary>
  19. /// <returns>Test data for all discovered examples.</returns>
  20. [RequiresUnreferencedCode ("Calls ExampleDiscovery.DiscoverFromDirectory")]
  21. [RequiresDynamicCode ("Calls ExampleDiscovery.DiscoverFromDirectory")]
  22. public static IEnumerable<object []> AllExamples ()
  23. {
  24. // Navigate from test assembly location to repository root, then to Examples directory
  25. // Test output is typically at: Tests/UnitTestsParallelizable/bin/Debug/net8.0/
  26. // Examples are at: Examples/
  27. string examplesDir = Path.GetFullPath (Path.Combine (AppContext.BaseDirectory, "..", "..", "..", "..", "..", "Examples"));
  28. if (!Directory.Exists (examplesDir))
  29. {
  30. return [];
  31. }
  32. List<ExampleInfo> examples = ExampleDiscovery.DiscoverFromDirectory (examplesDir).ToList ();
  33. if (examples.Count == 0)
  34. {
  35. return [];
  36. }
  37. return examples.Select (e => new object [] { e });
  38. }
  39. [Theory]
  40. [MemberData (nameof (AllExamples))]
  41. public void Example_Has_Metadata (ExampleInfo example)
  42. {
  43. Assert.NotNull (example);
  44. Assert.False (string.IsNullOrWhiteSpace (example.Name), "Example name should not be empty");
  45. Assert.False (string.IsNullOrWhiteSpace (example.Description), "Example description should not be empty");
  46. Assert.True (File.Exists (example.AssemblyPath), $"Example assembly should exist: {example.AssemblyPath}");
  47. _output.WriteLine ($"Example: {example.Name}");
  48. _output.WriteLine ($" Description: {example.Description}");
  49. _output.WriteLine ($" Categories: {string.Join (", ", example.Categories)}");
  50. _output.WriteLine ($" Assembly: {example.AssemblyPath}");
  51. }
  52. [Theory]
  53. [MemberData (nameof (AllExamples))]
  54. public void All_Examples_Quit_And_Init_Shutdown_Properly_OutOfProcess (ExampleInfo example)
  55. {
  56. _output.WriteLine ($"Running example '{example.Name}' out-of-process");
  57. ExampleContext context = new ()
  58. {
  59. DriverName = "FakeDriver",
  60. KeysToInject = new () { "Esc" },
  61. TimeoutMs = 5000,
  62. CollectMetrics = false,
  63. Mode = ExecutionMode.OutOfProcess
  64. };
  65. ExampleResult result = ExampleRunner.Run (example, context);
  66. if (!result.Success)
  67. {
  68. _output.WriteLine ($"Example failed: {result.ErrorMessage}");
  69. if (!string.IsNullOrEmpty (result.StandardOutput))
  70. {
  71. _output.WriteLine ($"Standard Output:\n{result.StandardOutput}");
  72. }
  73. if (!string.IsNullOrEmpty (result.StandardError))
  74. {
  75. _output.WriteLine ($"Standard Error:\n{result.StandardError}");
  76. }
  77. }
  78. Assert.True (result.Success, $"Example '{example.Name}' should complete successfully");
  79. Assert.False (result.TimedOut, $"Example '{example.Name}' should not timeout");
  80. Assert.Equal (0, result.ExitCode);
  81. }
  82. [Theory]
  83. [MemberData (nameof (AllExamples))]
  84. public void All_Examples_Quit_And_Init_Shutdown_Properly_InProcess (ExampleInfo example)
  85. {
  86. _output.WriteLine ($"Running example '{example.Name}' in-process");
  87. // Force a complete reset to ensure clean state
  88. Application.ResetState (true);
  89. ExampleContext context = new ()
  90. {
  91. DriverName = "FakeDriver",
  92. KeysToInject = new () { "Esc" },
  93. TimeoutMs = 5000,
  94. CollectMetrics = false,
  95. Mode = ExecutionMode.InProcess
  96. };
  97. ExampleResult result = ExampleRunner.Run (example, context);
  98. if (!result.Success)
  99. {
  100. _output.WriteLine ($"Example failed: {result.ErrorMessage}");
  101. }
  102. // Reset state after in-process execution
  103. Application.ResetState (true);
  104. Assert.True (result.Success, $"Example '{example.Name}' should complete successfully");
  105. Assert.False (result.TimedOut, $"Example '{example.Name}' should not timeout");
  106. }
  107. [Fact]
  108. public void ExampleContext_Serialization_Works ()
  109. {
  110. ExampleContext context = new ()
  111. {
  112. DriverName = "FakeDriver",
  113. KeysToInject = new () { "Esc", "Enter" },
  114. TimeoutMs = 5000,
  115. MaxIterations = 100,
  116. CollectMetrics = true,
  117. Mode = ExecutionMode.InProcess
  118. };
  119. string json = context.ToJson ();
  120. Assert.False (string.IsNullOrWhiteSpace (json));
  121. ExampleContext? deserialized = ExampleContext.FromJson (json);
  122. Assert.NotNull (deserialized);
  123. Assert.Equal (context.DriverName, deserialized.DriverName);
  124. Assert.Equal (context.TimeoutMs, deserialized.TimeoutMs);
  125. Assert.Equal (context.MaxIterations, deserialized.MaxIterations);
  126. Assert.Equal (context.CollectMetrics, deserialized.CollectMetrics);
  127. Assert.Equal (context.Mode, deserialized.Mode);
  128. Assert.Equal (context.KeysToInject.Count, deserialized.KeysToInject.Count);
  129. }
  130. }