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);
}
}