//! Unit coverage for HEVC and direct-MJPEG corruption guard decisions.

#[test]
fn hevc_jpeg_quality_defaults_to_moderate_transport_pressure() {
    temp_env::with_var_unset("LESAVKA_UVC_HEVC_JPEG_QUALITY", || {
        assert_eq!(super::hevc_jpeg_quality(), 72);
    });

    temp_env::with_var("LESAVKA_UVC_HEVC_JPEG_QUALITY", Some("101"), || {
        assert_eq!(super::hevc_jpeg_quality(), 100);
    });

    temp_env::with_var("LESAVKA_UVC_HEVC_JPEG_QUALITY", Some("0"), || {
        assert_eq!(super::hevc_jpeg_quality(), 1);
    });
}

#[test]
fn direct_mjpeg_normalization_defaults_on_and_clamps_tuning() {
    temp_env::with_vars(
        [
            ("LESAVKA_UVC_DIRECT_MJPEG_NORMALIZE", None::<&str>),
            ("LESAVKA_UVC_DIRECT_MJPEG_JPEG_QUALITY", None::<&str>),
            (
                "LESAVKA_UVC_DIRECT_MJPEG_NORMALIZE_PULL_TIMEOUT_MS",
                None::<&str>,
            ),
            (
                "LESAVKA_UVC_DIRECT_MJPEG_NORMALIZE_MISS_LIMIT",
                None::<&str>,
            ),
            (
                "LESAVKA_UVC_DIRECT_MJPEG_NORMALIZE_RSS_LIMIT_MB",
                None::<&str>,
            ),
        ],
        || {
            assert!(super::direct_mjpeg_normalize_enabled());
            assert_eq!(super::direct_mjpeg_jpeg_quality(), 60);
            assert_eq!(super::direct_mjpeg_normalize_pull_timeout_ms(), 0);
            assert_eq!(super::direct_mjpeg_normalize_miss_limit(), 30);
            assert_eq!(
                super::direct_mjpeg_normalize_rss_limit_kb(),
                Some(384 * 1024)
            );
        },
    );

    temp_env::with_vars(
        [
            ("LESAVKA_UVC_DIRECT_MJPEG_NORMALIZE", Some("on")),
            ("LESAVKA_UVC_DIRECT_MJPEG_JPEG_QUALITY", Some("101")),
            (
                "LESAVKA_UVC_DIRECT_MJPEG_NORMALIZE_PULL_TIMEOUT_MS",
                Some("999"),
            ),
            (
                "LESAVKA_UVC_DIRECT_MJPEG_NORMALIZE_MISS_LIMIT",
                Some("999"),
            ),
            (
                "LESAVKA_UVC_DIRECT_MJPEG_NORMALIZE_RSS_LIMIT_MB",
                Some("0"),
            ),
        ],
        || {
            assert!(super::direct_mjpeg_normalize_enabled());
            assert_eq!(super::direct_mjpeg_jpeg_quality(), 100);
            assert_eq!(super::direct_mjpeg_normalize_pull_timeout_ms(), 50);
            assert_eq!(super::direct_mjpeg_normalize_miss_limit(), 300);
            assert_eq!(super::direct_mjpeg_normalize_rss_limit_kb(), None);
        },
    );

    temp_env::with_var("LESAVKA_UVC_DIRECT_MJPEG_JPEG_QUALITY", Some("0"), || {
        assert_eq!(super::direct_mjpeg_jpeg_quality(), 1);
    });

    temp_env::with_var(
        "LESAVKA_UVC_DIRECT_MJPEG_NORMALIZE_MISS_LIMIT",
        Some("0"),
        || {
            assert_eq!(super::direct_mjpeg_normalize_miss_limit(), 1);
        },
    );
}

#[test]
fn freeze_guard_catches_large_decoded_frame_collapses() {
    temp_env::with_vars(
        [
            ("LESAVKA_UVC_HEVC_FREEZE_ON_SIZE_DROP", Some("1")),
            ("LESAVKA_UVC_HEVC_SIZE_DROP_PCT", Some("45")),
            ("LESAVKA_UVC_HEVC_MIN_REFERENCE_BYTES", Some("65536")),
        ],
        || {
            assert!(super::should_freeze_decoded_mjpeg(200_000, 80_000));
            assert!(!super::should_freeze_decoded_mjpeg(200_000, 110_000));
            assert!(!super::should_freeze_decoded_mjpeg(20_000, 1_000));
        },
    );
}

