RunnableLifecycleTests.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. #nullable enable
  2. using Xunit.Abstractions;
  3. namespace ViewsTests;
  4. /// <summary>
  5. /// Tests for IRunnable lifecycle behavior.
  6. /// </summary>
  7. public class RunnableLifecycleTests (ITestOutputHelper output)
  8. {
  9. private readonly ITestOutputHelper _output = output;
  10. [Fact]
  11. public void Runnable_OnIsRunningChanging_CanExtractResult ()
  12. {
  13. // Arrange
  14. ResultExtractingRunnable runnable = new ();
  15. runnable.TestValue = "extracted";
  16. // Act
  17. bool canceled = runnable.RaiseIsRunningChanging (true, false); // Stopping
  18. // Assert
  19. Assert.False (canceled);
  20. Assert.Equal ("extracted", runnable.Result);
  21. }
  22. [Fact]
  23. public void Runnable_OnIsRunningChanging_ClearsResultWhenStarting ()
  24. {
  25. // Arrange
  26. ResultExtractingRunnable runnable = new () { Result = "previous" };
  27. // Act
  28. bool canceled = runnable.RaiseIsRunningChanging (false, true); // Starting
  29. // Assert
  30. Assert.False (canceled);
  31. Assert.Null (runnable.Result); // Result should be cleared
  32. }
  33. [Fact]
  34. public void Runnable_CanCancelStoppingWithUnsavedChanges ()
  35. {
  36. // Arrange
  37. UnsavedChangesRunnable runnable = new () { HasUnsavedChanges = true };
  38. // Act
  39. bool canceled = runnable.RaiseIsRunningChanging (true, false); // Stopping
  40. // Assert
  41. Assert.True (canceled); // Should be canceled
  42. }
  43. [Fact]
  44. public void Runnable_AllowsStoppingWithoutUnsavedChanges ()
  45. {
  46. // Arrange
  47. UnsavedChangesRunnable runnable = new () { HasUnsavedChanges = false };
  48. // Act
  49. bool canceled = runnable.RaiseIsRunningChanging (true, false); // Stopping
  50. // Assert
  51. Assert.False (canceled); // Should not be canceled
  52. }
  53. [Fact]
  54. public void Runnable_OnIsRunningChanged_CalledAfterStateChange ()
  55. {
  56. // Arrange
  57. TrackedRunnable runnable = new ();
  58. // Act
  59. runnable.RaiseIsRunningChangedEvent (true);
  60. // Assert
  61. Assert.True (runnable.OnIsRunningChangedCalled);
  62. Assert.True (runnable.LastIsRunningValue);
  63. }
  64. [Fact]
  65. public void Runnable_OnIsModalChanged_CalledAfterStateChange ()
  66. {
  67. // Arrange
  68. TrackedRunnable runnable = new ();
  69. // Act
  70. runnable.RaiseIsModalChangedEvent (true);
  71. // Assert
  72. Assert.True (runnable.OnIsModalChangedCalled);
  73. Assert.True (runnable.LastIsModalValue);
  74. }
  75. /// <summary>
  76. /// Test runnable that extracts result in OnIsRunningChanging.
  77. /// </summary>
  78. private class ResultExtractingRunnable : Runnable<string>
  79. {
  80. public string? TestValue { get; set; }
  81. protected override bool OnIsRunningChanging (bool oldIsRunning, bool newIsRunning)
  82. {
  83. if (!newIsRunning) // Stopping
  84. {
  85. // Extract result before removal from stack
  86. Result = TestValue;
  87. }
  88. return base.OnIsRunningChanging (oldIsRunning, newIsRunning);
  89. }
  90. }
  91. /// <summary>
  92. /// Test runnable that can prevent stopping with unsaved changes.
  93. /// </summary>
  94. private class UnsavedChangesRunnable : Runnable<int>
  95. {
  96. public bool HasUnsavedChanges { get; set; }
  97. protected override bool OnIsRunningChanging (bool oldIsRunning, bool newIsRunning)
  98. {
  99. if (!newIsRunning && HasUnsavedChanges) // Stopping with unsaved changes
  100. {
  101. return true; // Cancel stopping
  102. }
  103. return base.OnIsRunningChanging (oldIsRunning, newIsRunning);
  104. }
  105. }
  106. /// <summary>
  107. /// Test runnable that tracks lifecycle method calls.
  108. /// </summary>
  109. private class TrackedRunnable : Runnable<int>
  110. {
  111. public bool OnIsRunningChangedCalled { get; private set; }
  112. public bool LastIsRunningValue { get; private set; }
  113. public bool OnIsModalChangedCalled { get; private set; }
  114. public bool LastIsModalValue { get; private set; }
  115. protected override void OnIsRunningChanged (bool newIsRunning)
  116. {
  117. OnIsRunningChangedCalled = true;
  118. LastIsRunningValue = newIsRunning;
  119. base.OnIsRunningChanged (newIsRunning);
  120. }
  121. protected override void OnIsModalChanged (bool newIsModal)
  122. {
  123. OnIsModalChangedCalled = true;
  124. LastIsModalValue = newIsModal;
  125. base.OnIsModalChanged (newIsModal);
  126. }
  127. }
  128. }