370 lines
12 KiB
C#
370 lines
12 KiB
C#
using MBN_STOCK_WEBVIEW.PlayoutSmoke;
|
|
|
|
namespace MBN_STOCK_WEBVIEW.Playout.Tests;
|
|
|
|
public sealed class SmokeCommandLineTests
|
|
{
|
|
[Theory]
|
|
[InlineData("Tornado2 TEST", false)]
|
|
[InlineData("TEST-1", false)]
|
|
[InlineData("Tornado2", true)]
|
|
[InlineData("PGM", true)]
|
|
[InlineData("CONTEST", true)]
|
|
[InlineData("", true)]
|
|
[InlineData(null, true)]
|
|
public void TornadoWindowTitleWithoutExplicitTestMarkerIsUnsafe(
|
|
string? title,
|
|
bool expected)
|
|
{
|
|
Assert.Equal(expected, SmokeCommandLine.IsUnsafeTornadoWindowTitle(title));
|
|
}
|
|
|
|
[Fact]
|
|
public void Parse_NoArguments_PreservesReadOnlyProbeDefault()
|
|
{
|
|
var parsed = SmokeCommandLine.Parse([]);
|
|
|
|
Assert.True(parsed.IsValid);
|
|
Assert.Equal(SmokeCommandKind.Probe, parsed.Invocation.Kind);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("--probe", "Probe")]
|
|
[InlineData("--PROBE", "Probe")]
|
|
[InlineData("--dry-run", "DryRun")]
|
|
public void Parse_ExistingComFreeCommandsRemainAvailable(
|
|
string argument,
|
|
string expected)
|
|
{
|
|
var parsed = SmokeCommandLine.Parse([argument]);
|
|
|
|
Assert.True(parsed.IsValid);
|
|
Assert.Equal(expected, parsed.Invocation.Kind.ToString());
|
|
}
|
|
|
|
[Fact]
|
|
public void Parse_TestConnectRequiresExplicitAcknowledgementAndConfigArgument()
|
|
{
|
|
var withoutAcknowledgement = SmokeCommandLine.Parse(
|
|
["--test-connect", "--config", "C:\\safe\\playout.local.json"]);
|
|
var complete = SmokeCommandLine.Parse(
|
|
[
|
|
"--test-connect",
|
|
SmokeCommandLine.AcknowledgementFlag,
|
|
"--config",
|
|
"C:\\safe\\playout.local.json"
|
|
]);
|
|
|
|
Assert.False(withoutAcknowledgement.IsValid);
|
|
Assert.Equal("missing-acknowledgement", withoutAcknowledgement.ErrorCode);
|
|
Assert.True(complete.IsValid);
|
|
Assert.Equal(SmokeCommandKind.TestConnect, complete.Invocation.Kind);
|
|
}
|
|
|
|
[Fact]
|
|
public void Parse_TestSequenceRequiresBothSceneCodesAndBoundedObservation()
|
|
{
|
|
var missingObservation = SmokeCommandLine.Parse(
|
|
[
|
|
"--test-sequence",
|
|
SmokeCommandLine.AcknowledgementFlag,
|
|
"--config",
|
|
"C:\\safe\\playout.local.json",
|
|
"--prepare",
|
|
"5001",
|
|
"--next",
|
|
"5006"
|
|
]);
|
|
var complete = SmokeCommandLine.Parse(
|
|
[
|
|
"--test-sequence",
|
|
"--prepare",
|
|
"5001",
|
|
"--observe-ms",
|
|
"1000",
|
|
SmokeCommandLine.AcknowledgementFlag,
|
|
"--next",
|
|
"5006",
|
|
"--config",
|
|
"C:\\safe\\playout.local.json"
|
|
]);
|
|
|
|
Assert.False(missingObservation.IsValid);
|
|
Assert.Equal("missing-required-option", missingObservation.ErrorCode);
|
|
Assert.True(complete.IsValid);
|
|
Assert.Equal(1000, complete.Invocation.ObservationMilliseconds);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("999")]
|
|
[InlineData("30001")]
|
|
[InlineData("1.5")]
|
|
[InlineData("secret")]
|
|
public void Parse_RejectsUnboundedOrNonIntegralObservation(string value)
|
|
{
|
|
var parsed = ValidSequenceArguments(observation: value);
|
|
|
|
Assert.False(parsed.IsValid);
|
|
Assert.Equal("invalid-observation-duration", parsed.ErrorCode);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("../5001")]
|
|
[InlineData("5001.t2s")]
|
|
[InlineData("장면")]
|
|
[InlineData("SCENE A")]
|
|
public void Parse_RejectsUnsafeSceneCodesWithoutReflectingThem(string sceneCode)
|
|
{
|
|
var parsed = ValidSequenceArguments(prepare: sceneCode);
|
|
|
|
Assert.False(parsed.IsValid);
|
|
Assert.Equal("unsafe-scene-code", parsed.ErrorCode);
|
|
Assert.DoesNotContain(sceneCode, parsed.ErrorCode, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
[Fact]
|
|
public void Parse_TestConnectRejectsMutationOptions()
|
|
{
|
|
var parsed = SmokeCommandLine.Parse(
|
|
[
|
|
"--test-connect",
|
|
SmokeCommandLine.AcknowledgementFlag,
|
|
"--config",
|
|
"C:\\safe\\playout.local.json",
|
|
"--prepare",
|
|
"5001"
|
|
]);
|
|
|
|
Assert.False(parsed.IsValid);
|
|
Assert.Equal("unknown-option", parsed.ErrorCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void Parse_TestSequenceRequiresTwoDistinctSceneCodes()
|
|
{
|
|
var parsed = SmokeCommandLine.Parse(
|
|
[
|
|
"--test-sequence",
|
|
SmokeCommandLine.AcknowledgementFlag,
|
|
"--config",
|
|
"C:\\safe\\playout.local.json",
|
|
"--prepare",
|
|
"5001",
|
|
"--next",
|
|
"5001",
|
|
"--observe-ms",
|
|
"1000"
|
|
]);
|
|
|
|
Assert.False(parsed.IsValid);
|
|
Assert.Equal("duplicate-scene-code", parsed.ErrorCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void Parse_TestPlanUsesTheSameSequenceInputsButNeverImpliesExecution()
|
|
{
|
|
var parsed = SmokeCommandLine.Parse(
|
|
[
|
|
"--test-plan",
|
|
SmokeCommandLine.AcknowledgementFlag,
|
|
"--config",
|
|
"C:\\safe\\playout.local.json",
|
|
"--prepare",
|
|
"5001",
|
|
"--next",
|
|
"5006",
|
|
"--observe-ms",
|
|
"5000"
|
|
]);
|
|
|
|
Assert.True(parsed.IsValid);
|
|
Assert.Equal(SmokeCommandKind.TestPlan, parsed.Invocation.Kind);
|
|
}
|
|
|
|
[Fact]
|
|
public void Parse_PgmConnectDiagnosticRequiresDistinctAcknowledgementAndExactInputs()
|
|
{
|
|
string[] complete =
|
|
[
|
|
"--pgm-connect-diagnostic",
|
|
SmokeCommandLine.PgmConnectAcknowledgementFlag,
|
|
"--host",
|
|
"127.0.0.1",
|
|
"--port",
|
|
"30001",
|
|
"--expected-pgm-window-title",
|
|
"PGM"
|
|
];
|
|
var missingAcknowledgement = SmokeCommandLine.Parse(complete[0..1]
|
|
.Concat(complete[2..])
|
|
.ToArray());
|
|
var wrongAcknowledgement = SmokeCommandLine.Parse(
|
|
complete.Select(value => value == SmokeCommandLine.PgmConnectAcknowledgementFlag
|
|
? SmokeCommandLine.AcknowledgementFlag
|
|
: value).ToArray());
|
|
var parsed = SmokeCommandLine.Parse(complete);
|
|
|
|
Assert.False(missingAcknowledgement.IsValid);
|
|
Assert.Equal("missing-acknowledgement", missingAcknowledgement.ErrorCode);
|
|
Assert.False(wrongAcknowledgement.IsValid);
|
|
Assert.Equal("unknown-option", wrongAcknowledgement.ErrorCode);
|
|
Assert.True(parsed.IsValid);
|
|
Assert.Equal(SmokeCommandKind.PgmConnectDiagnostic, parsed.Invocation.Kind);
|
|
Assert.Equal("127.0.0.1", parsed.Invocation.Host);
|
|
Assert.Equal(30001, parsed.Invocation.Port);
|
|
Assert.Equal("PGM", parsed.Invocation.ExpectedPgmWindowTitle);
|
|
Assert.Null(parsed.Invocation.ConfigPath);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("--config")]
|
|
[InlineData("--prepare")]
|
|
[InlineData("--next")]
|
|
[InlineData("--observe-ms")]
|
|
public void Parse_PgmConnectDiagnosticRejectsEveryConfigOrRenderOption(string option)
|
|
{
|
|
var parsed = SmokeCommandLine.Parse(
|
|
[
|
|
"--pgm-connect-diagnostic",
|
|
SmokeCommandLine.PgmConnectAcknowledgementFlag,
|
|
"--host",
|
|
"127.0.0.1",
|
|
"--port",
|
|
"30001",
|
|
"--expected-pgm-window-title",
|
|
"PGM",
|
|
option,
|
|
"5001"
|
|
]);
|
|
|
|
Assert.False(parsed.IsValid);
|
|
Assert.Equal("unknown-option", parsed.ErrorCode);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("0")]
|
|
[InlineData("65536")]
|
|
[InlineData("secret")]
|
|
public void Parse_PgmConnectDiagnosticRejectsInvalidPort(string port)
|
|
{
|
|
var parsed = SmokeCommandLine.Parse(
|
|
[
|
|
"--pgm-connect-diagnostic",
|
|
SmokeCommandLine.PgmConnectAcknowledgementFlag,
|
|
"--host",
|
|
"127.0.0.1",
|
|
"--port",
|
|
port,
|
|
"--expected-pgm-window-title",
|
|
"PGM"
|
|
]);
|
|
|
|
Assert.False(parsed.IsValid);
|
|
Assert.Equal("invalid-port", parsed.ErrorCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void Parse_PgmCutsSequenceRequiresItsOwnLongAcknowledgementAndFixedInputs()
|
|
{
|
|
var complete = ValidPgmCutsArguments();
|
|
var missingAcknowledgement = SmokeCommandLine.Parse(
|
|
complete.Where(value => value != SmokeCommandLine.PgmCutsSequenceAcknowledgementFlag)
|
|
.ToArray());
|
|
var wrongAcknowledgement = SmokeCommandLine.Parse(
|
|
complete.Select(value => value == SmokeCommandLine.PgmCutsSequenceAcknowledgementFlag
|
|
? SmokeCommandLine.AcknowledgementFlag
|
|
: value).ToArray());
|
|
var parsed = SmokeCommandLine.Parse(complete);
|
|
var explicitObservation = SmokeCommandLine.Parse(
|
|
complete.Concat(["--observe-ms", "5000"]).ToArray());
|
|
|
|
Assert.False(missingAcknowledgement.IsValid);
|
|
Assert.Equal("missing-acknowledgement", missingAcknowledgement.ErrorCode);
|
|
Assert.False(wrongAcknowledgement.IsValid);
|
|
Assert.Equal("unknown-option", wrongAcknowledgement.ErrorCode);
|
|
Assert.True(parsed.IsValid);
|
|
Assert.True(explicitObservation.IsValid);
|
|
Assert.Equal(SmokeCommandKind.PgmCutsSequence, parsed.Invocation.Kind);
|
|
Assert.Equal(5_000, parsed.Invocation.ObservationMilliseconds);
|
|
Assert.Equal("C:\\Cuts", parsed.Invocation.SceneRoot);
|
|
Assert.Null(parsed.Invocation.ConfigPath);
|
|
Assert.Null(parsed.Invocation.PrepareSceneCode);
|
|
Assert.Null(parsed.Invocation.NextSceneCode);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("--config")]
|
|
[InlineData("--prepare")]
|
|
[InlineData("--next")]
|
|
public void Parse_PgmCutsSequenceRejectsConfigAndCallerSelectedScenes(string option)
|
|
{
|
|
var parsed = SmokeCommandLine.Parse(
|
|
ValidPgmCutsArguments().Concat([option, "sensitive-value"]).ToArray());
|
|
|
|
Assert.False(parsed.IsValid);
|
|
Assert.Equal("unknown-option", parsed.ErrorCode);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("4999")]
|
|
[InlineData("5001")]
|
|
[InlineData("secret")]
|
|
public void Parse_PgmCutsSequenceOnlyAcceptsExplicitFiveSecondObservation(string value)
|
|
{
|
|
var parsed = SmokeCommandLine.Parse(
|
|
ValidPgmCutsArguments().Concat(["--observe-ms", value]).ToArray());
|
|
|
|
Assert.False(parsed.IsValid);
|
|
Assert.Equal("invalid-observation-duration", parsed.ErrorCode);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("localhost", "C:\\Cuts")]
|
|
[InlineData("192.0.2.1", "C:\\Cuts")]
|
|
[InlineData("127.0.0.1", "relative-cuts")]
|
|
public void Parse_PgmCutsSequenceRequiresLiteralLoopbackAndAbsoluteSceneRoot(
|
|
string host,
|
|
string sceneRoot)
|
|
{
|
|
var arguments = ValidPgmCutsArguments();
|
|
arguments[Array.IndexOf(arguments, "127.0.0.1")] = host;
|
|
arguments[Array.IndexOf(arguments, "C:\\Cuts")] = sceneRoot;
|
|
|
|
var parsed = SmokeCommandLine.Parse(arguments);
|
|
|
|
Assert.False(parsed.IsValid);
|
|
Assert.Equal("missing-or-invalid-required-option", parsed.ErrorCode);
|
|
}
|
|
|
|
private static SmokeCommandParseResult ValidSequenceArguments(
|
|
string prepare = "5001",
|
|
string observation = "1000") =>
|
|
SmokeCommandLine.Parse(
|
|
[
|
|
"--test-sequence",
|
|
SmokeCommandLine.AcknowledgementFlag,
|
|
"--config",
|
|
"C:\\safe\\playout.local.json",
|
|
"--prepare",
|
|
prepare,
|
|
"--next",
|
|
"5006",
|
|
"--observe-ms",
|
|
observation
|
|
]);
|
|
|
|
private static string[] ValidPgmCutsArguments() =>
|
|
[
|
|
"--pgm-cuts-sequence",
|
|
SmokeCommandLine.PgmCutsSequenceAcknowledgementFlag,
|
|
"--host",
|
|
"127.0.0.1",
|
|
"--port",
|
|
"30001",
|
|
"--expected-pgm-window-title",
|
|
"Tornado2 PGM",
|
|
"--scene-root",
|
|
"C:\\Cuts"
|
|
];
|
|
}
|