From d8d8043e09365ea8b784d6960c5f296cf82be323 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Fri, 3 Nov 2023 14:44:18 -0700 Subject: [PATCH 1/5] Add Rect::NormalizePoint method --- impeller/geometry/rect.h | 29 +++++ impeller/geometry/rect_unittests.cc | 184 ++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+) diff --git a/impeller/geometry/rect.h b/impeller/geometry/rect.h index c40ce26ad1541..6b1ce8d726e49 100644 --- a/impeller/geometry/rect.h +++ b/impeller/geometry/rect.h @@ -181,6 +181,35 @@ struct TRect { return {GetRight(), GetBottom()}; } + /// @brief Computes the normalized location of an absolute point relative + /// to this rectangle and returns it as a relative Scalar Point + /// where (0, 0) represents the origin and (1, 1) represents the + /// lower right corner of the rectangle. + /// + /// Empty rectangles produce (0, 0) for all input values as well + /// as infinite rectangles in the case where the computation is + /// mathematically impossible. + template + constexpr TPoint NormalizePoint(TPoint absolute) { + if (size.IsEmpty()) { + // empty rects have no interior so the only point that maps correctly + // via the calculations is the origin and the rest produce infinities + // or NaN. To avoid polluting the downstream calculations with values + // that are not finite, all points will be the origin relative to an + // empty rectangle. The checks below would catch this case for zero + // sized empty rects, but not for negative sizes. + return {}; + } + Scalar relativeX = + (static_cast(absolute.x) - origin.x) / size.width; + Scalar relativeY = + (static_cast(absolute.y) - origin.y) / size.height; + // An infinite rect can still produce NaN for (infinity / infinity) + return (std::isfinite(relativeX) && std::isfinite(relativeY)) + ? Point(relativeX, relativeY) + : Point(); + } + constexpr std::array GetLTRB() const { return {GetLeft(), GetTop(), GetRight(), GetBottom()}; } diff --git a/impeller/geometry/rect_unittests.cc b/impeller/geometry/rect_unittests.cc index 583c04fee6484..6ff238f8e7a6c 100644 --- a/impeller/geometry/rect_unittests.cc +++ b/impeller/geometry/rect_unittests.cc @@ -55,5 +55,189 @@ TEST(RectTest, RectMakeSize) { } } +TEST(RectTest, NormalizePoint) { + // Tests finite rects including: + // - points at the corners, inside, and outside + // - rects that are non-empty or empty through either zero or + // negative width and/or height + // - all combinations of integer and scalar rects and points. + + // Tests one rectangle in all 4 combinations of integer and scalar data + // and also against NaN point values + auto test_one = [](int64_t l, int64_t t, int64_t r, int64_t b, // + const std::string& rect_desc, // + int64_t px, int64_t py, // + const std::string& pt_desc, // + Point expected) { + // Scalar point inside Scalar rect + ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(Point(px, py)), + expected) + << "Point(" << pt_desc << ") in " << rect_desc << " Rect"; + // Scalar point inside Integer rect + ASSERT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(Point(px, py)), + expected) + << "Point(" << pt_desc << ") in " << rect_desc << " IRect"; + // Integer point inside Scalar rect + ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(IPoint(px, py)), + expected) + << "IPoint(" << pt_desc << ") in " << rect_desc << " Rect"; + // Integer point inside Integer rect + ASSERT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(IPoint(px, py)), + expected) + << "IPoint(" << pt_desc << ") in " << rect_desc << " IRect"; + + auto nan = std::numeric_limits::quiet_NaN(); + auto nan_x = Point(nan, py); + auto nan_y = Point(px, nan); + auto nan_p = Point(nan, nan); + // Nan Scalar point inside Scalar and integer rects + ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_x), Point()) + << "Point(NaN x) in " << rect_desc << " Rect"; + ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_y), Point()) + << "Point(NaN y) in " << rect_desc << " Rect"; + ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_p), Point()) + << "Point(NaN x&y) in " << rect_desc << " Rect"; + ASSERT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(nan_x), Point()) + << "Point(NaN x) in " << rect_desc << " Rect"; + ASSERT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(nan_y), Point()) + << "Point(NaN y) in " << rect_desc << " Rect"; + ASSERT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(nan_p), Point()) + << "Point(NaN x&y) in " << rect_desc << " Rect"; + }; + + // Tests a rectangle using test_one both normally and all variants of + // being empty by reversing the lr and tb points. + auto test = [&test_one](int64_t l, int64_t t, int64_t r, int64_t b, // + int64_t px, int64_t py, // + const std::string& pt_desc, Point expected) { + test_one(l, t, r, b, "non-empty", px, py, pt_desc, expected); + test_one(l, t, l, b, "LR empty", px, py, pt_desc, Point()); + test_one(r, t, l, b, "LR reversed", px, py, pt_desc, Point()); + test_one(l, t, r, t, "TB empty", px, py, pt_desc, Point()); + test_one(l, b, r, t, "TB reversed", px, py, pt_desc, Point()); + test_one(l, t, l, t, "all empty", px, py, pt_desc, Point()); + test_one(r, b, l, t, "all reversed", px, py, pt_desc, Point()); + }; + + test(100, 100, 200, 200, 100, 100, "UL", Point(0, 0)); + test(100, 100, 200, 200, 200, 100, "UR", Point(1, 0)); + test(100, 100, 200, 200, 200, 200, "LR", Point(1, 1)); + test(100, 100, 200, 200, 100, 200, "LL", Point(0, 1)); + test(100, 100, 200, 200, 150, 150, "Center", Point(0.5, 0.5)); + test(100, 100, 200, 200, 0, 0, "outside UL", Point(-1, -1)); + test(100, 100, 200, 200, 300, 0, "outside UR", Point(2, -1)); + test(100, 100, 200, 200, 300, 300, "outside LR", Point(2, 2)); + test(100, 100, 200, 200, 0, 300, "outside LL", Point(-1, 2)); + + // We can't test the true min and max due to overflow of the xywh + // internal representation, but we can test with half their values. + // When TRect is converted to ltrb notation, we can relax this + // restriction. + int64_t min_int = std::numeric_limits::min() / 2; + int64_t max_int = std::numeric_limits::max() / 2; + test(min_int, 100, max_int, 200, 0, 150, "max int center", Point(0.5, 0.5)); +} + +TEST(RectTest, NormalizePointToNonFiniteRects) { + // Tests non-finite Scalar rects including: + // - points at the corners, inside, and outside + // - rects that are non-empty or empty through either zero or + // negative width and/or height + + // Tests one rectangle against supplied point values and NaN replacements. + auto test = [](Scalar l, Scalar t, Scalar r, Scalar b, // + Scalar px, Scalar py, // + const std::string& pt_desc, // + Point expected) { + auto nan = std::numeric_limits::quiet_NaN(); + auto inf = std::numeric_limits::infinity(); + + // Scalar point inside Scalar rect + ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(Point(px, py)), + expected) + << "Point(" << pt_desc << ") in Rect"; + // Scalar point inside Scalar rect with NaN left + ASSERT_EQ(Rect::MakeLTRB(nan, t, r, b).NormalizePoint(Point(px, py)), + Point()) + << "Point(" << pt_desc << ") in Rect NaN Left"; + // Scalar point inside Scalar rect with NaN top + ASSERT_EQ(Rect::MakeLTRB(l, nan, r, b).NormalizePoint(Point(px, py)), + Point()) + << "Point(" << pt_desc << ") in Rect NaN Top"; + // Scalar point inside Scalar rect with NaN right + ASSERT_EQ(Rect::MakeLTRB(l, t, nan, b).NormalizePoint(Point(px, py)), + Point()) + << "Point(" << pt_desc << ") in Rect NaN Left"; + // Scalar point inside Scalar rect with NaN bottom + ASSERT_EQ(Rect::MakeLTRB(l, t, r, nan).NormalizePoint(Point(px, py)), + Point()) + << "Point(" << pt_desc << ") in Rect NaN Top"; + // Scalar point inside Scalar rect with infinite left + ASSERT_EQ(Rect::MakeLTRB(-inf, t, r, b).NormalizePoint(Point(px, py)), + Point()) + << "Point(" << pt_desc << ") in Rect -Inf Left"; + // Scalar point inside Scalar rect with infinite top + ASSERT_EQ(Rect::MakeLTRB(l, -inf, r, b).NormalizePoint(Point(px, py)), + Point()) + << "Point(" << pt_desc << ") in Rect -Inf Top"; + // Scalar point inside Scalar rect with infinite right + ASSERT_EQ(Rect::MakeLTRB(l, t, inf, b).NormalizePoint(Point(px, py)), + Point(0, expected.y)) + << "Point(" << pt_desc << ") in Rect Inf Right"; + // Scalar point inside Scalar rect with infinite bottom + ASSERT_EQ(Rect::MakeLTRB(l, t, r, inf).NormalizePoint(Point(px, py)), + Point(expected.x, 0)) + << "Point(" << pt_desc << ") in Rect Inf Bottom"; + + // Testing with NaN points + auto nan_x = Point(nan, py); + auto nan_y = Point(px, nan); + auto nan_p = Point(nan, nan); + // Nan Scalar point inside Scalar rect + ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_x), Point()) + << "Point(NaN x) in Rect"; + ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_y), Point()) + << "Point(NaN y) in Rect"; + ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_p), Point()) + << "Point(NaN x&y) in Rect"; + + // Testing with infinite points + auto inf_x = Point(inf, py); + auto inf_y = Point(px, inf); + auto inf_p = Point(inf, inf); + // Infinite Scalar point inside Scalar rect + ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(inf_x), Point()) + << "Point(Infinite x) in Rect"; + ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(inf_y), Point()) + << "Point(Infinite y) in Rect"; + ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(inf_p), Point()) + << "Point(Infinite x&y) in Rect"; + ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(-inf_x), Point()) + << "Point(-Infinite x) in Rect"; + ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(-inf_y), Point()) + << "Point(-Infinite y) in Rect"; + ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(-inf_p), Point()) + << "Point(-Infinite x&y) in Rect"; + }; + + test(100, 100, 200, 200, 100, 100, "UL", Point(0, 0)); + test(100, 100, 200, 200, 200, 100, "UR", Point(1, 0)); + test(100, 100, 200, 200, 200, 200, "LR", Point(1, 1)); + test(100, 100, 200, 200, 100, 200, "LL", Point(0, 1)); + test(100, 100, 200, 200, 150, 150, "Center", Point(0.5, 0.5)); + test(100, 100, 200, 200, 0, 0, "outside UL", Point(-1, -1)); + test(100, 100, 200, 200, 300, 0, "outside UR", Point(2, -1)); + test(100, 100, 200, 200, 300, 300, "outside LR", Point(2, 2)); + test(100, 100, 200, 200, 0, 300, "outside LL", Point(-1, 2)); + + // We can't test the true min and max due to overflow of the xywh + // internal representation, but we can test with half their values. + // When TRect is converted to ltrb notation, we can relax this + // restriction. + int64_t min_int = std::numeric_limits::min() / 2; + int64_t max_int = std::numeric_limits::max() / 2; + test(min_int, 100, max_int, 200, 0, 150, "max int center", Point(0.5, 0.5)); +} + } // namespace testing } // namespace impeller From 79bfa41b4ab37a4ceada26a305e294e7d7810751 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Fri, 3 Nov 2023 15:06:39 -0700 Subject: [PATCH 2/5] switch to EXPECT for more complete test runs on failures --- impeller/geometry/rect_unittests.cc | 68 ++++++++++++++--------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/impeller/geometry/rect_unittests.cc b/impeller/geometry/rect_unittests.cc index 6ff238f8e7a6c..ba3f213d357b0 100644 --- a/impeller/geometry/rect_unittests.cc +++ b/impeller/geometry/rect_unittests.cc @@ -14,14 +14,14 @@ namespace testing { TEST(RectTest, RectOriginSizeGetters) { { Rect r = Rect::MakeOriginSize({10, 20}, {50, 40}); - ASSERT_EQ(r.GetOrigin(), Point(10, 20)); - ASSERT_EQ(r.GetSize(), Size(50, 40)); + EXPECT_EQ(r.GetOrigin(), Point(10, 20)); + EXPECT_EQ(r.GetSize(), Size(50, 40)); } { Rect r = Rect::MakeLTRB(10, 20, 50, 40); - ASSERT_EQ(r.GetOrigin(), Point(10, 20)); - ASSERT_EQ(r.GetSize(), Size(40, 20)); + EXPECT_EQ(r.GetOrigin(), Point(10, 20)); + EXPECT_EQ(r.GetSize(), Size(40, 20)); } } @@ -44,14 +44,14 @@ TEST(RectTest, RectMakeSize) { Size s(100, 200); IRect r = IRect::MakeSize(s); IRect expected = IRect::MakeLTRB(0, 0, 100, 200); - ASSERT_EQ(r, expected); + EXPECT_EQ(r, expected); } { ISize s(100, 200); IRect r = IRect::MakeSize(s); IRect expected = IRect::MakeLTRB(0, 0, 100, 200); - ASSERT_EQ(r, expected); + EXPECT_EQ(r, expected); } } @@ -70,19 +70,19 @@ TEST(RectTest, NormalizePoint) { const std::string& pt_desc, // Point expected) { // Scalar point inside Scalar rect - ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(Point(px, py)), + EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(Point(px, py)), expected) << "Point(" << pt_desc << ") in " << rect_desc << " Rect"; // Scalar point inside Integer rect - ASSERT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(Point(px, py)), + EXPECT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(Point(px, py)), expected) << "Point(" << pt_desc << ") in " << rect_desc << " IRect"; // Integer point inside Scalar rect - ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(IPoint(px, py)), + EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(IPoint(px, py)), expected) << "IPoint(" << pt_desc << ") in " << rect_desc << " Rect"; // Integer point inside Integer rect - ASSERT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(IPoint(px, py)), + EXPECT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(IPoint(px, py)), expected) << "IPoint(" << pt_desc << ") in " << rect_desc << " IRect"; @@ -91,17 +91,17 @@ TEST(RectTest, NormalizePoint) { auto nan_y = Point(px, nan); auto nan_p = Point(nan, nan); // Nan Scalar point inside Scalar and integer rects - ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_x), Point()) + EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_x), Point()) << "Point(NaN x) in " << rect_desc << " Rect"; - ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_y), Point()) + EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_y), Point()) << "Point(NaN y) in " << rect_desc << " Rect"; - ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_p), Point()) + EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_p), Point()) << "Point(NaN x&y) in " << rect_desc << " Rect"; - ASSERT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(nan_x), Point()) + EXPECT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(nan_x), Point()) << "Point(NaN x) in " << rect_desc << " Rect"; - ASSERT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(nan_y), Point()) + EXPECT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(nan_y), Point()) << "Point(NaN y) in " << rect_desc << " Rect"; - ASSERT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(nan_p), Point()) + EXPECT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(nan_p), Point()) << "Point(NaN x&y) in " << rect_desc << " Rect"; }; @@ -153,39 +153,39 @@ TEST(RectTest, NormalizePointToNonFiniteRects) { auto inf = std::numeric_limits::infinity(); // Scalar point inside Scalar rect - ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(Point(px, py)), + EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(Point(px, py)), expected) << "Point(" << pt_desc << ") in Rect"; // Scalar point inside Scalar rect with NaN left - ASSERT_EQ(Rect::MakeLTRB(nan, t, r, b).NormalizePoint(Point(px, py)), + EXPECT_EQ(Rect::MakeLTRB(nan, t, r, b).NormalizePoint(Point(px, py)), Point()) << "Point(" << pt_desc << ") in Rect NaN Left"; // Scalar point inside Scalar rect with NaN top - ASSERT_EQ(Rect::MakeLTRB(l, nan, r, b).NormalizePoint(Point(px, py)), + EXPECT_EQ(Rect::MakeLTRB(l, nan, r, b).NormalizePoint(Point(px, py)), Point()) << "Point(" << pt_desc << ") in Rect NaN Top"; // Scalar point inside Scalar rect with NaN right - ASSERT_EQ(Rect::MakeLTRB(l, t, nan, b).NormalizePoint(Point(px, py)), + EXPECT_EQ(Rect::MakeLTRB(l, t, nan, b).NormalizePoint(Point(px, py)), Point()) << "Point(" << pt_desc << ") in Rect NaN Left"; // Scalar point inside Scalar rect with NaN bottom - ASSERT_EQ(Rect::MakeLTRB(l, t, r, nan).NormalizePoint(Point(px, py)), + EXPECT_EQ(Rect::MakeLTRB(l, t, r, nan).NormalizePoint(Point(px, py)), Point()) << "Point(" << pt_desc << ") in Rect NaN Top"; // Scalar point inside Scalar rect with infinite left - ASSERT_EQ(Rect::MakeLTRB(-inf, t, r, b).NormalizePoint(Point(px, py)), + EXPECT_EQ(Rect::MakeLTRB(-inf, t, r, b).NormalizePoint(Point(px, py)), Point()) << "Point(" << pt_desc << ") in Rect -Inf Left"; // Scalar point inside Scalar rect with infinite top - ASSERT_EQ(Rect::MakeLTRB(l, -inf, r, b).NormalizePoint(Point(px, py)), + EXPECT_EQ(Rect::MakeLTRB(l, -inf, r, b).NormalizePoint(Point(px, py)), Point()) << "Point(" << pt_desc << ") in Rect -Inf Top"; // Scalar point inside Scalar rect with infinite right - ASSERT_EQ(Rect::MakeLTRB(l, t, inf, b).NormalizePoint(Point(px, py)), + EXPECT_EQ(Rect::MakeLTRB(l, t, inf, b).NormalizePoint(Point(px, py)), Point(0, expected.y)) << "Point(" << pt_desc << ") in Rect Inf Right"; // Scalar point inside Scalar rect with infinite bottom - ASSERT_EQ(Rect::MakeLTRB(l, t, r, inf).NormalizePoint(Point(px, py)), + EXPECT_EQ(Rect::MakeLTRB(l, t, r, inf).NormalizePoint(Point(px, py)), Point(expected.x, 0)) << "Point(" << pt_desc << ") in Rect Inf Bottom"; @@ -194,11 +194,11 @@ TEST(RectTest, NormalizePointToNonFiniteRects) { auto nan_y = Point(px, nan); auto nan_p = Point(nan, nan); // Nan Scalar point inside Scalar rect - ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_x), Point()) + EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_x), Point()) << "Point(NaN x) in Rect"; - ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_y), Point()) + EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_y), Point()) << "Point(NaN y) in Rect"; - ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_p), Point()) + EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_p), Point()) << "Point(NaN x&y) in Rect"; // Testing with infinite points @@ -206,17 +206,17 @@ TEST(RectTest, NormalizePointToNonFiniteRects) { auto inf_y = Point(px, inf); auto inf_p = Point(inf, inf); // Infinite Scalar point inside Scalar rect - ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(inf_x), Point()) + EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(inf_x), Point()) << "Point(Infinite x) in Rect"; - ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(inf_y), Point()) + EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(inf_y), Point()) << "Point(Infinite y) in Rect"; - ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(inf_p), Point()) + EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(inf_p), Point()) << "Point(Infinite x&y) in Rect"; - ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(-inf_x), Point()) + EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(-inf_x), Point()) << "Point(-Infinite x) in Rect"; - ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(-inf_y), Point()) + EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(-inf_y), Point()) << "Point(-Infinite y) in Rect"; - ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(-inf_p), Point()) + EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(-inf_p), Point()) << "Point(-Infinite x&y) in Rect"; }; From a112dfabad78fe7cce604131be0972958ec92a1a Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Fri, 3 Nov 2023 16:45:18 -0700 Subject: [PATCH 3/5] better comments in the unit test --- impeller/geometry/rect_unittests.cc | 98 +++++++++++++++++------------ 1 file changed, 58 insertions(+), 40 deletions(-) diff --git a/impeller/geometry/rect_unittests.cc b/impeller/geometry/rect_unittests.cc index ba3f213d357b0..53eb1d8dee49e 100644 --- a/impeller/geometry/rect_unittests.cc +++ b/impeller/geometry/rect_unittests.cc @@ -73,24 +73,28 @@ TEST(RectTest, NormalizePoint) { EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(Point(px, py)), expected) << "Point(" << pt_desc << ") in " << rect_desc << " Rect"; + // Scalar point inside Integer rect EXPECT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(Point(px, py)), expected) << "Point(" << pt_desc << ") in " << rect_desc << " IRect"; + // Integer point inside Scalar rect EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(IPoint(px, py)), expected) << "IPoint(" << pt_desc << ") in " << rect_desc << " Rect"; + // Integer point inside Integer rect EXPECT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(IPoint(px, py)), expected) << "IPoint(" << pt_desc << ") in " << rect_desc << " IRect"; + // Now test nan handling by substituting a nan for the X and/or Y of + // the point. auto nan = std::numeric_limits::quiet_NaN(); auto nan_x = Point(nan, py); auto nan_y = Point(px, nan); auto nan_p = Point(nan, nan); - // Nan Scalar point inside Scalar and integer rects EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_x), Point()) << "Point(NaN x) in " << rect_desc << " Rect"; EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_y), Point()) @@ -105,29 +109,39 @@ TEST(RectTest, NormalizePoint) { << "Point(NaN x&y) in " << rect_desc << " Rect"; }; - // Tests a rectangle using test_one both normally and all variants of - // being empty by reversing the lr and tb points. + // Tests the rectangle as specified, which is assumed to be non-empty + // and then tests it in various states of emptiness in both dimensions + // by reversing left/right and top/bottom or using the same value for + // both. auto test = [&test_one](int64_t l, int64_t t, int64_t r, int64_t b, // int64_t px, int64_t py, // const std::string& pt_desc, Point expected) { - test_one(l, t, r, b, "non-empty", px, py, pt_desc, expected); - test_one(l, t, l, b, "LR empty", px, py, pt_desc, Point()); - test_one(r, t, l, b, "LR reversed", px, py, pt_desc, Point()); - test_one(l, t, r, t, "TB empty", px, py, pt_desc, Point()); - test_one(l, b, r, t, "TB reversed", px, py, pt_desc, Point()); - test_one(l, t, l, t, "all empty", px, py, pt_desc, Point()); - test_one(r, b, l, t, "all reversed", px, py, pt_desc, Point()); + // clang-format off + // rect point expected + // rect description point desc result + test_one(l, t, r, b, "non-empty", px, py, pt_desc, expected); + test_one(l, t, l, b, "LR empty", px, py, pt_desc, Point()); + test_one(r, t, l, b, "LR reversed", px, py, pt_desc, Point()); + test_one(l, t, r, t, "TB empty", px, py, pt_desc, Point()); + test_one(l, b, r, t, "TB reversed", px, py, pt_desc, Point()); + test_one(l, t, l, t, "all empty", px, py, pt_desc, Point()); + test_one(r, b, l, t, "all reversed", px, py, pt_desc, Point()); + // clang-format on }; - test(100, 100, 200, 200, 100, 100, "UL", Point(0, 0)); - test(100, 100, 200, 200, 200, 100, "UR", Point(1, 0)); - test(100, 100, 200, 200, 200, 200, "LR", Point(1, 1)); - test(100, 100, 200, 200, 100, 200, "LL", Point(0, 1)); - test(100, 100, 200, 200, 150, 150, "Center", Point(0.5, 0.5)); - test(100, 100, 200, 200, 0, 0, "outside UL", Point(-1, -1)); - test(100, 100, 200, 200, 300, 0, "outside UR", Point(2, -1)); - test(100, 100, 200, 200, 300, 300, "outside LR", Point(2, 2)); - test(100, 100, 200, 200, 0, 300, "outside LL", Point(-1, 2)); + // clang-format off + // rect point point expected + // [ l t r b ] [ px py ] description result + test(100, 100, 200, 200, 100, 100, "UL", Point(0, 0)); + test(100, 100, 200, 200, 200, 100, "UR", Point(1, 0)); + test(100, 100, 200, 200, 200, 200, "LR", Point(1, 1)); + test(100, 100, 200, 200, 100, 200, "LL", Point(0, 1)); + test(100, 100, 200, 200, 150, 150, "Center", Point(0.5, 0.5)); + test(100, 100, 200, 200, 0, 0, "outside UL", Point(-1, -1)); + test(100, 100, 200, 200, 300, 0, "outside UR", Point(2, -1)); + test(100, 100, 200, 200, 300, 300, "outside LR", Point(2, 2)); + test(100, 100, 200, 200, 0, 300, "outside LL", Point(-1, 2)); + // clang-format on // We can't test the true min and max due to overflow of the xywh // internal representation, but we can test with half their values. @@ -156,44 +170,52 @@ TEST(RectTest, NormalizePointToNonFiniteRects) { EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(Point(px, py)), expected) << "Point(" << pt_desc << ") in Rect"; + // Scalar point inside Scalar rect with NaN left EXPECT_EQ(Rect::MakeLTRB(nan, t, r, b).NormalizePoint(Point(px, py)), Point()) << "Point(" << pt_desc << ") in Rect NaN Left"; + // Scalar point inside Scalar rect with NaN top EXPECT_EQ(Rect::MakeLTRB(l, nan, r, b).NormalizePoint(Point(px, py)), Point()) << "Point(" << pt_desc << ") in Rect NaN Top"; + // Scalar point inside Scalar rect with NaN right EXPECT_EQ(Rect::MakeLTRB(l, t, nan, b).NormalizePoint(Point(px, py)), Point()) << "Point(" << pt_desc << ") in Rect NaN Left"; + // Scalar point inside Scalar rect with NaN bottom EXPECT_EQ(Rect::MakeLTRB(l, t, r, nan).NormalizePoint(Point(px, py)), Point()) << "Point(" << pt_desc << ") in Rect NaN Top"; + // Scalar point inside Scalar rect with infinite left EXPECT_EQ(Rect::MakeLTRB(-inf, t, r, b).NormalizePoint(Point(px, py)), Point()) << "Point(" << pt_desc << ") in Rect -Inf Left"; + // Scalar point inside Scalar rect with infinite top EXPECT_EQ(Rect::MakeLTRB(l, -inf, r, b).NormalizePoint(Point(px, py)), Point()) << "Point(" << pt_desc << ") in Rect -Inf Top"; + // Scalar point inside Scalar rect with infinite right EXPECT_EQ(Rect::MakeLTRB(l, t, inf, b).NormalizePoint(Point(px, py)), Point(0, expected.y)) << "Point(" << pt_desc << ") in Rect Inf Right"; + // Scalar point inside Scalar rect with infinite bottom EXPECT_EQ(Rect::MakeLTRB(l, t, r, inf).NormalizePoint(Point(px, py)), Point(expected.x, 0)) << "Point(" << pt_desc << ") in Rect Inf Bottom"; - // Testing with NaN points + // Now test NaN handling by substituting a NaN for the X and/or Y of + // the point. auto nan_x = Point(nan, py); auto nan_y = Point(px, nan); auto nan_p = Point(nan, nan); - // Nan Scalar point inside Scalar rect EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_x), Point()) << "Point(NaN x) in Rect"; EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_y), Point()) @@ -201,11 +223,11 @@ TEST(RectTest, NormalizePointToNonFiniteRects) { EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_p), Point()) << "Point(NaN x&y) in Rect"; - // Testing with infinite points + // Now test +/- infinity handling by substituting an infinity for the + // X and/or Y of the point. auto inf_x = Point(inf, py); auto inf_y = Point(px, inf); auto inf_p = Point(inf, inf); - // Infinite Scalar point inside Scalar rect EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(inf_x), Point()) << "Point(Infinite x) in Rect"; EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(inf_y), Point()) @@ -220,23 +242,19 @@ TEST(RectTest, NormalizePointToNonFiniteRects) { << "Point(-Infinite x&y) in Rect"; }; - test(100, 100, 200, 200, 100, 100, "UL", Point(0, 0)); - test(100, 100, 200, 200, 200, 100, "UR", Point(1, 0)); - test(100, 100, 200, 200, 200, 200, "LR", Point(1, 1)); - test(100, 100, 200, 200, 100, 200, "LL", Point(0, 1)); - test(100, 100, 200, 200, 150, 150, "Center", Point(0.5, 0.5)); - test(100, 100, 200, 200, 0, 0, "outside UL", Point(-1, -1)); - test(100, 100, 200, 200, 300, 0, "outside UR", Point(2, -1)); - test(100, 100, 200, 200, 300, 300, "outside LR", Point(2, 2)); - test(100, 100, 200, 200, 0, 300, "outside LL", Point(-1, 2)); - - // We can't test the true min and max due to overflow of the xywh - // internal representation, but we can test with half their values. - // When TRect is converted to ltrb notation, we can relax this - // restriction. - int64_t min_int = std::numeric_limits::min() / 2; - int64_t max_int = std::numeric_limits::max() / 2; - test(min_int, 100, max_int, 200, 0, 150, "max int center", Point(0.5, 0.5)); + // clang-format off + // rect point point expected + // [ l t r b ] [ px py ] description result + test(100, 100, 200, 200, 100, 100, "UL", Point(0, 0)); + test(100, 100, 200, 200, 200, 100, "UR", Point(1, 0)); + test(100, 100, 200, 200, 200, 200, "LR", Point(1, 1)); + test(100, 100, 200, 200, 100, 200, "LL", Point(0, 1)); + test(100, 100, 200, 200, 150, 150, "Center", Point(0.5, 0.5)); + test(100, 100, 200, 200, 0, 0, "outside UL", Point(-1, -1)); + test(100, 100, 200, 200, 300, 0, "outside UR", Point(2, -1)); + test(100, 100, 200, 200, 300, 300, "outside LR", Point(2, 2)); + test(100, 100, 200, 200, 0, 300, "outside LL", Point(-1, 2)); + // clang-format on } } // namespace testing From 5b7d69a99f70ad2fa4161ae3204b430574350f8d Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Fri, 3 Nov 2023 18:42:28 -0700 Subject: [PATCH 4/5] make the test cases more concise and show the exact test data on failures --- impeller/geometry/rect_unittests.cc | 260 ++++++++++++---------------- 1 file changed, 112 insertions(+), 148 deletions(-) diff --git a/impeller/geometry/rect_unittests.cc b/impeller/geometry/rect_unittests.cc index 53eb1d8dee49e..e444a1ccbc540 100644 --- a/impeller/geometry/rect_unittests.cc +++ b/impeller/geometry/rect_unittests.cc @@ -55,6 +55,13 @@ TEST(RectTest, RectMakeSize) { } } +// Performs an EXPECT_EQ on the operation of Rect::NormalizePoint and +// outputs the raw data for the test case on failure to help with diagnosis +#define TEST_NORMALIZE_POINT(RT, PT, l, t, r, b, px, py, expected) \ + EXPECT_EQ(RT::MakeLTRB(l, t, r, b).NormalizePoint(PT(px, py)), expected) \ + << #RT "::MakeLTRB(" << l << ", " << t << ", " << r << ", " << b << ")" \ + << ".NormalizePoint(" << #PT "(" << px << ", " << py << "))" + TEST(RectTest, NormalizePoint) { // Tests finite rects including: // - points at the corners, inside, and outside @@ -62,51 +69,55 @@ TEST(RectTest, NormalizePoint) { // negative width and/or height // - all combinations of integer and scalar rects and points. - // Tests one rectangle in all 4 combinations of integer and scalar data - // and also against NaN point values + // Tests one rectangle against one point in all 4 combinations of integer + // and scalar data types and with NaN and infinity point values auto test_one = [](int64_t l, int64_t t, int64_t r, int64_t b, // - const std::string& rect_desc, // int64_t px, int64_t py, // - const std::string& pt_desc, // Point expected) { - // Scalar point inside Scalar rect - EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(Point(px, py)), - expected) - << "Point(" << pt_desc << ") in " << rect_desc << " Rect"; - - // Scalar point inside Integer rect - EXPECT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(Point(px, py)), - expected) - << "Point(" << pt_desc << ") in " << rect_desc << " IRect"; - - // Integer point inside Scalar rect - EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(IPoint(px, py)), - expected) - << "IPoint(" << pt_desc << ") in " << rect_desc << " Rect"; - - // Integer point inside Integer rect - EXPECT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(IPoint(px, py)), - expected) - << "IPoint(" << pt_desc << ") in " << rect_desc << " IRect"; + // First test with all combinations of [I]Rect and [I]Point + // clang-format off + TEST_NORMALIZE_POINT( Rect, Point, l, t, r, b, px, py, expected); + TEST_NORMALIZE_POINT(IRect, Point, l, t, r, b, px, py, expected); + TEST_NORMALIZE_POINT( Rect, IPoint, l, t, r, b, px, py, expected); + TEST_NORMALIZE_POINT(IRect, IPoint, l, t, r, b, px, py, expected); + // clang-format on // Now test nan handling by substituting a nan for the X and/or Y of // the point. auto nan = std::numeric_limits::quiet_NaN(); - auto nan_x = Point(nan, py); - auto nan_y = Point(px, nan); - auto nan_p = Point(nan, nan); - EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_x), Point()) - << "Point(NaN x) in " << rect_desc << " Rect"; - EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_y), Point()) - << "Point(NaN y) in " << rect_desc << " Rect"; - EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_p), Point()) - << "Point(NaN x&y) in " << rect_desc << " Rect"; - EXPECT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(nan_x), Point()) - << "Point(NaN x) in " << rect_desc << " Rect"; - EXPECT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(nan_y), Point()) - << "Point(NaN y) in " << rect_desc << " Rect"; - EXPECT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(nan_p), Point()) - << "Point(NaN x&y) in " << rect_desc << " Rect"; + // Test with Rect and IRect, but we have to use Point to hold the NaN + // clang-format off + TEST_NORMALIZE_POINT( Rect, Point, l, t, r, b, nan, py, Point()); + TEST_NORMALIZE_POINT( Rect, Point, l, t, r, b, px, nan, Point()); + TEST_NORMALIZE_POINT( Rect, Point, l, t, r, b, nan, nan, Point()); + TEST_NORMALIZE_POINT(IRect, Point, l, t, r, b, nan, py, Point()); + TEST_NORMALIZE_POINT(IRect, Point, l, t, r, b, px, nan, Point()); + TEST_NORMALIZE_POINT(IRect, Point, l, t, r, b, nan, nan, Point()); + // clang-format on + + // Now test +/- infinity handling by substituting an infinity for the + // X and/or Y of the point. + auto inf = std::numeric_limits::infinity(); + + // Test with Rect, but we have to use Point to hold the infinity + // clang-format off + TEST_NORMALIZE_POINT( Rect, Point, l, t, r, b, inf, py, Point()); + TEST_NORMALIZE_POINT( Rect, Point, l, t, r, b, px, inf, Point()); + TEST_NORMALIZE_POINT( Rect, Point, l, t, r, b, inf, inf, Point()); + TEST_NORMALIZE_POINT( Rect, Point, l, t, r, b, -inf, py, Point()); + TEST_NORMALIZE_POINT( Rect, Point, l, t, r, b, px, -inf, Point()); + TEST_NORMALIZE_POINT( Rect, Point, l, t, r, b, -inf, -inf, Point()); + // clang-format on + + // Test with IRect, but we have to use Point to hold the infinity + // clang-format off + TEST_NORMALIZE_POINT(IRect, Point, l, t, r, b, inf, py, Point()); + TEST_NORMALIZE_POINT(IRect, Point, l, t, r, b, px, inf, Point()); + TEST_NORMALIZE_POINT(IRect, Point, l, t, r, b, inf, inf, Point()); + TEST_NORMALIZE_POINT(IRect, Point, l, t, r, b, -inf, py, Point()); + TEST_NORMALIZE_POINT(IRect, Point, l, t, r, b, px, -inf, Point()); + TEST_NORMALIZE_POINT(IRect, Point, l, t, r, b, -inf, -inf, Point()); + // clang-format on }; // Tests the rectangle as specified, which is assumed to be non-empty @@ -115,41 +126,48 @@ TEST(RectTest, NormalizePoint) { // both. auto test = [&test_one](int64_t l, int64_t t, int64_t r, int64_t b, // int64_t px, int64_t py, // - const std::string& pt_desc, Point expected) { + Point expected) { // clang-format off - // rect point expected - // rect description point desc result - test_one(l, t, r, b, "non-empty", px, py, pt_desc, expected); - test_one(l, t, l, b, "LR empty", px, py, pt_desc, Point()); - test_one(r, t, l, b, "LR reversed", px, py, pt_desc, Point()); - test_one(l, t, r, t, "TB empty", px, py, pt_desc, Point()); - test_one(l, b, r, t, "TB reversed", px, py, pt_desc, Point()); - test_one(l, t, l, t, "all empty", px, py, pt_desc, Point()); - test_one(r, b, l, t, "all reversed", px, py, pt_desc, Point()); + // expected + // rect point result + test_one(l, t, r, b, px, py, expected); // normal + test_one(l, t, l, b, px, py, Point()); // empty horizontally + test_one(r, t, l, b, px, py, Point()); // reversed horizontally + test_one(l, t, r, t, px, py, Point()); // empty vertically + test_one(l, b, r, t, px, py, Point()); // reversed vertically + test_one(l, t, l, t, px, py, Point()); // empty in both axes + test_one(r, b, l, t, px, py, Point()); // reversed in both axes // clang-format on }; // clang-format off - // rect point point expected - // [ l t r b ] [ px py ] description result - test(100, 100, 200, 200, 100, 100, "UL", Point(0, 0)); - test(100, 100, 200, 200, 200, 100, "UR", Point(1, 0)); - test(100, 100, 200, 200, 200, 200, "LR", Point(1, 1)); - test(100, 100, 200, 200, 100, 200, "LL", Point(0, 1)); - test(100, 100, 200, 200, 150, 150, "Center", Point(0.5, 0.5)); - test(100, 100, 200, 200, 0, 0, "outside UL", Point(-1, -1)); - test(100, 100, 200, 200, 300, 0, "outside UR", Point(2, -1)); - test(100, 100, 200, 200, 300, 300, "outside LR", Point(2, 2)); - test(100, 100, 200, 200, 0, 300, "outside LL", Point(-1, 2)); + // rect point expected + // [ l t r b ] [ px py ] result + test(100, 100, 200, 200, 100, 100, Point(0, 0)); // Upper Left (UL) + test(100, 100, 200, 200, 200, 100, Point(1, 0)); // Upper Right (UR) + test(100, 100, 200, 200, 200, 200, Point(1, 1)); // Lower Right (LR) + test(100, 100, 200, 200, 100, 200, Point(0, 1)); // Lower Left (LL) + test(100, 100, 200, 200, 150, 150, Point(0.5, 0.5)); // Center + test(100, 100, 200, 200, 0, 0, Point(-1, -1)); // Outside UL + test(100, 100, 200, 200, 300, 0, Point(2, -1)); // Outside UR + test(100, 100, 200, 200, 300, 300, Point(2, 2)); // Outside LR + test(100, 100, 200, 200, 0, 300, Point(-1, 2)); // Outside LL // clang-format on - // We can't test the true min and max due to overflow of the xywh - // internal representation, but we can test with half their values. + // We can't test the true min and max 64-bit values due to overflow of + // the xywh internal representation, but we can test with half their + // values. + // // When TRect is converted to ltrb notation, we can relax this // restriction. int64_t min_int = std::numeric_limits::min() / 2; int64_t max_int = std::numeric_limits::max() / 2; - test(min_int, 100, max_int, 200, 0, 150, "max int center", Point(0.5, 0.5)); + + // clang-format off + test(min_int, 100, max_int, 200, 0, 150, Point(0.5, 0.5)); + test( 100, min_int, 200, max_int, 150, 0, Point(0.5, 0.5)); + test(min_int, min_int, max_int, max_int, 150, 150, Point(0.5, 0.5)); + // clang-format on } TEST(RectTest, NormalizePointToNonFiniteRects) { @@ -161,101 +179,47 @@ TEST(RectTest, NormalizePointToNonFiniteRects) { // Tests one rectangle against supplied point values and NaN replacements. auto test = [](Scalar l, Scalar t, Scalar r, Scalar b, // Scalar px, Scalar py, // - const std::string& pt_desc, // Point expected) { auto nan = std::numeric_limits::quiet_NaN(); auto inf = std::numeric_limits::infinity(); - // Scalar point inside Scalar rect - EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(Point(px, py)), - expected) - << "Point(" << pt_desc << ") in Rect"; - - // Scalar point inside Scalar rect with NaN left - EXPECT_EQ(Rect::MakeLTRB(nan, t, r, b).NormalizePoint(Point(px, py)), - Point()) - << "Point(" << pt_desc << ") in Rect NaN Left"; - - // Scalar point inside Scalar rect with NaN top - EXPECT_EQ(Rect::MakeLTRB(l, nan, r, b).NormalizePoint(Point(px, py)), - Point()) - << "Point(" << pt_desc << ") in Rect NaN Top"; - - // Scalar point inside Scalar rect with NaN right - EXPECT_EQ(Rect::MakeLTRB(l, t, nan, b).NormalizePoint(Point(px, py)), - Point()) - << "Point(" << pt_desc << ") in Rect NaN Left"; - - // Scalar point inside Scalar rect with NaN bottom - EXPECT_EQ(Rect::MakeLTRB(l, t, r, nan).NormalizePoint(Point(px, py)), - Point()) - << "Point(" << pt_desc << ") in Rect NaN Top"; - - // Scalar point inside Scalar rect with infinite left - EXPECT_EQ(Rect::MakeLTRB(-inf, t, r, b).NormalizePoint(Point(px, py)), - Point()) - << "Point(" << pt_desc << ") in Rect -Inf Left"; - - // Scalar point inside Scalar rect with infinite top - EXPECT_EQ(Rect::MakeLTRB(l, -inf, r, b).NormalizePoint(Point(px, py)), - Point()) - << "Point(" << pt_desc << ") in Rect -Inf Top"; - - // Scalar point inside Scalar rect with infinite right - EXPECT_EQ(Rect::MakeLTRB(l, t, inf, b).NormalizePoint(Point(px, py)), - Point(0, expected.y)) - << "Point(" << pt_desc << ") in Rect Inf Right"; - - // Scalar point inside Scalar rect with infinite bottom - EXPECT_EQ(Rect::MakeLTRB(l, t, r, inf).NormalizePoint(Point(px, py)), - Point(expected.x, 0)) - << "Point(" << pt_desc << ") in Rect Inf Bottom"; - - // Now test NaN handling by substituting a NaN for the X and/or Y of - // the point. - auto nan_x = Point(nan, py); - auto nan_y = Point(px, nan); - auto nan_p = Point(nan, nan); - EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_x), Point()) - << "Point(NaN x) in Rect"; - EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_y), Point()) - << "Point(NaN y) in Rect"; - EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_p), Point()) - << "Point(NaN x&y) in Rect"; - - // Now test +/- infinity handling by substituting an infinity for the - // X and/or Y of the point. - auto inf_x = Point(inf, py); - auto inf_y = Point(px, inf); - auto inf_p = Point(inf, inf); - EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(inf_x), Point()) - << "Point(Infinite x) in Rect"; - EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(inf_y), Point()) - << "Point(Infinite y) in Rect"; - EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(inf_p), Point()) - << "Point(Infinite x&y) in Rect"; - EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(-inf_x), Point()) - << "Point(-Infinite x) in Rect"; - EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(-inf_y), Point()) - << "Point(-Infinite y) in Rect"; - EXPECT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(-inf_p), Point()) - << "Point(-Infinite x&y) in Rect"; + TEST_NORMALIZE_POINT(Rect, Point, l, t, r, b, px, py, expected); + + // Now retest with NaN replacing each rect parameter - producing (0, 0) + TEST_NORMALIZE_POINT(Rect, Point, nan, t, r, b, px, py, Point()); + TEST_NORMALIZE_POINT(Rect, Point, l, nan, r, b, px, py, Point()); + TEST_NORMALIZE_POINT(Rect, Point, l, t, nan, b, px, py, Point()); + TEST_NORMALIZE_POINT(Rect, Point, l, t, r, nan, px, py, Point()); + + // Now retest with -inf replacing the left/top values - producing (0, 0) + TEST_NORMALIZE_POINT(Rect, Point, -inf, t, r, b, px, py, Point()); + TEST_NORMALIZE_POINT(Rect, Point, l, -inf, r, b, px, py, Point()); + + // Now retest with +inf replacing the right/bottom values which + // produces a valid result, but the associated normalized coordinate + // will always be 0. + TEST_NORMALIZE_POINT(Rect, Point, l, t, inf, b, px, py, + Point(0, expected.y)); + TEST_NORMALIZE_POINT(Rect, Point, l, t, r, inf, px, py, + Point(expected.x, 0)); }; // clang-format off - // rect point point expected - // [ l t r b ] [ px py ] description result - test(100, 100, 200, 200, 100, 100, "UL", Point(0, 0)); - test(100, 100, 200, 200, 200, 100, "UR", Point(1, 0)); - test(100, 100, 200, 200, 200, 200, "LR", Point(1, 1)); - test(100, 100, 200, 200, 100, 200, "LL", Point(0, 1)); - test(100, 100, 200, 200, 150, 150, "Center", Point(0.5, 0.5)); - test(100, 100, 200, 200, 0, 0, "outside UL", Point(-1, -1)); - test(100, 100, 200, 200, 300, 0, "outside UR", Point(2, -1)); - test(100, 100, 200, 200, 300, 300, "outside LR", Point(2, 2)); - test(100, 100, 200, 200, 0, 300, "outside LL", Point(-1, 2)); + // rect point expected + // [ l t r b ] [ px py ] result + test(100, 100, 200, 200, 100, 100, Point(0, 0)); // Upper Left (UL) + test(100, 100, 200, 200, 200, 100, Point(1, 0)); // Upper Right (UR) + test(100, 100, 200, 200, 200, 200, Point(1, 1)); // Lower Right (LR) + test(100, 100, 200, 200, 100, 200, Point(0, 1)); // Lower Left (LL) + test(100, 100, 200, 200, 150, 150, Point(0.5, 0.5)); // Center + test(100, 100, 200, 200, 0, 0, Point(-1, -1)); // Outside UL + test(100, 100, 200, 200, 300, 0, Point(2, -1)); // Outside UR + test(100, 100, 200, 200, 300, 300, Point(2, 2)); // Outside LR + test(100, 100, 200, 200, 0, 300, Point(-1, 2)); // Outside LL // clang-format on } +#undef TEST_NORMALIZE_POINT + } // namespace testing } // namespace impeller From 0659b6a5e38e0c1e0d093158fe91af11af09ea7f Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Fri, 3 Nov 2023 19:32:34 -0700 Subject: [PATCH 5/5] add newline on failed tests so output is easier to scan --- impeller/geometry/rect_unittests.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/impeller/geometry/rect_unittests.cc b/impeller/geometry/rect_unittests.cc index e444a1ccbc540..5cf1e5f89a2c6 100644 --- a/impeller/geometry/rect_unittests.cc +++ b/impeller/geometry/rect_unittests.cc @@ -60,7 +60,8 @@ TEST(RectTest, RectMakeSize) { #define TEST_NORMALIZE_POINT(RT, PT, l, t, r, b, px, py, expected) \ EXPECT_EQ(RT::MakeLTRB(l, t, r, b).NormalizePoint(PT(px, py)), expected) \ << #RT "::MakeLTRB(" << l << ", " << t << ", " << r << ", " << b << ")" \ - << ".NormalizePoint(" << #PT "(" << px << ", " << py << "))" + << ".NormalizePoint(" << #PT "(" << px << ", " << py << "))" \ + << std::endl TEST(RectTest, NormalizePoint) { // Tests finite rects including: