feat: align legacy operator and playout behavior
This commit is contained in:
@@ -237,6 +237,38 @@ public sealed class CandleSceneBuilderTests
|
||||
value == item.ExpectedPrice);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(CandleMarketTarget.KospiIndex)]
|
||||
[InlineData(CandleMarketTarget.KosdaqIndex)]
|
||||
[InlineData(CandleMarketTarget.Kospi200Index)]
|
||||
[InlineData(CandleMarketTarget.Krx100Index)]
|
||||
[InlineData(CandleMarketTarget.FuturesIndex)]
|
||||
[InlineData(CandleMarketTarget.KospiIndustry)]
|
||||
[InlineData(CandleMarketTarget.KosdaqIndustry)]
|
||||
[InlineData(CandleMarketTarget.OverseasIndex)]
|
||||
public void IndexAndIndustryTargetsForceMovingAveragePathsAndGuideOff(
|
||||
CandleMarketTarget target)
|
||||
{
|
||||
var data = new S8010SceneData(
|
||||
CandleCutAlias.Cut8061,
|
||||
target,
|
||||
CandleChartMode.Price,
|
||||
"Target",
|
||||
new CandleQuoteData(100, 0, 0, ScenePriceDirection.Flat),
|
||||
[Row(1, 100, 110, 90, 100, 10, 101, 102)],
|
||||
ShowMovingAverage5: true,
|
||||
ShowMovingAverage20: true);
|
||||
|
||||
var mutations = new S8010SceneMutationBuilder().Build(data);
|
||||
|
||||
Assert.Empty(mutations.OfType<PlayoutSetPathPoints>()
|
||||
.Last(path => path.ObjectName == "ma5").Points);
|
||||
Assert.Empty(mutations.OfType<PlayoutSetPathPoints>()
|
||||
.Last(path => path.ObjectName == "ma20").Points);
|
||||
Assert.False(mutations.OfType<PlayoutSetVisible>()
|
||||
.Last(visible => visible.ObjectName == "guide").IsVisible);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Equal_range_zero_volume_and_single_partial_path_are_finite()
|
||||
{
|
||||
|
||||
@@ -46,6 +46,159 @@ public sealed class LegacyPlayoutWorkflowTests
|
||||
], provider.Calls);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task S8010SamplesCurrentMovingAveragesForPrepareTakeInRefreshAndNext()
|
||||
{
|
||||
var engine = new RecordingEngine();
|
||||
var provider = new RecordingProvider(new Dictionary<string, (int, ScenePageSize?)>
|
||||
{
|
||||
["8051"] = (1, null),
|
||||
["8040"] = (1, null)
|
||||
});
|
||||
var source = new MutableLegacySceneMovingAverageSelectionSource(
|
||||
new LegacySceneMovingAverageSelection(false, false));
|
||||
var workflow = new LegacyPlayoutWorkflow(engine, provider);
|
||||
LegacyPlaylistEntry[] playlist =
|
||||
[
|
||||
CandleEntry("first", "8051", source),
|
||||
CandleEntry("second", "8040", source)
|
||||
];
|
||||
|
||||
Assert.True((await workflow.PrepareAsync(playlist, 0)).IsSuccess);
|
||||
source.Update(new LegacySceneMovingAverageSelection(true, false));
|
||||
Assert.True((await workflow.TakeInAsync()).IsSuccess);
|
||||
source.Update(new LegacySceneMovingAverageSelection(false, true));
|
||||
Assert.True((await workflow.RefreshOnAirAsync()).IsSuccess);
|
||||
source.Update(new LegacySceneMovingAverageSelection(true, true));
|
||||
Assert.True((await workflow.NextAsync()).IsSuccess);
|
||||
|
||||
Assert.Equal(["", "MA5", "MA20", "MA5,MA20"],
|
||||
provider.SelectionGraphicTypes);
|
||||
Assert.Equal("second", workflow.State.CurrentEntryId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OperatorPageCountRemainsFrozenAcrossGrowthAndRefresh()
|
||||
{
|
||||
var definitions = new Dictionary<string, (int Count, ScenePageSize? Size)>
|
||||
{
|
||||
["5074"] = (6, ScenePageSize.Five),
|
||||
["5001"] = (1, null)
|
||||
};
|
||||
var engine = new RecordingEngine();
|
||||
var provider = new RecordingProvider(definitions);
|
||||
var workflow = new LegacyPlayoutWorkflow(engine, provider);
|
||||
LegacyPlaylistEntry[] playlist =
|
||||
[
|
||||
new(
|
||||
"paged",
|
||||
"5074",
|
||||
PageNavigation: new(ScenePageSize.Five, FrozenPageCount: 2)),
|
||||
new("ordinary", "5001", PageNavigation: LegacyPlaylistPageNavigation.Disabled)
|
||||
];
|
||||
|
||||
Assert.True((await workflow.TakeSelectedAsync(playlist, 0)).IsSuccess);
|
||||
Assert.Equal(2, workflow.State.PageCount);
|
||||
Assert.True(workflow.State.IsPageNavigationEnabled);
|
||||
|
||||
definitions["5074"] = (16, ScenePageSize.Five);
|
||||
Assert.True((await workflow.RefreshOnAirAsync()).IsSuccess);
|
||||
Assert.Equal(2, workflow.State.PageCount);
|
||||
Assert.Equal(LegacyWorkflowNextKind.PageNext, workflow.State.NextKind);
|
||||
|
||||
Assert.True((await workflow.NextAsync()).IsSuccess);
|
||||
Assert.Equal(1, workflow.State.PageIndexZeroBased);
|
||||
Assert.Equal(2, workflow.State.PageCount);
|
||||
Assert.True(workflow.State.IsLastPage);
|
||||
Assert.Equal(LegacyWorkflowNextKind.PlaylistNext, workflow.State.NextKind);
|
||||
|
||||
definitions["5074"] = (101, ScenePageSize.Five);
|
||||
Assert.True((await workflow.RefreshOnAirAsync()).IsSuccess);
|
||||
Assert.Equal(2, workflow.State.PageCount);
|
||||
Assert.Equal(5, workflow.State.CurrentPageItemCount);
|
||||
Assert.Equal(LegacyWorkflowNextKind.PlaylistNext, workflow.State.NextKind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OperatorPageCountRemainsFrozenAfterShrinkAndMissingNextPageFailsClosed()
|
||||
{
|
||||
var definitions = new Dictionary<string, (int Count, ScenePageSize? Size)>
|
||||
{
|
||||
["5074"] = (6, ScenePageSize.Five)
|
||||
};
|
||||
var engine = new RecordingEngine();
|
||||
var provider = new RecordingProvider(definitions);
|
||||
var workflow = new LegacyPlayoutWorkflow(engine, provider);
|
||||
LegacyPlaylistEntry[] playlist =
|
||||
[
|
||||
new(
|
||||
"paged",
|
||||
"5074",
|
||||
PageNavigation: new(ScenePageSize.Five, FrozenPageCount: 2))
|
||||
];
|
||||
Assert.True((await workflow.TakeSelectedAsync(playlist, 0)).IsSuccess);
|
||||
|
||||
definitions["5074"] = (5, ScenePageSize.Five);
|
||||
Assert.True((await workflow.RefreshOnAirAsync()).IsSuccess);
|
||||
Assert.Equal(2, workflow.State.PageCount);
|
||||
Assert.Equal(LegacyWorkflowNextKind.PageNext, workflow.State.NextKind);
|
||||
var engineCallCount = engine.Calls.Count;
|
||||
|
||||
await Assert.ThrowsAsync<LegacySceneDataException>(() => workflow.NextAsync());
|
||||
|
||||
Assert.Equal(engineCallCount, engine.Calls.Count);
|
||||
Assert.Equal(0, workflow.State.PageIndexZeroBased);
|
||||
Assert.Equal(2, workflow.State.PageCount);
|
||||
Assert.Equal(LegacyWorkflowNextKind.PageNext, workflow.State.NextKind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExplicitlyNonPagedOperatorEntryMovesToNextPlaylistRowDespitePagedProvider()
|
||||
{
|
||||
var engine = new RecordingEngine();
|
||||
var provider = new RecordingProvider(new Dictionary<string, (int, ScenePageSize?)>
|
||||
{
|
||||
["5074"] = (11, ScenePageSize.Five),
|
||||
["5001"] = (1, null)
|
||||
});
|
||||
var workflow = new LegacyPlayoutWorkflow(engine, provider);
|
||||
LegacyPlaylistEntry[] playlist =
|
||||
[
|
||||
new("noncanonical", "5074", PageNavigation: LegacyPlaylistPageNavigation.Disabled),
|
||||
new("ordinary", "5001", PageNavigation: LegacyPlaylistPageNavigation.Disabled)
|
||||
];
|
||||
|
||||
Assert.True((await workflow.TakeSelectedAsync(playlist, 0)).IsSuccess);
|
||||
Assert.False(workflow.State.IsPageNavigationEnabled);
|
||||
Assert.Equal(1, workflow.State.PageCount);
|
||||
Assert.Equal(LegacyWorkflowNextKind.PlaylistNext, workflow.State.NextKind);
|
||||
|
||||
Assert.True((await workflow.NextAsync()).IsSuccess);
|
||||
Assert.Equal("ordinary", workflow.State.CurrentEntryId);
|
||||
Assert.DoesNotContain("5074:1", provider.Calls);
|
||||
Assert.Equal("Next:5001:p0", engine.Calls[^1]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DirectCoreEntryWithoutNavigationMetadataRetainsFreshPlanBehavior()
|
||||
{
|
||||
var definitions = new Dictionary<string, (int Count, ScenePageSize? Size)>
|
||||
{
|
||||
["5074"] = (6, ScenePageSize.Five)
|
||||
};
|
||||
var workflow = new LegacyPlayoutWorkflow(
|
||||
new RecordingEngine(),
|
||||
new RecordingProvider(definitions));
|
||||
|
||||
Assert.True((await workflow.TakeSelectedAsync([new("direct", "5074")], 0)).IsSuccess);
|
||||
Assert.Equal(2, workflow.State.PageCount);
|
||||
|
||||
definitions["5074"] = (11, ScenePageSize.Five);
|
||||
Assert.True((await workflow.RefreshOnAirAsync()).IsSuccess);
|
||||
Assert.Equal(3, workflow.State.PageCount);
|
||||
Assert.True(workflow.State.IsPageNavigationEnabled);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Next_AtTheEndDoesNotWrapOrDispatchTheEngine()
|
||||
{
|
||||
@@ -181,7 +334,7 @@ public sealed class LegacyPlayoutWorkflowTests
|
||||
var workflow = new LegacyPlayoutWorkflow(engine, provider);
|
||||
|
||||
await Assert.ThrowsAsync<ArgumentException>(() => workflow.PrepareAsync(
|
||||
[new LegacyPlaylistEntry("entry", "5001", FadeDuration: 61)],
|
||||
[new LegacyPlaylistEntry("entry", "5001", FadeDuration: 20)],
|
||||
0));
|
||||
|
||||
Assert.Empty(provider.Calls);
|
||||
@@ -243,7 +396,7 @@ public sealed class LegacyPlayoutWorkflowTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PrepareAndTakeIn_LoadsOnceAndCallsPrepareThenTakeIn()
|
||||
public async Task TakeSelected_LoadsOnceAndCallsPrepareThenTakeIn()
|
||||
{
|
||||
var engine = new RecordingEngine();
|
||||
var provider = new RecordingProvider(new Dictionary<string, (int, ScenePageSize?)>
|
||||
@@ -252,7 +405,7 @@ public sealed class LegacyPlayoutWorkflowTests
|
||||
});
|
||||
var workflow = new LegacyPlayoutWorkflow(engine, provider);
|
||||
|
||||
var result = await workflow.PrepareAndTakeInAsync(
|
||||
var result = await workflow.TakeSelectedAsync(
|
||||
[new("disabled", "5006", false), new("selected", "5001")],
|
||||
0);
|
||||
|
||||
@@ -267,7 +420,7 @@ public sealed class LegacyPlayoutWorkflowTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PrepareAndTakeIn_WhenTakeInFails_RetainsPreparedStateWithoutRetry()
|
||||
public async Task TakeSelected_WhenTakeInFails_RetainsPreparedStateWithoutRetry()
|
||||
{
|
||||
var engine = new RecordingEngine();
|
||||
engine.TakeInResults.Enqueue(PlayoutResultCode.OutcomeUnknown);
|
||||
@@ -277,7 +430,7 @@ public sealed class LegacyPlayoutWorkflowTests
|
||||
});
|
||||
var workflow = new LegacyPlayoutWorkflow(engine, provider);
|
||||
|
||||
var result = await workflow.PrepareAndTakeInAsync([new("selected", "5074")], 0);
|
||||
var result = await workflow.TakeSelectedAsync([new("selected", "5074")], 0);
|
||||
|
||||
Assert.Equal(PlayoutResultCode.OutcomeUnknown, result.Code);
|
||||
Assert.Equal(["5074:0"], provider.Calls);
|
||||
@@ -288,6 +441,198 @@ public sealed class LegacyPlayoutWorkflowTests
|
||||
Assert.Equal(LegacyWorkflowNextKind.PageNext, workflow.State.NextKind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TakeSelected_WhileProgram_PreparesAndPlaysTheCurrentOperatorSelection()
|
||||
{
|
||||
var engine = new RecordingEngine();
|
||||
var provider = new RecordingProvider(new Dictionary<string, (int, ScenePageSize?)>
|
||||
{
|
||||
["5001"] = (1, null),
|
||||
["5006"] = (1, null),
|
||||
["5074"] = (1, null)
|
||||
});
|
||||
var workflow = new LegacyPlayoutWorkflow(engine, provider);
|
||||
LegacyPlaylistEntry[] playlist =
|
||||
[
|
||||
new("program-a", "5001"),
|
||||
new("between", "5006"),
|
||||
new("candidate-d", "5074")
|
||||
];
|
||||
Assert.True((await workflow.TakeSelectedAsync(playlist, 0)).IsSuccess);
|
||||
|
||||
var switchResult = await workflow.TakeSelectedAsync(playlist, 2);
|
||||
|
||||
Assert.True(switchResult.IsSuccess);
|
||||
Assert.Equal(
|
||||
["Prepare:5001:p0", "TakeIn", "Prepare:5074:p0", "TakeIn"],
|
||||
engine.Calls);
|
||||
Assert.Equal(["5001:0", "5074:0"], provider.Calls);
|
||||
Assert.Equal(2, workflow.State.CurrentCueIndexZeroBased);
|
||||
Assert.Equal("candidate-d", workflow.State.CurrentEntryId);
|
||||
Assert.Null(workflow.State.PreparedCutCode);
|
||||
Assert.Equal("5074", workflow.State.OnAirCutCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ManualCandidateRemainsIndependentAcrossNextUntilTheNextF8()
|
||||
{
|
||||
var engine = new RecordingEngine();
|
||||
var provider = new RecordingProvider(new Dictionary<string, (int, ScenePageSize?)>
|
||||
{
|
||||
["5001"] = (1, null),
|
||||
["5006"] = (1, null),
|
||||
["5074"] = (1, null)
|
||||
});
|
||||
var workflow = new LegacyPlayoutWorkflow(engine, provider);
|
||||
LegacyPlaylistEntry[] playlist =
|
||||
[
|
||||
new("program-a", "5001"),
|
||||
new("next-b", "5006"),
|
||||
new("candidate-d", "5074")
|
||||
];
|
||||
Assert.True((await workflow.TakeSelectedAsync(playlist, 0)).IsSuccess);
|
||||
const int operatorCandidateIndex = 2;
|
||||
|
||||
Assert.True((await workflow.NextAsync()).IsSuccess);
|
||||
|
||||
Assert.Equal(1, workflow.State.CurrentCueIndexZeroBased);
|
||||
Assert.Equal("next-b", workflow.State.CurrentEntryId);
|
||||
Assert.Equal(2, operatorCandidateIndex);
|
||||
|
||||
Assert.True((await workflow.TakeSelectedAsync(
|
||||
playlist,
|
||||
operatorCandidateIndex)).IsSuccess);
|
||||
|
||||
Assert.Equal(2, workflow.State.CurrentCueIndexZeroBased);
|
||||
Assert.Equal("candidate-d", workflow.State.CurrentEntryId);
|
||||
Assert.Equal(
|
||||
[
|
||||
"Prepare:5001:p0", "TakeIn",
|
||||
"Next:5006:p0",
|
||||
"Prepare:5074:p0", "TakeIn"
|
||||
],
|
||||
engine.Calls);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TakeSelected_AfterExplicitPrepare_UsesTheLaterRowSelection()
|
||||
{
|
||||
var engine = new RecordingEngine();
|
||||
var provider = new RecordingProvider(new Dictionary<string, (int, ScenePageSize?)>
|
||||
{
|
||||
["5001"] = (1, null),
|
||||
["5074"] = (1, null)
|
||||
});
|
||||
var workflow = new LegacyPlayoutWorkflow(engine, provider);
|
||||
LegacyPlaylistEntry[] playlist =
|
||||
[
|
||||
new("prepared-a", "5001"),
|
||||
new("selected-d", "5074")
|
||||
];
|
||||
Assert.True((await workflow.PrepareAsync(playlist, 0)).IsSuccess);
|
||||
|
||||
var result = await workflow.TakeSelectedAsync(playlist, 1);
|
||||
|
||||
Assert.True(result.IsSuccess);
|
||||
Assert.Equal(
|
||||
["Prepare:5001:p0", "Prepare:5074:p0", "TakeIn"],
|
||||
engine.Calls);
|
||||
Assert.Equal(["5001:0", "5074:0"], provider.Calls);
|
||||
Assert.Equal(1, workflow.State.CurrentCueIndexZeroBased);
|
||||
Assert.Equal("selected-d", workflow.State.CurrentEntryId);
|
||||
Assert.Null(workflow.State.PreparedCutCode);
|
||||
Assert.Equal("5074", workflow.State.OnAirCutCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TakeSelected_WhileProgram_WhenPrepareFails_PreservesCurrentOnAirRow()
|
||||
{
|
||||
var engine = new RecordingEngine();
|
||||
var provider = new RecordingProvider(new Dictionary<string, (int, ScenePageSize?)>
|
||||
{
|
||||
["5001"] = (1, null),
|
||||
["5074"] = (1, null)
|
||||
});
|
||||
var workflow = new LegacyPlayoutWorkflow(engine, provider);
|
||||
LegacyPlaylistEntry[] playlist =
|
||||
[
|
||||
new("program-a", "5001"),
|
||||
new("candidate-d", "5074")
|
||||
];
|
||||
Assert.True((await workflow.TakeSelectedAsync(playlist, 0)).IsSuccess);
|
||||
engine.PrepareResults.Enqueue(PlayoutResultCode.Rejected);
|
||||
|
||||
var result = await workflow.TakeSelectedAsync(playlist, 1);
|
||||
|
||||
Assert.Equal(PlayoutResultCode.Rejected, result.Code);
|
||||
Assert.Equal(
|
||||
["Prepare:5001:p0", "TakeIn", "Prepare:5074:p0"],
|
||||
engine.Calls);
|
||||
Assert.Equal(0, workflow.State.CurrentCueIndexZeroBased);
|
||||
Assert.Equal("program-a", workflow.State.CurrentEntryId);
|
||||
Assert.Null(workflow.State.PreparedCutCode);
|
||||
Assert.Equal("5001", workflow.State.OnAirCutCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TakeSelected_WhileProgram_WhenPlayIsUnknown_KeepsOldOnAirAndNewPreparedState()
|
||||
{
|
||||
var engine = new RecordingEngine();
|
||||
var provider = new RecordingProvider(new Dictionary<string, (int, ScenePageSize?)>
|
||||
{
|
||||
["5001"] = (1, null),
|
||||
["5074"] = (1, null)
|
||||
});
|
||||
var workflow = new LegacyPlayoutWorkflow(engine, provider);
|
||||
LegacyPlaylistEntry[] playlist =
|
||||
[
|
||||
new("program-a", "5001"),
|
||||
new("candidate-d", "5074")
|
||||
];
|
||||
Assert.True((await workflow.TakeSelectedAsync(playlist, 0)).IsSuccess);
|
||||
engine.TakeInResults.Enqueue(PlayoutResultCode.OutcomeUnknown);
|
||||
|
||||
var result = await workflow.TakeSelectedAsync(playlist, 1);
|
||||
|
||||
Assert.Equal(PlayoutResultCode.OutcomeUnknown, result.Code);
|
||||
Assert.Equal(
|
||||
["Prepare:5001:p0", "TakeIn", "Prepare:5074:p0", "TakeIn"],
|
||||
engine.Calls);
|
||||
Assert.Equal(0, workflow.State.CurrentCueIndexZeroBased);
|
||||
Assert.Equal("program-a", workflow.State.CurrentEntryId);
|
||||
Assert.Equal("5074", workflow.State.PreparedCutCode);
|
||||
Assert.Equal("5001", workflow.State.OnAirCutCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TakeSelected_WhilePlayCompletionIsPending_DoesNotQueryOrDispatch()
|
||||
{
|
||||
var engine = new RecordingEngine();
|
||||
var provider = new RecordingProvider(new Dictionary<string, (int, ScenePageSize?)>
|
||||
{
|
||||
["5001"] = (1, null),
|
||||
["5074"] = (1, null)
|
||||
});
|
||||
var workflow = new LegacyPlayoutWorkflow(engine, provider);
|
||||
LegacyPlaylistEntry[] playlist =
|
||||
[
|
||||
new("program-a", "5001"),
|
||||
new("candidate-d", "5074")
|
||||
];
|
||||
Assert.True((await workflow.TakeSelectedAsync(playlist, 0)).IsSuccess);
|
||||
engine.Status = engine.Status with { IsPlayCompletionPending = true };
|
||||
var providerCallCount = provider.Calls.Count;
|
||||
var engineCallCount = engine.Calls.Count;
|
||||
|
||||
var result = await workflow.TakeSelectedAsync(playlist, 1);
|
||||
|
||||
Assert.Equal(PlayoutResultCode.Rejected, result.Code);
|
||||
Assert.Equal(providerCallCount, provider.Calls.Count);
|
||||
Assert.Equal(engineCallCount, engine.Calls.Count);
|
||||
Assert.Equal(0, workflow.State.CurrentCueIndexZeroBased);
|
||||
Assert.Equal("5001", workflow.State.OnAirCutCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TakeIn_WhenFreshPrepareIsOutcomeUnknown_DoesNotPlayOrReplacePreparedState()
|
||||
{
|
||||
@@ -312,7 +657,7 @@ public sealed class LegacyPlayoutWorkflowTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RefreshOnAir_RequeriesTheCurrentPagedWindowAndUsesGetPlayingSceneEnginePath()
|
||||
public async Task RefreshOnAir_RequeriesTheCurrentPagedWindowAndUsesOnAirUpdatePath()
|
||||
{
|
||||
var engine = new RecordingEngine();
|
||||
var provider = new RecordingProvider(new Dictionary<string, (int, ScenePageSize?)>
|
||||
@@ -530,6 +875,8 @@ public sealed class LegacyPlayoutWorkflowTests
|
||||
|
||||
public List<string> PlanCalls { get; } = [];
|
||||
|
||||
public List<string?> SelectionGraphicTypes { get; } = [];
|
||||
|
||||
public Func<string, int, string>? SceneNameOverride { get; init; }
|
||||
|
||||
public string? BuilderKey { get; init; }
|
||||
@@ -543,6 +890,7 @@ public sealed class LegacyPlayoutWorkflowTests
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
Calls.Add($"{entry.CutCode}:{pageIndexZeroBased}");
|
||||
SelectionGraphicTypes.Add(entry.Selection?.GraphicType);
|
||||
var definition = definitions[entry.CutCode];
|
||||
var name = SceneNameOverride?.Invoke(entry.CutCode, pageIndexZeroBased) ?? entry.CutCode;
|
||||
return Task.FromResult(new LegacySceneCuePage(
|
||||
@@ -577,6 +925,21 @@ public sealed class LegacyPlayoutWorkflowTests
|
||||
}
|
||||
}
|
||||
|
||||
private static LegacyPlaylistEntry CandleEntry(
|
||||
string entryId,
|
||||
string cutCode,
|
||||
ILegacySceneMovingAverageSelectionSource source) =>
|
||||
new(
|
||||
entryId,
|
||||
cutCode,
|
||||
Selection: new LegacySceneSelection(
|
||||
"KOSPI_STOCK",
|
||||
"Samsung Electronics",
|
||||
"persisted-candle-identity",
|
||||
"PRICE",
|
||||
"005930"),
|
||||
MovingAverageSelectionSource: source);
|
||||
|
||||
private sealed class RecordingEngine : IPlayoutEngine
|
||||
{
|
||||
public List<string> Calls { get; } = [];
|
||||
@@ -589,7 +952,7 @@ public sealed class LegacyPlayoutWorkflowTests
|
||||
|
||||
public Action? PrepareCallback { get; set; }
|
||||
|
||||
public PlayoutStatus Status { get; } = new(
|
||||
public PlayoutStatus Status { get; set; } = new(
|
||||
PlayoutMode.DryRun,
|
||||
PlayoutConnectionState.DryRunReady,
|
||||
true,
|
||||
|
||||
@@ -23,7 +23,7 @@ public sealed class LegacyScenePreviewTests
|
||||
new PlayoutSetPathPoints("line", [new(1, 2), new(3, 4, 5)]),
|
||||
new PlayoutSetPathShapePoints("shape", [new(6, 7)]),
|
||||
new PlayoutSetBackgroundTexture(secretAsset),
|
||||
new PlayoutSetBackgroundVideo(secretAsset, 2004, true),
|
||||
new PlayoutSetBackgroundVideo(secretAsset, 2004, 10),
|
||||
new PlayoutUseBackground(true)
|
||||
]);
|
||||
|
||||
@@ -42,7 +42,7 @@ public sealed class LegacyScenePreviewTests
|
||||
value => Assert.Equal(new("path-shape", "shape", "count=1;6,7,0"), value),
|
||||
value => Assert.Equal(new("background-texture", "scene", "configured"), value),
|
||||
value => Assert.Equal(
|
||||
new("background-video", "scene", "configured;loop=2004;infinite=true"),
|
||||
new("background-video", "scene", "configured;loop=2004;loop-mode=10"),
|
||||
value),
|
||||
value => Assert.Equal(new("background", "scene", "enabled"), value));
|
||||
Assert.DoesNotContain(secretAsset, string.Join("|", preview.Select(value => value.Value)));
|
||||
|
||||
@@ -9,9 +9,8 @@ public sealed class LegacySceneRefreshPolicyTests
|
||||
{ "5001", 2 }, { "N5001", 2 }, { "5006", 5 }, { "5011", 5 },
|
||||
{ "5016", 5 }, { "50160", 30 }, { "5023", 30 }, { "5024", 60 },
|
||||
{ "5025", 30 }, { "5026", 8 }, { "5029", 7 }, { "5032", 5 },
|
||||
{ "5037", 5 }, { "5074", 7 }, { "5076", 3_000_000 }, { "5077", 7 },
|
||||
{ "5078", 30 }, { "5079", 3_000_000 }, { "5080", 3_000_000 },
|
||||
{ "5081", 3_000_000 }, { "5082", 6 }, { "5083", 60 }, { "5084", 5 },
|
||||
{ "5037", 5 }, { "5074", 7 }, { "5077", 7 }, { "5078", 30 },
|
||||
{ "5082", 6 }, { "5083", 60 }, { "5084", 5 },
|
||||
{ "5085", 30 }, { "5086", 7 }, { "50860", 7 }, { "5087", 7 },
|
||||
{ "5088", 7 }, { "6001", 30 }, { "6067", 30 }, { "8001", 120 },
|
||||
{ "8002", 120 }, { "8003", 8 }, { "8018", 5 }, { "8032", 5 },
|
||||
@@ -28,6 +27,18 @@ public sealed class LegacySceneRefreshPolicyTests
|
||||
Assert.Equal(TimeSpan.FromSeconds(seconds), interval);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("5076")]
|
||||
[InlineData("5079")]
|
||||
[InlineData("5080")]
|
||||
[InlineData("5081")]
|
||||
public void OverflowedMainFormTimerAliasesDoNotArmAutomaticRefresh(string alias)
|
||||
{
|
||||
Assert.True(LegacySceneRefreshPolicy.ContainsAlias(alias));
|
||||
Assert.True(LegacySceneRefreshPolicy.IsDisabledByLegacyTimerOverflow(alias));
|
||||
Assert.False(LegacySceneRefreshPolicy.TryGetInterval(alias, out _));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PolicyCoversExactlyTheCatalogsActiveAliases()
|
||||
{
|
||||
@@ -39,7 +50,7 @@ public sealed class LegacySceneRefreshPolicyTests
|
||||
Assert.Equal(45, aliases.Length);
|
||||
Assert.Equal(aliases.Length, LegacySceneRefreshPolicy.Count);
|
||||
Assert.All(aliases, alias =>
|
||||
Assert.True(LegacySceneRefreshPolicy.TryGetInterval(alias, out _), alias));
|
||||
Assert.True(LegacySceneRefreshPolicy.ContainsAlias(alias), alias));
|
||||
Assert.False(LegacySceneRefreshPolicy.TryGetInterval("8086", out _));
|
||||
Assert.False(LegacySceneRefreshPolicy.TryGetInterval("../5001", out _));
|
||||
Assert.Equal(TimeSpan.FromSeconds(3), LegacySceneRefreshPolicy.RecurringInterval);
|
||||
|
||||
@@ -147,7 +147,7 @@ public sealed class PlayoutBridgeProtocolTests
|
||||
[InlineData("{\"requestId\":\"REQ\",\"command\":\"next\",\"playlist\":[],\"selectedIndex\":0}")]
|
||||
[InlineData("{\"requestId\":\"REQ\",\"command\":\"prepare\",\"playlist\":[],\"selectedIndex\":0}")]
|
||||
[InlineData("{\"requestId\":\"REQ\",\"command\":\"prepare\",\"playlist\":[{\"id\":\"same\",\"code\":\"5001\",\"enabled\":true},{\"id\":\"same\",\"code\":\"5006\",\"enabled\":true}],\"selectedIndex\":0}")]
|
||||
[InlineData("{\"requestId\":\"REQ\",\"command\":\"prepare\",\"playlist\":[{\"id\":\"one\",\"code\":\"5001\",\"enabled\":true,\"fadeDuration\":61}],\"selectedIndex\":0}")]
|
||||
[InlineData("{\"requestId\":\"REQ\",\"command\":\"prepare\",\"playlist\":[{\"id\":\"one\",\"code\":\"5001\",\"enabled\":true,\"fadeDuration\":20}],\"selectedIndex\":0}")]
|
||||
[InlineData("{\"requestId\":\"REQ\",\"command\":\"prepare\",\"playlist\":[{\"id\":\"one\",\"code\":\"5001\",\"enabled\":true,\"selection\":{\"groupCode\":\"코스피\",\"subject\":\"bad\\nvalue\",\"graphicType\":\"\",\"subtype\":\"\",\"dataCode\":\"005930\"}}],\"selectedIndex\":0}")]
|
||||
[InlineData("{\"requestId\":\"REQ\",\"command\":\"prepare\",\"playlist\":[{\"id\":\"one\",\"code\":\"5001\",\"enabled\":true,\"selection\":{\"groupCode\":\"코스피\",\"subject\":\"삼성전자\",\"graphicType\":\"\",\"subtype\":\"\",\"dataCode\":\"005930\",\"objectName\":\"title\"}}],\"selectedIndex\":0}")]
|
||||
public void ParseWorkflowCommand_RejectsCueOverrideDuplicateOrUnsafeShapes(string json)
|
||||
|
||||
@@ -546,7 +546,7 @@ public sealed class ReadOnlyPanelSceneBuildersTests
|
||||
PlayoutSetFaceColor color =>
|
||||
$"C:{color.ObjectName}:{color.Red}:{color.Green}:{color.Blue}:{color.Alpha}",
|
||||
PlayoutSetBackgroundVideo video =>
|
||||
$"B:{video.AssetPath}:{video.LoopCount}:{(video.LoopInfinite ? 1 : 0)}",
|
||||
$"B:{video.AssetPath}:{video.LoopCount}:{video.LoopInfinite}",
|
||||
_ => mutation.GetType().Name
|
||||
};
|
||||
}
|
||||
|
||||
@@ -54,6 +54,30 @@ public sealed class RegisteredLegacySceneCueProviderTests
|
||||
page.Cue.Mutations!.Skip(2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreatePage_CommonVideoBackgroundUsesOriginalRawK3dLoopValueTen()
|
||||
{
|
||||
var provider = new RegisteredLegacySceneCueProvider(
|
||||
new StubDataSource(new LegacySceneDataPage(
|
||||
"s5085",
|
||||
new S5085SceneData(
|
||||
[
|
||||
new ProgramTradingMetricData(ProgramTradingMetric.NetBuy, 0d)
|
||||
]),
|
||||
1)),
|
||||
options: new LegacySceneCueCompositionOptions(
|
||||
6,
|
||||
LegacySceneBackgroundKind.Video,
|
||||
"Video\\studio.vrv"));
|
||||
|
||||
var page = await provider.CreatePageAsync(new("entry", "5085"), 0);
|
||||
|
||||
Assert.Equal(
|
||||
new PlayoutSetBackgroundVideo("Video\\studio.vrv", 2004, 10),
|
||||
page.Cue.Mutations![0]);
|
||||
Assert.Equal(new PlayoutUseBackground(true), page.Cue.Mutations[1]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreatePagePlan_UsesDedicatedDtoRouteWithoutBuildingACue()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user