Files
PowerToys/src/modules/powerdisplay/PowerDisplay.Cli.UnitTests/RecordingCliOutput.cs
moooyo 5c9c93d56d feat(powerdisplay): add CLI for monitor control (#48632)
## Summary of the Pull Request

Adds `PowerToys.PowerDisplay.Cli.exe`, a scriptable interface for
controlling monitors through the running PowerDisplay process. It
supports `list`, `get`, `set`, `up`, `down`, `capabilities`, `profiles`,
and `apply-profile`.

The CLI communicates over an authenticated, per-session named pipe;
PowerDisplay remains responsible for DDC/CI and WMI access.

## PR Checklist

- [x] Closes: #48713
- [x] **Communication:** Discussed with core contributors
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** Core errors are localizable; some help and
output text remains English-only
- [ ] **Dev docs:** N/A; built-in CLI help is the command reference
- [x] **New binaries:** Added on the required places
- [x] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
- [x] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetupVNext/Resources.wxs)
- [x] **YML for CI pipeline:** N/A; test assemblies are auto-discovered
- [x] **YML for signed pipeline:** N/A; signing is driven by
`ESRPSigning_core.json`
- [ ] **Documentation updated:** N/A

## Detailed Description of the Pull Request / Additional comments

- Adds an AOT-compatible CLI and shared request/response contracts.
- Uses a secured named-pipe server in PowerDisplay, with stable exit
codes and a bounded request timeout.
- Supports saved profiles by their existing stable profile IDs.
- Adds solution, signing, installer, and unit-test project integration.

## Validation Steps Performed

- PowerDisplay Lib, Contracts, CLI, and IPC unit-test suites pass.
- Native AOT publish completes without analyzer warnings.
- Manually validated the CLI on two DDC/CI monitors, including the
PowerDisplay-unavailable path.
- Rebuilt the PowerDisplay GUI after the shared-library changes.

---------

Co-authored-by: Yu Leng <yuleng@microsoft.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-16 23:08:27 +08:00

51 lines
1.9 KiB
C#

// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using PowerDisplay.Cli.Output;
using PowerDisplay.Contracts;
namespace PowerDisplay.Cli.UnitTests;
/// <summary>
/// Shared <see cref="ICliOutput"/> test double. Records each rendered result as a tagged stdout line
/// and each warning/error as a tagged stderr line (so dispatch tests can assert which renderer ran),
/// and additionally tracks the error count and last error (so batch tests can assert aggregation).
/// </summary>
internal sealed class RecordingCliOutput : ICliOutput
{
private readonly List<string> stdoutLines = new();
private readonly List<string> stderrLines = new();
public IReadOnlyList<string> StdoutLines => this.stdoutLines;
public IReadOnlyList<string> StderrLines => this.stderrLines;
public int ErrorCount { get; private set; }
public CliErrorResult? LastError { get; private set; }
public void WriteListResult(CliListResult r) => this.stdoutLines.Add("list:" + r.Command);
public void WriteSetResult(CliSetResult r) => this.stdoutLines.Add("set:" + r.Setting);
public void WriteGetResult(CliGetResult r) => this.stdoutLines.Add("get");
public void WriteCapabilitiesResult(CliCapabilitiesResult r) => this.stdoutLines.Add("capabilities");
public void WriteProfileListResult(CliProfileListResult r) => this.stdoutLines.Add("profiles");
public void WriteApplyProfileResult(CliApplyProfileResult r) => this.stdoutLines.Add("apply-profile:" + r.Profile);
public void WriteError(CliErrorResult r)
{
this.ErrorCount++;
this.LastError = r;
this.stderrLines.Add("error:" + r.Error.Code + ":" + r.Error.ExitCode);
}
public void WriteWarning(string message) => this.stderrLines.Add("warn:" + message);
}