Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable platform compatibility warnings for android, ios, tvos, and browser #5046

Merged
merged 4 commits into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,30 @@ public HotReloadHandler(IConsole console, IOutputDevice outputDevice, IOutputDev
_console = console;
_outputDevice = outputDevice;
_outputDeviceDataProducer = outputDeviceDataProducer;
_console.CancelKeyPress += (_, _) =>

if (!IsCancelKeyPressNotSupported())
{
if (!s_shutdownProcess)
_console.CancelKeyPress += (_, _) =>
{
s_shutdownProcess = true;
SemaphoreSlim.Release();
}
};
if (!s_shutdownProcess)
{
s_shutdownProcess = true;
SemaphoreSlim.Release();
}
};
}
}

[SupportedOSPlatformGuard("android")]
[SupportedOSPlatformGuard("ios")]
[SupportedOSPlatformGuard("tvos")]
[SupportedOSPlatformGuard("browser")]
private static bool IsCancelKeyPressNotSupported()
=> RuntimeInformation.IsOSPlatform(OSPlatform.Create("ANDROID")) ||
RuntimeInformation.IsOSPlatform(OSPlatform.Create("IOS")) ||
RuntimeInformation.IsOSPlatform(OSPlatform.Create("TVOS")) ||
RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER"));

// Called automatically by the runtime through the MetadataUpdateHandlerAttribute
public static void ClearCache(Type[]? _)
{
Expand Down Expand Up @@ -82,10 +96,22 @@ public async Task<bool> ShouldRunAsync(Task? waitExecutionCompletion, Cancellati
// We're closing
}

_console!.Clear();
if (!IsClearNotSupported())
{
_console!.Clear();
}

await _outputDevice.DisplayAsync(_outputDeviceDataProducer, new TextOutputDeviceData(ExtensionResources.HotReloadSessionStarted));

return !s_shutdownProcess;
}

