Add process discovery helpers and Magic facade accessors
Introduces ApplicationFinder (by name/title/handle), Magic.Open overloads, and Magic.Threads/Regions/QueryRegion accessors. Closes section 3 of add-thread-region-finder and updates tasks/comparison doc.
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
using System.Linq;
|
||||
using WhiteMagic;
|
||||
using WhiteMagic.Memory;
|
||||
using WhiteMagic.Native;
|
||||
using WhiteMagic.Thread;
|
||||
using Xunit;
|
||||
|
||||
namespace WhiteMagicTest;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for the convenience accessors exposed directly on <see cref="Magic"/>.
|
||||
/// </summary>
|
||||
public sealed class MagicFacadeTests
|
||||
{
|
||||
[Fact]
|
||||
public void QueryRegion_returns_region_containing_image_base()
|
||||
{
|
||||
using var magic = Magic.OpenInProcess();
|
||||
MemoryRegion region = magic.QueryRegion(magic.Memory.ImageBase);
|
||||
Assert.True(region.Contains(magic.Memory.ImageBase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Regions_enumerates_region_containing_image_base()
|
||||
{
|
||||
using var magic = Magic.OpenInProcess();
|
||||
|
||||
bool found = magic.Regions.Any(r => r.Contains(magic.Memory.ImageBase));
|
||||
|
||||
Assert.True(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Threads_factory_enumerates_current_thread()
|
||||
{
|
||||
using var magic = Magic.OpenInProcess();
|
||||
ThreadFactory factory = magic.Threads;
|
||||
|
||||
int currentOsId = (int)NativeMethods.GetCurrentThreadId();
|
||||
bool found = factory.Enumerate().Any(t => t.Id == currentOsId);
|
||||
|
||||
Assert.True(found);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using WhiteMagic;
|
||||
using WhiteMagic.Native;
|
||||
using WhiteMagic.ProcessDiscovery;
|
||||
using Xunit;
|
||||
|
||||
namespace WhiteMagicTest.ProcessDiscovery;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for process discovery via <see cref="ApplicationFinder"/> and the matching
|
||||
/// <see cref="Magic.Open"/> overloads.
|
||||
/// </summary>
|
||||
public sealed class ApplicationFinderTests
|
||||
{
|
||||
[Fact]
|
||||
public void Enumerate_finds_current_process_by_name()
|
||||
{
|
||||
string currentName = Process.GetCurrentProcess().ProcessName;
|
||||
|
||||
Process[] found = ApplicationFinder.Enumerate(currentName).ToArray();
|
||||
|
||||
Assert.True(found.Length >= 1);
|
||||
Assert.Contains(found, p => p.Id == Process.GetCurrentProcess().Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Open_by_name_returns_current_process_when_unique()
|
||||
{
|
||||
string currentName = Process.GetCurrentProcess().ProcessName;
|
||||
|
||||
using Process process = ApplicationFinder.OpenProcess(currentName);
|
||||
|
||||
Assert.Equal(Process.GetCurrentProcess().Id, process.Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Open_throws_when_name_is_ambiguous()
|
||||
{
|
||||
// Look for a multi-instance system process; skip if the environment is not typical.
|
||||
Process[] candidates = Process.GetProcessesByName("svchost");
|
||||
if (candidates.Length <= 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InvalidOperationException ex = Assert.Throws<InvalidOperationException>(
|
||||
() => ApplicationFinder.OpenProcess("svchost"));
|
||||
|
||||
Assert.Contains("svchost", ex.Message);
|
||||
Assert.Contains("ambiguous", ex.Message, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Open_throws_when_no_process_matches()
|
||||
{
|
||||
InvalidOperationException ex = Assert.Throws<InvalidOperationException>(
|
||||
() => ApplicationFinder.OpenProcess("probably-not-loaded-xyz.exe"));
|
||||
|
||||
Assert.Contains("No process", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OpenByWindowHandle_returns_owning_process()
|
||||
{
|
||||
IntPtr handle = Process.GetCurrentProcess().MainWindowHandle;
|
||||
if (handle == IntPtr.Zero)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using Process process = ApplicationFinder.OpenByWindowHandle(handle);
|
||||
Assert.Equal(Process.GetCurrentProcess().Id, process.Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OpenByWindowHandle_throws_for_zero_handle()
|
||||
{
|
||||
Assert.Throws<ArgumentException>("handle", () => ApplicationFinder.OpenByWindowHandle(IntPtr.Zero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Magic_Open_by_name_attaches_to_current_process()
|
||||
{
|
||||
string currentName = Process.GetCurrentProcess().ProcessName;
|
||||
|
||||
using var magic = Magic.Open(currentName);
|
||||
|
||||
Assert.Equal(Process.GetCurrentProcess().Id, magic.Memory.ProcessId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Magic_OpenByWindowHandle_attaches_to_owning_process()
|
||||
{
|
||||
IntPtr handle = Process.GetCurrentProcess().MainWindowHandle;
|
||||
if (handle == IntPtr.Zero)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var magic = Magic.OpenByWindowHandle(handle);
|
||||
|
||||
Assert.Equal(Process.GetCurrentProcess().Id, magic.Memory.ProcessId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user