diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs index f296ebc6e42ad7..c38fde15d3013a 100644 --- a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs +++ b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs @@ -8,6 +8,7 @@ using System.IO.Pipes; using System.Linq; using System.Net; +using System.Reflection; using System.Security; using System.Text; using System.Threading; @@ -1556,15 +1557,14 @@ public void MainWindowHandle_GetNotStarted_ThrowsInvalidOperationException() var process = new Process(); Assert.Throws(() => process.MainWindowHandle); } - - [Fact] - [OuterLoop] - [Trait(XunitConstants.Category, XunitConstants.IgnoreForCI)] // Pops UI + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))] // it needs Notepad + [OuterLoop("Pops UI")] [PlatformSpecific(TestPlatforms.Windows)] public void MainWindowHandle_GetWithGui_ShouldRefresh_Windows() { const string ExePath = "notepad.exe"; - Assert.True(IsProgramInstalled(ExePath)); + Assert.True(IsProgramInstalled(ExePath), "Notepad is not installed"); using (Process process = Process.Start(ExePath)) { @@ -1591,16 +1591,15 @@ public void MainWindowHandle_GetWithGui_ShouldRefresh_Windows() } } - [Fact] - [OuterLoop] - [Trait(XunitConstants.Category, XunitConstants.IgnoreForCI)] // Pops UI + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))] // it needs Notepad + [OuterLoop("Pops UI")] [PlatformSpecific(TestPlatforms.Windows)] public void MainWindowTitle_GetWithGui_ShouldRefresh_Windows() { const string ExePath = "notepad.exe"; - Assert.True(IsProgramInstalled(ExePath)); + Assert.True(IsProgramInstalled(ExePath), "Notepad is not installed"); - using (Process process = Process.Start(ExePath)) + using (Process process = Process.Start(new ProcessStartInfo(ExePath))) { try { @@ -1627,6 +1626,76 @@ public void MainWindowTitle_GetWithGui_ShouldRefresh_Windows() } } + [Fact] + public void RefreshResetsAllRefreshableFields() + { + // testing Process.Responding using a real unresponsive process would be very hard to do properly + // instead of this, we just test the implementation to ensure that #36768 is not coming back + var process = new Process(); + + VerifyPrivateFieldsValues(process, shouldHaveDefaultValues: true); + + SetPrivateFieldsToNonDefaultValues(process); + + VerifyPrivateFieldsValues(process, shouldHaveDefaultValues: false); + + process.Refresh(); + + VerifyPrivateFieldsValues(process, shouldHaveDefaultValues: true); + + static void VerifyPrivateFieldsValues(Process process, bool shouldHaveDefaultValues) + { + Assert.Equal(shouldHaveDefaultValues, !(bool)GetPrivateFieldValue(process, "_exited")); + Assert.Equal(shouldHaveDefaultValues, !(bool)GetPrivateFieldValue(process, "_haveWorkingSetLimits")); + Assert.Equal(shouldHaveDefaultValues, !(bool)GetPrivateFieldValue(process, "_haveProcessorAffinity")); + Assert.Equal(shouldHaveDefaultValues, !(bool)GetPrivateFieldValue(process, "_havePriorityClass")); + Assert.Equal(shouldHaveDefaultValues, !(bool)GetPrivateFieldValue(process, "_haveExitTime")); + Assert.Equal(shouldHaveDefaultValues, !(bool)GetPrivateFieldValue(process, "_havePriorityBoostEnabled")); + + Assert.Equal(shouldHaveDefaultValues, null == GetPrivateFieldValue(process, "_processInfo")); + Assert.Equal(shouldHaveDefaultValues, null == GetPrivateFieldValue(process, "_threads")); + Assert.Equal(shouldHaveDefaultValues, null == GetPrivateFieldValue(process, "_modules")); + + if (OperatingSystem.IsWindows()) + { + Assert.Equal(shouldHaveDefaultValues, null == GetPrivateFieldValue(process, "_mainWindowTitle")); + Assert.Equal(shouldHaveDefaultValues, !(bool)GetPrivateFieldValue(process, "_signaled")); + Assert.Equal(shouldHaveDefaultValues, !(bool)GetPrivateFieldValue(process, "_haveMainWindow")); + Assert.Equal(shouldHaveDefaultValues, !(bool)GetPrivateFieldValue(process, "_haveResponding")); + } + } + + static void SetPrivateFieldsToNonDefaultValues(Process process) + { + SetPrivateFieldValue(process, "_exited", true); + SetPrivateFieldValue(process, "_haveWorkingSetLimits", true); + SetPrivateFieldValue(process, "_haveProcessorAffinity", true); + SetPrivateFieldValue(process, "_havePriorityClass", true); + SetPrivateFieldValue(process, "_haveExitTime", true); + SetPrivateFieldValue(process, "_havePriorityBoostEnabled", true); + + SetPrivateFieldValue(process, "_processInfo", typeof(Process).Assembly.GetType("System.Diagnostics.ProcessInfo").GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, Array.Empty()).Invoke(null)); + SetPrivateFieldValue(process, "_threads", new ProcessThreadCollection(Array.Empty())); + SetPrivateFieldValue(process, "_modules", new ProcessModuleCollection(Array.Empty())); + + if (OperatingSystem.IsWindows()) + { + SetPrivateFieldValue(process, "_signaled", true); + SetPrivateFieldValue(process, "_haveMainWindow", true); + SetPrivateFieldValue(process, "_mainWindowTitle", "notNull"); + SetPrivateFieldValue(process, "_haveResponding", true); + } + } + + static object GetPrivateFieldValue(Process process, string fieldName) => typeof(Process) + .GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance) + .GetValue(process); + + static void SetPrivateFieldValue(Process process, string fieldName, object value) => typeof(Process) + .GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance) + .SetValue(process, value); + } + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] public void MainWindowTitle_NoWindow_ReturnsEmpty() {