- tests/FakeClaude: eseguibile finto 'claude' configurabile con variabili d'ambiente (registro di argomenti/cwd/stdin, output, exit code, ritardo), con le prove FK-01…FK-05. - Test organizzati per livello (Gui/, Process/, Support/) e struttura descritta in TESTING.md. - MarkdownView: la parte sulle immagini passa in MarkdownView.Images.cs (partial), senza cambiare il comportamento. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
90 lines
3.2 KiB
C#
90 lines
3.2 KiB
C#
using System.Diagnostics;
|
|
using System.Text.Json;
|
|
|
|
namespace AgentWikiUi.Tests;
|
|
|
|
/// <summary>Il doppio di test di <c>claude</c> (docs/TESTING.md → FakeClaude, FK-01…FK-05).</summary>
|
|
[Trait("Category", "Process")]
|
|
public sealed class FakeClaudeTests : IDisposable
|
|
{
|
|
readonly string dir = Directory.CreateTempSubdirectory("awui-fake-").FullName;
|
|
|
|
public void Dispose() => Directory.Delete(dir, true);
|
|
|
|
string LogPath => Path.Combine(dir, "log.jsonl");
|
|
|
|
Process Start(IEnumerable<string> args, Dictionary<string, string>? env = null, string? cwd = null)
|
|
{
|
|
var psi = new ProcessStartInfo(FakeClaudePath.Exe)
|
|
{
|
|
UseShellExecute = false, RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true,
|
|
WorkingDirectory = cwd ?? dir,
|
|
};
|
|
foreach (var a in args) psi.ArgumentList.Add(a);
|
|
psi.Environment["FAKE_CLAUDE_LOG"] = LogPath;
|
|
foreach (var (k, v) in env ?? []) psi.Environment[k] = v;
|
|
return Process.Start(psi)!;
|
|
}
|
|
|
|
[Fact]
|
|
public void Registra_argomenti_cwd_e_stdin()
|
|
{
|
|
var cwd = Directory.CreateDirectory(Path.Combine(dir, "lavoro")).FullName;
|
|
using var p = Start(["-p", "dì \"ciao\" a tutti", "--model", "m"], cwd: cwd);
|
|
p.StandardInput.Write("dati da stdin");
|
|
p.StandardInput.Close();
|
|
Assert.True(p.WaitForExit(10_000));
|
|
|
|
using var line = JsonDocument.Parse(File.ReadAllLines(LogPath).Single());
|
|
var r = line.RootElement;
|
|
Assert.Equal(["-p", "dì \"ciao\" a tutti", "--model", "m"], r.GetProperty("args").EnumerateArray().Select(a => a.GetString()));
|
|
Assert.Equal(cwd, r.GetProperty("cwd").GetString());
|
|
Assert.Equal("dati da stdin", r.GetProperty("stdin").GetString());
|
|
}
|
|
|
|
[Fact]
|
|
public void Output_e_stderr_configurati()
|
|
{
|
|
using var p = Start([], new() { ["FAKE_CLAUDE_OUT"] = "risposta", ["FAKE_CLAUDE_ERR"] = "avviso" });
|
|
p.StandardInput.Close();
|
|
Assert.Equal("risposta", p.StandardOutput.ReadToEnd());
|
|
Assert.Equal("avviso", p.StandardError.ReadToEnd());
|
|
Assert.True(p.WaitForExit(10_000));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(null, 0)]
|
|
[InlineData("3", 3)]
|
|
[InlineData("127", 127)]
|
|
public void ExitCode_configurato(string? configured, int expected)
|
|
{
|
|
using var p = Start([], configured is null ? null : new() { ["FAKE_CLAUDE_EXIT"] = configured });
|
|
p.StandardInput.Close();
|
|
Assert.True(p.WaitForExit(10_000));
|
|
Assert.Equal(expected, p.ExitCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void Ritardo_configurato()
|
|
{
|
|
using var p = Start([], new() { ["FAKE_CLAUDE_DELAY_MS"] = "600" });
|
|
var sw = Stopwatch.StartNew();
|
|
p.StandardInput.Close();
|
|
Assert.True(p.WaitForExit(10_000));
|
|
Assert.True(sw.ElapsedMilliseconds >= 500, $"terminato dopo {sw.ElapsedMilliseconds} ms");
|
|
}
|
|
|
|
[Fact]
|
|
public void Attende_la_chiusura_di_stdin()
|
|
{
|
|
using var p = Start([]);
|
|
try
|
|
{
|
|
Assert.False(p.WaitForExit(700), "il processo è terminato con stdin ancora aperto");
|
|
p.StandardInput.Close();
|
|
Assert.True(p.WaitForExit(10_000));
|
|
}
|
|
finally { if (!p.HasExited) p.Kill(); }
|
|
}
|
|
}
|