using System; using Xunit; using ytLive.Services.Compositor; namespace ytLive.Tests; /// /// The privacy blur (creator ruling 2026-11-01): a Live-scene layer that blurs the frame beneath it /// inside a box or circle, so a creator can hide part of their desktop. /// /// Two rules are load-bearing and both are here: pixels OUTSIDE the mask must be untouched /// (otherwise the layer is a full-frame filter), and overlapping layers must resolve to the /// strongest single blur, never to a blurred blur — the creator was explicit that a stack cannot /// be stronger than any one slider setting. /// public class RegionBlurTests { private const int W = 320; private const int H = 180; private const int Stride = W * 4; /// A frame of vertical hard edges: blurring is then obvious (edges go grey). private static byte[] StripedFrame() { var pixels = new byte[Stride * H]; for (var y = 0; y < H; y++) for (var x = 0; x < W; x++) { var p = y * Stride + x * 4; var on = (x / 8) % 2 == 0; pixels[p] = pixels[p + 1] = pixels[p + 2] = (byte)(on ? 255 : 0); pixels[p + 3] = 255; } return pixels; } private static int CenterVariance(byte[] pixels, int x0, int y0, int x1, int y1) { // Crude "is this still hard-edged" measure: count horizontal transitions in the middle row. var y = (y0 + y1) / 2; var transitions = 0; for (var x = x0 + 1; x < x1; x++) { var a = pixels[y * Stride + (x - 1) * 4]; var b = pixels[y * Stride + x * 4]; if (Math.Abs(a - b) > 32) transitions++; } return transitions; } [Fact] public void Pixels_outside_the_mask_are_untouched_and_inside_are_blurred() { var pixels = StripedFrame(); var before = (byte[])pixels.Clone(); var applied = RegionBlur.ApplyInPlace( pixels, Stride, W, H, 100, 60, 120, 60, strength: 0.8, round: false); Assert.True(applied); // Outside: untouched, byte for byte. for (var y = 0; y < H; y++) for (var x = 0; x < W; x++) { var inside = x >= 100 && x < 220 && y >= 60 && y < 120; if (inside) continue; var p = y * Stride + x * 4; Assert.Equal(before[p], pixels[p]); } // Inside: the hard stripes are gone. Assert.True(CenterVariance(pixels, 110, 70, 210, 110) < CenterVariance(before, 110, 70, 210, 110)); } [Fact] public void A_round_blur_leaves_the_corners_of_its_box_alone() { var pixels = StripedFrame(); var before = (byte[])pixels.Clone(); RegionBlur.ApplyInPlace(pixels, Stride, W, H, 100, 60, 120, 60, strength: 0.8, round: true); // The box's corner is outside the inscribed ellipse. var corner = 60 * Stride + 100 * 4; Assert.Equal(before[corner], pixels[corner]); } [Fact] public void An_overlap_uses_the_strongest_blur_once_and_never_stacks() { // Same region blurred twice: without the coverage map the second pass blurs an already // blurred region, which is stronger than either slider setting. With it, the second pass // skips the covered pixels and the result equals a single strong pass. var once = StripedFrame(); RegionBlur.ApplyInPlace(once, Stride, W, H, 100, 60, 120, 60, 0.8, false); var onceVariance = CenterVariance(once, 110, 70, 210, 110); var stacked = StripedFrame(); var coverage = new byte[W * H]; RegionBlur.ApplyInPlace(stacked, Stride, W, H, 100, 60, 120, 60, 0.8, false, coverage); RegionBlur.ApplyInPlace(stacked, Stride, W, H, 100, 60, 120, 60, 0.8, false, coverage); Assert.Equal(onceVariance, CenterVariance(stacked, 110, 70, 210, 110)); } [Fact] public void Strength_zero_still_blurs_a_little_and_the_curve_is_the_webcams() { // The shared radius curve: 1 downscaled px at 0, 6 at 1 — the webcam's own numbers. Assert.Equal(RegionBlur.MinRadius, RegionBlur.RadiusFor(0)); Assert.Equal(RegionBlur.MaxRadius, RegionBlur.RadiusFor(1)); Assert.Equal(RegionBlur.MaxRadius, RegionBlur.RadiusFor(4)); // clamped Assert.Equal(RegionBlur.MinRadius, RegionBlur.RadiusFor(-1)); } }