Repository navigation
Expand file tree
/
Copy pathWindowsPowerTests.cs
More file actions
154 lines (137 loc) · 5.26 KB
/
Copy pathWindowsPowerTests.cs
File metadata and controls
154 lines (137 loc) · 5.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
using static WindowsDeviceControl.Tests.TestFixtures;
namespace WindowsDeviceControl.Tests;
public sealed class WindowsPowerTests
{
private static readonly Guid Custom = new("d0905d52-3ba4-4fe9-a463-e6d96ac80e93");
[Theory]
[InlineData("Höchstleistung")]
[InlineData("省電力")]
public void DecodesLocalizedUtf16NamesUsingTheReturnedByteCount(string name)
{
var bytes = Encoding.Unicode.GetBytes(name + "\0ignored padding");
Assert.Equal(name, WindowsPower.DecodeName(bytes, (uint)(name.Length + 1) * 2, Custom));
}
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(3)]
[InlineData(6)]
[InlineData(10)]
public void RejectsMalformedNameLengthsOrMissingTerminators(uint size)
{
var bytes = Encoding.Unicode.GetBytes("abc\0");
AssertInvalidData(() => WindowsPower.DecodeName(bytes, size, Custom));
}
[Fact]
public void EmptyNameFallsBackToStableGuid()
{
Assert.Equal(Custom.ToString("D"), WindowsPower.DecodeName([0, 0], 2, Custom));
}
[Theory]
[InlineData(WindowsPowerAction.Shutdown, "/s /t 0")]
[InlineData(WindowsPowerAction.Restart, "/r /t 0")]
[InlineData(WindowsPowerAction.SignOut, "/l")]
public void ActionsUseTheSystemToolWithoutForceOrInteractiveWindows(WindowsPowerAction action, string arguments)
{
var start = WindowsPower.ActionStartInfo(action);
Assert.Equal(Path.Combine(Environment.SystemDirectory, "shutdown.exe"), start.FileName);
Assert.Equal(arguments, start.Arguments);
Assert.True(start.CreateNoWindow);
Assert.False(start.UseShellExecute);
}
[Fact]
public async Task CancelledActionsNeverCallThePort()
{
CancellationToken cancelled = new(true);
var api = new FakePowerActionApi();
await Assert.ThrowsAnyAsync<OperationCanceledException>(() => WindowsPower.SuspendAsync(false, api, cancelled));
await Assert.ThrowsAnyAsync<OperationCanceledException>(() =>
WindowsPower.RequestActionAsync(WindowsPowerAction.Restart, api, cancelled));
Assert.Equal(0, api.SuspendCalls);
Assert.Equal(0, api.ToolCalls);
}
[Theory]
[InlineData(WindowsPowerAction.Shutdown, "/s /t 0")]
[InlineData(WindowsPowerAction.Restart, "/r /t 0")]
[InlineData(WindowsPowerAction.SignOut, "/l")]
public async Task ActionArgumentsAreForwardedUnchanged(WindowsPowerAction action, string arguments)
{
using var cancellation = new CancellationTokenSource();
var api = new FakePowerActionApi();
await WindowsPower.RequestActionAsync(action, api, cancellation.Token);
Assert.Equal(1, api.ToolCalls);
Assert.NotNull(api.Start);
Assert.Equal(arguments, api.Start.Arguments);
Assert.Equal(cancellation.Token, api.Token);
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task SuspendForwardsTheHibernateFlagOnce(bool hibernate)
{
var api = new FakePowerActionApi();
await WindowsPower.SuspendAsync(hibernate, api, CancellationToken.None);
Assert.Equal(1, api.SuspendCalls);
Assert.Equal(hibernate, api.Hibernate);
Assert.Equal(0, api.ToolCalls);
}
[Fact]
public async Task ToolRefusalPreservesTheExitCodeWithoutRetry()
{
var api = new FakePowerActionApi { ExitCode = 5 };
var error = await Assert.ThrowsAsync<Win32Exception>(() =>
WindowsPower.RequestActionAsync(WindowsPowerAction.Restart, api, CancellationToken.None));
Assert.Equal(5, error.NativeErrorCode);
Assert.Equal("Windows refused the power request.", error.Message);
Assert.Equal(1, api.ToolCalls);
}
[Fact]
public async Task SuspendFailurePropagatesOnce()
{
var refusal = new Win32Exception(50);
var api = new FakePowerActionApi { SuspendFailure = refusal };
var error = await Assert.ThrowsAsync<Win32Exception>(() =>
WindowsPower.SuspendAsync(true, api, CancellationToken.None));
Assert.Same(refusal, error);
Assert.Equal(1, api.SuspendCalls);
Assert.Equal(0, api.ToolCalls);
}
[Fact]
public void UnknownActionIsRejectedBeforeDispatch()
{
Assert.Throws<ArgumentOutOfRangeException>(() => WindowsPower.ActionStartInfo((WindowsPowerAction)100));
}
private sealed class FakePowerActionApi : IPowerActionApi
{
internal int SuspendCalls, ToolCalls;
internal bool Hibernate;
internal int ExitCode;
internal Win32Exception? SuspendFailure;
internal ProcessStartInfo? Start;
internal CancellationToken Token;
public void Suspend(bool hibernate)
{
SuspendCalls++;
Hibernate = hibernate;
if (SuspendFailure is not null)
{
throw SuspendFailure;
}
}
public Task<int> RunToolAsync(ProcessStartInfo start, CancellationToken cancellationToken)
{
ToolCalls++;
Start = start;
Token = cancellationToken;
return Task.FromResult(ExitCode);
}
}
}