#[test]
fn freeze_guard_can_be_disabled_for_diagnostics() {
    temp_env::with_vars(
        [
            ("LESAVKA_UVC_HEVC_FREEZE_ON_SIZE_DROP", Some("0")),
            ("LESAVKA_UVC_HEVC_SIZE_DROP_PCT", Some("95")),
            ("LESAVKA_UVC_HEVC_MIN_REFERENCE_BYTES", Some("1")),
        ],
        || {
            assert!(!super::should_freeze_decoded_mjpeg(200_000, 1_000));
        },
    );
}

#[test]
/// Verifies flat or incomplete HEVC-decoded MJPEG frames freeze out.
///
/// Inputs: synthetic JPEG-like payloads. Output: assertions only. Why:
/// the source-level guard should keep the same behavior as the root
/// taxonomy tests even when this helper is compiled inside the server crate.
fn freeze_guard_rejects_incomplete_or_flat_decoded_payloads() {
    fn jpeg_with_payload(payload: &[u8]) -> Vec<u8> {
        let mut bytes = vec![0xff, 0xd8, 0xff, 0xda];
        bytes.extend_from_slice(payload);
        bytes.extend_from_slice(&[0xff, 0xd9]);
        bytes
    }

    temp_env::with_vars(
        [
            ("LESAVKA_UVC_HEVC_FREEZE_ON_SIZE_DROP", Some("1")),
            ("LESAVKA_UVC_HEVC_SIZE_DROP_PCT", Some("45")),
            ("LESAVKA_UVC_HEVC_MIN_REFERENCE_BYTES", Some("65536")),
            (
                "LESAVKA_UVC_HEVC_MIN_PAYLOAD_DISTINCT_BYTES",
                Some("12"),
            ),
            ("LESAVKA_UVC_HEVC_DOMINANT_BYTE_PCT", Some("92")),
        ],
        || {
            let healthy_payload: Vec<u8> = (0..120_000).map(|idx| (idx % 251) as u8).collect();
            let flat_payload = vec![0x80; 120_000];
            let mut truncated = jpeg_with_payload(&healthy_payload);
            truncated.pop();

            assert!(!super::should_freeze_decoded_mjpeg_frame(
                200_000,
                &jpeg_with_payload(&healthy_payload),
            ));
            assert_eq!(
                super::decoded_mjpeg_reject_reason(
                    200_000,
                    &jpeg_with_payload(&healthy_payload),
                ),
                None
            );
            assert!(super::should_freeze_decoded_mjpeg_frame(
                200_000,
                &jpeg_with_payload(&flat_payload),
            ));
            assert_eq!(
                super::decoded_mjpeg_reject_reason(200_000, &jpeg_with_payload(&flat_payload)),
                Some(super::DecodedMjpegRejectReason::FlatPayload)
            );
            assert!(super::should_freeze_decoded_mjpeg_frame(
                200_000, &truncated,
            ));
            assert_eq!(
                super::decoded_mjpeg_reject_reason(200_000, &truncated),
                Some(super::DecodedMjpegRejectReason::Incomplete)
            );
            assert!(super::should_freeze_decoded_mjpeg_frame(
                0,
                &jpeg_with_payload(&flat_payload),
            ));
        },
    );
}

#[test]
fn direct_mjpeg_guard_rejects_incomplete_and_obvious_bad_frames_after_baseline() {
    fn jpeg_with_payload(payload: &[u8]) -> Vec<u8> {
        let mut bytes = vec![0xff, 0xd8, 0xff, 0xda];
        bytes.extend_from_slice(payload);
        bytes.extend_from_slice(&[0xff, 0xd9]);
        bytes
    }

    let flat = jpeg_with_payload(&vec![0x80; 120_000]);
    let varied = jpeg_with_payload(&(0..120_000).map(|idx| (idx % 251) as u8).collect::<Vec<_>>());
    let tiny = jpeg_with_payload(&vec![0x42; 4_000]);
    let mut truncated = varied.clone();
    truncated.pop();

    temp_env::with_vars(
        [
            ("LESAVKA_UVC_DIRECT_MJPEG_VISUAL_GUARD", Some("1")),
            ("LESAVKA_UVC_DIRECT_MJPEG_SIZE_DROP_PCT", Some("18")),
            ("LESAVKA_UVC_DIRECT_MJPEG_MIN_REFERENCE_BYTES", Some("49152")),
        ],
        || {
            assert!(!super::should_reject_direct_mjpeg_frame(0, &flat));
            assert!(!super::should_reject_direct_mjpeg_frame(180_000, &varied));
            assert!(super::should_reject_direct_mjpeg_frame(180_000, &flat));
            assert!(super::should_reject_direct_mjpeg_frame(180_000, &tiny));
            assert!(super::should_reject_direct_mjpeg_frame(180_000, &truncated));
        },
    );
}

