using UICatalog; using Xunit.Abstractions; namespace IntegrationTests.UICatalog; /// /// Integration tests for ForceDriver persistence when opening scenarios in UICatalog. /// public class ForceDriverTests { private readonly ITestOutputHelper _output; public ForceDriverTests (ITestOutputHelper output) { _output = output; } /// /// Tests that ForceDriver persists when running UICatalogTop and then opening a scenario. /// /// This test verifies the fix for issue #4391 works correctly by calling UICatalog's actual methods. /// /// THE BUG: Without the fix, ForceDriver was set directly on Application, but /// ConfigurationManager would override it from config files when scenarios ran. /// /// THE FIX has two parts (both in UICatalog.cs): /// 1. SetupForceDriverConfig() - Sets ForceDriver in ConfigurationManager.RuntimeConfig /// 2. ReloadForceDriverConfig() - Reloads RuntimeConfig before each scenario /// /// This test calls both UICatalog methods to verify the fix works. /// If you remove the calls to these methods or modify UICatalog.cs to remove the fix, /// this test will fail. /// [Fact] public void ForceDriver_Persists_From_UICatalogTop_To_Scenario () { // Arrange const string expectedDriver = "fake"; ConfigurationManager.Disable (true); Application.ResetState (true); // Initialize UICatalog.Options (required by UICatalogTop) global::UICatalog.UICatalog.Options = new UICatalogCommandLineOptions { Driver = expectedDriver, DontEnableConfigurationManagement = false, Scenario = "none", BenchmarkTimeout = 2500, Benchmark = false, ResultsFile = string.Empty, DebugLogLevel = "Warning" }; // Initialize cached scenarios (required by UICatalogTop) UICatalogTop.CachedScenarios = Scenario.GetScenarios (); // Call UICatalog's setup method (this is part 1 of the fix in UICatalog.cs) // This sets ForceDriver in RuntimeConfig global::UICatalog.UICatalog.SetupForceDriverConfig (expectedDriver); // Enable ConfigurationManager with all locations (as UICatalog does) ConfigurationManager.Enable (ConfigLocations.All); var topLevelDriverName = string.Empty; var scenarioDriverName = string.Empty; var iterationCount = 0; EventHandler? iterationHandler = null; try { // Phase 1: Run UICatalogTop (simulating main UI) _output.WriteLine ("=== Phase 1: Running UICatalogTop ==="); Application.Init (); topLevelDriverName = Application.Driver?.GetName () ?? string.Empty; _output.WriteLine ($"UICatalogTop driver: {topLevelDriverName}"); var top = new UICatalogTop (); // Set up to automatically select a scenario and stop iterationHandler = (sender, e) => { iterationCount++; // On first iteration, select a scenario and request stop if (iterationCount == 1) { // Select the first scenario if (UICatalogTop.CachedScenarios is { Count: > 0 }) { UICatalogTop.CachedSelectedScenario = (Scenario)Activator.CreateInstance (UICatalogTop.CachedScenarios[0].GetType ())!; Application.RequestStop (); } } }; Application.Iteration += iterationHandler; Application.Run (top); Application.Iteration -= iterationHandler; top.Dispose (); Application.Shutdown (); _output.WriteLine ($"Selected scenario: {UICatalogTop.CachedSelectedScenario?.GetName ()}"); _output.WriteLine ($"UICatalogTop completed after {iterationCount} iterations"); // Phase 2: Run the selected scenario (simulating what UICatalog.cs does) if (UICatalogTop.CachedSelectedScenario is { } scenario) { _output.WriteLine ($"\n=== Phase 2: Running scenario '{scenario.GetName ()}' ==="); // Call UICatalog's reload method (this is part 2 of the fix in UICatalog.cs) // This ensures ForceDriver persists across Init/Shutdown cycles global::UICatalog.UICatalog.ReloadForceDriverConfig (); _output.WriteLine ("Reloaded ForceDriver config via UICatalog.ReloadForceDriverConfig()"); // Track the driver used inside the scenario string? driverInsideScenario = null; EventHandler>? initHandler = null; EventHandler? scenarioIterationHandler = null; initHandler = (s, e) => { if (e.Value) { driverInsideScenario = Application.Driver?.GetName (); // Request stop immediately so the scenario doesn't actually run scenarioIterationHandler = (_, _) => { Application.RequestStop (); // Remove immediately to avoid assertions in Shutdown if (scenarioIterationHandler != null) { Application.Iteration -= scenarioIterationHandler; scenarioIterationHandler = null; } }; Application.Iteration += scenarioIterationHandler; } }; Application.InitializedChanged += initHandler; // Run the scenario's Main() method (this is what UICatalog does) scenario.Main (); scenarioDriverName = driverInsideScenario ?? string.Empty; Application.InitializedChanged -= initHandler; scenario.Dispose (); _output.WriteLine ($"Scenario driver: {scenarioDriverName}"); _output.WriteLine ("Scenario completed and disposed"); } else { _output.WriteLine ("ERROR: No scenario was selected"); Assert.Fail ("No scenario was selected"); } // Assert _output.WriteLine ($"\n=== Results ==="); _output.WriteLine ($"UICatalogTop driver: {topLevelDriverName}"); _output.WriteLine ($"Scenario driver: {scenarioDriverName}"); Assert.Equal (expectedDriver, topLevelDriverName); Assert.Equal (expectedDriver, scenarioDriverName); _output.WriteLine ($"SUCCESS: Driver '{expectedDriver}' persisted from UICatalogTop to scenario"); } finally { if (iterationHandler != null) { Application.Iteration -= iterationHandler; } ConfigurationManager.Disable (true); Application.ResetState (true); } } /// /// Tests that ForceDriver persists when running multiple scenarios in sequence. /// /// This verifies the fix works correctly by calling UICatalog's ReloadForceDriverConfig() method. /// /// THE FIX: ReloadForceDriverConfig() in UICatalog.cs reloads RuntimeConfig before each scenario. /// Without calling this method, the driver would revert to platform default. /// [Fact] public void ForceDriver_Persists_Across_Multiple_Scenarios () { // Arrange const string expectedDriver = "fake"; ConfigurationManager.Disable (true); Application.ResetState (true); // Initialize UICatalog.Options global::UICatalog.UICatalog.Options = new UICatalogCommandLineOptions { Driver = expectedDriver, DontEnableConfigurationManagement = false, Scenario = "none", BenchmarkTimeout = 2500, Benchmark = false, ResultsFile = string.Empty, DebugLogLevel = "Warning" }; // Call UICatalog's setup method (this is part 1 of the fix in UICatalog.cs) global::UICatalog.UICatalog.SetupForceDriverConfig (expectedDriver); // Enable ConfigurationManager ConfigurationManager.Enable (ConfigLocations.All); string? driver1 = null; string? driver2 = null; EventHandler>? initHandler1 = null; EventHandler>? initHandler2 = null; EventHandler? iterHandler1 = null; EventHandler? iterHandler2 = null; try { // Get two different scenarios to test var scenarios = Scenario.GetScenarios (); Assert.True (scenarios.Count >= 2, "Need at least 2 scenarios for this test"); var scenario1 = scenarios[0]; var scenario2 = scenarios[1]; _output.WriteLine ($"Testing with scenarios: {scenario1.GetName ()} and {scenario2.GetName ()}"); // Run scenario 1 initHandler1 = (s, e) => { if (e.Value) { driver1 = Application.Driver?.GetName (); iterHandler1 = (_, _) => { Application.RequestStop (); // Remove immediately to avoid assertions in Shutdown if (iterHandler1 != null) { Application.Iteration -= iterHandler1; iterHandler1 = null; } }; Application.Iteration += iterHandler1; } }; Application.InitializedChanged += initHandler1; scenario1.Main (); Application.InitializedChanged -= initHandler1; scenario1.Dispose (); _output.WriteLine ($"Scenario 1 completed with driver: {driver1}"); // Call UICatalog's reload method (this is part 2 of the fix in UICatalog.cs) // This ensures ForceDriver persists across Init/Shutdown cycles global::UICatalog.UICatalog.ReloadForceDriverConfig (); _output.WriteLine ("Reloaded ForceDriver config via UICatalog.ReloadForceDriverConfig()"); // Run scenario 2 // Run scenario 2 initHandler2 = (s, e) => { if (e.Value) { driver2 = Application.Driver?.GetName (); iterHandler2 = (_, _) => { Application.RequestStop (); // Remove immediately to avoid assertions in Shutdown if (iterHandler2 != null) { Application.Iteration -= iterHandler2; iterHandler2 = null; } }; Application.Iteration += iterHandler2; } }; Application.InitializedChanged += initHandler2; scenario2.Main (); Application.InitializedChanged -= initHandler2; scenario2.Dispose (); _output.WriteLine ($"Scenario 2 completed with driver: {driver2}"); // Assert Assert.Equal (expectedDriver, driver1); Assert.Equal (expectedDriver, driver2); _output.WriteLine ($"SUCCESS: Driver '{expectedDriver}' persisted across both scenarios"); } finally { // Cleanup any remaining handlers if (initHandler1 != null) { Application.InitializedChanged -= initHandler1; } if (iterHandler2 != null) { Application.InitializedChanged -= initHandler2; } if (iterHandler1 != null) { Application.Iteration -= iterHandler1; } if (iterHandler2 != null) { Application.Iteration -= iterHandler2; } ConfigurationManager.Disable (true); Application.ResetState (true); } } }