[SupportedOSPlatformGuard("android")]
[SupportedOSPlatformGuard("ios")]
[SupportedOSPlatformGuard("tvos")]
private static bool IsClearNotSupported()
=> RuntimeInformation.IsOSPlatform(OSPlatform.Create("ANDROID")) ||
RuntimeInformation.IsOSPlatform(OSPlatform.Create("IOS")) ||
RuntimeInformation.IsOSPlatform(OSPlatform.Create("TVOS"));
#endif
}
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,9 @@ public Task<ValidationResult> ValidateCommandLineOptionsAsync(ICommandLineOption
{
// We let the api to do the validity check before to go down the subscription path.
// If we don't fail here but we fail below means that the parent process is not there anymore and we can take it as exited.
#pragma warning disable CA1416 // Validate platform compatibility
_ = Process.GetProcessById(parentProcessPid);
#pragma warning restore CA1416
}
catch (ArgumentException ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ internal static async Task<bool> WaitAsync(this CountdownEvent countdownEvent, u
// executeOnlyOnce set to true to indicate that the thread will no longer wait on the waitObject
// parameter after the delegate has been called;
// false to indicate that the timer is reset every time the wait operation completes until the wait is unregistered.
#pragma warning disable CA1416 // Validate platform compatibility
registeredHandle = ThreadPool.RegisterWaitForSingleObject(
waitObject: countdownEvent.WaitHandle,
callBack: (state, timedOut) => ((TaskCompletionSource<bool>)state!).TrySetResult(!timedOut),
state: tcs,
millisecondsTimeOutInterval: millisecondsTimeOutInterval,
executeOnlyOnce: true);
#pragma warning restore CA1416
#pragma warning restore SA1115 // Parameter should follow comma

// Register the cancellation callback
Expand All @@ -45,7 +47,9 @@ internal static async Task<bool> WaitAsync(this CountdownEvent countdownEvent, u
// If the callback method executes because the WaitHandle is
// signaled, stop future execution of the callback method
// by unregistering the WaitHandle.
#pragma warning disable CA1416 // Validate platform compatibility
registeredHandle?.Unregister(null);
#pragma warning restore CA1416
await DisposeHelper.DisposeAsync(tokenRegistration);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ private void SubscribeToParentProcess()

try
{
#pragma warning disable CA1416 // Validate platform compatibility
_parentProcess = Process.GetProcessById(int.Parse(pid[0], CultureInfo.InvariantCulture));
_parentProcess.EnableRaisingEvents = true;
_parentProcess.Exited += ParentProcess_Exited;
#pragma warning restore CA1416
}
catch (ArgumentException)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,36 @@ namespace Microsoft.Testing.Platform.Helpers;
/// </summary>
internal interface IConsole
{
[UnsupportedOSPlatform("android")]
[UnsupportedOSPlatform("ios")]
[UnsupportedOSPlatform("tvos")]
[UnsupportedOSPlatform("browser")]
event ConsoleCancelEventHandler? CancelKeyPress;

[UnsupportedOSPlatform("android")]
[UnsupportedOSPlatform("browser")]
[UnsupportedOSPlatform("ios")]
[UnsupportedOSPlatform("tvos")]
public int BufferHeight { get; }

[UnsupportedOSPlatform("android")]
[UnsupportedOSPlatform("browser")]
[UnsupportedOSPlatform("ios")]
[UnsupportedOSPlatform("tvos")]
public int BufferWidth { get; }

public bool IsOutputRedirected { get; }

[UnsupportedOSPlatform("android")]
[UnsupportedOSPlatform("ios")]
[UnsupportedOSPlatform("tvos")]
[UnsupportedOSPlatform("browser")]
void SetForegroundColor(ConsoleColor color);

[UnsupportedOSPlatform("android")]
[UnsupportedOSPlatform("ios")]
[UnsupportedOSPlatform("tvos")]
[UnsupportedOSPlatform("browser")]
ConsoleColor GetForegroundColor();

void WriteLine();
Expand All @@ -28,5 +48,8 @@ internal interface IConsole

void Write(char value);

[UnsupportedOSPlatform("android")]
[UnsupportedOSPlatform("ios")]
[UnsupportedOSPlatform("tvos")]
void Clear();
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,19 @@ internal sealed class SystemConsole : IConsole
/// <summary>
/// Gets the height of the buffer area.
/// </summary>
[UnsupportedOSPlatform("android")]
[UnsupportedOSPlatform("browser")]
[UnsupportedOSPlatform("ios")]
[UnsupportedOSPlatform("tvos")]
public int BufferHeight => Console.BufferHeight;

/// <summary>
/// Gets the width of the buffer area.
/// </summary>
[UnsupportedOSPlatform("android")]
[UnsupportedOSPlatform("browser")]
[UnsupportedOSPlatform("ios")]
[UnsupportedOSPlatform("tvos")]
public int BufferWidth => Console.BufferWidth;

/// <summary>
Expand All @@ -43,35 +51,14 @@ static SystemConsole()
};
}

// This is based on the UnsupportedOSPlatformAttribute on the API:
// https://github.com/dotnet/runtime/blob/8a79637e1454c751c24a984b7fb8af4c4d43394b/src/libraries/System.Console/src/System/Console.cs#L560-L563
private static bool IsCancelKeyPressNotSupported()
=> RuntimeInformation.IsOSPlatform(OSPlatform.Create("ANDROID")) ||
RuntimeInformation.IsOSPlatform(OSPlatform.Create("IOS")) ||
RuntimeInformation.IsOSPlatform(OSPlatform.Create("TVOS")) ||
RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER"));

[UnsupportedOSPlatform("android")]
[UnsupportedOSPlatform("ios")]
[UnsupportedOSPlatform("tvos")]
[UnsupportedOSPlatform("browser")]
public event ConsoleCancelEventHandler? CancelKeyPress
{
add
{
if (IsCancelKeyPressNotSupported())
{
return;
}

Console.CancelKeyPress += value;
}

remove
{
if (IsCancelKeyPressNotSupported())
{
return;
}

Console.CancelKeyPress -= value;
}
add => Console.CancelKeyPress += value;
remove => Console.CancelKeyPress -= value;
}

public void SuppressOutput() => _suppressOutput = true;
Expand Down Expand Up @@ -108,33 +95,23 @@ public void Write(char value)
}
}

[UnsupportedOSPlatform("android")]
[UnsupportedOSPlatform("ios")]
[UnsupportedOSPlatform("tvos")]
[UnsupportedOSPlatform("browser")]
public void SetForegroundColor(ConsoleColor color)
{
#if NET8_0_OR_GREATER
if (RuntimeInformation.RuntimeIdentifier.Contains("ios") ||
RuntimeInformation.RuntimeIdentifier.Contains("android"))
{
return;
}
#endif
#pragma warning disable IDE0022 // Use expression body for method
Console.ForegroundColor = color;
#pragma warning restore IDE0022 // Use expression body for method
}
=> Console.ForegroundColor = color;

[UnsupportedOSPlatform("android")]
[UnsupportedOSPlatform("ios")]
[UnsupportedOSPlatform("tvos")]
[UnsupportedOSPlatform("browser")]
public ConsoleColor GetForegroundColor()
{
#if NET8_0_OR_GREATER
if (RuntimeInformation.RuntimeIdentifier.Contains("ios") ||
RuntimeInformation.RuntimeIdentifier.Contains("android"))
{
return ConsoleColor.Black;
}
#endif
#pragma warning disable IDE0022 // Use expression body for method
return Console.ForegroundColor;
#pragma warning restore IDE0022 // Use expression body for method
}
=> Console.ForegroundColor;

public void Clear() => Console.Clear();
[UnsupportedOSPlatform("android")]
[UnsupportedOSPlatform("ios")]
[UnsupportedOSPlatform("tvos")]
public void Clear()
=> Console.Clear();
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ internal sealed class SystemMainModule(ProcessModule? processModule) : IMainModu
{
private readonly ProcessModule? _processModule = processModule;

#pragma warning disable CA1416 // Validate platform compatibility
public string? FileName => _processModule?.FileName;
#pragma warning restore CA1416
}
#else
internal sealed class SystemMainModule : IMainModule
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ internal sealed class SystemProcess : IProcess, IDisposable
{
private readonly Process _process;

#pragma warning disable CA1416 // Validate platform compatibility
public SystemProcess(Process process)
{
_process = process;
Expand Down Expand Up @@ -51,4 +52,5 @@ public void Kill()
#endif

public void Dispose() => _process.Dispose();
#pragma warning restore CA1416
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace Microsoft.Testing.Platform.Helpers;
[SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "This is the Process wrapper.")]
internal sealed class SystemProcessHandler : IProcessHandler
{
#pragma warning disable CA1416 // Validate platform compatibility
public IProcess GetCurrentProcess() => new SystemProcess(Process.GetCurrentProcess());

public IProcess GetProcessById(int pid) => new SystemProcess(Process.GetProcessById(pid));
Expand All @@ -21,4 +22,5 @@ public IProcess Start(ProcessStartInfo startInfo)
process.EnableRaisingEvents = true;
return new SystemProcess(process);
}
#pragma warning restore CA1416
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ public Task RunLongRunning(Func<Task> action, string name, CancellationToken can
Name = name,
};

#pragma warning disable CA1416 // Validate platform compatibility
thread.Start();
#pragma warning restore CA1416

return taskCompletionSource.Task;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ protected override async Task<int> InternalRunAsync()
#else
string arguments = string.Join(" ", partialCommandLine);
#endif

#pragma warning disable CA1416 // Validate platform compatibility
ProcessStartInfo processStartInfo = new(
executableInfo.FilePath,
arguments)
Expand All @@ -122,6 +124,7 @@ protected override async Task<int> InternalRunAsync()
UseShellExecute = false,
#endif
};
#pragma warning restore CA1416

List<IDataConsumer> dataConsumersBuilder = [.. _testHostsInformation.DataConsumer];

Expand Down Expand Up @@ -209,7 +212,9 @@ protected override async Task<int> InternalRunAsync()

foreach (EnvironmentVariable envVar in environmentVariables.GetAll())
{
#pragma warning disable CA1416 // Validate platform compatibility
processStartInfo.EnvironmentVariables[envVar.Variable] = envVar.Value;
#pragma warning restore CA1416
}
}