fn smooth_rgb_frame(width: usize, height: usize) -> Vec<u8> {
    let mut pixels = Vec::with_capacity(width * height * 3);
    for y in 0..height {
        for x in 0..width {
            pixels.push(((x * 180 / width) + 32) as u8);
            pixels.push(((y * 150 / height) + 48) as u8);
            pixels.push((((x + y) * 120 / (width + height)) + 64) as u8);
        }
    }
    pixels
}

fn checker_grid_rgb_frame(width: usize, height: usize) -> Vec<u8> {
    let mut pixels = Vec::with_capacity(width * height * 3);
    for y in 0..height {
        for x in 0..width {
            let block = ((x / 16) + (y / 16)) % 2;
            let base = if block == 0 { 42 } else { 214 };
            pixels.push((base + (x % 17)) as u8);
            pixels.push((base + (y % 19)) as u8);
            pixels.push((base + ((x + y) % 13)) as u8);
        }
    }
    pixels
}

#[test]
/// Verifies smooth camera-like frames are not treated as visual corruption.
fn pixel_guard_accepts_smooth_frames() {
    temp_env::with_vars(
        [
            ("LESAVKA_UVC_MJPEG_PIXEL_GUARD", Some("1")),
            ("LESAVKA_UVC_MJPEG_PIXEL_GUARD_SAMPLE_WIDTH", Some("160")),
        ],
        || {
            let frame = smooth_rgb_frame(320, 180);
            assert_eq!(super::mjpeg_visual_guard::sampled_rgb_frame_for_test(320, 180, &frame), None);
        },
    );
}

#[test]
/// Verifies calibration grids do not look like damaged MJPEG seams.
fn pixel_guard_accepts_regular_synthetic_checker_grids() {
    temp_env::with_vars(
        [
            ("LESAVKA_UVC_MJPEG_PIXEL_GUARD", Some("1")),
            ("LESAVKA_UVC_MJPEG_PIXEL_GUARD_SAMPLE_WIDTH", Some("160")),
            (
                "LESAVKA_UVC_MJPEG_PIXEL_GUARD_PARTIAL_SEAM_DELTA",
                Some("28"),
            ),
            (
                "LESAVKA_UVC_MJPEG_PIXEL_GUARD_PARTIAL_SEAM_COVERAGE_PCT",
                Some("32"),
            ),
            (
                "LESAVKA_UVC_MJPEG_PIXEL_GUARD_PARTIAL_SEAM_RUN_PCT",
                Some("12"),
            ),
        ],
        || {
            let frame = checker_grid_rgb_frame(320, 180);
            assert_eq!(
                super::mjpeg_visual_guard::sampled_rgb_frame_for_test(320, 180, &frame),
                None
            );
        },
    );
}

#[test]
/// Verifies textured scene edges are not misclassified as partial tile tears.
fn pixel_guard_accepts_textured_partial_scene_edges() {
    temp_env::with_vars(
        [
            ("LESAVKA_UVC_MJPEG_PIXEL_GUARD", Some("1")),
            (
                "LESAVKA_UVC_MJPEG_PIXEL_GUARD_PARTIAL_SEAM_DELTA",
                Some("28"),
            ),
            (
                "LESAVKA_UVC_MJPEG_PIXEL_GUARD_PARTIAL_SEAM_COVERAGE_PCT",
                Some("32"),
            ),
            (
                "LESAVKA_UVC_MJPEG_PIXEL_GUARD_PARTIAL_SEAM_RUN_PCT",
                Some("12"),
            ),
            (
                "LESAVKA_UVC_MJPEG_PIXEL_GUARD_PARTIAL_SEAM_BLOCK_STDDEV",
                Some("14"),
            ),
        ],
        || {
            let width = 320;
            let height = 180;
            let mut frame = smooth_rgb_frame(width, height);
            let start_x = width / 4;
            let end_x = start_x + width / 3;
            for y in height / 2..height {
                for x in start_x..end_x {
                    let offset = (y * width + x) * 3;
                    let texture = ((x * 17 + y * 11) % 96) as u8;
                    let value = 56u8.saturating_add(texture);
                    frame[offset] = value;
                    frame[offset + 1] = value.saturating_add((x % 23) as u8);
                    frame[offset + 2] = value.saturating_sub((y % 19) as u8);
                }
            }
            assert_eq!(
                super::mjpeg_visual_guard::sampled_rgb_frame_for_test(width, height, &frame),
                None
            );
        },
    );
}

