using System.CommandLine; using ScadaLink.CLI.Commands; using ScadaLink.Commons.Messages.Management; namespace ScadaLink.CLI.Tests.Commands; /// /// Tests for the scadalink notification smtp update subcommand. The command /// gained two optional flags — --tls-mode and --credentials — that plumb /// through to . These tests pin that the flags /// parse, are genuinely optional (non-breaking), and that --tls-mode rejects /// values outside the canonical {None, StartTLS, SSL} set. /// public class SmtpUpdateCommandTests { private static readonly Option Url = new("--url") { Recursive = true }; private static readonly Option Username = new("--username") { Recursive = true }; private static readonly Option Password = new("--password") { Recursive = true }; private static readonly Option Format = CliOptions.CreateFormatOption(); private static Command SmtpUpdateCommand() { var notification = NotificationCommands.Build(Url, Format, Username, Password); var smtp = notification.Subcommands.Single(c => c.Name == "smtp"); return smtp.Subcommands.Single(c => c.Name == "update"); } private static ParseResult ParseUpdate(params string[] args) => SmtpUpdateCommand().Parse(args); [Fact] public void Update_WithTlsModeAndCredentials_ProducesCommandCarryingThem() { var parse = ParseUpdate( "--id", "1", "--server", "smtp.example.com", "--port", "587", "--auth-mode", "Basic", "--from-address", "noreply@example.com", "--tls-mode", "None", "--credentials", "user:pass"); Assert.Empty(parse.Errors); var cmd = NotificationCommands.BuildUpdateSmtpConfigCommand(parse); Assert.Equal(1, cmd.SmtpConfigId); Assert.Equal("smtp.example.com", cmd.Server); Assert.Equal(587, cmd.Port); Assert.Equal("Basic", cmd.AuthMode); Assert.Equal("noreply@example.com", cmd.FromAddress); Assert.Equal("None", cmd.TlsMode); Assert.Equal("user:pass", cmd.Credentials); } [Fact] public void Update_WithoutTlsModeAndCredentials_ProducesCommandWithNulls() { var parse = ParseUpdate( "--id", "2", "--server", "smtp.example.com", "--port", "25", "--auth-mode", "OAuth2", "--from-address", "noreply@example.com"); Assert.Empty(parse.Errors); var cmd = NotificationCommands.BuildUpdateSmtpConfigCommand(parse); Assert.Equal(2, cmd.SmtpConfigId); Assert.Null(cmd.TlsMode); Assert.Null(cmd.Credentials); } [Theory] [InlineData("None")] [InlineData("StartTLS")] [InlineData("SSL")] public void Update_TlsModeOption_AcceptsCanonicalValues(string value) { var parse = ParseUpdate( "--id", "1", "--server", "smtp.example.com", "--port", "587", "--auth-mode", "Basic", "--from-address", "noreply@example.com", "--tls-mode", value); Assert.Empty(parse.Errors); } [Theory] [InlineData("Bogus")] [InlineData("tls")] [InlineData("none")] // AcceptOnlyFromAmong is case-sensitive: constrain to canonical spelling public void Update_TlsModeOption_RejectsValuesOutsideCanonicalSet(string value) { var parse = ParseUpdate( "--id", "1", "--server", "smtp.example.com", "--port", "587", "--auth-mode", "Basic", "--from-address", "noreply@example.com", "--tls-mode", value); Assert.NotEmpty(parse.Errors); } [Fact] public void Update_TlsModeAndCredentials_AreNotRequired() { var update = SmtpUpdateCommand(); var tls = update.Options.Single(o => o.Name == "--tls-mode"); var creds = update.Options.Single(o => o.Name == "--credentials"); Assert.False(tls.Required, "--tls-mode must be optional (preserve-if-omitted)."); Assert.False(creds.Required, "--credentials must be optional (preserve-if-omitted)."); } }