From 6c4f7e9d6639bdc4e3ca76121965132d51bd08f2 Mon Sep 17 00:00:00 2001 From: Adam Heinermann Date: Sun, 31 Aug 2025 01:01:05 -0700 Subject: [PATCH] chore(region): add several more edge case tests --- test/Region.cpp | 248 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 247 insertions(+), 1 deletion(-) diff --git a/test/Region.cpp b/test/Region.cpp index e700f72..8a9241d 100644 --- a/test/Region.cpp +++ b/test/Region.cpp @@ -1,4 +1,5 @@ #include "RegionTest.hpp" +#include TEST_CASE("SRgnClear", "[region]") { @@ -67,6 +68,11 @@ TEST_CASE("SRgnCombineRectf", "[region]") { RECTF baseRect = { 0.0f, 0.0f, 1.0f, 1.0f }; RECTF testRect = { 0.5f, 0.6f, 1.8f, 1.4f }; + SECTION("does nothing with an invalid region object") { + HSRGN inval = reinterpret_cast(1234); + SRgnCombineRectf(inval, &baseRect, nullptr, SRGN_OR); + } + SECTION("combines the region with a single given rect 1") { SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); @@ -133,6 +139,78 @@ TEST_CASE("SRgnCombineRectf", "[region]") { CHECK_THAT(buffer[2], MatchesRect({ 0.5f, 1.0f, 1.8f, 1.4f })); } + SECTION("OR operation on self does nothing") { + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + + uint32_t numRects = 1; + RECTF buffer[1]; + SRgnGetRectsf(region, &numRects, buffer); + + CHECK(numRects == 1); + CHECK_THAT(buffer[0], MatchesRect({ 0.0f, 0.0f, 1.0f, 1.0f })); + } + + SECTION("OR operation merges vertical rects") { + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + RECTF rect2 = { 0.0f, 2.0f, 1.0f, 3.0f}; + RECTF rect3 = { 0.0f, 1.0f, 1.0f, 2.0f}; + SRgnCombineRectf(region, &rect3, nullptr, SRGN_OR); + SRgnCombineRectf(region, &rect2, nullptr, SRGN_OR); + + uint32_t numRects = 1; + RECTF buffer[1]; + SRgnGetRectsf(region, &numRects, buffer); + + CHECK(numRects == 1); + CHECK_THAT(buffer[0], MatchesRect({ 0.0f, 0.0f, 1.0f, 3.0f })); + } + + SECTION("OR operation merges vertical rects 2") { + RECTF rect2 = { 0.0f, 2.0f, 1.0f, 3.0f}; + RECTF rect3 = { 0.0f, 1.0f, 1.0f, 2.0f}; + SRgnCombineRectf(region, &rect3, nullptr, SRGN_OR); + SRgnCombineRectf(region, &rect2, nullptr, SRGN_OR); + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + + uint32_t numRects = 1; + RECTF buffer[1]; + SRgnGetRectsf(region, &numRects, buffer); + + CHECK(numRects == 1); + CHECK_THAT(buffer[0], MatchesRect({ 0.0f, 0.0f, 1.0f, 3.0f })); + } + + SECTION("OR operation merges horizontal rects") { + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + RECTF rect2 = { 2.0f, 0.0f, 3.0f, 1.0f}; + RECTF rect3 = { 1.0f, 0.0f, 2.0f, 1.0f}; + SRgnCombineRectf(region, &rect3, nullptr, SRGN_OR); + SRgnCombineRectf(region, &rect2, nullptr, SRGN_OR); + + uint32_t numRects = 1; + RECTF buffer[1]; + SRgnGetRectsf(region, &numRects, buffer); + + CHECK(numRects == 1); + CHECK_THAT(buffer[0], MatchesRect({ 0.0f, 0.0f, 3.0f, 1.0f })); + } + + SECTION("OR operation merges horizontal rects 2") { + RECTF rect2 = { 2.0f, 0.0f, 3.0f, 1.0f}; + RECTF rect3 = { 1.0f, 0.0f, 2.0f, 1.0f}; + SRgnCombineRectf(region, &rect3, nullptr, SRGN_OR); + SRgnCombineRectf(region, &rect2, nullptr, SRGN_OR); + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + + uint32_t numRects = 1; + RECTF buffer[1]; + SRgnGetRectsf(region, &numRects, buffer); + + CHECK(numRects == 1); + CHECK_THAT(buffer[0], MatchesRect({ 0.0f, 0.0f, 3.0f, 1.0f })); + } + SECTION("AND operation intersects rects") { SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); SRgnCombineRectf(region, &testRect, nullptr, SRGN_AND); @@ -152,6 +230,18 @@ TEST_CASE("SRgnCombineRectf", "[region]") { CHECK_THAT(buffer[0], MatchesRect({ 0.5f, 0.6f, 1.0f, 1.0f })); } + SECTION("AND operation on self does nothing") { + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_AND); + + uint32_t numRects = 1; + RECTF buffer[1]; + SRgnGetRectsf(region, &numRects, buffer); + + CHECK(numRects == 1); + CHECK_THAT(buffer[0], MatchesRect({ 0.0f, 0.0f, 1.0f, 1.0f })); + } + SECTION("XOR operation takes exclusive differences of rects") { SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); SRgnCombineRectf(region, &testRect, nullptr, SRGN_XOR); @@ -174,6 +264,16 @@ TEST_CASE("SRgnCombineRectf", "[region]") { CHECK_THAT(buffer[3], MatchesRect({ 0.5f, 1.0f, 1.8f, 1.4f })); } + SECTION("XOR operation on self erases rect") { + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_XOR); + + uint32_t numRects = 1; + SRgnGetRectsf(region, &numRects, nullptr); + + CHECK(numRects == 0); + } + SECTION("DIFF operation removes parts of rects") { SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); SRgnCombineRectf(region, &testRect, nullptr, SRGN_DIFF); @@ -194,6 +294,16 @@ TEST_CASE("SRgnCombineRectf", "[region]") { CHECK_THAT(buffer[1], MatchesRect({ 0.0f, 0.6f, 0.5f, 1.0f })); } + SECTION("DIFF operation on self erases rect") { + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_DIFF); + + uint32_t numRects = 1; + SRgnGetRectsf(region, &numRects, nullptr); + + CHECK(numRects == 0); + } + SECTION("COPY operation splits intersecting rects") { SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); SRgnCombineRectf(region, &testRect, nullptr, SRGN_COPY); @@ -235,6 +345,18 @@ TEST_CASE("SRgnCombineRectf", "[region]") { CHECK_THAT(buffer[2], MatchesRect({ 0.0f, 0.6f, 1.0f, 1.0f })); } + SECTION("COPY operation on self does nothing") { + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_COPY); + + uint32_t numRects = 1; + RECTF buffer[1]; + SRgnGetRectsf(region, &numRects, buffer); + + CHECK(numRects == 1); + CHECK_THAT(buffer[0], MatchesRect({ 0.0f, 0.0f, 1.0f, 1.0f })); + } + SECTION("operation doesn't work when operating rect width or height is <= 0") { int32_t combineMode = GENERATE(SRGN_OR, SRGN_XOR, SRGN_DIFF, SRGN_COPY, SRGN_PARAMONLY); RECTF testRects = GENERATE( @@ -350,7 +472,7 @@ TEST_CASE("SRgnDuplicate", "[region]") { CHECK_THAT(buffer[0], MatchesRect(baseRect)); } - SECTION("copies parms") { + SECTION("copies params") { SRgnCombineRectf(region, &baseRect, &baseRect, SRGN_PARAMONLY); uint32_t numParams = 2; @@ -382,6 +504,59 @@ TEST_CASE("SRgnDuplicate", "[region]") { } } +TEST_CASE("SRgnGetBoundingRectf", "[region]") { + RgnDataTest region; + RECTF result = {}; + RECTF baseRect = { 0.0f, 0.0f, 1.0f, 1.0f }; + + SECTION("returns null rect when there are no rects") { + // make the result dirty so we test it being set + result = { 123, 456, 666, 9 }; + + SRgnGetBoundingRectf(region, &result); + CHECK_THAT(result, MatchesRect({ 0, 0, 0, 0 })); + } + + SECTION("returns invalid rect when using an invalid region object") { + HSRGN inval = reinterpret_cast(1234); + + SRgnGetBoundingRectf(inval, &result); + CHECK_THAT(result, MatchesRect({ FLT_MAX, FLT_MAX, FLT_MIN, FLT_MIN })); + } + + SECTION("returns the dimensions of 1 rect") { + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + + SRgnGetBoundingRectf(region, &result); + CHECK_THAT(result, MatchesRect({ 0.0f, 0.0f, 1.0f, 1.0f })); + } + + SECTION("returns the combined dimensions of multiple rects") { + RECTF testRect = { 0.5f, 0.5f, 1.5f, 1.5f }; + RECTF testRect2 = { -0.5f, -0.5f, 0.5f, 0.5f }; + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + SRgnCombineRectf(region, &testRect, nullptr, SRGN_OR); + + SRgnGetBoundingRectf(region, &result); + CHECK_THAT(result, MatchesRect({ 0.0f, 0.0f, 1.5f, 1.5f })); + + SRgnCombineRectf(region, &testRect2, nullptr, SRGN_OR); + + SRgnGetBoundingRectf(region, &result); + CHECK_THAT(result, MatchesRect({ -0.5f, -0.5f, 1.5f, 1.5f })); + } + + SECTION("excludes param rects") { + RECTF testRect = { 0.5f, 0.5f, 1.5f, 1.5f }; + int param1 = 0; + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + SRgnCombineRectf(region, &testRect, ¶m1, SRGN_PARAMONLY); + + SRgnGetBoundingRectf(region, &result); + CHECK_THAT(result, MatchesRect({ 0.0f, 0.0f, 1.0f, 1.0f })); + } +} + TEST_CASE("SRgnGetRectParamsf", "[region]") { RgnDataTest region; @@ -428,6 +603,71 @@ TEST_CASE("SRgnGetRectParamsf", "[region]") { CHECK(buffer[0] == ¶m2); CHECK(buffer[1] == ¶m3); } + + SECTION("can have multiple params for same rect") { + RECTF rect1 = { 0, 0, 1, 1 }; + RECTF queryRect = { 0, 0, 1, 1 }; + int param1 = 5; + int param2 = 8; + + SRgnCombineRectf(region, &rect1, ¶m1, SRGN_PARAMONLY); + SRgnCombineRectf(region, &rect1, ¶m2, SRGN_PARAMONLY); + + uint32_t numParams = 0; + SRgnGetRectParamsf(region, &queryRect, &numParams, nullptr); + REQUIRE(numParams == 2); + + void* buffer[2]; + SRgnGetRectParamsf(region, &queryRect, &numParams, buffer); + CHECK(numParams == 2); + CHECK(buffer[0] == ¶m1); + CHECK(buffer[1] == ¶m2); + } + + SECTION("can duplicate the same param") { + RECTF rect1 = { 0, 0, 1, 1 }; + RECTF queryRect = { 0, 0, 1, 1 }; + int param1 = 5; + + SRgnCombineRectf(region, &rect1, ¶m1, SRGN_PARAMONLY); + SRgnCombineRectf(region, &rect1, ¶m1, SRGN_PARAMONLY); + + uint32_t numParams = 0; + SRgnGetRectParamsf(region, &queryRect, &numParams, nullptr); + REQUIRE(numParams == 2); + + void* buffer[2]; + SRgnGetRectParamsf(region, &queryRect, &numParams, buffer); + CHECK(numParams == 2); + CHECK(buffer[0] == ¶m1); + CHECK(buffer[1] == ¶m1); + } + + SECTION("orders params by sequence") { + RECTF rect1 = { 0, 0, 1, 1 }; + RECTF queryRect = { 0, 0, 1, 1 }; + int param1 = 11; + int param2 = 10; + int param3 = 5; + int param4 = 55; + + SRgnCombineRectf(region, &rect1, ¶m1, SRGN_PARAMONLY); + SRgnCombineRectf(region, &rect1, ¶m2, SRGN_PARAMONLY); + SRgnCombineRectf(region, &rect1, ¶m3, SRGN_PARAMONLY); + SRgnCombineRectf(region, &rect1, ¶m4, SRGN_PARAMONLY); + + uint32_t numParams = 0; + SRgnGetRectParamsf(region, &queryRect, &numParams, nullptr); + REQUIRE(numParams == 4); + + void* buffer[4]; + SRgnGetRectParamsf(region, &queryRect, &numParams, buffer); + CHECK(numParams == 4); + CHECK(buffer[0] == ¶m1); + CHECK(buffer[1] == ¶m2); + CHECK(buffer[2] == ¶m3); + CHECK(buffer[3] == ¶m4); + } } TEST_CASE("SRgnGetRectsf", "[region]") { @@ -662,6 +902,12 @@ TEST_CASE("SRgnIsRectInRegionf", "[region]") { TEST_CASE("SRgnOffsetf", "[region]") { RgnDataTest region; + SECTION("does nothing when using an invalid region object") { + // doesn't crash + HSRGN inval = reinterpret_cast(1234); + SRgnOffsetf(inval, 10.0f, 10.0f); + } + SECTION("shifts rects by given amount") { RECTF rects[] = { { -200.0f, -200.0f, -100.0f, -100.0f },