#[test]
/// Verifies smooth wall plus textured furniture edges are not frozen as tears.
fn pixel_guard_accepts_wall_over_couch_scene_edges() {
    temp_env::with_vars(
        [
            ("LESAVKA_UVC_MJPEG_PIXEL_GUARD", Some("1")),
            (
                "LESAVKA_UVC_MJPEG_PIXEL_GUARD_PARTIAL_SEAM_DELTA",
                Some("28"),
            ),
            (
                "LESAVKA_UVC_MJPEG_PIXEL_GUARD_PARTIAL_SEAM_COVERAGE_PCT",
                Some("32"),
            ),
            (
                "LESAVKA_UVC_MJPEG_PIXEL_GUARD_PARTIAL_SEAM_RUN_PCT",
                Some("12"),
            ),
            (
                "LESAVKA_UVC_MJPEG_PIXEL_GUARD_PARTIAL_SEAM_BLOCK_STDDEV",
                Some("14"),
            ),
        ],
        || {
            let width = 320;
            let height = 180;
            let mut frame = vec![0u8; width * height * 3];
            let seam_y = height.saturating_mul(77) / 100;
            let start_x = width.saturating_mul(61) / 100;
            let end_x = width.saturating_mul(80) / 100;

            for y in 0..height {
                for x in 0..width {
                    let offset = (y * width + x) * 3;
                    if y < seam_y || !(start_x..end_x).contains(&x) {
                        // Keep the wall naturally smooth but not slab-flat; the
                        // regression is specifically about one smooth side plus
                        // one textured side, not about blank-frame detection.
                        let shade = 174u8.saturating_add(((x + y) % 28) as u8);
                        frame[offset] = shade;
                        frame[offset + 1] = shade.saturating_add(6);
                        frame[offset + 2] = shade.saturating_sub(5);
                    } else {
                        let texture = ((x * 23 + y * 17) % 74) as u8;
                        let base = 54u8.saturating_add(texture);
                        frame[offset] = base;
                        frame[offset + 1] = base.saturating_add((x % 27) as u8);
                        frame[offset + 2] = base.saturating_sub((y % 21) as u8);
                    }
                }
            }

            assert_eq!(
                super::mjpeg_visual_guard::sampled_rgb_frame_for_test(width, height, &frame),
                None
            );
        },
    );
}

#[test]
/// Verifies close-up webcam regions are not frozen as damaged gray slabs.
fn pixel_guard_accepts_midframe_flat_camera_regions() {
    temp_env::with_vars(
        [
            ("LESAVKA_UVC_MJPEG_PIXEL_GUARD", Some("1")),
            ("LESAVKA_UVC_MJPEG_PIXEL_GUARD_FLAT_STDDEV", Some("6")),
            ("LESAVKA_UVC_MJPEG_PIXEL_GUARD_FLAT_RUN_PCT", Some("16")),
            ("LESAVKA_UVC_MJPEG_PIXEL_GUARD_FLAT_MIN_START_PCT", Some("45")),
            ("LESAVKA_UVC_MJPEG_PIXEL_GUARD_FLAT_MIN_END_PCT", Some("72")),
        ],
        || {
            let width = 320;
            let height = 180;
            let mut frame = vec![0u8; width * height * 3];
            let band_start = height.saturating_mul(43) / 100;
            let band_end = height.saturating_mul(63) / 100;

            for y in 0..height {
                for x in 0..width {
                    let offset = (y * width + x) * 3;
                    if (band_start..band_end).contains(&y) {
                        frame[offset] = 132;
                        frame[offset + 1] = 132;
                        frame[offset + 2] = 132;
                    } else {
                        let shade = 122u8.saturating_add(((x * 13 + y * 7) % 24) as u8);
                        frame[offset] = shade;
                        frame[offset + 1] = shade.saturating_add((x % 3) as u8);
                        frame[offset + 2] = shade.saturating_sub((y % 3) as u8);
                    }
                }
            }

            assert_eq!(
                super::mjpeg_visual_guard::sampled_rgb_frame_for_test(width, height, &frame),
                None
            );
        },
    );
}

