namespace AcDream.Headless.Tests; public sealed class HeadlessEntryPointTests { [Theory] [InlineData("--help")] [InlineData("-h")] public void HelpIsPresentationFreeAndSuccessful(string argument) { using var output = new StringWriter(); using var error = new StringWriter(); int exitCode = HeadlessEntryPoint.Run( [argument], output, error); Assert.Equal(0, exitCode); Assert.Contains("acdream-headless", output.ToString()); Assert.Contains("Secrets are never accepted", output.ToString()); Assert.Equal(string.Empty, error.ToString()); } [Fact] public void ValidateAcceptsStrictEmptyNoConnectConfiguration() { using var file = TemporaryConfiguration.Create( """{"version":1,"sessions":[]}"""); using var output = new StringWriter(); using var error = new StringWriter(); int exitCode = HeadlessEntryPoint.Run( ["validate", "--config", file.Path], output, error); Assert.Equal(0, exitCode); Assert.Contains("0 session(s)", output.ToString()); Assert.Equal(string.Empty, error.ToString()); } [Theory] [InlineData("""{"version":2,"sessions":[]}""", "Unsupported configuration version")] [InlineData("""{"version":1,"sessions":[],"password":"secret"}""", "could not be mapped")] [InlineData("""{"version":1,"sessions":[{"id":"bot"},{"id":"bot"}]}""", "Duplicate session id")] [InlineData("""{"version":1,"sessions":[null]}""", "non-empty id")] [InlineData("""{"version":1}""", "required properties")] public void ValidateRejectsInvalidOrSecretShapedConfiguration( string json, string expectedError) { using var file = TemporaryConfiguration.Create(json); using var output = new StringWriter(); using var error = new StringWriter(); int exitCode = HeadlessEntryPoint.Run( ["validate", "--config", file.Path], output, error); Assert.Equal(3, exitCode); Assert.Contains( expectedError, error.ToString(), StringComparison.OrdinalIgnoreCase); Assert.DoesNotContain("secret", error.ToString()); Assert.Equal(string.Empty, output.ToString()); } [Fact] public void UnknownCommandReturnsUsageError() { using var output = new StringWriter(); using var error = new StringWriter(); int exitCode = HeadlessEntryPoint.Run( ["connect", "--password", "secret"], output, error); Assert.Equal(2, exitCode); Assert.DoesNotContain("secret", error.ToString()); Assert.Equal(string.Empty, output.ToString()); } private sealed class TemporaryConfiguration : IDisposable { private TemporaryConfiguration(string path) { Path = path; } internal string Path { get; } internal static TemporaryConfiguration Create(string json) { string path = System.IO.Path.Combine( System.IO.Path.GetTempPath(), $"acdream-headless-{Guid.NewGuid():N}.json"); File.WriteAllText(path, json); return new TemporaryConfiguration(path); } public void Dispose() { File.Delete(Path); } } }