using System.CommandLine; using ZB.MOM.WW.ScadaBridge.CLI.Commands; namespace ZB.MOM.WW.ScadaBridge.CLI.Tests.Commands; /// /// #54: template script add/update must expose --min-time-between-runs /// (a duration with ms/s/min units) and --execution-timeout-seconds (an int) /// so the per-script throttle/re-fire interval and the execution-timeout override — /// previously settable only via Transport bundle import — are CLI-authorable. These /// tests pin the option surface and the duration-parsing semantics of /// . /// public class TemplateScriptTimingTests { 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 ScriptGroup() => TemplateCommands.Build(Url, Format, Username, Password) .Subcommands.Single(c => c.Name == "script"); // ---- option surface ---- [Fact] public void ScriptAdd_HasTimingOptions() { var add = ScriptGroup().Subcommands.Single(c => c.Name == "add"); var names = add.Options.Select(o => o.Name).ToArray(); Assert.Contains("--min-time-between-runs", names); Assert.Contains("--execution-timeout-seconds", names); } [Fact] public void ScriptUpdate_HasTimingOptions() { var update = ScriptGroup().Subcommands.Single(c => c.Name == "update"); var names = update.Options.Select(o => o.Name).ToArray(); Assert.Contains("--min-time-between-runs", names); Assert.Contains("--execution-timeout-seconds", names); } // ---- --min-time-between-runs parsing ---- [Fact] public void MinTime_Absent_IsUnsetNoError() { Assert.True(TemplateCommands.TryParseMinTimeBetweenRuns(null, out var d, out var err)); Assert.Null(d); Assert.Null(err); } [Fact] public void MinTime_Blank_IsUnsetNoError() { Assert.True(TemplateCommands.TryParseMinTimeBetweenRuns(" ", out var d, out var err)); Assert.Null(d); Assert.Null(err); } [Theory] [InlineData("500ms", 500)] [InlineData("250MS", 250)] public void MinTime_Milliseconds_Parsed(string value, int expectedMs) { Assert.True(TemplateCommands.TryParseMinTimeBetweenRuns(value, out var d, out var err)); Assert.Null(err); Assert.Equal(TimeSpan.FromMilliseconds(expectedMs), d); } [Theory] [InlineData("5")] // bare number → seconds [InlineData("5s")] [InlineData("5sec")] [InlineData("5SEC")] public void MinTime_Seconds_BareDefaultsToSeconds(string value) { Assert.True(TemplateCommands.TryParseMinTimeBetweenRuns(value, out var d, out var err)); Assert.Null(err); Assert.Equal(TimeSpan.FromSeconds(5), d); } [Theory] [InlineData("2m")] [InlineData("2min")] [InlineData("2MIN")] public void MinTime_Minutes_Parsed(string value) { Assert.True(TemplateCommands.TryParseMinTimeBetweenRuns(value, out var d, out var err)); Assert.Null(err); Assert.Equal(TimeSpan.FromMinutes(2), d); } [Theory] [InlineData("0")] [InlineData("0s")] [InlineData("0min")] public void MinTime_Zero_IsUnset(string value) { // 0 means "no throttle" → null, mirroring DurationInput.Compose's non-positive handling. Assert.True(TemplateCommands.TryParseMinTimeBetweenRuns(value, out var d, out var err)); Assert.Null(err); Assert.Null(d); } [Theory] [InlineData("abc")] [InlineData("5h")] // hours not supported [InlineData("5days")] [InlineData("-3")] [InlineData("1.5s")] // non-integer public void MinTime_Invalid_ReturnsError(string value) { Assert.False(TemplateCommands.TryParseMinTimeBetweenRuns(value, out var d, out var err)); Assert.Null(d); Assert.NotNull(err); } }