Screen backdrop (schema v5/v6) + five-scene catalog + webcam polish: live desktop/game capture as a permanent non-deletable bottom layer (Source.IsBackdrop), auto full-screen game detection (Win32FullScreenDetector) else primary display, GraphicsCapturePicker re-designation, refcounted shared ScreenCaptureManager, Live-only backdrop by policy (HasBackdrop + v5-v6 backfill + EnforceBackdropPolicy, checkbox gone), SceneCatalog (Starting/Live/BRB/Chat/Ending) with + button re-adding missing scenes, webcam mid-session transparent-container fix (GetPreviewBitmap propagation), Chat half-screen-area cap, 'Add Webcam' always opens the picker (SwapWebcamIdentityAsync, no silent resurrect), WindowsRuntimeMarshal frame-read + 5s-throttled errors, docs updated, tests (65 passing)
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
using Xunit;
|
||||
using ytLive.Models;
|
||||
using ytLive.ViewModels;
|
||||
|
||||
namespace ytLive.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// The backdrop is a permanent, non-deletable bottom layer holding live
|
||||
/// desktop/game capture, and it exists only in the canonical Live scene (see
|
||||
/// <see cref="SceneCatalog"/>). Every backdrop-enabled scene
|
||||
/// (<see cref="Scene.HasBackdrop"/>) is healed to have exactly one, inserted
|
||||
/// first; it is never reorderable or removable by the UI. Scenes without the
|
||||
/// flag never get one.
|
||||
/// </summary>
|
||||
public class BackdropTests
|
||||
{
|
||||
[Fact]
|
||||
public void EnsureBackdrop_OnEmptyScene_InsertsFullFrameBackdrop()
|
||||
{
|
||||
var scene = new Scene { Name = "S", HasBackdrop = true };
|
||||
|
||||
var backdrop = MainViewModel.EnsureBackdrop(scene);
|
||||
|
||||
Assert.NotNull(backdrop);
|
||||
Assert.Single(scene.Elements);
|
||||
Assert.Same(backdrop, scene.Elements[0]);
|
||||
Assert.True(backdrop.IsBackdrop);
|
||||
Assert.True(backdrop.IsEnabled);
|
||||
Assert.Equal(SourceType.DisplayCapture, backdrop.Type);
|
||||
Assert.Equal(0, backdrop.X);
|
||||
Assert.Equal(0, backdrop.Y);
|
||||
Assert.Equal(1920, backdrop.Width);
|
||||
Assert.Equal(1080, backdrop.Height);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EnsureBackdrop_ExistingBackdrop_IsIdempotent()
|
||||
{
|
||||
var scene = new Scene { Name = "S", HasBackdrop = true };
|
||||
var first = MainViewModel.EnsureBackdrop(scene);
|
||||
var second = MainViewModel.EnsureBackdrop(scene);
|
||||
|
||||
Assert.Same(first, second);
|
||||
Assert.Single(scene.Elements);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EnsureBackdrop_HealsMissingBackdropAtIndexZero()
|
||||
{
|
||||
var scene = new Scene { Name = "S", HasBackdrop = true };
|
||||
var image = new Source { Name = "Logo", Type = SourceType.Image };
|
||||
scene.Elements.Add(image);
|
||||
|
||||
MainViewModel.EnsureBackdrop(scene);
|
||||
|
||||
Assert.Equal(2, scene.Elements.Count);
|
||||
Assert.True(((Source)scene.Elements[0]).IsBackdrop);
|
||||
Assert.Same(image, scene.Elements[1]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EnsureBackdrop_SceneWithoutHasBackdrop_ReturnsNullAndInsertsNothing()
|
||||
{
|
||||
var scene = new Scene { Name = "Ending", HasBackdrop = false };
|
||||
|
||||
var backdrop = MainViewModel.EnsureBackdrop(scene);
|
||||
|
||||
Assert.Null(backdrop);
|
||||
Assert.Empty(scene.Elements);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(SourceType.DisplayCapture, true)]
|
||||
[InlineData(SourceType.WindowCapture, true)]
|
||||
[InlineData(SourceType.Background, false)]
|
||||
[InlineData(SourceType.Image, false)]
|
||||
[InlineData(SourceType.TextOverlay, false)]
|
||||
public void Source_IsLiveCapture_OnlyForDisplayAndWindow(SourceType type, bool expected)
|
||||
{
|
||||
Assert.Equal(expected, new Source { Type = type }.IsLiveCapture);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Source_DisplaySource_IsVideoImageSource_WhenLiveCapture()
|
||||
{
|
||||
var source = new Source { Type = SourceType.DisplayCapture };
|
||||
var bitmap = new System.Windows.Media.Imaging.WriteableBitmap(
|
||||
2, 2, 96, 96, System.Windows.Media.PixelFormats.Bgra32, null);
|
||||
source.VideoImageSource = bitmap;
|
||||
|
||||
Assert.Same(bitmap, source.DisplaySource);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Source_DisplaySource_IsImageSource_WhenNotLiveCapture()
|
||||
{
|
||||
var source = new Source { Type = SourceType.Background };
|
||||
var bitmap = new System.Windows.Media.Imaging.WriteableBitmap(
|
||||
2, 2, 96, 96, System.Windows.Media.PixelFormats.Bgra32, null);
|
||||
source.VideoImageSource = bitmap;
|
||||
|
||||
Assert.NotSame(bitmap, source.DisplaySource);
|
||||
Assert.Null(source.DisplaySource);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Source_TypeChange_RaisesDisplaySource()
|
||||
{
|
||||
var source = new Source { Type = SourceType.Image };
|
||||
var raised = new List<string>();
|
||||
source.PropertyChanged += (_, e) => raised.Add(e.PropertyName ?? string.Empty);
|
||||
|
||||
source.Type = SourceType.DisplayCapture;
|
||||
|
||||
Assert.Contains(nameof(Source.IsLiveCapture), raised);
|
||||
Assert.Contains(nameof(Source.DisplaySource), raised);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user