using ClaudeDo.Installer.Checks; using ClaudeDo.Installer.Core; namespace ClaudeDo.Installer.Tests.Checks; public sealed class ClaudeAuthCheckTests : IDisposable { private readonly string _dir; public ClaudeAuthCheckTests() { _dir = Path.Combine(Path.GetTempPath(), $"cdclaudeauth_{Guid.NewGuid():N}"); Directory.CreateDirectory(_dir); File.WriteAllText(Path.Combine(_dir, "claude.exe"), ""); } public void Dispose() { try { Directory.Delete(_dir, recursive: true); } catch { } } private ClaudeCliLookup MakeLookup(FakeProcessRunner runner) => new(runner, pathOverride: _dir, pathExtOverride: ".exe"); [Fact] public async Task Logged_in_reports_ok_without_sending_a_prompt() { var runner = new FakeProcessRunner( (0, "2.1.230 (Claude Code)"), (0, "{\"loggedIn\":true,\"authMethod\":\"claude.ai\"}")); var check = new ClaudeAuthCheck(MakeLookup(runner)); var result = await check.RunAsync(new InstallContext(), CancellationToken.None); Assert.Equal(CheckStatus.Ok, result.Status); Assert.All(runner.Calls, call => Assert.DoesNotContain("-p ", call.Arguments)); Assert.Contains(runner.Calls, call => call.Arguments.Contains("auth") && call.Arguments.Contains("status")); } [Fact] public async Task Logged_out_reports_failed() { var runner = new FakeProcessRunner( (0, "2.1.230 (Claude Code)"), (0, "{\"loggedIn\":false}")); var check = new ClaudeAuthCheck(MakeLookup(runner)); var result = await check.RunAsync(new InstallContext(), CancellationToken.None); Assert.Equal(CheckStatus.Failed, result.Status); Assert.NotNull(result.HintKey); } [Fact] public async Task Unparseable_output_reports_unknown_not_failed() { var runner = new FakeProcessRunner( (0, "2.1.230 (Claude Code)"), (0, "not json")); var check = new ClaudeAuthCheck(MakeLookup(runner)); var result = await check.RunAsync(new InstallContext(), CancellationToken.None); Assert.Equal(CheckStatus.Unknown, result.Status); } [Fact] public async Task Cli_missing_reports_unknown() { var emptyDir = Path.Combine(Path.GetTempPath(), $"cdclaudeauth_empty_{Guid.NewGuid():N}"); Directory.CreateDirectory(emptyDir); try { var runner = new FakeProcessRunner(); var check = new ClaudeAuthCheck(new ClaudeCliLookup(runner, pathOverride: emptyDir, pathExtOverride: ".exe")); var ctx = new InstallContext { ClaudeBin = "claudedo_totally_missing_cmd_9f3a1" }; var result = await check.RunAsync(ctx, CancellationToken.None); Assert.Equal(CheckStatus.Unknown, result.Status); Assert.Empty(runner.Calls); } finally { Directory.Delete(emptyDir, recursive: true); } } }