Expand All @@ -224,9 +229,13 @@ protected override async Task<int> InternalRunAsync()

// Launch the test host process
string testHostProcessStartupTime = _clock.UtcNow.ToString("HH:mm:ss.fff", CultureInfo.InvariantCulture);
#pragma warning disable CA1416 // Validate platform compatibility
processStartInfo.EnvironmentVariables.Add($"{EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_TESTHOSTPROCESSSTARTTIME}_{currentPID}", testHostProcessStartupTime);
#pragma warning restore CA1416
await _logger.LogDebugAsync($"{EnvironmentVariableConstants.TESTINGPLATFORM_TESTHOSTCONTROLLER_TESTHOSTPROCESSSTARTTIME}_{currentPID} '{testHostProcessStartupTime}'");
#pragma warning disable CA1416 // Validate platform compatibility
await _logger.LogDebugAsync($"Starting test host process '{processStartInfo.FileName}' with args '{processStartInfo.Arguments}'");
#pragma warning restore CA1416
using IProcess testHostProcess = process.Start(processStartInfo);

int? testHostProcessId = null;
Expand Down Expand Up @@ -266,7 +275,9 @@ protected override async Task<int> InternalRunAsync()
// Wait for the test host controller to send the PID of the test host process
using (CancellationTokenSource timeout = new(TimeoutHelper.DefaultHangTimeSpanTimeout))
{
#pragma warning disable CA1416 // Validate platform compatibility
_waitForPid.Wait(timeout.Token);
#pragma warning restore CA1416
}

await _logger.LogDebugAsync("Fire OnTestHostProcessStartedAsync");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

namespace Microsoft.Testing.Platform.IPC;

#pragma warning disable CA1416 // Validate platform compatibility
internal sealed class NamedPipeClient : NamedPipeBase, IClient
{
private readonly NamedPipeClientStream _namedPipeClientStream;
Expand Down
Loading