This document covers the debugging techniques, test frameworks, and testing infrastructure used in PowerToys development. It explains the unit test organization, the MockedInput system for keyboard testing, integration testing approaches, and debugging workflows. For information about building PowerToys from source, see Building from Source. For details on the CI/CD pipeline, see Code Quality and CI.
PowerToys uses a multi-layered testing approach combining unit tests, integration tests, and UI automation tests. The testing infrastructure varies by technology stack:
Sources: Directory.Packages.props89-90 Directory.Packages.props14 Directory.Packages.props122
PowerToys organizes test projects alongside their corresponding module implementations:
| Module | Test Project Location | Technology | Purpose |
|---|---|---|---|
| Keyboard Manager | src/modules/keyboardmanager/KeyboardManagerEngineTest/ | C++ | Tests remapping logic and keyboard event handling |
| Settings UI | src/settings-ui/Settings.UI.UnitTests/ | C# | Tests settings ViewModels and configuration |
| PowerToys Run Plugins | src/modules/launcher/Plugins/*/Tests/ | C# | Tests individual plugin functionality |
| Common Libraries | src/common/*/Tests/ | C#/C++ | Tests shared utility functions |
Test projects follow naming conventions with .Tests, .UnitTests, or Test suffixes. The build system conditionally includes test projects based on the BuildTests property.
Sources: Cpp.Build.props5-9 project structure from file paths
C++ test projects use the MSTest framework integrated into Visual Studio. Test projects are configured with specific compiler settings:
The build system automatically disables expensive operations like precompiled headers and code analysis for test projects when BuildTests=false, improving build times during development.
Sources: Cpp.Build.props5-9 Cpp.Build.props32-36
To debug C++ tests:
Debug configurations are defined in project properties with appropriate symbol generation:
DebugInformationFormat=ProgramDatabase, optimization disabledSources: Cpp.Build.props84-93 Cpp.Build.props94-107
The Keyboard Manager module includes a sophisticated input mocking system that simulates keyboard input without requiring physical keyboard interaction. This enables automated testing of complex remapping scenarios.
Sources: src/modules/keyboardmanager/KeyboardManagerEngineTest/MockedInput.h8-57 src/modules/keyboardmanager/KeyboardManagerEngineTest/MockedInput.cpp1-11
The MockedInput class inherits from InputInterface and provides methods for simulating keyboard input:
| Method | Purpose | Key Functionality |
|---|---|---|
SetHookProc | Sets the keyboard hook procedure to test | Configures the low-level keyboard hook handler that processes input events |
SendVirtualInput | Simulates keyboard input | Processes INPUT structures, updates keyboard state, calls hook procedure, records events |
GetVirtualKeyState | Queries key state | Returns whether a virtual key is currently pressed (true) or released (false) |
GetInputEventHistory | Retrieves event history | Returns vector of all LowlevelKeyboardEvent objects generated during test |
ResetInputEventHistory | Clears event history | Resets the event recording for new test scenarios |
SetSendInputCallTestHandler | Monitors SendInput calls | Allows tests to verify correct number of SendInput calls with specific conditions |
Sources: src/modules/keyboardmanager/KeyboardManagerEngineTest/MockedInput.h14-57
The input simulation process in MockedInput follows this flow:
The system handles recursive SendInput calls (when the hook procedure generates new input) by detecting the KEYBOARDMANAGER_SINGLEKEY_FLAG or KEYBOARDMANAGER_SHORTCUT_FLAG in the dwExtraInfo field.
Sources: src/modules/keyboardmanager/KeyboardManagerEngineTest/MockedInput.cpp14-104 src/modules/keyboardmanager/common/KeyboardManagerConstants.h86-89
Tests using MockedInput follow a standard pattern:
MockedInput instanceSetHookProcSendVirtualInputGetVirtualKeyState and GetInputEventHistoryFor detailed examples of test scenarios, refer to the test implementation files in the KeyboardManagerEngineTest project.
Sources: doc/devdocs/modules/keyboardmanager/keyboardeventhandlers.md11-13
C# test projects use MSTest 3.8.3 as the test framework and Moq 4.18.4 for creating mock objects:
Note: Moq is pinned to version 4.18.4 to avoid behavior changes introduced in version 4.20+.
Sources: Directory.Packages.props87-88 Directory.Packages.props89
PowerToys uses System.IO.Abstractions.TestingHelpers (version 22.0.13) to mock file system operations in tests:
| Class | Purpose | Usage |
|---|---|---|
MockFileSystem | In-memory file system | Create test file structures without disk I/O |
MockFileData | File content mock | Define file contents, attributes, timestamps |
MockDirectoryData | Directory mock | Define directory structures and attributes |
This enables testing of file-based functionality (settings loading, configuration parsing, etc.) without creating actual files on disk.
Sources: Directory.Packages.props121-122
PowerToys uses Appium WebDriver (version 4.4.5) for UI automation testing:
UI automation tests interact with WinUI3 and WPF applications through the Windows UI Automation framework, enabling automated testing of user interactions without manual intervention.
Sources: Directory.Packages.props14
To debug UI automation tests:
Common debugging challenges:
WebDriverWait for element availabilityPowerToys supports standard Visual Studio debugging capabilities:
| Feature | C++ Projects | C# Projects | Configuration |
|---|---|---|---|
| Breakpoints | โ | โ | Available in all configurations |
| Edit and Continue | โ | โ | Debug builds only |
| Memory inspection | โ | โ | ProgramDatabase debug format |
| Performance profiling | โ | โ | Available with PDB symbols |
| Dump file debugging | โ | โ | Symbols required |
Debug information format is set to ProgramDatabase for C++ projects when Control Flow Guard is enabled, ensuring full debugging capability.
Sources: Cpp.Build.props72 Cpp.Build.props91
PowerToys architecture involves multiple processes (Runner, modules, Settings UI). To debug multi-process scenarios:
Steps for multi-process debugging:
PowerToys.exeSources: src/modules/keyboardmanager/dll/dllmain.cpp131-164 src/modules/keyboardmanager/dll/dllmain.cpp166-181
Most PowerToys modules implement ETW (Event Tracing for Windows) tracing for debugging:
| Module | Trace Class | Registration |
|---|---|---|
| Keyboard Manager | Trace | keyboardmanager/dll/dllmain.cpp18 |
| Measure Tool | Trace | MeasureTool/MeasureToolModuleInterface/trace.h77 |
| Find My Mouse | Trace | MouseUtils/FindMyMouse/trace.h112 |
Trace events are registered on DLL_PROCESS_ATTACH and unregistered on DLL_PROCESS_DETACH. To capture traces:
logman command-line tool to create trace sessionsSources: src/modules/keyboardmanager/dll/dllmain.cpp13-29
The CI pipeline includes multiple testing phases:
Test projects are conditionally built in CI using the BuildTests property. The YML pipeline configuration includes test execution steps.
Sources: Cpp.Build.props5-9 .github/pull_request_template.md16
During development, test project compilation can be skipped to speed up builds:
When BuildTests=false:
UsePrecompiledHeaders=falseRunCodeAnalysis=falseThis is particularly useful when iterating on implementation code without running tests.
Sources: Cpp.Build.props5-9
| Command | Environment | Purpose |
|---|---|---|
| Build โ Run All Tests | Visual Studio | Execute all tests in Test Explorer |
| Right-click test โ Debug | Visual Studio | Debug specific test with breakpoints |
dotnet test | Command line | Run C# tests from solution directory |
| MSBuild with test target | Command line | Build and run C++ tests |
Pull request automation commands (via GitHub comments):
| Command | Effect |
|---|---|
/azp run | Triggers full CI pipeline including all tests |
/bugreport | Request bug report file from reporter (not test-related) |
Sources: doc/devdocs/commands.md5-10 .github/policies/resourceManagement.yml108-128
Test projects inherit common properties but override specific settings:
Sources: Cpp.Build.props111-113 Cpp.Build.props118-119
C# test projects use SDK-style project format with centralized package management:
net9.0-windows10.0.26100.0 (defined in Directory.Build.props)$(Platform)\$(Configuration)\Test package versions are managed centrally in Directory.Packages.props
Sources: Directory.Packages.props2-4 src/modules/MeasureTool/MeasureToolUI/MeasureToolUI.csproj1-4
| Issue | Symptoms | Solution |
|---|---|---|
| Test project not building | Errors about missing test framework | Ensure MSTest package references are correct in Directory.Packages.props |
| Tests not discovered | Test Explorer shows no tests | Clean and rebuild test project; restart Visual Studio |
| UI tests timing out | WinAppDriver tests fail intermittently | Add explicit waits; check element locators |
| Mock verification failures | Moq throws MockException | Verify mock setup matches actual calls; check parameter matchers |
| Keyboard tests failing | MockedInput state incorrect | Reset keyboard state between tests; check event history |
When filing issues about test failures:
Sources: .github/ISSUE_TEMPLATE/bug_report.yml88-109
Page Sources: Directory.Packages.props Cpp.Build.props src/modules/keyboardmanager/KeyboardManagerEngineTest/MockedInput.cpp src/modules/keyboardmanager/KeyboardManagerEngineTest/MockedInput.h src/modules/keyboardmanager/dll/dllmain.cpp src/modules/keyboardmanager/common/KeyboardManagerConstants.h .github/pull_request_template.md doc/devdocs/modules/keyboardmanager/keyboardeventhandlers.md .github/ISSUE_TEMPLATE/bug_report.yml
Refresh this wiki
This wiki was recently refreshed. Please wait 4 days to refresh again.