#[test]
/// Verifies low-detail gray slabs freeze out before UVC handoff.
fn pixel_guard_rejects_flat_lower_block_frames() {
    temp_env::with_vars(
        [
            ("LESAVKA_UVC_MJPEG_PIXEL_GUARD", Some("1")),
            ("LESAVKA_UVC_MJPEG_PIXEL_GUARD_FLAT_STDDEV", Some("6")),
            ("LESAVKA_UVC_MJPEG_PIXEL_GUARD_FLAT_RUN_PCT", Some("16")),
        ],
        || {
            let width = 320;
            let height = 180;
            let mut frame = smooth_rgb_frame(width, height);
            for y in height / 2..height {
                for x in 0..width {
                    let offset = (y * width + x) * 3;
                    frame[offset] = 128;
                    frame[offset + 1] = 128;
                    frame[offset + 2] = 128;
                }
            }
            assert!(matches!(
                super::mjpeg_visual_guard::sampled_rgb_frame_for_test(width, height, &frame),
                Some(super::mjpeg_visual_guard::MjpegVisualArtifactReason::FlatBlock { .. })
            ));
        },
    );
}

#[test]
/// Verifies broad horizontal tile seams are detected.
fn pixel_guard_rejects_rectangular_tile_seams() {
    temp_env::with_vars(
        [
            ("LESAVKA_UVC_MJPEG_PIXEL_GUARD", Some("1")),
            ("LESAVKA_UVC_MJPEG_PIXEL_GUARD_SEAM_DELTA", Some("28")),
            (
                "LESAVKA_UVC_MJPEG_PIXEL_GUARD_SEAM_COVERAGE_PCT",
                Some("35"),
            ),
        ],
        || {
            let width = 320;
            let height = 180;
            let mut frame = smooth_rgb_frame(width, height);
            for y in height / 2..height {
                for x in 0..width {
                    let offset = (y * width + x) * 3;
                    if x < width / 2 {
                        frame[offset] = 42;
                        frame[offset + 1] = 96;
                        frame[offset + 2] = 124;
                    } else {
                        frame[offset] = 220;
                        frame[offset + 1] = 178;
                        frame[offset + 2] = 132;
                    }
                }
            }
            assert!(matches!(
                super::mjpeg_visual_guard::sampled_rgb_frame_for_test(width, height, &frame),
                Some(
                    super::mjpeg_visual_guard::MjpegVisualArtifactReason::HorizontalTileSeam { .. }
                        | super::mjpeg_visual_guard::MjpegVisualArtifactReason::PartialTileSeam { .. }
                        | super::mjpeg_visual_guard::MjpegVisualArtifactReason::ChromaTileSeam { .. }
                )
            ));
        },
    );
}

#[test]
/// Verifies partial-width tile tears are detected.
fn pixel_guard_rejects_partial_width_tile_seams() {
    temp_env::with_vars(
        [
            ("LESAVKA_UVC_MJPEG_PIXEL_GUARD", Some("1")),
            (
                "LESAVKA_UVC_MJPEG_PIXEL_GUARD_PARTIAL_SEAM_DELTA",
                Some("28"),
            ),
            (
                "LESAVKA_UVC_MJPEG_PIXEL_GUARD_PARTIAL_SEAM_COVERAGE_PCT",
                Some("32"),
            ),
            (
                "LESAVKA_UVC_MJPEG_PIXEL_GUARD_PARTIAL_SEAM_RUN_PCT",
                Some("12"),
            ),
        ],
        || {
            let width = 320;
            let height = 180;
            let mut frame = smooth_rgb_frame(width, height);
            for y in height / 2..height {
                for x in width / 4..(width / 4 + width / 3) {
                    let offset = (y * width + x) * 3;
                    frame[offset] = 28;
                    frame[offset + 1] = 82;
                    frame[offset + 2] = 130;
                }
            }
            assert!(matches!(
                super::mjpeg_visual_guard::sampled_rgb_frame_for_test(width, height, &frame),
                Some(super::mjpeg_visual_guard::MjpegVisualArtifactReason::PartialTileSeam { .. })
            ));
        },
    );
}

