#nullable enable using System.Diagnostics.CodeAnalysis; using Terminal.Gui.Examples; using Xunit.Abstractions; namespace ApplicationTests.Examples; /// /// Tests for the example discovery and execution infrastructure. /// public class ExampleTests { private readonly ITestOutputHelper _output; public ExampleTests (ITestOutputHelper output) { _output = output; } /// /// Discovers all examples by looking for assemblies with ExampleMetadata attributes. /// /// Test data for all discovered examples. [RequiresUnreferencedCode ("Calls ExampleDiscovery.DiscoverFromDirectory")] [RequiresDynamicCode ("Calls ExampleDiscovery.DiscoverFromDirectory")] public static IEnumerable AllExamples () { // Navigate from test assembly location to repository root, then to Examples directory // Test output is typically at: Tests/UnitTestsParallelizable/bin/Debug/net8.0/ // Examples are at: Examples/ string examplesDir = Path.GetFullPath (Path.Combine (AppContext.BaseDirectory, "..", "..", "..", "..", "..", "Examples")); if (!Directory.Exists (examplesDir)) { return []; } List examples = ExampleDiscovery.DiscoverFromDirectory (examplesDir).ToList (); if (examples.Count == 0) { return []; } return examples.Select (e => new object [] { e }); } [Theory] [MemberData (nameof (AllExamples))] public void Example_Has_Metadata (ExampleInfo example) { Assert.NotNull (example); Assert.False (string.IsNullOrWhiteSpace (example.Name), "Example name should not be empty"); Assert.False (string.IsNullOrWhiteSpace (example.Description), "Example description should not be empty"); Assert.True (File.Exists (example.AssemblyPath), $"Example assembly should exist: {example.AssemblyPath}"); _output.WriteLine ($"Example: {example.Name}"); _output.WriteLine ($" Description: {example.Description}"); _output.WriteLine ($" Categories: {string.Join (", ", example.Categories)}"); _output.WriteLine ($" Assembly: {example.AssemblyPath}"); } [Theory] [MemberData (nameof (AllExamples))] public void All_Examples_Quit_And_Init_Shutdown_Properly_OutOfProcess (ExampleInfo example) { _output.WriteLine ($"Running example '{example.Name}' out-of-process"); ExampleContext context = new () { DriverName = "FakeDriver", KeysToInject = new () { "Esc" }, TimeoutMs = 5000, CollectMetrics = false, Mode = ExecutionMode.OutOfProcess }; ExampleResult result = ExampleRunner.Run (example, context); if (!result.Success) { _output.WriteLine ($"Example failed: {result.ErrorMessage}"); if (!string.IsNullOrEmpty (result.StandardOutput)) { _output.WriteLine ($"Standard Output:\n{result.StandardOutput}"); } if (!string.IsNullOrEmpty (result.StandardError)) { _output.WriteLine ($"Standard Error:\n{result.StandardError}"); } } Assert.True (result.Success, $"Example '{example.Name}' should complete successfully"); Assert.False (result.TimedOut, $"Example '{example.Name}' should not timeout"); Assert.Equal (0, result.ExitCode); } [Theory] [MemberData (nameof (AllExamples))] public void All_Examples_Quit_And_Init_Shutdown_Properly_InProcess (ExampleInfo example) { _output.WriteLine ($"Running example '{example.Name}' in-process"); // Force a complete reset to ensure clean state Application.ResetState (true); ExampleContext context = new () { DriverName = "FakeDriver", KeysToInject = new () { "Esc" }, TimeoutMs = 5000, CollectMetrics = false, Mode = ExecutionMode.InProcess }; ExampleResult result = ExampleRunner.Run (example, context); if (!result.Success) { _output.WriteLine ($"Example failed: {result.ErrorMessage}"); } // Reset state after in-process execution Application.ResetState (true); Assert.True (result.Success, $"Example '{example.Name}' should complete successfully"); Assert.False (result.TimedOut, $"Example '{example.Name}' should not timeout"); } [Fact] public void ExampleContext_Serialization_Works () { ExampleContext context = new () { DriverName = "FakeDriver", KeysToInject = new () { "Esc", "Enter" }, TimeoutMs = 5000, MaxIterations = 100, CollectMetrics = true, Mode = ExecutionMode.InProcess }; string json = context.ToJson (); Assert.False (string.IsNullOrWhiteSpace (json)); ExampleContext? deserialized = ExampleContext.FromJson (json); Assert.NotNull (deserialized); Assert.Equal (context.DriverName, deserialized.DriverName); Assert.Equal (context.TimeoutMs, deserialized.TimeoutMs); Assert.Equal (context.MaxIterations, deserialized.MaxIterations); Assert.Equal (context.CollectMetrics, deserialized.CollectMetrics); Assert.Equal (context.Mode, deserialized.Mode); Assert.Equal (context.KeysToInject.Count, deserialized.KeysToInject.Count); } }