Skip to content
89 changes: 79 additions & 10 deletions src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1556,15 +1557,14 @@ public void MainWindowHandle_GetNotStarted_ThrowsInvalidOperationException()
var process = new Process();
Assert.Throws<InvalidOperationException>(() => 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))
{
Expand All @@ -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
{
Expand All @@ -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<Type>()).Invoke(null));
SetPrivateFieldValue(process, "_threads", new ProcessThreadCollection(Array.Empty<ProcessThread>()));
SetPrivateFieldValue(process, "_modules", new ProcessModuleCollection(Array.Empty<ProcessModule>()));

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()
{
Expand Down