using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Paca.Core.Platform;
using Xunit;
namespace Paca.Tests.Core;
///
/// Cycle 5: 극한 RED 시나리오 - 프로세스 실행 시 따옴표 감싸인 ExePath, Null 인자 방어 및 고속 취소 시 스트림 무결성 검증
///
public class ProcessExecutionExtremeRedTests
{
[Fact]
public async Task Cycle5_Gate1_DesktopProcessRunner_QuotedExePath_MustBeUnquotedAndExecute()
{
// Windows 에서 UseShellExecute=false 일 때 ExePath 에 따옴표가 있으면 Win32Exception 발생
// DesktopProcessRunner 는 따옴표를 자동 정제하여 정상 실행해야 함
var runner = new DesktopProcessRunner();
var cmdExe = Environment.GetEnvironmentVariable("ComSpec") ?? "cmd.exe";
var quotedCmd = $"\"{cmdExe}\"";
var spec = new ProcessSpec(quotedCmd, new[] { "/c", "echo", "PACA_DESKTOP_PROCESS_RUNNER_OK" });
var result = await runner.RunAsync(spec, null, CancellationToken.None);
Assert.Equal(0, result.ExitCode);
Assert.Contains("PACA_DESKTOP_PROCESS_RUNNER_OK", result.Stdout);
}
[Fact]
public async Task Cycle5_Gate2_DesktopProcessRunner_NullArgsInSpec_MustNotThrowArgumentNullException()
{
var runner = new DesktopProcessRunner();
var cmdExe = Environment.GetEnvironmentVariable("ComSpec") ?? "cmd.exe";
// 동적 인자 빌더 등에서 전달될 수 있는 null 원소 방어
var args = new string[] { "/c", "echo", null!, "NULL_ARG_DEFENSE_OK" };
var spec = new ProcessSpec(cmdExe, args);
var result = await runner.RunAsync(spec, null, CancellationToken.None);
Assert.Equal(0, result.ExitCode);
Assert.Contains("NULL_ARG_DEFENSE_OK", result.Stdout);
}
[Fact]
public async Task Cycle5_Gate3_DesktopProcessRunner_FastCancellation_MustKillTreeWithoutDisposedStreamFault()
{
var runner = new DesktopProcessRunner();
var cmdExe = Environment.GetEnvironmentVariable("ComSpec") ?? "cmd.exe";
// 10초간 대기하는 자식 프로세스
var spec = new ProcessSpec(cmdExe, new[] { "/c", "ping", "127.0.0.1", "-n", "10" });
using var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(50));
// 고속 취소 발생 시 ObjectDisposedException 이나 UnobservedTaskException 없이 OperationCanceledException 으로 종료
await Assert.ThrowsAnyAsync(async () =>
{
await runner.RunAsync(spec, null, cts.Token);
});
}
}