using System.Diagnostics; using System.Text.Json; using System.Runtime.CompilerServices; using Xunit; namespace DevTool.Tests; public sealed class DevShellScriptTests { [Theory] [InlineData("pwsh")] [InlineData("bash")] [InlineData("zsh")] [InlineData("cmd")] public async Task DevShellExport_ReturnsSuccess_ForSupportedShells(string shell) { var python = ResolvePython(); var result = await RunAsync( python, ["scripts/dev_shell.py", "export", "--shell", shell, "--json"]); Assert.Equal(0, result.ExitCode); using var doc = JsonDocument.Parse(result.StdOut); Assert.True(doc.RootElement.TryGetProperty("projectRoot", out _)); Assert.True(doc.RootElement.TryGetProperty("env", out _)); } [Fact] public async Task DevShellExport_InvalidShell_ReturnsExitCode3() { var python = ResolvePython(); var result = await RunAsync( python, ["scripts/dev_shell.py", "export", "--shell", "fish"]); Assert.Equal(3, result.ExitCode); } [Fact] public async Task DevShellDoctor_ReturnsJson() { var python = ResolvePython(); var result = await RunAsync( python, ["scripts/dev_shell.py", "doctor"]); Assert.Equal(0, result.ExitCode); using var doc = JsonDocument.Parse(result.StdOut); Assert.True(doc.RootElement.TryGetProperty("repo_root", out _)); } private static string ResolvePython() { var candidates = OperatingSystem.IsWindows() ? new[] { "python", "py" } : new[] { "python3", "python" }; foreach (var candidate in candidates) { try { using var process = new Process { StartInfo = new ProcessStartInfo { FileName = candidate, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true, } }; process.StartInfo.ArgumentList.Add("--version"); process.Start(); process.WaitForExit(2000); if (process.ExitCode == 0) return candidate; } catch { } } throw new InvalidOperationException("Python executable not found."); } private static async Task<(int ExitCode, string StdOut, string StdErr)> RunAsync(string command, IReadOnlyList args) { var psi = new ProcessStartInfo { FileName = command, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true, WorkingDirectory = RepoRoot(), }; foreach (var arg in args) psi.ArgumentList.Add(arg); using var process = new Process { StartInfo = psi }; process.Start(); var stdout = await process.StandardOutput.ReadToEndAsync(); var stderr = await process.StandardError.ReadToEndAsync(); await process.WaitForExitAsync(); return (process.ExitCode, stdout, stderr); } private static string RepoRoot([CallerFilePath] string file = "") { var repoRoot = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(file)!, "..", "..")); if (!File.Exists(Path.Combine(repoRoot, "scripts", "dev_shell.py"))) throw new InvalidOperationException("Could not locate repo root."); return repoRoot; } }