jay-compositor 1.15.0

The Jay compositor
use crate::it::test_client::TestClientExt;
use crate::it::test_error::TestResult;
use crate::it::testrun::TestRun;
use std::rc::Rc;

testcase!();

/// Test that committing damage on a visible surface causes the backend connector to be damaged.
/// This test verifies that surface damage triggers backend connector damage tracking AND
/// that the frontend actually calls into the backend connector's damage method,
/// ensuring the rendering pipeline knows when to update the display.
async fn test(run: Rc<TestRun>) -> TestResult {
    run.backend.install_default().await?;
    let client = run.create_client()?;

    // Get connector for tracking backend damage state
    let connector_id = run.backend.default_connector.id;
    let connector_data = run.state.connectors.get(&connector_id).unwrap();

    // Create a visible window with mapped surface
    let window = client.create_window().await?;
    let buffer = client.create_single_pixel_buffer(crate::theme::Color::from_srgb(0, 255, 0));
    window.surface.attach(buffer.id);
    window.map().await?;
    client.sync().await;

    // Test 1: Ensure initially the backend is not damaged
    connector_data.damaged.set(false);
    run.backend.default_connector.damage_calls.set(0);
    tassert!(!connector_data.damaged.get());
    tassert_eq!(run.backend.default_connector.damage_calls.get(), 0);

    // Test 2: Add surface damage and commit - this should trigger backend connector damage
    window.surface.damage(10, 10, 50, 50);
    window.surface.commit();
    client.sync().await;

    // Critical test: Verify the backend connector is now damaged AND the backend method was called
    tassert!(connector_data.damaged.get());
    tassert!(run.backend.default_connector.damage_calls.get() > 0);

    // Test 3: Reset damage state and test buffer damage
    connector_data.damaged.set(false);
    let previous_calls = run.backend.default_connector.damage_calls.get();
    tassert!(!connector_data.damaged.get());

    // Add buffer damage and commit - this should also trigger backend connector damage
    window.surface.damage_buffer(0, 0, 1, 1); // Damage entire 1x1 buffer
    window.surface.commit();
    client.sync().await;

    // Verify the backend connector is damaged again AND more backend calls were made
    tassert!(connector_data.damaged.get());
    tassert!(run.backend.default_connector.damage_calls.get() > previous_calls);

    // Test 4: Test that invisible surfaces do not trigger backend damage
    let invisible_surface = client.create_surface().await?;
    let invisible_buffer =
        client.create_single_pixel_buffer(crate::theme::Color::from_srgb(255, 255, 0));
    invisible_surface.attach(invisible_buffer.id);
    invisible_surface.commit(); // Initial commit to attach buffer
    client.sync().await;

    // Reset damage state
    connector_data.damaged.set(false);
    let invisible_calls_before = run.backend.default_connector.damage_calls.get();
    tassert!(!connector_data.damaged.get());

    // Add damage to invisible surface and commit
    invisible_surface.damage(20, 20, 30, 30);
    invisible_surface.commit();
    client.sync().await;

    // Invisible surface damage should NOT trigger backend connector damage or backend calls
    tassert!(!connector_data.damaged.get());
    tassert_eq!(
        run.backend.default_connector.damage_calls.get(),
        invisible_calls_before
    );

    // Test 5: Test multiple damage areas on visible surface
    connector_data.damaged.set(false);
    let multi_calls_before = run.backend.default_connector.damage_calls.get();
    tassert!(!connector_data.damaged.get());

    // Add multiple damage rectangles to visible surface
    window.surface.damage(5, 5, 10, 10);
    window.surface.damage(25, 25, 15, 15);
    window.surface.damage_buffer(0, 0, 1, 1);
    window.surface.commit();
    client.sync().await;

    // Multiple damage areas on visible surface should trigger backend connector damage and calls
    tassert!(connector_data.damaged.get());
    tassert!(run.backend.default_connector.damage_calls.get() > multi_calls_before);

    // Test 6: Test that damage without commit does not trigger backend damage
    connector_data.damaged.set(false);
    let no_commit_calls_before = run.backend.default_connector.damage_calls.get();
    tassert!(!connector_data.damaged.get());

    // Add damage but don't commit
    window.surface.damage(40, 40, 20, 20);
    client.sync().await;

    // Damage without commit should NOT trigger backend connector damage or backend calls
    tassert!(!connector_data.damaged.get());
    tassert_eq!(
        run.backend.default_connector.damage_calls.get(),
        no_commit_calls_before
    );

    // Now commit the pending damage
    window.surface.commit();
    client.sync().await;

    // After commit, backend connector should be damaged and backend called
    tassert!(connector_data.damaged.get());
    tassert!(run.backend.default_connector.damage_calls.get() > no_commit_calls_before);

    Ok(())
}