#[test]
/// Verifies chroma-only tile shifts are detected.
fn pixel_guard_rejects_chroma_shifted_tile_seams() {
    temp_env::with_vars(
        [
            ("LESAVKA_UVC_MJPEG_PIXEL_GUARD", Some("1")),
            ("LESAVKA_UVC_MJPEG_PIXEL_GUARD_CHROMA_DELTA", Some("18")),
            (
                "LESAVKA_UVC_MJPEG_PIXEL_GUARD_CHROMA_COVERAGE_PCT",
                Some("30"),
            ),
        ],
        || {
            let width = 320;
            let height = 180;
            let mut frame = smooth_rgb_frame(width, height);
            for y in height / 2..height {
                for x in 0..width {
                    let offset = (y * width + x) * 3;
                    frame[offset] = 120u8.saturating_add((x % 90) as u8);
                    frame[offset + 1] = 20u8.saturating_add((y % 36) as u8);
                    frame[offset + 2] = 210u8.saturating_sub((x % 100) as u8);
                }
            }
            assert!(matches!(
                super::mjpeg_visual_guard::sampled_rgb_frame_for_test(width, height, &frame),
                Some(super::mjpeg_visual_guard::MjpegVisualArtifactReason::ChromaTileSeam { .. })
            ));
        },
    );
}

#[test]
fn direct_mjpeg_guard_reports_oversize_and_profile_mismatch_when_configured() {
    fn jpeg_with_sof(width: u16, height: u16, payload: &[u8]) -> Vec<u8> {
        let mut bytes = vec![
            0xff, 0xd8, // SOI
            0xff, 0xc0, 0x00, 0x11, 0x08, // SOF0 len + precision
            (height >> 8) as u8,
            height as u8,
            (width >> 8) as u8,
            width as u8,
            0x03, 0x01, 0x11, 0x00, 0x02, 0x11, 0x00, 0x03, 0x11, 0x00,
            0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x3f, 0x00,
        ];
        bytes.extend_from_slice(payload);
        bytes.extend_from_slice(&[0xff, 0xd9]);
        bytes
    }

    let healthy_payload: Vec<u8> = (0..8_000).map(|idx| (idx % 251) as u8).collect();
    let frame = jpeg_with_sof(1920, 1080, &healthy_payload);
    let inspection = super::inspect_mjpeg_frame(&frame);
    assert_eq!(inspection.width, Some(1920));
    assert_eq!(inspection.height, Some(1080));
    assert!(inspection.entropy_distinct_bytes > 64);

    temp_env::with_var_unset("LESAVKA_UVC_DIRECT_MJPEG_REJECT_PROFILE_MISMATCH", || {
        assert_eq!(
            super::direct_mjpeg_reject_reason(0, Some(frame.len() + 1), Some((1280, 720)), &frame),
            Some(super::DirectMjpegRejectReason::ProfileMismatch {
                expected_width: 1280,
                expected_height: 720,
                actual_width: 1920,
                actual_height: 1080,
            })
        );
    });
    temp_env::with_var(
        "LESAVKA_UVC_DIRECT_MJPEG_REJECT_PROFILE_MISMATCH",
        Some("0"),
        || {
            assert_eq!(
                super::direct_mjpeg_reject_reason(0, Some(frame.len() + 1), Some((1280, 720)), &frame),
                None
            );
        },
    );

    assert_eq!(
        super::direct_mjpeg_reject_reason(0, Some(frame.len() - 1), Some((1920, 1080)), &frame),
        Some(super::DirectMjpegRejectReason::Oversized {
            max_bytes: frame.len() - 1,
        })
    );
}

#[test]
fn direct_mjpeg_visual_guard_can_be_disabled_without_allowing_truncation() {
    let mut complete = vec![0xff, 0xd8, 0xff, 0xda];
    complete.extend_from_slice(&vec![0x80; 120_000]);
    complete.extend_from_slice(&[0xff, 0xd9]);
    let mut truncated = complete.clone();
    truncated.pop();

    temp_env::with_var("LESAVKA_UVC_DIRECT_MJPEG_VISUAL_GUARD", Some("0"), || {
        assert!(!super::should_reject_direct_mjpeg_frame(180_000, &complete));
        assert!(super::should_reject_direct_mjpeg_frame(180_000, &truncated));
    });
}
