using Xunit;
using ytLive.Models;
using ytLive.Services;
using ytLive.Services.Compositor;
namespace ytLive.Tests;
///
/// The universal privacy blur at the compositor level (creator ruling 2026-11-01): it blankets
/// every layer beneath it, and the brand logo — blitted after the blur — is never swallowed.
///
public class BlurCompositorTests
{
private static VideoFrame Solid(int w, int h, byte r, byte g, byte b)
{
var pixels = new byte[w * h * 4];
for (var i = 0; i < pixels.Length; i += 4)
{
pixels[i] = b; pixels[i + 1] = g; pixels[i + 2] = r; pixels[i + 3] = 255;
}
return new VideoFrame(w, h, pixels);
}
/// Hard left/right colour split — blurring is unmistakable on it.
private static VideoFrame Split(int w, int h, byte lr, byte lg, byte lb, byte rr, byte rg, byte rb)
{
var pixels = new byte[w * h * 4];
var half = w / 2;
for (var y = 0; y < h; y++)
for (var x = 0; x < w; x++)
{
var i = (y * w + x) * 4;
pixels[i] = x < half ? lb : rb;
pixels[i + 1] = x < half ? lg : rg;
pixels[i + 2] = x < half ? lr : rr;
pixels[i + 3] = 255;
}
return new VideoFrame(w, h, pixels);
}
private static void AssertPixel(VideoFrame frame, int x, int y, byte r, byte g, byte b)
{
var i = (y * frame.Width + x) * 4;
Assert.True(
frame.BgraPixels[i + 2] == r && frame.BgraPixels[i + 1] == g && frame.BgraPixels[i] == b,
$"pixel ({x},{y}): expected rgb({r},{g},{b}), got rgb({frame.BgraPixels[i + 2]},{frame.BgraPixels[i + 1]},{frame.BgraPixels[i]})");
}
[Fact]
public void The_blur_covers_what_is_beneath_it_and_never_the_brand_logo()
{
var stripes = Split(1920, 1080, 0, 0, 255, 0, 255, 0); // blue | green, hard edge at x=960
var brand = Solid(120, 60, 255, 255, 255); // white logo
var background = new Source { Type = SourceType.DisplayCapture, IsBackground = true, CaptureKey = "monitor:0" };
var logo = new Source { Type = SourceType.Image, IsBrandLogo = true, X = 900, Y = 500, Width = 120, Height = 60 };
var blur = new Source { Type = SourceType.Blur, X = 700, Y = 400, Width = 600, Height = 300, BlurAmount = 1.0 };
var scene = new Scene { Name = "Live" };
scene.Elements.Add(background);
scene.Elements.Add(logo);
scene.Elements.Add(blur);
VideoFrame? FrameFor(SceneElement e) => e switch
{
Source { IsBackground: true } => stripes,
Source { IsBrandLogo: true } => brand,
_ => null,
};
var options = new CompositorOptions
{
SourceRectX = 0, SourceRectY = 0, SourceRectWidth = 1920, SourceRectHeight = 1080,
OutputWidth = 1920, OutputHeight = 1080,
};
var output = new SceneCompositor().Render(scene, FrameFor, null, options);
// 1. Inside the blur, over the colour edge: blended, not the hard split.
var i = (450 * output.Width + 950) * 4;
Assert.True(output.BgraPixels[i] > 0 && output.BgraPixels[i + 1] > 0,
"a blurred pixel on the colour edge must be a blend of both sides");
// 2. The logo, sitting inside the blur's area, is untouched.
AssertPixel(output, 950, 530, 255, 255, 255);
}
}