mirror of
https://github.com/hyprwm/Hyprland
synced 2026-05-07 03:38:00 +02:00
tests: add unit tests for CDamageRing (#13995)
Adds GTest unit tests for CDamageRing in src/helpers/DamageRing.hpp.
Covers:
- setSize: initial full damage, same-size no-op, resize re-damage, zero-size
- damage: in-bounds accept, empty/out-of-bounds reject, partial clip
- damageEntire: normal path and zero-size no-op
- rotate: clears current, preserves as previous, wraps beyond ring length
- getBufferDamage: age<=0 and age>ring return full screen, age=1 current only,
age=2 accumulates previous, full ring accumulation, coalescing fallback,
empty ring returns empty
- hasChanged: false initially, true after damage/damageEntire, false after
rotate, false for out-of-bounds damage
27 new test cases, all passing.
This commit is contained in:
parent
3af9b10890
commit
d7edc50eb4
1 changed files with 313 additions and 0 deletions
313
tests/helpers/DamageRing.cpp
Normal file
313
tests/helpers/DamageRing.cpp
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
#include <helpers/DamageRing.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// --- setSize ---
|
||||
|
||||
TEST(DamageRing, setSizeMarksDamageEntire) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({100, 200});
|
||||
|
||||
// After setSize the entire screen should be damaged
|
||||
EXPECT_TRUE(ring.hasChanged());
|
||||
}
|
||||
|
||||
TEST(DamageRing, setSizeSameSizeNoChange) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({100, 200});
|
||||
ring.rotate(); // clear current damage
|
||||
|
||||
// Setting same size again must not re-damage
|
||||
ring.setSize({100, 200});
|
||||
EXPECT_FALSE(ring.hasChanged());
|
||||
}
|
||||
|
||||
TEST(DamageRing, setSizeNewSizeReDamages) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({100, 200});
|
||||
ring.rotate(); // clear current damage
|
||||
|
||||
ring.setSize({300, 400});
|
||||
EXPECT_TRUE(ring.hasChanged());
|
||||
}
|
||||
|
||||
TEST(DamageRing, setSizeZeroSize) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({0, 0});
|
||||
|
||||
// Zero-size screen: damageEntire covers a 0x0 box, which is empty
|
||||
EXPECT_FALSE(ring.hasChanged());
|
||||
}
|
||||
|
||||
// --- damage ---
|
||||
|
||||
TEST(DamageRing, damageReturnsTrueForRegionInsideSize) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({200, 200});
|
||||
ring.rotate(); // clear current damage
|
||||
|
||||
CRegion rg(10, 10, 50, 50);
|
||||
EXPECT_TRUE(ring.damage(rg));
|
||||
}
|
||||
|
||||
TEST(DamageRing, damageReturnsFalseForEmptyRegion) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({200, 200});
|
||||
ring.rotate();
|
||||
|
||||
CRegion empty;
|
||||
EXPECT_FALSE(ring.damage(empty));
|
||||
}
|
||||
|
||||
TEST(DamageRing, damageReturnsFalseForRegionOutsideSize) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({100, 100});
|
||||
ring.rotate();
|
||||
|
||||
// Region entirely outside the screen bounds
|
||||
CRegion outside(200, 200, 50, 50);
|
||||
EXPECT_FALSE(ring.damage(outside));
|
||||
}
|
||||
|
||||
TEST(DamageRing, damageClipsRegionToSize) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({100, 100});
|
||||
ring.rotate();
|
||||
|
||||
// Region that partially overlaps the screen
|
||||
CRegion partial(50, 50, 200, 200);
|
||||
EXPECT_TRUE(ring.damage(partial));
|
||||
EXPECT_TRUE(ring.hasChanged());
|
||||
}
|
||||
|
||||
TEST(DamageRing, damageSetsHasChanged) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({200, 200});
|
||||
ring.rotate();
|
||||
|
||||
EXPECT_FALSE(ring.hasChanged());
|
||||
|
||||
CRegion rg(0, 0, 10, 10);
|
||||
ring.damage(rg);
|
||||
EXPECT_TRUE(ring.hasChanged());
|
||||
}
|
||||
|
||||
// --- damageEntire ---
|
||||
|
||||
TEST(DamageRing, damageEntireSetsHasChanged) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({200, 200});
|
||||
ring.rotate();
|
||||
|
||||
EXPECT_FALSE(ring.hasChanged());
|
||||
ring.damageEntire();
|
||||
EXPECT_TRUE(ring.hasChanged());
|
||||
}
|
||||
|
||||
TEST(DamageRing, damageEntireOnZeroSizeDoesNotSetHasChanged) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({0, 0});
|
||||
ring.rotate();
|
||||
|
||||
ring.damageEntire();
|
||||
EXPECT_FALSE(ring.hasChanged());
|
||||
}
|
||||
|
||||
// --- rotate ---
|
||||
|
||||
TEST(DamageRing, rotateClearsCurrentDamage) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({200, 200});
|
||||
// setSize already damaged; rotate should clear it
|
||||
ring.rotate();
|
||||
EXPECT_FALSE(ring.hasChanged());
|
||||
}
|
||||
|
||||
TEST(DamageRing, rotatePreservesCurrentAsPreviousForNextFrame) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({200, 200});
|
||||
ring.rotate(); // clear initial damage
|
||||
|
||||
CRegion rg(0, 0, 50, 50);
|
||||
ring.damage(rg);
|
||||
ring.rotate(); // the damage just applied becomes "previous[0]"
|
||||
|
||||
// With age=2 we should see that previous damage accumulated
|
||||
CRegion bufDamage = ring.getBufferDamage(2);
|
||||
EXPECT_FALSE(bufDamage.empty());
|
||||
}
|
||||
|
||||
TEST(DamageRing, rotateMultipleTimes) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({200, 200});
|
||||
|
||||
// Rotate more times than the ring length — must not crash
|
||||
for (int i = 0; i < DAMAGE_RING_PREVIOUS_LEN + 5; ++i) {
|
||||
ring.damageEntire();
|
||||
ring.rotate();
|
||||
}
|
||||
EXPECT_FALSE(ring.hasChanged());
|
||||
}
|
||||
|
||||
// --- getBufferDamage ---
|
||||
|
||||
TEST(DamageRing, getBufferDamageAge0ReturnsFullScreen) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({100, 100});
|
||||
ring.rotate();
|
||||
|
||||
// age <= 0 returns full screen
|
||||
CRegion full = ring.getBufferDamage(0);
|
||||
EXPECT_FALSE(full.empty());
|
||||
}
|
||||
|
||||
TEST(DamageRing, getBufferDamageNegativeAgeReturnsFullScreen) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({100, 100});
|
||||
ring.rotate();
|
||||
|
||||
CRegion full = ring.getBufferDamage(-1);
|
||||
EXPECT_FALSE(full.empty());
|
||||
}
|
||||
|
||||
TEST(DamageRing, getBufferDamageExceedsRingLengthReturnsFullScreen) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({100, 100});
|
||||
ring.rotate();
|
||||
|
||||
// age > DAMAGE_RING_PREVIOUS_LEN + 1 returns full screen
|
||||
CRegion full = ring.getBufferDamage(DAMAGE_RING_PREVIOUS_LEN + 2);
|
||||
EXPECT_FALSE(full.empty());
|
||||
}
|
||||
|
||||
TEST(DamageRing, getBufferDamageAge1ReturnCurrentOnly) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({200, 200});
|
||||
ring.rotate();
|
||||
|
||||
EXPECT_TRUE(ring.getBufferDamage(1).empty());
|
||||
|
||||
CRegion rg(10, 10, 20, 20);
|
||||
ring.damage(rg);
|
||||
EXPECT_FALSE(ring.getBufferDamage(1).empty());
|
||||
}
|
||||
|
||||
TEST(DamageRing, getBufferDamageAge2AccumulatesOnePreviousFrame) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({200, 200});
|
||||
ring.rotate();
|
||||
|
||||
// Frame N: damage a region, then rotate
|
||||
CRegion rg(0, 0, 30, 30);
|
||||
ring.damage(rg);
|
||||
ring.rotate();
|
||||
|
||||
// Frame N+1: no new damage
|
||||
// age=2 should include previous frame's damage
|
||||
CRegion buf = ring.getBufferDamage(2);
|
||||
EXPECT_FALSE(buf.empty());
|
||||
}
|
||||
|
||||
TEST(DamageRing, getBufferDamageAccumulatesUpToRingLength) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({200, 200});
|
||||
ring.rotate();
|
||||
|
||||
// Fill the ring with damage then check full accumulation
|
||||
for (int i = 0; i < DAMAGE_RING_PREVIOUS_LEN; ++i) {
|
||||
CRegion rg(i * 10, 0, 5, 5);
|
||||
ring.damage(rg);
|
||||
ring.rotate();
|
||||
}
|
||||
|
||||
// age = DAMAGE_RING_PREVIOUS_LEN + 1 accumulates all stored frames
|
||||
CRegion buf = ring.getBufferDamage(DAMAGE_RING_PREVIOUS_LEN + 1);
|
||||
EXPECT_FALSE(buf.empty());
|
||||
}
|
||||
|
||||
TEST(DamageRing, getBufferDamageCoalescesWhenTooManyRects) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({500, 500});
|
||||
ring.rotate();
|
||||
|
||||
// Add many non-overlapping rects across several frames so that
|
||||
// accumulation produces more than 8 rectangles, triggering the
|
||||
// getExtents() fallback path.
|
||||
int x = 0;
|
||||
for (int frame = 0; frame < DAMAGE_RING_PREVIOUS_LEN; ++frame) {
|
||||
for (int r = 0; r < 4; ++r) {
|
||||
ring.damage(CRegion(x, 0, 5, 5));
|
||||
x += 10;
|
||||
}
|
||||
ring.rotate();
|
||||
}
|
||||
|
||||
// Current frame damage
|
||||
ring.damage(CRegion(x, 0, 5, 5));
|
||||
|
||||
// age = DAMAGE_RING_PREVIOUS_LEN + 1 accumulates all frames
|
||||
CRegion buf = ring.getBufferDamage(DAMAGE_RING_PREVIOUS_LEN + 1);
|
||||
EXPECT_FALSE(buf.empty());
|
||||
|
||||
// The result should be coalesced into a single extents rect (<=1 rect)
|
||||
EXPECT_LE(buf.getRects().size(), 1);
|
||||
}
|
||||
|
||||
TEST(DamageRing, getBufferDamageEmptyRingReturnsEmptyForValidAge) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({200, 200});
|
||||
|
||||
// Rotate enough times to clear all previous slots
|
||||
for (int i = 0; i < DAMAGE_RING_PREVIOUS_LEN + 1; ++i)
|
||||
ring.rotate();
|
||||
|
||||
// No damage in any slot
|
||||
CRegion buf = ring.getBufferDamage(1);
|
||||
EXPECT_TRUE(buf.empty());
|
||||
}
|
||||
|
||||
// --- hasChanged ---
|
||||
|
||||
TEST(DamageRing, hasChangedFalseInitially) {
|
||||
CDamageRing ring;
|
||||
// No size set, no damage applied
|
||||
EXPECT_FALSE(ring.hasChanged());
|
||||
}
|
||||
|
||||
TEST(DamageRing, hasChangedTrueAfterDamage) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({100, 100});
|
||||
ring.rotate();
|
||||
|
||||
CRegion rg(0, 0, 10, 10);
|
||||
ring.damage(rg);
|
||||
EXPECT_TRUE(ring.hasChanged());
|
||||
}
|
||||
|
||||
TEST(DamageRing, hasChangedFalseAfterRotate) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({100, 100});
|
||||
// setSize caused damage; rotate clears it
|
||||
ring.rotate();
|
||||
EXPECT_FALSE(ring.hasChanged());
|
||||
}
|
||||
|
||||
TEST(DamageRing, hasChangedTrueAfterDamageEntire) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({100, 100});
|
||||
ring.rotate();
|
||||
|
||||
ring.damageEntire();
|
||||
EXPECT_TRUE(ring.hasChanged());
|
||||
}
|
||||
|
||||
TEST(DamageRing, hasChangedFalseAfterDamageOutsideBounds) {
|
||||
CDamageRing ring;
|
||||
ring.setSize({100, 100});
|
||||
ring.rotate();
|
||||
|
||||
// Damage entirely outside the screen must not change state
|
||||
CRegion outside(500, 500, 10, 10);
|
||||
ring.damage(outside);
|
||||
EXPECT_FALSE(ring.hasChanged());
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue