Flutter Impeller
geometry_asserts.h
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef FLUTTER_IMPELLER_GEOMETRY_GEOMETRY_ASSERTS_H_
6 #define FLUTTER_IMPELLER_GEOMETRY_GEOMETRY_ASSERTS_H_
7 
8 #include <array>
9 #include <iostream>
10 
11 #include "gtest/gtest.h"
14 #include "impeller/geometry/rect.h"
15 #include "impeller/geometry/size.h"
17 
18 inline bool NumberNear(double a, double b) {
19  if (a == b) {
20  return true;
21  }
22  if (std::isnan(a) || std::isnan(b)) {
23  return false;
24  }
25 
26  // We used to compare based on an absolute difference of 1e-3 which
27  // would allow up to 10 bits of mantissa difference in a float
28  // (leaving 14 bits of accuracy being tested). Some numbers in the tests
29  // will fail with a bit difference of up to 19 (a little over 4 bits) even
30  // though the numbers print out identically using the float ostream output
31  // at the default output precision. Choosing a max "units of least precision"
32  // of 32 allows up to 5 bits of imprecision.
33  static constexpr float kImpellerTestingMaxULP = 32;
34 
35  // We also impose a minimum step size so that cases of comparing numbers
36  // very close to 0.0 don't compute a huge number of ULPs due to the ever
37  // increasing precision near 0. This value is approximately the step size
38  // of numbers going less than 1.0f.
39  static constexpr float kMinimumULPStep = (1.0f / (1 << 24));
40 
41  auto adjust_step = [](float v) {
42  return (std::abs(v) < kMinimumULPStep) ? std::copysignf(kMinimumULPStep, v)
43  : v;
44  };
45 
46  float step_ab = adjust_step(a - std::nexttowardf(a, b));
47  float step_ba = adjust_step(b - std::nexttowardf(b, a));
48 
49  float ab_ulps = (a - b) / step_ab;
50  float ba_ulps = (b - a) / step_ba;
51  FML_CHECK(ab_ulps >= 0 && ba_ulps >= 0);
52 
53  return (std::min(ab_ulps, ba_ulps) < kImpellerTestingMaxULP);
54 }
55 
56 inline ::testing::AssertionResult MatrixNear(impeller::Matrix a,
58  auto equal = NumberNear(a.m[0], b.m[0]) //
59  && NumberNear(a.m[1], b.m[1]) //
60  && NumberNear(a.m[2], b.m[2]) //
61  && NumberNear(a.m[3], b.m[3]) //
62  && NumberNear(a.m[4], b.m[4]) //
63  && NumberNear(a.m[5], b.m[5]) //
64  && NumberNear(a.m[6], b.m[6]) //
65  && NumberNear(a.m[7], b.m[7]) //
66  && NumberNear(a.m[8], b.m[8]) //
67  && NumberNear(a.m[9], b.m[9]) //
68  && NumberNear(a.m[10], b.m[10]) //
69  && NumberNear(a.m[11], b.m[11]) //
70  && NumberNear(a.m[12], b.m[12]) //
71  && NumberNear(a.m[13], b.m[13]) //
72  && NumberNear(a.m[14], b.m[14]) //
73  && NumberNear(a.m[15], b.m[15]);
74 
75  return equal ? ::testing::AssertionSuccess()
76  : ::testing::AssertionFailure()
77  << "Matrixes are not equal " << a << " " << b;
78 }
79 
80 inline ::testing::AssertionResult QuaternionNear(impeller::Quaternion a,
82  auto equal = NumberNear(a.x, b.x) && NumberNear(a.y, b.y) &&
83  NumberNear(a.z, b.z) && NumberNear(a.w, b.w);
84 
85  return equal ? ::testing::AssertionSuccess()
86  : ::testing::AssertionFailure() << "Quaternions are not equal.";
87 }
88 
89 inline ::testing::AssertionResult RectNear(impeller::Rect a, impeller::Rect b) {
90  auto equal = NumberNear(a.GetLeft(), b.GetLeft()) &&
91  NumberNear(a.GetTop(), b.GetTop()) &&
92  NumberNear(a.GetRight(), b.GetRight()) &&
93  NumberNear(a.GetBottom(), b.GetBottom());
94 
95  return equal ? ::testing::AssertionSuccess()
96  : ::testing::AssertionFailure()
97  << "Rects are not equal (" << a << " " << b << ")";
98 }
99 
100 inline ::testing::AssertionResult ColorNear(impeller::Color a,
101  impeller::Color b) {
102  auto equal = NumberNear(a.red, b.red) && NumberNear(a.green, b.green) &&
103  NumberNear(a.blue, b.blue) && NumberNear(a.alpha, b.alpha);
104 
105  return equal ? ::testing::AssertionSuccess()
106  : ::testing::AssertionFailure() << "Colors are not equal.";
107 }
108 
109 inline ::testing::AssertionResult PointNear(impeller::Point a,
110  impeller::Point b) {
111  auto equal = NumberNear(a.x, b.x) && NumberNear(a.y, b.y);
112 
113  return equal ? ::testing::AssertionSuccess()
114  : ::testing::AssertionFailure()
115  << "Points are not equal (" << a << " " << b << ").";
116 }
117 
118 inline ::testing::AssertionResult Vector3Near(impeller::Vector3 a,
120  auto equal =
121  NumberNear(a.x, b.x) && NumberNear(a.y, b.y) && NumberNear(a.z, b.z);
122 
123  return equal ? ::testing::AssertionSuccess()
124  : ::testing::AssertionFailure() << "Vector3s are not equal.";
125 }
126 
127 inline ::testing::AssertionResult Vector4Near(impeller::Vector4 a,
129  auto equal = NumberNear(a.x, b.x) && NumberNear(a.y, b.y) &&
130  NumberNear(a.z, b.z) && NumberNear(a.w, b.w);
131 
132  return equal ? ::testing::AssertionSuccess()
133  : ::testing::AssertionFailure() << "Vector4s are not equal.";
134 }
135 
136 inline ::testing::AssertionResult SizeNear(impeller::Size a, impeller::Size b) {
137  auto equal = NumberNear(a.width, b.width) && NumberNear(a.height, b.height);
138 
139  return equal ? ::testing::AssertionSuccess()
140  : ::testing::AssertionFailure() << "Sizes are not equal.";
141 }
142 
143 inline ::testing::AssertionResult Array4Near(std::array<uint8_t, 4> a,
144  std::array<uint8_t, 4> b) {
145  auto equal = NumberNear(a[0], b[0]) && NumberNear(a[1], b[1]) &&
146  NumberNear(a[2], b[2]) && NumberNear(a[3], b[3]);
147 
148  return equal ? ::testing::AssertionSuccess()
149  : ::testing::AssertionFailure() << "Arrays are not equal.";
150 }
151 
152 inline ::testing::AssertionResult ColorBufferNear(
153  std::vector<uint8_t> a,
154  std::vector<impeller::Color> b) {
155  if (a.size() != b.size() * 4) {
156  return ::testing::AssertionFailure()
157  << "Color buffer length does not match";
158  }
159  for (auto i = 0u; i < b.size(); i++) {
160  auto right = b[i].Premultiply().ToR8G8B8A8();
161  auto j = i * 4;
162  auto equal = NumberNear(a[j], right[0]) && NumberNear(a[j + 1], right[1]) &&
163  NumberNear(a[j + 2], right[2]) &&
164  NumberNear(a[j + 3], right[3]);
165  if (!equal) {
166  ::testing::AssertionFailure() << "Color buffers are not equal.";
167  }
168  }
169  return ::testing::AssertionSuccess();
170 }
171 
172 inline ::testing::AssertionResult ColorsNear(std::vector<impeller::Color> a,
173  std::vector<impeller::Color> b) {
174  if (a.size() != b.size()) {
175  return ::testing::AssertionFailure() << "Colors length does not match";
176  }
177  for (auto i = 0u; i < b.size(); i++) {
178  auto equal =
179  NumberNear(a[i].red, b[i].red) && NumberNear(a[i].green, b[i].green) &&
180  NumberNear(a[i].blue, b[i].blue) && NumberNear(a[i].alpha, b[i].alpha);
181 
182  if (!equal) {
183  ::testing::AssertionFailure() << "Colors are not equal.";
184  }
185  }
186  return ::testing::AssertionSuccess();
187 }
188 
189 #define ASSERT_MATRIX_NEAR(a, b) ASSERT_PRED2(&::MatrixNear, a, b)
190 #define ASSERT_QUATERNION_NEAR(a, b) ASSERT_PRED2(&::QuaternionNear, a, b)
191 #define ASSERT_RECT_NEAR(a, b) ASSERT_PRED2(&::RectNear, a, b)
192 #define ASSERT_COLOR_NEAR(a, b) ASSERT_PRED2(&::ColorNear, a, b)
193 #define ASSERT_POINT_NEAR(a, b) ASSERT_PRED2(&::PointNear, a, b)
194 #define ASSERT_VECTOR3_NEAR(a, b) ASSERT_PRED2(&::Vector3Near, a, b)
195 #define ASSERT_VECTOR4_NEAR(a, b) ASSERT_PRED2(&::Vector4Near, a, b)
196 #define ASSERT_SIZE_NEAR(a, b) ASSERT_PRED2(&::SizeNear, a, b)
197 #define ASSERT_ARRAY_4_NEAR(a, b) ASSERT_PRED2(&::Array4Near, a, b)
198 #define ASSERT_COLOR_BUFFER_NEAR(a, b) ASSERT_PRED2(&::ColorBufferNear, a, b)
199 #define ASSERT_COLORS_NEAR(a, b) ASSERT_PRED2(&::ColorsNear, a, b)
200 
201 #define EXPECT_MATRIX_NEAR(a, b) EXPECT_PRED2(&::MatrixNear, a, b)
202 #define EXPECT_QUATERNION_NEAR(a, b) EXPECT_PRED2(&::QuaternionNear, a, b)
203 #define EXPECT_RECT_NEAR(a, b) EXPECT_PRED2(&::RectNear, a, b)
204 #define EXPECT_COLOR_NEAR(a, b) EXPECT_PRED2(&::ColorNear, a, b)
205 #define EXPECT_POINT_NEAR(a, b) EXPECT_PRED2(&::PointNear, a, b)
206 #define EXPECT_VECTOR3_NEAR(a, b) EXPECT_PRED2(&::Vector3Near, a, b)
207 #define EXPECT_VECTOR4_NEAR(a, b) EXPECT_PRED2(&::Vector4Near, a, b)
208 #define EXPECT_SIZE_NEAR(a, b) EXPECT_PRED2(&::SizeNear, a, b)
209 #define EXPECT_ARRAY_4_NEAR(a, b) EXPECT_PRED2(&::Array4Near, a, b)
210 #define EXPECT_COLOR_BUFFER_NEAR(a, b) EXPECT_PRED2(&::ColorBufferNear, a, b)
211 #define EXPECT_COLORS_NEAR(a, b) EXPECT_PRED2(&::ColorsNear, a, b)
212 
213 #endif // FLUTTER_IMPELLER_GEOMETRY_GEOMETRY_ASSERTS_H_
inline ::testing::AssertionResult RectNear(impeller::Rect a, impeller::Rect b)
inline ::testing::AssertionResult QuaternionNear(impeller::Quaternion a, impeller::Quaternion b)
inline ::testing::AssertionResult ColorNear(impeller::Color a, impeller::Color b)
inline ::testing::AssertionResult ColorsNear(std::vector< impeller::Color > a, std::vector< impeller::Color > b)
inline ::testing::AssertionResult PointNear(impeller::Point a, impeller::Point b)
inline ::testing::AssertionResult SizeNear(impeller::Size a, impeller::Size b)
inline ::testing::AssertionResult Array4Near(std::array< uint8_t, 4 > a, std::array< uint8_t, 4 > b)
bool NumberNear(double a, double b)
inline ::testing::AssertionResult MatrixNear(impeller::Matrix a, impeller::Matrix b)
inline ::testing::AssertionResult Vector4Near(impeller::Vector4 a, impeller::Vector4 b)
inline ::testing::AssertionResult Vector3Near(impeller::Vector3 a, impeller::Vector3 b)
inline ::testing::AssertionResult ColorBufferNear(std::vector< uint8_t > a, std::vector< impeller::Color > b)
Scalar blue
Definition: color.h:138
Scalar alpha
Definition: color.h:143
Scalar red
Definition: color.h:128
Scalar green
Definition: color.h:133
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
Scalar m[16]
Definition: matrix.h:39
constexpr auto GetBottom() const
Definition: rect.h:361
constexpr auto GetTop() const
Definition: rect.h:357
constexpr auto GetLeft() const
Definition: rect.h:355
constexpr auto GetRight() const
Definition: rect.h:359
Type height
Definition: size.h:29
Type width
Definition: size.h:28