// Copyright (c) The Geekeey Authors // SPDX-License-Identifier: EUPL-1.2 using System.Diagnostics; namespace Geekeey.Arcade.NET.Tests.Shared; internal sealed record Command(string WorkingDirectory, IEnumerable> Environment) { public bool ThrowOnExit { get; init; } public static Command WithWorkingDirectory(string path) { return new Command(path, []); } public Command WithEnvironment(string name, string value) { return WithEnvironment([new KeyValuePair(name, value)]); } public Command WithEnvironment(IEnumerable> environment) { var env = new Dictionary(Environment); foreach (var pair in environment) { env[pair.Key] = pair.Value; } return this with { Environment = env }; } public Command WithThrowOnExit() { return this with { ThrowOnExit = true }; } public async Task RunAsync(string exe, params IReadOnlyList args) { ArgumentNullException.ThrowIfNull(args); var startInfo = new ProcessStartInfo(exe) { WorkingDirectory = WorkingDirectory, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; foreach (var argument in args) { startInfo.ArgumentList.Add(argument); } foreach (var pair in Environment) { startInfo.Environment[pair.Key] = pair.Value; } var process = Process.Start(startInfo) ?? throw new InvalidOperationException("Could not start dotnet."); var output = await process.StandardOutput.ReadToEndAsync(); var error = await process.StandardError.ReadToEndAsync(); await process.WaitForExitAsync(); _ = ThrowOnExit && process.ExitCode is not 0 ? throw new InvalidOperationException($"'{exe}' exited with code {process.ExitCode}.{System.Environment.NewLine}{error}{output}") : 0; return new CommandOutput(output, error, process.ExitCode); } }